// Copyright 2024 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.privilegedaccessmanager.v1;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
import "google/rpc/status.proto";

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

// This API allows customers to manage temporary, request based privileged
// access to their resources.
//
// It defines the following resource model:
//
// * A collection of `Entitlement` resources. An entitlement allows configuring
//   (among other things):
//
//   * Some kind of privileged access that users can request.
//   * A set of users called _requesters_ who can request this access.
//   * A maximum duration for which the access can be requested.
//   * An optional approval workflow which must be satisfied before access is
//     granted.
//
// * A collection of `Grant` resources. A grant is a request by a requester to
//   get the privileged access specified in an entitlement for some duration.
//
//   After the approval workflow as specified in the entitlement is satisfied,
//   the specified access is given to the requester. The access is automatically
//   taken back after the requested duration is over.
service PrivilegedAccessManager {
  option (google.api.default_host) = "privilegedaccessmanager.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/cloud-platform";

  // CheckOnboardingStatus reports the onboarding status for a
  // project/folder/organization. Any findings reported by this API need to be
  // fixed before PAM can be used on the resource.
  rpc CheckOnboardingStatus(CheckOnboardingStatusRequest)
      returns (CheckOnboardingStatusResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*}:checkOnboardingStatus"
      additional_bindings {
        get: "/v1/{parent=organizations/*/locations/*}:checkOnboardingStatus"
      }
      additional_bindings {
        get: "/v1/{parent=folders/*/locations/*}:checkOnboardingStatus"
      }
    };
  }

  // Lists entitlements in a given project/folder/organization and location.
  rpc ListEntitlements(ListEntitlementsRequest)
      returns (ListEntitlementsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*}/entitlements"
      additional_bindings {
        get: "/v1/{parent=organizations/*/locations/*}/entitlements"
      }
      additional_bindings {
        get: "/v1/{parent=folders/*/locations/*}/entitlements"
      }
    };
    option (google.api.method_signature) = "parent";
  }

  // `SearchEntitlements` returns entitlements on which the caller has the
  // specified access.
  rpc SearchEntitlements(SearchEntitlementsRequest)
      returns (SearchEntitlementsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*}/entitlements:search"
      additional_bindings {
        get: "/v1/{parent=organizations/*/locations/*}/entitlements:search"
      }
      additional_bindings {
        get: "/v1/{parent=folders/*/locations/*}/entitlements:search"
      }
    };
  }

  // Gets details of a single entitlement.
  rpc GetEntitlement(GetEntitlementRequest) returns (Entitlement) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/entitlements/*}"
      additional_bindings {
        get: "/v1/{name=organizations/*/locations/*/entitlements/*}"
      }
      additional_bindings {
        get: "/v1/{name=folders/*/locations/*/entitlements/*}"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a new entitlement in a given project/folder/organization and
  // location.
  rpc CreateEntitlement(CreateEntitlementRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*}/entitlements"
      body: "entitlement"
      additional_bindings {
        post: "/v1/{parent=organizations/*/locations/*}/entitlements"
        body: "entitlement"
      }
      additional_bindings {
        post: "/v1/{parent=folders/*/locations/*}/entitlements"
        body: "entitlement"
      }
    };
    option (google.api.method_signature) = "parent,entitlement,entitlement_id";
    option (google.longrunning.operation_info) = {
      response_type: "Entitlement"
      metadata_type: "OperationMetadata"
    };
  }

  // Deletes a single entitlement. This method can only be called when there
  // are no in-progress (ACTIVE/ACTIVATING/REVOKING) grants under the
  // entitlement.
  rpc DeleteEntitlement(DeleteEntitlementRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      delete: "/v1/{name=projects/*/locations/*/entitlements/*}"
      additional_bindings {
        delete: "/v1/{name=organizations/*/locations/*/entitlements/*}"
      }
      additional_bindings {
        delete: "/v1/{name=folders/*/locations/*/entitlements/*}"
      }
    };
    option (google.api.method_signature) = "name";
    option (google.longrunning.operation_info) = {
      response_type: "Entitlement"
      metadata_type: "OperationMetadata"
    };
  }

  // Updates the entitlement specified in the request. Updated fields in the
  // entitlement need to be specified in an update mask. The changes made to an
  // entitlement are applicable only on future grants of the entitlement.
  // However, if new approvers are added or existing approvers are removed from
  // the approval workflow, the changes are effective on existing grants.
  //
  // The following fields are not supported for updates:
  //
  //  * All immutable fields
  //  * Entitlement name
  //  * Resource name
  //  * Resource type
  //  * Adding an approval workflow in an entitlement which previously had no
  //    approval workflow.
  //  * Deleting the approval workflow from an entitlement.
  //  * Adding or deleting a step in the approval workflow (only one step is
  //    supported)
  //
  // Note that updates are allowed on the list of approvers in an approval
  // workflow step.
  rpc UpdateEntitlement(UpdateEntitlementRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      patch: "/v1/{entitlement.name=projects/*/locations/*/entitlements/*}"
      body: "entitlement"
      additional_bindings {
        patch: "/v1/{entitlement.name=organizations/*/locations/*/entitlements/*}"
        body: "entitlement"
      }
      additional_bindings {
        patch: "/v1/{entitlement.name=folders/*/locations/*/entitlements/*}"
        body: "entitlement"
      }
    };
    option (google.api.method_signature) = "entitlement,update_mask";
    option (google.longrunning.operation_info) = {
      response_type: "Entitlement"
      metadata_type: "OperationMetadata"
    };
  }

  // Lists grants for a given entitlement.
  rpc ListGrants(ListGrantsRequest) returns (ListGrantsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*/entitlements/*}/grants"
      additional_bindings {
        get: "/v1/{parent=organizations/*/locations/*/entitlements/*}/grants"
      }
      additional_bindings {
        get: "/v1/{parent=folders/*/locations/*/entitlements/*}/grants"
      }
    };
    option (google.api.method_signature) = "parent";
  }

  // `SearchGrants` returns grants that are related to the calling user in the
  // specified way.
  rpc SearchGrants(SearchGrantsRequest) returns (SearchGrantsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*/entitlements/*}/grants:search"
      additional_bindings {
        get: "/v1/{parent=organizations/*/locations/*/entitlements/*}/grants:search"
      }
      additional_bindings {
        get: "/v1/{parent=folders/*/locations/*/entitlements/*}/grants:search"
      }
    };
  }

  // Get details of a single grant.
  rpc GetGrant(GetGrantRequest) returns (Grant) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/entitlements/*/grants/*}"
      additional_bindings {
        get: "/v1/{name=organizations/*/locations/*/entitlements/*/grants/*}"
      }
      additional_bindings {
        get: "/v1/{name=folders/*/locations/*/entitlements/*/grants/*}"
      }
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a new grant in a given project and location.
  rpc CreateGrant(CreateGrantRequest) returns (Grant) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/entitlements/*}/grants"
      body: "grant"
      additional_bindings {
        post: "/v1/{parent=organizations/*/locations/*/entitlements/*}/grants"
        body: "grant"
      }
      additional_bindings {
        post: "/v1/{parent=folders/*/locations/*/entitlements/*}/grants"
        body: "grant"
      }
    };
    option (google.api.method_signature) = "parent,grant";
  }

  // `ApproveGrant` is used to approve a grant. This method can only be called
  // on a grant when it's in the `APPROVAL_AWAITED` state. This operation can't
  // be undone.
  rpc ApproveGrant(ApproveGrantRequest) returns (Grant) {
    option (google.api.http) = {
      post: "/v1/{name=projects/*/locations/*/entitlements/*/grants/*}:approve"
      body: "*"
      additional_bindings {
        post: "/v1/{name=organizations/*/locations/*/entitlements/*/grants/*}:approve"
        body: "*"
      }
      additional_bindings {
        post: "/v1/{name=folders/*/locations/*/entitlements/*/grants/*}:approve"
        body: "*"
      }
    };
  }

  // `DenyGrant` is used to deny a grant. This method can only be called on a
  // grant when it's in the `APPROVAL_AWAITED` state. This operation can't be
  // undone.
  rpc DenyGrant(DenyGrantRequest) returns (Grant) {
    option (google.api.http) = {
      post: "/v1/{name=projects/*/locations/*/entitlements/*/grants/*}:deny"
      body: "*"
      additional_bindings {
        post: "/v1/{name=organizations/*/locations/*/entitlements/*/grants/*}:deny"
        body: "*"
      }
      additional_bindings {
        post: "/v1/{name=folders/*/locations/*/entitlements/*/grants/*}:deny"
        body: "*"
      }
    };
  }

  // `RevokeGrant` is used to immediately revoke access for a grant. This method
  // can be called when the grant is in a non-terminal state.
  rpc RevokeGrant(RevokeGrantRequest) returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v1/{name=projects/*/locations/*/entitlements/*/grants/*}:revoke"
      body: "*"
      additional_bindings {
        post: "/v1/{name=organizations/*/locations/*/entitlements/*/grants/*}:revoke"
        body: "*"
      }
      additional_bindings {
        post: "/v1/{name=folders/*/locations/*/entitlements/*/grants/*}:revoke"
        body: "*"
      }
    };
    option (google.longrunning.operation_info) = {
      response_type: "Grant"
      metadata_type: "OperationMetadata"
    };
  }
}

// Request message for `CheckOnboardingStatus` method.
message CheckOnboardingStatusRequest {
  // Required. The resource for which the onboarding status should be checked.
  // Should be in one of the following formats:
  //
  // * `projects/{project-number|project-id}/locations/{region}`
  // * `folders/{folder-number}/locations/{region}`
  // * `organizations/{organization-number}/locations/{region}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "privilegedaccessmanager.googleapis.com/Entitlement"
    }
  ];
}

// Response message for `CheckOnboardingStatus` method.
message CheckOnboardingStatusResponse {
  // Finding represents an issue which prevents PAM from functioning properly
  // for this resource.
  message Finding {
    // PAM's service account is being denied access by Cloud IAM.
    // This can be fixed by granting a role that contains the missing
    // permissions to the service account or exempting it from deny policies if
    // they are blocking the access.
    message IAMAccessDenied {
      // List of permissions that are being denied.
      repeated string missing_permissions = 1;
    }

    oneof finding_type {
      // PAM's service account is being denied access by Cloud IAM.
      IAMAccessDenied iam_access_denied = 1;
    }
  }

  // The service account that PAM uses to act on this resource.
  string service_account = 1;

  // List of issues that are preventing PAM from functioning for this resource
  // and need to be fixed to complete onboarding. Some issues might not be
  // detected or reported.
  repeated Finding findings = 2;
}

// An entitlement defines the eligibility of a set of users to obtain
// predefined access for some time possibly after going through an approval
// workflow.
message Entitlement {
  option (google.api.resource) = {
    type: "privilegedaccessmanager.googleapis.com/Entitlement"
    pattern: "projects/{project}/locations/{location}/entitlements/{entitlement}"
    pattern: "folders/{folder}/locations/{location}/entitlements/{entitlement}"
    pattern: "organizations/{organization}/locations/{location}/entitlements/{entitlement}"
    plural: "entitlements"
    singular: "entitlement"
  };

  // Defines how a requester must provide a justification when requesting
  // access.
  message RequesterJustificationConfig {
    // The justification is not mandatory but can be provided in any of the
    // supported formats.
    message NotMandatory {}

    // The requester has to provide a justification in the form of a string.
    message Unstructured {}

    // This is a required field and the user must explicitly opt out if a
    // justification from the requester isn't mandatory.
    oneof justification_type {
      // This option means the requester isn't required to provide a
      // justification.
      NotMandatory not_mandatory = 1;

      // This option means the requester must provide a string as
      // justification. If this is selected, the server allows the requester
      // to provide a justification but doesn't validate it.
      Unstructured unstructured = 2;
    }
  }

  // AdditionalNotificationTargets includes email addresses to be notified.
  message AdditionalNotificationTargets {
    // Optional. Additional email addresses to be notified when a principal
    // (requester) is granted access.
    repeated string admin_email_recipients = 1
        [(google.api.field_behavior) = OPTIONAL];

    // Optional. Additional email address to be notified about an eligible
    // entitlement.
    repeated string requester_email_recipients = 2
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Different states an entitlement can be in.
  enum State {
    // Unspecified state. This value is never returned by the server.
    STATE_UNSPECIFIED = 0;

    // The entitlement is being created.
    CREATING = 1;

    // The entitlement is available for requesting access.
    AVAILABLE = 2;

    // The entitlement is being deleted.
    DELETING = 3;

    // The entitlement has been deleted.
    DELETED = 4;

    // The entitlement is being updated.
    UPDATING = 5;
  }

  // Identifier. Name of the entitlement.
  // Possible formats:
  //
  // * `organizations/{organization-number}/locations/{region}/entitlements/{entitlement-id}`
  // * `folders/{folder-number}/locations/{region}/entitlements/{entitlement-id}`
  // * `projects/{project-id|project-number}/locations/{region}/entitlements/{entitlement-id}`
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. Create time stamp.
  google.protobuf.Timestamp create_time = 2
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Update time stamp.
  google.protobuf.Timestamp update_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. Who can create grants using this entitlement. This list should
  // contain at most one entry.
  repeated AccessControlEntry eligible_users = 5
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The approvals needed before access are granted to a requester. No
  // approvals are needed if this field is null.
  ApprovalWorkflow approval_workflow = 6
      [(google.api.field_behavior) = OPTIONAL];

  // The access granted to a requester on successful approval.
  PrivilegedAccess privileged_access = 7;

  // Required. The maximum amount of time that access is granted for a request.
  // A requester can ask for a duration less than this, but never more.
  google.protobuf.Duration max_request_duration = 8
      [(google.api.field_behavior) = REQUIRED];

  // Output only. Current state of this entitlement.
  State state = 9 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Required. The manner in which the requester should provide a justification
  // for requesting access.
  RequesterJustificationConfig requester_justification_config = 10
      [(google.api.field_behavior) = REQUIRED];

  // Optional. Additional email addresses to be notified based on actions taken.
  AdditionalNotificationTargets additional_notification_targets = 11
      [(google.api.field_behavior) = OPTIONAL];

  // An `etag` is used for optimistic concurrency control as a way to prevent
  // simultaneous updates to the same entitlement. An `etag` is returned in the
  // response to `GetEntitlement` and the caller should put the `etag` in the
  // request to `UpdateEntitlement` so that their change is applied on
  // the same version. If this field is omitted or if there is a mismatch while
  // updating an entitlement, then the server rejects the request.
  string etag = 12;
}

// AccessControlEntry is used to control who can do some operation.
message AccessControlEntry {
  // Optional. Users who are allowed for the operation. Each entry should be a
  // valid v1 IAM principal identifier. The format for these is documented at:
  // https://cloud.google.com/iam/docs/principal-identifiers#v1
  repeated string principals = 1 [(google.api.field_behavior) = OPTIONAL];
}

// Different types of approval workflows that can be used to gate privileged
// access granting.
message ApprovalWorkflow {
  oneof approval_workflow {
    // An approval workflow where users designated as approvers review and act
    // on the grants.
    ManualApprovals manual_approvals = 1;
  }
}

// A manual approval workflow where users who are designated as approvers
// need to call the `ApproveGrant`/`DenyGrant` APIs for a grant. The workflow
// can consist of multiple serial steps where each step defines who can act as
// approver in that step and how many of those users should approve before the
// workflow moves to the next step.
//
// This can be used to create approval workflows such as:
//
// * Require an approval from any user in a group G.
// * Require an approval from any k number of users from a Group G.
// * Require an approval from any user in a group G and then from a user U.
//
// A single user might be part of the `approvers` ACL for multiple steps in this
// workflow, but they can only approve once and that approval is only considered
// to satisfy the approval step at which it was granted.
message ManualApprovals {
  // Step represents a logical step in a manual approval workflow.
  message Step {
    // Optional. The potential set of approvers in this step. This list must
    // contain at most one entry.
    repeated AccessControlEntry approvers = 1
        [(google.api.field_behavior) = OPTIONAL];

    // Required. How many users from the above list need to approve. If there
    // aren't enough distinct users in the list, then the workflow indefinitely
    // blocks. Should always be greater than 0. 1 is the only supported value.
    int32 approvals_needed = 2 [(google.api.field_behavior) = REQUIRED];

    // Optional. Additional email addresses to be notified when a grant is
    // pending approval.
    repeated string approver_email_recipients = 3
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Optional. Do the approvers need to provide a justification for their
  // actions?
  bool require_approver_justification = 1
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. List of approval steps in this workflow. These steps are followed
  // in the specified order sequentially. Only 1 step is supported.
  repeated Step steps = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Privileged access that this service can be used to gate.
message PrivilegedAccess {
  // GcpIamAccess represents IAM based access control on a Google Cloud
  // resource. Refer to https://cloud.google.com/iam/docs to understand more
  // about IAM.
  message GcpIamAccess {
    // IAM Role bindings that are created after a successful grant.
    message RoleBinding {
      // Required. IAM role to be granted.
      // https://cloud.google.com/iam/docs/roles-overview.
      string role = 1 [(google.api.field_behavior) = REQUIRED];

      // Optional. The expression field of the IAM condition to be associated
      // with the role. If specified, a user with an active grant for this
      // entitlement is able to access the resource only if this condition
      // evaluates to true for their request.
      //
      // This field uses the same CEL format as IAM and supports all attributes
      // that IAM supports, except tags.
      // https://cloud.google.com/iam/docs/conditions-overview#attributes.
      string condition_expression = 2 [(google.api.field_behavior) = OPTIONAL];
    }

    // Required. The type of this resource.
    string resource_type = 1 [(google.api.field_behavior) = REQUIRED];

    // Required. Name of the resource.
    string resource = 2 [(google.api.field_behavior) = REQUIRED];

    // Required. Role bindings that are created on successful grant.
    repeated RoleBinding role_bindings = 4
        [(google.api.field_behavior) = REQUIRED];
  }

  oneof access_type {
    // Access to a Google Cloud resource through IAM.
    GcpIamAccess gcp_iam_access = 1;
  }
}

// Message for requesting list of entitlements.
message ListEntitlementsRequest {
  // Required. The parent which owns the entitlement resources.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "privilegedaccessmanager.googleapis.com/Entitlement"
    }
  ];

  // Optional. Requested page size. Server may return fewer items than
  // requested. If unspecified, the server picks an appropriate default.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A token identifying a page of results the server should return.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Filtering results.
  string filter = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Hint for how to order the results.
  string order_by = 5 [(google.api.field_behavior) = OPTIONAL];
}

// Message for response to listing entitlements.
message ListEntitlementsResponse {
  // The list of entitlements.
  repeated Entitlement entitlements = 1;

  // A token identifying a page of results the server should return.
  string next_page_token = 2;

  // Locations that could not be reached.
  repeated string unreachable = 3;
}

// Request message for `SearchEntitlements` method.
message SearchEntitlementsRequest {
  // Different types of access a user can have on the entitlement resource.
  enum CallerAccessType {
    // Unspecified access type.
    CALLER_ACCESS_TYPE_UNSPECIFIED = 0;

    // The user has access to create grants using this entitlement.
    GRANT_REQUESTER = 1;

    // The user has access to approve/deny grants created under this
    // entitlement.
    GRANT_APPROVER = 2;
  }

  // Required. The parent which owns the entitlement resources.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "privilegedaccessmanager.googleapis.com/Entitlement"
    }
  ];

  // Required. Only entitlements where the calling user has this access are
  // returned.
  CallerAccessType caller_access_type = 2
      [(google.api.field_behavior) = REQUIRED];

  // Optional. Only entitlements matching this filter are returned in the
  // response.
  string filter = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Requested page size. The server may return fewer items than
  // requested. If unspecified, the server picks an appropriate default.
  int32 page_size = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A token identifying a page of results the server should return.
  string page_token = 5 [(google.api.field_behavior) = OPTIONAL];
}

// Response message for `SearchEntitlements` method.
message SearchEntitlementsResponse {
  // The list of entitlements.
  repeated Entitlement entitlements = 1;

  // A token identifying a page of results the server should return.
  string next_page_token = 2;
}

// Message for getting an entitlement.
message GetEntitlementRequest {
  // Required. Name of the resource.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "privilegedaccessmanager.googleapis.com/Entitlement"
    }
  ];
}

// Message for creating an entitlement.
message CreateEntitlementRequest {
  // Required. Name of the parent resource for the entitlement.
  // Possible formats:
  //
  // * `organizations/{organization-number}/locations/{region}`
  // * `folders/{folder-number}/locations/{region}`
  // * `projects/{project-id|project-number}/locations/{region}`
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "privilegedaccessmanager.googleapis.com/Entitlement"
    }
  ];

  // Required. The ID to use for this entitlement. This becomes the last part of
  // the resource name.
  //
  // This value should be 4-63 characters in length, and valid characters are
  // "[a-z]", "[0-9]", and "-". The first character should be from [a-z].
  //
  // This value should be unique among all other entitlements under the
  // specified `parent`.
  string entitlement_id = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The resource being created
  Entitlement entitlement = 3 [(google.api.field_behavior) = REQUIRED];

  // Optional. An optional request ID to identify requests. Specify a unique
  // request ID so that if you must retry your request, the server knows to
  // ignore the request if it has already been completed. The server guarantees
  // this for at least 60 minutes after the first request.
  //
  // For example, consider a situation where you make an initial request and the
  // request times out. If you make the request again with the same request
  // ID, the server can check if original operation with the same request ID
  // was received, and if so, ignores the second request and returns the
  // previous operation's response. This prevents clients from accidentally
  // creating duplicate commitments.
  //
  // The request ID must be a valid UUID with the exception that zero UUID is
  // not supported (00000000-0000-0000-0000-000000000000).
  string request_id = 4 [(google.api.field_behavior) = OPTIONAL];
}

// Message for deleting an entitlement.
message DeleteEntitlementRequest {
  // Required. Name of the resource.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "privilegedaccessmanager.googleapis.com/Entitlement"
    }
  ];

  // Optional. An optional request ID to identify requests. Specify a unique
  // request ID so that if you must retry your request, the server knows to
  // ignore the request if it has already been completed. The server guarantees
  // this for at least 60 minutes after the first request.
  //
  // For example, consider a situation where you make an initial request and the
  // request times out. If you make the request again with the same request
  // ID, the server can check if original operation with the same request ID
  // was received, and if so, ignores the second request. This prevents
  // clients from accidentally creating duplicate commitments.
  //
  // The request ID must be a valid UUID with the exception that zero UUID is
  // not supported (00000000-0000-0000-0000-000000000000).
  string request_id = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. If set to true, any child grant under this entitlement is also
  // deleted. (Otherwise, the request only works if the entitlement has no child
  // grant.)
  bool force = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Message for updating an entitlement.
message UpdateEntitlementRequest {
  // Required. The entitlement resource that is updated.
  Entitlement entitlement = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The list of fields to update. A field is overwritten if, and only
  // if, it is in the mask. Any immutable fields set in the mask are ignored by
  // the server. Repeated fields and map fields are only allowed in the last
  // position of a `paths` string and overwrite the existing values. Hence an
  // update to a repeated field or a map should contain the entire list of
  // values. The fields specified in the update_mask are relative to the
  // resource and not to the request.
  // (e.g. `MaxRequestDuration`; *not* `entitlement.MaxRequestDuration`)
  // A value of '*' for this field refers to full replacement of the resource.
  google.protobuf.FieldMask update_mask = 2
      [(google.api.field_behavior) = REQUIRED];
}

// This is to ensure that the `Grants` and `ProducerGrants` proto are byte
// compatible.
// A grant represents a request from a user for obtaining the access specified
// in an entitlement they are eligible for.
message Grant {
  option (google.api.resource) = {
    type: "privilegedaccessmanager.googleapis.com/Grant"
    pattern: "projects/{project}/locations/{location}/entitlements/{entitlement}/grants/{grant}"
    pattern: "folders/{folder}/locations/{location}/entitlements/{entitlement}/grants/{grant}"
    pattern: "organizations/{organization}/locations/{location}/entitlements/{entitlement}/grants/{grant}"
    plural: "grants"
    singular: "grant"
  };

  // Timeline of a grant describing what happened to it and when.
  message Timeline {
    // A single operation on the grant.
    message Event {
      // An event representing that a grant was requested.
      message Requested {
        // Output only. The time at which this grant expires unless the approval
        // workflow completes. If omitted, then the request never expires.
        google.protobuf.Timestamp expire_time = 1
            [(google.api.field_behavior) = OUTPUT_ONLY];
      }

      // An event representing that the grant was approved.
      message Approved {
        // Output only. The reason provided by the approver for approving the
        // grant.
        string reason = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

        // Output only. Username of the user who approved the grant.
        string actor = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
      }

      // An event representing that the grant was denied.
      message Denied {
        // Output only. The reason provided by the approver for denying the
        // grant.
        string reason = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

        // Output only. Username of the user who denied the grant.
        string actor = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
      }

      // An event representing that the grant was revoked.
      message Revoked {
        // Output only. The reason provided by the user for revoking the grant.
        string reason = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

        // Output only. Username of the user who revoked the grant.
        string actor = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
      }

      // An event representing that the grant has been scheduled to be
      // activated later.
      message Scheduled {
        // Output only. The time at which the access is granted.
        google.protobuf.Timestamp scheduled_activation_time = 1
            [(google.api.field_behavior) = OUTPUT_ONLY];
      }

      // An event representing that the grant was successfully
      // activated.
      message Activated {}

      // An event representing that the grant activation failed.
      message ActivationFailed {
        // Output only. The error that occurred while activating the grant.
        google.rpc.Status error = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
      }

      // An event representing that the grant was expired.
      message Expired {}

      // An event representing that the grant has ended.
      message Ended {}

      // An event representing that the policy bindings made by this grant were
      // modified externally.
      message ExternallyModified {}

      oneof event {
        // The grant was requested.
        Requested requested = 2;

        // The grant was approved.
        Approved approved = 3;

        // The grant was denied.
        Denied denied = 4;

        // The grant was revoked.
        Revoked revoked = 5;

        // The grant has been scheduled to give access.
        Scheduled scheduled = 6;

        // The grant was successfully activated to give access.
        Activated activated = 7;

        // There was a non-retriable error while trying to give access.
        ActivationFailed activation_failed = 8;

        // The approval workflow did not complete in the necessary duration,
        // and so the grant is expired.
        Expired expired = 10;

        // Access given by the grant ended automatically as the approved
        // duration was over.
        Ended ended = 11;

        // The policy bindings made by grant have been modified outside of PAM.
        ExternallyModified externally_modified = 12;
      }

      // Output only. The time (as recorded at server) when this event occurred.
      google.protobuf.Timestamp event_time = 1
          [(google.api.field_behavior) = OUTPUT_ONLY];
    }

    // Output only. The events that have occurred on this grant. This list
    // contains entries in the same order as they occurred. The first entry is
    // always be of type `Requested` and there is always at least one entry in
    // this array.
    repeated Event events = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // Audit trail for the access provided by this grant.
  message AuditTrail {
    // Output only. The time at which access was given.
    google.protobuf.Timestamp access_grant_time = 1
        [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. The time at which the system removed access. This could be
    // because of an automatic expiry or because of a revocation.
    //
    // If unspecified, then access hasn't been removed yet.
    google.protobuf.Timestamp access_remove_time = 2
        [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // Different states a grant can be in.
  enum State {
    // Unspecified state. This value is never returned by the server.
    STATE_UNSPECIFIED = 0;

    // The entitlement had an approval workflow configured and this grant is
    // waiting for the workflow to complete.
    APPROVAL_AWAITED = 1;

    // The approval workflow completed with a denied result. No access is
    // granted for this grant. This is a terminal state.
    DENIED = 3;

    // The approval workflow completed successfully with an approved result or
    // none was configured. Access is provided at an appropriate time.
    SCHEDULED = 4;

    // Access is being given.
    ACTIVATING = 5;

    // Access was successfully given and is currently active.
    ACTIVE = 6;

    // The system could not give access due to a non-retriable error. This is a
    // terminal state.
    ACTIVATION_FAILED = 7;

    // Expired after waiting for the approval workflow to complete. This is a
    // terminal state.
    EXPIRED = 8;

    // Access is being revoked.
    REVOKING = 9;

    // Access was revoked by a user. This is a terminal state.
    REVOKED = 10;

    // System took back access as the requested duration was over. This is a
    // terminal state.
    ENDED = 11;
  }

  // Identifier. Name of this grant.
  // Possible formats:
  //
  // * `organizations/{organization-number}/locations/{region}/entitlements/{entitlement-id}/grants/{grant-id}`
  // * `folders/{folder-number}/locations/{region}/entitlements/{entitlement-id}/grants/{grant-id}`
  // * `projects/{project-id|project-number}/locations/{region}/entitlements/{entitlement-id}/grants/{grant-id}`
  //
  // The last segment of this name (`{grant-id}`) is autogenerated.
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. Create time stamp.
  google.protobuf.Timestamp create_time = 2
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Update time stamp.
  google.protobuf.Timestamp update_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Username of the user who created this grant.
  string requester = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Required. The amount of time access is needed for. This value should be
  // less than the `max_request_duration` value of the entitlement.
  google.protobuf.Duration requested_duration = 5
      [(google.api.field_behavior) = REQUIRED];

  // Optional. Justification of why this access is needed.
  Justification justification = 6 [(google.api.field_behavior) = OPTIONAL];

  // Output only. Current state of this grant.
  State state = 7 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Timeline of this grant.
  Timeline timeline = 8 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The access that would be granted by this grant.
  PrivilegedAccess privileged_access = 9
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Audit trail of access provided by this grant. If unspecified
  // then access was never granted.
  AuditTrail audit_trail = 10 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. Additional email addresses to notify for all the actions
  // performed on the grant.
  repeated string additional_email_recipients = 11
      [(google.api.field_behavior) = OPTIONAL];

  // Output only. Flag set by the PAM system to indicate that policy bindings
  // made by this grant have been modified from outside PAM.
  //
  // After it is set, this flag remains set forever irrespective of the grant
  // state. A `true` value here indicates that PAM no longer has any certainty
  // on the access a user has because of this grant.
  bool externally_modified = 12 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// Justification represents a justification for requesting access.
message Justification {
  oneof justification {
    // A free form textual justification. The system only ensures that this
    // is not empty. No other kind of validation is performed on the string.
    string unstructured_justification = 1;
  }
}

// Message for requesting list of grants.
message ListGrantsRequest {
  // Required. The parent resource which owns the grants.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "privilegedaccessmanager.googleapis.com/Grant"
    }
  ];

  // Optional. Requested page size. The server may return fewer items than
  // requested. If unspecified, the server picks an appropriate default.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A token identifying a page of results the server should return.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Filtering results.
  string filter = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Hint for how to order the results
  string order_by = 5 [(google.api.field_behavior) = OPTIONAL];
}

// Message for response to listing grants.
message ListGrantsResponse {
  // The list of grants.
  repeated Grant grants = 1;

  // A token identifying a page of results the server should return.
  string next_page_token = 2;

  // Locations that could not be reached.
  repeated string unreachable = 3;
}

// Request message for `SearchGrants` method.
message SearchGrantsRequest {
  // Different types of relationships a user can have with a grant.
  enum CallerRelationshipType {
    // Unspecified caller relationship type.
    CALLER_RELATIONSHIP_TYPE_UNSPECIFIED = 0;

    // The user created this grant by calling `CreateGrant` earlier.
    HAD_CREATED = 1;

    // The user is an approver for the entitlement that this grant is parented
    // under and can currently approve/deny it.
    CAN_APPROVE = 2;

    // The caller had successfully approved/denied this grant earlier.
    HAD_APPROVED = 3;
  }

  // Required. The parent which owns the grant resources.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "privilegedaccessmanager.googleapis.com/Grant"
    }
  ];

  // Required. Only grants which the caller is related to by this relationship
  // are returned in the response.
  CallerRelationshipType caller_relationship = 2
      [(google.api.field_behavior) = REQUIRED];

  // Optional. Only grants matching this filter are returned in the response.
  string filter = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Requested page size. The server may return fewer items than
  // requested. If unspecified, server picks an appropriate default.
  int32 page_size = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A token identifying a page of results the server should return.
  string page_token = 5 [(google.api.field_behavior) = OPTIONAL];
}

// Response message for `SearchGrants` method.
message SearchGrantsResponse {
  // The list of grants.
  repeated Grant grants = 1;

  // A token identifying a page of results the server should return.
  string next_page_token = 2;
}

// Message for getting a grant.
message GetGrantRequest {
  // Required. Name of the resource.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "privilegedaccessmanager.googleapis.com/Grant"
    }
  ];
}

// Request message for `ApproveGrant` method.
message ApproveGrantRequest {
  // Required. Name of the grant resource which is being approved.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "privilegedaccessmanager.googleapis.com/Grant"
    }
  ];

  // Optional. The reason for approving this grant. This is required if the
  // `require_approver_justification` field of the `ManualApprovals` workflow
  // used in this grant is true.
  string reason = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Request message for `DenyGrant` method.
message DenyGrantRequest {
  // Required. Name of the grant resource which is being denied.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "privilegedaccessmanager.googleapis.com/Grant"
    }
  ];

  // Optional. The reason for denying this grant. This is required if
  // `require_approver_justification` field of the `ManualApprovals` workflow
  // used in this grant is true.
  string reason = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Request message for `RevokeGrant` method.
message RevokeGrantRequest {
  // Required. Name of the grant resource which is being revoked.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "privilegedaccessmanager.googleapis.com/Grant"
    }
  ];

  // Optional. The reason for revoking this grant.
  string reason = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Message for creating a grant
message CreateGrantRequest {
  // Required. Name of the parent entitlement for which this grant is being
  // requested.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "privilegedaccessmanager.googleapis.com/Grant"
    }
  ];

  // Required. The resource being created.
  Grant grant = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. An optional request ID to identify requests. Specify a unique
  // request ID so that if you must retry your request, the server knows to
  // ignore the request if it has already been completed. The server guarantees
  // this for at least 60 minutes after the first request.
  //
  // For example, consider a situation where you make an initial request and the
  // request times out. If you make the request again with the same request
  // ID, the server can check if original operation with the same request ID
  // was received, and if so, ignores the second request. This prevents
  // clients from accidentally creating duplicate commitments.
  //
  // The request ID must be a valid UUID with the exception that zero UUID is
  // not supported (00000000-0000-0000-0000-000000000000).
  string request_id = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Represents the metadata of the long-running operation.
message OperationMetadata {
  // Output only. The time the operation was created.
  google.protobuf.Timestamp create_time = 1
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time the operation finished running.
  google.protobuf.Timestamp end_time = 2
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Server-defined resource path for the target of the operation.
  string target = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Name of the verb executed by the operation.
  string verb = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Human-readable status of the operation, if any.
  string status_message = 5 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Identifies whether the user has requested cancellation
  // of the operation. Operations that have been cancelled successfully
  // have [Operation.error][] value with a
  // [google.rpc.Status.code][google.rpc.Status.code] of 1, corresponding to
  // `Code.CANCELLED`.
  bool requested_cancellation = 6 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. API version used to start the operation.
  string api_version = 7 [(google.api.field_behavior) = OUTPUT_ONLY];
}
