Skip to content

feat: deferred credential resolution with user consent#1111

Closed
huang195 wants to merge 1 commit intoNVIDIA:mainfrom
huang195:feat/deferred-credentials
Closed

feat: deferred credential resolution with user consent#1111
huang195 wants to merge 1 commit intoNVIDIA:mainfrom
huang195:feat/deferred-credentials

Conversation

@huang195
Copy link
Copy Markdown

@huang195 huang195 commented May 1, 2026

Summary

Adds runtime credential resolution that prompts the user via OS-native dialog before sharing secrets with sandboxes. Secrets never leave the user's machine until explicitly approved per-request.

  • Proto: 2 new RPCs (ResolveCredential, RegisterCredentialAuthority) + 4 additive messages
  • Server: CredentialAuthorityRegistry with generation-based unregister to prevent race conditions
  • Sandbox: DeferredCredentialResolver with fail-closed semantics in the L7 proxy
  • CLI: credential_authority module with macOS (AppleScript) and Linux (zenity) dialog support

How to use deferred credentials

Automatic (interactive sandbox connect)

When connecting to a sandbox that requires a provider but no local credentials are found:

openshell sandbox create -- claude
# CLI prompts: "No local credentials found. Share on demand (deferred)?"
# Select Yes -> provider created with deferred credentials
# When the sandbox agent makes an API call -> macOS popup asks approval

Explicit (manual provider creation)

# Create a provider with deferred credentials (sentinel value)
openshell provider create --name anthropic --type generic \
  --credential "ANTHROPIC_API_KEY=openshell:deferred"

# Connect - CLI spawns credential authority in background
openshell sandbox connect my-sandbox
# On first API call -> OS-native dialog: "Sandbox my-sandbox requests ANTHROPIC_API_KEY
#                      Destination: api.anthropic.com"
# Options: [Deny] [Once] [Always]

How it works

Sandbox agent makes API call
  -> L7 proxy detects deferred placeholder in outbound headers
  -> Sandbox calls ResolveCredential RPC to gateway
  -> Gateway relays to CLI via bidirectional RegisterCredentialAuthority stream
  -> CLI shows OS-native dialog (AppleScript on macOS, zenity on Linux)
  -> User approves -> CLI reads secret from local env var -> sends back
  -> Sandbox injects credential into the outbound request
  -> Request forwarded to upstream API

The secret is held in sandbox memory only for the session duration - it is never persisted to disk or stored on the gateway.

Analogy

Like ssh-add -c (SSH agent with confirmation): your API key stays on your laptop, and the remote sandbox can only use it when you explicitly approve - one request at a time.

Backward compatibility

  • All proto changes are additive (new field on existing response, new RPCs, new messages)
  • Existing providers with real credential values work unchanged
  • Old sandboxes ignore the new config_environment field (proto default: empty map)
  • Deferred mode is opt-in via the openshell:deferred sentinel value
  • No existing tests broken

Test plan

  • cargo build -p openshell-sandbox -p openshell-server -p openshell-cli
  • cargo test -p openshell-sandbox - existing tests pass
  • cargo test -p openshell-server - provider env resolution tests updated
  • Create provider with --credential KEY=openshell:deferred - deferred provider stored
  • sandbox connect spawns credential authority (visible in debug logs)
  • First API call from sandbox - macOS popup appears
  • "Once" - credential shared, next request prompts again
  • "Always" - credential cached for session, no further prompts
  • "Deny" - sandbox receives 403, no credential shared
  • Regular providers (non-deferred) continue working unchanged

Add runtime credential resolution that prompts the user (via OS-native
dialog) before sharing secrets with sandboxes. When a provider is created
with the sentinel value "openshell:deferred", credentials are not stored
on the gateway. Instead, the CLI registers as a credential authority via
a bidirectional gRPC stream, and the sandbox L7 proxy requests credentials
on-demand when outbound API calls require them.

Key components:
- Proto: ResolveCredential and RegisterCredentialAuthority RPCs
- Server: CredentialAuthorityRegistry with generation-based unregister
- Sandbox: DeferredCredentialResolver with fail-closed semantics
- CLI: credential_authority module with macOS/Linux dialog support

The feature is fully backward compatible — existing providers with real
credential values continue to work unchanged. Deferred mode is opt-in
via the "openshell:deferred" sentinel in the credential value.

Signed-off-by: Hai Huang <haihuang@us.ibm.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
@huang195 huang195 requested a review from a team as a code owner May 1, 2026 15:09
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented May 1, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

Thank you for your submission! We ask that you sign our Developer Certificate of Origin before we can accept your contribution. You can sign the DCO by adding a comment below using this text:


I have read the DCO document and I hereby sign the DCO.


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the DCO Assistant Lite bot.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

Thank you for your interest in contributing to OpenShell, @huang195.

This project uses a vouch system for first-time contributors. Before submitting a pull request, you need to be vouched by a maintainer.

To get vouched:

  1. Open a Vouch Request discussion.
  2. Describe what you want to change and why.
  3. Write in your own words — do not have an AI generate the request.
  4. A maintainer will comment /vouch if approved.
  5. Once vouched, open a new PR (preferred) or reopen this one after a few minutes.

See CONTRIBUTING.md for details.

@github-actions github-actions Bot closed this May 1, 2026
@huang195
Copy link
Copy Markdown
Author

huang195 commented May 1, 2026

I have read the DCO document and I hereby sign the DCO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant