openova/infra/cloudflare-worker-leases
e3mrah 7ca4abddd2
feat(continuum): K-Cont-4 — Cloudflare Worker source + tofu wiring for lease witness (#1101) (#1159)
* feat(continuum): K-Cont-4 — Cloudflare Worker source + tofu wiring for lease witness (#1101)

Implements the server side of the Cloudflare KV lease-witness pattern
that K-Cont-3's CFKVClient (in core/controllers/continuum/internal/
witness/cloudflarekv/) speaks to. The Worker fronts a Cloudflare
Workers KV namespace with read-then-CAS-write semantics enforced via
the If-Match header — exact contract per K-Cont-3 #1158 report (item d)
and the canonical-seams "Cloudflare KV Worker contract" entry.

Routes:
  GET    /lease/<slot-url-encoded>  → 200 + LeaseState | 404 | 401
  PUT    /lease/<slot>              → 200 + LeaseState | 412 + state | 401
  DELETE /lease/<slot>              → 204 | 412 | 401

All 7 K-Cont-3 trap behaviors verified by 46 vitest tests:
  1. If-Match: 0 = first-acquire-on-empty-slot
  2. Generation increments unconditionally (incl. Release)
  3. 412 includes current state body
  4. TTL eviction is server-authoritative in stamping (Worker doesn't
     auto-evict — controller's IsHeldBy decides)
  5. X-Holder mismatch on DELETE returns 412 (stale region can't
     evict new primary)
  6. Bearer token validation against env-bound allow-list
  7. Optional X-Lease-Slot header logged for KV granularity

Files:
  products/continuum/cloudflare-worker/{package.json, tsconfig.json,
    wrangler.toml, vitest.config.ts, .eslintrc.cjs, .gitignore,
    DESIGN.md, src/{index,auth,kv,types}.ts,
    src/handlers/{get,put,delete}.ts,
    test/{handlers,contract,env.d}.ts}
  infra/cloudflare-worker-leases/{versions,variables,main,outputs}.tf
    + README.md
  .github/workflows/cloudflare-worker-leases-build.yaml
    (event-driven, NO cron — push-on-paths + PR + workflow_dispatch)

Tests: 46/46 vitest pass (handlers 37 + contract 9). ESLint clean.
tsc --noEmit clean. wrangler deploy --dry-run produces 9.47 KiB
bundle.

Per the brief: tofu module ships ready for operator action — no
auto-deploy. Operator runbook in DESIGN.md §"Operator runbook —
deploy a new Sovereign".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(continuum/cf-worker-tofu): K-Cont-4 — adopt CF v5 inline secret_text binding (was v4 separate resource)

`tofu validate` failed on `cloudflare_workers_secret` — that resource
was REMOVED in cloudflare/cloudflare v5 (it consolidated into the
inline `bindings = [...]` array on `cloudflare_workers_script` with
`type = "secret_text"`). Same security guarantee — encrypted at rest
in CF, never visible via dashboard read API once written. `tofu fmt`
also wanted versions.tf alignment + the .terraform.lock.hcl pinning
the resolved cloudflare/cloudflare v5.19.1 (mirrors infra/hetzner/
which commits its lock file).

Per Inviolable Principle #5 the bearer token value still flows from
TF_VAR_bearer_tokens_csv extracted at apply time from a K8s
SealedSecret — never inlined here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: hatiyildiz <hati.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 08:01:44 +04:00
..
.terraform.lock.hcl feat(continuum): K-Cont-4 — Cloudflare Worker source + tofu wiring for lease witness (#1101) (#1159) 2026-05-09 08:01:44 +04:00
main.tf feat(continuum): K-Cont-4 — Cloudflare Worker source + tofu wiring for lease witness (#1101) (#1159) 2026-05-09 08:01:44 +04:00
outputs.tf feat(continuum): K-Cont-4 — Cloudflare Worker source + tofu wiring for lease witness (#1101) (#1159) 2026-05-09 08:01:44 +04:00
README.md feat(continuum): K-Cont-4 — Cloudflare Worker source + tofu wiring for lease witness (#1101) (#1159) 2026-05-09 08:01:44 +04:00
variables.tf feat(continuum): K-Cont-4 — Cloudflare Worker source + tofu wiring for lease witness (#1101) (#1159) 2026-05-09 08:01:44 +04:00
versions.tf feat(continuum): K-Cont-4 — Cloudflare Worker source + tofu wiring for lease witness (#1101) (#1159) 2026-05-09 08:01:44 +04:00

infra/cloudflare-worker-leases/ — OpenTofu module for the Continuum lease-witness Worker

Slice K-Cont-4 of EPIC-6 (#1101). Deploys the Worker source from products/continuum/cloudflare-worker/ to Cloudflare alongside its KV namespace and env-bound bearer-token allow-list.

Inputs

Variable Required Description
cloudflare_account_id yes 32-char hex. Read from CF dashboard.
cloudflare_api_token yes (sensitive) API token with Workers Scripts: Edit + Workers KV Storage: Edit.
bearer_tokens_csv yes (sensitive) Comma-separated allow-list of bearer tokens. Source: per-Sovereign SealedSecret.
worker_name no (default openova-continuum-lease-witness) Worker script name (becomes part of the URL).
kv_namespace_title no (default openova-continuum-leases) KV namespace display title.
log_level no (default info) One of error / info / debug.
worker_script_path no (default ../../products/continuum/cloudflare-worker/dist/index.js) Path to the bundled Worker JS. Run npm run build:dryrun in the worker dir first.

Outputs

Output Use for
worker_url Paste into Continuum CR spec.leaseClient.config.baseURL.
kv_namespace_id Ad-hoc wrangler kv:key list introspection.
worker_name Deployed Worker script name.

Operator runbook

  1. Build the Worker bundle:

    cd ../../products/continuum/cloudflare-worker
    npm install && npm run build:dryrun
    

    This produces dist/index.js (the bundled Worker script).

  2. Extract bearer tokens from the per-Sovereign SealedSecret:

    kubectl --kubeconfig <sov-kubeconfig> get secret -n catalyst-system \
      continuum-cf-witness-tokens -o jsonpath='{.data.token}' | base64 -d
    

    For rotation, prepare a <new>,<old> CSV.

  3. Apply:

    cd ../infra/cloudflare-worker-leases
    tofu init
    TF_VAR_cloudflare_account_id=<acct> \
    TF_VAR_cloudflare_api_token=<token> \
    TF_VAR_bearer_tokens_csv='<csv>' \
      tofu apply
    
  4. Wire the Continuum CR with the worker_url output. The catalyst-controllers reconciler picks up the change on next reconcile (~30s); verify via kubectl logs -n catalyst-controllers continuum-controller-*.

Why no cloudflare_workers_route?

The Worker's default *.workers.dev URL is sufficient for the controller's HTTPS calls. A custom hostname (e.g. lease.openova.io) would require zone setup outside this module. Operators wanting a custom domain set spec.leaseClient.config.baseURL directly to the custom hostname AFTER setting up the route in the CF dashboard or a sibling tofu module.

What this module does NOT do

  • Doesn't deploy automatically. Per the K-Cont-4 brief, tofu apply is operator-run. CI only verifies tofu validate + tofu fmt -check.
  • Doesn't manage the SealedSecret. That's a clusters/<sov>/... overlay artifact; the operator extracts plaintext to feed this module's bearer_tokens_csv var.
  • Doesn't tear down on Continuum CR deletion. Worker + KV outlive the CR (they may serve other CRs). Manual tofu destroy when retiring a Sovereign.