Skip to content

feat(control-plane): real Cloudflare Containers driver for tenant lifecycle#7975

Merged
loopover-orb[bot] merged 1 commit into
mainfrom
claude/control-plane-container-driver
Jul 22, 2026
Merged

feat(control-plane): real Cloudflare Containers driver for tenant lifecycle#7975
loopover-orb[bot] merged 1 commit into
mainfrom
claude/control-plane-container-driver

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Summary

Closes #7851

  • Implements createContainer/destroyContainer/containerExists for real: one Cloudflare Container Durable Object per tenant+product, keyed by ${product}:${tenant.name} (a single binding is fixed to one Docker image, so ORB and AMS each get their own binding/class).
  • Runs each product's existing self-host Docker image unmodified: ORB gets the root Dockerfile (the same self-host image already used elsewhere, PORT=8787); AMS gets packages/loopover-miner/Dockerfile (its existing CLI/batch image — confirmed via Cloudflare Cron Trigger wake scheduling for hosted AMS containers #7182's own text that AMS runs one-shot subcommands via a per-invocation entrypoint override, not HTTP, so no defaultPort/HTTP surface is needed for this piece).
  • "Provisioned" is tracked as an explicit flag in the paired Container DO's own durable storage, not derived from Cloudflare's transient container run-state (running/stopped/stopped_with_code/etc). That distinction is load-bearing for AMS specifically: its image is a one-shot CLI tool expected to sit in a "stopped"-shaped run state almost all the time by design (Cloudflare Cron Trigger wake scheduling for hosted AMS containers #7182's "sleeping, zero-cost container" model) — indistinguishable from "never provisioned" using run-state alone. An explicit flag is unambiguous for either product.
  • Composed onto the existing driver via withRealContainerDriver (same composition pattern Real Postgres/Hyperdrive driver for control-plane's provisionDatabase/deprovisionDatabase #7653 established with withRealDatabaseDriver), so Real secret-injection driver for control-plane's injectSecrets/revokeSecrets via the generalized broker #7852 (secret injection, still not landed) can still ship independently without this file changing again.
  • createTenantProvisioningDriver gains an optional second parameter for container bindings — kept separate from the string-keyed env parameter since real Durable Object namespace bindings only exist inside a Workers runtime, not as env strings; worker.ts passes them explicitly.

Scope

Validation

  • git diff --check
  • npm run typecheck (root)
  • npm run control-plane:test — 94/94 passing (node --test).
  • npm run control-plane:coverage — 100% line/branch/function coverage on every file this PR touches or adds; the only residual gap (settlement-backend-driver.ts) is pre-existing and untouched by this PR.
  • npm run cf:typecheck (Workers-runtime typecheck including the two new Container subclasses).
  • npx wrangler deploy --dry-runboth real Docker images actually build successfully (ORB's root Dockerfile and AMS's packages/loopover-miner/Dockerfile, both from the repo-root build context), and both Durable Object bindings resolve correctly.
  • npm audit --audit-level=moderate — pre-existing ambient advisories only (confirmed unrelated: this PR's only new dependency, @cloudflare/containers, introduces nothing new; root package-lock.json is untouched by this diff).
  • New behavior has unit tests for every branch: fresh provision, idempotent re-provision (already provisioned), idempotent destroy (never provisioned), containerExists true/false, product-scoped instance keys, an unconfigured product's error, and the composition helper forwarding every non-container step to the base driver unchanged.

Safety

  • No secrets, tokens, or credentials committed anywhere.
  • No visible UI changes.

Notes

Follow-up infra work on top of #7180 (provisioning core, now 3/5 pieces done: #7524, #7653, #7851) and #7654 (the Worker deployment this extends, rather than a second redundant one). Unlocks #7181 (webhook routing) and #7182 (cron wake scheduling) as the next real candidates, both of which need a real container to route/wake — that now exists. Only #7852 (secret injection) is left to fully close out #7180.

…ecycle (#7851)

Implements createContainer/destroyContainer/containerExists for real: one
Container Durable Object per tenant+product, running each product's existing
self-host Docker image unmodified (ORB: root Dockerfile; AMS:
packages/loopover-miner/Dockerfile). "Provisioned" is tracked as an explicit
flag in the paired DO's own durable storage rather than derived from
Cloudflare's transient container run-state -- necessary because AMS's image
is a one-shot CLI tool (#7182's own cron-wake design) that's expected to sit
in a "stopped"-shaped run state almost all the time by design, which would
otherwise be indistinguishable from "never provisioned."

Composed onto the existing driver via withRealContainerDriver (same pattern
as #7653's withRealDatabaseDriver), so #7852 (secret injection) can still
ship independently. Adds both container images + Durable Object bindings to
control-plane's wrangler.jsonc; both build successfully via wrangler deploy
--dry-run.
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

1 similar comment
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.40%. Comparing base (84a7878) to head (2a8a629).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7975      +/-   ##
==========================================
- Coverage   91.89%   91.40%   -0.50%     
==========================================
  Files         738      739       +1     
  Lines       75706    75837     +131     
  Branches    23011    23016       +5     
==========================================
- Hits        69573    69321     -252     
- Misses       5041     5470     +429     
+ Partials     1092     1046      -46     
Flag Coverage Δ
control-plane 99.74% <100.00%> (+0.03%) ⬆️
shard-1 58.13% <ø> (-0.60%) ⬇️
shard-2 46.24% <ø> (-0.66%) ⬇️
shard-3 55.77% <ø> (-0.52%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
control-plane/src/container-driver.ts 100.00% <100.00%> (ø)
control-plane/src/driver-factory.ts 100.00% <100.00%> (ø)
control-plane/src/index.ts 100.00% <100.00%> (ø)

... and 3 files with indirect coverage changes

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 22, 2026
@loopover-orb

loopover-orb Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-22 01:14:18 UTC

10 files · 1 AI reviewer · no blockers · readiness 100/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR wires a real Cloudflare Containers driver for tenant lifecycle (createContainer/destroyContainer/containerExists), composed onto the existing fake/real driver stack via the same withReal*Driver pattern already established for the Neon database driver. The design correctly tracks 'provisioned' as an explicit durable-storage flag rather than deriving it from Cloudflare's transient container run-state, which is well-reasoned given AMS's one-shot CLI image spends most of its life in a 'stopped'-shaped state. The container-driver.ts unit tests exercise the real logic (idempotency, per-product binding routing, unconfigured-product errors) against hand-rolled fakes of the DO RPC surface, and wrangler.jsonc correctly pairs the new Container classes with a new_sqlite_classes migration. Issue linkage (#7851) is present and the diff matches its stated scope.

Nits — 5 non-blocking

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #7851
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 21 registered-repo PR(s), 14 merged, 284 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 21 PR(s), 284 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: significant
Linked issue satisfaction

Addressed
The PR implements real createContainer/destroyContainer/containerExists against the Cloudflare Containers API keyed by product+tenant, pairs each container with a Durable Object (per #7173's shape) as the routing target for #7181/#7182, keeps the fake driver intact and composes the real one via a driver-factory pattern mirroring the existing withRealDatabaseDriver convention, implements idempotent

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, Ruby, Go, JavaScript, MDX, Shell, Solidity
  • Official Gittensor activity: 21 PR(s), 284 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit eb31847 into main Jul 22, 2026
14 checks passed
@loopover-orb
loopover-orb Bot deleted the claude/control-plane-container-driver branch July 22, 2026 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Real Cloudflare Containers driver for control-plane's createContainer/destroyContainer/containerExists

1 participant