mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
New web-svc-mirror role: an nginx vhost that proxies and caches exactly the external asset hosts aggregated from all deployed applications' CSP whitelists (external_asset_origins filter) under first-party paths (/<origin-host>/...), refusing every other upstream. svc-net-tor consumes the service, so any tor deployment automatically serves the mirror on its onion. For apps with services.tor.enabled the shared body filter rewrites external asset URLs in HTML to the onion mirror (onion sessions only; clearnet untouched) and the CSP builder allows the mirror origin in the asset directives. The dashboard's keycloak-js vendoring is reverted: onion sessions now load the adapter through the mirror, clearnet loads jsdelivr directly as before. Verified: variant=0 deploy green (failed=0), dashboard 14/14 over onion with keycloak-js served through the mirror, mirror spec green, health check accepts the 404 vhost root. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
1.5 KiB
JavaScript
35 lines
1.5 KiB
JavaScript
const { test, expect } = require("@playwright/test");
|
|
|
|
const { decodeDotenvQuotedValue, expectHstsWhenTls, gotoOnion, normalizeBaseUrl } = require("./personas");
|
|
test.use({ ignoreHTTPSErrors: true });
|
|
|
|
const mirrorBaseUrl = normalizeBaseUrl(process.env.MIRROR_BASE_URL || "");
|
|
const canonicalDomain = decodeDotenvQuotedValue(process.env.CANONICAL_DOMAIN);
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
expect(mirrorBaseUrl, "MIRROR_BASE_URL must be set").toBeTruthy();
|
|
expect(canonicalDomain, "CANONICAL_DOMAIN must be set").toBeTruthy();
|
|
await page.context().clearCookies();
|
|
});
|
|
|
|
test("mirror is served under canonical domain and refuses unmapped paths", async ({ page }) => {
|
|
const response = await gotoOnion(page, `${mirrorBaseUrl}/`);
|
|
expect(response, "Expected mirror root response").toBeTruthy();
|
|
expect(response.status(), "Expected mirror root to refuse unmapped paths").toBe(404);
|
|
expect(
|
|
response.url().includes(canonicalDomain),
|
|
`Expected canonical domain "${canonicalDomain}" to back the mirror URL`
|
|
).toBe(true);
|
|
const headers = response.headers();
|
|
expectHstsWhenTls(headers, mirrorBaseUrl, "Mirror");
|
|
});
|
|
|
|
test("mirror refuses origins outside the CSP-derived allowlist", async ({ page }) => {
|
|
const response = await gotoOnion(page, `${mirrorBaseUrl}/evil.example/payload.js`);
|
|
expect(response, "Expected mirror allowlist response").toBeTruthy();
|
|
expect(
|
|
response.status(),
|
|
"Expected a non-whitelisted origin path to be refused"
|
|
).toBe(404);
|
|
});
|