// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.cloud.policysimulator.v1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/cloud/orgpolicy/v2/constraint.proto";
import "google/cloud/orgpolicy/v2/orgpolicy.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/timestamp.proto";
import "google/rpc/status.proto";

option csharp_namespace = "Google.Cloud.PolicySimulator.V1";
option go_package = "cloud.google.com/go/policysimulator/apiv1/policysimulatorpb;policysimulatorpb";
option java_multiple_files = true;
option java_outer_classname = "OrgpolicyProto";
option java_package = "com.google.cloud.policysimulator.v1";
option php_namespace = "Google\\Cloud\\PolicySimulator\\V1";
option ruby_package = "Google::Cloud::PolicySimulator::V1";
option (google.api.resource_definition) = {
  type: "iam.googleapis.com/OrganizationLocation"
  pattern: "organizations/{organization}/locations/{location}"
};
option (google.api.resource_definition) = {
  type: "iam.googleapis.com/FolderLocation"
  pattern: "folders/{folder}/locations/{location}"
};

// Violations Preview API service for OrgPolicy.
//
// An
// [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
// is a preview of the violations that will exist as soon as a proposed
// OrgPolicy change is submitted. To create an
// [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview],
// the API user specifies the changes they wish to make and requests the
// generation of a preview via [GenerateViolationsPreview][]. the OrgPolicy
// Simulator service then scans the API user's currently existing resources to
// determine these resources violate the newly set OrgPolicy.
service OrgPolicyViolationsPreviewService {
  option (google.api.default_host) = "policysimulator.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // ListOrgPolicyViolationsPreviews lists each
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // in an organization. Each
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // is available for at least 7 days.
  rpc ListOrgPolicyViolationsPreviews(ListOrgPolicyViolationsPreviewsRequest)
      returns (ListOrgPolicyViolationsPreviewsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=organizations/*/locations/*}/orgPolicyViolationsPreviews"
    };
    option (google.api.method_signature) = "parent";
  }

  // GetOrgPolicyViolationsPreview gets the specified
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview].
  // Each
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // is available for at least 7 days.
  rpc GetOrgPolicyViolationsPreview(GetOrgPolicyViolationsPreviewRequest)
      returns (OrgPolicyViolationsPreview) {
    option (google.api.http) = {
      get: "/v1/{name=organizations/*/locations/*/orgPolicyViolationsPreviews/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // CreateOrgPolicyViolationsPreview creates an
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // for the proposed changes in the provided
  // [OrgPolicyViolationsPreview.OrgPolicyOverlay][]. The changes to OrgPolicy
  // are specified by this `OrgPolicyOverlay`. The resources to scan are
  // inferred from these specified changes.
  rpc CreateOrgPolicyViolationsPreview(CreateOrgPolicyViolationsPreviewRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v1/{parent=organizations/*/locations/*}/orgPolicyViolationsPreviews"
      body: "org_policy_violations_preview"
    };
    option (google.api.method_signature) =
        "parent,org_policy_violations_preview,org_policy_violations_preview_id";
    option (google.longrunning.operation_info) = {
      response_type: "OrgPolicyViolationsPreview"
      metadata_type: "CreateOrgPolicyViolationsPreviewOperationMetadata"
    };
  }

  // ListOrgPolicyViolations lists the [OrgPolicyViolations][] that are present
  // in an
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview].
  rpc ListOrgPolicyViolations(ListOrgPolicyViolationsRequest)
      returns (ListOrgPolicyViolationsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=organizations/*/locations/*/orgPolicyViolationsPreviews/*}/orgPolicyViolations"
    };
    option (google.api.method_signature) = "parent";
  }
}

// The current state of an
// [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview].
enum PreviewState {
  // The state is unspecified.
  PREVIEW_STATE_UNSPECIFIED = 0;

  // The
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // has not been created yet.
  PREVIEW_PENDING = 1;

  // The
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // is currently being created.
  PREVIEW_RUNNING = 2;

  // The
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // creation finished successfully.
  PREVIEW_SUCCEEDED = 3;

  // The
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // creation failed with an error.
  PREVIEW_FAILED = 4;
}

// OrgPolicyViolationsPreview is a resource providing a preview of the
// violations that will exist if an OrgPolicy change is made.
//
// The list of violations are modeled as child resources and retrieved via a
// [ListOrgPolicyViolations][] API call. There are potentially more
// [OrgPolicyViolations][] than could fit in an embedded field. Thus, the use of
// a child resource instead of a field.
message OrgPolicyViolationsPreview {
  option (google.api.resource) = {
    type: "policysimulator.googleapis.com/OrgPolicyViolationsPreview"
    pattern: "organizations/{organization}/locations/{location}/orgPolicyViolationsPreviews/{org_policy_violations_preview}"
    plural: "orgPolicyViolationsPreviews"
    singular: "orgPolicyViolationsPreview"
  };

  // A summary of the state of all resources scanned for compliance with the
  // changed OrgPolicy.
  message ResourceCounts {
    // Output only. Number of resources checked for compliance.
    //
    // Must equal:  unenforced + noncompliant + compliant + error
    int32 scanned = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. Number of scanned resources with at least one violation.
    int32 noncompliant = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. Number of scanned resources with zero violations.
    int32 compliant = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. Number of resources where the constraint was not enforced,
    // i.e. the Policy set `enforced: false` for that resource.
    int32 unenforced = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. Number of resources that returned an error when scanned.
    int32 errors = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // Output only. The resource name of the `OrgPolicyViolationsPreview`. It has
  // the following format:
  //
  // `organizations/{organization}/locations/{location}/orgPolicyViolationsPreviews/{orgPolicyViolationsPreview}`
  //
  // Example:
  // `organizations/my-example-org/locations/global/orgPolicyViolationsPreviews/506a5f7f`
  string name = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The state of the `OrgPolicyViolationsPreview`.
  PreviewState state = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Required. The proposed changes we are previewing violations for.
  OrgPolicyOverlay overlay = 3 [(google.api.field_behavior) = REQUIRED];

  // Output only. The number of [OrgPolicyViolations][] in this
  // `OrgPolicyViolationsPreview`. This count may differ from
  // `resource_summary.noncompliant_count` because each
  // [OrgPolicyViolation][google.cloud.policysimulator.v1.OrgPolicyViolation] is
  // specific to a resource **and** constraint. If there are multiple
  // constraints being evaluated (i.e. multiple policies in the overlay), a
  // single resource may violate multiple constraints.
  int32 violations_count = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. A summary of the state of all resources scanned for compliance
  // with the changed OrgPolicy.
  ResourceCounts resource_counts = 5
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The names of the constraints against which all
  // `OrgPolicyViolations` were evaluated.
  //
  // If `OrgPolicyOverlay` only contains `PolicyOverlay` then it contains
  // the name of the configured custom constraint, applicable to the specified
  // policies. Otherwise it contains the name of the constraint specified in
  // `CustomConstraintOverlay`.
  //
  // Format:
  // `organizations/{organization_id}/customConstraints/{custom_constraint_id}`
  //
  // Example: `organizations/123/customConstraints/custom.createOnlyE2TypeVms`
  repeated string custom_constraints = 6 [
    (google.api.field_behavior) = OUTPUT_ONLY,
    (google.api.resource_reference) = {
      type: "orgpolicy.googleapis.com/CustomConstraint"
    }
  ];

  // Output only. Time when this `OrgPolicyViolationsPreview` was created.
  google.protobuf.Timestamp create_time = 7
      [(google.api.field_behavior) = OUTPUT_ONLY];
}

// OrgPolicyViolation is a resource representing a single resource violating a
// single OrgPolicy constraint.
message OrgPolicyViolation {
  option (google.api.resource) = {
    type: "policysimulator.googleapis.com/OrgPolicyViolation"
    pattern: "organizations/{organization}/locations/{location}/orgPolicyViolationsPreviews/{org_policy_violations_preview}/orgPolicyViolations/{org_policy_violation}"
    plural: "orgPolicyViolations"
    singular: "orgPolicyViolation"
  };

  // The name of the `OrgPolicyViolation`. Example:
  // organizations/my-example-org/locations/global/orgPolicyViolationsPreviews/506a5f7f/orgPolicyViolations/38ce`
  string name = 1;

  // The resource violating the constraint.
  ResourceContext resource = 2;

  // The custom constraint being violated.
  google.cloud.orgpolicy.v2.CustomConstraint custom_constraint = 3;

  // Any error encountered during the evaluation.
  google.rpc.Status error = 4;
}

// ResourceContext provides the context we know about a resource.
// It is similar in concept to google.cloud.asset.v1.Resource, but focuses
// on the information specifically used by Simulator.
message ResourceContext {
  // The full name of the resource. Example:
  // `//compute.googleapis.com/projects/my_project_123/zones/zone1/instances/instance1`
  //
  // See [Resource
  // names](https://cloud.google.com/apis/design/resource_names#full_resource_name)
  // for more information.
  string resource = 1;

  // The asset type of the resource as defined by CAIS.
  //
  // Example: `compute.googleapis.com/Firewall`
  //
  // See [Supported asset
  // types](https://cloud.google.com/asset-inventory/docs/supported-asset-types)
  // for more information.
  string asset_type = 2;

  // The ancestry path of the resource in Google Cloud [resource
  // hierarchy](https://cloud.google.com/resource-manager/docs/cloud-platform-resource-hierarchy),
  // represented as a list of relative resource names. An ancestry path starts
  // with the closest ancestor in the hierarchy and ends at root. If the
  // resource is a project, folder, or organization, the ancestry path starts
  // from the resource itself.
  //
  // Example: `["projects/123456789", "folders/5432", "organizations/1234"]`
  repeated string ancestors = 3;
}

// The proposed changes to OrgPolicy.
message OrgPolicyOverlay {
  // A change to an OrgPolicy.
  message PolicyOverlay {
    // Optional. The parent of the policy we are attaching to.
    // Example: "projects/123456"
    string policy_parent = 1 [(google.api.field_behavior) = OPTIONAL];

    // Optional. The new or updated OrgPolicy.
    google.cloud.orgpolicy.v2.Policy policy = 2
        [(google.api.field_behavior) = OPTIONAL];
  }

  // A change to an OrgPolicy custom constraint.
  message CustomConstraintOverlay {
    // Optional. Resource the constraint is attached to.
    // Example: "organization/987654"
    string custom_constraint_parent = 1
        [(google.api.field_behavior) = OPTIONAL];

    // Optional. The new or updated custom constraint.
    google.cloud.orgpolicy.v2.CustomConstraint custom_constraint = 2
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Optional. The OrgPolicy changes to preview violations for.
  //
  // Any existing OrgPolicies with the same name will be overridden
  // in the simulation. That is, violations will be determined as if all
  // policies in the overlay were created or updated.
  repeated PolicyOverlay policies = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The OrgPolicy CustomConstraint changes to preview violations for.
  //
  // Any existing CustomConstraints with the same name will be overridden
  // in the simulation. That is, violations will be determined as if all
  // custom constraints in the overlay were instantiated.
  //
  // Only a single custom_constraint is supported in the overlay at a time.
  // For evaluating multiple constraints, multiple
  // `GenerateOrgPolicyViolationsPreview` requests are made, where each request
  // evaluates a single constraint.
  repeated CustomConstraintOverlay custom_constraints = 2
      [(google.api.field_behavior) = OPTIONAL];
}

// CreateOrgPolicyViolationsPreviewOperationMetadata is metadata about an
// OrgPolicyViolationsPreview generations operation.
message CreateOrgPolicyViolationsPreviewOperationMetadata {
  // Time when the request was received.
  google.protobuf.Timestamp request_time = 1;

  // Time when the request started processing, i.e., when the state was set to
  // RUNNING.
  google.protobuf.Timestamp start_time = 2;

  // Output only. The current state of the operation.
  PreviewState state = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Total number of resources that need scanning.
  // Should equal resource_scanned + resources_pending
  int32 resources_found = 4;

  // Number of resources already scanned.
  int32 resources_scanned = 5;

  // Number of resources still to scan.
  int32 resources_pending = 6;
}

// ListOrgPolicyViolationsPreviewsRequest is the request message for
// [OrgPolicyViolationsPreviewService.ListOrgPolicyViolationsPreviews][google.cloud.policysimulator.v1.OrgPolicyViolationsPreviewService.ListOrgPolicyViolationsPreviews].
message ListOrgPolicyViolationsPreviewsRequest {
  // Required. The parent the violations are scoped to.
  // Format:
  // `organizations/{organization}/locations/{location}`
  //
  // Example: `organizations/my-example-org/locations/global`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "policysimulator.googleapis.com/OrgPolicyViolationsPreview"
    }
  ];

  // Optional. The maximum number of items to return. The service may return
  // fewer than this value. If unspecified, at most 5 items will be returned.
  // The maximum value is 10; values above 10 will be coerced to 10.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A page token, received from a previous call. Provide this to
  // retrieve the subsequent page.
  //
  // When paginating, all other parameters must match the call that provided the
  // page token.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
}

// ListOrgPolicyViolationsPreviewsResponse is the response message for
// [OrgPolicyViolationsPreviewService.ListOrgPolicyViolationsPreviews][google.cloud.policysimulator.v1.OrgPolicyViolationsPreviewService.ListOrgPolicyViolationsPreviews].
message ListOrgPolicyViolationsPreviewsResponse {
  // The list of OrgPolicyViolationsPreview
  repeated OrgPolicyViolationsPreview org_policy_violations_previews = 1;

  // A token that you can use to retrieve the next page of results.
  // If this field is omitted, there are no subsequent pages.
  string next_page_token = 2;
}

// GetOrgPolicyViolationsPreviewRequest is the request message for
// [OrgPolicyViolationsPreviewService.GetOrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreviewService.GetOrgPolicyViolationsPreview].
message GetOrgPolicyViolationsPreviewRequest {
  // Required. The name of the OrgPolicyViolationsPreview to get.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "policysimulator.googleapis.com/OrgPolicyViolationsPreview"
    }
  ];
}

// CreateOrgPolicyViolationsPreviewRequest is the request message for
// [OrgPolicyViolationsPreviewService.CreateOrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreviewService.CreateOrgPolicyViolationsPreview].
message CreateOrgPolicyViolationsPreviewRequest {
  // Required. The organization under which this
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // will be created.
  //
  // Example: `organizations/my-example-org/locations/global`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "policysimulator.googleapis.com/OrgPolicyViolationsPreview"
    }
  ];

  // Required. The
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview]
  // to generate.
  OrgPolicyViolationsPreview org_policy_violations_preview = 2
      [(google.api.field_behavior) = REQUIRED];

  // Optional. An optional user-specified ID for the
  // [OrgPolicyViolationsPreview][google.cloud.policysimulator.v1.OrgPolicyViolationsPreview].
  // If not provided, a random ID will be generated.
  string org_policy_violations_preview_id = 3
      [(google.api.field_behavior) = OPTIONAL];
}

// ListOrgPolicyViolationsRequest is the request message for
// [OrgPolicyViolationsPreviewService.ListOrgPolicyViolations][google.cloud.policysimulator.v1.OrgPolicyViolationsPreviewService.ListOrgPolicyViolations].
message ListOrgPolicyViolationsRequest {
  // Required. The OrgPolicyViolationsPreview to get OrgPolicyViolations from.
  // Format:
  // organizations/{organization}/locations/{location}/orgPolicyViolationsPreviews/{orgPolicyViolationsPreview}
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "policysimulator.googleapis.com/OrgPolicyViolation"
    }
  ];

  // Optional. The maximum number of items to return. The service may return
  // fewer than this value. If unspecified, at most 1000 items will be returned.
  // The maximum value is 1000; values above 1000 will be coerced to 1000.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A page token, received from a previous call. Provide this to
  // retrieve the subsequent page.
  //
  // When paginating, all other parameters must match the call that provided the
  // page token.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];
}

// ListOrgPolicyViolationsResponse is the response message for
// [OrgPolicyViolationsPreviewService.ListOrgPolicyViolations][google.cloud.policysimulator.v1.OrgPolicyViolationsPreviewService.ListOrgPolicyViolations]
message ListOrgPolicyViolationsResponse {
  // The list of OrgPolicyViolations
  repeated OrgPolicyViolation org_policy_violations = 1;

  // A token that you can use to retrieve the next page of results.
  // If this field is omitted, there are no subsequent pages.
  string next_page_token = 2;
}
