Surface CI secret variant shadowing in depot ci secrets list#532
Open
robstolarz wants to merge 6 commits into
Open
Surface CI secret variant shadowing in depot ci secrets list#532robstolarz wants to merge 6 commits into
depot ci secrets list#532robstolarz wants to merge 6 commits into
Conversation
The generated Go bindings for the CI secret service had drifted behind their .proto source: the ListSecretsRequest.context field and the per-variant VariantResolution enum were defined in the schema but missing from the generated code, so the CLI had no way to ask the server to resolve variants or to read back which one wins. Regenerate with the pinned buf plugins so the bindings match the schema. DEP-5304 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2fab160. Configure here.
A CI secret can have several variants scoped by repository, environment, branch, or workflow, plus a catch-all default. At runtime the most specific matching variant wins. That means a repo-scoped variant silently overrides the default for its repository, and `secrets list` gave no hint this was happening: re-importing a value into the default appeared to succeed while the stale repo-scoped variant kept winning. Route `secrets list` through the context-aware ListSecrets path. The --repo/--env/--branch/--workflow selectors are now sent as a job context rather than a hard filter, so the server annotates every variant with its resolution and orders winners first instead of dropping variants. The table gains a STATUS column that labels each variant active, shadowed, or candidate for the given context, and a legend explains the terms. Without a context there is no single winner to report, so the column is omitted and a hint points at the selector flags. `list <name>` takes the same path so it, too, shows which variant wins. DEP-5304 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bels Adds a write-path advisory: after `secrets set/add/bulk`, probe each sibling variant scope through the context-aware list RPC and warn on stderr when the server marks the just-written variant lower-priority for some job. Precedence stays server-side; no specificity weights in the CLI. Refines the list STATUS labels to active (wins) / shadowed / may win, moving STATUS to the trailing column since its labels are the widest. Ref: DEP-5304 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sync the vendored variables proto with canonical: add ListVariablesRequest.context (job context the server resolves against), Variable.resolution, and the ListVariableAttributes RPC. DEP-5304. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror the secrets work onto variables. `variables list` now forwards --repo/--env/--branch/--workflow as job context so the server resolves each group (which variant wins, which are shadowed) and orders winners first; the table gains a SCOPE column and, when context is given, a STATUS column (active (wins) / shadowed / may win). `variables set`/`add` warn on stderr when the value just written is shadowed by a more specific variant. Variables report resolution only at the group level, so per-row STATUS is derived from the group verdict plus the server winner-first ordering rather than a per-variant field (see variableVariantRowResolution). The shadow-probe and warning helpers are shared with secrets. DEP-5304. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tively Two refinements to the write-path shadow check. Bulk writes now share one probe budget across every item, so a large dotenv import cannot fan out into hundreds of advisory list reads after the writes already succeeded; a single set/add still gets its own full budget. And the disjoint check now compares repository scopes case-insensitively, matching resolution everywhere else in this file, so a sibling scoped to owner/Repo is no longer wrongly skipped against a written owner/repo. DEP-5304. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
a929289 to
21a4447
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
A CI secret or variable can carry several variants, each scoped to a repository, environment, branch, or workflow, alongside a catch-all default. At runtime the most specific matching variant wins — so a repo-scoped variant quietly outranks the default for its repository.
That rule was invisible at the CLI. If someone re-imports a value into the default while a stale repo-scoped variant still exists, the import looks like it succeeded but the old repo-scoped value keeps winning, and nothing explains why the "updated" secret never takes effect. This change surfaces that resolution both when you list and at the moment you write — for both
secretsandvariables, which share the same variant model and the same blind spot.What changed
Listing reveals the winner. The
--repo,--env,--branch, and--workflowselectors are now sent to the server as a job context instead of a hard client-side filter. The server already knows how to resolve variants for a context: it returns the relevant variants ordered winner-first and tags each with its resolution. The CLI now asks for that and renders it, rather than filtering variants out itself — which also fixes a subtle bug where the old exact-match client filter could drop a variant the server had legitimately resolved through a pattern (for example abranch=release/*variant matching--branch release/1).The list table gains a STATUS column whenever a context is supplied:
active (wins)(this variant wins),shadowed(a more specific variant overrides it), ormay win (needs branch/env)(it could still win with more context). A short legend explains the terms. Without a context there is no single winner to report, so the column is omitted and a hint points at the selector flags.list <name>takes the same path, so inspecting a single secret also shows which variant wins. The SCOPE column shows each variant's attributes in both modes.Writing warns when the value is shadowed. After
secrets set,secrets add, orsecrets bulk, the CLI checks whether the variant it just wrote is actually the one that will apply. For each sibling variant's scope it asks the server — through the same context-aware list — which variant wins there, and prints a stderr advisory only when the server reports the just-written variant aslower-priority. This closes the "reported success but nothing changed" gap at the moment it bites: re-importing the default while a repo-scoped variant still wins now prints a warning pointing at the exactdepot ci secrets list … --repo …that reveals the shadowing variant. All precedence stays server-authoritative; the CLI never recomputes the specificity weights. The probes are de-duplicated by scope and capped so a large bulk import can't fan out into unbounded follow-up requests.variablesgets the same treatment.variables listnow forwards the same selectors as job context, gains the SCOPE and STATUS columns, andvariables set/addwarn on the write path — mirroring secrets and reusing the shared shadow-probe and warning helpers. One difference under the hood: variables report resolution only at the group level (there is no per-variant resolution field on the wire, as there is for secrets), so the per-row STATUS is derived from the server's group verdict plus its winner-first ordering — the first row wins, the rest are shadowed — rather than read off each variant. Precedence stays entirely server-authoritative either way.Proto bindings. The generated
v3beta2secret and variable proto bindings had drifted behind their schema — the requestcontextfield and (for secrets) the per-variant resolution enum were defined but never generated — so the CLI had no way to send a context or read the resolution back. They are regenerated here with the pinned buf plugins.Example
The stale repo-scoped variant that keeps winning shows as
active (wins), the freshly re-imported org-wide default shows asshadowed, and the re-import now says so out loud.Notes
The server side (context resolution and winner-first ordering) already shipped; this is the CLI catching up to surface it. No server change is required.
Deferred / known-open
VariableVariant.resolution(as secrets already do) would let variables use the exact same per-row path; it needs a server + proto change and is left as a follow-up.lower-priority; a few multi-dimension cross-shadows can still resolve toindeterminateand not warn.listremains the complete tool for inspecting resolution, and the warning always points there.Ref: DEP-5304
Note
Medium Risk
Changes how CI secret/variable list and write UX interpret scoped variants and adds extra list RPCs after writes; precedence remains server-side but mis-synced proto/server behavior could confuse resolution display.
Overview
CI secrets and variables can have multiple scoped variants where the most specific match wins at runtime; the CLI previously filtered lists client-side and gave no signal when a write was overridden by a more specific variant.
Listing now sends
--repo/--env/--branch/--workflowas server job context (notattributesfilters), maps per-variant resolution into JSON and a STATUS table column (active,shadowed,may win), and drops client-side variant filtering so server resolution and pattern matching stay authoritative. The same flow applies tosecrets listandvariables list(variables derive per-row status from group resolution + winner-first ordering).Writes (
set/add/bulk) run bounded follow-up context-aware list probes after success and print a stderr shadow warning with a suggestedlistcommand when the server marks the written variant as lower-priority.API/proto:
CIListSecretVariants/CIListVariableVariantsuseContexton list RPCs; generatedv3beta2bindings addcontext, variant/group resolution, andListSecretAttributes/ListVariableAttributesstubs.Reviewed by Cursor Bugbot for commit 21a4447. Bugbot is set up for automated code reviews on this repo. Configure here.