feat(cloud-facts): signed, versioned, cached facts channel (slice 1, flag off) - #5752
Draft
Hmbown wants to merge 8 commits into
Draft
feat(cloud-facts): signed, versioned, cached facts channel (slice 1, flag off)#5752Hmbown wants to merge 8 commits into
Hmbown wants to merge 8 commits into
Conversation
…st fixtures Add web/scripts/facts-publish.mjs (zero-dependency Node: keygen, sign, verify, emit-sql, publish, revoke; private key and service key only from env at run time, refuses under CI) and docs/cloud-facts/stable.json as the human-edited source of truth for the facts/v1 stable channel. Signing contract: Ed25519 over "codewhale-facts/v1\0" || key_id || "\0" || canonical-JSON payload. docs/cloud-facts/fixtures/ carries a deliberately public TEST-ONLY keypair and two envelopes signed with it (v7 all-sections, v8 applies_to >=99.0.0) shared by the Rust and web test suites; the test-only key is never pinned. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net>
… layer 15 codewhale_config::cloud_facts is network-free: payload types (schema_version 1), pinned Ed25519 trust anchors (TRUSTED_KEYS; the dogfood key cwf-dogfood-2026-08 generated 2026-08-30, private half held outside every repo), verify_envelope (size cap -> shape -> pinned key -> ring Ed25519 -> parse -> cross-checks -> channel -> schema -> applies_to semver scope -> rollback -> not_after grace), scoped_view (per-item applies_to, announcement windows, https + official-host allowlist for base_url), a process-wide overlay with /status provenance, and field-level catalog patch semantics. CatalogSource::CloudFacts / CatalogCompiler::with_cloud_facts sit at layer 15 (above bundled + live models.dev, below provider /v1/models, config, user). PricingProvenance gains CloudFacts. Cloud default_model is consulted only after CLI/env/config declined, so an explicit choice is never overridden. cargo test -p codewhale-config: 642 passed; 0 failed; 1 ignored. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net>
New crate codewhale-cloud-facts modeled on the TUI models_dev_live producer: maybe_load_persisted_cache (bounded sync read, re-verified on every load, tampered cache deleted), refresh (If-None-Match/304, 404 = no facts, body cap, persisted exponential backoff, rollback-protected highest_seen_version), and spawn_background_refresh. Off by default; CODEWHALE_CLOUD_FACTS=1|0, CODEWHALE_DISABLE_CLOUD_FACTS=1 (hard kill), CODEWHALE_CLOUD_FACTS_URL / _CHANNEL / _PATH; CI markers suppress the fetch. Fixed identifier-free User-Agent only. Inert with no active pinned key. examples/fetch_live.rs is the dogfood/proof harness. No new registry entries in Cargo.lock (ring, base64, semver already in the graph). cargo test -p codewhale-cloud-facts: 8 passed; 0 failed (mock HTTP server: 200/304/404/500/oversize, cache round trip, tamper, local path, backoff). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…(default off) - [cloud_facts] config table (enabled=false, channel, url, ttl_hours) next to [update]; documented in config.example.toml. - Startup seam right after the models.dev pair: seed from the re-verified disk cache, then background refresh; nothing blocks startup. - provider_lake merges cloud patches between models.dev live and per-provider live rows (layer 15) and invalidates its memoized merge on overlay updates. - /status gains 'Catalog:' (models.dev freshness/count/age) and 'Cloud facts:' (channel/version/key/age/origin or why bundled is in use) rows; MessageIds added to all 15 locale bundles. - /model refresh also forces the cloud facts fetch when enabled. - Picker and fleet badges label CatalogSource::CloudFacts rows. CARGO_BUILD_JOBS=4 cargo check -p codewhale-tui: Finished (0 warnings). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…nnel> web/lib/cloud-facts.ts reads public.facts_current from the CodeWhale Web Supabase project over PostgREST with the publishable (anon) key only, rebuilds the envelope, recomputes the payload SHA-256 (mismatch -> 502), and verifies the Ed25519 signature against web/lib/cloud-facts/keys.ts (failure -> 503; the edge never amplifies a bad row; an empty key table skips verification and reports it). keys.ts mirrors crates/config/src/cloud_facts/keys.rs; check:facts fails on divergence. The route answers GET/HEAD with a strong ETag, If-None-Match -> 304, CDN cache headers (s-maxage=300, stale-while-revalidate, stale-if-error), no Set-Cookie/Vary/query params, and a KV last-good copy (CURATED_KV) served as X-Facts-Source: kv-stale when Supabase errors or times out (3 s budget); both down -> 503 Retry-After: 600. /api/facts gains an additive cloudFacts summary block; schemaVersion unchanged. Env names SUPABASE_URL / SUPABASE_PUBLISHABLE_KEY added to .env.example and wrangler.jsonc vars (values set by the founder); .dev.vars ignored. Verification skip now requires a truly empty key table, so a retired-only table still rejects instead of silently skipping. npm test: 355 passed, 0 failed (41 files). npm run check:facts OK (check-cloud-facts: keys.rs == keys.ts, stable.json release.latest == latest-published-release.json, fixtures verify). tsc --noEmit and eslint clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net>
… vocabulary docs/CLOUD_FACTS.md documents the facts/v1 channel end to end: envelope and domain-separated signing (Ed25519 over DOMAIN || key_id || payload), the Supabase schema with forced RLS and immutability/monotonic triggers, key custody and rotation runbook (the dogfood key cwf-dogfood-2026-08 was generated 2026-08-30; its private half lives outside every repo, noted for founder custody), the publish/revoke runbook, the /status vocabulary, the two-release key-then-flip rule, and the codewhale.net hosting discrepancy (Cloudflare Worker via OpenNext, not Vercel as the PRD states; the route is host-agnostic). CATALOG_REFRESH.md gains the layer-15 paragraph; CHANGELOG records the feature behind [cloud_facts].enabled (default off). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net>
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 36729265 | Triggered | Generic Private Key | 9e83f81 | docs/cloud-facts/fixtures/test-only-signing-key.pem | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
…re key docs/cloud-facts/fixtures/test-only-signing-key.pem is a deliberately public Ed25519 test fixture (never pinned, signs nothing outside tests). Silences the false-positive 'Generic Private Key' incident from 9e83f81. Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Hmbown
added a commit
that referenced
this pull request
Sep 8, 2026
Add an optional signed catalog layer through the existing config, provider lake, route resolver and dispatch-pricing receipt. Cloud prices are captured at admission and remain stable after refresh, disable and session reload; old turns without a quote cannot borrow later cloud prices. Provider live rosters, exact identities/endpoints, hand tiers and billing modes retain authority. Preserve separate legacy Chat and Anthropic route identities. Bound and authenticate HTTP/disk/cache envelopes, applicability, expiry and rollback history. One ticket gate rejects superseded callbacks and guards publication with atomic cache writes. Reject unsafe file inputs, untrusted future cache hints and provider cache attempts to claim cloud/config price authority. Keep cloud endpoint scope static, independent of operator URL overrides, and retain the existing provider-live wire receipt compatibility. Add fail-closed web transport, strict HEAD/ETag handling, bounded KV reads, fixture validation and guarded authoring. Production trust tables remain empty and cloud facts default off. Public test keys do not activate a feed. Generated website facts remain reserved for combined release integration. Validation on final source: - Rust selected suite: 3396 passed, 0 failed, 9436 skipped (674 config, 17 cloud-facts, 2705 TUI). - Web: 440 passed across 49 files; TypeScript, generated route types, scoped ESLint and cloud-facts fixture/key parity passed. - Production/test cargo check, cargo fmt and diff whitespace checks passed. - Two negative controls: 0 passed, 2 failed as required; digest rejection and late-publication guards restored and hash-verified before final tests. - Earlier executed TUI run: 2509 passed, 2 failed; first combined run: 3394 passed, 1 failed. Fixed status width, explicit MiniMax PAYG fixture authority and the actual legacy identity-parser bug; logs retained. - Required root npm test / check:web both fail: those scripts are absent. Web check:facts reports deferred generated crate/credential-label drift. Local macOS fixture evidence only; Windows checks are source-reviewed. No hosted CI, live provider calls, production key reads, remote database changes, public push, publication or deployment are claimed. Local commit uses an empty per-command hooks path to omit optional session capture; shared hooks configuration is unchanged. Harvested and adapted from PR #5752; donor head 98785c5. Excludes stale synchronization merges and unrelated release history. Exact ownership, hashes, commands and failure logs: /private/tmp/cw-5752-verification-20260907/REPORT.md Co-authored-by: Hmbown <101357273+Hmbown@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Slice 1 of the Supabase-backed cloud facts channel: signed + versioned + cached + fail-safe facts (model catalog deltas, provider defaults, release truth, announcements) served by the website at /api/facts/v1/, consumed by a client behind
[cloud_facts].enabled(default OFF), provenance in /status, schema ready for per-org override.Evidence
cargo test -p codewhale-cloud-facts→ 8 passed;cargo test -p codewhale-config cloud_facts→ 18 passed; webnpm test→ 355 passed;check:factsOK; tsc + lint clean.Unproven / before merge
No-Issue: cloud facts lane per founder dogfood-Supabase direction