// 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.bigquery.datapolicies.v2;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/iam/v1/iam_policy.proto";
import "google/iam/v1/policy.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";

option csharp_namespace = "Google.Cloud.BigQuery.DataPolicies.V2";
option go_package = "cloud.google.com/go/bigquery/datapolicies/apiv2/datapoliciespb;datapoliciespb";
option java_multiple_files = true;
option java_outer_classname = "DataPolicyProto";
option java_package = "com.google.cloud.bigquery.datapolicies.v2";
option php_namespace = "Google\\Cloud\\BigQuery\\DataPolicies\\V2";
option ruby_package = "Google::Cloud::Bigquery::DataPolicies::V2";
option (google.api.resource_definition) = {
  type: "datacatalog.googleapis.com/PolicyTag"
  pattern: "projects/{project}/locations/{location}/taxonomies/{taxonomy}/policyTags/{policy_tag}"
};
option (google.api.resource_definition) = {
  type: "bigquery.googleapis.com/Routine"
  pattern: "projects/{project}/datasets/{dataset}/routines/{routine}"
};

// Data Policy Service provides APIs for managing the BigQuery Data Policy.
service DataPolicyService {
  option (google.api.default_host) = "bigquerydatapolicy.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/bigquery,"
      "https://www.googleapis.com/auth/cloud-platform";

  // Creates a new data policy under a project with the given `data_policy_id`
  // (used as the display name), and data policy type.
  rpc CreateDataPolicy(CreateDataPolicyRequest) returns (DataPolicy) {
    option (google.api.http) = {
      post: "/v2/{parent=projects/*/locations/*}/dataPolicies"
      body: "*"
    };
    option (google.api.method_signature) = "parent,data_policy,data_policy_id";
  }

  // Adds new grantees to a data policy.
  // The new grantees will be added to the existing grantees.
  // If the request contains a duplicate grantee, the grantee will be ignored.
  // If the request contains a grantee that already exists, the grantee will be
  // ignored.
  rpc AddGrantees(AddGranteesRequest) returns (DataPolicy) {
    option (google.api.http) = {
      post: "/v2/{data_policy=projects/*/locations/*/dataPolicies/*}:addGrantees"
      body: "*"
    };
    option (google.api.method_signature) = "data_policy,grantees";
  }

  // Removes grantees from a data policy.
  // The grantees will be removed from the existing grantees.
  // If the request contains a grantee that does not exist, the grantee will be
  // ignored.
  rpc RemoveGrantees(RemoveGranteesRequest) returns (DataPolicy) {
    option (google.api.http) = {
      post: "/v2/{data_policy=projects/*/locations/*/dataPolicies/*}:removeGrantees"
      body: "*"
    };
    option (google.api.method_signature) = "data_policy,grantees";
  }

  // Updates the metadata for an existing data policy. The target data policy
  // can be specified by the resource name.
  rpc UpdateDataPolicy(UpdateDataPolicyRequest) returns (DataPolicy) {
    option (google.api.http) = {
      patch: "/v2/{data_policy.name=projects/*/locations/*/dataPolicies/*}"
      body: "data_policy"
    };
    option (google.api.method_signature) = "data_policy,update_mask";
  }

  // Deletes the data policy specified by its resource name.
  rpc DeleteDataPolicy(DeleteDataPolicyRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v2/{name=projects/*/locations/*/dataPolicies/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Gets the data policy specified by its resource name.
  rpc GetDataPolicy(GetDataPolicyRequest) returns (DataPolicy) {
    option (google.api.http) = {
      get: "/v2/{name=projects/*/locations/*/dataPolicies/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // List all of the data policies in the specified parent project.
  rpc ListDataPolicies(ListDataPoliciesRequest)
      returns (ListDataPoliciesResponse) {
    option (google.api.http) = {
      get: "/v2/{parent=projects/*/locations/*}/dataPolicies"
    };
    option (google.api.method_signature) = "parent";
  }

  // Gets the IAM policy for the specified data policy.
  rpc GetIamPolicy(google.iam.v1.GetIamPolicyRequest)
      returns (google.iam.v1.Policy) {
    option (google.api.http) = {
      post: "/v2/{resource=projects/*/locations/*/dataPolicies/*}:getIamPolicy"
      body: "*"
    };
  }

  // Sets the IAM policy for the specified data policy.
  rpc SetIamPolicy(google.iam.v1.SetIamPolicyRequest)
      returns (google.iam.v1.Policy) {
    option (google.api.http) = {
      post: "/v2/{resource=projects/*/locations/*/dataPolicies/*}:setIamPolicy"
      body: "*"
    };
  }

  // Returns the caller's permission on the specified data policy resource.
  rpc TestIamPermissions(google.iam.v1.TestIamPermissionsRequest)
      returns (google.iam.v1.TestIamPermissionsResponse) {
    option (google.api.http) = {
      post: "/v2/{resource=projects/*/locations/*/dataPolicies/*}:testIamPermissions"
      body: "*"
    };
  }
}

// Request message for the CreateDataPolicy method.
message CreateDataPolicyRequest {
  // Required. Resource name of the project that the data policy will belong to.
  // The format is `projects/{project_number}/locations/{location_id}`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "bigquerydatapolicy.googleapis.com/DataPolicy"
    }
  ];

  // Required. User-assigned (human readable) ID of the data policy that needs
  // to be unique within a project. Used as {data_policy_id} in part of the
  // resource name.
  string data_policy_id = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The data policy to create. The `name` field does not need to be
  // provided for the data policy creation.
  DataPolicy data_policy = 3 [(google.api.field_behavior) = REQUIRED];
}

// Request message for the UpdateDataPolicy method.
message UpdateDataPolicyRequest {
  // Required. Update the data policy's metadata.
  //
  // The target data policy is determined by the `name` field.
  // Other fields are updated to the specified values based on the field masks.
  DataPolicy data_policy = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. The update mask applies to the resource. For the `FieldMask`
  // definition, see
  // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask
  // If not set, defaults to all of the fields that are allowed to update.
  //
  // Updates to the `name` and `dataPolicyId` fields are not allowed.
  google.protobuf.FieldMask update_mask = 2
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. If set to true, and the data policy is not found, a new data
  // policy will be created. In this situation, update_mask is ignored.
  bool allow_missing = 3 [(google.api.field_behavior) = OPTIONAL];
}

// Request message for the AddGrantees method.
message AddGranteesRequest {
  // Required. Resource name of this data policy, in the format of
  // `projects/{project_number}/locations/{location_id}/dataPolicies/{data_policy_id}`.
  string data_policy = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "bigquerydatapolicy.googleapis.com/DataPolicy"
    }
  ];

  // Required. IAM principal that should be granted Fine Grained Access to the
  // underlying data goverened by the data policy. The target data policy is
  // determined by the `data_policy` field.
  //
  // Uses the [IAM V2 principal
  // syntax](https://cloud.google.com/iam/docs/principal-identifiers#v2).
  // Supported principal types:
  //
  // * User
  // * Group
  // * Service account
  repeated string grantees = 2 [(google.api.field_behavior) = REQUIRED];
}

// Request message for the RemoveGrantees method.
message RemoveGranteesRequest {
  // Required. Resource name of this data policy, in the format of
  // `projects/{project_number}/locations/{location_id}/dataPolicies/{data_policy_id}`.
  string data_policy = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "bigquerydatapolicy.googleapis.com/DataPolicy"
    }
  ];

  // Required. IAM principal that should be revoked from Fine Grained Access to
  // the underlying data goverened by the data policy. The target data policy is
  // determined by the `data_policy` field.
  //
  // Uses the [IAM V2 principal
  // syntax](https://cloud.google.com/iam/docs/principal-identifiers#v2).
  // Supported principal types:
  //
  // * User
  // * Group
  // * Service account
  repeated string grantees = 2 [(google.api.field_behavior) = REQUIRED];
}

// Request message for the DeleteDataPolicy method.
message DeleteDataPolicyRequest {
  // Required. Resource name of the data policy to delete. Format is
  // `projects/{project_number}/locations/{location_id}/dataPolicies/{id}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "bigquerydatapolicy.googleapis.com/DataPolicy"
    }
  ];
}

// Request message for the GetDataPolicy method.
message GetDataPolicyRequest {
  // Required. Resource name of the requested data policy. Format is
  // `projects/{project_number}/locations/{location_id}/dataPolicies/{id}`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "bigquerydatapolicy.googleapis.com/DataPolicy"
    }
  ];
}

// Request message for the ListDataPolicies method.
message ListDataPoliciesRequest {
  // Required. Resource name of the project for which to list data policies.
  // Format is `projects/{project_number}/locations/{location_id}`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "bigquerydatapolicy.googleapis.com/DataPolicy"
    }
  ];

  // Optional. The maximum number of data policies to return. Must be a value
  // between 1 and 1000. If not set, defaults to 50.
  int32 page_size = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The `nextPageToken` value returned from a previous list request,
  // if any. If not set, defaults to an empty string.
  string page_token = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Filters the data policies by policy tags that they
  // are associated with. Currently filter only supports
  // "policy_tag" based filtering and OR based predicates. Sample
  // filter can be "policy_tag:
  // projects/1/locations/us/taxonomies/2/policyTags/3".
  // You may also use wildcard such as "policy_tag:
  // projects/1/locations/us/taxonomies/2*". Please note that OR predicates
  // cannot be used with wildcard filters.
  string filter = 4 [(google.api.field_behavior) = OPTIONAL];
}

// Response message for the ListDataPolicies method.
message ListDataPoliciesResponse {
  // Data policies that belong to the requested project.
  repeated DataPolicy data_policies = 1;

  // Token used to retrieve the next page of results, or empty if there are no
  // more results.
  string next_page_token = 2;
}

// Represents the label-policy binding.
message DataPolicy {
  option (google.api.resource) = {
    type: "bigquerydatapolicy.googleapis.com/DataPolicy"
    pattern: "projects/{project}/locations/{location}/dataPolicies/{data_policy}"
    plural: "dataPolicies"
    singular: "dataPolicy"
  };

  // A list of supported data policy types.
  enum DataPolicyType {
    // Default value for the data policy type. This should not be used.
    DATA_POLICY_TYPE_UNSPECIFIED = 0;

    // Used to create a data policy for data masking.
    DATA_MASKING_POLICY = 1;

    // Used to create a data policy for raw data access.
    RAW_DATA_ACCESS_POLICY = 2;

    // Used to create a data policy for column-level security, without data
    // masking. This is deprecated in V2 api and only present to support GET and
    // LIST operations for V1 data policies in V2 api.
    COLUMN_LEVEL_SECURITY_POLICY = 3;
  }

  // The supported versions for the Data Policy resource.
  enum Version {
    // Default value for the data policy version. This should not be used.
    VERSION_UNSPECIFIED = 0;

    // V1 data policy version. V1 Data Policies will be present in V2 List api
    // response, but can not be created/updated/deleted from V2 api.
    V1 = 1;

    // V2 data policy version.
    V2 = 2;
  }

  // The policy that is bound to this data policy.
  oneof policy {
    // Optional. The data masking policy that specifies the data masking rule to
    // use. It must be set if the data policy type is DATA_MASKING_POLICY.
    DataMaskingPolicy data_masking_policy = 7
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Identifier. Resource name of this data policy, in the format of
  // `projects/{project_number}/locations/{location_id}/dataPolicies/{data_policy_id}`.
  string name = 1 [(google.api.field_behavior) = IDENTIFIER];

  // Output only. User-assigned (human readable) ID of the data policy that
  // needs to be unique within a project. Used as {data_policy_id} in part of
  // the resource name.
  string data_policy_id = 2 [(google.api.field_behavior) = OUTPUT_ONLY];

  // The etag for this Data Policy.
  // This field is used for UpdateDataPolicy calls. If Data Policy exists, this
  // field is required and must match the server's etag. It will also be
  // populated in the response of GetDataPolicy, CreateDataPolicy, and
  // UpdateDataPolicy calls.
  optional string etag = 11;

  // Required. Type of data policy.
  DataPolicyType data_policy_type = 3 [(google.api.field_behavior) = REQUIRED];

  // Output only. Policy tag resource name, in the format of
  // `projects/{project_number}/locations/{location_id}/taxonomies/{taxonomy_id}/policyTags/{policyTag_id}`.
  // policy_tag is supported only for V1 data policies.
  string policy_tag = 4 [
    (google.api.field_behavior) = OUTPUT_ONLY,
    (google.api.resource_reference) = {
      type: "datacatalog.googleapis.com/PolicyTag"
    }
  ];

  // Optional. The list of IAM principals that have Fine Grained Access to the
  // underlying data goverened by this data policy.
  //
  // Uses the [IAM V2 principal
  // syntax](https://cloud.google.com/iam/docs/principal-identifiers#v2) Only
  // supports principal types users, groups, serviceaccounts, cloudidentity.
  // This field is supported in V2 Data Policy only. In case of V1 data policies
  // (i.e. verion = 1 and policy_tag is set), this field is not populated.
  repeated string grantees = 8 [(google.api.field_behavior) = OPTIONAL];

  // Output only. The version of the Data Policy resource.
  Version version = 9 [(google.api.field_behavior) = OUTPUT_ONLY];
}

// The policy used to specify data masking rule.
message DataMaskingPolicy {
  // The available masking rules. Learn more here:
  // https://cloud.google.com/bigquery/docs/column-data-masking-intro#masking_options.
  enum PredefinedExpression {
    // Default, unspecified predefined expression. No masking will take place
    // since no expression is specified.
    PREDEFINED_EXPRESSION_UNSPECIFIED = 0;

    // Masking expression to replace data with SHA-256 hash.
    SHA256 = 1;

    // Masking expression to replace data with NULLs.
    ALWAYS_NULL = 2;

    // Masking expression to replace data with their default masking values.
    // The default masking values for each type listed as below:
    //
    // * STRING: ""
    // * BYTES: b''
    // * INTEGER: 0
    // * FLOAT: 0.0
    // * NUMERIC: 0
    // * BOOLEAN: FALSE
    // * TIMESTAMP: 1970-01-01 00:00:00 UTC
    // * DATE: 1970-01-01
    // * TIME: 00:00:00
    // * DATETIME: 1970-01-01T00:00:00
    // * GEOGRAPHY: POINT(0 0)
    // * BIGNUMERIC: 0
    // * ARRAY: []
    // * STRUCT: NOT_APPLICABLE
    // * JSON: NULL
    DEFAULT_MASKING_VALUE = 3;

    // Masking expression shows the last four characters of text.
    // The masking behavior is as follows:
    //
    // * If text length > 4 characters: Replace text with XXXXX, append last
    // four characters of original text.
    // * If text length <= 4 characters: Apply SHA-256 hash.
    LAST_FOUR_CHARACTERS = 4;

    // Masking expression shows the first four characters of text.
    // The masking behavior is as follows:
    //
    // * If text length > 4 characters: Replace text with XXXXX, prepend first
    // four characters of original text.
    // * If text length <= 4 characters: Apply SHA-256 hash.
    FIRST_FOUR_CHARACTERS = 5;

    // Masking expression for email addresses.
    // The masking behavior is as follows:
    //
    // * Syntax-valid email address: Replace username with XXXXX. For example,
    // cloudysanfrancisco@gmail.com becomes XXXXX@gmail.com.
    // * Syntax-invalid email address: Apply SHA-256 hash.
    //
    // For more information, see [Email
    // mask](https://cloud.google.com/bigquery/docs/column-data-masking-intro#masking_options).
    EMAIL_MASK = 6;

    // Masking expression to only show the <i>year</i> of `Date`,
    // `DateTime` and `TimeStamp`. For example, with the
    // year 2076:
    //
    // * DATE         :  2076-01-01
    // * DATETIME     :  2076-01-01T00:00:00
    // * TIMESTAMP    :  2076-01-01 00:00:00 UTC
    //
    // Truncation occurs according to the UTC time zone. To change this, adjust
    // the default time zone using the `time_zone` system variable.
    // For more information, see [System variables
    // reference](https://cloud.google.com/bigquery/docs/reference/system-variables).
    DATE_YEAR_MASK = 7;

    // Masking expression that uses hashing to mask column data.
    // It differs from SHA256 in that a unique random value is generated for
    // each query and is added to the hash input, resulting in the hash / masked
    // result to be different for each query. Hence the name "random hash".
    RANDOM_HASH = 8;
  }

  // A masking expression to bind to the data masking rule.
  oneof masking_expression {
    // Optional. A predefined masking expression.
    PredefinedExpression predefined_expression = 1
        [(google.api.field_behavior) = OPTIONAL];

    // Optional. The name of the BigQuery routine that contains the custom
    // masking routine, in the format of
    // `projects/{project_number}/datasets/{dataset_id}/routines/{routine_id}`.
    string routine = 2 [
      (google.api.field_behavior) = OPTIONAL,
      (google.api.resource_reference) = {
        type: "bigquery.googleapis.com/Routine"
      }
    ];
  }
}
