// This proto file was generated from secrets-service-api.yml.
// Care should be taken while both files exist to maintain backwards compatibility with the Conjure generated code.

syntax = "proto3";

package nominal.secrets.v1;

import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
import "nominal/protos/conjure/v1/compat.proto";
import "nominal/protos/gen/v1/alias.proto";
import "nominal/protos/gen/v1/error.proto";
import "nominal/protos/types/types.proto";

option java_multiple_files = true;
option java_package = "io.nominal.secrets.v1";

message CreateSecretRequest {
  string name = 1;

  string description = 2;

  // SENSITIVE: cleartext secret. The Conjure field was `safety: do-not-log`; proto3 has no equivalent, so never log
  // this value or serialize this message into a log/error payload.
  string decrypted_value = 3;

  map<string, string> properties = 4 [(nominal.gen.v1.alias) = {
    key_java_name: "io.nominal.api.PropertyName"
    value_java_name: "io.nominal.api.PropertyValue"
  }];

  repeated string labels = 5 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Label"}];

  // The workspace in which to create the secret. If not provided, the secret will be created in
  // the default workspace for the user's organization, if the default workspace for the
  // organization is configured.
  optional string workspace = 6 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.WorkspaceRid"}];
}

message GetSecretsRequest {
  repeated string secret_rids = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.secrets.api.SecretRid"}];
}

message GetSecretsResponse {
  repeated Secret response = 1;
}

message SearchSecretsQuery {
  option (nominal.conjure.v1.conjure_compat) = {union_message: true};

  optional string search_text = 1;

  optional string label = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Label"}];

  optional nominal.types.Property property = 3;

  repeated SearchSecretsQuery and = 4;

  repeated SearchSecretsQuery or = 5;

  optional string workspace = 6 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.rids.WorkspaceRid"}];
}

message SearchSecretsRequest {
  SearchSecretsQuery query = 1;

  // Defaults to 100. Will throw if larger than 1000.
  optional int32 page_size = 2;

  SortOptions sort = 3;

  optional string token = 4 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Token"}];

  // Default search status is NOT_ARCHIVED if none are provided. Allows for including archived secrets in search.
  repeated nominal.types.ArchivedStatus archived_statuses = 5;
}

message SearchSecretsResponse {
  repeated Secret results = 1;

  optional string next_page_token = 2 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Token"}];
}

message Secret {
  string rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.secrets.api.SecretRid"}];

  string name = 2;

  string description = 3;

  string created_by = 4 [(nominal.gen.v1.alias) = {java_name: "com.palantir.ri.ResourceIdentifier"}];

  map<string, string> properties = 5 [(nominal.gen.v1.alias) = {
    key_java_name: "io.nominal.api.PropertyName"
    value_java_name: "io.nominal.api.PropertyValue"
  }];

  repeated string labels = 6 [(nominal.gen.v1.alias) = {java_name: "io.nominal.api.Label"}];

  google.protobuf.Timestamp created_at = 7;

  bool is_archived = 8;
}

// buf:lint:ignore ENUM_VALUE_PREFIX
enum SortField {
  SORT_FIELD_UNSPECIFIED = 0;
  CREATED_AT = 1;
}

message SortOptions {
  bool is_descending = 1;

  SortField field = 2;
}

message UpdateSecretRequest {
  optional string name = 1;

  optional string description = 2;

  // Wrapped in optional message types so an explicitly-provided empty map/set (clear all) is
  // distinguishable from an absent field (leave untouched), matching the Conjure
  // optional<map>/optional<set> semantics. A bare proto3 map/repeated cannot express that presence.
  optional nominal.types.PropertyUpdateWrapper properties = 3 [(nominal.conjure.v1.conjure_field_compat) = {single_field_wrapper: true}];

  optional nominal.types.LabelUpdateWrapper labels = 4 [(nominal.conjure.v1.conjure_field_compat) = {single_field_wrapper: true}];

  // SENSITIVE: cleartext secret. The Conjure field was `safety: do-not-log`; proto3 has no equivalent, so never log
  // this value or serialize this message into a log/error payload.
  optional string decrypted_value = 5;
}

message CreateResponse {
  Secret secret = 1;
}

message GetRequest {
  string rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.secrets.api.SecretRid"}];
}

message GetResponse {
  Secret secret = 1;
}

message UpdateRequest {
  string rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.secrets.api.SecretRid"}];

  UpdateSecretRequest request = 2;
}

message UpdateResponse {
  Secret secret = 1;
}

message DeleteRequest {
  string rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.secrets.api.SecretRid"}];
}

message DeleteResponse {}

message ArchiveRequest {
  string rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.secrets.api.SecretRid"}];
}

message ArchiveResponse {}

message UnarchiveRequest {
  string rid = 1 [(nominal.gen.v1.alias) = {java_name: "io.nominal.secrets.api.SecretRid"}];
}

message UnarchiveResponse {}

// buf:lint:ignore ENUM_ZERO_VALUE_SUFFIX
enum SecretsError {
  SECRETS_ERROR_SECRET_NOT_FOUND = 0 [(nominal.gen.v1.error) = {
    code: "NOT_FOUND"
    message: "SecretNotFound"
  }];
  SECRETS_ERROR_SECRETS_NOT_FOUND = 1 [(nominal.gen.v1.error) = {
    code: "NOT_FOUND"
    message: "SecretsNotFound"
  }];
  SECRETS_ERROR_UNABLE_TO_ENCRYPT_SECRET = 2 [(nominal.gen.v1.error) = {
    code: "FAILED_PRECONDITION"
    message: "UnableToEncryptSecret"
  }];
  SECRETS_ERROR_INVALID_ARGUMENT = 3 [(nominal.gen.v1.error) = {
    code: "INVALID_ARGUMENT"
    message: "InvalidArgument"
  }];
}

// The secrets service provides functionality for creating and retrieving customer secrets (e.g. influx passwords, API keys, etc)
service SecretService {
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // Create a new secret.
  rpc Create(CreateSecretRequest) returns (CreateResponse) {
    option (google.api.http) = {
      post: "/secrets/v1/secrets"
      response_body: "secret"
      body: "*"
    };
  }
  // Get secret by rid.
  rpc Get(GetRequest) returns (GetResponse) {
    option (google.api.http) = {
      get: "/secrets/v1/secrets/{rid}"
      response_body: "secret"
    };
  }
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
  // Get secrets by a set of rids.
  rpc GetBatch(GetSecretsRequest) returns (GetSecretsResponse) {
    option (google.api.http) = {
      post: "/secrets/v1/secrets/batch"
      body: "*"
    };
  }
  // Update a secret by rid.
  rpc Update(UpdateRequest) returns (UpdateResponse) {
    option (google.api.http) = {
      response_body: "secret"
      body: "request"
      put: "/secrets/v1/secrets/{rid}"
    };
  }
  // Delete a secret by rid. This is a permanent deletion. To perform a soft delete,
  // use the archive endpoint.
  rpc Delete(DeleteRequest) returns (DeleteResponse) {
    option (google.api.http) = {delete: "/secrets/v1/secrets/{rid}"};
  }
  // Archive a secret by rid.
  rpc Archive(ArchiveRequest) returns (ArchiveResponse) {
    option (google.api.http) = {put: "/secrets/v1/secrets/{rid}/archive"};
  }
  // Unarchive a secret by rid.
  rpc Unarchive(UnarchiveRequest) returns (UnarchiveResponse) {
    option (google.api.http) = {put: "/secrets/v1/secrets/{rid}/unarchive"};
  }
  // buf:lint:ignore RPC_REQUEST_STANDARD_NAME
  // buf:lint:ignore RPC_RESPONSE_STANDARD_NAME
  // Returns metadata about secrets that match a given query.
  rpc Search(SearchSecretsRequest) returns (SearchSecretsResponse) {
    option (google.api.http) = {
      post: "/secrets/v1/secrets/search"
      body: "*"
    };
  }
}
