Spaces:
Sleeping
Sleeping
File size: 3,241 Bytes
6952bcb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | -- 007_knowledge (sqlite) — Phase 6 first-customer UX (docs/HARDENING.md):
-- company-knowledge ingestion (vault docs) + generated L5 exam drafts.
--
-- Data class T2 "crown jewels" (docs/TENANCY.md): uploaded company documents
-- and the exam items derived from them. Protection = T1 (org-scoped queries
-- via atp/tenant_db.py) PLUS Fernet encryption at rest via
-- atp/crypto.py encrypt_for_org (per-org HKDF subkeys):
-- * vault_docs.content_enc / summary_enc — 'enc1:…' ciphertext, never
-- plaintext (leak surface #7: T2 columns are ciphertext in dumps by
-- construction).
-- * l5_drafts.items_json_enc — exam items derived from the
-- docs, encrypted for the same reason; the blueprint (section names +
-- weights only) stays plaintext for review listings.
-- Tenant files NEVER land under /videos or /media (leak surface #4) — there
-- is no file path at all: content lives only in these encrypted columns.
--
-- Conventions (002/004/005/006):
-- * ts columns are ISO-8601 UTC strings ("%Y-%m-%dT%H:%M:%SZ").
-- * org_id defaults to 'org-demo', the bootstrap org (005 bridge), so dev
-- mode (BU_AUTH_DISABLED=1) keeps working unchanged.
-- * SQLite has NO row-level security: dev/demo isolation relies on layers
-- 1-2 of docs/TENANCY.md (route deps + org-scoped SQL). The Postgres
-- twin (007_knowledge.pg.sql) adds RLS.
--
-- Mutability model: NOT append-only, by design. Drafts are working documents
-- (draft -> approved | rejected state transitions; docs move uploaded ->
-- drafted -> signed). The tamper-evident record of who signed what lives in
-- the atp_evidence hash chain instead: approve/reject writes a signed
-- 'sme_signoff' evidence row via atp/signing.py append_chain.
--
-- Statement separator convention: a line containing only `--;;` splits this
-- file into statements (see atp/db.py).
CREATE TABLE IF NOT EXISTS vault_docs (
id TEXT PRIMARY KEY,
org_id TEXT NOT NULL DEFAULT 'org-demo',
title TEXT NOT NULL,
filename TEXT,
mime TEXT,
content_enc TEXT NOT NULL, -- Fernet 'enc1:…' via crypto.encrypt_for_org
summary_enc TEXT, -- heuristic summary, encrypted too (T2)
uploaded_by TEXT,
created_at TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'uploaded'
CHECK (status IN ('uploaded', 'drafted', 'signed'))
);
--;;
-- (org_id, <pk>) per docs/TENANCY.md invariants.
CREATE INDEX IF NOT EXISTS idx_vault_docs_org ON vault_docs(org_id, id);
--;;
CREATE TABLE IF NOT EXISTS l5_drafts (
id TEXT PRIMARY KEY,
org_id TEXT NOT NULL DEFAULT 'org-demo',
cert_label TEXT NOT NULL,
blueprint_json TEXT NOT NULL, -- sections/weights only — reviewable, plaintext
items_json_enc TEXT NOT NULL, -- T2: items derived from docs are encrypted
doc_ids_json TEXT NOT NULL, -- JSON array of vault_docs.id this draft covers
status TEXT NOT NULL DEFAULT 'draft'
CHECK (status IN ('draft', 'approved', 'rejected')),
created_by TEXT,
created_at TEXT NOT NULL,
reviewed_by TEXT,
reviewed_at TEXT,
review_note TEXT
);
--;;
CREATE INDEX IF NOT EXISTS idx_l5_drafts_org ON l5_drafts(org_id, id);
|