Uh oh!
There was an error while loading. Please reload this page.
fix(cli): use cobra mutual-exclusivity template in sso add - #5974
Conversation
Coly010
commented
Jul 28, 2026
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:bb94ec7ee8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
…(review: PR #5974) The raw-argv mutex scan and the Effect parser could disagree on which flags pflag would consider set: pflag consumes flag-shaped tokens as values unconditionally, the Effect parser does not. The scan matched pflag for the mutex check, but the handler then acted on the parsed Options — so 'sso add --type saml --project-ref --metadata-file x.xml --metadata-url u' suppressed the mutex yet read the metadata file and POSTed metadata_xml, an API call the Go CLI never makes (Go fails AssertProjectRefIsValid on the consumed value '--metadata-file' in PersistentPreRunE, cmd/root.go:113, before ValidateFlagGroups). Replace the per-flag hasExplicitValueFlag scan with a single pflag-faithful pflagLongFlagOccurrences pass that also yields each flag's effective value(s), and reconcile everything both sso handlers act on (project-ref, metadata-file, metadata-url, attribute-mapping-file, the domain slices, and set-ness of name-id-format/skip-url-validation) to those values. sso update shares the same gap and gets the same fix.
Coly010
commented
Jul 29, 2026
🤖 pr-autopilot needs a human here: this branch now conflicts with |
…2-sso-add-mutual-exclusivity-error-is-not-cobra-format # Conflicts: # apps/cli/src/legacy/commands/sso/update/update.handler.ts
Coly010
commented
Jul 29, 2026
Merged origin/develop (887811b). The one conflict was the domains block in |
Coly010
commented
Jul 29, 2026
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:887811b4e1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…ective argv in sso (review: PR #5974) The pflag reconciliation kept handlers from acting on values pflag never set, but two cobra validations that run before RunE were still invisible to it (Codex review on 887811b): - 'sso add --domains --type saml': pflag hands --type to --domains, so Go fails ValidateRequiredFlags (command.go:1007, required "type" per cmd/sso.go:165) and never POSTs — the TS handler POSTed with domains ["--type"]. - 'sso update --domains --metadata-url u <id>': the consumed token orphans u into the positionals, so Go fails ValidateArgs/ExactArgs(1) (command.go:968, cmd/sso.go:87) before any hook — the TS handler performed the GET and PUT. Evolve the raw-argv scan (pflagLongFlagOccurrences -> pflagArgvScan) into a fuller pflag walk over the closed set of flags the parser can let through: root persistent value flags (cmd/root.go:324-333, incl. the TS-only --output-format), value shorthands (-t/-o per parseSingleShortArg, flag.go:1080-1094), pflag-effective positionals, and consumed long-flag tracking. sso add emulates the required-type check ahead of the mutex block (required beats groups); sso update emulates ExactArgs(1) ahead of the mutex and UUID checks (arity beats both) — binary-verified orderings. Naive per-thread fixes would have regressed '-t saml' and '-o json <id>' / '--workdir . <id>'; the update test that expected ref validation for '--project-ref --metadata-file x.xml ...' now expects the arity error Go actually raises there (x.xml is positional to pflag).
Coly010
commented
Jul 29, 2026
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:25df67c562
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…es, and interspersed flags (review: PR #5974) Three narrow gaps in the pflag-faithful argv scan, all binary-verified against apps/cli-go (Codex review round 3 on 25df67c): - 'sso add --domains -t saml': pflag hands the -t token to --domains, so type is never Changed and Go fails ValidateRequiredFlags — the TS handler POSTed type "saml" with domains ["-t"]. The scan's consumed-token tracking now maps shorthand tokens (-t, -t=saml, -tsaml) to their canonical long names (consumedLongFlagNames -> consumedFlagNames). - 'sso update <id> --domains': pflag fails ParseFlags (cobra command.go:919) with 'flag needs an argument: --domains' (pflag errors.go:75,78 for the 't' in -t shorthand form) before ValidateArgs, every hook, and RunE — the TS handlers performed the GET and PUT / the POST. The scan now reports missingValueError instead of inventing an empty occurrence, and both handlers reject it first (parse beats arity: 'sso update a b --domains' names the missing argument, not the arg count). - 'sso --profile foo update --domains --metadata-url u <id>': cobra's Find/stripFlags routes through persistent flags between path segments and Go still raises 'accepts 1 arg(s), received 2', but the contiguous anchor failed and the TS handler skipped the arity re-count and proceeded. Anchoring now walks argv matching segments while stepping over flag tokens and their consumed values. (The reviewer's original '--project-ref' example cannot reach the handler — the Effect parser rejects leaf flags at the group level — but root globals like --profile/-o reproduce it.) Known shared residual, unchanged from the round-2 arity emulation: Go prints a usage block for errors raised before PersistentPreRunE sets SilenceUsage (cmd/root.go:97), i.e. parse and arity errors; the TS handler-level emulations render the single error line + --debug suggestion only.
Coly010
commented
Jul 29, 2026
@codex review |
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Supabase CLI previewnpx --yes https://pkg.pr.new/supabase/cli/supabase@8213bb0e627a9f766e6d0b7c35e46e5b14052142Preview package for commit |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:e2de9121e1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…tics in sso (review: PR #5974) The round-2 value reconciliation covered sso's string and slice flags but left --skip-url-validation, --name-id-format, and --type on the Effect- parsed values gated on set-ness. Those values can disagree with pflag in two ways, both binary-verified against apps/cli-go (Codex review round 4 on e2de912): - Repeated flags: the Effect parser resolves first-wins, pflag Sets every occurrence so the last wins. 'sso update <id> --skip-url-validation --skip-url-validation=false --metadata-url http://x' skips URL validation in TS but validates (and rejects non-HTTPS) in Go; the mirror argv diverges the other way, and '--domains' consuming one of two --name-id-format occurrences flips which URN lands in the PUT body. - Set-rejected values: pflag aborts ParseFlags on any occurrence its Value.Set rejects, before every hook, validation, and request. The Effect parser accepts yes/no booleans (strconv.ParseBool does not) and never validates the repeats it discards, so '--type saml --type bogus' and '--skip-url-validation=yes' reached the handlers and called the API where Go exits 1 with 'invalid argument ...'. The scan already records every non-consumed occurrence with its raw value, so the fix stays at the established handler-emulation level: two new helpers in sso.pflag-reconcile.ts re-run pflag's per-occurrence Set over the scan output (ParseBool set; enum membership; byte-exact pflag error messages incl. the '-t, --type' shorthand label) and yield the last-occurrence effective values the handlers now act on. Checks sit ahead of the missing-value emulation, matching pflag's sequential walk (an occurrence always precedes a trailing bare flag; binary-verified '--skip-url-validation=yes --domains' names the invalid argument). The shared NAME_ID_FORMATS list is hoisted to sso.saml.ts per the family-root rule. Known residuals unchanged: parse errors raised before Go sets SilenceUsage print cobra's usage block in Go only, and boolean literals ParseBool accepts but the Effect parser rejects (t/T/TRUE/...) still fail at the TS parse layer with the parser's own error.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:07b145b174
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
…2-sso-add-mutual-exclusivity-error-is-not-cobra-format
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:7e21b4aafc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
…flag scan (review: codex) pflag records NoOptDefVal "true" for a bare boolean occurrence and the literal empty string for --flag= (flag.go:1013-1019), then hands "" to strconv.ParseBool, which rejects it. The argv scan conflated the two, so --skip-url-validation=false --skip-url-validation= slipped past the handler as true and issued requests the Go CLI never makes (binary-verified: Go aborts ParseFlags with 'invalid argument "" for "--skip-url-validation" flag' before any request). Record the bare form as "true" in the scan so the bool reconciler fails inline-empty values exactly like Go.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:6fb04b67b7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
… sso add/update (review: codex)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:050108e854
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
…so add/update (review: codex)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:57e608cce1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…ike Go in sso add/update (review: codex) - an undecodable 200 body from the reconciled GET aborts with Go's failed-to-get error before any PUT (update.go:42-45); a 200 without a JSON content type falls into Go's nil-JSON200 gate branch - the reconciled raw GET stitches identity through the shared per-command guard, like Go's identityTransport on every response - the upgrade-gate fallback GETs and the linked-project cache fill target the reconciled profile host (Go's CurrentProfile is process-wide)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:22f27acf90
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:4b9e88f1e1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:8cc1bcc75a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:c4d15a0045
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
…2-sso-add-mutual-exclusivity-error-is-not-cobra-format
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:fbc2bba60c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
kanadgupta
left a comment
There was a problem hiding this comment.
One refactoring suggestion and one stale comment suggestion per Claude otherwise LGTM
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…I-1982) The comment said "Keep this the very first check" but three enum/bool validations already precede the missing-value check. Reworded to describe what it actually precedes, matching update.handler.ts:264's "Keep this ahead of the arity check" phrasing.
Uh oh!
There was an error while loading. Please reload this page.
…988) hasExplicitValueFlag was removed from cobra-flag-groups.ts (#5974), which broke gen types' mutex-flag detection after the develop merge. Migrate onto pflagArgvScan (the sso add/update pattern): a GEN_TYPES_SCAN_SPEC drives the scan, and its occurrences replace every flagChanged(...) call site. This also closes two gaps flagged on the PR: - The mutex scan is now short-flag aware (-s), and no longer ORs against the Effect-parsed boolean flags, which independently mark a flag changed even when pflag would have consumed its token as -s's value. - The postgrest-v9-compat PreRunE gate, the positional-lang guard, and the mutex-group checks now run inside the same Effect.ensuring(telemetryState.flush) block as the rest of the handler, matching Go's PersistentPreRunE-before-PreRunE ordering so a rejected invocation still flushes telemetry.
…LI-1990) (supabase#5978) Batch sweep of the small confirmed edge/cosmetic Go-parity divergences from the 2026-07-24 audit. Every item was re-verified against `apps/cli-go` at current develop before changing anything (audit line numbers were stale); several items turned out to be already fixed or in-flight in other PRs and are listed as such. Fixes CLI-1990 — https://linear.app/supabase/issue/CLI-1990/edgecosmetic-parity-sweep-from-the-2026-07-24-audit-batchable-tail ## Item-by-item | # | Item | Status | Notes | |---|------|--------|-------| | 1 | `functions delete` line colour | **Fixed** | Aqua slug + ref, stdout-gated (`delete.go:20`) | | 2 | `functions deploy` success ref Aqua, `Bundling Function:` bold, `No Functions specified…` bold | **Fixed** | `deploy.go:70,35`, `bundle.go:30`; stdout-gated where stdout-bound | | 3 | Prune bullets ` • <bold>` | **Already fixed** | by supabase#5947 (CLI-1974), commit `c4b45874` | | 4 | serve `supabase start is not running.` Aqua | **Deferred** | open PR supabase#5976 modifies the same `assertLocalDbRunning` hunk in `shared/functions/serve.ts`; one-liner to do after it merges | | 5 | `encryption update-root-key` Finished line + bogus comment | **Fixed** | Aqua'd; comment claimed a nonexistent "render Aqua as plain" convention | | 6 | start rollback missing `Stopping containers...` | **Fixed** | stderr, matching Go's `DockerRemoveAll` writer on the start-failure path (`start.go:77`) | | 7 | `--debug` `Pruned …` reports | **Fixed** | `Pruned containers:/volumes:/network:` (singular network) `[a b c]` on stderr; prune stdout now collected (also removes a latent unread-pipe hazard); `LegacyDebugFlag` threaded through stop/start/rollback | | 8 | Per-retry `Retrying after Ns: <image>` banner | **Fixed** | `4s`/`8s` per Go's `2<<(i+1)` schedule (`docker.go:314`); the failed attempt's error line is played by the already-teed `docker pull` stderr | | 9 | `inspect db blocking` backtick `blocking_statement` | **Fixed** | col 2 only; col 5 (`blocked_statement`) stays bare per Go's format string (`blocking.go:56`) | | 10 | `seed buckets` mutex bracket `[local linked]` | **Fixed** | cobra keeps registration order for the group list and sorts only the "were all set" list; corrected the misleading comment in `legacy-db-target-flags.ts` (storage's `[linked local]` stays correct) | | 11 | `snippets download` 4 UUID forms + lowercase URL | **Fixed** | faithful `uuid.Parse` port incl. the braced-form `s[1:]` quirk; canonical lowercase interpolated into the URL; Go's three error branches verbatim | | 12 | `storage cp --jobs` negative rejection | **Fixed** | pflag's exact uint error (`invalid argument "-1" for "-j, --jobs" flag: strconv.ParseUint: …`), before mutex validation and without telemetry; the documented `0 → 1` clamp stays (Go's 0 deadlocks) | | 13 | `postgres-config` value coercion + `%+v` floats | **Fixed** | exact `ParseBool` case set; int64-overflow → verbatim string; pretty table renders numbers with Go's float64 `%g` (`1000000` → `1e+06`) via hoisted `legacyGoFormatFloat` (also reused by `db query`) | | 14 | init template file modes | **Fixed** | 0644/0755 pinned; the gitignore *append*-branch write is deliberately left unpinned — mode only applies at creation, and supabase#5977 rewrites that exact line | | 15 | login fallback dir 0700→0755 | **Fixed** | Go pins the dir 0755 (`access_token.go:91`); the token file stays 0600, so no secret exposure | | 16 | `test new` 0644 | **Fixed** | + dir 0755, like Go's `utils.WriteFile` | | 17 | `inspect report` 0755/0644 | **Fixed** | | | 18 | bootstrap invalid-stored-token fast-fail | **Deferred** | not small: `resolveLegacyAccessToken` deliberately collapses invalid→`None` for many callers (sso, snippets, postgres-config, …); distinguishing invalid-vs-missing needs a shared-semantics change | | 19 | `migration new` Created line on stdin-copy failure | **Fixed** | mirrors Go's deferred `Println` (`new.go:24-28`); also stdout-gates the Bold path (CLI-1546 class) | | 20 | telemetry state-file recovery | **Fixed** | all-or-nothing decode like Go's `decodeState`; a corrupt file resets `enabled` to true and rotates identity, exactly like Go | | 21 | unlink/services ref-read error | **Fixed (services)** | unlink already matched Go; services now warns `failed to load project ref: …` on a read error and continues unlinked (TOCTOU NotFound stays silent, like Go's `ErrNotLinked` branch) | | 22 | `domains` CNAME dump byte codes | **Kept documented** | premise inaccurate: the non-reproducible part of Go's `%+v` is a runtime *pointer address* for `ValidationErrors`, not byte codes; TS's deterministic rendering is already documented in `domains.format.ts` | | 23 | sso `--domains=` explicit-empty | **Deferred** | `sso update` already matches Go (len-check drops it); the `add` fix touches `sso/add/add.handler.ts`, in-flight in open PR supabase#5974 | | 24 | `db dump --file ""` | **Fixed** | keys off `len > 0` like Go: empty means stdout, no file open, no `Dumped schema to …` line | | 25 | network-restrictions CIDR-before-ref ordering | **Deferred, kept documented** | direction is inverted vs the issue text: TS validates CIDR *before* ref, Go resolves ref first in `PersistentPreRunE`; aligning overlaps open PR supabase#5975 (incl. its integration test file). The `SIDE_EFFECTS.md` note frames this as intended based on an incomplete Go reading — worth revisiting after supabase#5975 | ## Known residuals (deliberate, documented in code) - `postgres-config` digits in `(2^53, 2^63)` still lose precision on the way in (`JSON.stringify` cannot emit exact int64 tokens); Go sends exact integers there. Values beyond int64 now match Go (string fallback). - Colour TTY gating: stderr-bound colour gates on stderr's TTY (per `legacy-colors.ts`/CLI-1546 convention), whereas Go's lipgloss gates everything on stdout. Deliberate, pre-existing convention; only observable when exactly one of stdout/stderr is a TTY. - Bun's `util.styleText` currently ignores `validateStream`/`NO_COLOR` (verified on Bun 1.3.x), so under Bun piped output still carries ANSI for *all* legacy colour sites — a pre-existing runtime gap that predates this PR and deserves its own issue. - The services warning's error suffix is Effect's error text, not Go's `*PathError` bytes — the `failed to load project ref: ` prefix is the parity-bearing part. - `--jobs abc`/`3.5` still surface Effect CLI's parser error rather than pflag's; this PR scopes to negatives (the only case `Flag.integer` accepts that Go rejects). ## Review notes Four-perspective review (architect / engineer / security / DX) run pre-PR; all approve. Engineer fuzz-verified `legacyGoFormatFloat` (23k values) and `legacyParseSnippetUuid` (~8k inputs) byte-identical to Go/google-uuid. Security signed off on the 0700→0755 fallback-dir change (token file unchanged at 0600, matches Go exactly). Remaining findings were the documented residuals above.
…onsumer (review: sso reconciliation ownership) Codex flagged that legacy-pflag-reconcile.ts/legacy-profile-load.ts have only two current consumers (sso add + update), which by AGENTS.md's hoist rule reads as "family root" tier, not shared/. The hoist is intentional: a human reviewer asked for exactly this in #5974's review, on the grounds that the pflag-vs-Effect-parser divergence is CLI-wide, not sso-specific. Recording that link in the source so future readers don't re-litigate it.
…lag builder (CLI-2005) (supabase#6010) ## What changed Follow-up to CLI-1983 (supabase#5975), from kanadgupta's review: the seven remaining hand-rolled pflag `StringSliceVar` call sites still mapped malformed-CSV failures to a bare `err.message`, so their stderr missed pflag's `invalid argument %q for %q flag: ...` framing. All of them now route through the shared `legacyStringSliceFlag` builder (`src/legacy/shared/legacy-string-slice-flag.ts`): - `sso add --domains` - `sso update --domains` / `--add-domains` / `--remove-domains` - `postgres-config update --config` - `postgres-config delete --config` - `start --exclude` / `-x` - `status --override-name` / `--exclude` The builder gains an optional `{ alias }` parameter because `start --exclude` is the one site whose Go counterpart is a `StringSliceVarP` **with a shorthand** (`cmd/start.go:58`): pflag frames such diagnostics with both spellings — `invalid argument %q for "-x, --exclude" flag: ...` (pflag v1.0.10 `errors.go:108-117` branches on `flag.Shorthand`) — regardless of which spelling the user typed, so the alias has to be registered inside the builder for the framing to come out right. `Flag.withDefault([] as ReadonlyArray<string>)` was dropped from the migrated flag definitions: `Flag.atLeast(0)` already yields `[]` when the flag is unset (covered by the existing "defaults to an empty array when unset" unit tests), and `--help` output was verified byte-identical before/after for all six commands. ## Per-site Go parity verification Every rendered line was verified against the Go binary built from `apps/cli-go` (pflag v1.0.10 → `encoding/csv`). All seven sites' malformed-CSV stderr changes user-visibly — from the bare parse-error text to the full pflag line: | Site | Go framing | Example (Go-verified, now byte-matched by TS) | | --- | --- | --- | | `sso add --domains` | `"--domains"` | `invalid argument "a\"b" for "--domains" flag: parse error on line 1, column 2: bare " in non-quoted-field` | | `sso update --domains` | `"--domains"` | same as above | | `sso update --add-domains` | `"--add-domains"` | `invalid argument "\"x" for "--add-domains" flag: parse error on line 1, column 3: extraneous or missing " in quoted-field` | | `sso update --remove-domains` | `"--remove-domains"` | same shape as `--add-domains` | | `postgres-config update --config` | `"--config"` | `invalid argument "a\"b" for "--config" flag: parse error on line 1, column 2: bare " in non-quoted-field` | | `postgres-config delete --config` | `"--config"` | `invalid argument "\"max_connections" for "--config" flag: parse error on line 1, column 17: extraneous or missing " in quoted-field` | | `start --exclude` / `-x` | **`"-x, --exclude"`** | `invalid argument "a\"b" for "-x, --exclude" flag: parse error on line 1, column 2: bare " in non-quoted-field` | | `status --override-name` | `"--override-name"` | `invalid argument "\"api.url=FOO" for "--override-name" flag: parse error on line 1, column 13: extraneous or missing " in quoted-field` | | `status --exclude` | `"--exclude"` | `invalid argument "a\"b" for "--exclude" flag: parse error on line 1, column 2: bare " in non-quoted-field` | For `postgres-config`, the parse error also correctly precedes the `--experimental` gate (cobra parses flags before `PersistentPreRunE`), asserted in the experimental-gate integration suite. ## Multiline / blank-line semantics findings CLI-1983's parser rewrite changed `legacyParseStringSliceFlag` itself, so all seven sibling sites silently inherited the first-record-only / EOF-on-blank semantics. I verified each site against the Go binary: - **First-record-only**: `--<flag> $'a\nb"c'` raises **no** parse error in Go at any of the seven sites (pflag calls `csv.Reader.Read()` once; the malformed second line is silently dropped). Observable proof for `start`: `start -x $'a\nb"c'` warns `The following container names are not valid to exclude: a` — only the first record survives. TS matches. - **Blank-only → EOF**: `--<flag> $'\n'` fails in Go with `invalid argument "\n" for "--<flag>" flag: EOF` at every site (with the `-x, --exclude` framing on `start`). TS matches. - **No sibling site's existing tests asserted stale pre-rewrite behaviour** — they simply had no multiline/blank-only coverage at all, and their malformed-CSV tests only asserted `Exit.isFailure` without the message. This PR adds exact-message assertions per flag plus first-record-only and blank-only-EOF vectors per site. ## Test coverage added - Per-site unit tests: exact pflag-framed diagnostics (including the shorthand framing for `start`), first-record-only multiline vectors, blank-only EOF vectors. - Per-family integration tests running the whole command tree (`Command.runWith`) and asserting the exact rendered message via `normalizeCause`, mirroring the network-bans/network-restrictions prior art from CLI-1983: new `sso.string-slice-flags.integration.test.ts`, `start.string-slice-flags.integration.test.ts`, `status.string-slice-flags.integration.test.ts`, plus malformed-CSV cases in the existing `postgres-config.experimental-gate.integration.test.ts`. - `start`'s `--exclude` flag is hoisted to an exported `legacyStartExcludeFlag` (mirroring `status`/`sso` conventions) so it is unit-testable. - SIDE_EFFECTS.md for all six commands gains the parse-time failure exit-code row (mirroring CLI-1983's doc updates). - Stale comments referencing the deleted `csvStringSliceFlag` helper in `legacy-db-target-flags.ts`/`.unit.test.ts` were updated; all helper-built flag names remain hand-registered in `VALUE_CONSUMING_LONG_FLAGS`, so telemetry argv parsing is unaffected. ## Overlap note: PR supabase#5974 Open PR supabase#5974 (`columferry/cli-1982-...`) touches sso command files (`sso.pflag-reconcile.ts`, add/update handlers). This PR's sso changes are deliberately minimal — the flag definition blocks in `add.command.ts`/`update.command.ts`, their unit tests, one new family-level integration test file, and one SIDE_EFFECTS.md row. Whoever merges second should re-verify the sso flag definitions still route through `legacyStringSliceFlag` after conflict resolution. ## Review notes (deliberately left open) - The `--schema` slice-flag family (`gen types`, `db lint/dump/pull/diff`, `db schema declarative generate`) still uses the hand-rolled `Flag.mapTryCatch(legacyParseSchemaFlags, err => err.message)` pattern via `legacy-schema-flags.ts`. It is not in CLI-2005's scope (and several of those are `StringSliceVarP` with `-s` shorthands needing their own per-site Go verification) — candidate for a follow-up issue. - The pathological double-error case (`-o bad` plus malformed CSV in one invocation): TS surfaces the CSV parse error while Go's winner depends on argv order; both exit non-zero. Same accepted approximation as CLI-1983, already documented on the network-bans/network-restrictions flag comments. - `cli-go:lint:check` fails with 5 pre-existing gosec findings unrelated to this change (no Go files touched). Fixes CLI-2005
…er (CLI-1982) (supabase#6040) ## What kind of change does this PR introduce? Refactor — pure move + rename, zero behavior change. ## What is the current behavior? `sso.pflag-reconcile.ts` and `sso.load-profile.ts` (added in supabase#5974 to reconcile pflag/viper-vs-Effect-parser divergence for `--profile`/`--workdir`/bool/enum flags, and to emulate Go's `LoadProfile`) live under the sso-specific command directory and are coupled to two sso-specific error types (`LegacySsoWorkdirError`, `LegacySsoProfileError`), even though every function in them is already generic. This was flagged in [supabase#5974's review](supabase#5974 (comment)): the logic doesn't scale to future command families that need the same pflag-vs-Effect-parser reconciliation. ## What is the new behavior? - Moved `sso.pflag-reconcile.ts` → `apps/cli/src/legacy/shared/legacy-pflag-reconcile.ts`, and `sso.load-profile.ts` → `apps/cli/src/legacy/shared/legacy-profile-load.ts` (plus their unit tests). - Renamed every export to drop the `Sso` infix (e.g. `legacySsoResolvePflagProfile` → `legacyResolvePflagProfile`). - Replaced `LegacySsoWorkdirError`/`LegacySsoProfileError` with new generic `LegacyPflagWorkdirError`/`LegacyProfileLoadError`, deleting the two sso-specific classes from `sso.errors.ts` with no compatibility shims. - Updated `sso add`/`sso update` handlers and their tests/SIDE_EFFECTS docs to the new location. All doc comments documenting binary-verified Go-parity behavior (across many supabase#5974 review rounds) are preserved verbatim. This is a follow-through on a review suggestion that was originally deferred to a follow-up ticket — implementing it directly instead.
What changed
sso addemitted a hand-written mutual-exclusivity error (only one of --metadata-file or --metadata-url may be set) and detected the conflict viaOption.isSomeon parsed flag values. The Go CLI enforces this group via cobra'sMarkFlagsMutuallyExclusive("metadata-file", "metadata-url")(apps/cli-go/cmd/sso.go:164), whose error template is:sso updatewas already migrated to the sharedcobraMutuallyExclusiveErrorMessagehelper plus raw-argvpflag.Changed-semantics detection (CLI-1902);addwas never migrated. This PR mirrors update's pattern inadd.handler.ts:cobraMutuallyExclusiveErrorMessage(group in Go's registration order; the violating subset sorted, per cobra'svalidateExclusiveFlagGroups).hasExplicitValueFlagraw-argv scan, so an explicit empty value (--metadata-file= --metadata-url x) still trips the mutex, while a bare--metadata-file --metadata-url(pflag consuming the second token as the first flag's value) correctly does not.ValidateFlagGroups-before-RunEprecedence.Integration tests cover the exact-message case (byte-match), the explicit-empty
--metadata-file=case, the consumed-value non-violation case, and single-flag happy paths.SIDE_EFFECTS.mdnow documents the cobra template andChangedsemantics.Review findings deliberately left open
A four-perspective review pass (architect / engineer / security / DX) approved the change; these pre-existing, cross-cutting observations were noted rather than fixed here:
sso addandsso update— a family-root helper (e.g.sso.mutex.ts) is a reasonable follow-up.SSO_ADD_VALUE_FLAG_NAMES(like update's equivalent) is a hand-maintained mirror of the command's declared value flags with no compile-time sync guarantee.sso update.-tshorthand — documented limitation shared withsso update; pflag fails-t's enum validation before flag groups anyway.--domains=explicit-empty edge onadd(parity audit §3.10) is a separate issue and is not addressed here.Fixes CLI-1982
https://linear.app/supabase/issue/CLI-1982/sso-add-mutual-exclusivity-error-is-not-cobra-format