// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

syntax = "proto3";
package tfplan;

// For Terraform's own parsing, the proto stub types go into an internal Go
// package. The public API is in github.com/hashicorp/terraform/plans/planfile .
option go_package = "github.com/hashicorp/terraform/internal/plans/planproto";

// Plan is the root message type for the tfplan file
message Plan {
    // Version is incremented whenever there is a breaking change to
    // the serialization format. Programs reading serialized plans should
    // verify that version is set to the expected value and abort processing
    // if not. A breaking change is any change that may cause an older
    // consumer to interpret the structure incorrectly. This number will
    // not be incremented if an existing consumer can either safely ignore
    // changes to the format or if an existing consumer would fail to process
    // the file for another message- or field-specific reason.
    uint64 version = 1;

    // The mode that was active when this plan was created.
    //
    // This is saved only for UI purposes, so that Terraform can tailor its
    // rendering of the plan depending on the mode. This must never be used to
    // make decisions in Terraform Core during the applying of a plan.
    Mode ui_mode = 17;

    // Applyable is true for any plan where it makes sense to ask an operator
    // to approve it and then ask Terraform to apply it.
    //
    // The other fields provide more context about why a non-applyable plan
    // is not applyable, but this field is here so that if new situations
    // arise in future then old callers can at least still make the right
    // decision about whether to show the approval prompt, even if they don't
    // know yet why a particular plan isn't applyable and have to just use
    // a generic error message.
    bool applyable = 25;

    // Complete is true for a plan that includes a planned action for every
    // resource input object that was present across the desired state and
    // prior state, even if the planned action is "no-op".
    //
    // Conversely, if this field is false then the plan deals with only a
    // subset of those objects. The reason for that should always be
    // determinable based on other fields in this message, but this flag
    // is here to ensure that if new situations arise in future then old
    // callers can at least still show a generic message about the plan
    // being incomplete, even if they don't know yet how to explain the
    // reason to the operator.
    bool complete = 26;

    // Errored is true for any plan whose creation was interrupted by an
    // error. A plan with this flag set cannot be applied
    // (i.e. applyable = false), and the changes it proposes are likely to be
    // incomplete.
    bool errored = 20;

    // The variables that were set when creating the plan. Each value is
    // a msgpack serialization of an HCL value.
    map<string, DynamicValue> variables = 2;

    // An unordered set of proposed changes to resources throughout the
    // configuration, including any nested modules. Use the address of
    // each resource to determine which module it belongs to.
    repeated ResourceInstanceChange resource_changes = 3;

    // An unordered set of detected drift: changes made to resources outside of
    // Terraform, computed by comparing the previous run's state to the state
    // after refresh.
    repeated ResourceInstanceChange resource_drift = 18;

    // An unordered set of deferred changes. These are changes that will be
    // applied in a subsequent plan, but were deferred in this plan for some
    // reason. Generally, if complete is set to false there should be entries
    // in this list.
    repeated DeferredResourceInstanceChange deferred_changes = 27;

    // An unordered set of proposed changes to outputs in the root module
    // of the configuration. This set also includes "no action" changes for
    // outputs that are not changing, as context for detecting inconsistencies
    // at apply time.
    repeated OutputChange output_changes = 4;

    // An unordered set of check results for the entire configuration.
    //
    // Each element represents a single static configuration object that has
    // checks, and each of those may have zero or more dynamic objects that
    // the checks were applied to nested within.
    repeated CheckResults check_results = 19;

    // An unordered set of target addresses to include when applying. If no
    // target addresses are present, the plan applies to the whole
    // configuration.
    repeated string target_addrs = 5;

    // An unordered set of force-replace addresses to include when applying.
    // This must match the set of addresses that was used when creating the
    // plan, or else applying the plan will fail when it reaches a different
    // conclusion about what action a particular resource instance needs.
    repeated string force_replace_addrs = 16;

    // The version string for the Terraform binary that created this plan.
    string terraform_version = 14;

    // Backend is a description of the backend configuration and other related
    // settings at the time the plan was created.
    Backend backend = 13;

    message resource_attr {
       string resource = 1;
       Path attr= 2;
    };

    // RelevantAttributes lists individual resource attributes from
    // ResourceDrift which may have contributed to the plan changes.
    repeated resource_attr relevant_attributes = 15;

    // timestamp is the record of truth for when the plan happened.
    string timestamp = 21;

    repeated ProviderFunctionCallHash provider_function_results = 22;
}

// Mode describes the planning mode that created the plan.
enum Mode {
    NORMAL = 0;
    DESTROY = 1;
    REFRESH_ONLY = 2;
}

// Backend is a description of backend configuration and other related settings.
message Backend {
    string type = 1;
    DynamicValue config = 2;
    string workspace = 3;
}

// Action describes the type of action planned for an object.
// Not all action values are valid for all object types.
enum Action {
    NOOP = 0;
    CREATE = 1;
    READ = 2;
    UPDATE = 3;
    DELETE = 5;
    DELETE_THEN_CREATE = 6;
    CREATE_THEN_DELETE = 7;
    FORGET = 8;
    CREATE_THEN_FORGET = 9;
}

// Change represents a change made to some object, transforming it from an old
// state to a new state.
message Change {
    // Not all action values are valid for all object types. Consult
    // the documentation for any message that embeds Change.
    Action action = 1;

    // msgpack-encoded HCL values involved in the change.
    // - For update and replace, two values are provided that give the old and new values,
    //   respectively.
    // - For create, one value is provided that gives the new value to be created
    // - For delete, one value is provided that describes the value being deleted
    // - For read, two values are provided that give the prior value for this object
    //   (or null, if no prior value exists) and the value that was or will be read,
    //   respectively.
    // - For no-op, one value is provided that is left unmodified by this non-change.
    repeated DynamicValue values = 2;

    // An unordered set of paths into the old value which are marked as
    // sensitive. Values at these paths should be obscured in human-readable
    // output. This set is always empty for create.
    repeated Path before_sensitive_paths = 3;

    // An unordered set of paths into the new value which are marked as
    // sensitive. Values at these paths should be obscured in human-readable
    // output. This set is always empty for delete.
    repeated Path after_sensitive_paths = 4;

    // Importing, if true, specifies that the resource is being imported as part
    // of the change.
    Importing importing = 5;

    // GeneratedConfig contains any configuration that was generated as part of
    // the change, as an HCL string.
    string generated_config = 6;
}

// ResourceInstanceActionReason sometimes provides some additional user-facing
// context for why a particular action was chosen for a resource instance.
// This is for user feedback only and never used to drive behavior during the
// subsequent apply step.
enum ResourceInstanceActionReason {
    NONE = 0;
    REPLACE_BECAUSE_TAINTED = 1;
    REPLACE_BY_REQUEST = 2;
    REPLACE_BECAUSE_CANNOT_UPDATE = 3;
    DELETE_BECAUSE_NO_RESOURCE_CONFIG = 4;
    DELETE_BECAUSE_WRONG_REPETITION = 5;
    DELETE_BECAUSE_COUNT_INDEX = 6;
    DELETE_BECAUSE_EACH_KEY = 7;
    DELETE_BECAUSE_NO_MODULE = 8;
    REPLACE_BY_TRIGGERS = 9;
    READ_BECAUSE_CONFIG_UNKNOWN = 10;
    READ_BECAUSE_DEPENDENCY_PENDING = 11;
    READ_BECAUSE_CHECK_NESTED = 13;
    DELETE_BECAUSE_NO_MOVE_TARGET = 12;
}

message ResourceInstanceChange {
    // addr is a string representation of the resource instance address that
    // this change will apply to.
    string addr = 13;

    // prev_run_addr is a string representation of the address at which
    // this resource instance was tracked during the previous apply operation.
    //
    // This is populated only if it would be different from addr due to
    // Terraform having reacted to refactoring annotations in the configuration.
    // If empty, the previous run address is the same as the current address.
    string prev_run_addr = 14;

    // NOTE: Earlier versions of this format had fields 1 through 6 describing
    // various indivdual parts of "addr". We're now using our standard compact
    // string representation to capture the same information. We don't support
    // preserving plan files from one Terraform version to the next, so we
    // no longer declare nor accept those fields.

    // deposed_key, if set, indicates that this change applies to a deposed
    // object for the indicated instance with the given deposed key. If not
    // set, the change applies to the instance's current object.
    string deposed_key = 7;

    // provider is the address of the provider configuration that this change
    // was planned with, and thus the configuration that must be used to
    // apply it.
    string provider = 8;

    // Description of the proposed change. May use "create", "read", "update",
    // "replace", "delete" and "no-op" actions.
    Change change = 9;

    // raw blob value provided by the provider as additional context for the
    // change. Must be considered an opaque value for any consumer other than
    // the provider that generated it, and will be returned verbatim to the
    // provider during the subsequent apply operation.
    bytes private = 10;

    // An unordered set of paths that prompted the change action to be
    // "replace" rather than "update". Empty for any action other than
    // "replace".
    repeated Path required_replace = 11;

    // Optional extra user-oriented context for why change.Action was chosen.
    // This is for user feedback only and never used to drive behavior during
    // apply.
    ResourceInstanceActionReason action_reason = 12;
}

// DeferredResourceInstanceChange represents a resource instance change that
// was deferred for some reason.
//
// It contains the original change that was deferred, along with the reason
// why it was deferred.
message DeferredResourceInstanceChange {
    // The reason why the change was deferred.
    Deferred deferred = 1;

    // The original change that was deferred.
    ResourceInstanceChange change = 2;
}

message OutputChange {
    // Name of the output as defined in the root module.
    string name = 1;

    // Description of the proposed change. May use "no-op", "create",
    // "update" and "delete" actions.
    Change change = 2;

    // Sensitive, if true, indicates that one or more of the values given
    // in "change" is sensitive and should not be shown directly in any
    // rendered plan.
    bool sensitive = 3;
}

message CheckResults {
    // Status describes the status of a particular checkable object at the
    // completion of the plan.
    enum Status {
        UNKNOWN = 0;
        PASS    = 1;
        FAIL    = 2;
        ERROR   = 3;
    }

    enum ObjectKind {
        UNSPECIFIED = 0;
        RESOURCE = 1;
        OUTPUT_VALUE = 2;
        CHECK = 3;
        INPUT_VARIABLE = 4;
    }

    message ObjectResult {
        string object_addr = 1;
        Status status = 2;
        repeated string failure_messages = 3;
    }

    ObjectKind kind = 1;

    // Address of the configuration object that declared the checks.
    string config_addr = 2;

    // The aggregate status of the entire configuration object, based on
    // the statuses of its zero or more checkable objects.
    Status status = 3;

    // The results for individual objects that were declared by the
    // configuration object named in config_addr.
    repeated ObjectResult objects = 4;
}

// ProviderFunctionCallHash stores a record of a hashed function call and
// result. This is used internally to ensure that providers return consistent
// values between plan and apply given the same arguments.
message ProviderFunctionCallHash {
    bytes key = 1;
    bytes result = 2;
}

// DynamicValue represents a value whose type is not decided until runtime,
// often based on schema information obtained from a plugin.
//
// At present dynamic values are always encoded as msgpack, with extension
// id 0 used to represent the special "unknown" value indicating results
// that won't be known until after apply.
//
// In future other serialization formats may be used, possibly with a
// transitional period of including both as separate attributes of this type.
// Consumers must ignore attributes they don't support and fail if no supported
// attribute is present. The top-level format version will not be incremented
// for changes to the set of dynamic serialization formats.
message DynamicValue {
    bytes msgpack = 1;
}

// Path represents a set of steps to traverse into a data structure. It is
// used to refer to a sub-structure within a dynamic data structure presented
// separately.
message Path {
    message Step {
        oneof selector {
            // Set "attribute_name" to represent looking up an attribute
            // in the current object value.
            string attribute_name = 1;

            // Set "element_key" to represent looking up an element in
            // an indexable collection type.
            DynamicValue element_key = 2;
        }
    }
    repeated Step steps = 1;
}

// Importing contains the embedded metadata about the import operation if this
// change describes it.
message Importing {
    // The original ID of the resource.
    string id = 1;
}

// DeferredReason describes the reason why a resource instance change was
// deferred.
enum DeferredReason {
    INVALID = 0;
    INSTANCE_COUNT_UNKNOWN = 1;
    RESOURCE_CONFIG_UNKNOWN = 2;
    PROVIDER_CONFIG_UNKNOWN = 3;
    ABSENT_PREREQ = 4;
    DEFERRED_PREREQ = 5;
}

// Deferred contains all the metadata about a the deferral of a resource
// instance change.
message Deferred {
    DeferredReason reason = 1;
}
