This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// The security headers of spec §6.4, and the two things a page may not do: load a script inline
|
||||
// or reach an origin that is not this app's.
|
||||
|
||||
import { describe, expect, it } from "vitest"
|
||||
import { contentSecurityPolicy, securityHeaders } from "../apps/web/src/server/headers"
|
||||
|
||||
const policy = contentSecurityPolicy({ nonce: "test-nonce" })
|
||||
|
||||
describe("the content security policy", () => {
|
||||
it("allows a script only with this request's nonce", () => {
|
||||
expect(policy).toContain("script-src 'self' 'nonce-test-nonce' 'strict-dynamic'")
|
||||
expect(policy).not.toContain("script-src 'self' 'unsafe-inline'")
|
||||
expect(policy).not.toContain("unsafe-eval")
|
||||
})
|
||||
|
||||
it("refuses framing, a base tag and a plugin outright", () => {
|
||||
expect(policy).toContain("frame-ancestors 'none'")
|
||||
expect(policy).toContain("base-uri 'none'")
|
||||
expect(policy).toContain("object-src 'none'")
|
||||
})
|
||||
|
||||
it("names no origin but this app's", () => {
|
||||
const sources = policy
|
||||
.split("; ")
|
||||
.flatMap((directive) => directive.split(" ").slice(1))
|
||||
.filter((source) => source.includes("."))
|
||||
expect(sources).toEqual([])
|
||||
})
|
||||
|
||||
it("keeps fonts and connections on this origin, so no CDN or font host is reachable", () => {
|
||||
expect(policy).toContain("font-src 'self'")
|
||||
expect(policy).toContain("connect-src 'self'")
|
||||
})
|
||||
})
|
||||
|
||||
describe("the content security policy of a development run", () => {
|
||||
it("allows eval for React's development build, and only there", () => {
|
||||
expect(contentSecurityPolicy({ nonce: "n", development: true })).toContain("'strict-dynamic' 'unsafe-eval'")
|
||||
expect(contentSecurityPolicy({ nonce: "n" })).not.toContain("unsafe-eval")
|
||||
expect(contentSecurityPolicy({ nonce: "n", development: false })).not.toContain("unsafe-eval")
|
||||
expect(securityHeaders({ nonce: "n", secure: false, development: true })["content-security-policy"]).toContain(
|
||||
"unsafe-eval",
|
||||
)
|
||||
expect(securityHeaders({ nonce: "n", secure: true })["content-security-policy"]).not.toContain("unsafe-eval")
|
||||
})
|
||||
})
|
||||
|
||||
describe("the response headers", () => {
|
||||
it("pin the transport only where there is one to pin", () => {
|
||||
expect(securityHeaders({ nonce: "n", secure: true })["strict-transport-security"]).toContain("max-age=63072000")
|
||||
expect(securityHeaders({ nonce: "n", secure: false })["strict-transport-security"]).toBeUndefined()
|
||||
})
|
||||
|
||||
it("carry the rest of the baseline", () => {
|
||||
const headers = securityHeaders({ nonce: "n", secure: true })
|
||||
expect(headers["x-content-type-options"]).toBe("nosniff")
|
||||
expect(headers["referrer-policy"]).toBe("strict-origin-when-cross-origin")
|
||||
expect(headers["cross-origin-opener-policy"]).toBe("same-origin")
|
||||
expect(headers["permissions-policy"]).toContain("camera=()")
|
||||
})
|
||||
})
|
||||
|
||||
describe("the browser's half of the API path", () => {
|
||||
it("types a call by its contract's own schemas", async () => {
|
||||
// A compile-time property, checked here by construction: `callContract` takes the contract's
|
||||
// input type and answers its output type. If either drifted, this file would not typecheck.
|
||||
const { callContract } = await import("../apps/web/src/ui/client")
|
||||
const contract = { name: "notes.note.create", input: { _input: { title: "" } }, output: { _output: { id: "" } } }
|
||||
expect(typeof callContract).toBe("function")
|
||||
expect(contract.name).toBe("notes.note.create")
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user