Govern deploy enrollment durability

Record the bootstrap-to-runtime credential replacement as one durable transition across API, agent lifecycle, security, and storage contracts. Document rollback, replay, and no-secret-on-failure guarantees proved by the deploy handler suite.\n\nChange-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-08-27 19:02:03 +01:00
parent e1d05e7b12
commit cbcd27b4a8
4 changed files with 62 additions and 0 deletions
@@ -6674,3 +6674,22 @@ or re-enrollment authority. Its liveness marker observes only whether the
monitor select loop is progressing; agent report success or failure cannot
independently assert that Pulse is healthy. Agent-lifecycle behavior and proof
routes remain unchanged.
### Deploy enrollment swaps credentials as one durable transition
A deploy bootstrap token remains the live credential until Pulse can durably
replace it with the long-lived, host-bound runtime token. Enrollment prepares
the runtime credential first, then removes the single-use bootstrap token and
adds the runtime token under one configuration lock and one persistence write.
Concurrent reuse loses the locked removal and returns `409`; persistence
failure restores the complete prior token inventory and primary-token
projection, returns `500`, discloses no runtime credential, and leaves the
target enrolling so the same bootstrap credential can be retried safely.
Bootstrap minting follows the same commit boundary: a token is returned only
after its updated inventory is durably stored, and a failed write restores the
prior live inventory. `TestHandleEnroll_Success`,
`TestHandleEnroll_RollsBackBootstrapConsumptionWhenPersistenceFails`, and
`TestMintBootstrapTokenForTarget_RollsBackWhenPersistenceFails` in
`internal/api/deploy_handlers_test.go` pin the durable replacement and rollback
paths.
@@ -9965,3 +9965,21 @@ failure count, sanitized error, and last interruption. It never returns the
URL or endpoint fingerprint. A saved configuration that cannot be decrypted is
`configuration_unavailable`, while explicit removal is immediately `disabled`
even if cancellation of an older request is still unwinding.
### Deploy enrollment reports only committed credentials
`POST /api/agents/agent/enroll` returns a long-lived runtime token only after
the authenticated single-use bootstrap token has been replaced in the durable
API-token inventory. The replacement is one locked persistence transition;
another request that already consumed the bootstrap token receives the stable
`409 token_already_consumed` response. If persistence fails, the API restores
the complete prior inventory and legacy primary-token projection, returns
`500 token_persistence_error`, emits no runtime token, and does not advance the
deployment target from `ENROLLING` to `VERIFYING`.
The internal bootstrap-mint boundary likewise returns no raw token or token ID
when persistence fails. `TestHandleEnroll_Success`,
`TestHandleEnroll_RollsBackBootstrapConsumptionWhenPersistenceFails`, and
`TestMintBootstrapTokenForTarget_RollsBackWhenPersistenceFails` in
`internal/api/deploy_handlers_test.go` prove the persisted success state and
both failed-commit responses.
@@ -2356,3 +2356,15 @@ tokens and primary-token projection, emits only a failed `token_deleted` audit
event, and returns an error; a successful response identifies a deletion that
will survive restart. Exact multi-token removal and persistence-failure
rollback are exercised in `internal/api/security_tokens_lifecycle_test.go`.
### Deploy enrollment never exposes an uncommitted credential
The deploy bootstrap secret is single-use only at the durable API-token commit
boundary. Pulse generates the host-bound runtime credential without admitting
or returning it, then replaces the bootstrap record under one lock and persists
the resulting inventory once. A concurrent replay cannot pass the locked
removal. A failed persistence write restores the complete prior inventory and
primary-token projection, returns an error, and discloses no runtime secret;
failed bootstrap minting likewise returns no credential material. The success,
replay, and forced-write-failure paths are exercised in
`internal/api/deploy_handlers_test.go`.
@@ -5642,3 +5642,16 @@ whose atomic/fsync discipline ensures a later process can report a Pulse
monitoring gap; it contains endpoint fingerprint and timing only. Configuration
export/import carries the watchdog URL solely inside the existing
passphrase-encrypted bundle and advances that bundle contract to version 4.4.
### Deploy credential replacement preserves restart-time truth
The shared deploy enrollment path treats the persisted API-token inventory as
the commit boundary when exchanging a bootstrap token for a runtime token. One
locked write records the replacement; a failed write restores the complete
prior inventory and primary-token projection, returns no new credential, and
leaves the deployment target retryable. Bootstrap minting also restores live
state and returns no token if its inventory write fails. These transitions add
no backup, restore, retention, snapshot, or recovery authority; they prevent a
successful enrollment response from describing credential state that a restart
would undo. Their success and forced-write-failure proofs live in
`internal/api/deploy_handlers_test.go`.