diff --git a/docs/TEST_INTEGRITY.md b/docs/TEST_INTEGRITY.md index b80534b..a9ce210 100644 --- a/docs/TEST_INTEGRITY.md +++ b/docs/TEST_INTEGRITY.md @@ -2677,3 +2677,28 @@ test_integrity_note: did_relax_any_assertion: false if_true_explain_spec_basis: "" ``` + +## 2026-10-01 — Candidate attempt-store B0 public database-boundary correction + +```yaml +test_integrity_note: + change_type: new_tests + scenarios: + - id: SCN-candidate-store-fixture-authority + given: A caller-owned instrumented database and a forged or issued fixture authority + when: The public fixture provisioner is called with a database selector or forged authority + then: It rejects before any database method executes; raw-database initializer and raw-connection verifier exports are absent + observable_outcomes: + - Stable input or authority refusal and zero observed exec or prepare calls on the caller-owned instrumented database + - Public module namespaces omit the raw database initializer and raw metadata verifier + determinism_controls: + - In-memory instrumented database object, private WeakMap authority, hermetic harness-owned mkdtemp, no retry or live control-plane state + anti_cheat_rationale: + prevents: + - Exporting an initializer that executes PRAGMA, CREATE, or INSERT against a caller-selected database + - Treating an internal comment as an authority boundary + - Allowing a forged fixture authority to select or mutate registered storage + relaxation: + did_relax_any_assertion: false + if_true_explain_spec_basis: "" +``` diff --git a/src/control-plane/candidate-attempt-store-provisioner.mjs b/src/control-plane/candidate-attempt-store-provisioner.mjs index f2a7f2a..5b58950 100644 --- a/src/control-plane/candidate-attempt-store-provisioner.mjs +++ b/src/control-plane/candidate-attempt-store-provisioner.mjs @@ -5,14 +5,17 @@ import { join } from 'node:path'; import { DatabaseSync } from 'node:sqlite'; import { TorchError } from '../kernel/errors.mjs'; import { + CANDIDATE_ATTEMPT_STORE_PROTOCOL_VERSION, + CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION, + candidateAttemptStoreDdlStatementsV1, candidateAttemptStoreDigestsV1, - initializeCandidateAttemptStoreV1, - inspectCandidateAttemptStoreMetadataV1, } from './candidate-attempt-store.mjs'; const harnesses = new WeakMap(); const fixtures = new WeakMap(); const TEST_CORRUPTIONS = new Set(['nonempty', 'registered-relationship', 'ddl-drift', 'malformed-meta']); +const DIGEST_PATTERN = /^[0-9a-f]{64}$/; +const MAX_IDENTIFIER_BYTES = 128; function fail(message, code, details) { throw new TorchError(message, { code, details }); @@ -27,6 +30,111 @@ function exactObject(value, allowed, label) { } } +function boundedIdentifier(value, field) { + if (typeof value !== 'string' || !value || Buffer.byteLength(value, 'utf8') > MAX_IDENTIFIER_BYTES) { + fail(`${field} must be a bounded identifier`, 'CANDIDATE_STORE_METADATA_INVALID', { field }); + } + return value; +} + +function assertConnection(database) { + database.exec('PRAGMA foreign_keys = ON'); + const foreignKeys = database.prepare('PRAGMA foreign_keys').get()?.foreign_keys; + if (foreignKeys !== 1) fail('Candidate-store connection did not enable foreign keys', 'CANDIDATE_STORE_FOREIGN_KEYS_REQUIRED'); + return foreignKeys; +} + +function assertSchemaStatements(database) { + const actual = database.prepare(` + SELECT type, name, sql + FROM sqlite_master + WHERE type IN ('table', 'index') AND name NOT LIKE 'sqlite_%' + ORDER BY CASE name + WHEN 'candidate_attempt_store_meta' THEN 0 + WHEN 'candidate_attempt_store_meta_fixture_identity_idx' THEN 1 + ELSE 2 + END ASC + `).all(); + const statements = candidateAttemptStoreDdlStatementsV1(); + const expected = [ + { type: 'table', name: 'candidate_attempt_store_meta', sql: statements[0] }, + { type: 'index', name: 'candidate_attempt_store_meta_fixture_identity_idx', sql: statements[1] }, + ]; + if (JSON.stringify(actual) !== JSON.stringify(expected)) { + fail('Candidate-store DDL does not match the canonical v1 schema', 'CANDIDATE_STORE_SCHEMA_DRIFT'); + } +} + +/** Module-private: it is reachable only after a closure-owned harness has selected the synthetic target. */ +function initializeFixtureStore(database, metadata) { + const fixtureIdentity = boundedIdentifier(metadata.fixtureIdentity, 'fixtureIdentity'); + const storeIdentity = boundedIdentifier(metadata.storeIdentity, 'storeIdentity'); + if (typeof metadata.createdAt !== 'string' || !metadata.createdAt || Buffer.byteLength(metadata.createdAt, 'utf8') > 40) { + fail('createdAt must be bounded ISO text', 'CANDIDATE_STORE_METADATA_INVALID', { field: 'createdAt' }); + } + assertConnection(database); + database.exec(`PRAGMA user_version = ${CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION}`); + for (const statement of candidateAttemptStoreDdlStatementsV1()) database.exec(statement); + const digests = candidateAttemptStoreDigestsV1(); + database.prepare(` + INSERT INTO candidate_attempt_store_meta ( + singleton, protocol_version, schema_version, ddl_digest, schema_digest, + fixture_identity, store_identity, promotion, created_at + ) VALUES (1, ?, ?, ?, ?, ?, ?, 'nonpromotable', ?) + `).run( + CANDIDATE_ATTEMPT_STORE_PROTOCOL_VERSION, + CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION, + digests.ddlDigest, + digests.schemaDigest, + fixtureIdentity, + storeIdentity, + metadata.createdAt, + ); + return inspectFixtureMetadata(database); +} + +/** Module-private read-only verifier; public callers can reach it only through fixture attestation. */ +function inspectFixtureMetadata(database) { + const foreignKeys = assertConnection(database); + const userVersion = database.prepare('PRAGMA user_version').get()?.user_version; + if (userVersion !== CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION) { + fail('Candidate-store user_version is incompatible', 'CANDIDATE_STORE_SCHEMA_MISMATCH', { + expected: CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION, observed: userVersion, + }); + } + assertSchemaStatements(database); + const rows = database.prepare(` + SELECT protocol_version, schema_version, ddl_digest, schema_digest, + fixture_identity, store_identity, promotion, created_at + FROM candidate_attempt_store_meta + ORDER BY singleton ASC + `).all(); + if (rows.length !== 1) fail('Candidate-store metadata must contain exactly one row', 'CANDIDATE_STORE_METADATA_INVALID'); + const row = rows[0]; + const digests = candidateAttemptStoreDigestsV1(); + if (row.protocol_version !== CANDIDATE_ATTEMPT_STORE_PROTOCOL_VERSION || row.schema_version !== CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION + || row.ddl_digest !== digests.ddlDigest || row.schema_digest !== digests.schemaDigest + || row.promotion !== 'nonpromotable' || !DIGEST_PATTERN.test(row.ddl_digest) || !DIGEST_PATTERN.test(row.schema_digest)) { + fail('Candidate-store metadata is malformed or drifted', 'CANDIDATE_STORE_METADATA_INVALID'); + } + boundedIdentifier(row.fixture_identity, 'fixtureIdentity'); + boundedIdentifier(row.store_identity, 'storeIdentity'); + if (typeof row.created_at !== 'string' || !row.created_at || Buffer.byteLength(row.created_at, 'utf8') > 40) { + fail('Candidate-store created_at is malformed', 'CANDIDATE_STORE_METADATA_INVALID'); + } + return Object.freeze({ + protocolVersion: row.protocol_version, + schemaVersion: row.schema_version, + ddlDigest: row.ddl_digest, + schemaDigest: row.schema_digest, + fixtureIdentity: row.fixture_identity, + storeIdentity: row.store_identity, + promotion: row.promotion, + createdAt: row.created_at, + connection: Object.freeze({ foreignKeys, userVersion }), + }); +} + function assertHarness(harness) { const state = harnesses.get(harness); if (!state) fail('Fixture authority is not issued by this harness', 'CANDIDATE_STORE_FIXTURE_AUTH_REQUIRED'); @@ -104,7 +212,7 @@ export function provisionCandidateAttemptStoreFixtureV1(input = {}) { const database = new DatabaseSync(databasePath(state)); let metadata; try { - metadata = initializeCandidateAttemptStoreV1(database, { + metadata = initializeFixtureStore(database, { fixtureIdentity: state.fixtureIdentity, storeIdentity: `store-${randomUUID()}`, createdAt: '2026-10-01T00:00:00.000Z', @@ -134,7 +242,7 @@ export function inspectCandidateAttemptStoreFixtureV1(input = {}) { const state = assertFixture(fixture); const database = new DatabaseSync(databasePath(state), { readOnly: true }); try { - const metadata = inspectCandidateAttemptStoreMetadataV1(database); + const metadata = inspectFixtureMetadata(database); const digests = candidateAttemptStoreDigestsV1(); if (metadata.fixtureIdentity !== fixture.fixtureIdentity || metadata.storeIdentity !== fixture.storeIdentity || metadata.ddlDigest !== digests.ddlDigest || metadata.schemaDigest !== digests.schemaDigest diff --git a/src/control-plane/candidate-attempt-store.mjs b/src/control-plane/candidate-attempt-store.mjs index 97e5691..8c781f1 100644 --- a/src/control-plane/candidate-attempt-store.mjs +++ b/src/control-plane/candidate-attempt-store.mjs @@ -1,12 +1,8 @@ import { createHash } from 'node:crypto'; -import { TorchError } from '../kernel/errors.mjs'; export const CANDIDATE_ATTEMPT_STORE_PROTOCOL_VERSION = 1; export const CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION = 1; -const DIGEST_PATTERN = /^[0-9a-f]{64}$/; -const MAX_IDENTIFIER_BYTES = 128; - const DDL_STATEMENTS = Object.freeze([ `CREATE TABLE candidate_attempt_store_meta ( singleton INTEGER PRIMARY KEY CHECK (singleton = 1), @@ -22,10 +18,6 @@ const DDL_STATEMENTS = Object.freeze([ 'CREATE INDEX candidate_attempt_store_meta_fixture_identity_idx ON candidate_attempt_store_meta (fixture_identity)', ]); -function fail(message, code, details) { - throw new TorchError(message, { code, details }); -} - function digest(bytes) { return createHash('sha256').update(bytes).digest('hex'); } @@ -35,62 +27,6 @@ function frame(label, value) { return `${label}:${bytes.length}\n${value}\n`; } -function exactObject(value, allowed, label) { - if (!value || typeof value !== 'object' || Array.isArray(value)) { - fail(`${label} must be an object`, 'CANDIDATE_STORE_METADATA_INVALID'); - } - for (const key of Object.keys(value)) { - if (!allowed.has(key)) fail(`${label} contains an unsupported field`, 'CANDIDATE_STORE_METADATA_INVALID', { field: key }); - } -} - -function boundedIdentifier(value, field) { - if (typeof value !== 'string' || !value || Buffer.byteLength(value, 'utf8') > MAX_IDENTIFIER_BYTES) { - fail(`${field} must be a bounded identifier`, 'CANDIDATE_STORE_METADATA_INVALID', { field }); - } - return value; -} - -function expectedMetaRow() { - const digests = candidateAttemptStoreDigestsV1(); - return { - protocolVersion: CANDIDATE_ATTEMPT_STORE_PROTOCOL_VERSION, - schemaVersion: CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION, - ddlDigest: digests.ddlDigest, - schemaDigest: digests.schemaDigest, - }; -} - -function assertConnection(database) { - if (!database || typeof database.exec !== 'function' || typeof database.prepare !== 'function') { - fail('Candidate-store metadata verifier requires an internal SQLite connection', 'CANDIDATE_STORE_METADATA_INVALID'); - } - database.exec('PRAGMA foreign_keys = ON'); - const foreignKeys = database.prepare('PRAGMA foreign_keys').get()?.foreign_keys; - if (foreignKeys !== 1) fail('Candidate-store connection did not enable foreign keys', 'CANDIDATE_STORE_FOREIGN_KEYS_REQUIRED'); - return foreignKeys; -} - -function assertSchemaStatements(database) { - const actual = database.prepare(` - SELECT type, name, sql - FROM sqlite_master - WHERE type IN ('table', 'index') AND name NOT LIKE 'sqlite_%' - ORDER BY CASE name - WHEN 'candidate_attempt_store_meta' THEN 0 - WHEN 'candidate_attempt_store_meta_fixture_identity_idx' THEN 1 - ELSE 2 - END ASC - `).all(); - const expected = [ - { type: 'table', name: 'candidate_attempt_store_meta', sql: DDL_STATEMENTS[0] }, - { type: 'index', name: 'candidate_attempt_store_meta_fixture_identity_idx', sql: DDL_STATEMENTS[1] }, - ]; - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - fail('Candidate-store DDL does not match the canonical v1 schema', 'CANDIDATE_STORE_SCHEMA_DRIFT'); - } -} - /** Internal, version-framed UTF-8/LF preimage; it contains no stored metadata values. */ export function candidateAttemptStoreDdlBytesV1() { const payload = [ @@ -120,73 +56,7 @@ export function candidateAttemptStoreDigestsV1() { return Object.freeze({ ddlDigest: digest(ddlBytes), schemaDigest: digest(schemaBytes) }); } -/** Internal provisioner seam; never accepts a caller path, root, manifest, or DDL. */ -export function initializeCandidateAttemptStoreV1(database, metadata) { - exactObject(metadata, new Set(['fixtureIdentity', 'storeIdentity', 'createdAt']), 'Candidate-store metadata'); - const fixtureIdentity = boundedIdentifier(metadata.fixtureIdentity, 'fixtureIdentity'); - const storeIdentity = boundedIdentifier(metadata.storeIdentity, 'storeIdentity'); - if (typeof metadata.createdAt !== 'string' || !metadata.createdAt || Buffer.byteLength(metadata.createdAt, 'utf8') > 40) { - fail('createdAt must be bounded ISO text', 'CANDIDATE_STORE_METADATA_INVALID', { field: 'createdAt' }); - } - assertConnection(database); - database.exec(`PRAGMA user_version = ${CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION}`); - for (const statement of DDL_STATEMENTS) database.exec(statement); - const digests = candidateAttemptStoreDigestsV1(); - database.prepare(` - INSERT INTO candidate_attempt_store_meta ( - singleton, protocol_version, schema_version, ddl_digest, schema_digest, - fixture_identity, store_identity, promotion, created_at - ) VALUES (1, ?, ?, ?, ?, ?, ?, 'nonpromotable', ?) - `).run( - CANDIDATE_ATTEMPT_STORE_PROTOCOL_VERSION, - CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION, - digests.ddlDigest, - digests.schemaDigest, - fixtureIdentity, - storeIdentity, - metadata.createdAt, - ); - return inspectCandidateAttemptStoreMetadataV1(database); -} - -/** Internal read-only metadata verifier. Its connection is owned by the fixture provisioner. */ -export function inspectCandidateAttemptStoreMetadataV1(database) { - const foreignKeys = assertConnection(database); - const userVersion = database.prepare('PRAGMA user_version').get()?.user_version; - if (userVersion !== CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION) { - fail('Candidate-store user_version is incompatible', 'CANDIDATE_STORE_SCHEMA_MISMATCH', { - expected: CANDIDATE_ATTEMPT_STORE_SCHEMA_VERSION, observed: userVersion, - }); - } - assertSchemaStatements(database); - const rows = database.prepare(` - SELECT protocol_version, schema_version, ddl_digest, schema_digest, - fixture_identity, store_identity, promotion, created_at - FROM candidate_attempt_store_meta - ORDER BY singleton ASC - `).all(); - if (rows.length !== 1) fail('Candidate-store metadata must contain exactly one row', 'CANDIDATE_STORE_METADATA_INVALID'); - const row = rows[0]; - const expected = expectedMetaRow(); - if (row.protocol_version !== expected.protocolVersion || row.schema_version !== expected.schemaVersion - || row.ddl_digest !== expected.ddlDigest || row.schema_digest !== expected.schemaDigest - || row.promotion !== 'nonpromotable' || !DIGEST_PATTERN.test(row.ddl_digest) || !DIGEST_PATTERN.test(row.schema_digest)) { - fail('Candidate-store metadata is malformed or drifted', 'CANDIDATE_STORE_METADATA_INVALID'); - } - boundedIdentifier(row.fixture_identity, 'fixtureIdentity'); - boundedIdentifier(row.store_identity, 'storeIdentity'); - if (typeof row.created_at !== 'string' || !row.created_at || Buffer.byteLength(row.created_at, 'utf8') > 40) { - fail('Candidate-store created_at is malformed', 'CANDIDATE_STORE_METADATA_INVALID'); - } - return Object.freeze({ - protocolVersion: row.protocol_version, - schemaVersion: row.schema_version, - ddlDigest: row.ddl_digest, - schemaDigest: row.schema_digest, - fixtureIdentity: row.fixture_identity, - storeIdentity: row.store_identity, - promotion: row.promotion, - createdAt: row.created_at, - connection: Object.freeze({ foreignKeys, userVersion }), - }); +/** Immutable executable statements for the provisioner's private, fixture-only initializer. */ +export function candidateAttemptStoreDdlStatementsV1() { + return Object.freeze([...DDL_STATEMENTS]); } diff --git a/test/fleet/candidate-attempt-store.test.mjs b/test/fleet/candidate-attempt-store.test.mjs index bf86c67..fdd8af5 100644 --- a/test/fleet/candidate-attempt-store.test.mjs +++ b/test/fleet/candidate-attempt-store.test.mjs @@ -112,6 +112,7 @@ test('SCN-candidate-store-fixture-nonpromotion: fixture attestation cannot expos assert.equal(inspectCandidateAttemptStoreFixtureV1({ fixture }).nonpromotable, true); for (const forbiddenExport of [ 'issueAttemptV1', 'startAttemptV1', 'sealAttemptV1', 'finalizeAttemptV1', 'createCandidateSourceReceiptV1', + 'initializeCandidateAttemptStoreV1', 'inspectCandidateAttemptStoreMetadataV1', ]) { assert.equal(Object.hasOwn(store, forbiddenExport), false, `${forbiddenExport} is outside B0`); assert.equal(Object.hasOwn(provisioner, forbiddenExport), false, `${forbiddenExport} is outside B0`); @@ -124,6 +125,23 @@ test('SCN-candidate-store-fixture-authority: foreign, closed, reused, nonempty, const foreign = { schema: 'torch.dev/candidate-attempt-fixture-authority/v1alpha1', fixtureIdentity: 'foreign' }; expectCode(() => provisionCandidateAttemptStoreFixtureV1({ harness: foreign }), 'CANDIDATE_STORE_FIXTURE_AUTH_REQUIRED'); + const executionCalls = []; + const arbitraryDatabase = Object.freeze({ + exec(sql) { executionCalls.push(['exec', sql]); }, + prepare(sql) { executionCalls.push(['prepare', sql]); return { get() {}, all() {}, run() {} }; }, + }); + const issuedForBypassAttempt = createCandidateAttemptStoreFixtureHarnessV1(); + expectCode( + () => provisionCandidateAttemptStoreFixtureV1({ harness: issuedForBypassAttempt, database: arbitraryDatabase }), + 'CANDIDATE_STORE_FIXTURE_INPUT_INVALID', + ); + expectCode( + () => provisionCandidateAttemptStoreFixtureV1({ harness: { ...foreign, database: arbitraryDatabase } }), + 'CANDIDATE_STORE_FIXTURE_AUTH_REQUIRED', + ); + assert.deepEqual(executionCalls, [], 'public fixture APIs must reject caller database or forged authority before any database execution'); + closeCandidateAttemptStoreFixtureHarnessV1({ harness: issuedForBypassAttempt }); + const closed = createCandidateAttemptStoreFixtureHarnessV1(); closeCandidateAttemptStoreFixtureHarnessV1({ harness: closed }); expectCode(() => provisionCandidateAttemptStoreFixtureV1({ harness: closed }), 'CANDIDATE_STORE_FIXTURE_AUTH_EXPIRED');