Skip to content

Bridge persistence and enrollment atomicity

The BridgePersistenceAdapter is the narrow PostgreSQL boundary for Bridge identity and enrollment state. The phase-1 authenticated HTTP enrollment transport in bridge_transport.py calls the adapter on the request-owned transaction connection. (The in-memory BridgeIdentityRegistry and BridgeEnrollmentService contracts that preceded it were never used by the server and have been removed.)

Stored data

The adapter stores only:

  • project and Bridge identity metadata;
  • lifecycle status and allowed account references;
  • challenge identifiers, public-key fingerprints, expiry and consumed time;
  • SHA-256 hashes of challenge nonces.
  • SHA-256 hashes of one-time bootstrap credentials and opaque Bridge tokens.

It never accepts or stores private keys, raw nonces, signatures, raw access tokens, or provider credential payloads. The transport verifies the Ed25519 proof before asking the adapter to activate a Bridge and inserts only the token hash in the same transaction.

Atomic activation

The enrollment proof route calls consume_and_activate_with_token_in_transaction on the request's own transaction connection, after the transport has verified the Ed25519 proof. In that one transaction it:

  1. locks the project-scoped Bridge identity with SELECT ... FOR UPDATE;
  2. locks the project-scoped challenge with SELECT ... FOR UPDATE;
  3. rejects missing, mismatched, revoked, non-pending, consumed or expired state;
  4. sets consumed_at exactly once;
  5. activates the pending identity with the account references stored on the challenge;
  6. inserts the hash of the new Bridge access token.

The route then binds the Bridge to the project in the same transaction. The request commits all of these together or none of them. If any step fails, the challenge stays unconsumed and the identity stays pending. A second request cannot consume the same challenge after the first successful activation because the identity is no longer pending and the row locks serialize concurrent transactions.

consume_and_activate is an older variant that owns its own transaction, takes the account references as an argument and mints no token. The server does not call it; only the adapter's tests do.

The adapter fences every lookup and update with project_id. A Bridge ID or challenge from another project is not visible through this contract. The bootstrap credential carries approved account references; the Bridge cannot choose those references in its request.

Migrations

013_bridge_identities.sql, 014_bridge_enrollment_challenges.sql and 015_bridge_enrollment_transport.sql hold this state. The server uses this adapter for every Bridge enrollment. The exact HTTP contract is documented in Bridge enrollment HTTP contract.