Skip to content

feat(secret): add secret get and secret set, and show key names in ls - #11

Merged
anak10thn merged 2 commits into
mainfrom
feat/secret-get-set
Aug 3, 2026
Merged

feat(secret): add secret get and secret set, and show key names in ls#11
anak10thn merged 2 commits into
mainfrom
feat/secret-get-set

Conversation

@anak10thn

Copy link
Copy Markdown
Member

Problem

Two gaps, and they made each other worse.

You could not see what a Secret holds. secret ls showed a key count and nothing else — not even the names — and there was no secret get. orcinus config --show-secrets does not cover it either: it selects on managed-by and orcinus.io/project, and a Secret made by secret create has no project label, so it never appears there. Reading a value meant:

orcinus kubectl get secret app-secret -o jsonpath='{.data.DB_PASS}' | base64 -d

Updating one key destroyed the others. secret create on an existing name replaces the whole object:

orcinus secret create app-secret --from-literal DB_PASS=xxx --from-literal API_KEY=yyy
orcinus secret create app-secret --from-literal DB_PASS=new
# → API_KEY gone, no warning

And since the keys could not be listed, there was no way to know what to re-pass.

Change

$ orcinus secret get app-secret
Name:                 app-secret
Type:                 Opaque
Managed by orcinus:   true

KEY       VALUE
API_KEY   <12 bytes, hidden>
DB_PASS   <8 bytes, hidden>

Values hidden. Re-run with --show-values to print them.

$ orcinus secret set app-secret --from-literal DB_PASS=new
secret "app-secret" updated: set DB_PASS (2 key(s) total)
         running pods keep the old values until restarted (`orcinus restart <service>`)
  • secret get — keys listed, values withheld unless --show-values, so it is safe in a shared terminal.
  • secret set — merges; keys not named are kept, and the Secret is created if absent. It preserves the Secret's existing type, so merging into a TLS or dockerconfigjson Secret does not retype it to Opaque and break every consumer (tested).
  • secret ls — key names instead of a bare count, truncated to three with +N more.
  • secret create — keeps replace semantics, since that is what it means, but now names the keys it dropped and points at set.

Both writers reject an empty --from-literal set rather than clearing a Secret.

The two things that bite, now in --help

  • create REPLACES — stated in its long help
  • a changed Secret does not reach running pods: env vars are injected at container start, so orcinus restart <service> is needed. Secrets consumed as a mounted file (external: true) are the exception — the kubelet refreshes those in place.

Tests

10 new, 147 total.

pkg/deploy against a fake clientset: merge keeps untouched keys; merge creates when absent; merge preserves an existing TLS type; GetSecret sorts keys and reports ManagedBy; ListSecrets returns names. Plus TestApplySecretReplaces, which pins the destructive behaviour set exists to avoid, so it cannot drift silently.

pkg/cli: subcommands resolve with the expected flag defaults, --show-values defaults to false, the help text keeps its two warnings, parseLiterals edge cases (K=, WITH=a=b, rejects NOEQUALS and =novalue), and summarizeKeys truncation.

Note for reviewers

GET /api/v1/secrets gains a KeyNames field, since it serializes the shared ListSecrets type — names only, no values. The API's POST keeps replace semantics; only the CLI grew a merge path. Say the word if the API should get set too.

…n `ls`

There was no way to see what a Secret holds. `secret ls` reported a key count
and nothing else — not even the key names — and there was no `secret get`.
`orcinus config --show-secrets` does not fill the gap either: it selects on
managed-by AND the project label, and a Secret made by `secret create` carries
no project label, so it never appears there. Reading a value meant dropping to
`orcinus kubectl get secret ... -o jsonpath` and decoding base64 by hand.

Updating was worse. `secret create` on an existing name replaces the whole
object, so changing one key silently dropped every key not passed with it —
and since the keys could not be listed, there was no way to know what to pass.

- `secret get <name>` lists the keys, with values withheld unless
  --show-values, so it is safe to run in a shared terminal.
- `secret set <name> --from-literal K=V` merges: keys not named are kept, and
  the Secret is created if absent. It keeps the Secret's existing type, so
  merging into a TLS or dockerconfigjson Secret does not retype it to Opaque
  and break its consumers.
- `secret ls` shows key names instead of a bare count, truncated to three with
  "+N more" to keep rows scannable.
- `secret create` keeps replace semantics — that is what it means — but now
  names the keys it dropped and points at `set`.

Both writers reject an empty --from-literal set rather than clearing a Secret.

Help text carries the two things that bite: that `create` REPLACES, and that a
changed Secret does not reach running pods, since env vars are injected at
container start (`orcinus restart <service>`). Secrets mounted as files are the
exception — the kubelet refreshes those in place.

GET /api/v1/secrets gains a KeyNames field from the shared ListSecrets type.
The API's POST keeps replace semantics; only the CLI grew a merge path.
…uster

TestLiveSecret only exercised create/ls/rm, so nothing checked the new commands
against a real API server — the unit tests use a fake clientset, which cannot
catch how the values actually round-trip.

Extends it with: ls naming the keys, get withholding values until --show-values,
set changing one key while leaving the other intact (verified through kubectl,
against the base64 the API actually stores), set creating a Secret that does not
exist yet, and create reporting the key it dropped.

Adds TestLiveSecretEnvFromSecret, which deploys a service with
x-orcinus-env-from-secret and reads the value back out of the running pod's
environment — the one thing no offline test can assert.

Both stay behind ORCINUS_E2E_LIVE, like the rest of the live suite.
@anak10thn
anak10thn merged commit e853473 into main Aug 3, 2026
2 checks passed
@anak10thn
anak10thn deleted the feat/secret-get-set branch August 3, 2026 08:55
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