Skip to content

Commit e4c9d24

Browse files
CodeWhale Botclaude
andcommitted
feat(cloud-facts): pin the first production trust anchor
Both trust tables were empty, which made the entire cloud-facts layer inert: with no active key `ticket()` returns `RefreshError::Inert`, so `refresh` and `maybe_load_persisted_cache` bail before reading anything, and `configure()` publishes `CloudFactsState::Inert`. Nothing downstream of that could run, however complete it was. And it was complete. Slice 1 (#5752) already shipped verification, scoping, the overlay, the catalog patch semantics, the full consumer wiring, the website transport and the publish tool. A signed fact lands on `ProviderModelOffering.limits` in `provider_lake.rs:764-812` and mints `RouteLimits`, which `route_budget.rs:47-51` consults *before* the fallback chain that currently ends at `LEGACY_DEEPSEEK_CONTEXT_WINDOW_TOKENS`. The gap was never schema or consumer. It was that no key existed. Anchor `cwf-2026-09`, Ed25519, generated by the founder with `facts-publish.mjs keygen`. The private half lives outside every repository at mode 0600 and was never read into this session: only the public half was derived locally, and only the public half is committed. Both tables carry the same key — `check-cloud-facts.mjs` now reports `OK (facts_version=1, 1 active production keys)`, up from 0. Why this has to land in the release rather than after it: a shipped binary can only trust a key it was compiled with. There is no in-band command that installs or widens trust, and `CODEWHALE_CLOUD_FACTS_PATH` verifies against this same table, so a local envelope is not an escape hatch either. A client that ships without the anchor can never be served a fact until it is replaced. Pinning it now is what makes delivery possible at all; it does not by itself deliver anything. Still required before any fact reaches a user, and all of it is founder authority: deploy `SUPABASE_URL` and the publication migration, confirm `facts_current` grants and RLS, then separately approve signing and publish a payload at a `facts_version` above the channel floor (1 today). This commit approves trust in a key. It does not approve a publication, and none has occurred. cargo test -p codewhale-config --locked cloud_facts test result: ok. 30 passed; 0 failed; 668 filtered out cargo test -p codewhale-cloud-facts --locked test result: ok. 17 passed; 0 failed node web/scripts/check-cloud-facts.mjs check-cloud-facts: OK (facts_version=1, 1 active production keys) cargo check --workspace --all-targets --locked: 0 errors, 0 warnings No new tests: the existing cloud-facts suite already covers verification, scoping and the empty-table inert path, and the parity gate is the check that matters for a two-table anchor. Refs: Linear SHA-6398, GitHub #5752. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X57KRgwqYkmmtVQScczqiL
1 parent 04a6e41 commit e4c9d24

2 files changed

Lines changed: 32 additions & 7 deletions

File tree

crates/config/src/cloud_facts/keys.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,27 @@ pub struct TrustedKey {
4848
pub status: KeyStatus,
4949
}
5050

51-
/// Production trust is deliberately empty until a public anchor is approved.
52-
/// Tests inject their own fixture keys; a shipped binary cannot trust those keys.
53-
pub const TRUSTED_KEYS: &[TrustedKey] = &[];
51+
/// Pinned production trust anchors.
52+
///
53+
/// A shipped binary can only trust a key it was compiled with — there is no
54+
/// in-band command that installs or widens trust, and `CODEWHALE_CLOUD_FACTS_PATH`
55+
/// verifies against this same table, so a local envelope is no escape hatch.
56+
/// Adding a key here is therefore a release-gated decision, and the matching
57+
/// entry in `web/lib/cloud-facts/keys.ts` must stay byte-identical:
58+
/// `check:facts` fails when the two tables diverge.
59+
///
60+
/// Tests inject their own fixture keys; no fixture signature establishes
61+
/// production trust.
62+
pub const TRUSTED_KEYS: &[TrustedKey] = &[TrustedKey {
63+
// Approved 2026-09-10. Private half held by the founder outside any
64+
// repository; only this public anchor is committed.
65+
key_id: "cwf-2026-09",
66+
public_key: [
67+
229, 221, 108, 200, 133, 179, 185, 249, 210, 78, 85, 107, 124, 85, 91, 236, 39, 143, 28,
68+
190, 129, 220, 233, 125, 216, 136, 82, 215, 148, 26, 6, 133,
69+
],
70+
status: KeyStatus::Active,
71+
}];
5472

5573
/// Look up a pinned key by id.
5674
#[must_use]

web/lib/cloud-facts/keys.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
* the two diverge. Keys are pinned here (and in the binary); the Supabase
66
* `facts_key` table is informational and never a trust root.
77
*
8-
* No production signing anchor has been approved for this release. An empty
9-
* table disables delivery before any transport read. Tests supply their own
10-
* public fixture keys; those keys never belong in this table.
8+
* The pinned anchor below is the trust root for delivery. Tests supply their
9+
* own public fixture keys; those keys never belong in this table.
1110
*/
1211
export type KeyStatus = "active" | "retired";
1312

@@ -23,7 +22,15 @@ export const ENVELOPE_VERSION = 1;
2322
export const SUPPORTED_SCHEMA_VERSION = 1;
2423
export const MAX_PAYLOAD_BYTES = 512 * 1024;
2524

26-
export const TRUSTED_KEYS: readonly TrustedKey[] = [];
25+
export const TRUSTED_KEYS: readonly TrustedKey[] = [
26+
{
27+
// Approved 2026-09-10. Mirrors crates/config/src/cloud_facts/keys.rs.
28+
// Private half held by the founder outside any repository.
29+
keyId: "cwf-2026-09",
30+
publicKey: "5d1syIWzufnSTlVrfFVb7CePHL6B3Ol92IhS15QaBoU=",
31+
status: "active",
32+
},
33+
];
2734

2835
export function trustedKey(keyId: string): TrustedKey | undefined {
2936
return TRUSTED_KEYS.find((key) => key.keyId === keyId);

0 commit comments

Comments
 (0)