Skip to content

feat: restore key data controls with deployment preflight - #87

Closed
ALikesToCode wants to merge 2 commits into
mainfrom
feat/key-data-guards-v2
Closed

ALikesToCode wants to merge 2 commits into
mainfrom
feat/key-data-guards-v2

Conversation

@ALikesToCode

Copy link
Copy Markdown
Owner

Re-land #85 for an app whose requests carry personal data, with account-RPC compatibility, release admission and complete local CI coverage.

Incident evidence and changes

The account RPC is owned by the main Worker and reads its D1 binding directly. It does not traverse the private Knowledge service or require a new policy-signing secret. Both incident flags default off when unset.

A local D1 migrated through 0043 reproduces account_storage_unavailable when the new account fields reach the previous Container's strict decoder. Matching current runtimes return 200 for both reported routes. No historical logs or Container fingerprint are available, so this establishes a version-compatibility failure mechanism, not the exact cause of the incident described as all-new. The stale private Worker does not explain these two account paths.

  • Negotiate data_policy_version: 1. Earlier Containers receive the original row shape only for verified unrestricted accounts; legacy reads and writes cannot bypass or replace restrictions. Current Containers still refuse absent, malformed or unsupported policies.
  • Restore provider-class controls, forced routing preferences, attested credentials, token accounting and the outbound admission boundaries from feat: enforce key data controls and record token details #85, including its reviewed regressions.
  • Run preflight from the default Wrangler build, including independent builds: require consistent bindings, the actual account columns, all tracked migrations, required secret names and the private Worker's fully active matching commit. Check main prerequisites before updating the private Worker as well. Never fetch secret values.
  • Add an integration test using a raw migrated account row, actual private RPC over HTTP and registered Container application routes. Only the external provider is mocked. Cover current restrictions, revocation, legacy readers/writers and unset flags.
  • Supply the shared readable control-store fixture in client-header and free-route tests, retain a missing/unreadable-store 503 assertion, and include every Node CI test file in test:worker with a coverage contract.
  • Freeze the timestamp in an existing byte-comparison test so crossing a clock second does not change its result or assertions.

Local verification

Every CI command below ran through blade-testlock. Python 3.11, Node 22 for Node/integration jobs and Node 24 for Cloudflare builds. Integration used PYTHON=.venv/bin/python. The package-manager install used an isolated local prefix; bundle output directories were isolated under .cache instead of shared /tmp paths.

CI command Result
python -m pip install --disable-pip-version-check --require-hashes -r requirements-ci.lock Passed
python scripts/check_static_secrets.py Passed
ruff check . --select E9,F63,F7,F82 Passed
mypy --ignore-missing-imports --follow-imports=skip --disable-error-code import-untyped --disable-error-code var-annotated --disable-error-code arg-type --disable-error-code assignment --disable-error-code operator app.py routes services providers streaming 290 files, no issues
bandit -q -c .bandit -r app.py config.py error_handlers.py route_helpers.py routes services providers streaming Passed
pip-audit -r requirements.lock No known vulnerabilities
python -m pytest -q 5,275 passed; 975 subtests passed; 2 skipped
npm ci Passed
npm audit --audit-level=high No vulnerabilities
node --test tests/test_frontend_build.mjs 2 passed on each Node version
npm run test:worker 1,998 passed
npm run cf:migrations:check 43 migrations checked
npm run test:deploy 13 passed
node --test tests/test_free_routes_worker.mjs 8 passed
node --test tests/test_client_headers_worker.mjs 13 passed
npm run test:integration 14 passed
npm install --global "$(node -p "require('./package.json').packageManager")" Passed, isolated prefix
pnpm install --frozen-lockfile Passed
pnpm run build Passed
git diff --exit-code -- static/css/style.css No changes
node scripts/key_data_preflight.mjs --check Passed
node scripts/check_worker_bundle.mjs --config wrangler.knowledge.jsonc --outdir /tmp/knowledge-worker Dry run passed
node scripts/check_worker_bundle.mjs --config wrangler.jsonc --outdir /tmp/main-worker Dry run passed

The bundle wrapper always supplies --dry-run, normalizes paths against argument injection, and omits the release build command only in a temporary configuration. Real deploys retain the default preflight. Release-admission failure cases use deterministic command evidence in tests; no live preflight, deployment, secret change or remote migration was performed. Confidentiality and attribution checks are clean, with no exemptions.

Rollout

Workers Builds deploys the main Worker and its Container independently of the GitHub workflow; a failed CI run does not stop that trigger. The default build must remain gated. Prefer disabling independent promotion and enabling the CI-gated orchestration workflow as the single deployment owner.

  1. Apply tracked migrations first; already-recorded migrations are retained, never replayed as bare ALTER statements.
  2. Check migrated schema and main bindings, then deploy the private Worker from the same commit.
  3. Activate the main Worker with --containers-rollout=none, then roll out the matching Container. The manual script and deployment workflow now use this order.
  4. Verify both runtime fingerprints and an ordinary durable key, then enable controls last. Do not roll back to unenforcing runtimes while restrictions are enabled.

If independent builds remain connected, their initial upload must fail until prerequisites match; rerun only after the ordered release prerequisites succeed. Do not treat this draft's local evidence as confirmation of the historical all-new runtime combination.

The restored changes retain existing oversized files: services/auth_service.py (1,261 lines), services/proxy_service.py (3,437) and tests/test_cloudflare_worker.mjs (4,165). A separate change can extract durable-principal lookup, provider orchestration and transport-specific tests respectively; this re-land preserves the reviewed boundaries. The new account-contract and release modules remain small.

@coderabbitai

coderabbitai Bot commented Oct 20, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
multillm-proxy da66481 Oct 20 2026, 12:10 PM

@ALikesToCode

Copy link
Copy Markdown
Owner Author

Superseded by the staged rollout in #88 (protocol expansion and dormant rollback refusal) and #89 (stacked enforcement). The split preserves unrestricted compatibility across independent deployments and refuses controlled content during rollback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant