Christian: 'The goal is not to hamstring closed source developers. It's just to validate clean code.' Right. So the cap is a rung, not a wall, and it now says so. L0 unattested -> 3 nothing but your word L1 declared -> 5 SBOM + signed hash + published destination allowlist L2 observed -> 7 someone other than you watched this exact binary L3 reproducible -> 9 anyone can rebuild it and get the same bytes L4 contested -> 10 someone tried to break it and published the attempt A court filing lifts the ceiling entirely, because it needs no vendor cooperation. db/attest/validate.mjs computes the level from which artifacts exist. A vendor cannot claim one. The load-bearing rule is the attestor column: a vendor running our harness produces a DECLARATION, not an OBSERVATION. Verified against three cases. A vendor claiming L2 with their own capture report is downgraded to L1 and fails validation. The same artifacts with us as attestor grant L2. A broken rebuild claim never reaches L3. Levels 3 and 4 survive a self-run on purpose: a public rebuild recipe and a published adversarial review can be re-executed or re-read by anyone, so who pressed the button stops mattering. Honest limit, written into the module: this cannot prove the absence of a backdoor. Rice's theorem makes that undecidable, and a backdoor triggered by remote config or message content is invisible to static inspection. An attestation raises the cost and shortens the shelf life. It is not a proof.
246 lines
10 KiB
SQL
246 lines
10 KiB
SQL
-- bigtech.sucks — living database schema
|
|
-- The website is a view over this. Nothing in the site may hardcode a number
|
|
-- that lives here.
|
|
--
|
|
-- Design rule: an assessment is an ARTIFACT with a date, a version, a method and
|
|
-- evidence. A score without an assessment is a placeholder and is stored as NULL,
|
|
-- never as a guess.
|
|
|
|
PRAGMA foreign_keys = ON;
|
|
PRAGMA journal_mode = WAL;
|
|
|
|
-- ---------------------------------------------------------------- who owns it
|
|
CREATE TABLE IF NOT EXISTS vendor (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
legal_entity TEXT,
|
|
entity_type TEXT CHECK (entity_type IN ('nonprofit','private','public','state','unknown')),
|
|
jurisdiction TEXT, -- ISO 3166-1 alpha-2
|
|
business_model TEXT CHECK (business_model IN ('advertising','subscription','hardware','license','mixed','none','unknown')),
|
|
parent_id TEXT REFERENCES vendor(id),
|
|
founded TEXT,
|
|
notes TEXT
|
|
);
|
|
|
|
-- ---------------------------------------------------------------- what it is
|
|
CREATE TABLE IF NOT EXISTS category (
|
|
id TEXT PRIMARY KEY,
|
|
label TEXT NOT NULL,
|
|
sensitivity REAL NOT NULL CHECK (sensitivity BETWEEN 0 AND 1),
|
|
nextcloud TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS product (
|
|
id TEXT PRIMARY KEY,
|
|
vendor_id TEXT NOT NULL REFERENCES vendor(id),
|
|
name TEXT NOT NULL,
|
|
category_id TEXT REFERENCES category(id),
|
|
-- platform is part of the identity: Signal iOS != Signal Desktop
|
|
platform TEXT NOT NULL,
|
|
source_url TEXT,
|
|
license TEXT,
|
|
sovereign INTEGER NOT NULL DEFAULT 0 CHECK (sovereign IN (0,1)),
|
|
boss INTEGER NOT NULL DEFAULT 0 CHECK (boss IN (0,1)),
|
|
art_slot TEXT,
|
|
monthly_cost REAL,
|
|
-- priority > 0 puts a product on the board even before anything discovers it
|
|
priority INTEGER NOT NULL DEFAULT 0,
|
|
notes TEXT,
|
|
UNIQUE(id, platform)
|
|
);
|
|
|
|
-- ---------------------------------------------------------------- the instrument
|
|
CREATE TABLE IF NOT EXISTS dimension (
|
|
id TEXT PRIMARY KEY,
|
|
label TEXT NOT NULL,
|
|
weight REAL NOT NULL CHECK (weight > 0),
|
|
anchor_10 TEXT NOT NULL,
|
|
anchor_0 TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS assessment (
|
|
id TEXT PRIMARY KEY,
|
|
product_id TEXT NOT NULL REFERENCES product(id),
|
|
version TEXT NOT NULL,
|
|
source_commit TEXT,
|
|
assessed_on TEXT NOT NULL,
|
|
method_version TEXT NOT NULL,
|
|
-- 0 = none, 1 = available but experimental/unverified, 2 = verified
|
|
reproducible_build INTEGER NOT NULL DEFAULT 0 CHECK (reproducible_build IN (0,1,2)),
|
|
-- 1 = we can read the code. 0 = closed. Closed source cannot exceed 5 on any
|
|
-- dimension unless independent evidence (a capture or a court filing) says so.
|
|
source_available INTEGER NOT NULL DEFAULT 1 CHECK (source_available IN (0,1)),
|
|
weighted_total REAL NOT NULL CHECK (weighted_total BETWEEN 0 AND 100),
|
|
grade TEXT NOT NULL,
|
|
weakest_dimension TEXT NOT NULL REFERENCES dimension(id),
|
|
headline TEXT NOT NULL, -- the caveat, in one sentence
|
|
not_tested TEXT,
|
|
UNIQUE(product_id, version, assessed_on)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS score (
|
|
assessment_id TEXT NOT NULL REFERENCES assessment(id) ON DELETE CASCADE,
|
|
dimension_id TEXT NOT NULL REFERENCES dimension(id),
|
|
value REAL NOT NULL CHECK (value BETWEEN 0 AND 10),
|
|
rationale TEXT,
|
|
PRIMARY KEY (assessment_id, dimension_id)
|
|
);
|
|
|
|
-- evidence is the only thing that makes a score legitimate
|
|
CREATE TABLE IF NOT EXISTS evidence (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
assessment_id TEXT NOT NULL REFERENCES assessment(id) ON DELETE CASCADE,
|
|
dimension_id TEXT REFERENCES dimension(id),
|
|
claim TEXT NOT NULL,
|
|
tier INTEGER NOT NULL CHECK (tier IN (1,2,3,4)),
|
|
kind TEXT CHECK (kind IN ('source','capture','record','filing','advisory','paper','claim')),
|
|
artifact TEXT, -- path inside the vault, or URL
|
|
sha256 TEXT,
|
|
observed_at TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS finding (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
assessment_id TEXT NOT NULL REFERENCES assessment(id) ON DELETE CASCADE,
|
|
severity TEXT NOT NULL CHECK (severity IN ('critical','high','medium','low','info')),
|
|
title TEXT NOT NULL,
|
|
detail TEXT,
|
|
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open','fixed','by_design','disputed','accepted')),
|
|
disclosed_on TEXT,
|
|
cve TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS offramp (
|
|
product_id TEXT NOT NULL REFERENCES product(id),
|
|
replacement TEXT NOT NULL,
|
|
nextcloud TEXT,
|
|
notes TEXT,
|
|
PRIMARY KEY (product_id, replacement)
|
|
);
|
|
|
|
-- ---------------------------------------------------------------- discovery
|
|
-- The database authors itself. Every product the ingest finds leaves a receipt
|
|
-- here, so a reader can see WHERE it came from and HOW MUCH it is used.
|
|
-- Discovery may create a product. Discovery may NEVER create a score.
|
|
CREATE TABLE IF NOT EXISTS discovery (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
product_id TEXT NOT NULL REFERENCES product(id),
|
|
source TEXT NOT NULL CHECK (source IN ('github','flathub','alternativeto','manual','seed')),
|
|
source_url TEXT,
|
|
usage_signal INTEGER,
|
|
usage_metric TEXT,
|
|
observed_at TEXT NOT NULL,
|
|
raw TEXT,
|
|
UNIQUE(product_id, source, source_url)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_discovery_product ON discovery(product_id);
|
|
|
|
-- ---------------------------------------------------------------- attestation
|
|
-- Closed source can earn its way up, but only by producing evidence that expires.
|
|
--
|
|
-- The level is NOT claimed by the vendor and NOT assigned by us. It is COMPUTED
|
|
-- from which required artifacts actually exist. A vendor can claim level 4 all day;
|
|
-- if the capture report is missing, the validator grants level 1.
|
|
--
|
|
-- Every attestation is bound to one artifact hash on one version. Any new build
|
|
-- invalidates it. There is no such thing as a standing certificate here.
|
|
CREATE TABLE IF NOT EXISTS attestation (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
product_id TEXT NOT NULL REFERENCES product(id),
|
|
version TEXT NOT NULL,
|
|
artifact_sha256 TEXT NOT NULL,
|
|
level INTEGER NOT NULL CHECK (level BETWEEN 0 AND 4),
|
|
-- L1 declared: the vendor tells the world what is in the box
|
|
sbom_url TEXT, -- CycloneDX or SPDX
|
|
signed_hash_url TEXT, -- signed release manifest
|
|
destination_allowlist_url TEXT, -- every host it may contact, and why
|
|
-- L2 observed: we watched this exact binary
|
|
capture_report TEXT, -- D1-D4 output, hash-bound
|
|
-- L3 reproducible: the binary is provably the build they claim
|
|
rebuild_recipe_url TEXT,
|
|
rebuild_matches INTEGER CHECK (rebuild_matches IN (0,1)),
|
|
-- L4 adversarial: someone tried to break it and published the attempt
|
|
adversarial_report_url TEXT,
|
|
differential_clean INTEGER CHECK (differential_clean IN (0,1)),
|
|
issued_on TEXT NOT NULL,
|
|
expires_on TEXT NOT NULL,
|
|
auditor TEXT NOT NULL,
|
|
-- Who ran the test. This is the load-bearing column.
|
|
-- A vendor running our harness produces a DECLARATION, not an observation.
|
|
-- Declarations are capped at level 1, because a self-run test is a claim.
|
|
-- Levels 3 and 4 survive a self-run, because a public rebuild recipe and a
|
|
-- published adversarial review can be re-checked by anyone.
|
|
attestor TEXT NOT NULL DEFAULT 'vendor'
|
|
CHECK (attestor IN ('vendor','binary-ranch','third-party','community')),
|
|
UNIQUE(product_id, version, artifact_sha256)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_attestation_product ON attestation(product_id, version);
|
|
|
|
-- ---------------------------------------------------------------- derived views
|
|
-- The single number the game and the report both use.
|
|
CREATE VIEW IF NOT EXISTS v_product_score AS
|
|
SELECT
|
|
p.id AS product_id,
|
|
p.name AS product,
|
|
p.platform,
|
|
p.category_id,
|
|
v.id AS vendor_id,
|
|
v.name AS vendor,
|
|
v.business_model,
|
|
v.jurisdiction,
|
|
a.id AS assessment_id,
|
|
a.assessed_on,
|
|
a.version,
|
|
a.weighted_total,
|
|
a.grade,
|
|
a.weakest_dimension,
|
|
a.headline,
|
|
-- policy axis: who holds your data, and what can they be made to hand over
|
|
CAST(ROUND(10 * (
|
|
0.40 * (SELECT value FROM score WHERE assessment_id = a.id AND dimension_id = 'server_retention')
|
|
+ 0.30 * (SELECT value FROM score WHERE assessment_id = a.id AND dimension_id = 'ownership_jurisdiction')
|
|
+ 0.30 * (SELECT value FROM score WHERE assessment_id = a.id AND dimension_id = 'user_control_exit')
|
|
)) AS INTEGER) AS policy,
|
|
-- infra axis: can you verify it, and what does it leave on your disk
|
|
CAST(ROUND(10 * (
|
|
0.50 * (SELECT value FROM score WHERE assessment_id = a.id AND dimension_id = 'verifiability')
|
|
+ 0.30 * (SELECT value FROM score WHERE assessment_id = a.id AND dimension_id = 'dependency_surface')
|
|
+ 0.20 * (SELECT value FROM score WHERE assessment_id = a.id AND dimension_id = 'local_data_exposure')
|
|
)) AS INTEGER) AS infra
|
|
FROM product p
|
|
JOIN vendor v ON v.id = p.vendor_id
|
|
LEFT JOIN assessment a
|
|
ON a.product_id = p.id
|
|
AND a.assessed_on = (SELECT MAX(assessed_on) FROM assessment WHERE product_id = p.id);
|
|
|
|
-- A product with no assessment must surface as unassessed, not as a number.
|
|
CREATE VIEW IF NOT EXISTS v_coverage AS
|
|
SELECT
|
|
p.id AS product_id,
|
|
p.name,
|
|
p.platform,
|
|
CASE WHEN a.id IS NULL THEN 'unassessed' ELSE a.grade END AS status,
|
|
a.weighted_total
|
|
FROM product p
|
|
LEFT JOIN assessment a ON a.product_id = p.id
|
|
AND a.assessed_on = (SELECT MAX(assessed_on) FROM assessment WHERE product_id = p.id);
|
|
|
|
-- What to assess next. Anything a human put on the board outranks anything a
|
|
-- crawler found, and within each tier usage decides.
|
|
CREATE VIEW IF NOT EXISTS v_backlog AS
|
|
SELECT
|
|
p.id AS product_id,
|
|
p.name,
|
|
p.platform,
|
|
p.category_id,
|
|
p.priority AS priority,
|
|
COALESCE(MAX(d.usage_signal), 0) AS usage,
|
|
GROUP_CONCAT(DISTINCT d.source) AS found_via
|
|
FROM product p
|
|
LEFT JOIN discovery d ON d.product_id = p.id
|
|
WHERE NOT EXISTS (SELECT 1 FROM assessment a WHERE a.product_id = p.id)
|
|
AND (d.id IS NOT NULL OR p.priority > 0)
|
|
GROUP BY p.id
|
|
ORDER BY p.priority DESC, usage DESC;
|