Skip to content

fix(daemon): refuse leases for providers without a registered runtime - #3773

Merged
thymikee merged 5 commits into
mainfrom
fix/provider-not-registered
Oct 17, 2026
Merged

thymikee merged 5 commits into
mainfrom
fix/provider-not-registered

Conversation

@thymikee

@thymikee thymikee commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Summary

leases.allocate with a leaseProvider that no registered runtime claims now fails before any lease is recorded: UNSUPPORTED_OPERATION, details.reason: 'provider-not-registered', details.provider, details.registeredProviders. Previously only the hard-coded required list was checked, so a plugin provider such as testmu on a daemon without the plugin recorded a lease with no device behind it.

  • leaseProviderRequiringRuntime in packages/contracts/src/lease-scope.ts is the one classifier. Provider-less leases (including backend-only), proxy and cloud (new CLOUD_LEASE_PROVIDER, used by cloud-profile.ts) need no runtime; every other id must be registered.
  • The admission site no longer compares provider names. The now-unread providerRuntimeRequiredIds plumbing is removed from the lease handler, request chain and router. The list itself and createProviderDeviceRuntimeRequestProviders are left for feat(plugins): plugin contract v2 and one provider registry #3767.
  • Heartbeat and release are unchanged. Help, plugins.md and client-api.md name the reason.
  • 19 files; tests that allocated provider leases without registering the runtime now register it.

Closes #3748. Part of #3747.

Validation

pnpm check:affected --run --head 9923eec046: all runnable checks passed (exactCommit=true). Provider integration suite: 65 files pass, including a testmu refusal with no lease in the registry. Unit tests cover each exemption (provider-less, backend-only, proxy, cloud). Not device-facing.

🤖 Generated with Claude Code

View guided diff Turn on auto-fix

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-10-17 10:39 UTC

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.34 MB 5.34 MB +376 B
Package (unpacked) 5.34 MB 5.34 MB +376 B
Package (download) 1.61 MB 1.61 MB +124 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 17.8 ms 17.4 ms -0.4 ms
CLI --help 49.5 ms 48.6 ms -0.9 ms

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 19 files

You’re at about 95% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread website/docs/docs/client-api.md Outdated
Comment thread packages/daemon/src/sessions/handlers/__tests__/lease.test.ts Outdated
Comment thread src/daemon-composition-credentials.test.ts Outdated
@thymikee

Copy link
Copy Markdown
Member Author

The code in 0f84dd1 looks correct to me, and all 20 checks pass, but live validation is still missing: I ran no tests and did not run the provider integration suite or the fallow gate. I also did not check whether any out-of-tree caller allocates leases with arbitrary provider ids against a local daemon. Please run lease_allocate against a daemon with no registered runtime for the requested provider, and show it fails with UNSUPPORTED_OPERATION and reason provider-not-registered. Also show the same call succeeds once that runtime is registered. No conflicts are known.

Not blocking, and you can take or leave these: the host admin route PUT /admin/leases/:id builds its own lease request with a caller-supplied leaseProvider and never meets the new check, so a body with testmu on a daemon without that runtime still records a lease (host-lease-http.ts#L134); the admission compares the raw leaseProvider, while the registry trims and validates the id later, so testmu is now refused although the registry would store testmu, and an invalid id such as a b now gets UNSUPPORTED_OPERATION instead of INVALID_ARGS (lease.ts#L336); and this changes behavior for existing callers, since an unregistered provider used to succeed, so one Unreleased line in CHANGELOG.md naming UNSUPPORTED_OPERATION and provider-not-registered would help.

Would it be simpler to enforce the registered-provider rule where leases are admitted, for example a registry or admission option that holds the registered provider ids, instead of in one RPC handler? Then lease_allocate and putHostLease both get it, and a future allocation entry point cannot skip it. You could hold that for #3767 if you prefer, since its single provider registry is the natural owner. At minimum, please cover the host admin route or say clearly that it is excluded.

The three earlier inline threads on the docs wording, the lease test assertions and the credentials test are fixed at this commit, so you can resolve them: #3773 (comment), #3773 (comment) and #3773 (comment).

Before merge, please decide whether the host admin route is covered or explicitly excluded, and add the CHANGELOG line.

@thymikee
thymikee force-pushed the fix/provider-not-registered branch from 0f84dd1 to c136996 Compare October 17, 2026 07:15

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 3 files (changes from recent commits).

You’re at about 96% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/daemon/src/sessions/handlers/lease.ts Outdated
@thymikee
thymikee force-pushed the fix/provider-not-registered branch from e08f4bf to 1281279 Compare October 17, 2026 08:34
@thymikee

Copy link
Copy Markdown
Member Author

Follow-up at 1281279e6b (rebased on current main; pnpm check:affected --run --head 1281279e6b passed, including the provider integration test).

Live validation. Real daemon from this worktree's build (node dist/src/internal/daemon.js, HTTP mode), fresh AGENT_DEVICE_STATE_DIR and AGENT_DEVICE_HOME, no plugins installed. Requests went to agent_device.lease.allocate over /rpc. There is no public leases list, so "no lease recorded" is shown by reusing the refused call's leaseId: a daemon never reuses an id it issued, so step 2 only succeeds if step 1 recorded nothing.

1. testmu, leaseId 0123456789abcdef0123456789abcdef:
   UNSUPPORTED_OPERATION  Provider "testmu" is not available in this daemon runtime.
   details: {"reason":"provider-not-registered","provider":"testmu","registeredProviders":["browserstack","aws-device-farm"]}
2. same leaseId, no provider:      allocated leaseId 0123456789abcdef0123456789abcdef
3. backend only:                   allocated
4. proxy:                          allocated (leaseProvider proxy)
5. cloud:                          allocated (leaseProvider cloud)
6. " testmu " (untrimmed):         same provider-not-registered refusal, provider "testmu"
7. "a b" (malformed):              INVALID_ARGS Invalid lease provider. Use 1-64 chars: ...
8. browserstack (registered, no BROWSERSTACK_USERNAME in env):
                                   passes admission; the provider then refuses with INVALID_ARGS "BrowserStack requires BROWSERSTACK_USERNAME in the environment."

The daemon was stopped afterwards (pid 40161 gone). Step 8 is as far as I can take "succeeds once registered" without real provider credentials; a full success with a registered runtime is the existing fake-provider integration scenario (Provider-backed scenario composes lease, inventory, dispatch...), which allocates a lease on FAKE_PROVIDER and passes.

Review items

  • Trim/validation order: fixed. The handler now normalizes the provider once (normalizeLeaseProvider), so " testmu " classifies as testmu and "a b" is INVALID_ARGS (steps 6 and 7). The credential-fingerprint check reads the same normalized id (cubic's thread), covered by a new test.
  • CHANGELOG: added an Unreleased line naming UNSUPPORTED_OPERATION and provider-not-registered.
  • Host admin route PUT /admin/leases/:id: explicitly excluded. It only allocates macos-app leases, a host-owned logical backend lease on the loopback admin listener; the leaseProvider there is a label and never selects a provider runtime, which matches the "a backend alone never implies a missing provider runtime" rule in fix(daemon): refuse leases for providers without a registered runtime #3748. I did not move the rule into the registry: the credential-changed check must not run before the not-registered refusal, and the registry has no provider set today. A single registry-owned check fits feat(plugins): plugin contract v2 and one provider registry #3767's one provider registry, so I would hold it for that PR. Say if you want the route covered here instead.

thymikee and others added 5 commits October 17, 2026 10:46
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… exemptions

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…sal in the changelog

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…provider

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ut a lease registry handle

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@thymikee
thymikee force-pushed the fix/provider-not-registered branch from 1281279 to b1f65c4 Compare October 17, 2026 08:50
@thymikee

Copy link
Copy Markdown
Member Author

Rebased onto current main (picks up #3722 and #3764–#3766); the only conflict was the CHANGELOG.md Unreleased list, kept both entries. pnpm check:affected --run --head b1f65c42d8 passed (format, lint, typecheck, layering, fallow, build, vitest-related, wire-compat, docs-links, docs-prose).

Live validation re-run on the rebased build (real daemon from this worktree, fresh state dir and AGENT_DEVICE_HOME, no plugins, then stopped; pid 60508 gone):

1. testmu + leaseId 0123456789abcdef0123456789abcdef:
   UNSUPPORTED_OPERATION  {"reason":"provider-not-registered","provider":"testmu","registeredProviders":["browserstack","aws-device-farm"]}
2. same leaseId, no provider:  allocated 0123456789abcdef0123456789abcdef   (so 1 recorded no lease)
3. backend only:               allocated
4. proxy:                      allocated (leaseProvider proxy)
5. cloud:                      allocated (leaseProvider cloud)

The earlier comment still applies for the trim/malformed cases, the registered-runtime pass-through, and the explicit exclusion of PUT /admin/leases/:id.

@thymikee

Copy link
Copy Markdown
Member Author

The PR is ready at b1f65c4. The provider-id mismatch, the doc and help gaps, and both test gaps from the earlier review are now fixed.

Not blocking: the trimmed-id test at lease-provider-credentials.test.ts:163 uses mismatched credentials, so it only fails through the provider string, and a case with a matching fingerprint and ' limrun ' that asserts allocations === 1 would cover the bug Cubic named. In lease.ts:84, the handler normalizes the provider id but allocateOrRenewLease still gets the raw scope and the registry normalizes it again, so building the normalized scope once and passing it to the asserts and to allocateOrRenewLease would drop the need for the explaining comment. Take or leave both.

I did not re-run the live daemon validation or any tests. I accepted the transcripts in comments 6231802940 and 6231954375. The live run reached the registered-provider path only up to the BrowserStack env refusal after admission, so full success with a registered runtime rests on the fake-provider integration scenario, which I did not run. I also did not audit out-of-tree callers that allocate leases with arbitrary provider ids against a local daemon.

The Cubic threads on the normalized id (#3773 (comment)), the exemption docs and help (#3773 (comment)), the lease test assertions (#3773 (comment)) and the credentials test mock (#3773 (comment)) are all fixed at this head, so you can resolve them.

CI is still pending: both Smoke Tests jobs are queued and nothing has failed yet. The change touches the daemon lease_allocate admission, which smoke routes that allocate a lease without registering the provider runtime would cross. No conflicts. Once the Smoke Tests jobs finish green, this can merge.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 17, 2026
@thymikee
thymikee merged commit c1639b4 into main Oct 17, 2026
20 of 21 checks passed
@thymikee
thymikee deleted the fix/provider-not-registered branch October 17, 2026 10:38
thymikee added a commit that referenced this pull request Oct 17, 2026
…ment

* origin/main:
  refactor(daemon): publish a single package entrypoint (#3781)
  fix(daemon-client): wait for an acknowledged quiesce instead of killing the daemon (#3780)
  fix(daemon): refuse leases for providers without a registered runtime (#3773)

# Conflicts:
#	packages/daemon/src/sessions/handlers/__tests__/lease.test.ts
#	src/daemon-client/daemon-client-ensure.ts
thymikee added a commit that referenced this pull request Oct 17, 2026
…refactor/daemon-runtime-no-process-globals

* origin/refactor/host-environment:
  refactor(cli): resolve one transport per run and one host per MCP tool call; default the lease provider cwd to the bound host
  refactor(daemon): publish a single package entrypoint (#3781)
  fix(daemon-client): wait for an acknowledged quiesce instead of killing the daemon (#3780)
  fix(daemon): refuse leases for providers without a registered runtime (#3773)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(daemon): refuse leases for providers without a registered runtime

1 participant