Skip to content

feat(provider-security): ChefVault client, slots, degraded mode - #38

Open
OnlineChef wants to merge 12 commits into
devfrom
feat/provider-security-plane
Open

feat(provider-security): ChefVault client, slots, degraded mode#38
OnlineChef wants to merge 12 commits into
devfrom
feat/provider-security-plane

Conversation

@OnlineChef

@OnlineChef OnlineChef commented Aug 1, 2026

Copy link
Copy Markdown

Summary

  • In-memory credential slots + ChefVault client with workload headers
  • chefvault:// resolve path, redacted doctor/status
  • Bounded degraded mode when authority is unavailable
  • Stacks with provider-account/fallback work on this plane

Test plan

  • bun test ./tests/provider-security.test.ts (12 pass)

Made with Cursor


View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.

Greptile Summary

This change adds ChefVault-backed provider credentials, lease handling, diagnostics, configurable provider fallback chains, and provider workspace updates.

Two authentication failures were reproduced. A provider configured only with a ChefVault credential reference can use that credential for model discovery but sends ordinary response traffic upstream without authentication. Also, an explicitly revoked ChefVault lease remains available from memory until its original expiration. These failures affect provider access control and should be corrected before merging.

Confidence Score: 4/5

Not safe to merge while revoked credentials can remain usable and credential-reference-only providers cannot authenticate ordinary requests.

The reproduced failures independently affect core provider authentication: one retains access after explicit revocation, and the other prevents ChefVault credentials from being applied to normal provider traffic.

Files Needing Attention: src/provider-security/resolve.ts needs explicit revoked-lease invalidation. src/oauth/index.ts and the ordinary request paths that consume provider.apiKey need request-time ChefVault credential application.

Security Review

ChefVault revocation is not enforced during lease renewal. When the authority returns a revoked response, the cached secret remains available and can continue authenticating requests until expiry. Separately, credential-reference-only provider configurations omit their resolved secret from ordinary response forwarding, which causes unauthenticated provider traffic and prevents the intended centrally managed credential flow from working.

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex produced a P1 finding proof and attached four artifacts showing CredentialRef authorization harness source, API-key authorization baseline output, CredentialRef-only observed output, and Harness source checksum outputs.
  • T-Rex produced a second P1 finding proof and attached three artifacts showing the renewal revocation runtime harness source and runtime outputs before validation refinement and after direct HTTP mapping verification.
  • T-Rex produced a third P1 finding proof with no artifacts attached.
  • T-Rex completed general contract validation comparing before and after behavior, referencing the chefvault-credentialref-e2e.ts harness and its SHA-256 checksum.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (1)

  1. General comment

    P1 CredentialRef secret is not applied to ordinary provider requests

    • Bug
      • A provider configured solely with credentialRef: chefvault://... successfully resolves a secret for /models, yet a real proxied /v1/responses request reaches the OpenAI-chat upstream with no Authorization header. Compact reads only compactProvider.apiKey; live and image selection also only recognize provider.apiKey, so credentialRef-only configuration cannot authenticate those paths.
    • Cause
      • ChefVault resolution is integrated only in resolveModelsAuthToken, while ordinary adapters and sidecar selectors consume provider.apiKey directly and no request-time credentialRef resolution injects the resolved secret into the routed provider.
    • Fix
      • Resolve a valid credentialRef into a per-request effective provider credential before adapter, compact, live, and image routing, without mutating persisted config; apply the resolved key to the appropriate provider-specific authorization header.

    T-Rex Ran code and verified through T-Rex

Fix All in Cursor Fix All in Codex Fix All in Claude Code Fix All in Conductor

Prompt To Fix All With AI
### Issue 1
src/oauth/index.ts:469-475
**ChefVault credentials are omitted from provider requests**

This resolves a `chefvault://` reference only for model discovery. A provider configured solely with `credentialRef` therefore authenticates `/models`, but ordinary response forwarding still consumes `provider.apiKey` and reaches the upstream without an Authorization header. Compact requests and live/image provider selection likewise use only API-key configuration. Resolve the credential reference into a per-request effective credential before routing these paths, without persisting the resolved secret.

### Issue 2
src/provider-security/resolve.ts:63-69
**Revoked leases remain usable after renewal**

When ChefVault rejects renewal as `revoked`, this catch suppresses the error and then returns the still-unexpired active snapshot. An explicitly revoked credential can therefore continue authenticating requests until its previous expiration. Handle revocation separately by evicting or revoking the affected slot and rejecting the request; retain cached fallback only for transient authority failures.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "feat(provider-security): ChefVault clien..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

Summary by CodeRabbit

  • New Features

    • Added secure runtime credential references for providers, including ChefVault-backed API keys.
    • Added credential rotation, renewal, validation, and fail-closed handling when credentials are unavailable or revoked.
    • Image, video, live, and response requests now support dynamically resolved provider credentials.
    • CLI status and doctor reports now include redacted provider-security health and readiness checks.
    • Provider configuration now indicates credentials supplied through references.
  • Bug Fixes

    • Improved provider credential errors with clearer HTTP status and error details.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Target branch corrected

This pull request now targets dev.

The [WRONG BRANCH] title prefix has been removed. The pull request has been marked ready for review again.

@github-actions github-actions Bot changed the title feat(provider-security): ChefVault client, slots, degraded mode [WRONG BRANCH] feat(provider-security): ChefVault client, slots, degraded mode Aug 1, 2026
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@OnlineChef, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 23 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 607d364f-b135-4a9f-95e2-bfeb9de3fe76

📥 Commits

Reviewing files that changed from the base of the PR and between 3d204a5 and ff63915.

📒 Files selected for processing (10)
  • src/oauth/index.ts
  • src/provider-security/client.ts
  • src/provider-security/degraded.ts
  • src/provider-security/resolve.ts
  • src/provider-security/slots.ts
  • src/provider-security/status.ts
  • src/provider-security/types.ts
  • tests/provider-security-forwarding.test.ts
  • tests/provider-security.test.ts
  • tests/server-images.test.ts
📝 Walkthrough

Walkthrough

Adds ChefVault-backed provider credentials with leased in-memory storage, renewal, fencing, degraded-mode handling, asynchronous provider resolution, server forwarding, CLI diagnostics, and comprehensive tests.

Changes

ChefVault provider security

Layer / File(s) Summary
Provider-security contracts and authority client
src/provider-security/types.ts, src/provider-security/client.ts, src/provider-security/index.ts
Defines ChefVault references, lease models, error codes, workload identity, HTTP authority operations, probes, and response validation.
Lease storage, degraded mode, and resolution
src/provider-security/slots.ts, src/provider-security/degraded.ts
Stores active, next, retiring, and revoked leases in memory. Applies fencing, renewal checks, rotation, revocation, degraded-mode decisions, and redacted status reporting.
Credential resolution orchestration
src/provider-security/resolve.ts
Resolves cached or new leases, coalesces concurrent cold resolves, renews leases, handles authority failures, and exposes global resolver and probe APIs.
Provider credential resolution and request wiring
src/types.ts, src/providers/*, src/images/plan.ts, src/oauth/index.ts, src/server/auth-cors.ts, src/server/images.ts, src/server/live.ts, src/server/responses/*
Adds credentialRef configuration and resolves inline, environment, or ChefVault credentials for model, image, video, live, compact, and core request paths. Provider failures produce structured HTTP errors.
Status and doctor diagnostics
src/provider-security/status.ts, src/cli/status.ts, src/cli/doctor.ts
Collects redacted status, authority probes, lease checks, degraded-mode checks, and doctor diagnostics. Exposes the report through CLI status JSON and doctor output.
Provider-security and integration validation
tests/provider-security.test.ts, tests/provider-security-forwarding.test.ts, tests/server-images.test.ts
Tests reference validation, lease lifecycle, fencing, renewal, degraded mode, authentication, diagnostics, secret redaction, forwarding, and asynchronous image selection.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: ingwannu, lidge-jun

Sequence Diagram(s)

sequenceDiagram
  participant ClientRequest
  participant ResponseHandler
  participant ProviderCredentialResolver
  participant ProviderSecurityClient
  participant ChefVaultAuthority
  participant UpstreamProvider
  ClientRequest->>ResponseHandler: submit provider request
  ResponseHandler->>ProviderCredentialResolver: resolve credentialRef
  ProviderCredentialResolver->>ProviderSecurityClient: resolve or renew lease
  ProviderSecurityClient->>ChefVaultAuthority: authenticated lease request
  ChefVaultAuthority-->>ProviderSecurityClient: lease and fencing token
  ProviderSecurityClient-->>ProviderCredentialResolver: validated credential lease
  ProviderCredentialResolver-->>ResponseHandler: request-local credential
  ResponseHandler->>UpstreamProvider: forward authenticated request
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the provider-security feature and its main ChefVault, credential-slot, and degraded-mode changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/provider-security-plane

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.

@OnlineChef
OnlineChef changed the base branch from main to dev August 1, 2026 07:09
@github-actions github-actions Bot changed the title [WRONG BRANCH] feat(provider-security): ChefVault client, slots, degraded mode feat(provider-security): ChefVault client, slots, degraded mode Aug 1, 2026
Comment thread src/oauth/index.ts
Comment on lines +469 to +475
const credentialRef = prov.credentialRef?.trim();
if (credentialRef && isChefVaultRef(credentialRef)) {
try {
const resolved = await globalProviderCredentialResolver.resolveCredentialRef(credentialRef);
return resolved.apiKey;
} catch {
return undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 ChefVault credentials are omitted from provider requests

This resolves a chefvault:// reference only for model discovery. A provider configured solely with credentialRef therefore authenticates /models, but ordinary response forwarding still consumes provider.apiKey and reaches the upstream without an Authorization header. Compact requests and live/image provider selection likewise use only API-key configuration. Resolve the credential reference into a per-request effective credential before routing these paths, without persisting the resolved secret.

Artifacts

CredentialRef authorization harness source

  • The authored Bun harness starts mock ChefVault and upstream services, starts the proxy, and captures the discovery and response Authorization headers; the takeaway is that the exact tested flow is reproducible.

API-key authorization baseline output

  • The executed API-key baseline records Bearer authorization on both model discovery and the proxied response request; the takeaway is that the capture server observes expected authentication when apiKey is configured.

CredentialRef-only observed output

  • The executed credentialRef-only run records the ChefVault secret on `/v1/models` and null authorization on `/v1/chat/completions`; the takeaway is that ordinary response forwarding is unauthenticated.

Harness source checksum output

  • The executed checksum command records the SHA-256 for the uploaded harness source; the takeaway is that the uploaded source is traceable to the tested file.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/oauth/index.ts
Line: 469-475

Comment:
**ChefVault credentials are omitted from provider requests**

This resolves a `chefvault://` reference only for model discovery. A provider configured solely with `credentialRef` therefore authenticates `/models`, but ordinary response forwarding still consumes `provider.apiKey` and reaches the upstream without an Authorization header. Compact requests and live/image provider selection likewise use only API-key configuration. Resolve the credential reference into a per-request effective credential before routing these paths, without persisting the resolved secret.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Codex Fix in Claude Code Fix in Conductor

Comment thread src/provider-security/resolve.ts Outdated
Comment on lines +63 to +69
await this.tryRenew(ref, renewTarget.leaseId, renewTarget.fencingToken, "active").catch(() => {
// Renewal failure keeps the current snapshot until expiry; degraded handling applies on resolve.
});
const refreshed = this.slotStore.snapshotForRequest(ref, this.now());
if (refreshed) {
return { apiKey: refreshed.secret, snapshot: refreshed, source: "memory" };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 security Revoked leases remain usable after renewal

When ChefVault rejects renewal as revoked, this catch suppresses the error and then returns the still-unexpired active snapshot. An explicitly revoked credential can therefore continue authenticating requests until its previous expiration. Handle revocation separately by evicting or revoking the affected slot and rejecting the request; retain cached fallback only for transient authority failures.

Artifacts

Renewal revocation runtime harness source

  • Authored Bun harness seeds a renewable active lease, makes the real client receive HTTP 410 revoked from renewal, and resolves the credential; it captures whether the cached secret is returned. The takeaway: it directly tests whether revocation is honored during renewal.

Runtime output before validation harness refinement

  • Executed initial harness output shows a POST renewal response recorded as HTTP 410 with revoked mapping, followed by the still-valid cached secret returned from memory. The takeaway: the revoked credential remains usable.

Runtime output after direct HTTP mapping verification

  • Executed refined harness directly verifies the HTTP 410 response maps to revoked and then shows resolution returns the active cached secret, confirming the defect. The takeaway: the resolver suppresses revoked renewal errors and retains the active credential.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/provider-security/resolve.ts
Line: 63-69

Comment:
**Revoked leases remain usable after renewal**

When ChefVault rejects renewal as `revoked`, this catch suppresses the error and then returns the still-unexpired active snapshot. An explicitly revoked credential can therefore continue authenticating requests until its previous expiration. Handle revocation separately by evicting or revoking the affected slot and rejecting the request; retain cached fallback only for transient authority failures.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Codex Fix in Claude Code Fix in Conductor

@github-actions github-actions Bot added the enhancement New feature or request label Aug 1, 2026
@OnlineChef
OnlineChef force-pushed the feat/provider-security-plane branch from 02bc847 to b89feab Compare August 1, 2026 07:39
OnlineChef and others added 4 commits August 1, 2026 09:44
…stub (PSP-008)

Add provider-security plane client for chefvault:// credential refs with
workload headers, active/next/retiring/revoked slot model, renewal jitter,
redacted doctor/status surfaces, and bounded degraded mode when ChefVault is
unreachable. Wire minimal resolve path for provider doctor/status and models auth.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add in-memory credential slots, workload-authenticated ChefVault client,
chefvault:// resolve path, redacted doctor/status, and bounded degraded
mode when the secret authority is unavailable.

Co-authored-by: Cursor <cursoragent@cursor.com>
CI failed on bun install --frozen-lockfile after provider-security
and fallback GUI dependency resolution drifted from the lockfile.

Co-authored-by: Cursor <cursoragent@cursor.com>
Group prompt.txt appends in issue-triage and keep bun.lock aligned
with frozen CI installs on provider-security branches.

Co-authored-by: Cursor <cursoragent@cursor.com>
@OnlineChef
OnlineChef force-pushed the feat/provider-security-plane branch from fc1ab0e to fea8ce1 Compare August 1, 2026 07:44
… request

Resolving a chefvault:// reference only for model discovery left ordinary
forwarding, compaction, and the live/images/bridge tiers authenticating from
provider.apiKey alone, so a credentialRef-only provider reached upstream with
no Authorization header. Route every provider-key path through a shared
per-request resolver that leases the secret in memory and fails closed.

Also stop suppressing a revoked renewal: an authority revocation now evicts the
active slot and rejects the request instead of serving the cached secret until
its old expiry.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@OnlineChef OnlineChef left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

MERGE BLOCKER — cross-repo contract mismatch against merged ChefVault lidge-jun#86.

ProviderSecurityClient sends only X-Chef-* identity assertions. The merged Vault HTTP surface authenticates /v1/credentials/resolve, /v1/credentials/renew, and /v1/refs/* with Authorization: Bearer <workload token> before accepting those assertions. Therefore this PR's client cannot resolve or renew a credential against the merged authority; it will receive 401. The current Sofie smoke/green CI does not prove compatibility with the merged authenticated contract.

Required before merge:

  1. Add workload-token configuration (for example CHEF_PROVIDER_SECURITY_TOKEN) and send the bearer header on authenticated ChefVault calls without logging or serializing it.
  2. Add a cross-repo-compatible integration test using the Vault token registry/server contract: no token => 401, valid workload token + matching headers => success, mismatched asserted identity => 403.
  3. Split doctor/status into unauthenticated liveness and authenticated readiness. /healthz alone can currently report green while every lease call fails.
  4. Preserve fail-closed behavior across responses, compact, model discovery, live, images, and video when credential resolution fails.
  5. Remove or split unrelated .github/workflows/issue-triage.yml and gui/bun.lock churn from this security PR.

The two earlier Greptile findings (ordinary forwarding missing the leased key and revoked renewal retaining the cached lease) appear fixed in the current head with regression tests; their threads should be rerun/resolved after the authenticated integration lane passes.

OnlineChef and others added 3 commits August 1, 2026 11:27
…readiness

Load CHEF_PROVIDER_SECURITY_TOKEN on the client, attach Authorization on
protected routes, fail closed on resolve/renew without a token, and split
doctor checks into liveness, authenticated readiness, and resolve readiness.

Co-authored-by: Cursor <cursoragent@cursor.com>
… PSP PR

Revert issue-triage workflow and gui/bun.lock to origin/dev so PSP CI
stays scoped to provider-security changes only.

Co-authored-by: Cursor <cursoragent@cursor.com>
…en code

Co-authored-by: Cursor <cursoragent@cursor.com>
@OnlineChef

Copy link
Copy Markdown
Author

Follow-up to MERGE BLOCKER review

Addressing the Vault Bearer gap (not merging yet):

  1. Client contract documented on Vault side: https://github.com/OnlineChefGroep/chefgroep-vault/pull/87 (CHEF_PROVIDER_SECURITY_TOKENPROVIDER_SECURITY_WORKLOAD_TOKENS) + /v1 401/200/403 tests.
  2. This PR now sends Authorization: Bearer and splits doctor into liveness / authenticated / credential readiness; workflow+lockfile churn dropped.
  3. CPM companion: fix(provider-security): ChefVault Bearer auth for ref probes coding-provider-manager#2
  4. Sofie redeployed to TokenRegistry Vault (unauth /provider-security/status → 401; bearer → 200) and OCX with CHEF_PROVIDER_SECURITY_TOKEN.

Still blocked on: green CI for these follow-ups + confirmed live deepseek resolve under TokenRegistry.

OnlineChef and others added 2 commits August 1, 2026 09:34
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
…probes

Only authority outages enter degraded mode; revoked renewals evict and fail
closed; in-flight resolve coalesces concurrent cold starts; status reporting
is read-only and skips probing when no refs are configured; images/compact
surface credential failures with the correct status.

refs #38

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/oauth/index.ts`:
- Around line 470-480: Update resolveModelsAuthToken to attempt
globalProviderCredentialResolver.resolveCredentialRef for every non-empty
trimmed credentialRef, removing the isChefVaultRef pre-check. Preserve the
existing resolved.apiKey return and failure behavior so malformed references are
rejected by the resolver rather than falling through to
resolveEnvValue(prov.apiKey).

In `@src/provider-security/client.ts`:
- Around line 178-211: Move the authenticated token resolution via
requireToken() in the request method before creating the AbortController and
arming timer, while preserving the existing authorization header behavior.
Ensure unauthenticated failures occur before timer allocation, and keep the
current try/finally cleanup for timers used by fetch requests.
- Around line 101-138: Extract the shared lease-field extraction and validation
from parseResolveResponse and parseRenewResponse into a single helper,
preserving the existing required-field and finiteness checks. Update both
parsers to reuse that helper, with parseResolveResponse continuing to apply its
slotHint-specific handling while parseRenewResponse returns only the common
fields.

In `@src/provider-security/resolve.ts`:
- Around line 116-144: Update resolveFromAuthority to distinguish genuine
authority outages from malformed responses, local authority_error failures, and
exceptions during applyResolve or snapshot handling; only mark degraded for
confirmed transport/availability failures, preserving the original error
otherwise. Enforce degraded mode by checking DegradedModeController.canResolve
before calling client.resolveLease and deny without issuing a request when
recovery is not permitted; retain the existing successful recovery path. Add
coverage in tests/provider-security.test.ts for malformed responses not entering
degraded mode and degraded resolution making no authority request.

In `@src/provider-security/slots.ts`:
- Around line 177-182: Make revocation reference-wide rather than
phase-specific: add a revokeRef method to the slot store that invalidates the
entire state, including active and retiring leases, and use it from
resolveCredentialRef when providerSecurityErrorCode(error) is "revoked" instead
of revokePhase(ref, "active"). Add a focused lease-lifecycle regression test
covering renewal revocation with a retiring lease and assert the next resolution
fails closed.
- Around line 185-206: Update redactedStatus so each RedactedSlotSummary uses
the lease object's phase rather than the iteration key, allowing revoked leases
stored in another slot to be reported as revoked. Keep the existing slot lookup,
validity calculation, and hasUsableCredential logic unchanged.

In `@src/provider-security/status.ts`:
- Around line 62-67: Move the refs.length === 0 early return in
collectProviderSecurityDoctorChecks to the beginning of the function, before any
resolver.client.healthz or authenticatedReady probes, and remove the duplicate
later guard. Add a regression test in provider-security.test.ts for zero
references that verifies no authority probe occurs and the function returns the
expected checks.
- Around line 46-60: Update collectProviderSecurityStatus to use the scoped
store from ProviderCredentialResolver via
resolver.slotStore.redactedStatus(entry.ref) instead of the
globalCredentialSlotStore, ensuring provider-layer status matches the resolver’s
configured store.
- Around line 79-90: Centralize redaction of provider-security error details and
apply it before any status or doctor output is constructed. Update the status
authority message paths around resolver.probeAuthenticatedReady(),
liveness.message, and mapAuthorityError/healthz responses, plus the doctor
credential-check detail from resolver.resolveCredentialRef(ref), so serialized
or printed messages contain only safe redacted text while preserving success and
failure status fields.

In `@src/provider-security/types.ts`:
- Around line 129-145: Update validateChefVaultRef to accept the host-only
references already accepted by isChefVaultRef, such as
chefvault://deepseek-api-key. Validate that the parsed URL has either a
non-empty host or a resource path, instead of rejecting solely because pathname
is empty, while preserving protocol and malformed-URI checks.

In `@tests/provider-security-forwarding.test.ts`:
- Around line 69-78: Add an assertion in the mocked ChefVault resolve branch of
the relevant provider-security forwarding test to verify init?.headers contains
Authorization: Bearer ${VAULT_TOKEN}, then assert the resolve response status
remains 200. Keep the existing URL matching and upstream authorization
assertions unchanged.

In `@tests/provider-security.test.ts`:
- Around line 118-128: Update the stale-token case in the “rejects stale fencing
tokens” test to capture the error thrown by store.applyResolve for fencingToken:
3 using an assertion that always fails when no error is thrown, then assert the
captured ProviderSecurityError code is “stale_fencing_token”.
- Around line 73-81: Add negative test cases in the “chefvault ref validation”
suite for an HTTP-scheme ref, an empty chefvault path, traversal segments, and
whitespace/control characters; assert each validateChefVaultRef result has code
“ref_invalid” while preserving the existing valid and bare-path cases.
- Around line 350-398: Add focused regression tests in server-images.test.ts for
selectImagesProvider using a chefvault-backed provider and mocked
resolveProviderApiKey failures. Assert revoked errors produce HTTP 401 with
authentication_error, while authority_unavailable errors produce HTTP 503 with
api_error, covering the openai-sidecar mapping and retry classification.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fb645a0d-b6c8-4f3f-a203-138703ba4ac8

📥 Commits

Reviewing files that changed from the base of the PR and between a6d347c and 3d204a5.

📒 Files selected for processing (22)
  • src/cli/doctor.ts
  • src/cli/status.ts
  • src/images/plan.ts
  • src/oauth/index.ts
  • src/provider-security/client.ts
  • src/provider-security/degraded.ts
  • src/provider-security/index.ts
  • src/provider-security/resolve.ts
  • src/provider-security/slots.ts
  • src/provider-security/status.ts
  • src/provider-security/types.ts
  • src/providers/credential.ts
  • src/providers/openai-sidecar.ts
  • src/server/auth-cors.ts
  • src/server/images.ts
  • src/server/live.ts
  • src/server/responses/compact.ts
  • src/server/responses/core.ts
  • src/types.ts
  • tests/provider-security-forwarding.test.ts
  • tests/provider-security.test.ts
  • tests/server-images.test.ts

Comment thread src/oauth/index.ts
Comment thread src/provider-security/client.ts Outdated
Comment thread src/provider-security/client.ts Outdated
Comment thread src/provider-security/resolve.ts
Comment thread src/provider-security/slots.ts
Comment thread src/provider-security/types.ts
Comment thread tests/provider-security-forwarding.test.ts
Comment thread tests/provider-security.test.ts
Comment thread tests/provider-security.test.ts
Comment thread tests/provider-security.test.ts
OnlineChef and others added 2 commits August 2, 2026 01:10
…octor guards

- degraded mode gates resolve before any authority call, with a bounded
  30s recovery probe; malformed responses (authority_error) no longer
  enter degraded mode
- revoked renewals revoke every slot for the ref (active/next/retiring)
  so rotation leftovers fail closed
- doctor returns early when no chefvault refs are configured, uses the
  resolver's slot store, and redacts authority error detail in
  status/doctor messages
- validateChefVaultRef validates the raw ref string (whitespace/control
  chars, traversal, empty segments) and accepts host-only refs;
  redactedStatus reports the lease's own phase
- ChefVault client: dedupe lease parsing, build headers before arming
  the request timeout so early throws cannot leak the timer
- resolveModelsAuthToken defers all non-empty credentialRefs to the
  resolver so invalid refs fail closed instead of silently falling
  through to apiKey
- tests: negative ref cases, degraded no-probe/recovery-interval
  coverage, retiring-slot revocation, doctor zero-ref guard, and vault
  bearer assertion in forwarding fixture

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
…ovider

A revoked lease must surface as a non-retryable 401 authentication_error
and an unreachable authority as a retryable 503 api_error, covering the
selectImagesProvider -> providerCredentialFailure split used by Codex.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant