Skip to content

feat: add cone secret command for internal text secrets#140

Closed
paul-doordash wants to merge 5 commits into
ConductorOne:mainfrom
paul-doordash:paul/add-secret-command
Closed

feat: add cone secret command for internal text secrets#140
paul-doordash wants to merge 5 commits into
ConductorOne:mainfrom
paul-doordash:paul/add-secret-command

Conversation

@paul-doordash

Copy link
Copy Markdown

Adds cone secret with create, get, and view subcommands for managing internal TEXT secrets.

  • Content is encrypted client-side with Age to the recipient returned by the API before upload.
  • Secrets support allowed-user restrictions, expiry, and max-view burning.
  • Bumps conductorone-sdk-go (and re-vendors) for the secrets API, and adds the corresponding client methods in pkg/client.

🤖 Generated with Claude Code

P3GLEG and others added 5 commits June 25, 2026 12:47
Add `cone secret` with create, get, and view subcommands for managing
internal TEXT secrets. Content is encrypted client-side with Age to the
recipient returned by the API before upload; secrets support allowed-user
restrictions, expiry, and max-view burning.

Bumps conductorone-sdk-go (and re-vendors) to pull in the secrets API
support, and adds the corresponding client methods in pkg/client.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Previously `secret create` only created internal (team/SSO) TEXT secrets,
covering 4 of the 10 combinations the web UI exposes. Add the two missing
axes:

- FILE secrets via --file <path>: sets SecretType=FILE with the file's
  derived content type, size (original/pre-encryption), and name, then
  Age-encrypts the bytes and PUTs them to the upload URL from the create
  response (rather than SetTextContent).
- External recipients via --allowed-emails: routes to CreateExternal for
  email-verified recipients, mutually exclusive with --allowed-user-ids.

--content and --file are mutually exclusive. Adds CreateExternalSecret and
UploadSecretFile client methods plus tests for the new helpers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Extract input validation into validateSecretCreateInput and narrow
createSecret to a secretCreator interface so request building is testable
without a live API. Add tests for:

- validation: recipient xor, required expiry, content/file conflict
- request building: internal/external x text/file, including secret type,
  input-format presence, file metadata, and display-name/max-views

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
FILE secrets could be created but not read back via the CLI (view only
handles TEXT and errors on files). Add `secret download <vault-id>`, which
generates an ephemeral Age identity, has the server re-encrypt the file to
it, downloads from the returned capability URL, decrypts, and writes to
--out (or the secret's original filename).

Adds the DownloadSecretFile client method and a decryptBytesFromAgeIdentity
helper (raw bytes, no base64), with roundtrip tests. Verified end-to-end
against a live tenant: upload then download returns byte-identical content.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Two UX fixes found while testing every create path against a live tenant:

- normalizeExpiresIn parses human durations (1h, 30m, 3600s), enforces the
  API's [1h, 720h] range client-side, and emits the protobuf "<seconds>s"
  format the API requires — so "1h" now works instead of returning an opaque
  400, and out-of-range/bad values fail fast without a round-trip.
- view/download now detect externally shared secrets up-front and explain
  they must be opened via their share URL (printing it), rather than leaking
  the raw "use opener service for external secrets" 400.

Adds normalizeExpiresIn tests; verified both paths live.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@c1-squire-dev

c1-squire-dev Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Thanks @paul-doordash for putting #140 together. I opened a follow-up PR at #141 that keeps your commits and structure intact and layers on the review/QA pass we discussed.

The follow-up adds C1 Web App terminology alignment, stricter create validation, share-code/share-URL refs, streaming file upload/download with destination-local temp decrypt, list/download/revoke/audit, and --user/--external-emails UX improvements. I also ran a c1dev-okta pass against Cone and the C1 Web App, including creating a personal API credential from the Web profile of an internal recipient user and using it with Cone to reveal a Web-created internal secret. The one explicit limitation is external secret reveal/download from Cone, because that uses the web opener service which is not in the currently vendored SDK, so the CLI now reports that clearly.

Credit in the PR body calls out that this builds directly on your original implementation. Thanks again for building the foundation for the secrets command.

c1-squire-dev Bot added a commit that referenced this pull request Jun 26, 2026
Builds on the secret command introduced by Paul Ganea in PR #140.

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
c1-squire-dev Bot added a commit that referenced this pull request Jun 26, 2026
Builds on the secret command introduced by Paul Ganea in PR #140.

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
pquerna added a commit that referenced this pull request Jun 26, 2026
* feat: add cone secret command for internal text secrets

Add `cone secret` with create, get, and view subcommands for managing
internal TEXT secrets. Content is encrypted client-side with Age to the
recipient returned by the API before upload; secrets support allowed-user
restrictions, expiry, and max-view burning.

Bumps conductorone-sdk-go (and re-vendors) to pull in the secrets API
support, and adds the corresponding client methods in pkg/client.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* feat: support FILE secrets and external recipients in cone secret create

Previously `secret create` only created internal (team/SSO) TEXT secrets,
covering 4 of the 10 combinations the web UI exposes. Add the two missing
axes:

- FILE secrets via --file <path>: sets SecretType=FILE with the file's
  derived content type, size (original/pre-encryption), and name, then
  Age-encrypts the bytes and PUTs them to the upload URL from the create
  response (rather than SetTextContent).
- External recipients via --allowed-emails: routes to CreateExternal for
  email-verified recipients, mutually exclusive with --allowed-user-ids.

--content and --file are mutually exclusive. Adds CreateExternalSecret and
UploadSecretFile client methods plus tests for the new helpers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* test: cover all secret create combinations and input validation

Extract input validation into validateSecretCreateInput and narrow
createSecret to a secretCreator interface so request building is testable
without a live API. Add tests for:

- validation: recipient xor, required expiry, content/file conflict
- request building: internal/external x text/file, including secret type,
  input-format presence, file metadata, and display-name/max-views

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* feat: harden secret command UX

Builds on the secret command introduced by Paul Ganea in PR #140.

Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: Pegleg <pegleg@linux.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Paul Querna <paul.querna@conductorone.com>
Co-authored-by: c1-squire-dev[bot] <c1-squire-dev[bot]@users.noreply.github.com>
@pquerna

pquerna commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Thank you for the contribution -- commits merged via #141 which stacked a couple fixes/changes on top

@pquerna pquerna closed this Jun 26, 2026
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.

3 participants