From e4d6f0772f769d3431f5ab31f9434eae6b6991e7 Mon Sep 17 00:00:00 2001 From: Jeff Larson Date: Sat, 18 Jul 2026 18:21:17 -0700 Subject: [PATCH] =?UTF-8?q?fix(dashboard):=20quiet=20the=20"no=20provenanc?= =?UTF-8?q?e"=20column=20noise=20=E2=80=94=20muted=20dash,=20not=20a=20chi?= =?UTF-8?q?p=20on=20every=20row?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Almost no image in a real cluster ships a SLSA build-provenance attestation, so the signing inventory rendered a loud "no provenance" chip (ProvenancePosture:: Absent) on nearly every row — pure noise that drowned the meaningful provenance states. The calm-default `absent` now reads as a quiet muted dash (mirroring the no-signer cell), and the loud chip is kept only for the states that mean something: verified / unverifiable / checking. The cell keeps its honest `data-provenance="absent"` tag and the expandable detail still explains the absence for anyone who looks — this is a presentation choice (ADR-0016), the server still sends the honest posture. Adds admission tests: an absent-provenance row renders a muted dash (no chip, no "no provenance" text) while still tagged absent; a verified provenance still renders its loud chip + builder. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01VtjoJttCvBY4dzCoE4f9vP --- engine/web/src/admission/signing.jsx | 38 ++++++++++++++++++++-------- engine/web/test/admission.test.jsx | 38 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/engine/web/src/admission/signing.jsx b/engine/web/src/admission/signing.jsx index 1c72326..bad6457 100644 --- a/engine/web/src/admission/signing.jsx +++ b/engine/web/src/admission/signing.jsx @@ -191,18 +191,34 @@ function SigningRow({ r, strength: repoStrength }) { )} - - - {prov.word} - - {provInfo ? ( - - {" \u{00B7} "} - {provInfo["builder-short"]} + {r.provenance === "absent" ? ( + // Almost no image ships a SLSA build-provenance attestation, so an "absent" chip would + // shout "no provenance" on nearly every row — pure noise. The calm default reads as a + // quiet muted dash (mirroring the no-signer cell); the loud chip is kept only for the + // meaningful states (verified / unverifiable / checking). The expandable detail still + // explains the absence for anyone who looks. + + {"\u{2014}"} - ) : null} + ) : ( + <> + + + {prov.word} + + {provInfo ? ( + + {" \u{00B7} "} + {provInfo["builder-short"]} + + ) : null} + + )} {repoStrength === "unknown" ? ( diff --git a/engine/web/test/admission.test.jsx b/engine/web/test/admission.test.jsx index a8a2338..d08da97 100644 --- a/engine/web/test/admission.test.jsx +++ b/engine/web/test/admission.test.jsx @@ -85,6 +85,44 @@ describe("Admission honesty", () => { }); }); +describe("Provenance column is quiet by default", () => { + // Almost no image ships a SLSA attestation, so an "absent" chip on every row is pure noise — the + // calm default reads as a muted dash, never the loud "no provenance" chip. + it("renders an ABSENT-provenance image as a muted dash, not the no-provenance chip", () => { + const { container } = render( + , + ); + const cell = container.querySelector('tr[data-signing="img-a"] .cell-provenance'); + expect(cell).toBeTruthy(); + expect(cell.getAttribute("data-provenance")).toBe("absent"); // still honestly tagged + expect(cell.querySelector(".gate-chip")).toBeNull(); // but no loud chip + expect(cell.textContent).not.toContain("no provenance"); + expect(cell.textContent).toContain("—"); // a quiet dash + }); + + it("still renders the loud chip for a VERIFIED build provenance", () => { + const { container } = render( + , + ); + const cell = container.querySelector('tr[data-signing="img-a"] .cell-provenance'); + expect(cell.querySelector(".gate-chip.prov-verified")).toBeTruthy(); + expect(cell.textContent).toContain("org/repo"); + }); +}); + describe("Admission escaping", () => { it("renders an XSS subject/image/signer identity as inert text", () => { window.__pwned = undefined;