life-as-api 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +377 -0
- package/dist/agent/finance-agent.d.ts +44 -0
- package/dist/agent/finance-agent.js +75 -0
- package/dist/agent/finance-agent.js.map +1 -0
- package/dist/agent/legal-agent.d.ts +44 -0
- package/dist/agent/legal-agent.js +76 -0
- package/dist/agent/legal-agent.js.map +1 -0
- package/dist/agent/medical-agent.d.ts +44 -0
- package/dist/agent/medical-agent.js +75 -0
- package/dist/agent/medical-agent.js.map +1 -0
- package/dist/agent/trusted-agent-registry.d.ts +53 -0
- package/dist/agent/trusted-agent-registry.js +57 -0
- package/dist/agent/trusted-agent-registry.js.map +1 -0
- package/dist/audit/audit-chain-verifier.d.ts +10 -0
- package/dist/audit/audit-chain-verifier.js +67 -0
- package/dist/audit/audit-chain-verifier.js.map +1 -0
- package/dist/audit/audit-log.d.ts +48 -0
- package/dist/audit/audit-log.js +74 -0
- package/dist/audit/audit-log.js.map +1 -0
- package/dist/audit/sqlite-audit-log.d.ts +29 -0
- package/dist/audit/sqlite-audit-log.js +142 -0
- package/dist/audit/sqlite-audit-log.js.map +1 -0
- package/dist/auth/access-context-issuer.d.ts +18 -0
- package/dist/auth/access-context-issuer.js +88 -0
- package/dist/auth/access-context-issuer.js.map +1 -0
- package/dist/auth/assert-authorized-for-subject.d.ts +2 -0
- package/dist/auth/assert-authorized-for-subject.js +20 -0
- package/dist/auth/assert-authorized-for-subject.js.map +1 -0
- package/dist/auth/backend-context-minting-boundary.d.ts +23 -0
- package/dist/auth/backend-context-minting-boundary.js +281 -0
- package/dist/auth/backend-context-minting-boundary.js.map +1 -0
- package/dist/auth/default-authorization-policy.d.ts +7 -0
- package/dist/auth/default-authorization-policy.js +64 -0
- package/dist/auth/default-authorization-policy.js.map +1 -0
- package/dist/auth/fake-auth-adapter.d.ts +7 -0
- package/dist/auth/fake-auth-adapter.js +27 -0
- package/dist/auth/fake-auth-adapter.js.map +1 -0
- package/dist/auth/http-client.d.ts +12 -0
- package/dist/auth/http-client.js +7 -0
- package/dist/auth/http-client.js.map +1 -0
- package/dist/auth/in-memory-grant-resolver.d.ts +21 -0
- package/dist/auth/in-memory-grant-resolver.js +73 -0
- package/dist/auth/in-memory-grant-resolver.js.map +1 -0
- package/dist/auth/in-memory-tenant-boundary.d.ts +16 -0
- package/dist/auth/in-memory-tenant-boundary.js +37 -0
- package/dist/auth/in-memory-tenant-boundary.js.map +1 -0
- package/dist/auth/jwks-key-ring-auth-adapter.d.ts +38 -0
- package/dist/auth/jwks-key-ring-auth-adapter.js +123 -0
- package/dist/auth/jwks-key-ring-auth-adapter.js.map +1 -0
- package/dist/auth/jwks-key-ring.d.ts +25 -0
- package/dist/auth/jwks-key-ring.js +111 -0
- package/dist/auth/jwks-key-ring.js.map +1 -0
- package/dist/auth/jwt-auth-adapter.d.ts +15 -0
- package/dist/auth/jwt-auth-adapter.js +59 -0
- package/dist/auth/jwt-auth-adapter.js.map +1 -0
- package/dist/auth/jwt-core.d.ts +32 -0
- package/dist/auth/jwt-core.js +226 -0
- package/dist/auth/jwt-core.js.map +1 -0
- package/dist/auth/jwt-key-ring-auth-adapter.d.ts +16 -0
- package/dist/auth/jwt-key-ring-auth-adapter.js +58 -0
- package/dist/auth/jwt-key-ring-auth-adapter.js.map +1 -0
- package/dist/auth/oidc-discovery.d.ts +15 -0
- package/dist/auth/oidc-discovery.js +46 -0
- package/dist/auth/oidc-discovery.js.map +1 -0
- package/dist/auth/production-scoped-life-api.d.ts +58 -0
- package/dist/auth/production-scoped-life-api.js +802 -0
- package/dist/auth/production-scoped-life-api.js.map +1 -0
- package/dist/auth/proposal-scope-inspector.d.ts +3 -0
- package/dist/auth/proposal-scope-inspector.js +42 -0
- package/dist/auth/proposal-scope-inspector.js.map +1 -0
- package/dist/auth/proposal-scoped-life-api.d.ts +21 -0
- package/dist/auth/proposal-scoped-life-api.js +168 -0
- package/dist/auth/proposal-scoped-life-api.js.map +1 -0
- package/dist/auth/rate-limited-context-minting-boundary.d.ts +27 -0
- package/dist/auth/rate-limited-context-minting-boundary.js +77 -0
- package/dist/auth/rate-limited-context-minting-boundary.js.map +1 -0
- package/dist/auth/revocation-aware-auth-adapter.d.ts +21 -0
- package/dist/auth/revocation-aware-auth-adapter.js +88 -0
- package/dist/auth/revocation-aware-auth-adapter.js.map +1 -0
- package/dist/auth/sqlite-grant-resolver.d.ts +8 -0
- package/dist/auth/sqlite-grant-resolver.js +78 -0
- package/dist/auth/sqlite-grant-resolver.js.map +1 -0
- package/dist/auth/sqlite-tenant-boundary.d.ts +7 -0
- package/dist/auth/sqlite-tenant-boundary.js +41 -0
- package/dist/auth/sqlite-tenant-boundary.js.map +1 -0
- package/dist/auth/static-jwt-key-ring.d.ts +13 -0
- package/dist/auth/static-jwt-key-ring.js +73 -0
- package/dist/auth/static-jwt-key-ring.js.map +1 -0
- package/dist/auth/subject-scoped-life-api.d.ts +14 -0
- package/dist/auth/subject-scoped-life-api.js +51 -0
- package/dist/auth/subject-scoped-life-api.js.map +1 -0
- package/dist/auth/test-context-minting-boundary.d.ts +13 -0
- package/dist/auth/test-context-minting-boundary.js +74 -0
- package/dist/auth/test-context-minting-boundary.js.map +1 -0
- package/dist/auth/types.d.ts +77 -0
- package/dist/auth/types.js +16 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/compliance/subject-data-report.d.ts +43 -0
- package/dist/compliance/subject-data-report.js +155 -0
- package/dist/compliance/subject-data-report.js.map +1 -0
- package/dist/consent/consent-guard.d.ts +4 -0
- package/dist/consent/consent-guard.js +37 -0
- package/dist/consent/consent-guard.js.map +1 -0
- package/dist/consent/grant-registry.d.ts +7 -0
- package/dist/consent/grant-registry.js +13 -0
- package/dist/consent/grant-registry.js.map +1 -0
- package/dist/consent/intersect-selector.d.ts +3 -0
- package/dist/consent/intersect-selector.js +66 -0
- package/dist/consent/intersect-selector.js.map +1 -0
- package/dist/contract/diagnostics.d.ts +32 -0
- package/dist/contract/diagnostics.js +112 -0
- package/dist/contract/diagnostics.js.map +1 -0
- package/dist/contract/project-contracts.d.ts +5 -0
- package/dist/contract/project-contracts.js +159 -0
- package/dist/contract/project-contracts.js.map +1 -0
- package/dist/contract/types.d.ts +32 -0
- package/dist/contract/types.js +5 -0
- package/dist/contract/types.js.map +1 -0
- package/dist/crypto/aes-gcm.d.ts +11 -0
- package/dist/crypto/aes-gcm.js +78 -0
- package/dist/crypto/aes-gcm.js.map +1 -0
- package/dist/crypto/claim-serializer.d.ts +26 -0
- package/dist/crypto/claim-serializer.js +59 -0
- package/dist/crypto/claim-serializer.js.map +1 -0
- package/dist/crypto/sha256.d.ts +12 -0
- package/dist/crypto/sha256.js +40 -0
- package/dist/crypto/sha256.js.map +1 -0
- package/dist/crypto/static-key.d.ts +11 -0
- package/dist/crypto/static-key.js +60 -0
- package/dist/crypto/static-key.js.map +1 -0
- package/dist/crypto/types.d.ts +20 -0
- package/dist/crypto/types.js +8 -0
- package/dist/crypto/types.js.map +1 -0
- package/dist/datasource/trusted-data-source-registry.d.ts +51 -0
- package/dist/datasource/trusted-data-source-registry.js +57 -0
- package/dist/datasource/trusted-data-source-registry.js.map +1 -0
- package/dist/erasure/tombstone.d.ts +13 -0
- package/dist/erasure/tombstone.js +20 -0
- package/dist/erasure/tombstone.js.map +1 -0
- package/dist/evidence/evidence-backed-claim-creator.d.ts +48 -0
- package/dist/evidence/evidence-backed-claim-creator.js +107 -0
- package/dist/evidence/evidence-backed-claim-creator.js.map +1 -0
- package/dist/evidence/in-memory-raw-document-store.d.ts +26 -0
- package/dist/evidence/in-memory-raw-document-store.js +84 -0
- package/dist/evidence/in-memory-raw-document-store.js.map +1 -0
- package/dist/evidence/raw-document-store.d.ts +12 -0
- package/dist/evidence/raw-document-store.js +8 -0
- package/dist/evidence/raw-document-store.js.map +1 -0
- package/dist/evidence/source-evidence-validator.d.ts +4 -0
- package/dist/evidence/source-evidence-validator.js +14 -0
- package/dist/evidence/source-evidence-validator.js.map +1 -0
- package/dist/evidence/sqlite-raw-document-store.d.ts +19 -0
- package/dist/evidence/sqlite-raw-document-store.js +122 -0
- package/dist/evidence/sqlite-raw-document-store.js.map +1 -0
- package/dist/guardian/guardian-registry.d.ts +96 -0
- package/dist/guardian/guardian-registry.js +95 -0
- package/dist/guardian/guardian-registry.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/observability/health.d.ts +12 -0
- package/dist/observability/health.js +16 -0
- package/dist/observability/health.js.map +1 -0
- package/dist/observability/logger.d.ts +21 -0
- package/dist/observability/logger.js +40 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +15 -0
- package/dist/observability/metrics.js +52 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/persistence/backup.d.ts +24 -0
- package/dist/persistence/backup.js +251 -0
- package/dist/persistence/backup.js.map +1 -0
- package/dist/persistence/decryptability-scan.d.ts +10 -0
- package/dist/persistence/decryptability-scan.js +144 -0
- package/dist/persistence/decryptability-scan.js.map +1 -0
- package/dist/persistence/in-memory-unit-of-work.d.ts +11 -0
- package/dist/persistence/in-memory-unit-of-work.js +32 -0
- package/dist/persistence/in-memory-unit-of-work.js.map +1 -0
- package/dist/persistence/key-availability.d.ts +9 -0
- package/dist/persistence/key-availability.js +125 -0
- package/dist/persistence/key-availability.js.map +1 -0
- package/dist/persistence/sqlite/migrations.d.ts +9 -0
- package/dist/persistence/sqlite/migrations.js +535 -0
- package/dist/persistence/sqlite/migrations.js.map +1 -0
- package/dist/persistence/sqlite/schema.d.ts +10 -0
- package/dist/persistence/sqlite/schema.js +101 -0
- package/dist/persistence/sqlite/schema.js.map +1 -0
- package/dist/persistence/sqlite/sqlite-fact-store.d.ts +24 -0
- package/dist/persistence/sqlite/sqlite-fact-store.js +207 -0
- package/dist/persistence/sqlite/sqlite-fact-store.js.map +1 -0
- package/dist/persistence/sqlite/sqlite-source-registry.d.ts +17 -0
- package/dist/persistence/sqlite/sqlite-source-registry.js +132 -0
- package/dist/persistence/sqlite/sqlite-source-registry.js.map +1 -0
- package/dist/persistence/sqlite/sqlite-unit-of-work.d.ts +8 -0
- package/dist/persistence/sqlite/sqlite-unit-of-work.js +41 -0
- package/dist/persistence/sqlite/sqlite-unit-of-work.js.map +1 -0
- package/dist/persistence/sqlite/types.d.ts +24 -0
- package/dist/persistence/sqlite/types.js +28 -0
- package/dist/persistence/sqlite/types.js.map +1 -0
- package/dist/persistence/unit-of-work.d.ts +6 -0
- package/dist/persistence/unit-of-work.js +15 -0
- package/dist/persistence/unit-of-work.js.map +1 -0
- package/dist/proposal/accepted-claim-appender.d.ts +7 -0
- package/dist/proposal/accepted-claim-appender.js +16 -0
- package/dist/proposal/accepted-claim-appender.js.map +1 -0
- package/dist/proposal/in-memory-proposal-queue.d.ts +21 -0
- package/dist/proposal/in-memory-proposal-queue.js +218 -0
- package/dist/proposal/in-memory-proposal-queue.js.map +1 -0
- package/dist/proposal/policy-aware-proposal-queue.d.ts +23 -0
- package/dist/proposal/policy-aware-proposal-queue.js +162 -0
- package/dist/proposal/policy-aware-proposal-queue.js.map +1 -0
- package/dist/proposal/proposal-policy.d.ts +37 -0
- package/dist/proposal/proposal-policy.js +72 -0
- package/dist/proposal/proposal-policy.js.map +1 -0
- package/dist/proposal/proposal-queue.d.ts +13 -0
- package/dist/proposal/proposal-queue.js +15 -0
- package/dist/proposal/proposal-queue.js.map +1 -0
- package/dist/proposal/source-aware-claim-appender.d.ts +13 -0
- package/dist/proposal/source-aware-claim-appender.js +47 -0
- package/dist/proposal/source-aware-claim-appender.js.map +1 -0
- package/dist/proposal/sqlite-proposal-queue.d.ts +26 -0
- package/dist/proposal/sqlite-proposal-queue.js +282 -0
- package/dist/proposal/sqlite-proposal-queue.js.map +1 -0
- package/dist/resolution/resolve-claims.d.ts +4 -0
- package/dist/resolution/resolve-claims.js +101 -0
- package/dist/resolution/resolve-claims.js.map +1 -0
- package/dist/resolution/trust-profile.d.ts +12 -0
- package/dist/resolution/trust-profile.js +23 -0
- package/dist/resolution/trust-profile.js.map +1 -0
- package/dist/resolution/types.d.ts +15 -0
- package/dist/resolution/types.js +8 -0
- package/dist/resolution/types.js.map +1 -0
- package/dist/sdk/create-backend-integrated-life-api-for-test.d.ts +23 -0
- package/dist/sdk/create-backend-integrated-life-api-for-test.js +240 -0
- package/dist/sdk/create-backend-integrated-life-api-for-test.js.map +1 -0
- package/dist/sdk/create-life-api.d.ts +55 -0
- package/dist/sdk/create-life-api.js +251 -0
- package/dist/sdk/create-life-api.js.map +1 -0
- package/dist/sdk/create-sqlite-life-api.d.ts +33 -0
- package/dist/sdk/create-sqlite-life-api.js +654 -0
- package/dist/sdk/create-sqlite-life-api.js.map +1 -0
- package/dist/sdk/life-api.d.ts +27 -0
- package/dist/sdk/life-api.js +17 -0
- package/dist/sdk/life-api.js.map +1 -0
- package/dist/sdk/validation.d.ts +8 -0
- package/dist/sdk/validation.js +216 -0
- package/dist/sdk/validation.js.map +1 -0
- package/dist/source/in-memory-source-registry.d.ts +15 -0
- package/dist/source/in-memory-source-registry.js +104 -0
- package/dist/source/in-memory-source-registry.js.map +1 -0
- package/dist/source/source-aware-fact-store.d.ts +19 -0
- package/dist/source/source-aware-fact-store.js +40 -0
- package/dist/source/source-aware-fact-store.js.map +1 -0
- package/dist/source/source-kind-predicate-policy.d.ts +4 -0
- package/dist/source/source-kind-predicate-policy.js +62 -0
- package/dist/source/source-kind-predicate-policy.js.map +1 -0
- package/dist/source/source-registry.d.ts +11 -0
- package/dist/source/source-registry.js +12 -0
- package/dist/source/source-registry.js.map +1 -0
- package/dist/store/in-memory-fact-store.d.ts +25 -0
- package/dist/store/in-memory-fact-store.js +192 -0
- package/dist/store/in-memory-fact-store.js.map +1 -0
- package/dist/surface/context-query.d.ts +21 -0
- package/dist/surface/context-query.js +113 -0
- package/dist/surface/context-query.js.map +1 -0
- package/dist/surface/evidence-backed-context-query.d.ts +62 -0
- package/dist/surface/evidence-backed-context-query.js +240 -0
- package/dist/surface/evidence-backed-context-query.js.map +1 -0
- package/dist/types/access-context.d.ts +25 -0
- package/dist/types/access-context.js +6 -0
- package/dist/types/access-context.js.map +1 -0
- package/dist/types/claim.d.ts +48 -0
- package/dist/types/claim.js +5 -0
- package/dist/types/claim.js.map +1 -0
- package/dist/types/consent.d.ts +41 -0
- package/dist/types/consent.js +3 -0
- package/dist/types/consent.js.map +1 -0
- package/dist/types/crypto-boundary.d.ts +12 -0
- package/dist/types/crypto-boundary.js +15 -0
- package/dist/types/crypto-boundary.js.map +1 -0
- package/dist/types/evidence.d.ts +31 -0
- package/dist/types/evidence.js +8 -0
- package/dist/types/evidence.js.map +1 -0
- package/dist/types/fact-store.d.ts +24 -0
- package/dist/types/fact-store.js +12 -0
- package/dist/types/fact-store.js.map +1 -0
- package/dist/types/ids.d.ts +36 -0
- package/dist/types/ids.js +11 -0
- package/dist/types/ids.js.map +1 -0
- package/dist/types/proposal.d.ts +38 -0
- package/dist/types/proposal.js +7 -0
- package/dist/types/proposal.js.map +1 -0
- package/dist/types/source.d.ts +33 -0
- package/dist/types/source.js +6 -0
- package/dist/types/source.js.map +1 -0
- package/dist/types/trust.d.ts +24 -0
- package/dist/types/trust.js +5 -0
- package/dist/types/trust.js.map +1 -0
- package/dist/utilities/deep-freeze.d.ts +1 -0
- package/dist/utilities/deep-freeze.js +17 -0
- package/dist/utilities/deep-freeze.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
// SQLite schema migration runner.
|
|
2
|
+
//
|
|
3
|
+
// SQLITE_MIGRATION_RUNNER_EXISTS_001: single authoritative source for schema history.
|
|
4
|
+
// initializeSchema() in schema.ts delegates here.
|
|
5
|
+
// SQLITE_SCHEMA_VERSION_TRACKED_001: 'migration_version' (numeric) in schema_meta tracks
|
|
6
|
+
// the last completed step; 'schema_version' (string) is preserved for legacy readers.
|
|
7
|
+
// SQLITE_MIGRATIONS_IDEMPOTENT_001: re-running on an up-to-date DB is a no-op.
|
|
8
|
+
// SQLITE_MIGRATIONS_RUN_IN_TRANSACTION_001: all pending steps are in one transaction.
|
|
9
|
+
// SQLITE_MIGRATION_FAILS_CLOSED_ON_UNKNOWN_FUTURE_VERSION_001: future version → throw.
|
|
10
|
+
// SQLITE_MIGRATION_DDL_NO_PAYLOAD_LEAK_001: DDL contains no crypto or payload material.
|
|
11
|
+
// SQLITE_MIGRATION_LEGACY_SCHEMA_NOT_ASSUMED_CURRENT_001: absent migration_version never
|
|
12
|
+
// silently assumes fully migrated — structural verification is always required.
|
|
13
|
+
// SQLITE_MIGRATION_CURRENT_SCHEMA_STRUCTURAL_VERIFY_001: structural verification runs at
|
|
14
|
+
// the end of every runMigrations call, even when migration_version already equals current.
|
|
15
|
+
import { sha256hexSync } from "../../crypto/sha256.js";
|
|
16
|
+
import { buildChainCanonical } from "../../audit/sqlite-audit-log.js";
|
|
17
|
+
// SQLITE_MIGRATION_RUNNER_EXISTS_001
|
|
18
|
+
// PROPOSAL_QUEUE_SCHEMA_ENCRYPTED_PAYLOAD_001 ✅ Production-06a
|
|
19
|
+
// PRODUCTION_AUDIT_C4_HASH_CHAIN_SEQUENCE_001 ✅ Audit Hardening C4 (v9)
|
|
20
|
+
// GUARDIAN_AUDIT_MARKED_001 ✅ Platform-03 Guardianship (v10): acting_as_guardian, ward_id
|
|
21
|
+
export const CURRENT_SCHEMA_VERSION = 10;
|
|
22
|
+
// ─── Error codes ──────────────────────────────────────────────────────────────
|
|
23
|
+
const FAIL_CLOSED_CODE = "SQLITE_MIGRATION_FAILS_CLOSED_ON_UNKNOWN_FUTURE_VERSION_001";
|
|
24
|
+
const LEGACY_INCOMPLETE_CODE = "SQLITE_MIGRATION_LEGACY_SCHEMA_INCOMPLETE_001";
|
|
25
|
+
const VERIFY_FAILED_CODE = "SQLITE_MIGRATION_CURRENT_SCHEMA_VERIFY_FAILED_001";
|
|
26
|
+
// ─── Structural verification constants ───────────────────────────────────────
|
|
27
|
+
// SQLITE_MIGRATION_LEGACY_SCHEMA_NOT_ASSUMED_CURRENT_001: these are the ground-truth
|
|
28
|
+
// requirements. A DB is only treated as current when it passes all of these checks.
|
|
29
|
+
const REQUIRED_TABLES = [
|
|
30
|
+
"schema_meta",
|
|
31
|
+
"claims",
|
|
32
|
+
"sources",
|
|
33
|
+
"raw_documents",
|
|
34
|
+
"audit_events",
|
|
35
|
+
"auth_tenant_memberships",
|
|
36
|
+
"auth_grants",
|
|
37
|
+
"proposals",
|
|
38
|
+
];
|
|
39
|
+
const REQUIRED_COLUMNS = {
|
|
40
|
+
sources: [
|
|
41
|
+
"id", "kind", "label", "status", "created_at", "created_by",
|
|
42
|
+
"evidence_id", "evidence_uri", "evidence_hash", "evidence_mime", "evidence_enc",
|
|
43
|
+
"metadata",
|
|
44
|
+
],
|
|
45
|
+
raw_documents: [
|
|
46
|
+
"id", "mime_type", "byte_length", "label",
|
|
47
|
+
"created_at", "created_by", "encrypted_blob", "metadata",
|
|
48
|
+
],
|
|
49
|
+
audit_events: [
|
|
50
|
+
"id", "recorded_at", "actor", "grant_id", "purpose", "decision",
|
|
51
|
+
"reason_code", "selector_fingerprint", "result_count", "result_claim_ids",
|
|
52
|
+
"contract_ids",
|
|
53
|
+
// PRODUCTION_AUDIT_C4_HASH_CHAIN_SEQUENCE_001 (v9)
|
|
54
|
+
"sequence", "prev_hash", "event_hash",
|
|
55
|
+
// GUARDIAN_AUDIT_MARKED_001 (v10)
|
|
56
|
+
"acting_as_guardian", "ward_id",
|
|
57
|
+
],
|
|
58
|
+
auth_tenant_memberships: [
|
|
59
|
+
"tenant_id", "person_id", "status", "created_at", "updated_at",
|
|
60
|
+
],
|
|
61
|
+
auth_grants: [
|
|
62
|
+
"grant_id", "agent_id", "tenant_id", "status",
|
|
63
|
+
"not_before", "not_after", "person_id", "created_at", "updated_at",
|
|
64
|
+
],
|
|
65
|
+
// PROPOSAL_QUEUE_SCHEMA_ENCRYPTED_PAYLOAD_001: candidateClaims stored as encrypted blob only.
|
|
66
|
+
// PROPOSAL_QUEUE_NO_PLAINTEXT_CANDIDATE_CLAIMS_001: no candidateClaims/rationale/reject_reason columns.
|
|
67
|
+
proposals: [
|
|
68
|
+
"proposal_id", "status", "proposed_by_agent", "under_grant",
|
|
69
|
+
"encrypted_payload", "payload_key_id",
|
|
70
|
+
"created_at", "updated_at", "decided_at",
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
// Required indexes introduced in v7. Checked by verifyCurrentSchema.
|
|
74
|
+
const REQUIRED_INDEXES = [
|
|
75
|
+
"idx_proposals_status",
|
|
76
|
+
"idx_proposals_agent",
|
|
77
|
+
"idx_proposals_grant",
|
|
78
|
+
"idx_proposals_status_grant",
|
|
79
|
+
// PRODUCTION_AUDIT_C4_HASH_CHAIN_SEQUENCE_001 (v9): unique sequence index on audit_events.
|
|
80
|
+
"audit_events_sequence_unique",
|
|
81
|
+
];
|
|
82
|
+
// ─── Historical DDL snapshots ─────────────────────────────────────────────────
|
|
83
|
+
// Each step preserves the schema state at that point in the project's history.
|
|
84
|
+
// Step v1→v2 creates sources WITHOUT evidence columns; those arrive in v3→v4.
|
|
85
|
+
const V1_SCHEMA_META_DDL = `
|
|
86
|
+
CREATE TABLE IF NOT EXISTS schema_meta (
|
|
87
|
+
key TEXT PRIMARY KEY,
|
|
88
|
+
value TEXT NOT NULL
|
|
89
|
+
) STRICT;
|
|
90
|
+
`;
|
|
91
|
+
const V1_CLAIMS_DDL = `
|
|
92
|
+
CREATE TABLE IF NOT EXISTS claims (
|
|
93
|
+
id TEXT PRIMARY KEY,
|
|
94
|
+
source_id TEXT NOT NULL,
|
|
95
|
+
subject TEXT NOT NULL,
|
|
96
|
+
predicate TEXT NOT NULL,
|
|
97
|
+
valid_from TEXT NOT NULL,
|
|
98
|
+
valid_to TEXT,
|
|
99
|
+
recorded_at TEXT NOT NULL,
|
|
100
|
+
recorded_seq INTEGER NOT NULL UNIQUE,
|
|
101
|
+
retracts TEXT,
|
|
102
|
+
supersedes TEXT,
|
|
103
|
+
overrides TEXT,
|
|
104
|
+
contract_id TEXT,
|
|
105
|
+
confidence REAL,
|
|
106
|
+
serializer_version TEXT NOT NULL,
|
|
107
|
+
encrypted_payload TEXT NOT NULL
|
|
108
|
+
) STRICT;
|
|
109
|
+
`;
|
|
110
|
+
// Sources without evidence link columns (added in step v3→v4).
|
|
111
|
+
const V2_SOURCES_BASE_DDL = `
|
|
112
|
+
CREATE TABLE IF NOT EXISTS sources (
|
|
113
|
+
id TEXT PRIMARY KEY,
|
|
114
|
+
kind TEXT NOT NULL,
|
|
115
|
+
label TEXT NOT NULL,
|
|
116
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
117
|
+
created_at TEXT NOT NULL,
|
|
118
|
+
created_by TEXT NOT NULL,
|
|
119
|
+
metadata TEXT
|
|
120
|
+
) STRICT;
|
|
121
|
+
`;
|
|
122
|
+
const V3_RAW_DOCUMENTS_DDL = `
|
|
123
|
+
CREATE TABLE IF NOT EXISTS raw_documents (
|
|
124
|
+
id TEXT PRIMARY KEY,
|
|
125
|
+
mime_type TEXT NOT NULL,
|
|
126
|
+
byte_length INTEGER NOT NULL,
|
|
127
|
+
label TEXT,
|
|
128
|
+
created_at TEXT NOT NULL,
|
|
129
|
+
created_by TEXT NOT NULL,
|
|
130
|
+
encrypted_blob TEXT NOT NULL,
|
|
131
|
+
metadata TEXT
|
|
132
|
+
) STRICT;
|
|
133
|
+
`;
|
|
134
|
+
// Evidence link columns added to sources in step v3→v4.
|
|
135
|
+
const V4_EVIDENCE_COLUMNS = [
|
|
136
|
+
"ALTER TABLE sources ADD COLUMN evidence_id TEXT",
|
|
137
|
+
"ALTER TABLE sources ADD COLUMN evidence_uri TEXT",
|
|
138
|
+
"ALTER TABLE sources ADD COLUMN evidence_hash TEXT",
|
|
139
|
+
"ALTER TABLE sources ADD COLUMN evidence_mime TEXT",
|
|
140
|
+
"ALTER TABLE sources ADD COLUMN evidence_enc INTEGER",
|
|
141
|
+
];
|
|
142
|
+
const V5_AUDIT_EVENTS_DDL = `
|
|
143
|
+
CREATE TABLE IF NOT EXISTS audit_events (
|
|
144
|
+
id TEXT PRIMARY KEY,
|
|
145
|
+
recorded_at TEXT NOT NULL,
|
|
146
|
+
actor TEXT NOT NULL,
|
|
147
|
+
grant_id TEXT,
|
|
148
|
+
purpose TEXT,
|
|
149
|
+
decision TEXT NOT NULL,
|
|
150
|
+
reason_code TEXT NOT NULL,
|
|
151
|
+
selector_fingerprint TEXT NOT NULL,
|
|
152
|
+
result_count INTEGER NOT NULL,
|
|
153
|
+
result_claim_ids TEXT NOT NULL,
|
|
154
|
+
contract_ids TEXT
|
|
155
|
+
) STRICT;
|
|
156
|
+
`;
|
|
157
|
+
// AUTH_SQLITE_TENANT_MEMBERSHIP_SCHEMA_001 ✅ Production-02d-a
|
|
158
|
+
const V6_AUTH_TENANT_MEMBERSHIPS_DDL = `
|
|
159
|
+
CREATE TABLE IF NOT EXISTS auth_tenant_memberships (
|
|
160
|
+
tenant_id TEXT NOT NULL,
|
|
161
|
+
person_id TEXT NOT NULL,
|
|
162
|
+
status TEXT NOT NULL CHECK (status IN ('active', 'suspended')),
|
|
163
|
+
created_at TEXT NOT NULL,
|
|
164
|
+
updated_at TEXT NOT NULL,
|
|
165
|
+
PRIMARY KEY (tenant_id, person_id)
|
|
166
|
+
) STRICT;
|
|
167
|
+
`;
|
|
168
|
+
// AUTH_SQLITE_GRANT_SCHEMA_001 ✅ Production-02d-a
|
|
169
|
+
const V6_AUTH_GRANTS_DDL = `
|
|
170
|
+
CREATE TABLE IF NOT EXISTS auth_grants (
|
|
171
|
+
grant_id TEXT NOT NULL PRIMARY KEY,
|
|
172
|
+
agent_id TEXT NOT NULL,
|
|
173
|
+
tenant_id TEXT NOT NULL,
|
|
174
|
+
status TEXT NOT NULL CHECK (status IN ('active', 'revoked')),
|
|
175
|
+
not_before TEXT NOT NULL,
|
|
176
|
+
not_after TEXT NOT NULL,
|
|
177
|
+
created_at TEXT NOT NULL,
|
|
178
|
+
updated_at TEXT NOT NULL
|
|
179
|
+
) STRICT;
|
|
180
|
+
`;
|
|
181
|
+
const V6_AUTH_GRANTS_INDEX = `
|
|
182
|
+
CREATE INDEX IF NOT EXISTS auth_grants_lookup
|
|
183
|
+
ON auth_grants (agent_id, tenant_id, grant_id);
|
|
184
|
+
`;
|
|
185
|
+
// PROPOSAL_QUEUE_SCHEMA_ENCRYPTED_PAYLOAD_001 ✅ Production-06a
|
|
186
|
+
// PROPOSAL_QUEUE_NO_PLAINTEXT_CANDIDATE_CLAIMS_001 ✅ Production-06a
|
|
187
|
+
// candidateClaims are stored as encrypted_payload (EncryptedBlob JSON).
|
|
188
|
+
// No plaintext candidateClaims, rationale, or reject_reason columns.
|
|
189
|
+
const V7_PROPOSALS_DDL = `
|
|
190
|
+
CREATE TABLE IF NOT EXISTS proposals (
|
|
191
|
+
proposal_id TEXT NOT NULL PRIMARY KEY,
|
|
192
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'accepted', 'rejected')),
|
|
193
|
+
proposed_by_agent TEXT NOT NULL,
|
|
194
|
+
under_grant TEXT NOT NULL,
|
|
195
|
+
encrypted_payload TEXT NOT NULL,
|
|
196
|
+
payload_key_id TEXT NOT NULL,
|
|
197
|
+
created_at TEXT NOT NULL,
|
|
198
|
+
updated_at TEXT NOT NULL,
|
|
199
|
+
decided_at TEXT
|
|
200
|
+
) STRICT;
|
|
201
|
+
`;
|
|
202
|
+
const V7_PROPOSALS_IDX_STATUS = `
|
|
203
|
+
CREATE INDEX IF NOT EXISTS idx_proposals_status
|
|
204
|
+
ON proposals (status);
|
|
205
|
+
`;
|
|
206
|
+
const V7_PROPOSALS_IDX_AGENT = `
|
|
207
|
+
CREATE INDEX IF NOT EXISTS idx_proposals_agent
|
|
208
|
+
ON proposals (proposed_by_agent);
|
|
209
|
+
`;
|
|
210
|
+
const V7_PROPOSALS_IDX_GRANT = `
|
|
211
|
+
CREATE INDEX IF NOT EXISTS idx_proposals_grant
|
|
212
|
+
ON proposals (under_grant);
|
|
213
|
+
`;
|
|
214
|
+
const V7_PROPOSALS_IDX_STATUS_GRANT = `
|
|
215
|
+
CREATE INDEX IF NOT EXISTS idx_proposals_status_grant
|
|
216
|
+
ON proposals (status, under_grant);
|
|
217
|
+
`;
|
|
218
|
+
// PRODUCTION_AUTH_SCHEMA_V8_PERSON_SCOPE_001
|
|
219
|
+
const V8_AUTH_GRANTS_PERSON_ID = `
|
|
220
|
+
ALTER TABLE auth_grants ADD COLUMN person_id TEXT;
|
|
221
|
+
`;
|
|
222
|
+
// ─── v9: Audit Hardening C4 — Local Hash Chain ──────────────────────────────────
|
|
223
|
+
// PRODUCTION_AUDIT_C4_HASH_CHAIN_SEQUENCE_001 / PRODUCTION_AUDIT_C4_PREV_HASH_LINKAGE_001 /
|
|
224
|
+
// PRODUCTION_AUDIT_C4_BACKFILL_LEGACY_CHAIN_VALID_001
|
|
225
|
+
//
|
|
226
|
+
// DEFAULT 0 / DEFAULT '' are temporary scaffolding to satisfy NOT NULL during ALTER. The
|
|
227
|
+
// backfill loop replaces them for every existing row before the unique index is created, so
|
|
228
|
+
// no committed chain row ever carries the scaffold values.
|
|
229
|
+
const V9_AUDIT_ADD_SEQUENCE = `ALTER TABLE audit_events ADD COLUMN sequence INTEGER NOT NULL DEFAULT 0`;
|
|
230
|
+
const V9_AUDIT_ADD_PREV_HASH = `ALTER TABLE audit_events ADD COLUMN prev_hash TEXT`;
|
|
231
|
+
const V9_AUDIT_ADD_EVENT_HASH = `ALTER TABLE audit_events ADD COLUMN event_hash TEXT NOT NULL DEFAULT ''`;
|
|
232
|
+
const V9_AUDIT_SEQUENCE_INDEX = `CREATE UNIQUE INDEX audit_events_sequence_unique ON audit_events(sequence)`;
|
|
233
|
+
// PRODUCTION_AUDIT_C4_BACKFILL_LEGACY_CHAIN_VALID_001: build a valid chain from current DB
|
|
234
|
+
// state, ordered by rowid ASC (stable SQLite insertion order). Runs inside the migration
|
|
235
|
+
// transaction; synchronous (better-sqlite3) so it uses sha256hexSync.
|
|
236
|
+
function backfillAuditChain(db) {
|
|
237
|
+
const rows = db
|
|
238
|
+
.prepare(`SELECT id, recorded_at, actor, grant_id, purpose, decision, reason_code,
|
|
239
|
+
selector_fingerprint, result_count, result_claim_ids, contract_ids
|
|
240
|
+
FROM audit_events ORDER BY rowid ASC`)
|
|
241
|
+
.all();
|
|
242
|
+
const update = db.prepare(`UPDATE audit_events SET sequence = ?, prev_hash = ?, event_hash = ? WHERE id = ?`);
|
|
243
|
+
let prevEventHash = null;
|
|
244
|
+
for (let i = 0; i < rows.length; i++) {
|
|
245
|
+
const row = rows[i];
|
|
246
|
+
const seq = i + 1;
|
|
247
|
+
const canonical = buildChainCanonical({
|
|
248
|
+
actor: row.actor,
|
|
249
|
+
contract_ids: row.contract_ids,
|
|
250
|
+
decision: row.decision,
|
|
251
|
+
grant_id: row.grant_id,
|
|
252
|
+
id: row.id,
|
|
253
|
+
prev_hash: prevEventHash,
|
|
254
|
+
purpose: row.purpose,
|
|
255
|
+
reason_code: row.reason_code,
|
|
256
|
+
recorded_at: row.recorded_at,
|
|
257
|
+
result_claim_ids: row.result_claim_ids,
|
|
258
|
+
result_count: row.result_count,
|
|
259
|
+
selector_fingerprint: row.selector_fingerprint,
|
|
260
|
+
sequence: seq,
|
|
261
|
+
});
|
|
262
|
+
const eventHash = sha256hexSync(canonical);
|
|
263
|
+
update.run(seq, prevEventHash, eventHash, row.id);
|
|
264
|
+
prevEventHash = eventHash;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const MIGRATIONS = [
|
|
268
|
+
{
|
|
269
|
+
fromVersion: 0,
|
|
270
|
+
apply(db) {
|
|
271
|
+
db.exec(V1_SCHEMA_META_DDL);
|
|
272
|
+
db.exec(V1_CLAIMS_DDL);
|
|
273
|
+
// INSERT OR IGNORE never overwrites an existing schema_version string.
|
|
274
|
+
db.prepare("INSERT OR IGNORE INTO schema_meta (key, value) VALUES ('schema_version', 'sqlite-claims-v1')").run();
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
fromVersion: 1,
|
|
279
|
+
apply(db) {
|
|
280
|
+
db.exec(V2_SOURCES_BASE_DDL);
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
fromVersion: 2,
|
|
285
|
+
apply(db) {
|
|
286
|
+
db.exec(V3_RAW_DOCUMENTS_DDL);
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
fromVersion: 3,
|
|
291
|
+
apply(db) {
|
|
292
|
+
for (const sql of V4_EVIDENCE_COLUMNS) {
|
|
293
|
+
db.prepare(sql).run();
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
fromVersion: 4,
|
|
299
|
+
apply(db) {
|
|
300
|
+
db.exec(V5_AUDIT_EVENTS_DDL);
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
fromVersion: 5,
|
|
305
|
+
apply(db) {
|
|
306
|
+
db.exec(V6_AUTH_TENANT_MEMBERSHIPS_DDL);
|
|
307
|
+
db.exec(V6_AUTH_GRANTS_DDL);
|
|
308
|
+
db.exec(V6_AUTH_GRANTS_INDEX);
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
fromVersion: 6,
|
|
313
|
+
apply(db) {
|
|
314
|
+
db.exec(V7_PROPOSALS_DDL);
|
|
315
|
+
db.exec(V7_PROPOSALS_IDX_STATUS);
|
|
316
|
+
db.exec(V7_PROPOSALS_IDX_AGENT);
|
|
317
|
+
db.exec(V7_PROPOSALS_IDX_GRANT);
|
|
318
|
+
db.exec(V7_PROPOSALS_IDX_STATUS_GRANT);
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
fromVersion: 7,
|
|
323
|
+
apply(db) {
|
|
324
|
+
db.prepare(V8_AUTH_GRANTS_PERSON_ID.trim()).run();
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
// PRODUCTION_AUDIT_C4_HASH_CHAIN_SEQUENCE_001 (v9): add chain columns, backfill, unique index.
|
|
329
|
+
// PRODUCTION_AUDIT_C4_WRITE_ATOMIC_BEGIN_IMMEDIATE_001: runs within the single BEGIN IMMEDIATE
|
|
330
|
+
// migration transaction — no half-migrated chain is ever observable.
|
|
331
|
+
fromVersion: 8,
|
|
332
|
+
apply(db) {
|
|
333
|
+
db.prepare(V9_AUDIT_ADD_SEQUENCE).run();
|
|
334
|
+
db.prepare(V9_AUDIT_ADD_PREV_HASH).run();
|
|
335
|
+
db.prepare(V9_AUDIT_ADD_EVENT_HASH).run();
|
|
336
|
+
backfillAuditChain(db);
|
|
337
|
+
db.prepare(V9_AUDIT_SEQUENCE_INDEX).run();
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
// GUARDIAN_AUDIT_MARKED_001 (v10): add guardian audit columns to audit_events.
|
|
342
|
+
// Both columns are nullable — NULL = not a guardian action.
|
|
343
|
+
// GUARDIAN_AUDIT_HASH_CHAIN_BACKWARD_COMPATIBLE_001: pre-existing rows remain NULL; their
|
|
344
|
+
// chain hashes are computed without these fields (absent from canonical) → unchanged.
|
|
345
|
+
fromVersion: 9,
|
|
346
|
+
apply(db) {
|
|
347
|
+
db.prepare(`ALTER TABLE audit_events ADD COLUMN acting_as_guardian INTEGER`).run();
|
|
348
|
+
db.prepare(`ALTER TABLE audit_events ADD COLUMN ward_id TEXT`).run();
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
];
|
|
352
|
+
// ─── Structural verification ──────────────────────────────────────────────────
|
|
353
|
+
// SQLITE_MIGRATION_CURRENT_SCHEMA_STRUCTURAL_VERIFY_001
|
|
354
|
+
export function verifyCurrentSchema(db) {
|
|
355
|
+
const missing = [];
|
|
356
|
+
const existingTables = new Set(db
|
|
357
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table'")
|
|
358
|
+
.all().map((r) => r.name));
|
|
359
|
+
for (const table of REQUIRED_TABLES) {
|
|
360
|
+
if (!existingTables.has(table))
|
|
361
|
+
missing.push(`table:${table}`);
|
|
362
|
+
}
|
|
363
|
+
// Only check columns and indexes once all required tables are confirmed present.
|
|
364
|
+
if (missing.length === 0) {
|
|
365
|
+
for (const [table, cols] of Object.entries(REQUIRED_COLUMNS)) {
|
|
366
|
+
const existingCols = new Set(db.pragma(`table_info(${table})`).map((r) => r.name));
|
|
367
|
+
for (const col of cols) {
|
|
368
|
+
if (!existingCols.has(col))
|
|
369
|
+
missing.push(`${table}.${col}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const existingIndexes = new Set(db
|
|
373
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='index'")
|
|
374
|
+
.all().map((r) => r.name));
|
|
375
|
+
for (const idx of REQUIRED_INDEXES) {
|
|
376
|
+
if (!existingIndexes.has(idx))
|
|
377
|
+
missing.push(`index:${idx}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return missing.length === 0 ? { ok: true } : { ok: false, missing };
|
|
381
|
+
}
|
|
382
|
+
// SQLITE_MIGRATION_CURRENT_SCHEMA_STRUCTURAL_VERIFY_001
|
|
383
|
+
function assertCurrentSchema(db) {
|
|
384
|
+
const result = verifyCurrentSchema(db);
|
|
385
|
+
if (!result.ok) {
|
|
386
|
+
throw Object.assign(new Error(`[${VERIFY_FAILED_CODE}] Schema verification failed. ` +
|
|
387
|
+
`Missing: ${result.missing.join(", ")}.`), { code: VERIFY_FAILED_CODE, missing: result.missing });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// ─── Version inference ────────────────────────────────────────────────────────
|
|
391
|
+
// Used only when schema_meta exists but migration_version key is absent.
|
|
392
|
+
// Returns the highest migration step whose preconditions are met by the current schema.
|
|
393
|
+
function inferMigrationVersion(db) {
|
|
394
|
+
const tables = new Set(db
|
|
395
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table'")
|
|
396
|
+
.all().map((r) => r.name));
|
|
397
|
+
if (!tables.has("claims"))
|
|
398
|
+
return 0; // schema_meta-only DB — start from scratch
|
|
399
|
+
if (!tables.has("sources"))
|
|
400
|
+
return 1;
|
|
401
|
+
const sourceCols = new Set(db.pragma("table_info(sources)").map((r) => r.name));
|
|
402
|
+
if (!tables.has("raw_documents"))
|
|
403
|
+
return 2;
|
|
404
|
+
if (!sourceCols.has("evidence_id"))
|
|
405
|
+
return 3;
|
|
406
|
+
if (!tables.has("audit_events"))
|
|
407
|
+
return 4;
|
|
408
|
+
if (!tables.has("auth_tenant_memberships") || !tables.has("auth_grants"))
|
|
409
|
+
return 5;
|
|
410
|
+
if (!tables.has("proposals"))
|
|
411
|
+
return 6;
|
|
412
|
+
// v8 check: auth_grants must have person_id column
|
|
413
|
+
const grantCols = new Set(db.pragma("table_info(auth_grants)").map(r => r.name));
|
|
414
|
+
if (!grantCols.has("person_id"))
|
|
415
|
+
return 7;
|
|
416
|
+
// The audit_events table exists. Before deciding whether it is a v8-complete DB awaiting
|
|
417
|
+
// the v9 chain upgrade, confirm its pre-v9 columns are intact. A table missing pre-v9
|
|
418
|
+
// columns (e.g. selector_fingerprint) is a structurally-broken legacy DB — fail closed here
|
|
419
|
+
// rather than letting the destructive v9 ALTER + backfill run and surface a raw SQLITE_ERROR.
|
|
420
|
+
// SQLITE_MIGRATION_LEGACY_SCHEMA_INCOMPLETE_001
|
|
421
|
+
const auditCols = new Set(db.pragma("table_info(audit_events)").map(r => r.name));
|
|
422
|
+
const PRE_V9_AUDIT_COLUMNS = [
|
|
423
|
+
"id", "recorded_at", "actor", "grant_id", "purpose", "decision",
|
|
424
|
+
"reason_code", "selector_fingerprint", "result_count", "result_claim_ids",
|
|
425
|
+
"contract_ids",
|
|
426
|
+
];
|
|
427
|
+
const missingPreV9 = PRE_V9_AUDIT_COLUMNS.filter(c => !auditCols.has(c));
|
|
428
|
+
if (missingPreV9.length > 0) {
|
|
429
|
+
throw Object.assign(new Error(`[${LEGACY_INCOMPLETE_CODE}] Legacy database has all required tables but ` +
|
|
430
|
+
`audit_events is missing columns: ${missingPreV9.map(c => `audit_events.${c}`).join(", ")}. ` +
|
|
431
|
+
`Cannot determine a safe migration starting point.`), { code: LEGACY_INCOMPLETE_CODE, missing: missingPreV9.map(c => `audit_events.${c}`) });
|
|
432
|
+
}
|
|
433
|
+
// v9 check: audit_events must have the C4 hash-chain columns.
|
|
434
|
+
// PRODUCTION_AUDIT_C4_HASH_CHAIN_SEQUENCE_001
|
|
435
|
+
if (!auditCols.has("sequence") || !auditCols.has("event_hash"))
|
|
436
|
+
return 8;
|
|
437
|
+
// v10 check: audit_events must have the guardian columns.
|
|
438
|
+
// GUARDIAN_AUDIT_MARKED_001
|
|
439
|
+
if (!auditCols.has("acting_as_guardian") || !auditCols.has("ward_id"))
|
|
440
|
+
return 9;
|
|
441
|
+
// All tables and v10 columns present.
|
|
442
|
+
return 10;
|
|
443
|
+
}
|
|
444
|
+
// ─── Legacy DB handling ───────────────────────────────────────────────────────
|
|
445
|
+
// SQLITE_MIGRATION_LEGACY_SCHEMA_NOT_ASSUMED_CURRENT_001
|
|
446
|
+
// SQLITE_MIGRATION_OLD_SCHEMA_META_HANDLED_001
|
|
447
|
+
function handleLegacyUnversioned(db) {
|
|
448
|
+
// schema_meta exists but migration_version key is absent.
|
|
449
|
+
// This DB was produced by the old flat initializeSchema() or is genuinely incomplete.
|
|
450
|
+
// We NEVER assume "fully migrated" without structural proof.
|
|
451
|
+
const inferred = inferMigrationVersion(db);
|
|
452
|
+
if (inferred === CURRENT_SCHEMA_VERSION) {
|
|
453
|
+
// All tables are present. Perform full column check before stamping.
|
|
454
|
+
// SQLITE_MIGRATION_LEGACY_SCHEMA_NOT_ASSUMED_CURRENT_001
|
|
455
|
+
const verification = verifyCurrentSchema(db);
|
|
456
|
+
if (!verification.ok) {
|
|
457
|
+
// Tables all present but columns are missing — cannot infer which step to re-run.
|
|
458
|
+
// SQLITE_MIGRATION_LEGACY_SCHEMA_INCOMPLETE_001
|
|
459
|
+
throw Object.assign(new Error(`[${LEGACY_INCOMPLETE_CODE}] Legacy database has all required tables but is ` +
|
|
460
|
+
`missing columns: ${verification.missing.join(", ")}. ` +
|
|
461
|
+
`Cannot determine a safe migration starting point.`), { code: LEGACY_INCOMPLETE_CODE, missing: verification.missing });
|
|
462
|
+
}
|
|
463
|
+
// Schema is structurally complete — stamp migration_version so future opens are fast.
|
|
464
|
+
writeMigrationVersion(db, CURRENT_SCHEMA_VERSION);
|
|
465
|
+
return CURRENT_SCHEMA_VERSION;
|
|
466
|
+
}
|
|
467
|
+
// inferred < CURRENT_SCHEMA_VERSION — run pending migrations from the inferred start.
|
|
468
|
+
return inferred;
|
|
469
|
+
}
|
|
470
|
+
// ─── Version read / write ─────────────────────────────────────────────────────
|
|
471
|
+
function writeMigrationVersion(db, version) {
|
|
472
|
+
db.prepare("INSERT OR REPLACE INTO schema_meta (key, value) VALUES ('migration_version', ?)").run(String(version));
|
|
473
|
+
}
|
|
474
|
+
// ─── Migration execution ──────────────────────────────────────────────────────
|
|
475
|
+
function applyPendingMigrations(db, fromVersion) {
|
|
476
|
+
const pending = MIGRATIONS.filter((m) => m.fromVersion >= fromVersion);
|
|
477
|
+
if (pending.length === 0)
|
|
478
|
+
return;
|
|
479
|
+
// SQLITE_MIGRATIONS_RUN_IN_TRANSACTION_001: all steps commit atomically.
|
|
480
|
+
// PRODUCTION_AUDIT_C4_WRITE_ATOMIC_BEGIN_IMMEDIATE_001: BEGIN IMMEDIATE reserves the write
|
|
481
|
+
// lock up front so schema changes + C4 backfill never leave a half-migrated chain.
|
|
482
|
+
db.prepare("BEGIN IMMEDIATE").run();
|
|
483
|
+
try {
|
|
484
|
+
for (const step of pending) {
|
|
485
|
+
step.apply(db);
|
|
486
|
+
}
|
|
487
|
+
writeMigrationVersion(db, CURRENT_SCHEMA_VERSION);
|
|
488
|
+
db.prepare("COMMIT").run();
|
|
489
|
+
}
|
|
490
|
+
catch (err) {
|
|
491
|
+
try {
|
|
492
|
+
db.prepare("ROLLBACK").run();
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
/* DB already closed or in bad state — original error is what matters */
|
|
496
|
+
}
|
|
497
|
+
throw err;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
// ─── Public runner ────────────────────────────────────────────────────────────
|
|
501
|
+
export function runMigrations(db) {
|
|
502
|
+
// Resolve the current migration version, handling the legacy unversioned case.
|
|
503
|
+
const hasMeta = db
|
|
504
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='schema_meta'")
|
|
505
|
+
.get();
|
|
506
|
+
const current = (() => {
|
|
507
|
+
if (!hasMeta)
|
|
508
|
+
return 0; // completely empty DB
|
|
509
|
+
const row = db
|
|
510
|
+
.prepare("SELECT value FROM schema_meta WHERE key = 'migration_version'")
|
|
511
|
+
.get();
|
|
512
|
+
if (!row) {
|
|
513
|
+
// SQLITE_MIGRATION_LEGACY_SCHEMA_NOT_ASSUMED_CURRENT_001:
|
|
514
|
+
// schema_meta present but migration_version absent → do NOT assume current.
|
|
515
|
+
// SQLITE_MIGRATION_OLD_SCHEMA_META_HANDLED_001:
|
|
516
|
+
// old schema_version string and flat-initializeSchema DBs go through structural check.
|
|
517
|
+
return handleLegacyUnversioned(db);
|
|
518
|
+
}
|
|
519
|
+
return parseInt(row.value, 10);
|
|
520
|
+
})();
|
|
521
|
+
if (current > CURRENT_SCHEMA_VERSION) {
|
|
522
|
+
// SQLITE_MIGRATION_FAILS_CLOSED_ON_UNKNOWN_FUTURE_VERSION_001
|
|
523
|
+
throw Object.assign(new Error(`[${FAIL_CLOSED_CODE}] Database migration_version ${current} exceeds ` +
|
|
524
|
+
`runner ceiling ${CURRENT_SCHEMA_VERSION}. ` +
|
|
525
|
+
`Upgrade the Life-as-API package to open this database.`), { code: FAIL_CLOSED_CODE });
|
|
526
|
+
}
|
|
527
|
+
if (current < CURRENT_SCHEMA_VERSION) {
|
|
528
|
+
applyPendingMigrations(db, current);
|
|
529
|
+
}
|
|
530
|
+
// SQLITE_MIGRATION_CURRENT_SCHEMA_STRUCTURAL_VERIFY_001:
|
|
531
|
+
// Always verify structural completeness — even when migration_version claims current.
|
|
532
|
+
// This catches tampered version numbers and post-commit corruption.
|
|
533
|
+
assertCurrentSchema(db);
|
|
534
|
+
}
|
|
535
|
+
//# sourceMappingURL=migrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../../src/persistence/sqlite/migrations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Database } from "better-sqlite3";
|
|
2
|
+
export declare const SCHEMA_VERSION = "sqlite-claims-v1";
|
|
3
|
+
export declare const SERIALIZER_VERSION = "claim-serializer-v1";
|
|
4
|
+
export declare const CLAIMS_DDL = "\nCREATE TABLE IF NOT EXISTS claims (\n id TEXT PRIMARY KEY,\n source_id TEXT NOT NULL,\n subject TEXT NOT NULL,\n predicate TEXT NOT NULL,\n valid_from TEXT NOT NULL,\n valid_to TEXT,\n recorded_at TEXT NOT NULL,\n recorded_seq INTEGER NOT NULL UNIQUE,\n retracts TEXT,\n supersedes TEXT,\n overrides TEXT,\n contract_id TEXT,\n confidence REAL,\n serializer_version TEXT NOT NULL,\n encrypted_payload TEXT NOT NULL\n) STRICT;\n";
|
|
5
|
+
export declare const SCHEMA_META_DDL = "\nCREATE TABLE IF NOT EXISTS schema_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n) STRICT;\n";
|
|
6
|
+
export declare const SOURCES_DDL = "\nCREATE TABLE IF NOT EXISTS sources (\n id TEXT PRIMARY KEY,\n kind TEXT NOT NULL,\n label TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'active',\n created_at TEXT NOT NULL,\n created_by TEXT NOT NULL,\n evidence_id TEXT,\n evidence_uri TEXT,\n evidence_hash TEXT,\n evidence_mime TEXT,\n evidence_enc INTEGER,\n metadata TEXT\n) STRICT;\n";
|
|
7
|
+
export declare const RAW_DOCUMENTS_DDL = "\nCREATE TABLE IF NOT EXISTS raw_documents (\n id TEXT PRIMARY KEY,\n mime_type TEXT NOT NULL,\n byte_length INTEGER NOT NULL,\n label TEXT,\n created_at TEXT NOT NULL,\n created_by TEXT NOT NULL,\n encrypted_blob TEXT NOT NULL,\n metadata TEXT\n) STRICT;\n";
|
|
8
|
+
export declare const AUDIT_EVENTS_DDL = "\nCREATE TABLE IF NOT EXISTS audit_events (\n id TEXT PRIMARY KEY,\n recorded_at TEXT NOT NULL,\n actor TEXT NOT NULL,\n grant_id TEXT,\n purpose TEXT,\n decision TEXT NOT NULL,\n reason_code TEXT NOT NULL,\n selector_fingerprint TEXT NOT NULL,\n result_count INTEGER NOT NULL,\n result_claim_ids TEXT NOT NULL,\n contract_ids TEXT\n) STRICT;\n";
|
|
9
|
+
export declare function initializeSchema(db: Database): void;
|
|
10
|
+
export declare function getSchemaVersion(db: Database): string | undefined;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// SQLite schema for the claims table.
|
|
2
|
+
//
|
|
3
|
+
// SQLITE_SCHEMA_VERSIONED_001: schema version tracked in schema_meta table.
|
|
4
|
+
// SQLITE_APPEND_ONLY_001: no UPDATE or DELETE statements anywhere in this module.
|
|
5
|
+
// SQLITE_PAYLOAD_ENCRYPTED_AT_REST_001: encrypted_payload column stores ciphertext only.
|
|
6
|
+
//
|
|
7
|
+
// Column layout:
|
|
8
|
+
// Metadata columns — plaintext (CRYPTO_METADATA_PLAINTEXT_ACCEPTED_001)
|
|
9
|
+
// encrypted_payload — JSON-serialized EncryptedBlob (AES-256-GCM ciphertext)
|
|
10
|
+
// serializer_version — "claim-serializer-v1" (SQLITE_SCHEMA_VERSIONED_001)
|
|
11
|
+
import { runMigrations } from "./migrations.js";
|
|
12
|
+
export const SCHEMA_VERSION = "sqlite-claims-v1";
|
|
13
|
+
export const SERIALIZER_VERSION = "claim-serializer-v1";
|
|
14
|
+
export const CLAIMS_DDL = `
|
|
15
|
+
CREATE TABLE IF NOT EXISTS claims (
|
|
16
|
+
id TEXT PRIMARY KEY,
|
|
17
|
+
source_id TEXT NOT NULL,
|
|
18
|
+
subject TEXT NOT NULL,
|
|
19
|
+
predicate TEXT NOT NULL,
|
|
20
|
+
valid_from TEXT NOT NULL,
|
|
21
|
+
valid_to TEXT,
|
|
22
|
+
recorded_at TEXT NOT NULL,
|
|
23
|
+
recorded_seq INTEGER NOT NULL UNIQUE,
|
|
24
|
+
retracts TEXT,
|
|
25
|
+
supersedes TEXT,
|
|
26
|
+
overrides TEXT,
|
|
27
|
+
contract_id TEXT,
|
|
28
|
+
confidence REAL,
|
|
29
|
+
serializer_version TEXT NOT NULL,
|
|
30
|
+
encrypted_payload TEXT NOT NULL
|
|
31
|
+
) STRICT;
|
|
32
|
+
`;
|
|
33
|
+
export const SCHEMA_META_DDL = `
|
|
34
|
+
CREATE TABLE IF NOT EXISTS schema_meta (
|
|
35
|
+
key TEXT PRIMARY KEY,
|
|
36
|
+
value TEXT NOT NULL
|
|
37
|
+
) STRICT;
|
|
38
|
+
`;
|
|
39
|
+
// SOURCE_REGISTRY_EXISTS_001: source records are plaintext (MVP accepted risk — no PII here).
|
|
40
|
+
export const SOURCES_DDL = `
|
|
41
|
+
CREATE TABLE IF NOT EXISTS sources (
|
|
42
|
+
id TEXT PRIMARY KEY,
|
|
43
|
+
kind TEXT NOT NULL,
|
|
44
|
+
label TEXT NOT NULL,
|
|
45
|
+
status TEXT NOT NULL DEFAULT 'active',
|
|
46
|
+
created_at TEXT NOT NULL,
|
|
47
|
+
created_by TEXT NOT NULL,
|
|
48
|
+
evidence_id TEXT,
|
|
49
|
+
evidence_uri TEXT,
|
|
50
|
+
evidence_hash TEXT,
|
|
51
|
+
evidence_mime TEXT,
|
|
52
|
+
evidence_enc INTEGER,
|
|
53
|
+
metadata TEXT
|
|
54
|
+
) STRICT;
|
|
55
|
+
`;
|
|
56
|
+
// RAW_DOCUMENT_BYTES_ENCRYPTED_AT_REST_001: encrypted_blob holds JSON EncryptedBlob only.
|
|
57
|
+
// RAW_DOCUMENT_METADATA_PLAINTEXT_ACCEPTED_001: id/mime_type/byte_length/label/created_* are plaintext.
|
|
58
|
+
export const RAW_DOCUMENTS_DDL = `
|
|
59
|
+
CREATE TABLE IF NOT EXISTS raw_documents (
|
|
60
|
+
id TEXT PRIMARY KEY,
|
|
61
|
+
mime_type TEXT NOT NULL,
|
|
62
|
+
byte_length INTEGER NOT NULL,
|
|
63
|
+
label TEXT,
|
|
64
|
+
created_at TEXT NOT NULL,
|
|
65
|
+
created_by TEXT NOT NULL,
|
|
66
|
+
encrypted_blob TEXT NOT NULL,
|
|
67
|
+
metadata TEXT
|
|
68
|
+
) STRICT;
|
|
69
|
+
`;
|
|
70
|
+
// AUDIT_DURABLE_SINK_EXISTS_001: audit_events table is append-only.
|
|
71
|
+
// AUDIT_EVENT_NO_PAYLOAD_VALUES_001: no payload or document-bytes column — safe metadata only.
|
|
72
|
+
// AUDIT_EVENT_NO_RAW_DOCUMENT_BYTES_001: encrypted_blob / plainBytes columns are absent by design.
|
|
73
|
+
// AUDIT_EVENT_SELECTOR_FINGERPRINT_ONLY_001: selector_fingerprint stores a string summary, not the full selector.
|
|
74
|
+
// AUDIT_EVENTS_APPEND_ONLY_001: INSERT only — no UPDATE or DELETE rows in schema or implementation.
|
|
75
|
+
export const AUDIT_EVENTS_DDL = `
|
|
76
|
+
CREATE TABLE IF NOT EXISTS audit_events (
|
|
77
|
+
id TEXT PRIMARY KEY,
|
|
78
|
+
recorded_at TEXT NOT NULL,
|
|
79
|
+
actor TEXT NOT NULL,
|
|
80
|
+
grant_id TEXT,
|
|
81
|
+
purpose TEXT,
|
|
82
|
+
decision TEXT NOT NULL,
|
|
83
|
+
reason_code TEXT NOT NULL,
|
|
84
|
+
selector_fingerprint TEXT NOT NULL,
|
|
85
|
+
result_count INTEGER NOT NULL,
|
|
86
|
+
result_claim_ids TEXT NOT NULL,
|
|
87
|
+
contract_ids TEXT
|
|
88
|
+
) STRICT;
|
|
89
|
+
`;
|
|
90
|
+
export function initializeSchema(db) {
|
|
91
|
+
db.pragma("journal_mode = WAL");
|
|
92
|
+
db.pragma("foreign_keys = ON");
|
|
93
|
+
runMigrations(db); // SQLITE_MIGRATION_RUNNER_EXISTS_001
|
|
94
|
+
}
|
|
95
|
+
export function getSchemaVersion(db) {
|
|
96
|
+
const row = db
|
|
97
|
+
.prepare("SELECT value FROM schema_meta WHERE key = 'schema_version'")
|
|
98
|
+
.get();
|
|
99
|
+
return row?.value;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=schema.js.map
|