Skip to content

Commit cf82b21

Browse files
jaydgossclaude
andauthored
feat(middleware): Serve production build URLs to the evals pin header (#20225)
## DESCRIBE YOUR PR Production build URLs (`sentry-docs-<hash>.sentry.dev`) now serve their own pages to requests that have an `x-sentry-evals-pin` header, instead of 308ing them to docs.sentry.io. Everyone else is still redirected as in #19033, and these responses still get `X-Robots-Tag: noindex`. [sentry-for-ai-evals](https://github.com/getsentry/sentry-for-ai-evals) compares a docs PR's preview with the docs at the PR's merge base, and that commit's production build is the only copy of those. The redirect sends the evals to the live docs instead, so a PR that's behind master gets everything master gained since counted as its own change. The evals' docs proxy sends the header, and #20214 points the base at the merge base's build. Like the redirect, the header isn't a security boundary: previews are already public, and an old build only has docs that were once live. Only builds made after this merges check for the header, so older merge bases keep reading the live docs. Refs [VDY-307](https://linear.app/getsentry/issue/VDY-307/onboarding-evals-ai-evals-label-workflow-in-sentry-docs) ## IS YOUR CHANGE URGENT? Help us prioritize incoming PRs by letting us know when the change needs to go live. Select exactly one option. For deadlines, replace `YYYY-MM-DD` with the due date. You can update this information later by editing the PR description. - [ ] Urgent deadline (GA date, etc.): YYYY-MM-DD - [ ] Other deadline: YYYY-MM-DD - [x] No deadline: Not urgent, can wait up to 1 week+ ## SLA - Teamwork makes the dream work, so please add a reviewer to your PRs. - Please give the docs team up to 1 week to review your PR unless you've supplied a deadline. Thanks in advance for your help! ## PRE-MERGE CHECKLIST _Make sure you've checked the following before merging your changes:_ - [ ] Checked Vercel preview for correctness, including links - [ ] PR was reviewed and approved by any necessary SMEs (subject matter experts) - [ ] PR was reviewed and approved by a member of the [Sentry docs team](https://github.com/orgs/getsentry/teams/docs) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 6388344 commit cf82b21

2 files changed

Lines changed: 26 additions & 3 deletions

File tree

‎middleware.test.ts‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,12 @@ describe('production build-url redirect to canonical (Deployment Protection off)
113113
vi.unstubAllEnvs();
114114
});
115115

116-
function makeHostRequest(url: string, method = 'GET'): NextRequest {
117-
return new NextRequest(new URL(url), {method});
116+
function makeHostRequest(
117+
url: string,
118+
method = 'GET',
119+
headers?: HeadersInit
120+
): NextRequest {
121+
return new NextRequest(new URL(url), {method, headers});
118122
}
119123

120124
it('redirects a non-canonical production host to the canonical host', async () => {
@@ -192,6 +196,17 @@ describe('production build-url redirect to canonical (Deployment Protection off)
192196
);
193197
expect(res.status).not.toBe(308);
194198
});
199+
200+
it('serves a production build URL to the evals pin header', async () => {
201+
const {middleware} = await importMiddleware({});
202+
vi.stubEnv('VERCEL_ENV', 'production');
203+
const res = middleware(
204+
makeHostRequest('https://sentry-docs-abc123.vercel.app/llms.txt', 'GET', {
205+
'x-sentry-evals-pin': '1',
206+
})
207+
);
208+
expect(res.status).not.toBe(308);
209+
});
195210
});
196211

197212
describe('canonical Link header on .md responses', () => {

‎middleware.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ const BASE_URL = isDeveloperDocs
1919

2020
const CANONICAL_HOST = new URL(BASE_URL).hostname;
2121

22+
// sentry-for-ai-evals compares a PR's docs with the docs at its merge base, which it reads
23+
// from that commit's production build URL. It sends this header so the build serves its
24+
// own pages instead of redirecting to the canonical host.
25+
const EVALS_PIN_HEADER = 'x-sentry-evals-pin';
26+
2227
// Production domains whose content should be indexable by search engines.
2328
// All other hostnames (Vercel preview/deployment URLs, old production deployments)
2429
// get X-Robots-Tag: noindex to prevent search engines from indexing stale content.
@@ -73,7 +78,10 @@ function redirectProductionBuildUrlToCanonical(
7378
) {
7479
return null;
7580
}
76-
if (request.nextUrl.hostname === CANONICAL_HOST) {
81+
if (
82+
request.nextUrl.hostname === CANONICAL_HOST ||
83+
request.headers.has(EVALS_PIN_HEADER)
84+
) {
7785
return null;
7886
}
7987
const url = request.nextUrl.clone();

0 commit comments

Comments
 (0)