@growth-labs/conformance 0.1.0 → 0.3.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 +46 -0
- package/README.md +113 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/policy.d.ts +54 -3
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +134 -10
- package/dist/policy.js.map +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +582 -15
- package/dist/runner.js.map +1 -1
- package/dist/schema.d.ts +829 -12
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +117 -1
- package/dist/schema.js.map +1 -1
- package/fixtures/negative/required-negative-fixtures.json +142 -0
- package/fixtures/valid/public-article.json +56 -2
- package/package.json +7 -1
- package/src/index.ts +19 -0
- package/src/policy.ts +203 -12
- package/src/runner.ts +673 -14
- package/src/schema.ts +132 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# @growth-labs/conformance Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-07-17
|
|
4
|
+
|
|
5
|
+
- Add `buildAstroCspConfig()` for Astro 7.1+ native SHA-256 CSP generation with
|
|
6
|
+
exact external-origin validation and no wildcard or `unsafe-*` escape hatch.
|
|
7
|
+
Its return shape is compile-checked against Astro's exported CSP config type,
|
|
8
|
+
and a real Astro build proves the attribute-only directive is emitted.
|
|
9
|
+
- Allow Astro 7.1+ consumers with a proven inline-style-attribute inventory to
|
|
10
|
+
scope `'unsafe-inline'` to `style-src-attr` only. Script and style-element
|
|
11
|
+
execution remain hash-protected and fail closed. The runner requires the
|
|
12
|
+
inventory receipt to match the exact build commit. The policy API requires
|
|
13
|
+
that structured receipt rather than a boolean escape hatch, including a
|
|
14
|
+
versioned scanner identity and SHA-256 output hash.
|
|
15
|
+
- Require canonical lowercase commit SHAs, SHA-256 evidence hashes, and CSP
|
|
16
|
+
hash algorithm tokens in security evidence.
|
|
17
|
+
- Let consumers set `contentSecurityPolicy: false` on
|
|
18
|
+
`buildSharedPublicationHeaders()` when Astro owns the per-response hash CSP;
|
|
19
|
+
all other shared response headers remain package-owned.
|
|
20
|
+
- Add an explicit per-fixture frame policy contract. The default remains
|
|
21
|
+
`frame-ancestors 'none'` plus `X-Frame-Options: DENY`; deliberately embeddable
|
|
22
|
+
routes may declare only `'self'`, `https:`, or exact HTTPS origins and must
|
|
23
|
+
omit a conflicting legacy frame header. The runner validates the CSP sources
|
|
24
|
+
exactly rather than accepting a fleet-wide relaxation.
|
|
25
|
+
|
|
26
|
+
## 0.2.0 — 2026-07-16
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- Added schema v2 security receipts for consumer-supplied enforced-CSP
|
|
31
|
+
functional probes and CSP reporting/canary evidence.
|
|
32
|
+
- Added required COOP/CORP response headers, conservative shared policy
|
|
33
|
+
defaults, and documented consumer overrides for verified auth/media/embed
|
|
34
|
+
constraints.
|
|
35
|
+
- Added required negative fixtures for missing COOP/CORP, HSTS below one year,
|
|
36
|
+
wildcard `default-src`, `unsafe-eval`, executable inline scripts without a
|
|
37
|
+
matching nonce or SHA-256 hash, conflicting duplicate security headers,
|
|
38
|
+
missing functional-probe receipts, and missing/failed CSP-report receipts.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- HSTS validation now requires `max-age >= 31536000`.
|
|
43
|
+
- `buildSharedPublicationHeaders()` now keeps `includeSubDomains` and `preload`
|
|
44
|
+
opt-in behind explicit host-inventory proof instead of emitting them by
|
|
45
|
+
default.
|
|
46
|
+
- CSP validation now parses directives instead of substring-matching the raw
|
|
47
|
+
header.
|
|
48
|
+
|
|
3
49
|
## 0.1.0 — 2026-07-15
|
|
4
50
|
|
|
5
51
|
### Added
|
package/README.md
CHANGED
|
@@ -30,7 +30,9 @@ const fixture = {
|
|
|
30
30
|
status: 200,
|
|
31
31
|
headers: {
|
|
32
32
|
'content-security-policy': "default-src 'self'; script-src 'self' 'nonce-runtime'",
|
|
33
|
-
'strict-transport-security': 'max-age=31536000
|
|
33
|
+
'strict-transport-security': 'max-age=31536000',
|
|
34
|
+
'cross-origin-opener-policy': 'same-origin',
|
|
35
|
+
'cross-origin-resource-policy': 'same-origin',
|
|
34
36
|
'x-frame-options': 'DENY',
|
|
35
37
|
'x-content-type-options': 'nosniff',
|
|
36
38
|
'referrer-policy': 'strict-origin-when-cross-origin',
|
|
@@ -43,6 +45,10 @@ const fixture = {
|
|
|
43
45
|
canonicalUrl: 'https://fronts.co/example',
|
|
44
46
|
schemaTypes: ['NewsArticle'],
|
|
45
47
|
discoverEligible: true,
|
|
48
|
+
framePolicy: {
|
|
49
|
+
ancestors: ["'none'"],
|
|
50
|
+
legacyHeader: 'DENY',
|
|
51
|
+
},
|
|
46
52
|
},
|
|
47
53
|
publicationSurfaces: [
|
|
48
54
|
{ name: 'sitemap', status: 'present', httpStatus: 200, bodyBytes: 1024 },
|
|
@@ -53,9 +59,35 @@ const fixture = {
|
|
|
53
59
|
{ audience: 'public', cacheKey: 'fronts:public:/example' },
|
|
54
60
|
{ audience: 'crawler', cacheKey: 'fronts:crawler:/example' },
|
|
55
61
|
],
|
|
62
|
+
securityReceipts: {
|
|
63
|
+
functionalProbes: [
|
|
64
|
+
{ name: 'oauth', status: 'pass', evidence: 'sanitized consumer probe receipt' },
|
|
65
|
+
{ name: 'media', status: 'pass', evidence: 'sanitized consumer probe receipt' },
|
|
66
|
+
{ name: 'images', status: 'pass', evidence: 'sanitized consumer probe receipt' },
|
|
67
|
+
{ name: 'analytics', status: 'pass', evidence: 'sanitized consumer probe receipt' },
|
|
68
|
+
{ name: 'embeds', status: 'pass', evidence: 'sanitized consumer probe receipt' },
|
|
69
|
+
{ name: 'error-pages', status: 'pass', evidence: 'sanitized consumer probe receipt' },
|
|
70
|
+
],
|
|
71
|
+
cspReports: [
|
|
72
|
+
{
|
|
73
|
+
name: 'csp-report-canary',
|
|
74
|
+
status: 'pass',
|
|
75
|
+
endpoint: 'consumer-owned-report-endpoint',
|
|
76
|
+
evidence: 'sanitized CSP report or blocked-canary receipt',
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
inlineStyleAttributes: {
|
|
80
|
+
commitSha: 'bd39d718f6a5b0df9a249e11638a8b430050941e',
|
|
81
|
+
occurrenceCount: 4,
|
|
82
|
+
evidence: {
|
|
83
|
+
tool: 'platform-foundations:inline-style-inventory@1',
|
|
84
|
+
outputHash: 'sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
56
88
|
buildEvidence: {
|
|
57
89
|
commitSha: 'bd39d718f6a5b0df9a249e11638a8b430050941e',
|
|
58
|
-
packageVersions: { '@growth-labs/seo': '0.9.0' },
|
|
90
|
+
packageVersions: { '@growth-labs/conformance': '0.3.0', '@growth-labs/seo': '0.9.0' },
|
|
59
91
|
staticHeaderPolicy: true,
|
|
60
92
|
ssrHeaderPolicy: true,
|
|
61
93
|
},
|
|
@@ -68,25 +100,81 @@ const fleetBundle = runFleetConformance([fixture])
|
|
|
68
100
|
## Shared Header Policy
|
|
69
101
|
|
|
70
102
|
Use `buildSharedPublicationHeaders()` when a site wants the package-owned
|
|
71
|
-
baseline for SSR and static response headers
|
|
103
|
+
baseline for SSR and static response headers. Astro 7.1+ sites should let Astro
|
|
104
|
+
own the per-route hash CSP and retain the remaining shared headers. The helper's
|
|
105
|
+
peer contract is intentionally pinned to the first Astro release that supports
|
|
106
|
+
attribute-scoped style resources:
|
|
72
107
|
|
|
73
108
|
```ts
|
|
74
|
-
import {
|
|
109
|
+
import {
|
|
110
|
+
buildAstroCspConfig,
|
|
111
|
+
buildSharedPublicationHeaders,
|
|
112
|
+
} from '@growth-labs/conformance/policy'
|
|
113
|
+
|
|
114
|
+
const csp = buildAstroCspConfig({
|
|
115
|
+
scriptSources: ['https://challenges.cloudflare.com'],
|
|
116
|
+
styleSources: ['https://fonts.googleapis.com'],
|
|
117
|
+
inlineStyleAttributes: {
|
|
118
|
+
commitSha: 'bd39d718f6a5b0df9a249e11638a8b430050941e',
|
|
119
|
+
occurrenceCount: 4,
|
|
120
|
+
evidence: {
|
|
121
|
+
tool: 'platform-foundations:inline-style-inventory@1',
|
|
122
|
+
outputHash: 'sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
})
|
|
75
126
|
|
|
76
127
|
const headers = buildSharedPublicationHeaders({
|
|
77
128
|
renderMode: 'ssr',
|
|
78
129
|
audience: 'public',
|
|
79
|
-
|
|
130
|
+
contentSecurityPolicy: false,
|
|
80
131
|
markdownTwinUrl: 'https://example.com/article.md',
|
|
81
132
|
})
|
|
82
133
|
```
|
|
83
134
|
|
|
135
|
+
The fixture default is the non-embeddable policy above. For a deliberately
|
|
136
|
+
embeddable route, declare its exact response class and omit a conflicting
|
|
137
|
+
`X-Frame-Options` header:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
expected: {
|
|
141
|
+
framePolicy: {
|
|
142
|
+
ancestors: ['https://trusted.example'],
|
|
143
|
+
legacyHeader: 'omit',
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Accepted ancestors are `'none'`, `'self'`, `https:`, and exact HTTPS origins;
|
|
149
|
+
wildcards, paths, credentials, query strings, and fragments are rejected.
|
|
150
|
+
`DENY` is valid only with `'none'`, and `SAMEORIGIN` only with `'self'`; broader
|
|
151
|
+
embeddable policies must use `legacyHeader: 'omit'` to avoid contradictory
|
|
152
|
+
browser behavior.
|
|
153
|
+
|
|
154
|
+
Astro 7.1+ consumers that prove they still emit HTML `style` attributes may set
|
|
155
|
+
`inlineStyleAttributes` to the validated inventory receipt. There is no boolean
|
|
156
|
+
escape hatch. The helper then scopes `'unsafe-inline'` to `style-src-attr`
|
|
157
|
+
while preserving hash protection for scripts and `<style>` elements. The
|
|
158
|
+
receipt requires the exact lowercase 40-character build commit SHA, a positive
|
|
159
|
+
occurrence count, the versioned scanner identity, and the lowercase SHA-256
|
|
160
|
+
content hash of its machine output. The same receipt must appear in the
|
|
161
|
+
conformance fixture and its commit must match `buildEvidence.commitSha`. Do not
|
|
162
|
+
enable this option as a generic compatibility fix.
|
|
163
|
+
|
|
84
164
|
The policy emits CSP, HSTS, frame protection, MIME sniffing protection,
|
|
85
|
-
referrer policy, permissions policy, cache semantics, and optional
|
|
86
|
-
twin `Link` metadata. Private audiences use `private, no-store`;
|
|
87
|
-
uses short shared-cache semantics; public static surfaces get longer
|
|
165
|
+
COOP, CORP, referrer policy, permissions policy, cache semantics, and optional
|
|
166
|
+
markdown twin `Link` metadata. Private audiences use `private, no-store`;
|
|
167
|
+
public SSR uses short shared-cache semantics; public static surfaces get longer
|
|
88
168
|
shared-cache semantics.
|
|
89
169
|
|
|
170
|
+
HSTS defaults to `max-age=31536000` only. Add `includeSubDomains` and `preload`
|
|
171
|
+
through `strictTransportSecurity: { includeSubDomains: true, preload: true }`
|
|
172
|
+
only after the consumer has separately verified the full host inventory can
|
|
173
|
+
enforce HTTPS. COOP defaults to `same-origin` and CORP defaults to
|
|
174
|
+
`same-origin`; consumers may override them only when verified OAuth popup,
|
|
175
|
+
media, or embed constraints require a looser policy and the receipt proves the
|
|
176
|
+
result under enforced CSP.
|
|
177
|
+
|
|
90
178
|
## Fixture Commands
|
|
91
179
|
|
|
92
180
|
The root repo exposes:
|
|
@@ -100,6 +188,16 @@ The fixture command proves the required negative fixtures fail loudly with
|
|
|
100
188
|
stable finding codes:
|
|
101
189
|
|
|
102
190
|
- `csp-unsafe-inline`
|
|
191
|
+
- `missing-coop`
|
|
192
|
+
- `missing-corp`
|
|
193
|
+
- `hsts-below-one-year`
|
|
194
|
+
- `csp-wildcard-default-src`
|
|
195
|
+
- `csp-unsafe-eval`
|
|
196
|
+
- `csp-inline-executable-without-nonce-or-hash`
|
|
197
|
+
- `conflicting-duplicate-security-header`
|
|
198
|
+
- `missing-functional-probe-receipt`
|
|
199
|
+
- `missing-csp-report-receipt`
|
|
200
|
+
- `failed-csp-report-receipt`
|
|
103
201
|
- `headers-static-only-while-ssr-missing`
|
|
104
202
|
- `undeclared-na`
|
|
105
203
|
- `stringified-is-accessible-for-free`
|
|
@@ -114,5 +212,11 @@ stable finding codes:
|
|
|
114
212
|
|
|
115
213
|
`runSiteConformance()` returns a `SiteEvidenceBundle`; `runFleetConformance()`
|
|
116
214
|
returns a `FleetEvidenceBundle`. Both are validated by exported Zod schemas
|
|
117
|
-
and carry `schemaVersion: "growth-labs.conformance.
|
|
215
|
+
and carry `schemaVersion: "growth-labs.conformance.v2"` so downstream jobs can
|
|
118
216
|
parse them without relying on console text.
|
|
217
|
+
|
|
218
|
+
Schema v2 adds `securityReceipts` to fixtures and site evidence bundles. Existing
|
|
219
|
+
v1 fixtures must add explicit functional-probe receipts for `oauth`, `media`,
|
|
220
|
+
`images`, `analytics`, `embeds`, and `error-pages`, plus at least one passing CSP
|
|
221
|
+
reporting/canary receipt. The package does not perform those live probes itself;
|
|
222
|
+
consumer CI supplies sanitized pass/fail/NA receipts.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildCacheControl, buildContentSecurityPolicy, buildSharedPublicationHeaders, type CachePolicyOptions, type HeaderPolicyOptions, isPrivateAudience, normalizeHeaders, REQUIRED_SECURITY_HEADERS, } from './policy.js';
|
|
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, cacheVariantSchema, checkStatusSchema, conformanceCheckReceiptSchema, conformanceExpectedSchema, conformanceFindingSchema, conformanceFixtureSchema, EVIDENCE_SCHEMA_VERSION, type EvidenceSummary, evidenceSummarySchema, type FleetEvidenceBundle, findingSeveritySchema, fleetEvidenceBundleSchema, type HeaderMap, headerMapSchema, headerValueSchema, type PublicationSurfaceEvidence, parseConformanceFixture, publicationSurfaceSchema, REQUIRED_NEGATIVE_FIXTURE_CODES, type RenderMode, type RequiredNegativeFindingCode, type RequiredNegativeFixtureId, renderModeSchema, type SiteEvidenceBundle, type SurfaceResponse, 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, 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';
|
|
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,iBAAiB,EACjB,0BAA0B,EAC1B,6BAA6B,EAC7B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,
|
|
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"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildCacheControl, buildContentSecurityPolicy, buildSharedPublicationHeaders, isPrivateAudience, normalizeHeaders, REQUIRED_SECURITY_HEADERS, } from './policy.js';
|
|
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, EVIDENCE_SCHEMA_VERSION, evidenceSummarySchema, findingSeveritySchema, fleetEvidenceBundleSchema, headerMapSchema, headerValueSchema, parseConformanceFixture, publicationSurfaceSchema, REQUIRED_NEGATIVE_FIXTURE_CODES, renderModeSchema, 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, 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,
|
|
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,EAEnC,uBAAuB,EACvB,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/policy.d.ts
CHANGED
|
@@ -1,18 +1,69 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { AstroConfig } from 'astro';
|
|
2
|
+
import { type Audience, type HeaderMap, type InlineStyleAttributeInventory, type RenderMode } from './schema.js';
|
|
3
|
+
export declare const REQUIRED_SECURITY_HEADERS: readonly ["content-security-policy", "strict-transport-security", "cross-origin-opener-policy", "cross-origin-resource-policy", "x-frame-options", "x-content-type-options", "referrer-policy", "permissions-policy"];
|
|
4
|
+
export type CrossOriginOpenerPolicy = 'same-origin' | 'same-origin-allow-popups' | 'unsafe-none';
|
|
5
|
+
export type CrossOriginResourcePolicy = 'same-origin' | 'same-site' | 'cross-origin';
|
|
6
|
+
export interface StrictTransportSecurityOptions {
|
|
7
|
+
maxAgeSeconds?: number;
|
|
8
|
+
includeSubDomains?: boolean;
|
|
9
|
+
preload?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ContentSecurityPolicyOptions {
|
|
12
|
+
nonce?: string;
|
|
13
|
+
reportUri?: string;
|
|
14
|
+
reportTo?: string;
|
|
15
|
+
}
|
|
3
16
|
export interface HeaderPolicyOptions {
|
|
4
17
|
renderMode: RenderMode;
|
|
5
18
|
audience: Audience;
|
|
6
19
|
nonce?: string;
|
|
20
|
+
cspReportUri?: string;
|
|
21
|
+
cspReportTo?: string;
|
|
22
|
+
contentSecurityPolicy?: false | ContentSecurityPolicyOptions;
|
|
23
|
+
strictTransportSecurity?: StrictTransportSecurityOptions;
|
|
24
|
+
crossOriginOpenerPolicy?: CrossOriginOpenerPolicy;
|
|
25
|
+
crossOriginResourcePolicy?: CrossOriginResourcePolicy;
|
|
7
26
|
markdownTwinUrl?: string;
|
|
8
27
|
}
|
|
28
|
+
export interface AstroCspPolicyOptions {
|
|
29
|
+
scriptSources?: readonly string[];
|
|
30
|
+
styleSources?: readonly string[];
|
|
31
|
+
inlineStyleAttributes?: InlineStyleAttributeInventory;
|
|
32
|
+
imgSources?: readonly string[];
|
|
33
|
+
fontSources?: readonly string[];
|
|
34
|
+
connectSources?: readonly string[];
|
|
35
|
+
mediaSources?: readonly string[];
|
|
36
|
+
frameSources?: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
type AstroNativeCspConfig = Exclude<NonNullable<NonNullable<AstroConfig['security']>['csp']>, boolean>;
|
|
39
|
+
type AstroCspDirective = NonNullable<AstroNativeCspConfig['directives']>[number];
|
|
40
|
+
export type AstroCspResource = NonNullable<NonNullable<AstroNativeCspConfig['styleDirective']>['resources']>[number];
|
|
41
|
+
export interface AstroCspConfig {
|
|
42
|
+
algorithm: 'SHA-256';
|
|
43
|
+
directives: AstroCspDirective[];
|
|
44
|
+
scriptDirective: {
|
|
45
|
+
resources: string[];
|
|
46
|
+
};
|
|
47
|
+
styleDirective: {
|
|
48
|
+
resources: AstroCspResource[];
|
|
49
|
+
};
|
|
50
|
+
}
|
|
9
51
|
export interface CachePolicyOptions {
|
|
10
52
|
renderMode: RenderMode;
|
|
11
53
|
audience: Audience;
|
|
12
54
|
}
|
|
13
55
|
export declare function buildSharedPublicationHeaders(options: HeaderPolicyOptions): Record<string, string>;
|
|
14
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Build framework-owned CSP configuration for Astro 7.1+.
|
|
58
|
+
* Astro hashes every script and style it emits, while this helper keeps the
|
|
59
|
+
* consumer's external source inventory exact and fail-closed.
|
|
60
|
+
*/
|
|
61
|
+
export declare function buildAstroCspConfig(options?: AstroCspPolicyOptions): AstroCspConfig;
|
|
62
|
+
export declare function buildContentSecurityPolicy(input?: string | ContentSecurityPolicyOptions): string;
|
|
63
|
+
export declare function buildStrictTransportSecurity(options?: StrictTransportSecurityOptions): string;
|
|
15
64
|
export declare function buildCacheControl({ renderMode, audience }: CachePolicyOptions): string;
|
|
16
65
|
export declare function normalizeHeaders(headers: HeaderMap | undefined): Record<string, string>;
|
|
66
|
+
export declare function collectHeaders(headers: HeaderMap | undefined): Record<string, string[]>;
|
|
17
67
|
export declare function isPrivateAudience(audience: Audience): boolean;
|
|
68
|
+
export {};
|
|
18
69
|
//# sourceMappingURL=policy.d.ts.map
|
package/dist/policy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/policy.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { inlineStyleAttributeInventorySchema, } from './schema.js';
|
|
1
2
|
export const REQUIRED_SECURITY_HEADERS = [
|
|
2
3
|
'content-security-policy',
|
|
3
4
|
'strict-transport-security',
|
|
5
|
+
'cross-origin-opener-policy',
|
|
6
|
+
'cross-origin-resource-policy',
|
|
4
7
|
'x-frame-options',
|
|
5
8
|
'x-content-type-options',
|
|
6
9
|
'referrer-policy',
|
|
@@ -8,27 +11,119 @@ export const REQUIRED_SECURITY_HEADERS = [
|
|
|
8
11
|
];
|
|
9
12
|
export function buildSharedPublicationHeaders(options) {
|
|
10
13
|
const headers = {
|
|
11
|
-
'
|
|
12
|
-
'
|
|
14
|
+
'Strict-Transport-Security': buildStrictTransportSecurity(options.strictTransportSecurity),
|
|
15
|
+
'Cross-Origin-Opener-Policy': options.crossOriginOpenerPolicy ?? 'same-origin',
|
|
16
|
+
'Cross-Origin-Resource-Policy': options.crossOriginResourcePolicy ?? 'same-origin',
|
|
13
17
|
'X-Frame-Options': 'DENY',
|
|
14
18
|
'X-Content-Type-Options': 'nosniff',
|
|
15
19
|
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
|
16
20
|
'Permissions-Policy': 'accelerometer=(), camera=(), geolocation=(), gyroscope=(), microphone=(), payment=(), usb=()',
|
|
17
21
|
'Cache-Control': buildCacheControl(options),
|
|
18
22
|
};
|
|
23
|
+
if (options.contentSecurityPolicy !== false) {
|
|
24
|
+
headers['Content-Security-Policy'] = buildContentSecurityPolicy(options.contentSecurityPolicy ?? {
|
|
25
|
+
nonce: options.nonce,
|
|
26
|
+
reportUri: options.cspReportUri,
|
|
27
|
+
reportTo: options.cspReportTo,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
19
30
|
if (options.markdownTwinUrl) {
|
|
20
31
|
headers.Link = `<${options.markdownTwinUrl}>; rel="alternate"; type="text/markdown"`;
|
|
21
32
|
}
|
|
22
33
|
return headers;
|
|
23
34
|
}
|
|
24
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Build framework-owned CSP configuration for Astro 7.1+.
|
|
37
|
+
* Astro hashes every script and style it emits, while this helper keeps the
|
|
38
|
+
* consumer's external source inventory exact and fail-closed.
|
|
39
|
+
*/
|
|
40
|
+
export function buildAstroCspConfig(options = {}) {
|
|
41
|
+
const inlineStyleAttributes = options.inlineStyleAttributes
|
|
42
|
+
? inlineStyleAttributeInventorySchema.parse(options.inlineStyleAttributes)
|
|
43
|
+
: undefined;
|
|
44
|
+
const scriptSources = exactCspSources(options.scriptSources);
|
|
45
|
+
const styleSources = exactCspSources(options.styleSources);
|
|
46
|
+
const imgSources = exactCspSources(options.imgSources);
|
|
47
|
+
const fontSources = exactCspSources(options.fontSources);
|
|
48
|
+
const connectSources = exactCspSources(options.connectSources);
|
|
49
|
+
const mediaSources = exactCspSources(options.mediaSources);
|
|
50
|
+
const frameSources = exactCspSources(options.frameSources);
|
|
51
|
+
return {
|
|
52
|
+
algorithm: 'SHA-256',
|
|
53
|
+
directives: [
|
|
54
|
+
"default-src 'self'",
|
|
55
|
+
cspDirective('img-src', ["'self'", 'data:', 'blob:', ...imgSources]),
|
|
56
|
+
cspDirective('font-src', ["'self'", 'data:', ...fontSources]),
|
|
57
|
+
cspDirective('connect-src', ["'self'", ...connectSources]),
|
|
58
|
+
cspDirective('media-src', ["'self'", 'blob:', ...mediaSources]),
|
|
59
|
+
cspDirective('frame-src', ["'self'", ...frameSources]),
|
|
60
|
+
"object-src 'none'",
|
|
61
|
+
"base-uri 'self'",
|
|
62
|
+
"frame-ancestors 'none'",
|
|
63
|
+
"form-action 'self'",
|
|
64
|
+
'upgrade-insecure-requests',
|
|
65
|
+
],
|
|
66
|
+
scriptDirective: {
|
|
67
|
+
resources: uniqueCspSources(["'self'", ...scriptSources]),
|
|
68
|
+
},
|
|
69
|
+
styleDirective: {
|
|
70
|
+
resources: inlineStyleAttributes
|
|
71
|
+
? [
|
|
72
|
+
...uniqueCspSources(["'self'", ...styleSources]).map((resource) => ({
|
|
73
|
+
resource,
|
|
74
|
+
kind: 'element',
|
|
75
|
+
})),
|
|
76
|
+
{ resource: "'unsafe-inline'", kind: 'attribute' },
|
|
77
|
+
]
|
|
78
|
+
: uniqueCspSources(["'self'", ...styleSources]),
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function uniqueCspSources(sources) {
|
|
83
|
+
return [...new Set(sources)];
|
|
84
|
+
}
|
|
85
|
+
function cspDirective(name, sources) {
|
|
86
|
+
return `${name} ${[...new Set(sources)].join(' ')}`;
|
|
87
|
+
}
|
|
88
|
+
function exactCspSources(sources) {
|
|
89
|
+
return [...new Set(sources ?? [])].map((source) => {
|
|
90
|
+
const normalized = source.trim();
|
|
91
|
+
if (normalized === "'self'")
|
|
92
|
+
return normalized;
|
|
93
|
+
if (normalized === '' ||
|
|
94
|
+
normalized.includes('*') ||
|
|
95
|
+
normalized === 'https:' ||
|
|
96
|
+
normalized === 'http:' ||
|
|
97
|
+
normalized.startsWith("'unsafe-")) {
|
|
98
|
+
throw new Error(`Astro CSP sources must be exact and cannot use ${source}`);
|
|
99
|
+
}
|
|
100
|
+
let parsed;
|
|
101
|
+
try {
|
|
102
|
+
parsed = new URL(normalized);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
throw new Error(`Astro CSP sources must be exact HTTPS/WSS origins: ${source}`);
|
|
106
|
+
}
|
|
107
|
+
if ((parsed.protocol !== 'https:' && parsed.protocol !== 'wss:') ||
|
|
108
|
+
parsed.username !== '' ||
|
|
109
|
+
parsed.password !== '' ||
|
|
110
|
+
parsed.search !== '' ||
|
|
111
|
+
parsed.hash !== '' ||
|
|
112
|
+
(parsed.pathname !== '' && parsed.pathname !== '/')) {
|
|
113
|
+
throw new Error(`Astro CSP sources must be exact HTTPS/WSS origins: ${source}`);
|
|
114
|
+
}
|
|
115
|
+
return parsed.origin;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
export function buildContentSecurityPolicy(input) {
|
|
119
|
+
const options = typeof input === 'string' ? { nonce: input } : (input ?? {});
|
|
25
120
|
const scriptSources = ["'self'"];
|
|
26
121
|
const styleSources = ["'self'"];
|
|
27
|
-
if (nonce) {
|
|
28
|
-
scriptSources.push(`'nonce-${nonce}'`);
|
|
29
|
-
styleSources.push(`'nonce-${nonce}'`);
|
|
122
|
+
if (options.nonce) {
|
|
123
|
+
scriptSources.push(`'nonce-${options.nonce}'`);
|
|
124
|
+
styleSources.push(`'nonce-${options.nonce}'`);
|
|
30
125
|
}
|
|
31
|
-
|
|
126
|
+
const directives = [
|
|
32
127
|
"default-src 'self'",
|
|
33
128
|
`script-src ${scriptSources.join(' ')}`,
|
|
34
129
|
`style-src ${styleSources.join(' ')}`,
|
|
@@ -39,7 +134,27 @@ export function buildContentSecurityPolicy(nonce) {
|
|
|
39
134
|
"base-uri 'self'",
|
|
40
135
|
"frame-ancestors 'none'",
|
|
41
136
|
'upgrade-insecure-requests',
|
|
42
|
-
]
|
|
137
|
+
];
|
|
138
|
+
if (options.reportTo)
|
|
139
|
+
directives.push(`report-to ${options.reportTo}`);
|
|
140
|
+
if (options.reportUri)
|
|
141
|
+
directives.push(`report-uri ${options.reportUri}`);
|
|
142
|
+
return directives.join('; ');
|
|
143
|
+
}
|
|
144
|
+
export function buildStrictTransportSecurity(options = {}) {
|
|
145
|
+
const maxAgeSeconds = options.maxAgeSeconds ?? 31536000;
|
|
146
|
+
if (!Number.isInteger(maxAgeSeconds) || maxAgeSeconds < 31536000) {
|
|
147
|
+
throw new Error('Strict-Transport-Security maxAgeSeconds must be at least 31536000');
|
|
148
|
+
}
|
|
149
|
+
if (options.preload === true && options.includeSubDomains !== true) {
|
|
150
|
+
throw new Error('Strict-Transport-Security preload requires includeSubDomains after host inventory proof');
|
|
151
|
+
}
|
|
152
|
+
const directives = [`max-age=${maxAgeSeconds}`];
|
|
153
|
+
if (options.includeSubDomains === true)
|
|
154
|
+
directives.push('includeSubDomains');
|
|
155
|
+
if (options.preload === true)
|
|
156
|
+
directives.push('preload');
|
|
157
|
+
return directives.join('; ');
|
|
43
158
|
}
|
|
44
159
|
export function buildCacheControl({ renderMode, audience }) {
|
|
45
160
|
if (isPrivateAudience(audience))
|
|
@@ -50,15 +165,24 @@ export function buildCacheControl({ renderMode, audience }) {
|
|
|
50
165
|
return 'public, max-age=0, s-maxage=300, stale-while-revalidate=86400';
|
|
51
166
|
}
|
|
52
167
|
export function normalizeHeaders(headers) {
|
|
168
|
+
const entries = collectHeaders(headers);
|
|
169
|
+
const normalized = {};
|
|
170
|
+
for (const [name, values] of Object.entries(entries)) {
|
|
171
|
+
normalized[name] = values.join(', ');
|
|
172
|
+
}
|
|
173
|
+
return normalized;
|
|
174
|
+
}
|
|
175
|
+
export function collectHeaders(headers) {
|
|
53
176
|
const normalized = {};
|
|
54
177
|
if (!headers)
|
|
55
178
|
return normalized;
|
|
56
179
|
for (const [name, value] of Object.entries(headers)) {
|
|
180
|
+
const normalizedName = name.toLowerCase();
|
|
57
181
|
if (typeof value === 'string') {
|
|
58
|
-
normalized[
|
|
182
|
+
normalized[normalizedName] = [...(normalized[normalizedName] ?? []), value];
|
|
59
183
|
}
|
|
60
184
|
else if (Array.isArray(value)) {
|
|
61
|
-
normalized[
|
|
185
|
+
normalized[normalizedName] = [...(normalized[normalizedName] ?? []), ...value];
|
|
62
186
|
}
|
|
63
187
|
}
|
|
64
188
|
return normalized;
|
package/dist/policy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAOA,OAAO,EAKN,KAAK,uBAAuB,EAG5B,KAAK,mBAAmB,EAGxB,KAAK,kBAAkB,EAEvB,MAAM,aAAa,CAAA;AAuBpB,MAAM,WAAW,qBAAqB;IACrC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAClB;AAED,wBAAgB,kBAAkB,CACjC,KAAK,EAAE,uBAAuB,EAC9B,OAAO,GAAE,qBAA0B,GACjC,kBAAkB,CA+BpB;AAED,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,uBAAuB,EAAE,EACjC,OAAO,GAAE,qBAA0B,GACjC,mBAAmB,CAuBrB"}
|