Repository navigation
feat(cli): scope secret command for provider credentials - #1473
Conversation
Closes a CLI↔Portal parity gap: provider credentials (GitHub, Anthropic, Azure AI Foundry) could only be managed from the Portal secrets page. - `secret list|get|create|preview|update|delete|validate` over the existing Secrets/Token Manager API (`/api/v1/keys`). - Secret values are never fetched or printed in any output format; a regression test pins this even when the API echoes a value back. - `ApiFetchInit.sensitiveBody` fully redacts request/response bodies in the API log sink for credential registration and validation. - `--value-stdin`/`--api-key-stdin` inputs; argv secrets print a warning. - Metadata reads retry transient failures; writes are never replayed. Extracted from #1470. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Test Results (Node.js 22)test: Run #211
🎉 All tests passed! |
Import secret helpers from new shared/token-manager and shared/retry subpaths instead of the shared root, which pulled ioredis into the bundle and crashed it outside the monorepo. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Test Results (Node.js 22)test: Run #213
🎉 All tests passed! |
Documents scope secret (create/preview/list/get/validate/update/delete), credential types and derived capabilities, which services acquire which capability, and the stdin/redaction safety behaviour. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Test Results (Node.js 22)test: Run #215
🎉 All tests passed! |
Define KEY_TYPES once in shared/token-manager and derive KeyType from it. Token Manager validation and the scope secret CLI now use it instead of their own copies. Internal types (github-oauth-cookie-state) are marked INTERNAL_KEY_TYPES and left out of CLI help and errors. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Test Results (Node.js 22)test: Run #218
🎉 All tests passed! |
Drop the internal/user key type split. scope secret help and errors now list all KEY_TYPES, including github-oauth-cookie-state, which is also added to the website credentials guide. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Test Results (Node.js 22)test: Run #219
🎉 All tests passed! |
Test Results (Node.js 22)test: Run #220
🎉 All tests passed! |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Test Results (Node.js 22)test: Run #221
🎉 All tests passed! |
| ]; | ||
| const validationFields: DisplayField<KeyValidationResult>[] = [ | ||
| { key: "status", label: "Status" }, { key: "capabilities", label: "Capabilities", formatter: (result) => result.capabilities?.join(", ") ?? "" }, | ||
| { key: "error", label: "Error" }, |
There was a problem hiding this comment.
P1: Validation errors can expose the credential. These error fields are printed verbatim, but the existing Anthropic validator can include the complete credential in an error message. I reproduced this with the real validator and built CLI using a fake multiline API key: secret preview --type anthropic-api-key --value-stdin -o json printed Anthropic key validation failed: Headers.append: "fixture-secret\nbad" is an invalid header value. The same error is persisted as lastValidationError and printed by secret get. The output allowlist and sensitiveBody log redaction therefore do not uphold the guarantee that secret values are never printed. Please sanitize validation errors at their source and add regression coverage for credentials echoed inside error/lastValidationError, not just a returned value property.
There was a problem hiding this comment.
Addressed in 99cb3cb2. Provider exception details and response bodies are no longer included in validation errors, preventing echoed credentials from being persisted as lastValidationError. The CLI also omits stored validation-error details from metadata output, which protects against errors persisted before this change. Regression tests cover credentials echoed by network exceptions and provider responses, and verify validation-error text is excluded from CLI output.
Auto-resolved by the GitHub Copilot app.
| import { getDefaultApiUrl, withOutputOption } from "../utils/shared.js"; | ||
| import type { DisplayField, OutputFormat } from "../utils/types.js"; | ||
|
|
||
| type KeyMetadata = Pick<KeyDocument, "_id" | "type" | "enabled" | "capabilities" | "lastValidationStatus" | "lastValidationError" | "comment">; |
There was a problem hiding this comment.
P2: Include expiration in the metadata output. create and update let operators set or clear expiresAt, but this type and the keyFields allowlist omit it from every output format. Even when the API returns an expiration, secret get -o json drops it, so operators cannot inspect credential expiration or confirm an expiration update without switching to the Portal. Please include expiresAt in the permitted metadata fields and cover its output after setting/clearing expiration.
There was a problem hiding this comment.
Addressed in 99cb3cb2. Added expiresAt to the CLI metadata output allowlist. Regression coverage checks create/get, setting expiration, and clearing it in table, JSON, YAML, and TSV output formats.
Auto-resolved by the GitHub Copilot app.
Sanitize provider validation failures before they are returned or stored, and omit persisted validation error details from CLI metadata output. Include expiration in credential metadata output and cover set/clear flows. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Test Results (Node.js 22)test: Run #227
🎉 All tests passed! |
Summary
Adds a
scope secretcommand group that manages provider credentials through the existing Secrets/Token Manager API (/api/v1/keys), closing a CLI ↔ Portal parity gap. Subcommands:list,get,create,preview,update,delete,validate.--value-stdin/--api-key-stdin(or flags).ApiFetchInit.sensitiveBodyredacts credential request/response bodies in the API log sink.Extracted from #1470 as an independent PR (based on
main, no dependency on named environments).Demos
CLI walkthrough recorded against a local Scope stack (API + Token Manager from
main, CLI from this branch).Before
N/A (new command)
After
Create a key from stdin, see server-side validation reject a dummy key, inspect metadata (value never printed), disable, delete.
scope-secret-walkthrough.mp4
Testing
cd apps/cli && npx tsc --noEmit: passedpnpm exec vitest run apps/cli/src: passed (155 tests; 18 insecret.test.ts, including no-leak checks on stdout and logs)Documentation and compatibility
apps/cli/README.md: new "Provider secrets" section.agents/skills/scope-cli/SKILL.md: new "Provider Secrets" tableguides/managing-credentials.md, under Guides → Admin). It covers credential types and capabilities, which services use which credential, everyscope secretcommand, and the safety behaviour.getting-started/access.mdnow links to it.secretgroup.Checklist
up()/down()and keep it CosmosDB-compatible. N/ANOTICE/NOTICE-REVIEW.txtwithpnpm noticeas needed. N/A