From cb75f1d9c9b3caaaaa2ab1ee83aaa70e7e313b73 Mon Sep 17 00:00:00 2001 From: Steve Beattie Date: Mon, 31 Aug 2026 15:19:24 -0700 Subject: [PATCH] Make the datastream's OVAL reference sources say Custom, and gate it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Five OVAL definitions embedded in the datastream carried while every standalone file said "Custom", and two embedded blocks said "Custom" as well — so the datastream disagreed both with its sources and with itself. "Custom" is the intended value, and this is a missed hand-sync rather than a judgement call. Commit 3f69d3f ("All of the formatting", 2025-07-18) deliberately changed exactly these five references from CIS to Custom in the standalone files. It touched the datastream in the same commit — 3402 lines — but left its reference sources alone. The value has never been anything but Custom in the standalone files since. These are Chainguard-authored checks for a DISA GPOS SRG profile, not CIS benchmark content, and the elements carry no ref_id, so "CIS" asserted a provenance that was not real. This does not change any scan verdict, but it is not invisible either. The value is absent from the HTML report oscap renders, and present in the machine-readable results a scan emits — so it reaches compliance evidence customers retain, as well as the published datastream itself. Convert the five, and close the gate behind them: descriptive differences in the mirror check now fail rather than being logged. They were logged deliberately while these five existed, because failing on a difference that changes no verdict would have meant disabling the check instead of fixing content. The content is fixed, so the exemption goes. Verified: no CIS values remain anywhere; the mirror check reports zero descriptive differences across all 8 files; reintroducing a single CIS now fails the check, naming the file and definition. gofmt/vet clean, validate_checks passes, sds-validate rc=0, and oscap xccdf validate reports the same 235 pre-existing errors as main. Co-Authored-By: Claude Opus 5 --- README.md | 12 +++++++----- .../scap/ssg/content/ssg-chainguard-gpos-ds.xml | 10 +++++----- tests/oscap-offline/internal/mirrors/doc.go | 15 ++++++++------- .../internal/mirrors/mirrors_test.go | 8 +++++++- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index daf9338..a91bbff 100644 --- a/README.md +++ b/README.md @@ -140,11 +140,13 @@ this check green is also what makes the next regeneration safe — if the datastream already matches what the in-repo sources would produce, rebuilding it cannot silently revert anything. -Differences that would change a scan verdict fail; purely descriptive -ones (titles, descriptions, ``) are logged instead, -since the two copies currently disagree on some of those without -affecting any result — failing on them would mean disabling the check -rather than fixing content. +Any difference fails, reported as either functional (criteria, tests, +objects, states, variables — these change a scan verdict) or descriptive +(titles, descriptions, `` — these do not). Descriptive +differences were logged rather than failed while five embedded blocks +still carried a `` of `CIS` against the standalone +files' `Custom`; that content was corrected and the gate closed behind +it. The comparison lives in `tests/oscap-offline/internal/mirrors` alongside its own unit tests, so diff --git a/gpos/xml/scap/ssg/content/ssg-chainguard-gpos-ds.xml b/gpos/xml/scap/ssg/content/ssg-chainguard-gpos-ds.xml index d536d0b..96bbddd 100644 --- a/gpos/xml/scap/ssg/content/ssg-chainguard-gpos-ds.xml +++ b/gpos/xml/scap/ssg/content/ssg-chainguard-gpos-ds.xml @@ -6312,7 +6312,7 @@ Check for OpenSSL FIPS Packages Ensure that the necessary OpenSSL FIPS packages and configuration files are present, and that the OPENSSL_CONF environment variable is either unset or set to /etc/ssl/openssl.cnf. Additionally verify that the OpenSSH client and server FIPS policy drop-ins (/etc/ssh/ssh_config.d/10-ssh-fips.conf and /etc/ssh/sshd_config.d/10-sshd-fips.conf) are present and pin the FIPS-approved ciphers, key-exchange, MAC, and signature algorithms. The main /etc/ssh/ssh_config and /etc/ssh/sshd_config must in turn Include their respective *_config.d/*.conf drop-in directories so the policy is applied. The client checks apply only when openssh-client is installed and the server checks only when openssh-server is installed. - + Chainguard @@ -6587,7 +6587,7 @@ Check Library Permissions Ensure all libraries in /usr/lib have root:root permissions. - + Chainguard @@ -6652,7 +6652,7 @@ Check for Login-Capable Users in /etc/shadow Ensure every entry in /etc/shadow is locked (password field starts with '!' or '*'), i.e. there are no login-capable user accounts. Locked service accounts, such as those apko creates for image run-as users, cannot log in and are permitted. - + Chainguard @@ -6774,7 +6774,7 @@ No active/unlocked password field in /etc/shadow Chainguard container images must not ship interactive shadow password entries; every account must have its shadow field locked ("!" or "*"). This check FAILS if any line in /etc/shadow matches an active/unlocked password field, on the premise that hardened images have no interactive logins. - + Chainguard @@ -6812,7 +6812,7 @@ Check Var/Log Permissions Ensure /var/log has root:root permissions. - + Chainguard diff --git a/tests/oscap-offline/internal/mirrors/doc.go b/tests/oscap-offline/internal/mirrors/doc.go index 08ec4b5..1ce9e32 100644 --- a/tests/oscap-offline/internal/mirrors/doc.go +++ b/tests/oscap-offline/internal/mirrors/doc.go @@ -29,13 +29,14 @@ // variable — is an error: the two copies would evaluate the same image // differently. // -// Metadata (title, description, reference, affected) is a warning. The copies -// disagree today on a reading "Custom" in every standalone -// file and "CIS" in five embedded blocks, which changes no verdict. Since -// generation copies the standalone file verbatim, the standalone spelling is -// canonical by construction and those embedded values are simply stale, but -// correcting them is a content change to the shipped datastream and is not -// bundled with the comparison itself. +// Metadata (title, description, reference, affected) is reported separately, +// because it does not change a verdict — but it is still a failure, since the +// two copies agree on all of it. They did not always: five embedded blocks +// carried a of "CIS" against the standalone files' "Custom", +// which is why this started out as a warning. Treating a difference that +// changes no verdict as fatal while known instances existed would have meant +// disabling the check rather than fixing content, so the content was corrected +// first and the gate closed behind it. // // # Why entities, not a flat node list // diff --git a/tests/oscap-offline/internal/mirrors/mirrors_test.go b/tests/oscap-offline/internal/mirrors/mirrors_test.go index 907b00a..38142a1 100644 --- a/tests/oscap-offline/internal/mirrors/mirrors_test.go +++ b/tests/oscap-offline/internal/mirrors/mirrors_test.go @@ -379,8 +379,14 @@ func TestRepositoryMirrorsMatch(t *testing.T) { for _, f := range report.Functional { t.Errorf("functional difference: %s", f) } + // Descriptive differences fail too, now that the two copies agree on all of + // them. They were logged rather than failed while five embedded blocks still + // carried a of "CIS" against the standalone files' + // "Custom" — a difference that changes no verdict, so failing on it would + // have meant disabling this test instead of fixing content. The content is + // fixed, so the gate closes behind it. for _, f := range report.Descriptive { - t.Logf("descriptive difference (not fatal): %s", f) + t.Errorf("descriptive difference: %s", f) } // A run that paired nothing would otherwise read as success.