fix(github): give internal-error PR comments a fixed sentence and an error reference - #768
fix(github): give internal-error PR comments a fixed sentence and an error reference#768aparajon wants to merge 9 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens SchemaBot’s GitHub PR-comment surfaces by preventing raw internal error strings (storage, GitHub API, transport, panic values) from being rendered verbatim, replacing them with fixed, user-safe summaries that point operators to server logs while preserving actionable, intentionally-authored user messages.
Changes:
- Introduces shared helpers to map errors into either (a) fixed “see server logs” PR-safe text for internal failures or (b) whitelisted user-authored messages for actionable cases.
- Updates webhook command paths (plan/apply/unlock/control/rollback/review gate/prior-env checks/panic recovery) to use the new rendering behavior.
- Adjusts and expands tests to assert that raw error text no longer appears in PR comments while preserving expected guidance and retry UX.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pkg/webhook/unlock_test.go | Updates unlock comment assertions to require log-pointer wording and forbid raw storage error text. |
| pkg/webhook/templates/apply_test.go | Updates template tests to ensure GitHub API errors don’t render raw and prior-env blocks point to logs. |
| pkg/webhook/templates/apply_commands.go | Stops rendering raw GitHub error details in apply-blocked templates; replaces with log-pointer text. |
| pkg/webhook/schema_reconciliation.go | Adds typed closed-PR rejection for check-refresh flows and maps other failures to internal log-pointer text. |
| pkg/webhook/rollback.go | Converts multiple rollback failure comment paths to PR-safe internal error summaries while keeping guardrail rejections user-visible. |
| pkg/webhook/review_gate.go | Replaces raw review-gate error rendering with internal log-pointer text plus actionable permission guidance where applicable. |
| pkg/webhook/review_gate_test.go | Adjusts review gate tests to assert raw errors aren’t rendered and log-pointer wording is present. |
| pkg/webhook/plan.go | Converts internal failures to PR-safe summaries; uses stricter schema-request error rendering in multi-env plan flow and avoids silent failures. |
| pkg/webhook/plan_test.go | Updates tests for remote-unavailable guidance to ensure raw gRPC text isn’t rendered. |
| pkg/webhook/handler.go | Changes panic recovery comments to avoid printing panic values; records recovered panic metric. |
| pkg/webhook/handler_test.go | Updates panic recovery test to ensure panic value isn’t rendered and log-pointer wording is present. |
| pkg/webhook/error_comment.go | Adds internalErrorDetail and error-mapping helpers; removes raw remote transport error rendering from PR surfaces. |
| pkg/webhook/error_comment_test.go | Adds/updates tests for internal error detail, mapped user-facing errors, schema-request mapping, and control-command error rendering. |
| pkg/webhook/control.go | Routes control-command failures through a detail-mapper to avoid rendering raw internal failures on PRs while preserving user-actionable rejections. |
| pkg/webhook/check_prior_env.go | Updates prior-environment apply-blocked comments to avoid rendering raw storage/GitHub errors. |
| pkg/webhook/check_prior_env_test.go | Updates fail-closed prior-env tests to assert log-pointer wording and forbid raw storage error text. |
| pkg/webhook/check_aggregate.go | Introduces environmentConfigError to mark safe-to-render configuration/discovery messages while preserving typed causes in the error chain. |
| pkg/webhook/apply_handlers.go | Converts many apply/apply-confirm/unlock internal failure comment paths to PR-safe log-pointer summaries; adds unlock database inference error mapping. |
| pkg/webhook/apply_execute.go | Converts apply confirm-time plan failure rendering to user-facing mapping and hides raw status-check update errors. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
🤖 Review findings - created by Kiran's code review agent - for pull/768, d0228cf. Verdict: 8 findings — 4 blocking (an allowlist regression, a raw-error leak on the new control path, merge conflicts with main, a mislabeled metric), 4 non-blocking. The core sanitization sweep is real and well-tested; the blockers are all small fixes plus one careful rebase. Blocking
Non-blocking
General suggestions
The one thing that could have broken, verifiedThe fail-closed direction: a suppression allowlist this broad could easily swallow authored, user-actionable messages wholesale. Verified it mostly doesn't: every wrap layer of the allowlisted config sentinels composes SchemaBot-authored text plus identifiers only (no GitHub response bodies ahead of the sentinel); Verified correct
This review was generated by Claude Code (claude-fable-5). |
Command-failure comments rendered raw error text from storage reads, GitHub API calls, lock bookkeeping, transport failures, and recovered panics. That text can carry hostnames, dial targets, DSN fragments, and driver internals that do not belong on a public PR, and it can break comment markdown. Internal failures now render a fixed summary plus a pointer at the server logs, where every site already logs the raw error with triage identifiers. Messages authored for PR display keep rendering: engine plan/apply errors (rejected DDL), control-command guardrail rejections, configuration and discovery errors (including the closed-PR check refresh rejection and truncated-tree fail-closed error, both now typed or whitelisted), and the fixed remote-unavailable guidance — which no longer embeds the raw dial error. Recovered webhook panics post a fixed message and record the recovered-panic metric. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…error references "See SchemaBot server logs for details" told users to look somewhere they cannot reach. Internal-error comments now say the failure is SchemaBot's fault (not the schema change), tell the user to retry, and render a short error reference that is logged (error_ref) on the same line as the raw error, so a user report maps to the exact server-side failure. Sites where the command was already accepted omit the retry guidance, and the remote-unavailable copy ends with contact-your-operators guidance. Also hardens userFacingErrorDetail per review: raw transport fingerprints are re-rendered before any pass-through, so a detail mixing formatted guidance with raw error text can no longer leak through. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Internal SchemaBot error — retry. If it keeps failing, report error reference `<ref>`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The generic-error, review-gate-error, prior-env-check-error, and check-status-error previews now render the internal-error guidance with a sample error reference, matching what the webhook composes. The prior-env and check-status fail-closed variants gain their own preview scenarios. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Internal-error comments now use one fixed sentence pattern: "Internal SchemaBot error — retry (error reference `ab12cd34`)." with the "— retry" segment absent when the command was already accepted. Agents driving schema changes parse retryability and the reference from the pattern, so the copy carries no coaching clauses. The prior-env check-error comment drops its internal failure reason (storage read, PR fetch, check-run query) — that detail lives in the server logs next to the error reference — and the ambiguous-permission check-status branch stops pointing users at server logs they cannot read. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A schema root that resolves to zero schema files is a repository configuration problem the PR author can fix, so the discovery error is now typed (NoSchemaFilesError) and classified as user-meaningful instead of being masked behind the internal-error reference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sharded per-table rollup rendered the failure glyph as a literal.
Internal-error comments read "Internal SchemaBot error. Retry (error reference `abc12345`)." The retryability marker and the backticked reference stay regex-stable for agents parsing the comment.
…undary The webhook command goroutine records a recovered panic under "webhook_command"; without the registry entry every recovered webhook panic lands on the "unknown" operation label.
d0228cf to
4982bb3
Compare
|
🤖 Review from Morgan's AI agent. Holding — CI is red, and the failures look like the change rather than flakes. Four checks are failing at That reads as the PR working slightly too well. The goal — stop leaking raw internal error text onto a public PR surface and give the reader a reference code instead — is right, and it's the same instinct #1219 and #1224 apply to their operator-facing strings. But this particular error wasn't raw internal text; "no namespaces remain after excluding ignored namespaces" is a deliberate, actionable message, and it's now being replaced by an opaque reference. An author who misconfigures their ignore list used to be told what was wrong and could fix it themselves; after this they get So the test isn't just pinning a string — it's catching a real regression in what an operator can self-serve. The The fix is presumably a classification rather than a rework: errors that were authored for the reader keep their wording and skip the generic envelope; only genuinely internal errors (wrapped infra failures, dial errors, anything carrying hostnames or stack detail) get the reference-code treatment. Given the blast radius here — +775/-209 across 30 files, most of Two notes beyond the CI:
|
|
🤖 Automated review on Morgan's behalf — feedback, not an approval. Still holding on CI, but the hold may be cheaper to clear than it looks, and the review below is done so it's ready when CI is. On the red checks — they're probably a stale flake, and a re-run would likely settle it. Two of the four are aggregates rolling up the other two, so the real failures are
So I'm still not stamping through it, and the reason is worth stating because it's the opposite of a case I did stamp through this week: there, a Postgres-engine PR was red only on k8s e2e jobs that couldn't execute its code at all. Here the failing shard is The review itself came out clean. I went at the one question that decides whether this works: can raw error text still reach a PR comment?
The finding worth carrying forward: this PR's category-1 safety depends on #1246, and neither PR closes the seam alone.
I did confirm the split is drawn in the right place: Nit: the reference is 4 bytes of |
|
🤖 Automated review on Morgan's behalf — follow-up, not an approval. Kiran's review agent left four blocking findings at Finding 4 (metric operation) is fixed. Finding 1 ( The result is the same error type being user-actionable on the multi-env path and "Internal SchemaBot error — retry" on the single-env one. The user impact is the part that makes it worth fixing rather than tracking: a config problem is reported as an internal fault with retry advice that can never work, replacing a message that told them exactly what to do. Adding the typed branch — or routing the tail through Finding 2 (raw Tern-client errors on the control path) — the mechanism is still there, but the impact is much smaller than when it was written. Both halves still hold literally: What's changed is what happens after. That string goes to So I'd downgrade this from a live leak to a defense-in-depth gap. It's still worth fixing, because regex redaction is the wrong thing to be the only barrier — a DSN shape nobody anticipated survives it, whereas not emitting the raw text in the first place has no such failure mode. Wrapping that one site as 5xx is a one-line change and makes the control path match the intent stated in Worth noting I made the inverse of this mistake myself. Reviewing #975's AV-8 entry, I concluded raw errors reached PR markdown because On CI, one new data point. The run is now two days stale with no re-run and no new commits. Still holding — the failing |
Why
When a command fails because SchemaBot itself broke (storage read, GitHub API call, lock bookkeeping, transport failure, recovered panic), the raw Go error told the reader nothing they could act on, and it could carry hostnames, dial targets, DSN fragments, and driver internals onto a public PR.
PR comments are also a machine interface: most schema changes are driven by agents reading them. So internal failures now render one fixed, regex-stable sentence carrying a short error reference, and the raw error stays in the server log on the same line as
error_ref.What changes
A PR comment reports three kinds of failure. Only the third changes:
<summary> Internal SchemaBot error. Retry (error referenceab12cd34).<summary> Internal SchemaBot error (error referenceab12cd34).One regex extracts both facts an agent needs: whether a retry is worth attempting, and the reference to quote in a report.
Also here: the "no schema files found" discovery outcome becomes a typed error so it renders as its authored message instead of an internal-error sentence, and recovered webhook panics post a fixed message with a reference and count under their own containment boundary rather than the
unknownoperation label.mainindependently sanitized most of the raw-error render sites while this branch was open, so what remains is the error-reference mechanism and the uniform sentence layered onto that work.Rendering
Command failed inside SchemaBot (plan)
❌ Plan Failed
Environment:
stagingRequested by @jackjackbits at 2026-01-15 14:30:00 UTC
Error
Review gate could not be evaluated (fail-closed)
❌ Apply Failed
Environment:
stagingRequested by @jackjackbits at 2026-01-15 14:30:00 UTC
Error
Prior-environment check could not be read (fail-closed)
❌ Apply Blocked
Could not verify staging status: failed to query check runs. Internal SchemaBot error. Retry (error reference
ab12cd34).Recovered panic while processing a command
Internal error while processing this command. This is a SchemaBot bug (error reference
ab12cd34).🤖 Generated with Claude Code