fix(ci): restore apps/web/vercel.json as Vercel SSOT (H7 hot-fix)#1600
Conversation
…= apps/web) H7 closure in #1595 deleted apps/web/vercel.json on the wrong assumption that the Vercel project's Root Directory was '/'. Real Root Directory is apps/web (visible in Vercel-bot PR comment metadata: rootDirectory:apps/web). Vercel reads vercel.json from the configured Root Directory only — so the deletion silently dropped installCommand / buildCommand that pre-build @sergeant/db-schema, and post-merge Vercel deploys started failing with rolldown 'cannot resolve @sergeant/db-schema/sqlite/migrations'. This PR swaps the SSOT to the file Vercel actually reads: - Restore apps/web/vercel.json with the merged headers contract (COOP/COEP, CSP-Report-Only pointed at api.sergeant.app/api/csp-report from C2, Permissions-Policy, well-known caching) and outputDirectory: 'dist' (relative to Root Directory). - Delete root vercel.json — it was never read by Vercel and only created the silent-drift exposure described in H7. - Invert scripts/check-vercel-config.sh: it now fails if any vercel.json exists outside apps/web/, and fails if apps/web/vercel.json is missing. - Refresh docs/deploy/vercel.md: SSOT path, out-of-repo Vercel settings table now lists Root Directory = apps/web (was '/'), incident playbook step 1 calls out the rolldown failure mode. - Append incident to docs/security/hardening/H7-vercel-config-drift.md with the 2026-05-04 wrong-SSOT log entry and corrected verification. Production-incident remediation, no behavioural change to end users. Co-Authored-By: Вася Пупкін <steppupa@gmail.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR consolidates Vercel configuration to a single source of truth at ChangesVercel Configuration Consolidation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Review rate limit: 7/10 reviews remaining, refill in 16 minutes and 53 seconds. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/deploy/vercel.md`:
- Around line 65-69: Update the docs/deploy/vercel.md header-scope description
to match the actual config: state that cross-cutting headers (CSP, COOP/COEP,
Permissions-Policy, Referrer-Policy) are defined in apps/web/vercel.json under
headers[*] with the source pattern "/((?!\\.well-known).*)" (not "/(.*)"), and
keep the note that path-scoped headers (e.g. cache-control on /assets/*,
well-known mime types) get their own block; reference the exact source pattern
string and the headers[*] blocks to ensure the wording aligns with the live
config.
In `@docs/security/hardening/H7-vercel-config-drift.md`:
- Line 4: Replace the status badge line that currently reads "> **Status:**
Closed (2026-05-04 — SSOT at `apps/web/vercel.json` + CI guard, after
live-rollback of an incorrect SSOT choice)." with one of the allowed badge
values: Active, Scaffolded, Deprecated, or Archived (e.g., "> **Status:**
Archived"), and move the closure details ("2026-05-04 — SSOT at
`apps/web/vercel.json` + CI guard, after live-rollback of an incorrect SSOT
choice") into the prose or a table elsewhere in the document so the badge
strictly uses an allowed value.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2996af62-61a2-45e7-8fcc-61234a77eec0
📒 Files selected for processing (4)
apps/web/vercel.jsondocs/deploy/vercel.mddocs/security/hardening/H7-vercel-config-drift.mdscripts/check-vercel-config.sh
| Every header that ships to browsers from `apps/web` is defined in | ||
| `apps/web/vercel.json` `headers[*]` blocks. Cross-cutting headers (CSP, | ||
| COOP/COEP, Permissions-Policy, Referrer-Policy) live under `source: "/(.*)"`. | ||
| Path-scoped headers (e.g. cache-control on `/assets/*`, well-known mime types) | ||
| get their own block. |
There was a problem hiding this comment.
Header-scope description is out of sync with apps/web/vercel.json.
The doc says COOP/COEP are under source: "/(.*)", but the live config scopes them to source: "/((?!\\.well-known).*)". Please align the wording to avoid operational confusion during incident checks.
Suggested edit
-Every header that ships to browsers from `apps/web` is defined in
-`apps/web/vercel.json` `headers[*]` blocks. Cross-cutting headers (CSP,
-COOP/COEP, Permissions-Policy, Referrer-Policy) live under `source: "/(.*)"`.
-Path-scoped headers (e.g. cache-control on `/assets/*`, well-known mime types)
+Every header that ships to browsers from `apps/web` is defined in
+`apps/web/vercel.json` `headers[*]` blocks. Most cross-cutting headers (CSP,
+Permissions-Policy, Referrer-Policy) live under `source: "/(.*)"`, while
+COOP/COEP are scoped to `source: "/((?!\\.well-known).*)"` to exempt
+`.well-known/*`. Path-scoped headers (e.g. cache-control on `/assets/*`, well-known mime types)
get their own block.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Every header that ships to browsers from `apps/web` is defined in | |
| `apps/web/vercel.json` `headers[*]` blocks. Cross-cutting headers (CSP, | |
| COOP/COEP, Permissions-Policy, Referrer-Policy) live under `source: "/(.*)"`. | |
| Path-scoped headers (e.g. cache-control on `/assets/*`, well-known mime types) | |
| get their own block. | |
| Every header that ships to browsers from `apps/web` is defined in | |
| `apps/web/vercel.json` `headers[*]` blocks. Most cross-cutting headers (CSP, | |
| Permissions-Policy, Referrer-Policy) live under `source: "/(.*)"`, while | |
| COOP/COEP are scoped to `source: "/((?!\\.well-known).*)"` to exempt | |
| `.well-known/*`. Path-scoped headers (e.g. cache-control on `/assets/*`, well-known mime types) | |
| get their own block. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/deploy/vercel.md` around lines 65 - 69, Update the docs/deploy/vercel.md
header-scope description to match the actual config: state that cross-cutting
headers (CSP, COOP/COEP, Permissions-Policy, Referrer-Policy) are defined in
apps/web/vercel.json under headers[*] with the source pattern
"/((?!\\.well-known).*)" (not "/(.*)"), and keep the note that path-scoped
headers (e.g. cache-control on /assets/*, well-known mime types) get their own
block; reference the exact source pattern string and the headers[*] blocks to
ensure the wording aligns with the live config.
|
|
||
| > **Last validated:** 2026-05-04 by @Skords-01. **Next review:** 2026-08-04. | ||
| > **Status:** Closed (2026-05-04 — single source of truth + CI guard) | ||
| > **Status:** Closed (2026-05-04 — SSOT at `apps/web/vercel.json` + CI guard, after live-rollback of an incorrect SSOT choice). |
There was a problem hiding this comment.
Use an allowed documentation status badge value.
Closed is not one of the allowed badge states for published docs. Please switch Line 4 to one of Active | Scaffolded | Deprecated | Archived and keep closure detail in prose/table if needed.
Suggested edit
-> **Status:** Closed (2026-05-04 — SSOT at `apps/web/vercel.json` + CI guard, after live-rollback of an incorrect SSOT choice).
+> **Status:** ActiveAs per coding guidelines: docs/**/*.md: Every published documentation file must include a status badge under the freshness marker: > **Status:** Active | Scaffolded | Deprecated | Archived.
Also applies to: 12-12
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/security/hardening/H7-vercel-config-drift.md` at line 4, Replace the
status badge line that currently reads "> **Status:** Closed (2026-05-04 — SSOT
at `apps/web/vercel.json` + CI guard, after live-rollback of an incorrect SSOT
choice)." with one of the allowed badge values: Active, Scaffolded, Deprecated,
or Archived (e.g., "> **Status:** Archived"), and move the closure details
("2026-05-04 — SSOT at `apps/web/vercel.json` + CI guard, after live-rollback of
an incorrect SSOT choice") into the prose or a table elsewhere in the document
so the badge strictly uses an allowed value.
⏱️ CI Pipeline Duration ReportBased on the last 50 successful runs on the default branch. Overall Pipeline
Trend (last 20 runs): Per-Job Breakdown
|
Summary
Hot-fix for the production-Vercel build break introduced by the H7 closure in #1595. Vercel project's Root Directory is
apps/web, not/— so deletingapps/web/vercel.jsonsilently removed theinstallCommand/buildCommandVercel was actually reading, and post-merge production deploys started failing with rolldown'scannot resolve @sergeant/db-schema/sqlite/migrationserror.This PR swaps the H7 SSOT to the file Vercel actually reads:
apps/web/vercel.jsonwith the merged headers contract (COOP/COEP, CSP-Report-Only pointed atapi.sergeant.app/api/csp-reportfrom C2, Permissions-Policy, well-known caching) andoutputDirectory: "dist"(relative to Root Directory).vercel.json— it was never read by Vercel (Root Directory ≠/) and only created the silent-drift exposure that H7 was trying to close in the first place.scripts/check-vercel-config.sh: now fails if anyvercel.jsonexists outsideapps/web/, and fails ifapps/web/vercel.jsonis missing.docs/deploy/vercel.md: out-of-repo settings table now lists Root Directory =apps/web(was/); Output Directory =dist; incident playbook step 1 calls out the rolldown failure mode that took prod down on 2026-05-04.docs/security/hardening/H7-vercel-config-drift.mddocumenting the wrong-SSOT decision in feat(server): security hardening — close H2 + H7 + ship C2 Phase 1 (CSP report sink) #1595 and the live-rollback in this PR.Governing Skill
Playbook
Verification
Post-merge verification (will confirm in the PR thread):
failuretosuccesson this PR's HEAD.curl -sI <preview-url> | grep -i 'cross-origin-opener-policy'returnssame-origin.curl -sI <preview-url> | grep -i 'content-security-policy-report-only'containsreport-uri https://api.sergeant.app/api/csp-report.Additional checks:
bash scripts/check-vercel-config.shgreen, JSON valid)apps/web)Docs and Governance
AGENTS.mdneeded an update — no policy change.Updated docs:
docs/deploy/vercel.md— SSOT path, Vercel project settings table (Root Directory + Output Directory corrected), incident playbook.docs/security/hardening/H7-vercel-config-drift.md— incident log entry for 2026-05-04 wrong-SSOT decision, corrected Verification + Recommendation sections, status note clarified.Risk and Rollout
apps/web/vercel.jsonadds back what Vercel was already using before feat(server): security hardening — close H2 + H7 + ship C2 Phase 1 (CSP report sink) #1595 plus the COOP/COEP that lived only in the dead root copy until now.successstatus → main is live again.849e3b62. Do not revert without a follow-up that re-restoresapps/web/vercel.jsonfromf912ed6bplus the C2report-urichange.Hard Rule #15
AGENTS.mdbefore coding.docs/deploy/vercel.md, hardening card H7) were already in English per existing convention; no Ukrainian-language doc touched.--no-verify.Reviewer Notes
vercel.json. That was based on a misread of the Vercel UI (Root Directory was assumed/, actuallyapps/web). The correction is documented in the H7 implementation log and the new "Decision (2026-05-04)" line.apps/web/vercel.jsonis now the only allowed path.apps/web(it should not have changed; this PR depends on that invariant).Summary by cubic
Restore
apps/web/vercel.jsonas Vercel’s single source of truth to match the project Root Directory and fix the production build failure (“cannot resolve@sergeant/db-schema/sqlite/migrations”). No user-visible changes; security headers remain the same and deploys should pass again.apps/web/vercel.jsonwith merged headers andoutputDirectory: "dist"; keptinstallCommand/buildCommandthat pre-build@sergeant/db-schemathen@sergeant/web.vercel.json(unused by Vercel).scripts/check-vercel-config.shto allow onlyapps/web/vercel.jsonand fail on any other or if missing; updated docs (docs/deploy/vercel.md,docs/security/hardening/H7-vercel-config-drift.md) to reflect Root Directory =apps/web.Written for commit 6119612. Summary will update on new commits.
Summary by CodeRabbit
Release Notes
Chores
Documentation