GoodMemGoodMem
ReferenceAPIgRPC API

Service Identity

Service Identity service API reference

Services

ServiceIdentityService Service

Manages workload service identities independently from credentials, grants, and roles.

Authentication: Every RPC requires gRPC metadata authorization: Bearer <api-key>.

Authorization Model:

  • Each RPC evaluates a typed operation against the target service identity or instance.
  • Role names are not interpreted by this service.
  • Creation is restricted to HUMAN request principals, including humans using an API key.

Global Errors: All RPCs may return DEADLINE_EXCEEDED, CANCELLED, UNAVAILABLE, RESOURCE_EXHAUSTED, or INTERNAL in addition to their operation-specific errors.

CreateServiceIdentity

Creates one service identity owned and created by the authenticated human request principal.

Type
Requestgoodmem.v1.CreateServiceIdentityRequest
Responsegoodmem.v1.ServiceIdentity

Auth: gRPC metadata authorization: Bearer <api-key>

Authorization Required: CREATE_SERVICE_IDENTITY on the proposed identity, with the authenticated human principal as its owner.

Request Behavior:

  • The request principal must be HUMAN, including a human authenticated through an API key.
  • display_name is required, nonblank, and globally unique, including among tombstones.
  • description is optional free-form text. The service applies no format or length rule beyond protobuf transport validity; an empty present value is treated as absent during creation.
  • labels are optional workload metadata and follow the documented label constraints.
  • The server generates service_identity_id when the caller omits it.
  • The initial API does not accept an owner override; use the transfer RPC after creation.

Response: The newly created ServiceIdentity, including ownership, lifecycle, and audit metadata. No credential material is returned.

Side Effects:

  • Atomically creates the durable SERVICE principal and service-identity profile.
  • Sets the authenticated human as both immutable creator and initial administrative owner.
  • Does not create an API key, role assignment, or direct grant.

Error Codes:

  • UNAUTHENTICATED: Missing or invalid authentication.
  • INVALID_ARGUMENT: Malformed UUID, blank or overlong display name, or invalid labels.
  • PERMISSION_DENIED: Request principal is not HUMAN or lacks creation authority.
  • ALREADY_EXISTS: The UUID or display name is already occupied.
  • INTERNAL: Unexpected server or database failure.

Idempotency: Not inherently idempotent. When a caller supplies service_identity_id, a retry after successful creation returns ALREADY_EXISTS because the UUID remains occupied.

Examples:

grpcurl -plaintext \
-H 'authorization: Bearer <api-key>' \
-d '{
"display_name": "production-search",
"description": "Production semantic-search workload",
"labels": { "environment": "production" }
}' \
localhost:8080 goodmem.v1.ServiceIdentityService/CreateServiceIdentity

GetServiceIdentity

Retrieves one service identity by UUID.

Type
Requestgoodmem.v1.GetServiceIdentityRequest
Responsegoodmem.v1.ServiceIdentity

Auth: gRPC metadata authorization: Bearer <api-key>

Authorization Required: READ_SERVICE_IDENTITY on the resolved service identity.

Request (Lookup Logic):

  • Resolves the exact service_identity_id supplied by the caller.
  • In protobuf JSON and grpcurl, the bytes-valued ID is base64-encoded.
  • Normal lookup excludes permanent tombstones.
  • include_deleted=true permits a tombstone to participate in lookup but grants no authority.
  • Existence is resolved before authorization, preserving NOT_FOUND before PERMISSION_DENIED.

Response: The resolved ServiceIdentity in the requested lifecycle view.

Side Effects: None; this is a read-only operation.

Error Codes:

  • UNAUTHENTICATED: Missing or invalid authentication.
  • INVALID_ARGUMENT: Malformed service-identity UUID.
  • NOT_FOUND: No identity exists in the requested lifecycle view.
  • PERMISSION_DENIED: Caller lacks READ_SERVICE_IDENTITY on the resolved identity.
  • INTERNAL: Unexpected server or database failure.

Idempotency: Read-only and safe to retry.

Examples:

grpcurl -plaintext \
-H 'authorization: Bearer <api-key>' \
-d '{ "service_identity_id": "BASE64_ENCODED_UUID" }' \
localhost:8080 goodmem.v1.ServiceIdentityService/GetServiceIdentity

ListServiceIdentities

Lists an authorization-filtered page of service identities.

Type
Requestgoodmem.v1.ListServiceIdentitiesRequest
Responsegoodmem.v1.ListServiceIdentitiesResponse

Auth: gRPC metadata authorization: Bearer <api-key>

Authorization Required:

  • LIST_SERVICE_IDENTITY on the singleton GoodMem instance; and
  • READ_SERVICE_IDENTITY on every identity returned in the page.

Request Behavior:

  • owner_principal_id optionally restricts results to one administrative owner.
  • label_selectors are combined with logical AND.
  • include_deleted=true adds tombstones to the candidate set but bypasses no authorization.
  • max_results defaults to 50 and may not exceed 1,000.
  • next_token is opaque and bound to the caller, authentication context, and stable filters.
  • Filtering, authorization, and keyset pagination execute in PostgreSQL.

Response: A ListServiceIdentitiesResponse ordered by ascending creation time and UUID. next_token is absent after the final page.

Side Effects: None; this is a read-only operation.

Error Codes:

  • UNAUTHENTICATED: Missing or invalid authentication.
  • INVALID_ARGUMENT: Invalid owner/filter UUID, labels, page size, or continuation token.
  • PERMISSION_DENIED: Caller lacks the instance-level collection gate.
  • INTERNAL: Unexpected server or database failure.

Idempotency: Read-only and safe to retry. Concurrent mutations may change later pages.

Examples:

grpcurl -plaintext \
-H 'authorization: Bearer <api-key>' \
-d '{ "label_selectors": { "environment": "production" }, "max_results": 50 }' \
localhost:8080 goodmem.v1.ServiceIdentityService/ListServiceIdentities

UpdateServiceIdentity

Updates mutable profile fields or labels of one active service identity.

Type
Requestgoodmem.v1.UpdateServiceIdentityRequest
Responsegoodmem.v1.ServiceIdentity

Auth: gRPC metadata authorization: Bearer <api-key>

Authorization Required: UPDATE_SERVICE_IDENTITY against the identity's current owner.

Request Behavior:

  • At least one mutable field or label strategy must be present.
  • A present blank display_name is invalid.
  • A present empty description clears that optional field; other values are free-form text with no application-level format or length rule.
  • replace_labels replaces the complete label map; merge_labels upserts supplied entries.
  • The two label strategies are mutually exclusive.
  • In protobuf JSON and grpcurl, the bytes-valued service_identity_id is base64-encoded.
  • Ownership is immutable through this RPC; use TransferServiceIdentityOwnership instead.
  • The final write rechecks authorization and active lifecycle state.

Response: The updated ServiceIdentity, including refreshed update-audit metadata.

Side Effects: Updates selected profile fields, labels, and update-audit metadata.

Error Codes (in precedence order):

  • UNAUTHENTICATED: Missing or invalid authentication.
  • INVALID_ARGUMENT: Malformed UUID, invalid/no-op mutation, or invalid labels.
  • NOT_FOUND: The service-identity UUID does not exist.
  • PERMISSION_DENIED: Caller lacks UPDATE_SERVICE_IDENTITY on the identity.
  • FAILED_PRECONDITION: The service identity is permanently deleted.
  • ALREADY_EXISTS: The replacement display name is already occupied.
  • ABORTED: A concurrent lifecycle or authorization change invalidated the final write.
  • INTERNAL: Unexpected server or database failure.

Idempotency: Repeating the same explicit values preserves the same profile state, although each successful call advances update-audit metadata.

Examples:

grpcurl -plaintext \
-H 'authorization: Bearer <api-key>' \
-d '{
"service_identity_id": "BASE64_ENCODED_UUID",
"description": "Updated production workload",
"merge_labels": { "labels": { "team": "search" } }
}' \
localhost:8080 goodmem.v1.ServiceIdentityService/UpdateServiceIdentity

DeleteServiceIdentity

Permanently soft-deletes one service identity.

Type
Requestgoodmem.v1.DeleteServiceIdentityRequest
Responsegoogle.protobuf.Empty

Auth: gRPC metadata authorization: Bearer <api-key>

Authorization Required: DELETE_SERVICE_IDENTITY against the identity's current owner.

Request Behavior:

  • The target must be an existing service principal.
  • In protobuf JSON and grpcurl, the bytes-valued service_identity_id is base64-encoded.
  • Deleting an already deleted service identity succeeds without changing its original tombstone or audit provenance.

Response: An empty protobuf message after the tombstone is committed.

Side Effects:

  • Atomically records the permanent principal tombstone and deleting audit actor.
  • Preserves the profile, credentials, roles, grants, and owned-resource columns for history.
  • Authentication rejects subject API keys after deletion without marking the keys revoked.

Error Codes (in precedence order):

  • UNAUTHENTICATED: Missing or invalid authentication.
  • INVALID_ARGUMENT: Malformed service-identity UUID.
  • NOT_FOUND: The service-identity UUID does not exist.
  • PERMISSION_DENIED: Caller lacks DELETE_SERVICE_IDENTITY on the identity.
  • ABORTED: A concurrent lifecycle or authorization change invalidated the final write.
  • INTERNAL: Unexpected server or database failure.

Idempotency: Authorized retries succeed without changing the original tombstone or its audit provenance.

Examples:

grpcurl -plaintext \
-H 'authorization: Bearer <api-key>' \
-d '{ "service_identity_id": "BASE64_ENCODED_UUID" }' \
localhost:8080 goodmem.v1.ServiceIdentityService/DeleteServiceIdentity

TransferServiceIdentityOwnership

Transfers administrative ownership to a different active HUMAN or SERVICE principal.

Type
Requestgoodmem.v1.TransferServiceIdentityOwnershipRequest
Responsegoodmem.v1.TransferServiceIdentityOwnershipResponse

Auth: gRPC metadata authorization: Bearer <api-key>

Authorization Required: Transfer authority derived from at least one of:

  • ownership of the active service identity;
  • ownership of the singleton GoodMem instance; or
  • TRANSFER_RESOURCE_OWNERSHIP authority covering the service identity.

Request and Validation Order:

  • Resolves the service identity before authorization, preserving NOT_FOUND before PERMISSION_DENIED for the target.
  • Authorizes transfer against the identity's current owner.
  • Resolves the destination only after target authorization to avoid disclosing principal data.
  • Requires a different, active HUMAN or SERVICE destination principal.
  • A service identity cannot be its own administrative owner.
  • In protobuf JSON and grpcurl, both bytes-valued UUID fields are base64-encoded.
  • Rechecks target lifecycle, ownership, and authorization in the final write.

Response: A TransferServiceIdentityOwnershipResponse containing the identity with its new administrative owner and refreshed update-audit metadata.

Side Effects:

  • Changes only owner_principal_id and update-audit fields.
  • Does not change the identity's subject UUID, creator, credentials, roles, grants, or lifecycle.

Error Codes:

  • UNAUTHENTICATED: Missing or invalid authentication.
  • INVALID_ARGUMENT: Malformed target or destination UUID.
  • NOT_FOUND: Target does not exist, or destination does not exist after target authorization.
  • PERMISSION_DENIED: Caller lacks transfer authority on the service identity.
  • FAILED_PRECONDITION: Target/destination is deleted, destination already owns the target, or the service identity itself was supplied as the destination.
  • ABORTED: A concurrent mutation invalidated the transfer transaction; the request may retry.
  • INTERNAL: Unexpected server or database failure.

Idempotency: A successful transfer changes ownership once. Repeating it with the same destination returns FAILED_PRECONDITION because that principal is already the owner.

Examples:

grpcurl -plaintext \
-H 'authorization: Bearer <api-key>' \
-d '{
"service_identity_id": "BASE64_ENCODED_SERVICE_IDENTITY_UUID",
"new_owner_principal_id": "BASE64_ENCODED_PRINCIPAL_UUID"
}' \
localhost:8080 \
goodmem.v1.ServiceIdentityService/TransferServiceIdentityOwnership

Messages

ServiceIdentity

A production workload backed by a durable SERVICE principal.

A service identity has one mutable administrative owner, but its authenticated subject UUID and immutable creator principal never change. Credentials, grants, and roles are separate resources and are never created or rewritten by this service. Deletion is a permanent tombstone transition.

All fields are OUTPUT_ONLY. Timestamps are UTC. Audit actor identifiers may name either a principal or the exact API key used for the mutation.

FieldTypeDescription
service_identity_idbytesOUTPUT_ONLY; UUID (16 bytes), immutable and permanently occupied after creation.
display_namestringOUTPUT_ONLY; globally unique, nonblank display name. Uniqueness includes tombstones.
descriptionstringOUTPUT_ONLY; optional operator description.
owner_principal_idbytesOUTPUT_ONLY; UUID (16 bytes) of the current owner; changed only by the transfer RPC.
creator_principal_idbytesOUTPUT_ONLY; UUID (16 bytes) of the HUMAN creator principal; immutable.
labels...v1.ServiceIdentity.LabelsEntryOUTPUT_ONLY; mutable labels; at most 20 entries with keys matching [a-z0-9._-].
created_atgoogle.protobuf.TimestampOUTPUT_ONLY; creation timestamp.
updated_atgoogle.protobuf.TimestampOUTPUT_ONLY; timestamp of the most recent profile, ownership, or lifecycle mutation.
created_by_idbytesOUTPUT_ONLY; exact audit actor UUID (16 bytes) that created the identity.
updated_by_idbytesOUTPUT_ONLY; exact audit actor UUID (16 bytes) responsible for the most recent mutation.
deleted_atgoogle.protobuf.TimestampOUTPUT_ONLY; permanent soft-deletion timestamp; absent while active.
deleted_by_idbytesOUTPUT_ONLY; exact actor UUID (16 bytes) that deleted the identity; absent while active.

ServiceIdentity.LabelsEntry

FieldTypeDescription
keystring
valuestring

CreateServiceIdentityRequest

Request to create a service identity without implicit security side effects.

FieldTypeDescription
service_identity_idbytesOptional client-provided UUID (16 bytes); the server generates one when absent.
display_namestringRequired globally unique, nonblank display name.
descriptionstringOptional free-form operator description; an empty present value is treated as absent.
labels...iceIdentityRequest.LabelsEntryOptional labels; at most 20 entries, keys/values at most 255 chars, keys [a-z0-9._-].

CreateServiceIdentityRequest.LabelsEntry

FieldTypeDescription
keystring
valuestring

GetServiceIdentityRequest

Request to get one service identity by UUID.

FieldTypeDescription
service_identity_idbytesRequired service-identity UUID (16 bytes).
include_deletedboolInclude a permanent tombstone in the lifecycle view; does not bypass authorization.

ListServiceIdentitiesRequest

Request for one stable, authorization-filtered service-identity page.

FieldTypeDescription
owner_principal_idbytesOptional exact administrative-owner UUID (16 bytes).
label_selectors...iesRequest.LabelSelectorsEntryConjunction of exact key/value matches against principal labels.
include_deletedboolInclude tombstones in the candidate lifecycle view; does not bypass authorization.
max_resultsint32Page size; defaults to 50 and must be between 1 and 1000 when present.
next_tokenstringOpaque continuation token returned by the preceding page.

ListServiceIdentitiesRequest.LabelSelectorsEntry

FieldTypeDescription
keystring
valuestring

ListServiceIdentitiesResponse

One stable page of readable service identities. All fields are OUTPUT_ONLY.

FieldTypeDescription
service_identitiesgoodmem.v1.ServiceIdentityOUTPUT_ONLY; identities ordered by creation timestamp and UUID using stable keyset ordering.
next_tokenstringOUTPUT_ONLY; opaque continuation token; absent after the final page.

ListServiceIdentitiesNextPageToken

Internal cursor encoded by the server; clients must treat public next_token strings as opaque.

FieldTypeDescription
requestor_idbytesAuthenticated request-principal UUID bound to the first page.
authenticating_api_key_idbytesExact authenticating API-key UUID, when API-key authentication was used.
owner_principal_idbytesAdministrative-owner filter bound to the first page.
label_selectors...tPageToken.LabelSelectorsEntryLabel filters bound to the first page.
include_deletedboolLifecycle filter bound to the first page.
last_created_atgoogle.protobuf.TimestampCreation timestamp of the final row returned by the preceding page.
last_service_identity_idbytesService-identity UUID of the final row returned by the preceding page.

ListServiceIdentitiesNextPageToken.LabelSelectorsEntry

FieldTypeDescription
keystring
valuestring

UpdateServiceIdentityRequest

Request to update mutable fields of one active service identity.

FieldTypeDescription
service_identity_idbytesRequired service-identity UUID (16 bytes).
display_namestringOptional replacement display name; a present empty or blank value is invalid.
descriptionstringOptional replacement description; a present empty value clears the description.
replace_labelsgoodmem.v1.StringMapReplace all labels; an empty map clears them.
merge_labelsgoodmem.v1.StringMapUpsert entries while preserving unmentioned labels; the final map must satisfy label limits.

DeleteServiceIdentityRequest

Request to permanently soft-delete a service identity.

FieldTypeDescription
service_identity_idbytesRequired service-identity UUID (16 bytes).

TransferServiceIdentityOwnershipRequest

Request to transfer service-identity administration to another active principal.

FieldTypeDescription
service_identity_idbytesRequired existing service-identity UUID (16 bytes).
new_owner_principal_idbytesRequired different, active HUMAN or SERVICE principal UUID (16 bytes); never the target itself.

TransferServiceIdentityOwnershipResponse

Result of one successful service-identity ownership transfer.

FieldTypeDescription
service_identitygoodmem.v1.ServiceIdentityOUTPUT_ONLY; updated service identity with the new administrative owner.