Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ jobs:
- name: Check release configuration
run: node scripts/key_data_preflight.mjs --check
# Bundle-only checks cannot attest remote deployment prerequisites. The
# normal Wrangler build enforces those before a real upload.
# normal Wrangler build command enforces those before a real upload.
- name: Validate Knowledge Worker bundle
env:
WRANGLER_SEND_METRICS: "false"
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ jobs:
with:
ref: ${{ needs.gate.outputs.sha }}
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.11"
Expand Down Expand Up @@ -161,7 +162,9 @@ jobs:
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: pnpm exec wrangler deploy --config .release-wrangler-actions.jsonc --tag "$SHA" --message "$DEPLOY_MESSAGE"
run: |
pnpm exec wrangler deploy --config .release-wrangler-actions.jsonc --containers-rollout=none --tag "$SHA" --message "$DEPLOY_MESSAGE"
pnpm exec wrangler deploy --config .release-wrangler-actions.jsonc --tag "$SHA" --message "$DEPLOY_MESSAGE"
- name: Verify actual Container rollout
if: vars.DEPLOY_MAIN_WORKER == 'true'
env:
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ SQLite or PostgreSQL elsewhere). Each key can have daily and monthly dollar budg
a model allowlist, an expiry time and client address ranges; the dashboard's Usage
page and `GET /v1/usage` show spend and remaining budget, and request telemetry can be
exported over OTLP. See [usage, budgets and key controls](docs/usage-and-budgets.md).
Keys can also restrict provider data classes and enforce request preferences; see
[key data controls and usage details](docs/key-data-guards.md).

Administrators can query `GET /admin/providers/usage` from an authenticated
dashboard session to combine provider-account allowances with local request,
Expand Down
1 change: 1 addition & 0 deletions config.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def load_env_choice(


class Config:
GEMINI_DATA_TIER = os.environ.get("GEMINI_DATA_TIER", "free").strip().lower()
FREE_ROUTE_EXTRA_PROVIDERS = os.environ.get('FREE_ROUTE_EXTRA_PROVIDERS', '')
FREE_ROUTE_WORKERSAI_ACCOUNT_ID = os.environ.get('FREE_ROUTE_WORKERSAI_ACCOUNT_ID', '')
FREE_ROUTE_FREE_TIER_PROVIDERS = os.environ.get('FREE_ROUTE_FREE_TIER_PROVIDERS', '')
Expand Down
18 changes: 12 additions & 6 deletions docs/deployment-cloudflare.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,12 @@ python -m pytest -q
npm run test:worker
npm run test:integration
npm run cf:migrations:check
npx wrangler deploy --dry-run
node scripts/key_data_preflight.mjs --check
node scripts/check_worker_bundle.mjs --config wrangler.jsonc --outdir /tmp/main-worker
```

Pushing to `main` deploys; see [How deploys work](#how-deploys-work). Never deploy
with a bare `wrangler deploy`, which skips the migrations.
with a bare `wrangler deploy`: its preflight verifies prerequisites but does not apply migrations.

## How deploys work

Expand All @@ -332,7 +333,10 @@ A push to `main` runs the `ci` workflow. When it passes, the `deploy` workflow
first because the main Worker binds it (`KNOWLEDGE_SERVICE`) and may call what the
new version adds. The main Worker and its Container go last, and only when the
repository variable `DEPLOY_MAIN_WORKER` is `true` (see [Workers Builds](#workers-builds)).
Each version is tagged with the full commit SHA, and its message links to the run.
Before upload, the main build verifies the migrated account schema, required bindings
and secret names, and the private Worker's tagged expansion capability. Main activation uses
`--containers-rollout=none` first, followed by the Container rollout. Each version
is tagged with the full commit SHA, and its message links to the run.
4. **Verify.** `scripts/deploy_status.mjs --verify` retries for up to ten minutes
until no migration is pending, `GET /ready` answers 200 (every D1 table exists and
the Container is healthy), the Knowledge Worker's live version carries the commit,
Expand All @@ -349,8 +353,9 @@ SHA.

## Migrations

Migrations are applied before the code that uses them, and with Workers Builds the new
code can briefly run before them, so the schema must work for the old and the new code:
Migrations are applied before the code that uses them. The main build refuses upload
until they are recorded and the required account columns exist. The schema must
still support old and new code during rollout:

- Make only additive changes: new tables, new nullable or defaulted columns, new
indexes, using `IF NOT EXISTS`. Add each new table to `REQUIRED_D1_TABLES` in
Expand Down Expand Up @@ -442,7 +447,8 @@ Set `D1_DATABASE` explicitly to the database in both selected Worker configurati
then run `npm run deploy` (`scripts/deploy.sh`). For another environment set
`MAIN_WORKER_CONFIG`, `KNOWLEDGE_WORKER_CONFIG` and `DEPLOY_STATUS_URL` as well. The
script checks migrations, applies them, deploys the private Worker, then the main
Worker and Container. From a clean checkout it tags both versions with the commit.
Worker with Container rollout disabled, then the Container. Preflight runs before
each main upload. From a clean checkout it tags both versions with the commit.
Extra arguments go to the final deploy. Never run it concurrently with another deploy.

Each release uses a fresh build-only image identifier. The command does not finish
Expand Down
18 changes: 17 additions & 1 deletion docs/key-controls-rollout.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ Rollback from enforcement to expansion leaves policy columns intact and refuses
controlled accounts. Restore enforcement-capable components to resume those accounts;
never clear restrictions as an automatic rollback step.

Enforcement advertises `key_controls: {protocol: 2, enforcement: true}`. A controlled
request probes the actual Container `/healthz` or private Knowledge `/ready` before
sending its body. Missing, stale, malformed or unreadable capability refuses with 503.
The Container independently checks the main Worker's account-RPC capability when
admitting controlled provider dispatch. The private Worker checks both current durable controls and
the sender's enforcement protocol. NULL-policy calls need no enforcement negotiation.

Deployment preflight verifies configuration, migration ledger, policy columns, required
secret names and a fully active private deployment whose tagged source supports
expansion. The tagged commit must be available in the checkout; a shallow build must
fetch that history before release. It reads no secret values. Runtime peer readiness,
rather than the tag, governs controlled dispatch. Bundle dry runs use isolated configs
and never stand in for release admission.

## Staging evidence and management compatibility

Real staging of the earlier re-land reproduced both incident errors with mixed Worker
Expand Down Expand Up @@ -112,4 +126,6 @@ See [Container deployment semantics](https://developers.cloudflare.com/container
and [rollout controls](https://developers.cloudflare.com/containers/configuration/rollouts/).


Account reads negotiate the additive row protocol only after a successful capability probe. Old Containers receive the original account fields on list reads and NULL-policy username reads, including when a controlled neighbour exists, so dashboard cache reloads and unrestricted sign-in remain available. Legacy username and prefix authentication refuse controlled rows, since either can also feed deferred provider work. Provider forwarding and private outbound admission remain separate from management projection; an old Container cannot use a projected row to dispatch for a controlled account. A Containers request the full policy from compatible peers and retain their dormant refusal fence. A failed or malformed capability probe never downgrades to a legacy row; only the old peer's explicit unsupported-operation response permits that fallback.
In expansion, account reads negotiate the additive row protocol only after a successful capability probe. Old Containers receive the original account fields on list reads and NULL-policy username reads, including when a controlled neighbour exists, so dashboard cache reloads and unrestricted sign-in remain available. Legacy username and prefix authentication refuse controlled rows, since either can also feed deferred provider work. Provider forwarding and private outbound admission remain separate from management projection; an old Container cannot use a projected row to dispatch for a controlled account. A Containers request the full policy from compatible peers and retain their dormant refusal fence. A failed or malformed capability probe never downgrades to a legacy row; only the old peer's explicit unsupported-operation response permits that fallback.

Contract Containers announce the expanded account-row protocol directly: every supported A/B peer accepts it. Management reads validate their policy envelope without requiring enforcement capability; the current capability is checked separately before controlled provider dispatch.
Loading
Loading