Skip to content

Commit e17a48c

Browse files
committed
Derive callback footer link labels from branding constants
The URLs lived in branding.ts while their display text stayed inline in the page template, so a rename would have had to touch both. Add matching label constants and restore the no-external-assets guard to its full strength by stripping the two intentional footer links before asserting no other off-machine URL or network call appears.
1 parent 31117fe commit e17a48c

3 files changed

Lines changed: 39 additions & 12 deletions

File tree

src/auth/callback-page.test.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { describe, expect, test } from "bun:test";
22

3+
import {
4+
PRODUCT_GITHUB_LABEL,
5+
PRODUCT_GITHUB_URL,
6+
PRODUCT_SITE_LABEL,
7+
PRODUCT_SITE_URL,
8+
} from "../branding.js";
39
import { callbackPageHtml, humanizeIdentifier } from "./callback-page.js";
410

511
describe("humanizeIdentifier", () => {
@@ -42,19 +48,25 @@ describe("callbackPageHtml", () => {
4248
);
4349
});
4450

45-
test("success footer links to corbits.dev and the GitHub org", () => {
51+
test("the footer links to the product site and the GitHub org", () => {
4652
const html = callbackPageHtml({ subject: "linear" });
47-
expect(html).toContain('href="https://corbits.dev"');
48-
expect(html).toContain('href="https://github.com/corbitsdev"');
49-
expect(html).toContain(">corbits.dev<");
50-
expect(html).toContain(">github.com/corbitsdev<");
53+
const link = (url: string, label: string) =>
54+
`<a href="${url}" target="_blank" rel="noopener noreferrer">${label}</a>`;
55+
expect(html).toContain(link(PRODUCT_SITE_URL, PRODUCT_SITE_LABEL));
56+
expect(html).toContain(link(PRODUCT_GITHUB_URL, PRODUCT_GITHUB_LABEL));
5157
});
5258

53-
test("the page loads no off-machine assets", () => {
59+
test("the page names no off-machine origin beyond the footer links", () => {
60+
// An allowlist rather than a shape match: a fifth URL fails loudly instead
61+
// of passing because it happened to be wrapped in an anchor tag.
62+
const allowed = new Set([
63+
PRODUCT_SITE_URL,
64+
PRODUCT_GITHUB_URL,
65+
"http://www.w3.org/2000/svg",
66+
]);
5467
const html = callbackPageHtml({ subject: "linear" });
55-
// Product links in the footer are intentional; nothing else may fetch.
56-
expect(html).not.toMatch(/<(?:link|script)\b[^>]+\bsrc=/i);
57-
expect(html).not.toMatch(/@import\b/);
58-
expect(html).not.toMatch(/url\(\s*["']?https?:/i);
68+
const found = html.match(/https?:\/\/[^"')\s]+/g) ?? [];
69+
expect(found.filter((url) => !allowed.has(url))).toEqual([]);
70+
expect(html).not.toMatch(/\b(?:fetch|XMLHttpRequest|WebSocket|sendBeacon)\s*\(/);
5971
});
6072
});

src/auth/callback-page.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616

1717
import {
18+
PRODUCT_GITHUB_LABEL,
1819
PRODUCT_GITHUB_URL,
1920
PRODUCT_NAME,
21+
PRODUCT_SITE_LABEL,
2022
PRODUCT_SITE_URL,
2123
} from "../branding.js";
2224

@@ -245,6 +247,16 @@ export function humanizeIdentifier(raw: string): string {
245247
return words.charAt(0).toUpperCase() + words.slice(1);
246248
}
247249

250+
/**
251+
* A footer link, preceded by its separator.
252+
*
253+
* Opens in a new tab so the operator keeps the tab telling them the
254+
* authorization finished and this window is safe to close.
255+
*/
256+
function footerLink(url: string, label: string): string {
257+
return `<span class="sep" aria-hidden="true">·</span><a href="${url}" target="_blank" rel="noopener noreferrer">${label}</a>`;
258+
}
259+
248260
export type CallbackPage = {
249261
/** What was being authorized: an MCP server or provider name. */
250262
readonly subject?: string;
@@ -292,7 +304,7 @@ export function callbackPageHtml(page: CallbackPage = {}): string {
292304
`<h1>${heading}</h1>`,
293305
`<p class="body">${body}</p>`,
294306
"<hr>",
295-
`<footer>${PRODUCT_NAME}<span class="sep" aria-hidden="true">·</span><a href="${PRODUCT_SITE_URL}">corbits.dev</a><span class="sep" aria-hidden="true">·</span><a href="${PRODUCT_GITHUB_URL}">github.com/corbitsdev</a></footer>`,
307+
`<footer>${PRODUCT_NAME}${footerLink(PRODUCT_SITE_URL, PRODUCT_SITE_LABEL)}${footerLink(PRODUCT_GITHUB_URL, PRODUCT_GITHUB_LABEL)}</footer>`,
296308
"</div>",
297309
"</main></body>",
298310
`<script>${SCRIPT}</script>`,

src/branding.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ export const PRODUCT_NAME = "Corbits Code";
1111
// Short attribution form used in compact UI (status lines, footers).
1212
export const PRODUCT_SHORT_NAME = "Corbits";
1313

14-
// Canonical public URLs shown on the OAuth callback page and other brand surfaces.
14+
// Canonical public URLs, with the display text that accompanies each, so a link
15+
// and its label cannot drift apart when a domain or org name changes.
1516
export const PRODUCT_SITE_URL = "https://corbits.dev";
17+
export const PRODUCT_SITE_LABEL = "corbits.dev";
1618
export const PRODUCT_GITHUB_URL = "https://github.com/corbitsdev";
19+
export const PRODUCT_GITHUB_LABEL = "github.com/corbitsdev";
1720

1821
export const COMMAND_NAME = "corbits";
1922

0 commit comments

Comments
 (0)