diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..cd0028b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,6 @@ +* @joey-huckabee + +/.github/ @joey-huckabee +/Containerfile @joey-huckabee +/container/ @joey-huckabee +/tests/ @joey-huckabee diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..fc5dbc5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,66 @@ +name: Bug report +description: Report reproducible image, runtime, or documentation behavior +title: "bug: " +labels: + - bug +body: + - type: markdown + attributes: + value: >- + Do not disclose vulnerabilities here. Use the private security link + shown before opening an issue. + - type: input + id: image + attributes: + label: Image tag and digest + description: Include both when available; do not report only a mutable tag. + placeholder: ghcr.io/datopsis/nginx-ubi9:v...@sha256:... + validations: + required: true + - type: input + id: runtime + attributes: + label: Runtime, host, and versions + placeholder: RHEL and Podman, Docker, or OpenShift versions + validations: + required: true + - type: dropdown + id: architecture + attributes: + label: Architecture + options: + - linux/amd64 + - linux/arm64 + - Other or unknown + validations: + required: true + - type: textarea + id: configuration + attributes: + label: Minimal NGINX and deployment configuration + description: Remove credentials, keys, internal names, and other secrets. + render: text + validations: + required: true + - type: textarea + id: behavior + attributes: + label: Reproduction and observed behavior + description: List exact steps, the result, and the expected result. + validations: + required: true + - type: textarea + id: logs + attributes: + label: Relevant logs + description: Redact secrets and personal or internal information. + render: text + - type: checkboxes + id: checks + attributes: + label: Checks + options: + - label: I searched existing issues and tested the current development revision or a supported release. + required: true + - label: I removed secrets and sensitive data from this report. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..98c4d2a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Report a vulnerability privately + url: https://github.com/datopsis/nginx-ubi/security/advisories/new + about: Never disclose a suspected vulnerability in a public issue. + - name: NGINX upstream + url: https://nginx.org/en/support.html + about: Use upstream channels for behavior that reproduces outside this image. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..cd254d7 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ +## Summary + +Describe the user-facing or operational outcome and why the change is needed. + +## Validation + +- [ ] I ran the relevant local checks from `docs/CI.md`. +- [ ] I reviewed logs, warnings, annotations, skipped steps, and retained + evidence rather than relying only on green status checks. +- [ ] I added or updated tests for behavior changes. +- [ ] I updated user and operator documentation where needed. +- [ ] I recorded notable completed work in `CHANGELOG.md` and removed it from + the forward-looking roadmap where applicable. +- [ ] I did not weaken a security or release control without documenting the + threat, rationale, compensating control, owner, and expiry. + +## Security and release impact + +State whether this changes image contents, runtime behavior, supported scope, +or release evidence. If it changes a published artifact, identify the required +version action under `docs/VERSION.md`. List accepted findings or write `None`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 945d6a7..fd0caa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ but container releases use the upstream-derived format documented in ### Added +- Added the Apache License 2.0 for Datopsis-authored work, third-party notices, + contribution guidance, and a private vulnerability-reporting policy. +- Defined support classifications, published the current development support + matrix and ownership boundary, and documented repository governance. +- Added Code Owners, a security-aware pull request template, and structured + public bug-report and private security-reporting routes. - Established repository guidance for secure, rootless image development and review. - Defined the forward-looking first-release roadmap and evidence lifecycle. @@ -28,6 +34,8 @@ but container releases use the upstream-derived format documented in hash-locked CI Python environment. - Documented local checks, GitHub automation, planned image assurance, and the evidence boundary of Podman Desktop or a remote Podman machine. +- Added a contributor environment record for the exercised Ubuntu WSL2 and + rootless Podman development setup. - Added an initial package-manager-free UBI 9 Micro development image using an exact Red Hat NGINX RPM build. - Added rootless NGINX defaults for unprivileged HTTP, read-only-root operation, @@ -49,8 +57,6 @@ but container releases use the upstream-derived format documented in - Expanded the first-release roadmap with deployment qualification, systemd and logging tests, OSCAL/control engineering, requirement-source review, FIPS boundary analysis, go-live evidence, and an assurance-completeness gate. -- Made upgrading the existing Ubuntu WSL2 Podman environment and rerunning the - complete Shell/Quadlet qualification the next roadmap action. - Added GitHub topics for NGINX, containers, Podman, OpenShift, UBI 9, and supply-chain security. - Extended CI with native AMD64 and ARM64 builds, restricted-runtime tests, @@ -72,3 +78,25 @@ but container releases use the upstream-derived format documented in effective capabilities, `no-new-privileges`, arbitrary-UID operation, read-only-root behavior, hardened temporary storage, log routing, graceful reload and shutdown, and actionable negative startup cases. + +### Changed + +- Renamed the source repository from `nginx-ubi9` to `nginx-ubi` so repository + identity does not prevent future work on other UBI major versions; existing + image, service, and UBI 9 identifiers remain unchanged. +- Upgraded the reference contributor environment from Ubuntu 22.04.5 and + Podman 3.4.4 to Ubuntu 24.04.5 and Podman 5.8.2, verified the restricted + runtime and Quadlet lifecycle after a cold WSL restart, and retired the + completed upgrade plan from the forward-looking roadmap. +- Retired the completed project-contract package from the forward-looking + roadmap after its repository files and current support boundary were added. + +### Security + +- Enabled GitHub vulnerability alerts, Dependabot security updates, secret + scanning with push protection, and private vulnerability reporting. + +### Fixed + +- Prevented the Docker smoke suite from failing with SIGPIPE when short-circuit + log and response assertions run under `pipefail`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1e7798b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,51 @@ +# Contributing + +Contributions are welcome through GitHub pull requests. Security reports must +use the private process in [SECURITY.md](SECURITY.md), not a public issue. + +## Before changing the repository + +1. Read [the agent and contributor guidance](CLAUDE.md), the + [forward-looking roadmap](docs/ROADMAP.md), and the + [support definitions](docs/SUPPORT.md). +2. Keep runtime additions minimal and explain why each package, module, port, + writable path, capability, or network permission is required. +3. Pin base images and external inputs as required by the artifact-acquisition + policy. Never commit credentials, private keys, private CAs, or internal + repository locations. +4. Add or update automated tests, operational guidance, security + considerations, and support classification together when behavior changes. +5. Record notable completed work under `Unreleased` in `CHANGELOG.md` and + remove completed work from `docs/ROADMAP.md`; the roadmap remains forward + looking. + +Do not weaken the non-root default, checksum and signature verification, +vulnerability gates, read-only-root compatibility, dropped-capability and +no-new-privileges baseline, SCAP evidence boundary, or signed-release process +merely to make a test pass. + +## Validate a change + +Install and run the pinned repository checks: + +```console +python -m pip install --require-hashes --only-binary=:all: \ + --requirement .github/requirements/pre-commit.txt +pre-commit install --install-hooks +pre-commit run --all-files --show-diff-on-failure +``` + +For image-affecting changes, use the build and smoke commands in `README.md`. +The exercised local WSL2 configuration and its evidence limitations are in +`docs/CONTRIBUTOR-ENVIRONMENT.md`. A local success does not replace native +architecture CI or release-candidate platform qualification. + +## Pull requests and commits + +Keep changes small and dependency ordered. Complete the pull request template, +identify image, runtime, security, documentation, and release impact, and +review logs and retained evidence rather than relying only on green checkmarks. + +Use concise Conventional Commit subjects such as `feat:`, `fix:`, `docs:`, +`test:`, `ci:`, `build:`, `refactor:`, or `chore:`. Do not add AI, assistant, +tool-attribution, or `Co-Authored-By` trailers to commits. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..db64ec4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Datopsis + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index df3f464..1e4ddee 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,16 @@ root filesystem, explicit `tmpfs` mounts, dropped capabilities, and - [Versioning and releases](docs/VERSION.md) separates container artifact versions from repository-only revisions. - [Changelog](CHANGELOG.md) records notable completed changes. +- [Contributing](CONTRIBUTING.md) defines change, validation, pull-request, and + commit expectations. +- [Security policy](SECURITY.md) provides private vulnerability reporting and + states the current absence of a supported release. +- [Support definitions](docs/SUPPORT.md) defines supported, compatible, + preview/unqualified, and unsupported and publishes the current matrix. +- [Repository governance](docs/REPOSITORY-GOVERNANCE.md) records branch, + review, automation, security-setting, and future tag-protection requirements. +- [Third-party notices](THIRD_PARTY_NOTICES.md) separates this project's + license from NGINX, UBI, and component terms. - [Agent guidance](CLAUDE.md) defines repository implementation and security conventions. - [Continuous integration](docs/CI.md) documents current automation, local @@ -105,8 +115,8 @@ root filesystem, explicit `tmpfs` mounts, dropped capabilities, and contract. TLS, configuration, architecture, control-matrix/OSCAL, SCAP, -vulnerability-management, support, and disconnected-network guides will be -added as their associated implementations and evidence are developed. +vulnerability-management, and disconnected-network guides will be added as +their associated implementations and evidence are developed. ## Images and releases @@ -161,10 +171,18 @@ CI supplies the canonical Linux shell execution and native architecture evidence. See the [continuous integration guide](docs/CI.md) for hook installation and -Podman evidence boundaries. Until the first signed release is published, this -repository should be treated as development material rather than a supported -production image. +Podman evidence boundaries. The +[contributor environment record](docs/CONTRIBUTOR-ENVIRONMENT.md) documents the +currently exercised Ubuntu WSL2 setup and its limitations. Until the first +signed release is published, this repository should be treated as development +material rather than a supported production image. -Security concerns should not be disclosed in a public issue. A private -reporting process and supported-version policy will be published in -`SECURITY.md` during the project-contract work package. +Security concerns must not be disclosed in a public issue. Follow the private +process in [SECURITY.md](SECURITY.md). + +## License + +Datopsis-authored packaging code and documentation are licensed under the +[Apache License 2.0](LICENSE). NGINX, Red Hat UBI, and installed components +retain their respective licenses and terms; see +[third-party software and terms](THIRD_PARTY_NOTICES.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..c4be81c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,38 @@ +# Security policy + +## Supported versions + +No supported image has been published. Repository revisions and development +images are available for evaluation but receive no security-support commitment. +Each future release will document its exact support status and supersession +policy; support must not be inferred from a tag, branch, successful build, or +scanner result. + +## Reporting a vulnerability + +Do not open a public issue for a suspected vulnerability. Use the repository's +**Security** tab and select **Report a vulnerability** to submit a private +security advisory: + + + +Include the affected image tag and digest when available, architecture, +runtime and host versions, configuration profile, reproduction steps, and +whether the issue appears to originate in this packaging, NGINX, or UBI. Remove +credentials, private keys, internal hostnames, customer data, and other secrets. + +Upstream vulnerabilities should also follow the applicable upstream process: + +- NGINX: +- Red Hat: + +## Handling and disclosure + +Maintainers will acknowledge a private report when practical, validate its +scope, coordinate with upstream suppliers when appropriate, and agree on a +disclosure plan before publishing details. No response or remediation SLA is +promised until the first supported release defines one. + +Scanner matches require vendor context. Red Hat can backport corrections +without adopting the upstream version number a scanner expects. Review the +exact RPM build and Red Hat advisory data before classifying a match. diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md new file mode 100644 index 0000000..4e2a8b5 --- /dev/null +++ b/THIRD_PARTY_NOTICES.md @@ -0,0 +1,42 @@ +# Third-party software and terms + +The root [Apache License 2.0](LICENSE) applies to Datopsis-authored packaging +code and documentation in this repository. It does not replace the licenses or +terms of software assembled into the container image. + +## NGINX + +The image installs the exact NGINX RPM selected by the project. NGINX +open-source software is distributed under its +[two-clause BSD license](https://nginx.org/LICENSE). NGINX names and marks +remain the property of their respective owners. This independent packaging +project is not affiliated with or endorsed by F5 or the NGINX project. + +## Red Hat Universal Base Image + +The base and installed runtime RPMs come from Red Hat UBI images and UBI +repositories. UBI content is redistributable subject to the +[Red Hat UBI terms and component licenses](https://developers.redhat.com/articles/ubi-faq). +Red Hat support is not included with this community image; eligibility depends +on the applicable subscription and supported deployment combination. + +The image retains installed component license material. Release SBOMs must +identify the exact RPM inventory and licenses. The OCI license expression +describes the principal packaging and NGINX license relationship; consumers +must also review the SBOM, embedded notices, UBI terms, and every component's +license. + +## Release review + +Before publishing a release: + +1. Confirm all Red Hat packages came from approved UBI repositories and remain + redistributable. +2. Confirm the selected NGINX package source, license, signature, and source RPM + are recorded. +3. Inspect the SBOM for new packages, unknown licenses, and missing notices. +4. Retain upstream copyright, license, attribution, and trademark notices. +5. Update this file when package sources, image contents, branding, or + distribution channels change. + +This notice is operational documentation, not legal advice. diff --git a/docs/CONTRIBUTOR-ENVIRONMENT.md b/docs/CONTRIBUTOR-ENVIRONMENT.md new file mode 100644 index 0000000..4f27c19 --- /dev/null +++ b/docs/CONTRIBUTOR-ENVIRONMENT.md @@ -0,0 +1,127 @@ +# Contributor development environment + +This document records the Ubuntu WSL2 environment exercised by contributors. +It is development evidence only. It does not qualify WSL2 as a supported +deployment platform or replace the exact RHEL-host evidence required before a +supported release. + +## Exercised baseline + +The environment was upgraded and requalified on 2026-09-10: + +| Component | Exercised value | +| --- | --- | +| WSL | 2.7.13.0 | +| Ubuntu | 24.04.5 LTS | +| Kernel | 6.18.33.2-microsoft-standard-WSL2 | +| Init and cgroups | systemd with unified cgroup v2 | +| Podman | 5.8.2, upstream tag `v5.8.2` | +| Podman commit | `5b263b5f5b48004a87caac44e67349a8266d9ef4` | +| Podman build toolchain | Go 1.26.8; removed after installation | +| OCI runtime | Ubuntu `runc` 1.3.4 | +| Container monitor | Ubuntu `conmon` 2.1.10 | +| Network stack | Netavark 1.4.0 with Aardvark DNS 1.4.0 | +| Rootless port forwarding | `slirp4netns` 1.2.1 | +| Storage driver | rootless overlay with `fuse-overlayfs` 1.13 available | + +Podman was built from the upstream signed Git tag after its tag object and +commit were verified. The engine is installed under `/usr/local`, which is the +filesystem hierarchy reserved for locally administered software: + +```text +/usr/local/bin/podman +/usr/local/bin/podman-remote +/usr/local/libexec/podman/quadlet +/usr/local/libexec/podman/rootlessport +``` + +`/usr/bin/podman` is a symbolic link to `/usr/local/bin/podman`. This allows +deployment examples that use the conventional package path to invoke the same +5.8.2 engine used by the source-installed Quadlet generator. The Ubuntu Podman, +Buildah, and older `crun` packages are not installed. + +Ubuntu remains the source of the runtime helpers and shared libraries. The +required packages are marked as explicitly installed so `apt autoremove` does +not remove them merely because the Ubuntu Podman package is absent. + +## Rootless configuration + +The contributor account has subordinate UID and GID mappings, lingering +enabled, and an active systemd user manager. Its local containers.conf drop-in +selects the supported OCI runtime and the WSL-compatible port forwarder: + +```toml +[engine] +runtime = "runc" + +[network] +default_rootless_network_cmd = "slirp4netns" +``` + +The drop-in is stored at: + +```text +~/.config/containers/containers.conf.d/99-source-podman-runtime.conf +``` + +Podman 5.8.2 otherwise selected `pasta` by default. In this WSL environment, +same-port forwarding such as `127.0.0.1:8080:8080` reset connections even +though translated and dynamically assigned ports worked. The same mapping +worked with `slirp4netns`, so the override is a development-host compatibility +setting rather than an image requirement. + +AppArmor support was compiled into Podman and the kernel module was present, +but the AppArmor security filesystem was not mounted. This run therefore does +not provide AppArmor policy-enforcement evidence. WSL2 also does not replace +the planned SELinux-enforcing RHEL qualification. + +## Qualification performed + +The following checks passed with a clean rootless store and again after +`wsl --shutdown` and a cold Ubuntu restart: + +- Podman 5.8.2 selected `runc`, systemd cgroups, cgroup v2, Netavark, and the + overlay storage driver. +- The development image built from the repository's digest-pinned UBI inputs. +- `tests/smoke.sh` completed without skipped assertions. +- The preview Quadlet generated successfully, including its memory limit. +- Quadlet start, health, static content, NGINX configuration validation, + journald logging, reload, and graceful stop succeeded. +- The running service used UID/GID `999:0`, a read-only root, no effective + capabilities, `no-new-privileges`, a 512 MiB memory limit, and a 128-process + limit. +- systemd reached `running` after the cold restart with no failed units. + +The validation images, containers, volumes, build layers, temporary Quadlet, +configuration copies, source tree, compiler toolchain, and rootless storage +were removed after qualification. The results describe repository commit +`d47148359ea6328521c05321b19a4274c76bf3e`; they are not release-candidate +evidence for later image-affecting revisions. + +## Contributor checks + +After changing the local runtime or upgrading a helper, recheck the engine +before building: + +```console +podman version +podman info +systemctl --user is-system-running +stat -fc %T /sys/fs/cgroup +``` + +Then use the canonical repository workflow: + +```console +podman build --format docker --file Containerfile \ + --tag localhost/nginx-ubi9:development . +CONTAINER_RUNTIME=podman IMAGE=localhost/nginx-ubi9:development \ + bash tests/smoke.sh +``` + +Installing Ubuntu's `podman` package can replace the `/usr/bin/podman` +symbolic link and reintroduce two engine versions. Treat that as an intentional +engine replacement: review the package plan, revalidate the dependency set, +and repeat the cold-start build and smoke checks. A future source upgrade must +also verify the upstream tag and commit, stage the install for review, and +requalify Quadlet and rootless runtime behavior. diff --git a/docs/REPOSITORY-GOVERNANCE.md b/docs/REPOSITORY-GOVERNANCE.md new file mode 100644 index 0000000..7c40ad1 --- /dev/null +++ b/docs/REPOSITORY-GOVERNANCE.md @@ -0,0 +1,45 @@ +# Repository governance + +## Protected default branch + +The active `Protect main` ruleset targets the default branch and: + +- blocks deletion and non-fast-forward pushes; +- requires changes through pull requests and resolved review threads; +- requires up-to-date `lint`, `configuration security`, and aggregate `image` + checks; +- requires approval for unattributed changes; and +- has no bypass actors. + +Required approving reviews and Code Owner review currently remain zero. Enable +them only when enough independent maintainers are regularly available to avoid +deadlocking changes. Any emergency relaxation must be time bounded, justified +in the pull request, approved by a maintainer, and restored immediately. + +## Security and automation settings + +Keep dependency graph and vulnerability alerts, Dependabot security updates, +secret scanning, push protection, and private vulnerability reporting enabled. +Workflow permissions remain read-only by default; jobs receive write access +only for a documented publication step. Third-party Actions must use immutable +commit SHAs. + +Verify these controls after a repository rename, transfer, visibility change, +or organization-policy change. Settings outside Git cannot be proven by the +presence of this document alone. + +## Release tags + +Before the first release, add an active tag ruleset matching the release format +in `VERSION.md`. It must block tag deletion and updates, prohibit bypass, and +allow creation only through the reviewed release procedure. Do not create a +tag rule before the release workflow and authorized actors are defined well +enough to avoid either bypassing protection or blocking every legitimate +release. + +## Review ownership + +`CODEOWNERS` identifies review responsibility but does not grant access or +replace branch protection. Image, workflow, test, and release-sensitive changes +require explicit security and release-impact review through the pull request +template. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 665971f..34e4d7d 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -9,37 +9,6 @@ release asset, or qualification record. Automated success is not sufficient where an item requires human analysis, an external environment, or a support decision. -## Next action: upgrade the existing WSL2 Podman environment - -This is the first work item for the next development session. Keep the current -Ubuntu WSL2 distribution; do not replace it solely to obtain Podman. - -- [ ] Export or otherwise back up the WSL2 development distribution and record - its current Ubuntu, kernel, systemd, Podman, OCI runtime, cgroup, storage, and - rootless configuration. -- [ ] Select a maintained, trustworthy upgrade path for a current Podman and - its compatible Buildah, conmon, crun, networking, and containers-common - dependencies. Do not use an unreviewed or bleeding-edge package source. -- [ ] Fully update the existing Ubuntu installation from its maintained - repositories, review the release-upgrade plan and available disk space, and - preserve the WSL export before package removal or distribution changes. -- [ ] Remove the currently observed Ubuntu 22.04.5 `podman 3.4.4` package - before installing the newer Podman package. Preserve or deliberately retire - rootless container storage; do not use package removal as an implicit data- - deletion operation. -- [ ] Complete the approved Ubuntu maintenance/release upgrade, fully update - the resulting system, and install the selected newer Podman plus its matched - dependencies from the maintained source. -- [ ] Verify rootless operation, cgroup v2 delegation, systemd user services, - subordinate IDs, networking, SELinux/AppArmor status, and the Quadlet - generator. Quadlet requires Podman 4.6 or newer, but the selected version - must also meet the project's complete runtime and support criteria. -- [ ] Load or build the development image and rerun the complete Bash smoke - suite without skipped assertions; retain the engine and result evidence. -- [ ] Dry-run and exercise the preview Quadlet, including health, reload, - journald, restart, stop, boot/login behavior, update, and rollback. WSL2 - remains development evidence and does not replace target RHEL qualification. - ## Evidence lifecycle Evidence has three levels: @@ -108,17 +77,6 @@ Steps 1 through 4 are the immediate engineering critical path. Steps 5 and 6 can proceed in parallel only where they do not assume an unfrozen NGINX package or module set. -## Package 1: project contract and minimal skeleton - -- [ ] Add `LICENSE`, `SECURITY.md`, `CONTRIBUTING.md`, notices, editor settings, - and ignore rules. -- [ ] Define supported, compatible, preview/unqualified, and unsupported. -- [ ] Publish the initial support matrix and explicit control ownership split. -- [ ] Add Code Owners and pull-request and issue templates. -- [ ] Document required GitHub rulesets, least-privilege Actions defaults, - secret scanning, push protection, private vulnerability reporting, and tag - protection. - ## Package 2: rootless minimal image - [ ] Approve official NGINX stable as the package channel and select an exact diff --git a/docs/SUPPORT.md b/docs/SUPPORT.md new file mode 100644 index 0000000..adda8bb --- /dev/null +++ b/docs/SUPPORT.md @@ -0,0 +1,49 @@ +# Support definitions and current boundary + +No supported container image has been released. Everything currently in this +repository is development material unless an immutable release and its evidence +explicitly state otherwise. + +## Definitions + +- **Supported** means an exact immutable image digest, architecture, + configuration profile, host/runtime combination, and support period passed + the documented release gates and is named by a published support statement. +- **Compatible** means limited tests demonstrated a behavior, but the project + makes no production-support or security-maintenance commitment for that + combination. +- **Preview/unqualified** means the material is available for evaluation while + required tests, operational guidance, or review remain incomplete. +- **Unsupported** means the project does not intend to qualify or maintain the + behavior within the stated release boundary. + +Absence from a matrix means unqualified, not implicitly compatible. + +## Current matrix + +| Area | Current classification | Evidence or limitation | +| --- | --- | --- | +| Published images | Unsupported | No release has been published. | +| Repository development image | Preview/unqualified | Rootless smoke tests exist; release inputs and evidence are not frozen. | +| Linux AMD64 and ARM64 | Preview/unqualified | Native CI exists; release-candidate evidence is not complete. | +| Ubuntu WSL2 | Compatible for contributor development | The recorded environment passes build, smoke, and Quadlet tests but is not a deployment target. | +| Standalone RHEL/Podman | Preview/unqualified | Exact SELinux-enforcing host qualification remains future work. | +| OpenShift | Preview/unqualified | Restricted-SCC and exact-release qualification remain future work. | +| Docker | Compatible for CI behavior | Docker evidence does not establish rootless Podman equivalence. | + +## Ownership boundary + +The image project owns verified build inputs, image userspace, the non-root +default, documented ports and writable paths, default NGINX configuration, +tests, SBOM/provenance/signature production, and image vulnerability response. + +The host or orchestrator owns the kernel, container runtime, cgroups, +namespaces, seccomp and SELinux/AppArmor enforcement, networking, firewall and +ingress, secrets, certificates and trust, persistent storage, resource policy, +logging retention, monitoring, backup, and incident response. Operators own +their NGINX configuration, upstreams, DNS, exposure, TLS choices, and update +approval. See [Security controls](SECURITY-CONTROLS.md) for the detailed split. + +Successful scanning, use of UBI, or a passing tailored SCAP result does not +make this community image Red Hat supported, FIPS validated, STIG certified, +or broadly compliant. diff --git a/tests/smoke.sh b/tests/smoke.sh index 4235823..b0bc710 100644 --- a/tests/smoke.sh +++ b/tests/smoke.sh @@ -11,7 +11,7 @@ invalid_config="${prefix}-invalid-config" missing_tmp_runtime_args=() no_new_privileges="no-new-privileges:true" -if "${runtime}" --version 2>&1 | grep -qi podman; then +if grep -qi podman <<< "$("${runtime}" --version 2>&1)"; then # Podman otherwise creates writable tmpfs mounts for read-only containers. missing_tmp_runtime_args+=(--read-only-tmpfs=false) # Older supported-for-development Podman releases reject Docker's :true @@ -170,14 +170,16 @@ assert_tmpfs_security "${primary}" binding="$("${runtime}" port "${primary}" 8080/tcp)" host_port="${binding##*:}" test "$(curl --fail --silent --show-error "http://127.0.0.1:${host_port}/healthz")" = "ok" -curl --fail --silent --show-error "http://127.0.0.1:${host_port}/" | grep -Fq 'NGINX on UBI 9' +grep -Fq 'NGINX on UBI 9' <<< \ + "$(curl --fail --silent --show-error "http://127.0.0.1:${host_port}/")" test "$(curl --silent --show-error --output /dev/null --write-out '%{http_code}' \ "http://127.0.0.1:${host_port}/missing?smoke-probe=value")" = "404" -curl --fail --silent --show-error --dump-header - --output /dev/null \ - "http://127.0.0.1:${host_port}/healthz" | \ - grep -Eiq '^server: nginx[[:space:]]*$' -"${runtime}" logs "${primary}" 2>&1 | grep -Fq '/missing?smoke-probe=value' -if "${runtime}" logs "${primary}" 2>&1 | grep -Fq 'GET /healthz'; then +grep -Eiq '^server: nginx[[:space:]]*$' <<< \ + "$(curl --fail --silent --show-error --dump-header - --output /dev/null \ + "http://127.0.0.1:${host_port}/healthz")" +primary_logs="$("${runtime}" logs "${primary}" 2>&1)" +grep -Fq '/missing?smoke-probe=value' <<< "${primary_logs}" +if grep -Fq 'GET /healthz' <<< "${primary_logs}"; then echo "The health endpoint unexpectedly wrote an access event" >&2 exit 1 fi @@ -201,8 +203,8 @@ assert_tmpfs_security "${arbitrary}" --security-opt "${no_new_privileges}" \ "${image}" >/dev/null wait_for_exit "${missing_tmp}" -"${runtime}" logs "${missing_tmp}" 2>&1 | grep -Eiq \ - 'read-only file system|/tmp/nginx.pid' +grep -Eiq 'read-only file system|/tmp/nginx.pid' <<< \ + "$("${runtime}" logs "${missing_tmp}" 2>&1)" "${runtime}" run --detach --name "${invalid_config}" \ --read-only \ @@ -214,8 +216,8 @@ wait_for_exit "${missing_tmp}" 'printf "invalid_directive;\n" > /tmp/invalid.conf; exec nginx -t -c /tmp/invalid.conf' \ >/dev/null wait_for_exit "${invalid_config}" -"${runtime}" logs "${invalid_config}" 2>&1 | grep -Eiq \ - 'unknown directive.*invalid_directive|emerg' +grep -Eiq 'unknown directive.*invalid_directive|emerg' <<< \ + "$("${runtime}" logs "${invalid_config}" 2>&1)" assert_clean_exit "${arbitrary}" assert_clean_exit "${primary}"