Skip to content

feat(cli): add feedback add and delete commands for quick CLI feedback - #5988

Open
kanadgupta wants to merge 43 commits into
developfrom
kanad-claude-2026-07-22/feedback-command
Open

feat(cli): add feedback add and delete commands for quick CLI feedback#5988
kanadgupta wants to merge 43 commits into
developfrom
kanad-claude-2026-07-22/feedback-command

Conversation

@kanadgupta

@kanadgupta kanadgupta commented Jul 29, 2026

Copy link
Copy Markdown
Member

What

Adds a TS-only supabase feedback command family (from the original brainstorm) to the legacy shell so users — and agents — can send quick, low-friction feedback to the Supabase team without filing a GitHub issue, and revoke a submission later (e.g. an accidentally pasted secret):

supabase feedback add "when I run multiple stacks in parallel I get port conflicts"
# → Thanks for the feedback!
# → To delete this feedback later, run: supabase feedback delete <token>

supabase feedback delete 123e4567-e89b-12d3-a456-426614174000

Part of CLI-1946; the delete command is CLI-2188. Scope evolved in this thread: feedback add (no btw alias) plus a token-based delete path, rather than full user-scoped CRUD.

How feedback add works

  • Message resolution: positional args → piped stdin (non-TTY) → interactive prompt (TTY, text mode) → error. Messages starting with a dash use the -- sentinel.
  • Transport: submits through the SECURITY DEFINER RPC submit_interfaces_feedback (feat: table for collecting interfaces feedback supabase#48420) via supabase-js — the table has no insert grant, so the RPC is the only door and the delete token is always server-generated. The committed key is a publishable (anon) key, safe to ship in the binary. 10s timeout.
  • Delete token: the RPC returns a uuid delete_token exactly once. Text mode prints it with a "to delete this later" hint; json/stream-json carry it as delete_token in the result payload. The CLI never persists it.
  • Submission context: CLI version, user agent, OS/arch, agent detection (is_agent/agent_name via @vercel/detect-agent, to support the activation analysis in AI-961), and the linked project ref. metadata.source: "cli" distinguishes CLI rows from the future MCP path. The access token is never sent; user_id is never sent.
  • Project ref resolution: SUPABASE_PROJECT_ID<workdir>/supabase/.temp/project-ref (the file supabase link writes) → omitted. Reads the file directly (not via LegacyProjectRefResolver, whose prompt path needs the platform API) so feedback works logged-out; a broken ref file degrades to "unlinked".
  • Environments: the feedback backend follows the resolved profile the same way the Management API URL does (staging profiles → staging project). Production intentionally reuses the staging project until a dedicated one is provisioned (tracked in CLI-1998).

How feedback delete <token> works

  • Validation: the token must be a UUID (checked client-side to avoid PostgREST's cryptic uuid-cast error) and is lowercased before sending.
  • Preview first: a token-scoped read shows the feedback text before anything is deleted, so the user can verify what the token unlocks. Zero rows → a friendly not-found error covering all three indistinguishable causes (wrong token, already deleted, project-ref context mismatch).
  • Confirmation: interactive text mode prompts (Permanently delete this feedback? [y/N]); --yes/SUPABASE_YES skips it. Machine modes (json/stream-json) fail loudly without --yes rather than deleting silently — same contract as logout.
  • Deletion: a hard DELETE with Prefer: count=exact; the CLI verifies Content-Range reports exactly one row. Authorization is the x-feedback-token request header matched by RLS — the delete_token=eq. URL filter only satisfies PostgREST's filterless-delete rejection.
  • Context gate: rows submitted from a linked project also require the matching x-feedback-project-ref header. The delete command resolves the ref as --project-refSUPABASE_PROJECT_ID → linked-ref file and always sends whatever resolves (extra context against a context-free row is ignored server-side).
  • Machine modes return the deleted text in the result payload: { "feedback": "...", "message": "Feedback deleted." }.

Privacy note for reviewers

The feedback message, the delete token, and the --project-ref value go only to the feedback backend — never to PostHog. Message and token are positional arguments, which extractChangedFlagNames structurally excludes from the flags telemetry property; --project-ref is recorded by name only with its value redacted. Regression tests assert none of them appear in captured analytics events.

Reviewer-relevant context

  • The shared service was reshaped from FeedbackSubmitter (insert-only) into FeedbackClient (submit/preview/delete) in src/shared/feedback/feedback-client.{service,layer}.ts, and the profile→environment mapping and cli-config layer wiring were hoisted to the feedback family root (feedback.layers.ts, feedback-project-ref.ts) now that two commands share them.
  • src/shared/feedback/database.types.ts is generated (supabase gen types) and excluded from formatting/knip.
  • The e2e golden path is one combined add → delete round trip against the staging project (pinned --profile supabase-staging), which also cleans up its own row each run.
  • postgrest-js silently retries idempotent GETs (the preview) up to 3× with backoff on network errors; mutations and the RPC don't retry. It settles fine — noted because supabase-js exposes no way to disable it.
  • The merge from develop picked up the CLI-1970 docs restructure: the feedback commands are recorded in docs/go-cli-divergences.md (TS-only section) and registered in legacy-docs-spec.tables.ts (other-commands tag) instead of the old porting-status tracker.
  • Heads-up on LegacyCliConfig.projectId: it is a bare SUPABASE_PROJECT_ID env passthrough — it does not read config.toml or the linked-project file, so it is None in a linked project unless that env var is set. An earlier revision of this branch used it directly as "the linked project ref", which meant project_ref was always null in practice. The AGENTS.md row that described it as resolving project-id from config.toml is corrected here, since that phrasing is what made the field look project-aware.
  • services.integration.test.ts now uses an isolated temp workdir instead of process.cwd(), fixing machine-dependent behavior when the developer has local supabase start state.

🤖 Generated with Claude Code

kanadgupta and others added 10 commits July 28, 2026 08:17
The vendored effect clone in .repos/ drowns out workspace results in
editor-wide search.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
LegacyCliConfig.projectId is a bare SUPABASE_PROJECT_ID env passthrough, so
the feedback submission's project_ref was null in a linked project unless
that env var happened to be set. Fall back to <workdir>/supabase/.temp/
project-ref, the file supabase link writes, mirroring the soft-load half of
LegacyProjectRefResolver.resolveOptional. The file is read directly rather
than through the resolver so the command keeps working unauthenticated; a
broken ref file degrades to unlinked instead of failing the submission.

The previous integration test injected projectId straight into the config
mock, so it only proved the handler forwarded the field and never exercised
resolution -- despite being named for the workdir-linked scenario that did
not work. Replace it with coverage that seeds the real file, plus env
precedence, unlinked, and unreadable-file cases.

Also correct the AGENTS.md row claiming LegacyCliConfig reads project-id
from config.toml, which is what made this field look project-aware.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kanadgupta
kanadgupta marked this pull request as ready for review July 29, 2026 05:25
@kanadgupta
kanadgupta requested a review from a team as a code owner July 29, 2026 05:25
@kanadgupta
kanadgupta requested review from gregnr and mattrossman July 29, 2026 05:28

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 656f13a667

ℹ️ 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".

Comment thread apps/cli/src/legacy/commands/feedback/feedback.e2e.test.ts Outdated
Comment thread apps/cli/src/legacy/commands/feedback/add/add.handler.ts
@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Supabase CLI preview

npx --yes https://pkg.pr.new/supabase/cli/supabase@f2529331d4b8f0358f79a4e094ffcd9959d52bb2

Preview package for commit f252933.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 830e565f2a

ℹ️ 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".

Comment thread apps/cli/src/legacy/commands/feedback/add/add.handler.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ae5d202bd6

ℹ️ 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".

Comment thread apps/cli/src/legacy/commands/feedback/feedback.handler.ts Outdated
Comment thread apps/cli/src/shared/feedback/feedback-submitter.layer.ts Outdated
Comment thread apps/cli/src/legacy/commands/feedback/add/add.handler.ts Outdated
…alias

Restructures the TS-only feedback command from a single `supabase feedback`
command (with a `btw` alias) into a `feedback` group with an `add`
subcommand, following the nested-subcommand layout. Telemetry now records
`command: "feedback add"`; behavior is otherwise unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kanadgupta kanadgupta changed the title feat(cli): add feedback command for quick CLI feedback submission feat(cli): add feedback add command for quick CLI feedback submission Aug 13, 2026
…07-22/feedback-command

# Conflicts:
#	apps/cli/src/legacy/commands/functions/delete/delete.integration.test.ts
#	apps/cli/src/legacy/commands/functions/download/download.integration.test.ts
#	apps/cli/src/legacy/telemetry/legacy-command-instrumentation.unit.test.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4ca265f84d

ℹ️ 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".

Comment thread apps/cli/src/shared/feedback/feedback-submitter.layer.ts Outdated
@kanadgupta
kanadgupta marked this pull request as draft August 13, 2026 18:09
Comment on lines +21 to +28
const FEEDBACK_STAGING: FeedbackEnvironment = {
url: "https://imrwaufzgcaczqmpnxyr.supabase.co",
key: "sb_publishable_puOyAlqG5J_XfBMTDM2Ckw_L5mieFdb",
};

// No dedicated production feedback project exists yet (CLI-1946): production
// intentionally reuses the staging values until one is provisioned.
const FEEDBACK_PRODUCTION: FeedbackEnvironment = { ...FEEDBACK_STAGING };

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note to self: update these values once CLI-1999 and CLI-1998 are complete

@kanadgupta
kanadgupta marked this pull request as ready for review August 19, 2026 00:03

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8a427eb17

ℹ️ 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".

Comment thread apps/cli/src/legacy/commands/feedback/feedback.layers.ts Outdated
Comment thread apps/cli/src/legacy/commands/feedback/add/add.live.test.ts Outdated
@kanadgupta
kanadgupta marked this pull request as draft August 19, 2026 00:20
@kanadgupta
kanadgupta marked this pull request as ready for review August 19, 2026 00:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8a427eb17

ℹ️ 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".

Comment thread apps/cli/src/legacy/commands/feedback/feedback.layers.ts Outdated

@avallete avallete left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing to fix before merge (the open Codex P1 on debug URLs, commented on that thread), one doc fix (PR description still says user_id is never sent), and a couple of non-blocking notes inline.

the PR description says "The access token is never sent; user_id is never sent", but the current code sends the consent-gated gotrue UUID as user_id (add.handler.ts:91), and SIDE_EFFECTS.md documents that correctly. Since the description is what privacy sign-off reads, could you update that bullet to match?

Comment thread apps/cli/src/legacy/commands/feedback/feedback.layers.ts Outdated
Comment thread apps/cli/src/legacy/commands/feedback/feedback.layers.ts Outdated
Comment thread apps/cli/src/legacy/commands/feedback/add/add.live.test.ts Outdated
Comment thread apps/cli/src/legacy/commands/feedback/add/add.command.ts
kanadgupta and others added 4 commits August 19, 2026 16:36
supabase-js passes init.headers as a Headers instance; spreading one into a
plain object yields zero entries, so the DoH rewrite dropped apikey,
content-type, and x-feedback-token on every feedback request. Rebuild through
the Headers constructor (which accepts records, Headers, and entry arrays)
and cover the Request-embedded case. The Management API path (Effect's
FetchHttpClient) passes a plain record and is byte-identical before/after.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The preview/delete URLs carry the row's capability token as a
delete_token=eq.<uuid> PostgREST filter; the --debug logger wrote that URL
verbatim to stderr, leaking read/delete authority into terminal recordings
and shared debug output. Redact the query-param value in the logged line
only — the transport still receives the original URL.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 1000-character limit was documented but only enforced server-side, so an
over-limit message surfaced as a raw PostgREST error classified
externalNetwork — a user mistake counted as a backend failure in the
actionability KPIs. Mirror the check client-side (invalidInput, no request
sent), counted in code points to match Postgres char_length. Same pattern as
feedback delete's client-side UUID pre-validation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The staging row was only deleted as a sequential test step, so an assertion
failure between the add and the delete leaked it. Capture the token before
asserting and run a best-effort exact-token delete in finally — inert when
the round trip already removed the row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
let request = client
.from("interfaces_feedback")
.select("feedback")
.eq("delete_token", token)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Severity: MEDIUM

The delete token is a bearer capability, but it is placed in the PostgREST query string for both preview and deletion. Although the debug wrapper redacts it, HTTPS intermediaries, gateway access logs, tracing, or server request logs can retain delete_token=eq.<token>; anyone obtaining such a log can read and delete the feedback.
Helpful? Add 👍 / 👎

💡 Fix Suggestion

Suggestion: The delete_token is being exposed in URL query parameters (?delete_token=eq.<token>) for both the preview (SELECT) and delete (DELETE) operations, which can be retained in HTTP access logs, proxy logs, CDN/gateway traces, etc.

There are two recommended mitigations:

  1. For the preview (SELECT at line 137): Since RLS already gates row visibility via the x-feedback-token request header (as documented in the file header), the .eq("delete_token", token) URL filter is redundant for authorization. It can be removed from the SELECT query — RLS will correctly limit results to the authorized row via the header alone, keeping the token out of the URL query string.

  2. For the delete (DELETE at line 159): PostgREST's filterless-delete protection prevents removing the .eq() filter. The cleanest solution is to expose a server-side RPC (e.g., delete_interfaces_feedback(token uuid)) analogous to the existing submit_interfaces_feedback RPC already used at line 118. Calling it via client.rpc("delete_interfaces_feedback", { token }) sends the token in the POST request body rather than the URL, eliminating log exposure. If a new RPC is not feasible, consider using a non-sensitive row identifier (e.g., a surrogate primary key returned during submission) as the URL filter for DELETE, keeping the x-feedback-token header as the actual authorization mechanism.

Comment thread apps/cli/src/legacy/commands/feedback/feedback-project-ref.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 129e3d627a

ℹ️ 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".

Comment thread apps/cli/docs/go-cli-divergences.md Outdated
Comment thread apps/cli/src/legacy/commands/feedback/add/SIDE_EFFECTS.md Outdated
Comment thread apps/cli/src/legacy/commands/feedback/add/add.handler.ts Outdated
Comment thread apps/cli/src/legacy/commands/feedback/add/add.handler.ts Outdated
Comment thread apps/cli/src/legacy/commands/feedback/delete/delete.handler.ts
kanadgupta and others added 6 commits August 20, 2026 12:51
The workdir can be an untrusted checkout where supabase/.temp/project-ref is
a symlink to a local secret; the resolver forwarded the raw file contents as
project_ref to the feedback backend. Filter both the env/flag override and
the file contents through PROJECT_REF_PATTERN — the same boundary
legacyResolveSoftLinkedRef applies — degrading anything malformed to
"unlinked".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
output.interactive is stdout-derived and clack's confirm answers on a single
y/n keypress from any stdin, so `printf 'y' | feedback delete <token>` with a
TTY stdout could confirm a permanent delete without --yes. Gate the prompt on
both streams being TTYs and fail with NonInteractiveError otherwise — the
behavior SIDE_EFFECTS.md already documented, and the same gate the add prompt
uses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
go-cli-divergences.md is a frozen historical record that no longer
accumulates entries; the feedback commands are new CLI behavior documented
through help text, tests, and their SIDE_EFFECTS.md files. The rows predate
the ledger freeze.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The SIDE_EFFECTS notes and -o enum comments framed behavior around Go parity
("no Go counterpart", "Go-compat -o json", "no Go struct"); the TS shell is
the source of truth, so describe the behavior directly. No functional change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tapError skips the interrupt path and the sequential clear() never runs, so
Ctrl-C mid-request left the delayed clack spinner (or its pending start
timer) running while shutdown finalizers executed. Wrap the three request
tasks in an onExit-based settle helper: cleared on success and interruption,
failed on a typed failure.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
readPipedText collects the entire stream before the 1000-character check ran,
so piping a huge file consumed unbounded memory before failing. Read piped
stdin through pipedBytesStream with a 64 KB cap — 16x the limit's worst-case
UTF-8 size, so trim-then-count semantics are unchanged for plausible input —
and fail as over-limit once the cap is crossed without consuming further.

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3c41e19d54

ℹ️ 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".

get [ErrorActionabilityId](): CliErrorActionabilityDeclaration {
// Both branches (PostgREST rejection, network failure/timeout) are
// failures of the external feedback backend, not user mistakes.
return actionability.externalNetwork;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Distinguish backend responses from transport failures

When PostgREST returns a structured HTTP error—for example, an RPC permission rejection or validation failure—run creates this same error class, and this getter records it as externalNetwork just like a timeout or failed fetch. That misclassifies backend/API-status failures as network outages in KPI telemetry; carry a typed failure reason or status from run and select apiStatus for response errors while retaining externalNetwork for transport failures.

AGENTS.md reference: apps/cli/AGENTS.md:L373-L388

Useful? React with 👍 / 👎.

Comment on lines +106 to +108
const confirmed = yield* output.promptConfirm("Permanently delete this feedback?", {
defaultValue: false,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep legacy JSON confirmation output payload-only

When feedback delete <token> -o json runs in a TTY without --yes, the legacy flag leaves output.format === "text", and the quiet-progress wrapper still delegates this Clack prompt, which writes ANSI and prompt text to stdout before the handler emits the raw JSON payload. PTY-based automation therefore cannot parse stdout; the add command has the same problem when -o json reaches its missing-message prompt. Fresh evidence after the earlier payload fix is that both prompts still execute before the goFmt output branch; require noninteractive inputs/--yes for legacy machine mode or render these prompts to stderr.

AGENTS.md reference: apps/cli/AGENTS.md:L442-L450

Useful? React with 👍 / 👎.

return total <= LEGACY_FEEDBACK_PIPE_CAP_BYTES;
}),
),
Effect.catchTag("PlatformError", () => Effect.succeed(undefined)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not submit a partial pipe after a read failure

When piped stdin yields one or more chunks and then fails with PlatformError, this catch converts the stream failure to success but leaves the already buffered parts intact, so the command silently submits the truncated prefix as the user's feedback. Fresh evidence after the bounded-reader fix is that pipedBytesStream intentionally propagates read errors while this consumer resumes from partial state; either discard all buffered input and follow the empty-input path or map the read failure to a typed CLI error instead of sending corrupted feedback.

AGENTS.md reference: AGENTS.md:L64-L68

Useful? React with 👍 / 👎.

…07-22/feedback-command

Conflict resolutions and merge fallout:
- apps/cli/package.json: kept develop's turbo-based test scripts and root-level
  tooling (per-package knip/nx blocks dropped); preserved the branch's
  gen:feedback-types script.
- knip.json / .oxlintrc.json: carried the branch's ignore for the generated
  src/shared/feedback/database.types.ts into develop's root configs.
- apps/cli/AGENTS.md: kept the branch's enriched legacy-infrastructure table
  with develop's LegacyCliConfig -> LegacyCliSettings rename applied (verified
  against the merged sources: projectId remains a bare SUPABASE_PROJECT_ID
  passthrough).
- Renamed LegacyCliConfig -> LegacyCliSettings across the feedback command
  (code, tests, SIDE_EFFECTS.md) to match develop's rename.
- Ported add.live.test.ts to develop's fixture-based live helper (test/cli
  from tests/helpers/live.ts), keeping the --profile supabase-staging pin.
- pnpm-lock.yaml: took develop's side and regenerated with pnpm install.

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: de7f7372e3

ℹ️ 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".

Comment on lines +49 to +53
const dohFetch = legacyDohFetch({
dnsResolver,
innerFetch: options.innerFetch,
resolver: options.resolver,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Cancel DoH resolution with feedback requests

When --dns-resolver https is active and Ctrl-C or the 10-second timeout fires during DNS resolution, this transport starts legacyDohFetch, whose Effect.runPromise(resolver(host)) does not observe the request's abort signal; cancellation can therefore leave the resolver request running in the background and holding the process open until it settles. Fresh evidence beyond the earlier native-transport abort fix is that the newly wired DoH path only forwards the signal to the inner fetch after resolution completes; thread that signal through the resolver so the whole feedback request is cancelled.

AGENTS.md reference: AGENTS.md:L92-L96

Useful? React with 👍 / 👎.

}
yield* output.success("Thanks for the feedback!");
yield* output.info(
`To delete this feedback later, run: supabase feedback delete ${deleteToken}`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the project ref in the deletion command

When feedback is submitted from a linked project, the backend requires the same project ref on preview and deletion, but this advertised command contains only the token. Copying it after leaving that checkout therefore resolves no matching ref and reports that the feedback was not found; include --project-ref when projectRef is present so the one-time receipt remains usable later.

Useful? React with 👍 / 👎.

// Suppressed under `-o json` as well: stdout must stay payload-only, and
// the payload already carries the feedback text.
if (goFmt !== "json" && output.format === "text") {
yield* output.info(`Found feedback: "${feedbackText}"`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Escape terminal controls in previewed feedback

When the stored feedback contains ANSI or OSC control sequences—for example, a malicious submitter gives another user its deletion token—this writes the backend-controlled text directly through Clack in text mode. Those bytes are interpreted by the terminal and can forge the confirmation display or modify terminal state such as the clipboard; strip or visibly escape control characters before rendering the human-readable preview while leaving structured JSON encoding unchanged.

Useful? React with 👍 / 👎.

Comment on lines +56 to +59
const projectRef = yield* legacyResolveFeedbackProjectRef(
cliSettings.workdir,
Option.orElse(args.projectRef, () => cliSettings.projectId),
).pipe(Effect.map(Option.getOrUndefined));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject an invalid explicit project ref

When --project-ref is malformed, Option.orElse selects it before validation, then legacyResolveFeedbackProjectRef silently discards it and falls through directly to the linked-ref file instead of reporting invalid input or trying SUPABASE_PROJECT_ID. In a checkout linked to another project this sends an unrelated context header and returns the misleading not-found error even though the user supplied the intended override; validate the explicit flag with the standard typed project-ref error before entering the soft fallback path.

AGENTS.md reference: AGENTS.md:L171-L175

Useful? React with 👍 / 👎.

Comment on lines +145 to +146
userId:
telemetryRuntime.consent === "granted" ? telemetryRuntime.identity.current() : undefined,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Severity: MEDIUM

The submit path sends the persisted GoTrue UUID as user_id whenever telemetry consent is granted, alongside free-form feedback that may contain secrets or other sensitive data. This creates an account-to-content record in the feedback backend, contradicting the PR’s stated guarantee that user_id is never sent and expanding identity exposure.
Helpful? Add 👍 / 👎

💡 Fix Suggestion

Suggestion: Remove the conditional that sends the GoTrue UUID as user_id. To honor the PR's stated privacy guarantee that user_id is never sent, replace the conditional expression with undefined unconditionally. This prevents any account identifier from being linked to free-form feedback submissions, regardless of telemetry consent status.

⚠️ Experimental Feature: This code suggestion is automatically generated. Please review carefully.

Suggested change
userId:
telemetryRuntime.consent === "granted" ? telemetryRuntime.identity.current() : undefined,
userId: undefined,

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