Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ jobs:
TSK_TEST_RECEIVER_PG_URL_B: postgresql://tsk_test:tsk-test-only-password@127.0.0.1:5433/tsk_test
TSK_TEST_CONTROL_PG_URL: postgresql://tsk_test:tsk-test-only-password@127.0.0.1:5434/tsk_test
TSK_TEST_REDIS_URL: redis://127.0.0.1:6379
# Governed OFFLINE control-schema v1->v2 migration: exact v1 catalog+stamp
# attestation, signed legacy activation preservation, atomic conversion, and
# fail-closed rollback on corrupt legacy authority. Real control PG16; no skip.
- run: npm run test:ha-control-migration
env:
TSK_TEST_CONTROL_PG_URL: postgresql://tsk_test:tsk-test-only-password@127.0.0.1:5434/tsk_test
- run: npm run test:ha-control-continuity -w packages/server
# Enterprise credential authority: every TumblerMapStore mutation commits its
# authoritative map change and a secret-free signed TSK record in one
# SERIALIZABLE source-A transaction. Independent B verifies the head chain,
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@

### Security

- Made source activation a signed, append-only head/history chain so repeated
promotions on one stream cannot overwrite or replay an earlier activation.
- Added governed return-site activation: a returning target supplies its exact
signed, terminal lease high-water and receives the next guard-signed lease
transition instead of an un-installable second genesis grant. Control schema
version 2 is intentionally required for this history-bearing layout.
- Added an owned, crash-atomic receiver-to-source activation authority that
rebuilds only persisted finalized staging, re-verifies both export signatures
and the complete ledger, then installs rows, fence, checkpoint, and lease in
one serializable target transaction. Manual multi-transaction import is not
an activation path.
- Closed numeric HOTP rollover paths across core derivation, lookahead, atomic
stores, client persistence, and replica input. Wire v1 now commits MAX only as
an exhausted sentinel and never writes or derives MAX+1.
Expand Down
2 changes: 2 additions & 0 deletions package-boundary-suite.mts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ for (const workspace of workspaces) {
for (const sym of ['NodePostgresTransactor', 'AmbiguousCommitError', 'PostCommitReleaseError', 'ConnectionDisposalError']) {
assert(typeof (exports as Record<string, unknown>)[sym] === 'function', `@tsk/server must export ${sym}`);
}
assert(typeof (exports as Record<string, unknown>).activateFinalizedReceiverAsSource === 'function',
'@tsk/server must export the owned atomic receiver-to-source activation authority');
for (const sym of ['PgHaTumblerMapStore', 'PgTskCredentialReceiverCheckpoint',
'assertCredentialAuthorityReady', 'provisionCredentialRuntimeMutationBoundary',
'assertCredentialRuntimeMutationBoundary', 'HmacCredentialMutationTicketSigner']) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"test:control-cutover": "npm run build -w packages/server && npx tsx tsk-control-cutover-drill.mts",
"test:sigkill": "npm run build -w packages/server && npx tsx tsk-cutover-sigkill-drill.mts",
"test:b-activation": "npm run build -w packages/server && npx tsx tsk-b-activation-drill.mts",
"test:ha-control-migration": "npm run build -w packages/server && npx tsx tsk-ha-control-migration-drill.mts",
"test:sentinel": "npm run build -w packages/server && bash ci/redis-sentinel/run.sh tsk-ha-sentinel-drill.mts",
"test:partition": "npm run build -w packages/server && bash ci/redis-sentinel/run.sh tsk-ha-partition-drill.mts",
"test:two-node": "npm run build -w packages/server && npx tsx tsk-two-node-drill.mts",
Expand Down
1 change: 1 addition & 0 deletions packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"test:hotp-outbox": "vitest run tests/tsk-hotp-outbox-pg.test.ts",
"test:pg-transactor": "vitest run tests/tsk-pg-transactor.test.ts",
"test:http-outbox": "vitest run tests/http-outbox-transport.test.ts",
"test:ha-control-continuity": "npx vitest run tests/ha-control-activation-continuity.test.ts",
"typecheck:contract": "tsc --noEmit -p tsconfig.contract-typecheck.json"
},
"dependencies": {
Expand Down
507 changes: 458 additions & 49 deletions packages/server/src/ha-control-fencing.ts

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions packages/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export {
StreamHeadVerificationUnavailableError,
PgTskDurableOutbox,
UnfencedSingleNodeTskDurableOutbox,
activateFinalizedReceiverAsSource,
PgTskPublisher,
PgTskReceiverCheckpoint,
schemaManifest,
Expand Down Expand Up @@ -54,6 +55,7 @@ export type {
TskOutboxTransport,
HotpApplier,
PgTskOutboxOptions,
ImportedSourceActivationOptions,
SourceFenceGate,
PgTskPublisherOptions,
TskDrainResult,
Expand All @@ -70,6 +72,8 @@ export {
HA_CONTROL_PG_SCHEMA,
HA_CONTROL_TABLES,
HA_CONTROL_MANIFEST_DIGEST,
HA_CONTROL_V1_MANIFEST_DIGEST,
HA_CONTROL_V1_SOURCE_ACTIVATION_SCHEMA,
CONTROL_SCHEMA_VERSION,
HaControlFencing,
GuardSigner,
Expand All @@ -80,6 +84,7 @@ export {
assertRedisAuthority,
reconcileFencedRedis,
provisionControlSchema,
migrateControlSchemaV1ToV2,
assertControlSchemaReady,
FenceAuthorityQuarantineError,
} from './ha-control-fencing.js';
Expand Down Expand Up @@ -158,6 +163,7 @@ export type {
export type {
GuardKeyResolver,
ControlSchemaReadyToken,
ControlSchemaMigrationDb,
HaControlPolicy,
ProvisioningState,
LeaseState,
Expand Down
Loading
Loading