first commit
This commit is contained in:
81
docs/api-stack/api/api-openapi-ui-scalar/src/headers/csp.md
Normal file
81
docs/api-stack/api/api-openapi-ui-scalar/src/headers/csp.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Strict Content-Security-Policy for the Scalar UI shell
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
The headers module builds the `Content-Security-Policy` header value
|
||||
emitted on every HTML response from the Scalar UI handler. The default
|
||||
posture is conservative: `default-src 'self'` plus the minimum set of
|
||||
directive relaxations the Scalar shell needs to render. In
|
||||
`assetMode = "cdn"` the policy is widened (per-handler) to whitelist the
|
||||
configured Scalar CDN origin. In `assetMode = "bundled"` the policy
|
||||
stays strict — every script/style/font load resolves to the host's own
|
||||
origin under `<uiEndpoint>/assets/`.
|
||||
|
||||
## Features
|
||||
|
||||
- `buildCspHeader({ assetMode, cdnOrigin?, openapiOrigin? })` — emits
|
||||
the `Content-Security-Policy` header pair.
|
||||
- `originOf(url)` — extracts the origin portion of a URL or returns
|
||||
`undefined` for non-URL inputs (used at handler construction to derive
|
||||
the CDN + OpenAPI origins from the parsed options).
|
||||
- `cspAllowsInlineScripts(headerValue)` — conformance predicate the
|
||||
handler test uses to prove the rendered policy never permits inline
|
||||
scripts. The Scalar bootstrap is loaded as an external `<script src>`
|
||||
so `'unsafe-inline'` in `script-src` would be a regression.
|
||||
- `'unsafe-inline'` allowed ONLY in `style-src` for the upstream Scalar
|
||||
React app's runtime style injection.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { buildCspHeader } from "@suaveplan/api-openapi-ui-scalar/headers";
|
||||
|
||||
const csp = buildCspHeader({ assetMode: "bundled" });
|
||||
console.log(csp.name); // "Content-Security-Policy"
|
||||
console.log(csp.value); // strict "default-src 'self'; script-src 'self'; …"
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
buildCspHeader,
|
||||
cspAllowsInlineScripts,
|
||||
originOf,
|
||||
} from "@suaveplan/api-openapi-ui-scalar/headers";
|
||||
|
||||
const cdnOrigin = originOf("https://cdn.jsdelivr.net/npm/@scalar/api-reference");
|
||||
const openapiOrigin = originOf("https://api.example.com/openapi.json");
|
||||
const { name, value } = buildCspHeader({
|
||||
assetMode: "cdn",
|
||||
cdnOrigin,
|
||||
openapiOrigin,
|
||||
});
|
||||
|
||||
if (cspAllowsInlineScripts(value)) {
|
||||
throw new Error("Scalar UI must never emit unsafe-inline scripts");
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `CSP_HEADER_NAME` — the canonical header name string.
|
||||
- `BuildCspInput` — `{ assetMode, cdnOrigin?, openapiOrigin? }`.
|
||||
- `buildCspHeader(input)` — `{ name, value }`.
|
||||
- `originOf(url)` — `string | undefined`.
|
||||
- `cspAllowsInlineScripts(headerValue)` — `boolean`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The policy structure is built directive-by-directive rather than via a
|
||||
single template string so future per-environment relaxations
|
||||
(e.g. nonce-based `script-src`) can be added without changing every
|
||||
call site. `script-src` never includes `'unsafe-inline'`; this is a
|
||||
load-bearing invariant enforced by the conformance predicate exposed
|
||||
above. The CDN origin is computed once at handler construction so a
|
||||
malicious `cdnUrl` value cannot leak into the response header — Zod
|
||||
rejects non-URL inputs at the options layer before `originOf` runs.
|
||||
Reference in New Issue
Block a user