Files
wehub-resource-sync b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:23:53 +08:00

136 lines
5.0 KiB
TypeScript

import { afterEach, describe, it, expect, vi } from "vitest";
import { buildEmDashCsp, getConfiguredStorageEndpoint } from "../../../src/astro/middleware/csp.js";
describe("buildEmDashCsp", () => {
it("includes https: in img-src to allow external images", () => {
const csp = buildEmDashCsp();
const imgSrc = csp.split("; ").find((d) => d.startsWith("img-src"));
expect(imgSrc).toContain("https:");
});
it("still includes self, data:, and blob: in img-src", () => {
const csp = buildEmDashCsp();
const imgSrc = csp.split("; ").find((d) => d.startsWith("img-src"));
expect(imgSrc).toContain("'self'");
expect(imgSrc).toContain("data:");
expect(imgSrc).toContain("blob:");
});
it("keeps connect-src restricted to self", () => {
const csp = buildEmDashCsp();
const connectSrc = csp.split("; ").find((d) => d.startsWith("connect-src"));
expect(connectSrc).toBe("connect-src 'self'");
});
it("allows the configured registry aggregator origin in connect-src", () => {
const csp = buildEmDashCsp({ aggregatorUrl: "https://registry.emdashcms.com/xrpc" });
const connectSrc = csp.split("; ").find((d) => d.startsWith("connect-src"));
expect(connectSrc).toBe("connect-src 'self' https://registry.emdashcms.com");
});
it("allows shorthand registry URLs in connect-src", () => {
const csp = buildEmDashCsp("https://registry.emdashcms.com");
const connectSrc = csp.split("; ").find((d) => d.startsWith("connect-src"));
expect(connectSrc).toBe("connect-src 'self' https://registry.emdashcms.com");
});
it("allows the configured storage endpoint origin in connect-src", () => {
const csp = buildEmDashCsp(undefined, "https://xxx.r2.cloudflarestorage.com");
const connectSrc = csp.split("; ").find((d) => d.startsWith("connect-src"));
expect(connectSrc).toBe("connect-src 'self' https://xxx.r2.cloudflarestorage.com");
});
it("ignores a storage endpoint that isn't http(s)", () => {
const csp = buildEmDashCsp(undefined, "file:///tmp/uploads");
const connectSrc = csp.split("; ").find((d) => d.startsWith("connect-src"));
expect(connectSrc).toBe("connect-src 'self'");
});
it("ignores a malformed storage endpoint", () => {
const csp = buildEmDashCsp(undefined, "not a url");
const connectSrc = csp.split("; ").find((d) => d.startsWith("connect-src"));
expect(connectSrc).toBe("connect-src 'self'");
});
it("allows both the registry and storage endpoint origins together", () => {
const csp = buildEmDashCsp(
"https://registry.emdashcms.com",
"https://xxx.r2.cloudflarestorage.com",
);
const connectSrc = csp.split("; ").find((d) => d.startsWith("connect-src"));
expect(connectSrc).toBe(
"connect-src 'self' https://registry.emdashcms.com https://xxx.r2.cloudflarestorage.com",
);
});
it("does not duplicate the origin when storage endpoint and registry share it", () => {
const csp = buildEmDashCsp("https://shared.example.com", "https://shared.example.com/bucket");
const connectSrc = csp.split("; ").find((d) => d.startsWith("connect-src"));
expect(connectSrc).toBe("connect-src 'self' https://shared.example.com");
});
it("blocks framing with frame-ancestors none", () => {
const csp = buildEmDashCsp();
expect(csp).toContain("frame-ancestors 'none'");
});
});
describe("getConfiguredStorageEndpoint", () => {
afterEach(() => {
vi.unstubAllEnvs();
});
it("returns undefined for undefined storage", () => {
expect(getConfiguredStorageEndpoint(undefined)).toBeUndefined();
});
it("returns undefined for storage config without an endpoint field", () => {
expect(
getConfiguredStorageEndpoint({
entrypoint: "emdash/storage/local",
config: { directory: "./uploads" },
}),
).toBeUndefined();
});
it("returns the explicit endpoint from config when present", () => {
expect(
getConfiguredStorageEndpoint({
entrypoint: "emdash/storage/s3",
config: { endpoint: "https://xxx.r2.cloudflarestorage.com" },
}),
).toBe("https://xxx.r2.cloudflarestorage.com");
});
it("falls back to S3_ENDPOINT when the s3 adapter's config omits endpoint", () => {
vi.stubEnv("S3_ENDPOINT", "https://from-env.example.com");
expect(getConfiguredStorageEndpoint({ entrypoint: "emdash/storage/s3", config: {} })).toBe(
"https://from-env.example.com",
);
});
it("explicit config endpoint wins over S3_ENDPOINT", () => {
vi.stubEnv("S3_ENDPOINT", "https://from-env.example.com");
expect(
getConfiguredStorageEndpoint({
entrypoint: "emdash/storage/s3",
config: { endpoint: "https://from-config.example.com" },
}),
).toBe("https://from-config.example.com");
});
it("does not fall back to S3_ENDPOINT for a non-s3 adapter", () => {
vi.stubEnv("S3_ENDPOINT", "https://from-env.example.com");
expect(
getConfiguredStorageEndpoint({ entrypoint: "emdash/storage/local", config: {} }),
).toBeUndefined();
});
it("returns undefined when S3_ENDPOINT is unset and config has no endpoint", () => {
expect(
getConfiguredStorageEndpoint({ entrypoint: "emdash/storage/s3", config: {} }),
).toBeUndefined();
});
});