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
13 changes: 11 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ jobs:
- name: Run repository checks
run: pre-commit run --all-files --show-diff-on-failure

- name: Validate artifact locks
run: python -m unittest tests.test_artifacts -v
- name: Validate artifact locks and component accountability
run: >-
python -m unittest
tests.test_artifacts tests.test_components tests.test_nginx_features
tests.test_transfer -v

- name: Audit GitHub Actions security
uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3
Expand Down Expand Up @@ -122,6 +125,12 @@ jobs:
artifacts/locks/${{ matrix.architecture }}.json
.artifact-bundle/${{ matrix.architecture }}

- name: Verify runtime component metadata
run: >-
python scripts/components.py
--lock artifacts/locks/${{ matrix.architecture }}.json
--bundle .artifact-bundle/${{ matrix.architecture }}

- name: Reject invalid RPM bundles
run: >-
python tests/rpm-bundle-negative.py
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,22 @@ but container releases use the upstream-derived format documented in
bound production lock validation to the reviewed base images, NGINX seed,
and signing-key inputs; and required filenames to agree with RPM metadata
and official source URLs.
- Added a lock-bound accountability inventory for all 79 runtime RPMs with
exact license and source-RPM metadata, publisher and redistribution policy,
lifecycle boundary, and named update ownership; native CI now checks the
recorded metadata against every acquired AMD64 and ARM64 RPM.
- Defined reviewed lock refresh, signing-key rotation and revocation, immutable
artifact mirroring, image rollback, and disconnected-transfer procedures;
added a schema and fail-closed transfer manifest that binds payload hashes to
the repository revision, architecture lock, and component inventory.
- Embedded the exact verified 79-RPM manifest in the package-manager-free final
image; added a reviewed inventory for 22 optional NGINX compile-time modules
and features; and made native Podman plus Docker compatibility tests reject
package, module, or NGINX build drift.
- Strengthened rootless failure and lifecycle tests to require precise mounted
configuration and unwritable-temporary-path diagnostics, worker-replacing
reloads with PID 1 retained, and complete active-request draining on
`SIGQUIT` before a clean exit.
- Expanded logging guidance with a field-by-field explanation of `$request`,
a sensitive ClickHouse example, and safer variable choices.
- Defined a source-independent pipeline contract that downloads and verifies
Expand Down
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,15 @@ root filesystem, explicit `tmpfs` mounts, dropped capabilities, and
- [External artifact acquisition](docs/ARTIFACT-ACQUISITION.md) defines the
pre-build download and verification process and hermetic image assembly
contract.
- [Artifact lifecycle and controlled transfer](docs/ARTIFACT-LIFECYCLE.md)
defines lock refresh, signing-key rotation, immutable mirrors, rollback, and
disconnected transfer and verification.
- [Runtime component accountability](docs/COMPONENT-OWNERSHIP.md) binds every
locked runtime RPM to its source, license metadata, redistribution and
lifecycle policy, and named update owner.
- [Rootless runtime and lifecycle contract](docs/RUNTIME-CONTRACT.md) records
startup diagnostics, reload and graceful-stop behavior, and the enforced RPM
and NGINX module inventories.

TLS, configuration, architecture, control-matrix/OSCAL, SCAP,
vulnerability-management, and disconnected-network guides will be added as
Expand Down Expand Up @@ -152,10 +161,14 @@ python -m pip install --require-hashes --only-binary=:all: \
pre-commit run --all-files --show-diff-on-failure
```

Validate the reviewed artifact locks and their negative cases with:
Validate the reviewed artifact locks, component inventory, and their negative
cases with:

```console
python -m unittest tests.test_artifacts -v
python -m unittest \
tests.test_artifacts tests.test_components tests.test_nginx_features \
tests.test_transfer -v
python scripts/components.py
```

Acquire and verify the exact AMD64 RPM bundle from the official sources:
Expand Down
5 changes: 5 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ describes the principal packaging and NGINX license relationship; consumers
must also review the SBOM, embedded notices, UBI terms, and every component's
license.

The machine-validated
[runtime component inventory](docs/COMPONENT-OWNERSHIP.md) records the exact
RPM license tag and source RPM for every locked binary package. RPM license
tags are upstream metadata rather than a project-authored legal conclusion.

## Release review

Before publishing a release:
Expand Down
116 changes: 116 additions & 0 deletions artifacts/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{
"schema_version": 1,
"locks": {
"amd64": {
"path": "artifacts/locks/amd64.json",
"sha256": "ec35b2bcd7f1de1b6f1416a18eed5e3cc186624776f9ad793f22940c9f034456"
},
"arm64": {
"path": "artifacts/locks/arm64.json",
"sha256": "9d53e9d6cccb8d291ece70e9e0605248e5e7033c8d7734ea1953d95edf226ad2"
}
},
"policies": [
{
"id": "nginx-stable",
"publisher": "F5, Inc. / NGINX",
"component_source": "https://nginx.org/packages/rhel/9/",
"redistribution_terms": "https://nginx.org/en/docs/faq/license_copyright.html",
"license_reference": "https://nginx.org/LICENSE",
"support_lifecycle": "The open-source stable channel has no fixed support term identified by this project; Datopsis maintainers monitor upstream releases and advisories and own update decisions.",
"update_owner": "Datopsis maintainers",
"rpm_vendor": "NGINX Packaging <nginx-packaging@f5.com>"
},
{
"id": "redhat-ubi9",
"publisher": "Red Hat, Inc.",
"component_source": "https://cdn-ubi.redhat.com/content/public/ubi/dist/ubi9/",
"redistribution_terms": "https://cdn-ubi.redhat.com/content/public/ubi/EULA.html",
"license_reference": "https://developers.redhat.com/articles/ubi-faq",
"support_lifecycle": "UBI content follows the RHEL lifecycle; Red Hat support depends on an eligible subscription and supported deployment, while Datopsis maintainers own image update decisions.",
"update_owner": "Datopsis maintainers",
"rpm_vendor": "Red Hat, Inc."
}
],
"components": [
{"name": "acl", "source_rpm": "acl-2.4.0-1.el9_8.src.rpm", "license": "GPLv2+", "policy": "redhat-ubi9"},
{"name": "alternatives", "source_rpm": "chkconfig-1.24-2.el9.src.rpm", "license": "GPL-2.0-only", "policy": "redhat-ubi9"},
{"name": "audit-libs", "source_rpm": "audit-3.1.5-8.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "basesystem", "source_rpm": "basesystem-11-13.el9.src.rpm", "license": "Public Domain", "policy": "redhat-ubi9"},
{"name": "bash", "source_rpm": "bash-5.1.8-9.el9.src.rpm", "license": "GPLv3+", "policy": "redhat-ubi9"},
{"name": "bzip2-libs", "source_rpm": "bzip2-1.0.8-11.el9.src.rpm", "license": "BSD", "policy": "redhat-ubi9"},
{"name": "ca-certificates", "source_rpm": "ca-certificates-2025.2.80_v9.0.305-91.el9.src.rpm", "license": "MIT AND GPL-2.0-or-later", "policy": "redhat-ubi9"},
{"name": "coreutils", "source_rpm": "coreutils-8.32-41.el9_8.1.src.rpm", "license": "GPLv3+", "policy": "redhat-ubi9"},
{"name": "coreutils-common", "source_rpm": "coreutils-8.32-41.el9_8.1.src.rpm", "license": "GPLv3+", "policy": "redhat-ubi9"},
{"name": "cracklib", "source_rpm": "cracklib-2.9.6-28.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "cracklib-dicts", "source_rpm": "cracklib-2.9.6-28.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "crypto-policies", "source_rpm": "crypto-policies-20260224-1.gitea0f072.el9_8.src.rpm", "license": "LGPL-2.1-or-later", "policy": "redhat-ubi9"},
{"name": "dbus", "source_rpm": "dbus-1.12.20-8.el9.src.rpm", "license": "(GPLv2+ or AFL) and GPLv2+", "policy": "redhat-ubi9"},
{"name": "dbus-broker", "source_rpm": "dbus-broker-28-9.el9_8.src.rpm", "license": "ASL 2.0", "policy": "redhat-ubi9"},
{"name": "dbus-common", "source_rpm": "dbus-1.12.20-8.el9.src.rpm", "license": "(GPLv2+ or AFL) and GPLv2+", "policy": "redhat-ubi9"},
{"name": "expat", "source_rpm": "expat-2.5.0-6.el9_8.3.src.rpm", "license": "MIT", "policy": "redhat-ubi9"},
{"name": "filesystem", "source_rpm": "filesystem-3.16-5.el9.src.rpm", "license": "Public Domain", "policy": "redhat-ubi9"},
{"name": "findutils", "source_rpm": "findutils-4.8.0-7.el9.src.rpm", "license": "GPLv3+", "policy": "redhat-ubi9"},
{"name": "glibc", "source_rpm": "glibc-2.34-275.el9_8.src.rpm", "license": "LGPL-2.1-or-later AND SunPro AND LGPL-2.1-or-later WITH GCC-exception-2.0 AND BSD-3-Clause AND GPL-2.0-or-later AND LGPL-2.1-or-later WITH GNU-compiler-exception AND GPL-2.0-only AND ISC AND LicenseRef-Fedora-Public-Domain AND HPND AND CMU-Mach AND LGPL-2.0-or-later AND Unicode-3.0 AND GFDL-1.1-or-later AND GPL-1.0-or-later AND FSFUL AND MIT AND Inner-Net-2.0 AND X11 AND GPL-2.0-or-later WITH GCC-exception-2.0 AND GFDL-1.3-only AND GFDL-1.1-only AND GPL-3.0-or-later AND GPL-3.0-or-later WITH Autoconf-exception-generic-3.0 AND GPL-3.0-or-later WITH Texinfo-exception", "policy": "redhat-ubi9"},
{"name": "glibc-common", "source_rpm": "glibc-2.34-275.el9_8.src.rpm", "license": "LGPL-2.1-or-later AND SunPro AND LGPL-2.1-or-later WITH GCC-exception-2.0 AND BSD-3-Clause AND GPL-2.0-or-later AND LGPL-2.1-or-later WITH GNU-compiler-exception AND GPL-2.0-only AND ISC AND LicenseRef-Fedora-Public-Domain AND HPND AND CMU-Mach AND LGPL-2.0-or-later AND Unicode-3.0 AND GFDL-1.1-or-later AND GPL-1.0-or-later AND FSFUL AND MIT AND Inner-Net-2.0 AND X11 AND GPL-2.0-or-later WITH GCC-exception-2.0 AND GFDL-1.3-only AND GFDL-1.1-only AND GPL-3.0-or-later AND GPL-3.0-or-later WITH Autoconf-exception-generic-3.0 AND GPL-3.0-or-later WITH Texinfo-exception", "policy": "redhat-ubi9"},
{"name": "glibc-minimal-langpack", "source_rpm": "glibc-2.34-275.el9_8.src.rpm", "license": "LGPL-2.1-or-later AND SunPro AND LGPL-2.1-or-later WITH GCC-exception-2.0 AND BSD-3-Clause AND GPL-2.0-or-later AND LGPL-2.1-or-later WITH GNU-compiler-exception AND GPL-2.0-only AND ISC AND LicenseRef-Fedora-Public-Domain AND HPND AND CMU-Mach AND LGPL-2.0-or-later AND Unicode-3.0 AND GFDL-1.1-or-later AND GPL-1.0-or-later AND FSFUL AND MIT AND Inner-Net-2.0 AND X11 AND GPL-2.0-or-later WITH GCC-exception-2.0 AND GFDL-1.3-only AND GFDL-1.1-only AND GPL-3.0-or-later AND GPL-3.0-or-later WITH Autoconf-exception-generic-3.0 AND GPL-3.0-or-later WITH Texinfo-exception", "policy": "redhat-ubi9"},
{"name": "gmp", "source_rpm": "gmp-6.2.0-13.el9.src.rpm", "license": "LGPLv3+ or GPLv2+", "policy": "redhat-ubi9"},
{"name": "grep", "source_rpm": "grep-3.6-5.el9.src.rpm", "license": "GPLv3+", "policy": "redhat-ubi9"},
{"name": "gzip", "source_rpm": "gzip-1.12-2.el9_8.src.rpm", "license": "GPLv3+ and GFDL", "policy": "redhat-ubi9"},
{"name": "kmod-libs", "source_rpm": "kmod-28-11.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libacl", "source_rpm": "acl-2.4.0-1.el9_8.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libattr", "source_rpm": "attr-2.6.0-1.el9_8.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libblkid", "source_rpm": "util-linux-2.37.4-25.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libcap", "source_rpm": "libcap-2.48-10.el9_8.1.src.rpm", "license": "BSD or GPLv2", "policy": "redhat-ubi9"},
{"name": "libcap-ng", "source_rpm": "libcap-ng-0.8.2-7.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libdb", "source_rpm": "libdb-5.3.28-57.el9_6.src.rpm", "license": "BSD and LGPLv2 and Sleepycat and MIT", "policy": "redhat-ubi9"},
{"name": "libeconf", "source_rpm": "libeconf-0.4.1-7.el9_8.src.rpm", "license": "MIT", "policy": "redhat-ubi9"},
{"name": "libfdisk", "source_rpm": "util-linux-2.37.4-25.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libffi", "source_rpm": "libffi-3.4.2-8.el9.src.rpm", "license": "MIT", "policy": "redhat-ubi9"},
{"name": "libgcc", "source_rpm": "gcc-11.5.0-14.el9.src.rpm", "license": "GPLv3+ and GPLv3+ with exceptions and GPLv2+ with exceptions and LGPLv2+ and BSD", "policy": "redhat-ubi9"},
{"name": "libgcrypt", "source_rpm": "libgcrypt-1.10.0-13.el9_8.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libgpg-error", "source_rpm": "libgpg-error-1.42-5.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libmount", "source_rpm": "util-linux-2.37.4-25.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libpwquality", "source_rpm": "libpwquality-1.4.4-8.el9.src.rpm", "license": "BSD or GPLv2+", "policy": "redhat-ubi9"},
{"name": "libseccomp", "source_rpm": "libseccomp-2.5.2-2.el9.src.rpm", "license": "LGPLv2", "policy": "redhat-ubi9"},
{"name": "libselinux", "source_rpm": "libselinux-3.6-3.el9.src.rpm", "license": "Public Domain", "policy": "redhat-ubi9"},
{"name": "libsemanage", "source_rpm": "libsemanage-3.6-5.el9_6.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libsepol", "source_rpm": "libsepol-3.6-3.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libsigsegv", "source_rpm": "libsigsegv-2.13-4.el9.src.rpm", "license": "GPLv2+", "policy": "redhat-ubi9"},
{"name": "libsmartcols", "source_rpm": "util-linux-2.37.4-25.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libtasn1", "source_rpm": "libtasn1-4.16.0-10.el9_8.src.rpm", "license": "GPLv3+ and LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libutempter", "source_rpm": "libutempter-1.2.1-6.el9.src.rpm", "license": "LGPLv2+", "policy": "redhat-ubi9"},
{"name": "libuuid", "source_rpm": "util-linux-2.37.4-25.el9.src.rpm", "license": "BSD", "policy": "redhat-ubi9"},
{"name": "libxcrypt", "source_rpm": "libxcrypt-4.4.18-3.el9.src.rpm", "license": "LGPLv2+ and BSD and Public Domain", "policy": "redhat-ubi9"},
{"name": "libzstd", "source_rpm": "zstd-1.5.5-1.el9.src.rpm", "license": "BSD and GPLv2", "policy": "redhat-ubi9"},
{"name": "lz4-libs", "source_rpm": "lz4-1.9.3-5.el9.src.rpm", "license": "GPLv2+ and BSD", "policy": "redhat-ubi9"},
{"name": "ncurses-base", "source_rpm": "ncurses-6.2-12.20210508.el9.src.rpm", "license": "MIT", "policy": "redhat-ubi9"},
{"name": "ncurses-libs", "source_rpm": "ncurses-6.2-12.20210508.el9.src.rpm", "license": "MIT", "policy": "redhat-ubi9"},
{"name": "nginx", "source_rpm": "nginx-1.30.4-1.el9.ngx.src.rpm", "license": "2-clause BSD-like license", "policy": "nginx-stable"},
{"name": "openssl", "source_rpm": "openssl-3.5.8-1.el9_8.src.rpm", "license": "Apache-2.0", "policy": "redhat-ubi9"},
{"name": "openssl-fips-provider", "source_rpm": "openssl-fips-provider-3.0.7-11.el9_8.src.rpm", "license": "ASL 2.0", "policy": "redhat-ubi9"},
{"name": "openssl-fips-provider-so", "source_rpm": "openssl-fips-provider-3.0.7-11.el9_8.src.rpm", "license": "ASL 2.0", "policy": "redhat-ubi9"},
{"name": "openssl-libs", "source_rpm": "openssl-3.5.8-1.el9_8.src.rpm", "license": "Apache-2.0", "policy": "redhat-ubi9"},
{"name": "p11-kit", "source_rpm": "p11-kit-0.26.4-1.el9_8.src.rpm", "license": "BSD-3-Clause", "policy": "redhat-ubi9"},
{"name": "p11-kit-trust", "source_rpm": "p11-kit-0.26.4-1.el9_8.src.rpm", "license": "BSD-3-Clause", "policy": "redhat-ubi9"},
{"name": "pam", "source_rpm": "pam-1.5.1-28.el9_8.1.src.rpm", "license": "BSD and GPLv2+", "policy": "redhat-ubi9"},
{"name": "pcre", "source_rpm": "pcre-8.44-4.el9.src.rpm", "license": "BSD", "policy": "redhat-ubi9"},
{"name": "pcre2", "source_rpm": "pcre2-10.40-6.el9.src.rpm", "license": "BSD", "policy": "redhat-ubi9"},
{"name": "pcre2-syntax", "source_rpm": "pcre2-10.40-6.el9.src.rpm", "license": "BSD", "policy": "redhat-ubi9"},
{"name": "procps-ng", "source_rpm": "procps-ng-3.3.17-14.el9.src.rpm", "license": "GPL+ and GPLv2 and GPLv2+ and GPLv3+ and LGPLv2+", "policy": "redhat-ubi9"},
{"name": "readline", "source_rpm": "readline-8.1-4.el9.src.rpm", "license": "GPLv3+", "policy": "redhat-ubi9"},
{"name": "redhat-release", "source_rpm": "redhat-release-9.8-1.0.el9.src.rpm", "license": "GPLv2", "policy": "redhat-ubi9"},
{"name": "sed", "source_rpm": "sed-4.8-10.el9.src.rpm", "license": "GPLv3+", "policy": "redhat-ubi9"},
{"name": "setup", "source_rpm": "setup-2.13.7-10.el9.src.rpm", "license": "Public Domain", "policy": "redhat-ubi9"},
{"name": "shadow-utils", "source_rpm": "shadow-utils-4.9-16.el9.src.rpm", "license": "BSD and GPLv2+", "policy": "redhat-ubi9"},
{"name": "systemd", "source_rpm": "systemd-252-67.el9_8.6.src.rpm", "license": "LGPLv2+ and MIT and GPLv2+", "policy": "redhat-ubi9"},
{"name": "systemd-libs", "source_rpm": "systemd-252-67.el9_8.6.src.rpm", "license": "LGPLv2+ and MIT", "policy": "redhat-ubi9"},
{"name": "systemd-pam", "source_rpm": "systemd-252-67.el9_8.6.src.rpm", "license": "LGPLv2+ and MIT and GPLv2+", "policy": "redhat-ubi9"},
{"name": "systemd-rpm-macros", "source_rpm": "systemd-252-67.el9_8.6.src.rpm", "license": "LGPLv2+ and MIT and GPLv2+", "policy": "redhat-ubi9"},
{"name": "tzdata", "source_rpm": "tzdata-2026c-1.el9_8.src.rpm", "license": "Public Domain", "policy": "redhat-ubi9"},
{"name": "util-linux", "source_rpm": "util-linux-2.37.4-25.el9.src.rpm", "license": "GPLv2 and GPLv2+ and LGPLv2+ and BSD with advertising and Public Domain", "policy": "redhat-ubi9"},
{"name": "util-linux-core", "source_rpm": "util-linux-2.37.4-25.el9.src.rpm", "license": "GPLv2 and GPLv2+ and LGPLv2+ and BSD with advertising and Public Domain", "policy": "redhat-ubi9"},
{"name": "xz-libs", "source_rpm": "xz-5.2.5-8.el9_0.src.rpm", "license": "Public Domain", "policy": "redhat-ubi9"},
{"name": "zlib", "source_rpm": "zlib-1.2.11-40.el9.src.rpm", "license": "zlib and Boost", "policy": "redhat-ubi9"}
]
}
39 changes: 39 additions & 0 deletions artifacts/nginx-features.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"schema_version": 1,
"nginx_version": "1.30.4",
"nginx_rpm_version": "1.30.4-1.el9.ngx",
"compiled_features": [
"--with-compat",
"--with-file-aio",
"--with-threads"
],
"compiled_optional_modules": [
"--with-http_addition_module",
"--with-http_auth_request_module",
"--with-http_dav_module",
"--with-http_flv_module",
"--with-http_gunzip_module",
"--with-http_gzip_static_module",
"--with-http_mp4_module",
"--with-http_random_index_module",
"--with-http_realip_module",
"--with-http_secure_link_module",
"--with-http_slice_module",
"--with-http_ssl_module",
"--with-http_stub_status_module",
"--with-http_sub_module",
"--with-http_v2_module",
"--with-http_v3_module",
"--with-mail",
"--with-mail_ssl_module",
"--with-stream",
"--with-stream_realip_module",
"--with-stream_ssl_module",
"--with-stream_ssl_preread_module"
],
"dynamic_module_files": [],
"compiled_but_unsupported_subsystems": [
"mail",
"stream"
]
}
Loading
Loading