Repository navigation
fix(automation): surface failed sync responses on repo detail page - #1387
Conversation
npm audit --omit=dev (blocking CI gate) failed on main and on this PR head: body-parser 2.3.0 was high (GHSA-27r3-jxmh-p828, DoS via trailing bytes after a compressed body), hono 4.13.7 and ip-address 10.7.2 were moderate. npm audit fix --package-lock-only --include=prod bumps body-parser to 2.4.0, hono to 4.13.13, ip-address to 10.7.4 and qs to 6.16.1; npm also re-resolved the dev tree (vite, rolldown, @oxc-project/types and @rolldown/* bindings) inside the same existing ranges. package.json and every range are unchanged; package-lock.json was already identical to main before this commit, so the failure pre-dates this PR. Local validation at this change state: npm ci --include=dev, npm run audit (0 vulnerabilities), typecheck, lint (1 pre-existing warning) and vitest all exit 0.
There was a problem hiding this comment.
AI Automated Review
Full PR review.
Analysis engine: MiniMax-M3.1-Flash (anthropic) — primary route · pr-reviewer-action v3.7.0
Recommendation: Approve.
Linked Issue Fit
The implementation satisfies the linked issue: non-OK JSON responses expose their error field, invalid/non-JSON responses receive an HTTP-status fallback, the page does not reload after failure, and the button is disabled while the request is in flight. The route contract confirms JSON errors for rate limiting, lock conflicts, and sync failures.
Claims
The functional UI claims held across the identified implementation points; the only wording discrepancy is that the non-JSON fallback contains the numeric HTTP status rather than Response.statusText. The audit and follow-up-scope claims also held based on the lockfile diff and unchanged rerun path, although external tracking of that follow-up was not independently verified.
Required Checks
- check for breaking API changes in updated dependencies — satisfied: the lock-only changes retain compatible semver lines, the affected transitive packages have no direct imports in
src, and build, typecheck, lint, and tests all succeeded. - run full test suite after upgrade — satisfied: the CI
Testscheck succeeded on the PR head.
Tool Harness Findings
Direct reads verified the changed page, sync API contract, client authentication, package manifest, lockfile dependency graph, audit guard, and rate-limit response shape. The GitHub check-runs API request failed because that transport was unavailable, but the supplied CI results cover the required checks.
Sources
Reviewed the changed page, src/app/api/automation/sync/route.ts, src/lib/client-auth.ts, src/lib/rate-limit.ts, package.json, package-lock.json, and the upstream body-parser advisory: GHSA-27r3-jxmh-p828
Unknowns or Needs Verification
Detailed upstream changelogs for every transitive version were not retrieved before the tool budget was exhausted, and no external tracking record for the out-of-scope rerun follow-up was available.
joryirving
left a comment
There was a problem hiding this comment.
Secondary hard-blocker review on exact head 71520e85f7057d68d89fcf63fec7636d39cfba20: APPROVE. The repo-detail sync handler checks res.ok, surfaces API errors with a safe status fallback, prevents reload on failure, and disables the button while the request is in flight. The lockfile-only dependency refresh stays within existing package semver ranges and resolves the known production audit gate; CI, build, smoke, Security Audit, and AI review are all green on this exact head. The missing dedicated UI regression test is a minor follow-up, not a blocker.
…1388) (#1396) The per-run rerun button in the repo detail page's runs table used the unguarded pattern authedFetch(...).then(() => window.location.reload()) with no res.ok check, silently hiding failed/throttled reruns (including 429 {"error":"Rate limit exceeded"}) as if they had succeeded. Adopt the handler pattern the sibling Sync button uses (#1387, after #1384's overview page): check res.ok, parse the JSON error body, render it in a destructive banner above the workflows list, and only reload the page on success. Rerun buttons disable while a rerun is in flight, with the active run's icon spinning.
Summary
Fixes #1385.
The repo detail "Sync" button posted to
POST /api/automation/syncand then unconditionally reloaded the page without checkingres.ok, so failed or throttled responses (e.g. the429 {"error":"Rate limit exceeded"}from #1307, the 409 "already running" lock, or a 500{error}body) were silently hidden by the reload. This mirrors the fix already open in #1384 exactly: checkres.ok, parse the error body (data?.error || 'Failed to sync (HTTP <status>)'), render the error on the page, reload only on success, disable the button while syncing, and spin the refresh icon. Applied tosrc/app/automation/repos/[...repo]/page.tsxonly — the #1324/#1384 scope wassrc/app/automation/page.tsx, per that issue's accepted scope.Changes
Issue fix (05126ab)
src/app/automation/repos/[...repo]/page.tsxsyncing/syncErrorstate and an asynchandleSync(fullName)handler: throws on!res.okwith the API error body (falling back to HTTP status text for non-JSON bodies), catches into rendered error text via theerror instanceof Errorpattern, reloads only on success.disabled={syncing}with a spinningRefreshCwwhile in flight.AlertTriangle).npm audit gate fix (71520e8)
package-lock.jsononly. The blockingnpm run auditCI gate (prod deps,--audit-level=high) failed on the pre-existing lock —package-lock.jsonwas byte-identical tomain, and this PR's UI change touches no dependencies — onbody-parser2.3.0 (high, GHSA-27r3-jxmh-p828: DoS via trailing bytes after a compressed request body) plus moderateshono4.13.7 (GHSA-5r4p-p66f-jhc7) andip-address10.7.2 (GHSA-rxp7-6hxx-x8q5).npm audit fix --package-lock-only --include=prodbumps body-parser → 2.4.0, hono → 4.13.13, ip-address → 10.7.4, qs → 6.16.1; npm also re-resolved the dev-only tree (vite 8.3.0→8.3.5, rolldown 1.2.8→1.2.15, @oxc-project/types, @rolldown/* bindings). Every bump stays inside the existing semver ranges (package.jsonuntouched, verified bynpm cisucceeding on the refreshed lock). Mechanical lockfile bump — skipped a separate review pass per the mech-bump review discipline; validation covers it.Local validation (run once per final change state, worktree HEAD 71520e8)
npm ci --include=dev— exit 0 (validates lock/package consistency)npm run audit— exit 0; "found 0 vulnerabilities" (the previously failing gate)npm run typecheck— exit 0npm run lint— exit 0; 0 errors, 1 pre-existing warning insrc/app/login/page.tsx(unrelated, pre-dates this change)npm run test(Vitest) — exit 0 (full suite green after the lock refresh)State prior to the audit fix, HEAD 05126ab: lint (0 errors, same pre-existing warning), typecheck, and vitest (206 files passed | 5 skipped, 5317 tests | 27 skipped | 1 todo) all exit 0.
Review
One bounded adversarial reviewer pass on the UI diff — PASS, no blockers/majors (verified error-path contract against
src/app/api/automation/sync/route.tsand rate limiting, double-click protection, TS narrowing on nullablerepostate). Limitation: all roles on this lane run the same model, so no model-diverse independent review. The lockfile-only audit-fix commit was validated rather than re-reviewed (in-range bump, mechanical).Remaining external verification
npm audit) on head 71520e8 is pending; not awaited by this run — operator verifies after exit. Thenpm auditfailure seen on the previous head (05126ab) was reproduced and fixed locally; expect that check green on the new head.authedFetch(.../runs/<id>?...&action=rerun).then(() => reload())) has the same silent-reload pattern; (2) PR fix(automation): surface failed/in-progress per-repo sync responses (#1324) #1384 must merge for the overview page.