Skip to content

Support Managed Git/GitHub Credentials in CLI - #449

Draft
scubbo wants to merge 27 commits into
mainfrom
scubbo/managed-credentials-simplification
Draft

scubbo wants to merge 27 commits into
mainfrom
scubbo/managed-credentials-simplification

Conversation

@scubbo

@scubbo scubbo commented Nov 5, 2026 •

Copy link
Copy Markdown

This PR adds support for Managed Git/GitHub credentials to the CLI.

Example usage:

$ vercel sandbox create --credentials=github

  Inferred Parameters:

  Setting       Value
  ------------  --------------------------
  Team          example-team-name
  Project       example-project-name
  Repo          vercel/repo-name                <------- inferred from local repo
  Actions       github:issues:read              <------- defaults; can be overridden
                github:issues:comment
                github:pull-request:create
                git:write
  GitHub actor  @scubbo                         <------- inferred from `gh auth status`, or from Vercel's own linkage

Create this sandbox? (y/n) n

  Edit these explicit commands as desired

sandbox create --scope=team_teamslug --project=prj_projectslug --credentials-github-repo=vercel/repo-name --credentials-github-action=github:issues:read,github:issues:comment,github:pull-request:create,git:write --credentials-github-act-as=@scubbo


Sandbox creation canceled.

(Per Melkey’s CLI advice, the best way to allow an agent to fixup incorrect guesses is to print the full explicit flags that represent what was inferred)

Credential inputs

--credentials=github requests the default GitHub credentials and infers the repository, actor, and actions. The option takes a comma-separated provider list. Only github is supported.

Do not combine it with --credentials-github-repo, --credentials-github-action, --credentials-github-act-as, --credentials-file, or --credentials-github-from-sandbox. Explicit credential inputs request GitHub credentials on their own. Conflicts fail before authentication or inference. Normal creation and authentication options, and the output path for exporting credentials, remain independent.

--credentials-github-action=git:write,github:pull-request:create requests exact actions. Explicit actions replace all defaults, including Git access. Git actions authorize Git operations. GitHub actions authorize GitHub API operations. There are no read/write presets, and unsupported git:read requests are rejected rather than replaced with write access.

--credentials-file=credentials.json reads the API's complete credentials object. Use - for stdin. The file has provider keys at its root:

{
  "github": [
    {
      "repositories": ["acme/widgets"],
      "actions": ["git:write", "github:pull-request:create"],
      "actAs": "@example-user"
    }
  ]
}

The file contents become the API request's credentials field without regrouping or inferred rights. Files do not select a clone source. Saved credential files use this same shape. File input cannot be combined with inferred credential defaults, direct credential overrides, or Sandbox reuse.

The managed-credentials guide lists all supported actions and their purpose. Consent, project Bounds, actor inference, and single-attempt creation retain their existing behavior.

Validation

The CLI input update was prepared by an automated agent, not Jack.

  • The six default/override regression cases failed before the fix. All 71 focused input, resolver, and creation-context tests pass.
  • env -u VERCEL_TOKEN -u VERCEL_OIDC_TOKEN pnpm --filter sandbox test --run: 868 tests passed, exit 0.
  • pnpm --filter sandbox typecheck: exit 0.
  • pnpm --filter sandbox generate-docs: build and help generation completed, exit 0.
  • Thirty built-binary cases cover conflicting inputs in both flag orders across create, run, and sh. Each rejects before authentication with exit 2. Help and stdin validation checks also pass.
  • Formatting and git diff --check pass.

The test suite emits dependency source-map warnings and output from unrelated tests. The build emits a tsdown deprecation warning. Documentation generation also emits a module-type warning. These commands succeed, but their output is not pristine. This update does not include a live Sandbox creation test.

This was referenced Nov 5, 2026
Comment thread packages/sandbox/src/commands/create.ts Resolved
Applies the eight "highest-value changes" from the automated audit on
PR #449. No active product feature is removed.

1. Replace 60 development-history changesets with one release note,
   preserving the maximum bump per package (sandbox minor,
   @vercel/sandbox minor, @vercel/sandbox-mock patch).
2. Carry one immutable API-shaped request. The canonical configuration
   already has the API shape, so managed-credentials-transport.ts, the
   CreateContext.creation copy and PreparedManagedCredentials.transport
   collapse into it; the legacy commitAs anti-widening guard moves into
   validateConfig, the one checkpoint every path goes through. Consent
   now approves the caller's own proposal instead of returning a
   replacement one.
3. Delete retired local/profile commit inference, the unused
   inferCommitIdentityImpl seam, unreachable provenance variants and the
   write-only InferredActor.profile metadata. Explicit commitAs parsing
   is unchanged.
4. Give each behavior one test owner: the transport and cross-module
   history suites are gone and the review/provenance suites are merged,
   with their unique cases moved to the owning suites.
5. Keep selected IDs separate from labels. Policy reads now take the
   selected IDs directly rather than round-tripping ID to slug and back,
   and the unused snapshot selector-kind plumbing is gone. The recovery
   command keeps its current selector spelling.
6. Classify creation failures once: creation no longer formats an
   APIError and writes its response to a temporary file only for the
   caller to unwrap and classify it again. Errors it rethrows are still
   formatted once by the top-level funnel.
7. Capture parsed argument units once for recovery instead of flattening
   to strings and reparsing them, which removes two hand-maintained
   lists of value-taking options that had to track every CLI flag. Skip
   the two display-name GETs and the review table when --yes makes the
   review invisible.
8. Shorten the guide around one approval/Bounds section, one canonical
   example and one recovery section, stop run and sh advertising a
   dry-run mode they reject, and regenerate the help reference from
   source (which also picked up four stale shared-scope help lines).

147 files/+15,513 becomes 84 files/+14,247. CLI 1,128 tests, SDK 492,
mock 238, and all three typechecks and builds pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Co-Authored-By: scubbo <scubbo@users.noreply.github.com>
@vercel

vercel Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
sandbox Ready Ready Preview, v0 Nov 9, 2026 9:13pm UTC
sandbox-cli Ready Ready Preview Nov 9, 2026 9:13pm UTC
sandbox-sdk-ai-example Ready Ready Preview Nov 9, 2026 9:13pm UTC
workflow-code-runner Ready Ready Preview Nov 9, 2026 9:13pm UTC

Request Review

Second simplification pass. Retires four optional surfaces and removes the
duplicate command-level test matrices, keeping sandbox reuse and the
explicit-flags recovery command.

Retired surfaces:
- --github-access read/write presets, with managed-credentials-github-access.ts
  and its two suites. Explicit --credentials-github-action is the single way to
  state a permission set.
- --credentials-github-no-write, a flag whose only behavior was rejection.
  Explicit git:read is still rejected by action parsing.
- --credentials-github-commit-as, the deprecated commit-credit override, with
  managed-credentials-commit.ts. The commitAs field stays in the configuration
  schema for files and reuse, and keeps its anti-widening guard; nothing
  derives it from a flag or from local Git any more.
- Bare --credentials-github-persist-configuration auto-naming. The flag now
  takes an explicit path, which removes the 110-line optional-value parser that
  existed only to disambiguate the bare form. Writes stay exclusive mode-0600
  after successful creation.

Test consolidation, per one owner per behavior:
- create-managed-credentials.test.ts drops the full-replay matrices it shared
  with the unit suites and keeps one wiring test per behavior (953 -> 471).
- managed-credentials-consent.test.ts is gone; its promptReviewDecision unit
  matrix moves to the suite that owns that module, and its flow-level cases
  were already covered by managed-credentials-flow.test.ts.
- project-bounds no longer repeats the HTTP status, redirect, sanitization and
  deadline matrices for the team endpoint, which shares readJson with the
  project endpoint. Team-identity verification is still covered.
- scope-display keeps two deadline properties instead of six; names are display
  metadata and the bounded-GET shape is covered by the client that gates
  creation.
- flow drops a duplicated JSON-warning test and the EOF/SIGINT cancellation
  copies of the "n" path.
- The SDK forwards the whole action registry in one request instead of 26
  runs asserting the same pass-through.

Docs drop the retired flags; the help reference is regenerated from source.

147 files/+15,513 at the branch point, 84/+14,247 after the first pass, now
78 files/+12,454. CLI 1,014 tests, SDK 468, mock 238; typechecks and builds
pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Co-Authored-By: scubbo <scubbo@users.noreply.github.com>
Remove unused private CLI action helpers, the parse-only validation wrapper, obsolete author/profile metadata and actor-origin bookkeeping, and the stored-but-unread managedOptions field. Keep the SDK exports and all required credential behavior.

Merge five redundant configuration cases into stronger existing owners. Move precision-loss and source-read-marker cases into existing tables. Share scope-lookup setup while retaining all 63 cases.

Validation: 836 CLI tests, typecheck, build, docs generation, formatting, and 88 parent/current action-normalization comparisons pass. Built preview and n recovery pass. The safety check held the credential-enabled live creation/operation script before execution, so those live checks remain blocked for this checkpoint. No Sandbox was created by that attempt.

Preserve the PR description note that From remains a desired follow-up, with c2699f2 and d95c878 as restoration references.
Rename the preview to Inferred Parameters. Remove the Sandbox, Commit credit and Resources rows, leaving GitHub actor as the identity row. Rename Access to Actions.

Use short labels and include repository names in values only when needed to distinguish targets. This prevents a long repository label from wrapping independently beside git:write and looking like a separate action row. Preserve per-repository and actor associations and the exact request. Actual name/resource creation options and rejection flags are unchanged.

Validation: the new row regression failed before implementation. CLI typecheck, build, docs generation, all 838 CLI tests, formatting and diff checks pass. The built CLI showed the requested long-repository preview and n printed explicit recovery flags before exiting 130. No Sandbox was created.

Keep the From restoration note for c2699f2/d95c878 in the PR description.
Rename the clone-source label to Repo, render each action on its own line, and add a dashed heading separator. Keep Git/API rights and per-repository actor associations unchanged.

Preserve deliberate line breaks in table cells while sanitizing each displayed line. Untrusted scope/repository/revision fields are still sanitized before row construction.

Validation: the updated exact-row regression failed before implementation. All 839 CLI tests, typecheck, build, docs generation, formatting and diff checks pass. The rebuilt CLI displays the requested final layout and n still prints explicit flags and exits 130 before creation. No Sandbox was created.

The previous safety hold blocks PR description edits in this turn. The existing From restoration note for c2699f2/d95c878 remains unchanged.
Use the requested recovery text: Edit these explicit commands as desired. Prefer a matching validated GitHub username in direct rejection flags. The flag already accepts bare usernames, @usernames and numeric IDs.

Keep original request data unchanged. Fall back to the original selector when username metadata is missing, mismatched or invalid. Never replace an existing username with display metadata. Prefix numeric usernames with @ to distinguish them from user IDs. Canonical JSON replay is unchanged.

Validation: recovery message and username regressions fail before implementation. All 846 CLI tests, typecheck, build, docs generation, formatting and diff checks pass. The built inferred preview followed by n prints @scubbo, the requested message, and exits 130 without creation.

The earlier safety hold still prevents updating the PR description this turn. Its existing From restoration note remains unchanged.
Remove unused metadata caching, repeated action validation in recovery, and redundant managedSource selection after approval. Keep policy reads fresh and preserve scope, identity, timeout, redirect and authorization guards.

Share the canonical API fixture, API-only replacement-default assertion, unreadable-Bounds failure harness and global-fetch/deadline success case. Preserve all interactive/yes failure combinations. Move empty-actor validation into the parser matrix; parser tests already own empty-action validation.

Validation: 257 focused tests, then 70 configuration tests and all 843 CLI tests pass. CLI typecheck, build, formatting and diff checks pass. The test inventory changes from 846 to 843 with explicit merge/ownership mappings. No Sandbox was created and no credential-enabled live operations were performed.

This removes 74 net lines. Preserve the existing From restoration note and all required UX, multi-repository input and Sandbox reuse.
Consolidate repeated scope, inference, action, consent, Bounds, recovery, configuration, export and safety explanations into their owning sections. Link the existing multi-repository JSON example instead of duplicating it. Shorten the release note without changing affected packages or bump types.

Keep all original flag names, limits, supported actors/actions, backend prerequisites, scope behavior, explicit-token recovery, exit codes, non-resuming reuse, uncertain-outcome guidance and managed-Git runtime restrictions. Correct the stale claim that Resources appear in the preview.

The guide shrinks from 446 to 230 lines and the changeset from 54 to 30: 240 net lines removed. No CLI implementation or generated help changes.

Validation: original flag-name coverage, relative links, unchanged changeset frontmatter, unchanged generated CLI help, built create-help example flags, production-parser acceptance/nonmutation of the linked JSON example, Prettier and git diff checks pass. The local launcher still runs the latest built CLI. No Sandbox was created.
Clarify consent and metadata handling in managed credentials.
Removed outdated information regarding server-side feature gates and permissions.
Clarified actions and identity section, updated flags description, and removed outdated local testing instructions.

This branch was successfully deployed

4 active deployments
Preview – sandbox-sdk-ai-example — 5b0bbb06 Deployed Nov 9, 2026 by vercel[bot]
Preview – sandbox — 5b0bbb06 Deployed Nov 9, 2026 by vercel[bot]
Preview – workflow-code-runner — 5b0bbb06 Deployed Nov 9, 2026 by vercel[bot]
Preview – sandbox-cli — 5b0bbb06 Deployed Nov 9, 2026 by vercel[bot]
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