@growth-labs/conformance 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/README.md +45 -1
- package/dist/endpoint.d.ts +21 -0
- package/dist/endpoint.d.ts.map +1 -0
- package/dist/endpoint.js +225 -0
- package/dist/endpoint.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runner.js +71 -5
- package/dist/runner.js.map +1 -1
- package/dist/schema.d.ts +255 -142
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +23 -3
- package/dist/schema.js.map +1 -1
- package/fixtures/negative/required-negative-fixtures.json +49 -0
- package/package.json +5 -1
- package/src/endpoint.ts +279 -0
- package/src/index.ts +4 -0
- package/src/runner.ts +81 -5
- package/src/schema.ts +27 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,71 @@
|
|
|
1
1
|
# @growth-labs/conformance Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0 — 2026-07-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Ship the stable `./endpoint` export with `initConformanceEndpoint` as the
|
|
8
|
+
deployment path: parses, validates, schema-strips, bounds, and serializes
|
|
9
|
+
the v2 artifact **once** at module initialization; per-request handling
|
|
10
|
+
validates only method and `versionMetadata.tag` — no I/O, no re-serialization.
|
|
11
|
+
Also exports `createDeploymentConformanceResponse` as a non-recommended
|
|
12
|
+
compatibility helper for direct per-request use (not the deployment path).
|
|
13
|
+
- The immutable factory captures body bytes at initialization time; post-init
|
|
14
|
+
source mutation and schema-external enumerable getters cannot change served
|
|
15
|
+
bytes or trigger I/O. The combined stripping parse validates endpoint
|
|
16
|
+
`buildEvidence` and the served v2 bundle together without reading schema-external
|
|
17
|
+
fields — no `.passthrough()`.
|
|
18
|
+
- Require `buildEvidence.generatedAt` (timezone-qualified ISO-8601 datetime) at
|
|
19
|
+
the deployment endpoint boundary alongside the existing `buildEvidence.commitSha`.
|
|
20
|
+
A missing or non-datetime `generatedAt` produces a permanently-failing handler.
|
|
21
|
+
- Support `GET` and `HEAD`; `HEAD` returns the same headers without a body,
|
|
22
|
+
while unsupported methods return generic `405` JSON with `Allow: GET, HEAD`.
|
|
23
|
+
- Require a non-empty string request method at runtime; missing, non-string, or
|
|
24
|
+
empty values fail closed with generic no-store JSON rather than defaulting to
|
|
25
|
+
`GET` or throwing from the helper.
|
|
26
|
+
- Require the expected production site and an exact lowercase 40-character
|
|
27
|
+
deployment tag from Cloudflare version metadata `tag`; expose that tag as
|
|
28
|
+
`X-Growth-Labs-Commit-SHA` without serializing Cloudflare version IDs or
|
|
29
|
+
timestamps.
|
|
30
|
+
- Require endpoint input bundles to carry an exact lowercase 40-character
|
|
31
|
+
`buildEvidence.commitSha` matching the deployment tag before returning any
|
|
32
|
+
success body or commit header. `buildEvidence.commitSha` is set from build
|
|
33
|
+
provenance independently of `versionMetadata.tag`; they are compared per
|
|
34
|
+
request and must match or the endpoint fails closed.
|
|
35
|
+
- Bound successful endpoint JSON responses to 1 MiB and return
|
|
36
|
+
`Content-Type: application/json; charset=utf-8`, `Cache-Control: private,
|
|
37
|
+
no-store`, and `X-Content-Type-Options: nosniff`.
|
|
38
|
+
- Fail closed with generic JSON for malformed bundles, wrong site or
|
|
39
|
+
environment, missing or malformed deployment tags, oversized evidence, and
|
|
40
|
+
internal exceptions.
|
|
41
|
+
- Serialize only the parsed v2 `SiteEvidenceBundle` schema so unknown schema
|
|
42
|
+
fields are stripped before the body is emitted.
|
|
43
|
+
- Document the consumer-owned sanitization boundary: the adapter does not
|
|
44
|
+
perform heuristic secret detection, and documented free-form finding or
|
|
45
|
+
receipt strings remain the consumer's responsibility.
|
|
46
|
+
|
|
47
|
+
## 0.4.0 — 2026-07-18
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- Add optional backward-compatible ownership fields to `publicationSurfaceSchema`:
|
|
52
|
+
`intendedOwner`, `observedOwner`, `ownerReceipt`, `observedCount`, and `minimumCount`.
|
|
53
|
+
- Add `publicationSurfaceOwnerSchema` and `publicationSurfaceOwnerReceiptSchema` exports.
|
|
54
|
+
- Add `publication.surface.static_shadow` finding: emitted when `intendedOwner=runtime` but
|
|
55
|
+
`observedOwner=static`, indicating the Worker is shadowed by a static asset (typically caused by
|
|
56
|
+
`assets.run_worker_first` not being set in `wrangler.toml`).
|
|
57
|
+
- Add `publication.surface.owner_mismatch` finding: emitted when `intendedOwner` and `observedOwner`
|
|
58
|
+
are both explicitly declared, neither is `'na'`, and they do not agree.
|
|
59
|
+
- Add `publication.surface.count_shortfall` finding: emitted when `observedCount < minimumCount`.
|
|
60
|
+
- Add required negative fixture `llms-runtime-static-shadow`: HTTP 200/nonempty `llms` surface with
|
|
61
|
+
`intendedOwner=runtime`, `observedOwner=static`, 14 static entries, 0 minimum dynamic entries.
|
|
62
|
+
Proves the static-shadow detection path before any positive code.
|
|
63
|
+
- The runner does not infer owner from response headers alone; both fields must be explicitly
|
|
64
|
+
declared by the fixture author or collector tool. Raw bodies and URLs are never retained in the
|
|
65
|
+
owner receipt.
|
|
66
|
+
- Document `assets.run_worker_first`, Astro/Cloudflare collector evidence, artifact inspection for
|
|
67
|
+
counts, and explicit `'na'` ownership in `packages-docs/conformance.md`.
|
|
68
|
+
|
|
3
69
|
## 0.3.1 — 2026-07-17
|
|
4
70
|
|
|
5
71
|
- Mark the `astro` peer dependency as optional (`peerDependenciesMeta.astro.optional: true`).
|
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ const fixture = {
|
|
|
87
87
|
},
|
|
88
88
|
buildEvidence: {
|
|
89
89
|
commitSha: 'bd39d718f6a5b0df9a249e11638a8b430050941e',
|
|
90
|
-
packageVersions: { '@growth-labs/conformance': '0.
|
|
90
|
+
packageVersions: { '@growth-labs/conformance': '0.5.0', '@growth-labs/seo': '0.9.0' },
|
|
91
91
|
staticHeaderPolicy: true,
|
|
92
92
|
ssrHeaderPolicy: true,
|
|
93
93
|
},
|
|
@@ -97,6 +97,50 @@ const siteBundle = runSiteConformance(fixture)
|
|
|
97
97
|
const fleetBundle = runFleetConformance([fixture])
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
+
## Deployment Endpoint Adapter
|
|
101
|
+
|
|
102
|
+
Consumers own the route, the conformance artifact, and the Cloudflare
|
|
103
|
+
`[version_metadata]` binding. The CI/build probe step runs
|
|
104
|
+
`runSiteConformance()`, serializes the result to a JSON artifact file, and
|
|
105
|
+
bundles that file with the Worker. The adapter reads the pre-built artifact at
|
|
106
|
+
module load (not per request) and serves it:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import artifact from './conformance-artifact.json' with { type: 'json' }
|
|
110
|
+
import { initConformanceEndpoint } from '@growth-labs/conformance/endpoint'
|
|
111
|
+
|
|
112
|
+
// Artifact produced by the CI probe step before deployment.
|
|
113
|
+
// Static import: a missing conformance-artifact.json is a build-time error —
|
|
114
|
+
// the Worker never starts if the artifact is absent.
|
|
115
|
+
// Artifact is parsed, schema-stripped, bounded, and serialized ONCE here.
|
|
116
|
+
const handler = initConformanceEndpoint(artifact, 'fronts')
|
|
117
|
+
|
|
118
|
+
// src/pages/.well-known/growth-labs-conformance.json.ts
|
|
119
|
+
export function GET({ locals, request }) {
|
|
120
|
+
return handler.handle({
|
|
121
|
+
method: request.method,
|
|
122
|
+
versionMetadata: locals.runtime.env.CF_VERSION_METADATA,
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const HEAD = GET
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`initConformanceEndpoint` parses the artifact, validates it against the v2
|
|
130
|
+
schema, checks `environment: 'production'` and the expected site, requires
|
|
131
|
+
`buildEvidence.commitSha` (lowercase 40-character hex) and
|
|
132
|
+
`buildEvidence.generatedAt` (timezone-qualified ISO-8601 datetime), and
|
|
133
|
+
serializes the schema-stripped body bytes once. Per-request handling only
|
|
134
|
+
validates the method and compares `versionMetadata.tag` against the baked commit
|
|
135
|
+
SHA — no I/O, no probe execution, no re-serialization. Missing/malformed
|
|
136
|
+
artifacts and wrong site/environment produce a handler that always returns 503.
|
|
137
|
+
The adapter never reads or serializes environment bindings, request headers,
|
|
138
|
+
Cloudflare version IDs, Cloudflare version timestamps, internal exceptions, or
|
|
139
|
+
fields outside the parsed v2 schema. It does not perform heuristic secret
|
|
140
|
+
detection: documented free-form strings such as finding messages, finding
|
|
141
|
+
evidence, remediation text, and receipt evidence remain unchanged and are the
|
|
142
|
+
consumer's sanitization responsibility.
|
|
143
|
+
|
|
100
144
|
## Shared Header Policy
|
|
101
145
|
|
|
102
146
|
Use `buildSharedPublicationHeaders()` when a site wants the package-owned
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const CONFORMANCE_ENDPOINT_MAX_BYTES: number;
|
|
2
|
+
export interface CloudflareVersionMetadataLike {
|
|
3
|
+
id?: unknown;
|
|
4
|
+
tag?: unknown;
|
|
5
|
+
timestamp?: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface DeploymentConformanceResponseOptions {
|
|
8
|
+
method: string;
|
|
9
|
+
bundle: unknown;
|
|
10
|
+
expectedSite: string;
|
|
11
|
+
versionMetadata?: CloudflareVersionMetadataLike | null;
|
|
12
|
+
}
|
|
13
|
+
export interface ConformanceEndpointHandler {
|
|
14
|
+
handle(options: {
|
|
15
|
+
method: unknown;
|
|
16
|
+
versionMetadata?: CloudflareVersionMetadataLike | null;
|
|
17
|
+
}): Response;
|
|
18
|
+
}
|
|
19
|
+
export declare function initConformanceEndpoint(artifact: unknown, expectedSite: string): ConformanceEndpointHandler;
|
|
20
|
+
export declare function createDeploymentConformanceResponse(options: DeploymentConformanceResponseOptions): Response;
|
|
21
|
+
//# sourceMappingURL=endpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../src/endpoint.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,8BAA8B,QAAc,CAAA;AAiBzD,MAAM,WAAW,6BAA6B;IAC7C,EAAE,CAAC,EAAE,OAAO,CAAA;IACZ,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,SAAS,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,oCAAoC;IACpD,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,6BAA6B,GAAG,IAAI,CAAA;CACtD;AAED,MAAM,WAAW,0BAA0B;IAC1C,MAAM,CAAC,OAAO,EAAE;QACf,MAAM,EAAE,OAAO,CAAA;QACf,eAAe,CAAC,EAAE,6BAA6B,GAAG,IAAI,CAAA;KACtD,GAAG,QAAQ,CAAA;CACZ;AAED,wBAAgB,uBAAuB,CACtC,QAAQ,EAAE,OAAO,EACjB,YAAY,EAAE,MAAM,GAClB,0BAA0B,CA+C5B;AAUD,wBAAgB,mCAAmC,CAClD,OAAO,EAAE,oCAAoC,GAC3C,QAAQ,CA8BV"}
|
package/dist/endpoint.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { buildEvidenceSchema, siteEvidenceBundleSchema } from './schema.js';
|
|
3
|
+
export const CONFORMANCE_ENDPOINT_MAX_BYTES = 1024 * 1024;
|
|
4
|
+
const COMMIT_SHA_PATTERN = /^[0-9a-f]{40}$/;
|
|
5
|
+
const CONTENT_TYPE = 'application/json; charset=utf-8';
|
|
6
|
+
const GENERIC_FAILURE_BODY = '{"status":"unavailable"}';
|
|
7
|
+
const INIT_FAILURE_DIAGNOSTIC = '[conformance] initConformanceEndpoint: artifact validation failed at init';
|
|
8
|
+
// Single stripping schema: validates endpoint buildEvidence and the v2 bundle together
|
|
9
|
+
// without touching schema-external fields. No .passthrough() — unknown fields are stripped.
|
|
10
|
+
const deploymentArtifactSchema = siteEvidenceBundleSchema.extend({
|
|
11
|
+
buildEvidence: buildEvidenceSchema.extend({
|
|
12
|
+
commitSha: z.string().regex(COMMIT_SHA_PATTERN),
|
|
13
|
+
generatedAt: z.string().datetime({ offset: true }),
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
export function initConformanceEndpoint(artifact, expectedSite) {
|
|
17
|
+
let capturedBody = null;
|
|
18
|
+
let capturedBuildCommitSha = null;
|
|
19
|
+
try {
|
|
20
|
+
const site = readExpectedSite(expectedSite);
|
|
21
|
+
const { buildEvidence, ...bundle } = deploymentArtifactSchema.parse(artifact);
|
|
22
|
+
if (bundle.site !== site || bundle.environment !== 'production') {
|
|
23
|
+
throw new Error('Conformance endpoint evidence does not match the expected production site.');
|
|
24
|
+
}
|
|
25
|
+
capturedBody = stringifyJsonBounded(bundle, CONFORMANCE_ENDPOINT_MAX_BYTES);
|
|
26
|
+
capturedBuildCommitSha = buildEvidence.commitSha;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
reportInitFailure();
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
handle(options) {
|
|
33
|
+
let isHead = false;
|
|
34
|
+
try {
|
|
35
|
+
const methodStr = readRequestMethod(options.method);
|
|
36
|
+
isHead = methodStr === 'HEAD';
|
|
37
|
+
if (methodStr !== 'GET' && methodStr !== 'HEAD') {
|
|
38
|
+
return genericFailureResponse(405, false, { Allow: 'GET, HEAD' });
|
|
39
|
+
}
|
|
40
|
+
if (capturedBody === null || capturedBuildCommitSha === null) {
|
|
41
|
+
throw new Error('Conformance endpoint artifact initialization failed.');
|
|
42
|
+
}
|
|
43
|
+
const commitSha = readDeploymentCommitSha(options.versionMetadata);
|
|
44
|
+
if (!commitShaEquals(capturedBuildCommitSha, commitSha)) {
|
|
45
|
+
throw new Error('Conformance endpoint build evidence does not match the deployment tag.');
|
|
46
|
+
}
|
|
47
|
+
return new Response(isHead ? null : capturedBody, {
|
|
48
|
+
status: 200,
|
|
49
|
+
headers: responseHeaders(commitSha),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return genericFailureResponse(503, isHead);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function reportInitFailure() {
|
|
59
|
+
try {
|
|
60
|
+
console.error(INIT_FAILURE_DIAGNOSTIC);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Logging must never turn a fail-closed handler into an import-time crash.
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function createDeploymentConformanceResponse(options) {
|
|
67
|
+
let isHead = false;
|
|
68
|
+
try {
|
|
69
|
+
const method = readRequestMethod(options.method);
|
|
70
|
+
isHead = method === 'HEAD';
|
|
71
|
+
if (method !== 'GET' && method !== 'HEAD') {
|
|
72
|
+
return genericFailureResponse(405, false, { Allow: 'GET, HEAD' });
|
|
73
|
+
}
|
|
74
|
+
const commitSha = readDeploymentCommitSha(options.versionMetadata);
|
|
75
|
+
const expectedSite = readExpectedSite(options.expectedSite);
|
|
76
|
+
const { buildEvidence, ...bundle } = deploymentArtifactSchema.parse(options.bundle);
|
|
77
|
+
if (bundle.site !== expectedSite || bundle.environment !== 'production') {
|
|
78
|
+
throw new Error('Conformance endpoint evidence does not match the expected production site.');
|
|
79
|
+
}
|
|
80
|
+
if (!commitShaEquals(buildEvidence.commitSha, commitSha)) {
|
|
81
|
+
throw new Error('Conformance endpoint build evidence does not match the deployment tag.');
|
|
82
|
+
}
|
|
83
|
+
const body = stringifyJsonBounded(bundle, CONFORMANCE_ENDPOINT_MAX_BYTES);
|
|
84
|
+
return new Response(isHead ? null : body, {
|
|
85
|
+
status: 200,
|
|
86
|
+
headers: responseHeaders(commitSha),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return genericFailureResponse(503, isHead);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function readRequestMethod(method) {
|
|
94
|
+
if (typeof method !== 'string') {
|
|
95
|
+
throw new Error('Request method is required.');
|
|
96
|
+
}
|
|
97
|
+
const normalizedMethod = method.trim().toUpperCase();
|
|
98
|
+
if (normalizedMethod.length === 0) {
|
|
99
|
+
throw new Error('Request method is required.');
|
|
100
|
+
}
|
|
101
|
+
return normalizedMethod;
|
|
102
|
+
}
|
|
103
|
+
function readExpectedSite(expectedSite) {
|
|
104
|
+
if (typeof expectedSite !== 'string' || expectedSite.trim().length === 0) {
|
|
105
|
+
throw new Error('Expected site identity is required.');
|
|
106
|
+
}
|
|
107
|
+
return expectedSite;
|
|
108
|
+
}
|
|
109
|
+
function readDeploymentCommitSha(versionMetadata) {
|
|
110
|
+
if (!versionMetadata || typeof versionMetadata !== 'object') {
|
|
111
|
+
throw new Error('Cloudflare version metadata is required.');
|
|
112
|
+
}
|
|
113
|
+
const { tag } = versionMetadata;
|
|
114
|
+
if (typeof tag !== 'string' || !COMMIT_SHA_PATTERN.test(tag)) {
|
|
115
|
+
throw new Error('Cloudflare version metadata tag must be a lowercase 40-character commit SHA.');
|
|
116
|
+
}
|
|
117
|
+
return tag;
|
|
118
|
+
}
|
|
119
|
+
function commitShaEquals(left, right) {
|
|
120
|
+
if (left.length !== right.length)
|
|
121
|
+
return false;
|
|
122
|
+
let difference = 0;
|
|
123
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
124
|
+
difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
|
|
125
|
+
}
|
|
126
|
+
return difference === 0;
|
|
127
|
+
}
|
|
128
|
+
function responseHeaders(commitSha) {
|
|
129
|
+
const headers = new Headers({
|
|
130
|
+
'Content-Type': CONTENT_TYPE,
|
|
131
|
+
'Cache-Control': 'private, no-store',
|
|
132
|
+
'X-Content-Type-Options': 'nosniff',
|
|
133
|
+
});
|
|
134
|
+
if (commitSha)
|
|
135
|
+
headers.set('X-Growth-Labs-Commit-SHA', commitSha);
|
|
136
|
+
return headers;
|
|
137
|
+
}
|
|
138
|
+
function genericFailureResponse(status, head, extraHeaders = {}) {
|
|
139
|
+
const headers = responseHeaders();
|
|
140
|
+
for (const [name, value] of Object.entries(extraHeaders))
|
|
141
|
+
headers.set(name, value);
|
|
142
|
+
return new Response(head ? null : GENERIC_FAILURE_BODY, { status, headers });
|
|
143
|
+
}
|
|
144
|
+
function stringifyJsonBounded(value, maxBytes) {
|
|
145
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) {
|
|
146
|
+
throw new RangeError('maxBytes must be a positive safe integer.');
|
|
147
|
+
}
|
|
148
|
+
const encoder = new TextEncoder();
|
|
149
|
+
const parts = [];
|
|
150
|
+
const seen = new Set();
|
|
151
|
+
let bytes = 0;
|
|
152
|
+
function append(part) {
|
|
153
|
+
const nextBytes = bytes + encoder.encode(part).byteLength;
|
|
154
|
+
if (nextBytes > maxBytes)
|
|
155
|
+
throw new RangeError('Conformance endpoint response is too large.');
|
|
156
|
+
bytes = nextBytes;
|
|
157
|
+
parts.push(part);
|
|
158
|
+
}
|
|
159
|
+
function writeJsonString(text) {
|
|
160
|
+
append(JSON.stringify(text));
|
|
161
|
+
}
|
|
162
|
+
function write(next) {
|
|
163
|
+
if (next === null) {
|
|
164
|
+
append('null');
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
switch (typeof next) {
|
|
168
|
+
case 'string':
|
|
169
|
+
writeJsonString(next);
|
|
170
|
+
return;
|
|
171
|
+
case 'number':
|
|
172
|
+
append(Number.isFinite(next) ? String(next) : 'null');
|
|
173
|
+
return;
|
|
174
|
+
case 'boolean':
|
|
175
|
+
append(next ? 'true' : 'false');
|
|
176
|
+
return;
|
|
177
|
+
case 'object':
|
|
178
|
+
writeObject(next);
|
|
179
|
+
return;
|
|
180
|
+
default:
|
|
181
|
+
throw new TypeError('Unsupported JSON value.');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function writeObject(next) {
|
|
185
|
+
if (seen.has(next))
|
|
186
|
+
throw new TypeError('Cannot serialize circular evidence.');
|
|
187
|
+
seen.add(next);
|
|
188
|
+
try {
|
|
189
|
+
if (Array.isArray(next)) {
|
|
190
|
+
append('[');
|
|
191
|
+
next.forEach((item, index) => {
|
|
192
|
+
if (index > 0)
|
|
193
|
+
append(',');
|
|
194
|
+
if (item === undefined || typeof item === 'function' || typeof item === 'symbol') {
|
|
195
|
+
append('null');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
write(item);
|
|
199
|
+
});
|
|
200
|
+
append(']');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
append('{');
|
|
204
|
+
let first = true;
|
|
205
|
+
for (const key of Object.keys(next)) {
|
|
206
|
+
const item = next[key];
|
|
207
|
+
if (item === undefined || typeof item === 'function' || typeof item === 'symbol')
|
|
208
|
+
continue;
|
|
209
|
+
if (!first)
|
|
210
|
+
append(',');
|
|
211
|
+
first = false;
|
|
212
|
+
append(JSON.stringify(key));
|
|
213
|
+
append(':');
|
|
214
|
+
write(item);
|
|
215
|
+
}
|
|
216
|
+
append('}');
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
seen.delete(next);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
write(value);
|
|
223
|
+
return parts.join('');
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../src/endpoint.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { type AstroCspConfig, type AstroCspPolicyOptions, type AstroCspResource, buildAstroCspConfig, buildCacheControl, buildContentSecurityPolicy, buildSharedPublicationHeaders, buildStrictTransportSecurity, type CachePolicyOptions, type ContentSecurityPolicyOptions, type CrossOriginOpenerPolicy, type CrossOriginResourcePolicy, collectHeaders, type HeaderPolicyOptions, isPrivateAudience, normalizeHeaders, REQUIRED_SECURITY_HEADERS, type StrictTransportSecurityOptions, } from './policy.js';
|
|
2
2
|
export { type RunConformanceOptions, runFleetConformance, runSiteConformance } from './runner.js';
|
|
3
|
-
export { type Audience, audienceSchema, type BuildEvidence, buildEvidenceSchema, type CacheVariant, type ConformanceCheckReceipt, type ConformanceFinding, type ConformanceFixture, type ConformanceFixtureInput, type CspReportReceipt, cacheVariantSchema, checkStatusSchema, conformanceCheckReceiptSchema, conformanceExpectedSchema, conformanceFindingSchema, conformanceFixtureSchema, cspReportReceiptSchema, EVIDENCE_SCHEMA_VERSION, type EvidenceSummary, evidenceSummarySchema, type FleetEvidenceBundle, findingSeveritySchema, fleetEvidenceBundleSchema, type HeaderMap, headerMapSchema, headerValueSchema, type InlineStyleAttributeInventory, inlineStyleAttributeInventorySchema, type PublicationSurfaceEvidence, parseConformanceFixture, publicationSurfaceSchema, REQUIRED_FUNCTIONAL_PROBE_NAMES, REQUIRED_NEGATIVE_FIXTURE_CODES, type RenderMode, type RequiredNegativeFindingCode, type RequiredNegativeFixtureId, renderModeSchema, type SecurityFunctionalProbeReceipt, type SecurityReceipts, type SiteEvidenceBundle, type SurfaceResponse, securityFunctionalProbeReceiptSchema, securityReceiptsSchema, siteEvidenceBundleSchema, surfaceResponseSchema, validateFleetEvidenceBundle, validateSiteEvidenceBundle, } from './schema.js';
|
|
3
|
+
export { type Audience, audienceSchema, type BuildEvidence, buildEvidenceSchema, type CacheVariant, type ConformanceCheckReceipt, type ConformanceFinding, type ConformanceFixture, type ConformanceFixtureInput, type CspReportReceipt, cacheVariantSchema, checkStatusSchema, conformanceCheckReceiptSchema, conformanceExpectedSchema, conformanceFindingSchema, conformanceFixtureSchema, cspReportReceiptSchema, EVIDENCE_SCHEMA_VERSION, type EvidenceSummary, evidenceSummarySchema, type FleetEvidenceBundle, findingSeveritySchema, fleetEvidenceBundleSchema, type HeaderMap, headerMapSchema, headerValueSchema, type InlineStyleAttributeInventory, inlineStyleAttributeInventorySchema, type PublicationSurfaceEvidence, type PublicationSurfaceOwner, type PublicationSurfaceOwnerReceipt, parseConformanceFixture, publicationSurfaceOwnerReceiptSchema, publicationSurfaceOwnerSchema, publicationSurfaceSchema, REQUIRED_FUNCTIONAL_PROBE_NAMES, REQUIRED_NEGATIVE_FIXTURE_CODES, type RenderMode, type RequiredNegativeFindingCode, type RequiredNegativeFixtureId, renderModeSchema, type SecurityFunctionalProbeReceipt, type SecurityReceipts, type SiteEvidenceBundle, type SurfaceResponse, securityFunctionalProbeReceiptSchema, securityReceiptsSchema, siteEvidenceBundleSchema, surfaceResponseSchema, validateFleetEvidenceBundle, validateSiteEvidenceBundle, } from './schema.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,0BAA0B,EAC1B,6BAA6B,EAC7B,4BAA4B,EAC5B,KAAK,kBAAkB,EACvB,KAAK,4BAA4B,EACjC,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,cAAc,EACd,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EACzB,KAAK,8BAA8B,GACnC,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,KAAK,qBAAqB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACjG,OAAO,EACN,KAAK,QAAQ,EACb,cAAc,EACd,KAAK,aAAa,EAClB,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,KAAK,SAAS,EACd,eAAe,EACf,iBAAiB,EACjB,KAAK,6BAA6B,EAClC,mCAAmC,EACnC,KAAK,0BAA0B,EAC/B,uBAAuB,EACvB,wBAAwB,EACxB,+BAA+B,EAC/B,+BAA+B,EAC/B,KAAK,UAAU,EACf,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,EAC9B,gBAAgB,EAChB,KAAK,8BAA8B,EACnC,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,oCAAoC,EACpC,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,GAC1B,MAAM,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,0BAA0B,EAC1B,6BAA6B,EAC7B,4BAA4B,EAC5B,KAAK,kBAAkB,EACvB,KAAK,4BAA4B,EACjC,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,cAAc,EACd,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EACzB,KAAK,8BAA8B,GACnC,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,KAAK,qBAAqB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACjG,OAAO,EACN,KAAK,QAAQ,EACb,cAAc,EACd,KAAK,aAAa,EAClB,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,KAAK,SAAS,EACd,eAAe,EACf,iBAAiB,EACjB,KAAK,6BAA6B,EAClC,mCAAmC,EACnC,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACnC,uBAAuB,EACvB,oCAAoC,EACpC,6BAA6B,EAC7B,wBAAwB,EACxB,+BAA+B,EAC/B,+BAA+B,EAC/B,KAAK,UAAU,EACf,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,EAC9B,gBAAgB,EAChB,KAAK,8BAA8B,EACnC,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,oCAAoC,EACpC,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,GAC1B,MAAM,aAAa,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { buildAstroCspConfig, buildCacheControl, buildContentSecurityPolicy, buildSharedPublicationHeaders, buildStrictTransportSecurity, collectHeaders, isPrivateAudience, normalizeHeaders, REQUIRED_SECURITY_HEADERS, } from './policy.js';
|
|
2
2
|
export { runFleetConformance, runSiteConformance } from './runner.js';
|
|
3
|
-
export { audienceSchema, buildEvidenceSchema, cacheVariantSchema, checkStatusSchema, conformanceCheckReceiptSchema, conformanceExpectedSchema, conformanceFindingSchema, conformanceFixtureSchema, cspReportReceiptSchema, EVIDENCE_SCHEMA_VERSION, evidenceSummarySchema, findingSeveritySchema, fleetEvidenceBundleSchema, headerMapSchema, headerValueSchema, inlineStyleAttributeInventorySchema, parseConformanceFixture, publicationSurfaceSchema, REQUIRED_FUNCTIONAL_PROBE_NAMES, REQUIRED_NEGATIVE_FIXTURE_CODES, renderModeSchema, securityFunctionalProbeReceiptSchema, securityReceiptsSchema, siteEvidenceBundleSchema, surfaceResponseSchema, validateFleetEvidenceBundle, validateSiteEvidenceBundle, } from './schema.js';
|
|
3
|
+
export { audienceSchema, buildEvidenceSchema, cacheVariantSchema, checkStatusSchema, conformanceCheckReceiptSchema, conformanceExpectedSchema, conformanceFindingSchema, conformanceFixtureSchema, cspReportReceiptSchema, EVIDENCE_SCHEMA_VERSION, evidenceSummarySchema, findingSeveritySchema, fleetEvidenceBundleSchema, headerMapSchema, headerValueSchema, inlineStyleAttributeInventorySchema, parseConformanceFixture, publicationSurfaceOwnerReceiptSchema, publicationSurfaceOwnerSchema, publicationSurfaceSchema, REQUIRED_FUNCTIONAL_PROBE_NAMES, REQUIRED_NEGATIVE_FIXTURE_CODES, renderModeSchema, securityFunctionalProbeReceiptSchema, securityReceiptsSchema, siteEvidenceBundleSchema, surfaceResponseSchema, validateFleetEvidenceBundle, validateSiteEvidenceBundle, } from './schema.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,mBAAmB,EACnB,iBAAiB,EACjB,0BAA0B,EAC1B,6BAA6B,EAC7B,4BAA4B,EAK5B,cAAc,EAEd,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,GAEzB,MAAM,aAAa,CAAA;AACpB,OAAO,EAA8B,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACjG,OAAO,EAEN,cAAc,EAEd,mBAAmB,EAOnB,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EAEvB,qBAAqB,EAErB,qBAAqB,EACrB,yBAAyB,EAEzB,eAAe,EACf,iBAAiB,EAEjB,mCAAmC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,mBAAmB,EACnB,iBAAiB,EACjB,0BAA0B,EAC1B,6BAA6B,EAC7B,4BAA4B,EAK5B,cAAc,EAEd,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,GAEzB,MAAM,aAAa,CAAA;AACpB,OAAO,EAA8B,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACjG,OAAO,EAEN,cAAc,EAEd,mBAAmB,EAOnB,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EAEvB,qBAAqB,EAErB,qBAAqB,EACrB,yBAAyB,EAEzB,eAAe,EACf,iBAAiB,EAEjB,mCAAmC,EAInC,uBAAuB,EACvB,oCAAoC,EACpC,6BAA6B,EAC7B,wBAAwB,EACxB,+BAA+B,EAC/B,+BAA+B,EAI/B,gBAAgB,EAKhB,oCAAoC,EACpC,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,2BAA2B,EAC3B,0BAA0B,GAC1B,MAAM,aAAa,CAAA"}
|
package/dist/runner.js
CHANGED
|
@@ -825,7 +825,7 @@ function checkPublicationSurfaces(fixture) {
|
|
|
825
825
|
findings.push({
|
|
826
826
|
code: 'publication.surface.missing',
|
|
827
827
|
severity: 'error',
|
|
828
|
-
message:
|
|
828
|
+
message: 'Required publication surface is missing or not declared NA.',
|
|
829
829
|
path: `publicationSurfaces.${required}`,
|
|
830
830
|
});
|
|
831
831
|
}
|
|
@@ -839,7 +839,6 @@ function checkPublicationSurfaces(fixture) {
|
|
|
839
839
|
severity: 'error',
|
|
840
840
|
message: 'NA publication surfaces require a capability boundary and evidence.',
|
|
841
841
|
path,
|
|
842
|
-
evidence: surface.name,
|
|
843
842
|
remediation: 'Declare why the site cannot provide the surface and attach supporting evidence.',
|
|
844
843
|
});
|
|
845
844
|
}
|
|
@@ -849,7 +848,7 @@ function checkPublicationSurfaces(fixture) {
|
|
|
849
848
|
findings.push({
|
|
850
849
|
code: 'publication.surface.missing',
|
|
851
850
|
severity: 'error',
|
|
852
|
-
message:
|
|
851
|
+
message: 'Publication surface is missing.',
|
|
853
852
|
path,
|
|
854
853
|
});
|
|
855
854
|
return;
|
|
@@ -858,18 +857,85 @@ function checkPublicationSurfaces(fixture) {
|
|
|
858
857
|
findings.push({
|
|
859
858
|
code: 'publication.surface.http_error',
|
|
860
859
|
severity: 'error',
|
|
861
|
-
message:
|
|
860
|
+
message: 'Publication surface returned an HTTP error.',
|
|
862
861
|
path: `${path}.httpStatus`,
|
|
862
|
+
evidence: `httpStatus=${surface.httpStatus}`,
|
|
863
863
|
});
|
|
864
864
|
}
|
|
865
865
|
if (surface.bodyBytes !== undefined && surface.bodyBytes === 0) {
|
|
866
866
|
findings.push({
|
|
867
867
|
code: 'publication.surface.empty',
|
|
868
868
|
severity: 'error',
|
|
869
|
-
message:
|
|
869
|
+
message: 'Publication surface has an empty body.',
|
|
870
870
|
path: `${path}.bodyBytes`,
|
|
871
871
|
});
|
|
872
872
|
}
|
|
873
|
+
const { intendedOwner, observedOwner } = surface;
|
|
874
|
+
const hasIntended = intendedOwner !== undefined;
|
|
875
|
+
const hasObserved = observedOwner !== undefined;
|
|
876
|
+
if (hasIntended !== hasObserved) {
|
|
877
|
+
findings.push({
|
|
878
|
+
code: 'publication.surface.owner_pair_incomplete',
|
|
879
|
+
severity: 'error',
|
|
880
|
+
message: 'Publication surface ownership requires both intendedOwner and observedOwner.',
|
|
881
|
+
path: hasIntended ? `${path}.observedOwner` : `${path}.intendedOwner`,
|
|
882
|
+
remediation: 'Declare both intendedOwner and observedOwner together, or omit both for legacy surfaces.',
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
else if (hasIntended && hasObserved && intendedOwner !== 'na' && observedOwner !== 'na') {
|
|
886
|
+
if (!surface.ownerReceipt) {
|
|
887
|
+
findings.push({
|
|
888
|
+
code: 'publication.surface.owner_receipt_missing',
|
|
889
|
+
severity: 'error',
|
|
890
|
+
message: 'Publication surface ownership requires a deterministic receipt when ownership is declared.',
|
|
891
|
+
path: `${path}.ownerReceipt`,
|
|
892
|
+
remediation: 'Attach a privacy-safe receipt with a versioned collector, observedAt timestamp, and signalHash.',
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
if (intendedOwner !== observedOwner) {
|
|
896
|
+
if (intendedOwner === 'runtime' && observedOwner === 'static') {
|
|
897
|
+
findings.push({
|
|
898
|
+
code: 'publication.surface.static_shadow',
|
|
899
|
+
severity: 'error',
|
|
900
|
+
message: 'Publication surface is intended to be runtime-owned but is served from static assets.',
|
|
901
|
+
path: `${path}.observedOwner`,
|
|
902
|
+
evidence: 'intended=runtime; observed=static',
|
|
903
|
+
remediation: 'Set assets.run_worker_first = true in wrangler.toml so the Worker handles requests before static assets.',
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
else {
|
|
907
|
+
findings.push({
|
|
908
|
+
code: 'publication.surface.owner_mismatch',
|
|
909
|
+
severity: 'error',
|
|
910
|
+
message: 'Publication surface intended owner does not match observed owner.',
|
|
911
|
+
path: `${path}.observedOwner`,
|
|
912
|
+
evidence: `intended=${intendedOwner}; observed=${observedOwner}`,
|
|
913
|
+
remediation: 'Verify the routing configuration ensures the intended owner handles requests for this surface.',
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
if (surface.minimumCount !== undefined && surface.observedCount === undefined) {
|
|
919
|
+
findings.push({
|
|
920
|
+
code: 'publication.surface.count_dimension_incomplete',
|
|
921
|
+
severity: 'error',
|
|
922
|
+
message: 'Publication surface count minimum requires both observedCount and minimumCount.',
|
|
923
|
+
path: `${path}.observedCount`,
|
|
924
|
+
remediation: 'Provide both observedCount and minimumCount, or omit both for surfaces without a count contract.',
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
else if (surface.minimumCount !== undefined &&
|
|
928
|
+
surface.observedCount !== undefined &&
|
|
929
|
+
surface.observedCount < surface.minimumCount) {
|
|
930
|
+
findings.push({
|
|
931
|
+
code: 'publication.surface.count_shortfall',
|
|
932
|
+
severity: 'error',
|
|
933
|
+
message: 'Publication surface has fewer entries than the required minimum.',
|
|
934
|
+
path: `${path}.observedCount`,
|
|
935
|
+
evidence: `observed=${surface.observedCount}; minimum=${surface.minimumCount}`,
|
|
936
|
+
remediation: 'Verify the surface is populated with the expected number of entries by the intended owner.',
|
|
937
|
+
});
|
|
938
|
+
}
|
|
873
939
|
});
|
|
874
940
|
return receipt('publication-surfaces', findings);
|
|
875
941
|
}
|