Secret API
Table of Contents
upsquad/secret/v1/secret.proto
DescribeRequest
DescribeRequest addresses one secret for metadata-only lookup.
| Field | Type | Label | Description |
|---|---|---|---|
| secret_id | string | The logical id of the secret to describe. |
DescribeResponse
DescribeResponse returns metadata-only fields for a named secret. The value field is deliberately absent; callers that attempt to add one are rejected by the CI grep-gate.
| Field | Type | Label | Description |
|---|---|---|---|
| secret_id | string | Logical id of the secret described. | |
| last_rotated_at | google.protobuf.Timestamp | UTC timestamp of the most recent rotation, or null when the secret has never been rotated. | |
| last_rotated_by | string | Actor principal id of the most recent rotate, or empty when the secret has never been rotated. | |
| last_rotated_by_clearance | int32 | Actor clearance at last rotation, or 0 when the secret has never been rotated. | |
| present | bool | True when the secret has a non-empty value stored in the backend. False when the secret has never been rotated or was removed. | |
| version_id | string | Opaque version tag (`sha256(value |
RotateRequest
RotateRequest carries the new plaintext secret value. The value field is scrubbed from all log lines and audit event payloads by the reflection-based RedactInterceptor (internal/secret/redact.go) BEFORE the request reaches any logger, tracer, or audit sink. Callers never put tenant_id in the request body — it is taken from the authenticated context, not from the wire.
| Field | Type | Label | Description |
|---|---|---|---|
| secret_id | string | The logical id of the secret, e.g. "hmac.signing_key", "scm.github.app_private_key". Stable across rotations — every rotate of the same secret reuses the same secret_id. L3 read clearance so the Describe widget can label the input; L5 edit clearance because changing the secret_id reference on a caveman form is a platform-operator action. | |
| value | bytes | The new plaintext value as opaque octets. HLD §2.3 locks bytes (not string) — secrets are binary (X25519 private keys, PEM blocks, signed tokens) and MUST NOT be forced through UTF-8 validation. Hard max 4096 bytes; larger payloads are rejected at the service boundary before any backend I/O. This field is scrubbed by the RedactInterceptor via the edit_clearance=L5 annotation — any future bytes field tagged L5 is scrubbed automatically. |
RotateResponse
RotateResponse returns metadata about the just-written secret. NEVER includes the value. All fields are L3-readable metadata — the widget labels (HLD §2.5) consume them.
| Field | Type | Label | Description |
|---|---|---|---|
| secret_id | string | Logical id of the secret that was rotated (echoed from the request). | |
| last_rotated_at | google.protobuf.Timestamp | UTC timestamp the rotation was committed to the backend. Renders in the widget label "Last rotated: {last_rotated_at} by …". | |
| last_rotated_by | string | Actor principal id (Clerk user id or platform-service id). Populated by the service layer at commit time from authctx.ClerkUserID(ctx); never trusted from the request body. | |
| last_rotated_by_clearance | int32 | Actor clearance at commit time (1..5 — mirrors the caveman ClearanceLevel enum ordinals; HLD §2.3 locks int32 on the wire). Populated by the service layer from authctx.ClearanceLevel(ctx). | |
| version_id | string | Opaque version identifier — `sha256(value |
SecretRef
SecretRef references a secret by id without carrying its value. Config protos embed this whenever a field carries a secret; the generator (LLD-3) emits the write-only Rotate widget whenever a field's type is SecretRef.
| Field | Type | Label | Description |
|---|---|---|---|
| secret_id | string | Logical id of the referenced secret. |
SecretWriteService
SecretWriteService manages named secrets with a write-only surface.
NO Get / View / Read / Reveal RPC is present or permitted. The CI grep-gate at .github/workflows/secret-grep-gate.yml rejects any PR that adds one (LLD-2 #766 §7 Definition of Done).
| Method Name | Request Type | Response Type | Description |
|---|---|---|---|
| Rotate | RotateRequest | RotateResponse | Rotate sets or rotates the value of a named secret for the caller's tenant. Clearance L5 required (enforced at the gateway interceptor AND in the service layer — defence in depth). The plaintext value is scrubbed from all logs, spans, and audit payloads by the reflection-based RedactInterceptor BEFORE any sink is written. |
| Describe | DescribeRequest | DescribeResponse | Describe returns metadata for a named secret (secret_id, last_rotated_at, last_rotated_by, last_rotated_by_clearance, version_id, presence). NEVER returns the value. Clearance L3 required (tenant admin + above). |
Scalar Value Types
| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
|---|---|---|---|---|---|---|---|---|
| double | double | double | float | float64 | double | float | Float | |
| float | float | float | float | float32 | float | float | Float | |
| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |
| uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |
| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |
| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |
| sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| bool | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass | |
| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |