Skip to content

fix: show app and environment when a path filter matches no secrets - #318

Merged
rohan-chaturvedi merged 2 commits into
mainfrom
claude/empty-app-env-fields-69b222
Aug 7, 2026
Merged

fix: show app and environment when a path filter matches no secrets#318
rohan-chaturvedi merged 2 commits into
mainfrom
claude/empty-app-env-fields-69b222

Conversation

@nimish-ks

Copy link
Copy Markdown
Member

The bug

phase run and phase shell printed blank Application and Environment labels whenever the fetch returned no secrets:

🚀 Injected 0 secrets from Application: , Environment:

This is easy to hit. Both commands default to --path /, and paths are matched exactly — so an app whose secrets all live in folders injects zero secrets at the default path. The blank names then read as a failure to resolve the app (an unreadable .phase.json, bad credentials) rather than what actually happened: a path filter that matched nothing.

Root cause

run.go and shell.go derived the labels from the fetched secret rows:

for _, s := range allSecrets {
    apps[s.Application] = true
    envs[s.Environment] = true
}

No rows → no names → strings.Join(nil, ", ")"". phase secrets list had the same root cause in RenderSecretsTree, which read secrets[0].Application; an empty result fell through to a bare No secrets to display. with no context at all. (Both behaviours were faithfully ported from the Python CLI, which has the same defect.)

The fix

Always report the queried app and environment. When no result row carries the names, resolve them from the account's app list via a new phase.ResolveNames. The lookup only runs on the empty path, so the normal path takes no extra requests. Selectors are normalised to canonical names on the way through — --app 3 --env dev, --app-id <uuid>, and .phase.json all report Application: 3, Environment: Development.

Explain why the result was empty, since exact-path matching is the usual reason. run, shell, secrets list and secrets export now point at --path "", and secrets get names the path it searched. The hint is suppressed when no path filter was applied — there, every path was already searched and the suggestion would be a dead end. The export note goes to stderr so piped output stays byte-identical.

phase shell also left PHASE_APP and PHASE_ENV unset whenever zero secrets were loaded; they now follow the resolved context.

No change to --path defaults or filtering semantics — those are documented behaviour (Default is '/'. Pass an empty string "" to fetch secrets from all paths) and match the Python CLI.

Before / after

Test app with secrets only under /one and /two, nothing at the root:

before after
phase run 🚀 Injected 0 secrets from Application: , Environment: 🚀 Injected 0 secrets from Application: 3, Environment: Development
💡 No secrets found at path /. Secrets under other paths are not included — pass --path "" to inject secrets from all paths.
phase secrets list --path / No secrets to display. 🔮 No secrets found for Application: 3, Environment: Development
💡 Nothing at path /. Secrets under other paths are not listed — pass --path "" to list secrets from all paths.
phase secrets get SECRET_1 Error: 🔍 No matching secrets found Error: 🔍 No matching secrets found at path / — secrets under other paths are not searched. Pass --path "" to search all paths
phase secrets export (silent, empty) (empty stdout) + stderr: 💡 No secrets found at path /. …
phase shell blank labels, PHASE_APP/PHASE_ENV unset correct labels, both vars set

Verification

Reproduced and verified end to end against a local Console, using a user token and an app with secrets only in folders:

  • ✅ Blank labels reproduced on the pre-fix build, gone after
  • ✅ Correct labels via --app/--env, partial/lowercase --env dev, --app-id alone, and .phase.json
  • ✅ Happy paths unchanged: --path /one, --path "", and unfiltered secrets list render as before
  • secrets create / delete (which route through listSecrets) render correctly
  • ✅ A genuinely empty environment queried with --path "" gets no misleading hint
  • ✅ Unresolvable app/env still error cleanly before any rendering
  • phase shell sets PHASE_APP=3 PHASE_ENV=Development with zero secrets loaded
  • secrets export | … stdout unchanged — the note is stderr-only
  • go build, go vet, gofmt, go test ./... all clean

New unit tests cover the empty-result renderer, the context-name fallback, and hint suppression when no path filter is set.

🤖 Generated with Claude Code

`phase run` and `phase shell` derived the Application and Environment
labels from the fetched secret rows. When the fetch returned nothing they
printed blank names:

    🚀 Injected 0 secrets from Application: , Environment:

This is easy to hit: both commands default to `--path /`, paths are
matched exactly, so an app whose secrets all live in folders injects zero
secrets at the default path. The blank names then read as a failure to
resolve the app — e.g. an unreadable .phase.json — rather than a path
filter that matched nothing.

Resolve the names from the account's app list when no result row carries
them, so the queried app and environment are always reported. The lookup
only runs on the empty path, leaving the normal path free of extra
requests. `phase secrets list` had the same root cause: its header read
`secrets[0]`, so an empty result printed a bare "No secrets to display."
with no context at all. It now renders the resolved context too.

Also say why the result was empty, since exact-path matching is the usual
reason: `run`, `shell`, `secrets list` and `secrets export` point at
`--path ""` to search all paths, and `secrets get` says which path it
searched. The `export` note goes to stderr so piped output stays clean.

`phase shell` additionally left PHASE_APP and PHASE_ENV unset whenever
zero secrets were loaded; they now follow the resolved context.
@rohan-chaturvedi
rohan-chaturvedi self-requested a review August 6, 2026 09:48
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 7, 2026

Copy link
Copy Markdown

Deploying phase-cli-install-script with  Cloudflare Pages  Cloudflare Pages

Latest commit: ff4526a
Status: ✅  Deploy successful!
Preview URL: https://46cf86f5.phase-cli-install-script.pages.dev
Branch Preview URL: https://claude-empty-app-env-fields.phase-cli-install-script.pages.dev

View logs

- ResolveNames reads the SDK's userdata.json cache before the network,
  never hits the network in offline mode, and falls back to the app ID
  so labels are never blank
- empty-result hints name a --tags filter when one was applied
- keyed secrets export miss names the searched path
- httptest coverage for the name resolution success paths
@rohan-chaturvedi
rohan-chaturvedi force-pushed the claude/empty-app-env-fields-69b222 branch from 3e39298 to ff4526a Compare August 7, 2026 08:46
@rohan-chaturvedi
rohan-chaturvedi merged commit 947be0f into main Aug 7, 2026
5 checks passed
@rohan-chaturvedi
rohan-chaturvedi deleted the claude/empty-app-env-fields-69b222 branch August 7, 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.

2 participants