feat(federation): enrollment controller + single-use token flow (FED-M2-07) (#497)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful

This commit was merged in pull request #497.
This commit is contained in:
2026-04-22 04:23:19 +00:00
parent 01dd6b9fa1
commit 0bfaa56e9e
10 changed files with 4202 additions and 3 deletions

View File

@@ -17,4 +17,5 @@ export {
federationPeers,
federationGrants,
federationAuditLog,
federationEnrollmentTokens,
} from './schema.js';

View File

@@ -778,3 +778,34 @@ export const federationAuditLog = pgTable(
index('federation_audit_log_created_at_idx').on(t.createdAt.desc()),
],
);
/**
* Single-use enrollment tokens — M2-07.
*
* An admin creates a token (with a TTL) and hands it out-of-band to the
* remote peer operator. The peer redeems it exactly once by posting its
* CSR to POST /api/federation/enrollment/:token. The token is atomically
* marked as used to prevent replay attacks.
*/
export const federationEnrollmentTokens = pgTable('federation_enrollment_tokens', {
/** 32-byte hex token — crypto.randomBytes(32).toString('hex') */
token: text('token').primaryKey(),
/** The federation grant this enrollment activates. */
grantId: uuid('grant_id')
.notNull()
.references(() => federationGrants.id, { onDelete: 'cascade' }),
/** The peer record that will be updated on successful enrollment. */
peerId: uuid('peer_id')
.notNull()
.references(() => federationPeers.id, { onDelete: 'cascade' }),
/** Hard expiry — token rejected after this time even if not used. */
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
/** NULL until the token is redeemed. Set atomically to prevent replay. */
usedAt: timestamp('used_at', { withTimezone: true }),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});