Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions gates/conformance/conformance.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ const met = (detail) => ({ status: "met", detail });
const unmet = (detail) => ({ status: "unmet", detail });
const notAssessed = (detail) => ({ status: "not-assessed", detail });

/** The OpenSSF Scorecard score at/above which `integrity.scorecard` is `met`. */
const SCORECARD_THRESHOLD = 7.0;

// Per-criterion evaluator for external evidence. Returns `not-assessed` when the
// relevant evidence field is absent; otherwise checks shape/thresholds.
const EXTERNAL_EVALUATORS = {
Expand Down Expand Up @@ -93,6 +96,13 @@ const EXTERNAL_EVALUATORS = {
? met("0 known critical/high vulns")
: unmet(`${v.knownCriticalOrHighVulns} known critical/high vuln(s)`);
},
"security.hsts-preload": (e) => {
const v = e.hstsPreload;
if (!v) return notAssessed("no HSTS preload status supplied");
return v.preloaded
? met("origin is on the HSTS preload list")
: unmet("origin is not on the HSTS preload list");
},
"performance.core-web-vitals": (e) => {
const samples = e.coreWebVitals;
if (!samples || samples.length === 0) {
Expand Down Expand Up @@ -197,6 +207,20 @@ const EXTERNAL_EVALUATORS = {
? met("SLSA/in-toto provenance present, signed, and verified")
: unmet(gaps.join(", "));
},
"integrity.slsa-level": (e) => {
const v = e.slsaLevel;
if (!v) return notAssessed("no SLSA build level supplied");
return v.level >= v.target
? met(`SLSA build Level ${v.level} (target L${v.target})`)
: unmet(`SLSA build Level ${v.level} below target L${v.target}`);
},
"integrity.scorecard": (e) => {
const v = e.scorecard;
if (!v) return notAssessed("no OpenSSF Scorecard result supplied");
return v.score >= SCORECARD_THRESHOLD
? met(`OpenSSF Scorecard ${v.score.toFixed(1)} (≥ ${SCORECARD_THRESHOLD})`)
: unmet(`OpenSSF Scorecard ${v.score.toFixed(1)} below ${SCORECARD_THRESHOLD}`);
},
"integrity.reproducible-build": (e) => {
const v = e.reproducibleBuild;
if (!v) return notAssessed("no reproducible-build report supplied");
Expand Down
45 changes: 45 additions & 0 deletions gates/conformance/web-build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ export const CRITERIA = [
evidence: "external",
required: true,
},
{
// External grader — Chromium-maintained HSTS preload list. Independent by
// construction, so it needs no `verifiedBy`. Recommended (non-gating).
id: "security.hsts-preload",
area: "security",
label: "HSTS preload",
standard: "RFC 6797 / hstspreload.org",
target: "Origin is on the HSTS preload list (HTTPS enforced before first byte).",
level: "preloaded",
evidence: "external",
required: false,
},

// ── Performance — Core Web Vitals ────────────────────────────────────────
{
Expand Down Expand Up @@ -336,6 +348,33 @@ export const CRITERIA = [
required: false,
tier: 3,
},
// ── Integrity — external graders (independent by construction) ────────────
{
// OpenSSF Scorecard — automated third-party grader of repo security posture
// (0–10). Independent, so no `verifiedBy`. Recommended (non-gating).
id: "integrity.scorecard",
area: "integrity",
label: "OpenSSF Scorecard",
standard: "OpenSSF Scorecard",
target: "Repository scores ≥ 7.0 on the OpenSSF Scorecard.",
level: "score ≥ 7.0",
evidence: "external",
required: false,
tier: 3,
},
{
// SLSA build LEVEL achieved (distinct from `integrity.slsa-provenance`, which
// only checks provenance is present/signed/verified). Recommended (non-gating).
id: "integrity.slsa-level",
area: "integrity",
label: "SLSA build level",
standard: "SLSA",
target: "Build achieves the targeted SLSA build level (default L3).",
level: "≥ target (default L3)",
evidence: "external",
required: false,
tier: 3,
},

// ══ COGNITIVE ACCESSIBILITY — W3C COGA ═════════════════════════════════════
// HONEST LABELING: an INTERFACE-COMPLEXITY BUDGET (W3C COGA-derived), explicitly
Expand Down Expand Up @@ -465,6 +504,8 @@ const ENVELOPE = {
// OSV). Decoupled from `asvs` so an objective vuln count can be supplied WITHOUT
// also self-grading an ASVS level.
vulns: opt(vObject({ knownCriticalOrHighVulns: req(vInt0) })),
// External grader — Chromium HSTS preload list. Independent; no `verifiedBy`.
hstsPreload: opt(vObject({ preloaded: req(vBool) })),
coreWebVitals: opt(vArrayOf(vObject(CWV_SAMPLE_SHAPE))),
baseline: opt(vObject({
status: req(vEnum("widely", "newly", "limited")),
Expand Down Expand Up @@ -494,6 +535,10 @@ const ENVELOPE = {
feeds: opt(vObject({ atomValid: req(vBool) })),
// tier-3
slsaProvenance: opt(vObject({ present: req(vBool), signed: req(vBool), verified: req(vBool) })),
// External grader — SLSA build LEVEL achieved (distinct from slsaProvenance).
slsaLevel: opt(vObject({ level: req(vEnum(0, 1, 2, 3)), target: def(vEnum(1, 2, 3), 3) })),
// External grader — OpenSSF Scorecard score (0–10). Independent; no `verifiedBy`.
scorecard: opt(vObject({ score: req(vNum(0, 10)) })),
reproducibleBuild: opt(vObject({ reproducible: req(vBool) })),
sbom: opt(vObject({ present: req(vBool), valid: req(vBool), complete: req(vBool), signed: req(vBool) })),
contentDigests: opt(vObject({ reprDigestHeaders: req(vBool) })),
Expand Down
24 changes: 24 additions & 0 deletions test/run.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,30 @@ await test("gates/conformance-report: build + render the conformance projection"
if (byIdV["security.no-critical-vulns"].status !== "unmet") throw new Error("3 vulns must be unmet, no asvs object required");
if (byIdV["security.asvs"].status !== "not-assessed") throw new Error("absent asvs must be not-assessed");

// (e) external graders (Scorecard / HSTS / SLSA level) — independent third-party
// grades, assessable on their own, recommended (non-gating).
const statusById = (r) => Object.fromEntries(r.results.map((x) => [x.id, x.status]));
const absent = statusById(buildConformanceReport({ evidence: {} }));
for (const id of ["security.hsts-preload", "integrity.scorecard", "integrity.slsa-level"]) {
if (absent[id] !== "not-assessed") throw new Error(`${id} absent must be not-assessed`);
}
const graders = statusById(buildConformanceReport({
evidence: {
hstsPreload: { preloaded: true },
scorecard: { score: 7.0 },
slsaLevel: { level: 3 }, // target defaults to L3
},
}));
if (graders["security.hsts-preload"] !== "met") throw new Error("preloaded HSTS must be met");
if (graders["integrity.scorecard"] !== "met") throw new Error("Scorecard 7.0 must be met");
if (graders["integrity.slsa-level"] !== "met") throw new Error("SLSA L3 (target L3) must be met");
const gradersBad = statusById(buildConformanceReport({
evidence: { hstsPreload: { preloaded: false }, scorecard: { score: 6.9 }, slsaLevel: { level: 2 } },
}));
if (gradersBad["security.hsts-preload"] !== "unmet") throw new Error("non-preloaded HSTS must be unmet");
if (gradersBad["integrity.scorecard"] !== "unmet") throw new Error("Scorecard 6.9 must be unmet");
if (gradersBad["integrity.slsa-level"] !== "unmet") throw new Error("SLSA L2 below target L3 must be unmet");

// malformed envelope → throw (lone refuses to guess).
let threw = false;
try { buildConformanceReport({ evidence: { sbom: { present: "yes" } } }); } catch { threw = true; }
Expand Down