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
2 changes: 1 addition & 1 deletion .github/workflows/codeql-verification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
shell: bash
run: |
set -euo pipefail
test "$(python3 --version)" = 'Python 3.14.7'
test "$(python3 --version)" = 'Python 3.14.9'
PYTHONDONTWRITEBYTECODE=1 python3 -m compileall -q tests/integration

- name: Initialize CodeQL
Expand Down
30 changes: 19 additions & 11 deletions .github/workflows/security-release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
env:
DAPPER_IMAGE: pasturestack/compose-cli-dapper:${{ github.sha }}
TRIVY_IMAGE: aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969
VERSION_OVERRIDE: 0.14.38
VERSION_OVERRIDE: 0.14.39
PLATFORM_COMPAT_JAR_URL: https://github.com/PastureStack/orchestration-engine/releases/download/v0.183.281/orchestration-engine-0.183.281.jar
PLATFORM_COMPAT_JAR_SHA256: da2a8a51562ed16e296f7e29e99482bb44042ff0834cca679bbe01d951ba1682

Expand Down Expand Up @@ -69,7 +69,7 @@ jobs:
}

run_ci
artifact="dist/artifacts/compose-executor-0.14.38-linux-amd64.gz"
artifact="dist/artifacts/compose-executor-0.14.39-linux-amd64.gz"
test -s "$artifact"
cp "$artifact" /tmp/compose-executor-first.gz

Expand All @@ -81,7 +81,7 @@ jobs:
mkdir -p evidence/product
gzip -cd "$artifact" > evidence/product/compose-executor
chmod +x evidence/product/compose-executor
evidence/product/compose-executor --version | grep -F '0.14.38' >/dev/null
evidence/product/compose-executor --version | grep -F '0.14.39' >/dev/null
cp "$artifact" evidence/
(
cd evidence
Expand Down Expand Up @@ -149,15 +149,23 @@ jobs:
-v "$PWD:/work" -w /work \
-v "$trivy_cache:/root/.cache/trivy" \
"$TRIVY_IMAGE" image \
--scanners vuln,secret --format json \
--scanners vuln,secret --list-all-pkgs --format json \
--output /work/evidence/dapper-image-raw.json "$DAPPER_IMAGE"

docker run --rm --entrypoint python3 "$DAPPER_IMAGE" \
/opt/python-security/scripts/check-pip-vendor-slice.py \
> evidence/pip-vendor-proof.json
python3 scripts/pip-security/test-pip-vex.py
python3 scripts/pip-security/filter-pip-vendor-findings.py \
--raw evidence/dapper-image-raw.json --proof evidence/pip-vendor-proof.json \
--output evidence/dapper-image-applicable.json --vex evidence/pip-vendor.openvex.json \
--subject "$(docker image inspect --format '{{.Id}}' "$DAPPER_IMAGE")"
jq -r '
.Results[]?.Vulnerabilities[]?
| select(.Severity == "CRITICAL" or .Severity == "HIGH")
| [.VulnerabilityID, .PkgIdentifier.PURL]
| @tsv
' evidence/dapper-image-raw.json | LC_ALL=C sort -u \
' evidence/dapper-image-applicable.json | LC_ALL=C sort -u \
> /tmp/dapper-critical-high.tsv
grep -F $'build\tCGO_ENABLED=0' evidence/product-go-version.txt >/dev/null
if grep -Eq '^linux-(image|modules)([-:]|[[:space:]])' evidence/dapper-dpkg.tsv; then
Expand All @@ -168,10 +176,10 @@ jobs:
.Results[]?.Vulnerabilities[]?
| select(.Severity == "CRITICAL" or .Severity == "HIGH")
| select(.PkgName != "linux-libc-dev" or ((.FixedVersion // "") != ""))
] | length' evidence/dapper-image-raw.json)"
] | length' evidence/dapper-image-applicable.json)"
test "$dapper_unreviewed" -eq 0
jq -n \
--slurpfile report evidence/dapper-image-raw.json \
--slurpfile report evidence/dapper-image-applicable.json \
--arg author 'PastureStack Security' \
--arg timestamp "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
--arg impact 'linux-libc-dev supplies user-space kernel API headers only in the disposable build and race-test image. The package is not copied into the CGO-disabled product binary, so the vulnerable kernel implementation is not shipped.' \
Expand Down Expand Up @@ -238,11 +246,11 @@ jobs:
product_critical=$(count evidence/product-security.json '[.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length')
product_high=$(count evidence/product-security.json '[.Results[]?.Vulnerabilities[]? | select(.Severity == "HIGH")] | length')
product_applicable=$(count evidence/product-security.json '[.Results[]?.Vulnerabilities[]? | select(.Status != "not_affected")] | length')
dapper_raw_critical=$(count evidence/dapper-image-raw.json '[.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length')
dapper_raw_high=$(count evidence/dapper-image-raw.json '[.Results[]?.Vulnerabilities[]? | select(.Severity == "HIGH")] | length')
dapper_raw_critical=$(count evidence/dapper-image-applicable.json '[.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL")] | length')
dapper_raw_high=$(count evidence/dapper-image-applicable.json '[.Results[]?.Vulnerabilities[]? | select(.Severity == "HIGH")] | length')
dapper_reviewed=$(count evidence/dapper.openvex.json '.statements | length')
dapper_unreviewed=$(count evidence/dapper-image-raw.json '[.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL" or .Severity == "HIGH") | select(.PkgName != "linux-libc-dev" or ((.FixedVersion // "") != ""))] | length')
dapper_secrets=$(count evidence/dapper-image-raw.json '[.Results[]?.Secrets[]?] | length')
dapper_unreviewed=$(count evidence/dapper-image-applicable.json '[.Results[]?.Vulnerabilities[]? | select(.Severity == "CRITICAL" or .Severity == "HIGH") | select(.PkgName != "linux-libc-dev" or ((.FixedVersion // "") != ""))] | length')
dapper_secrets=$(count evidence/dapper-image-applicable.json '[.Results[]?.Secrets[]?] | length')
{
printf 'source_secrets=%s\n' "$source_secrets"
printf 'source_applicable=%s\n' "$source_applicable"
Expand Down
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.14.7
3.14.9
16 changes: 15 additions & 1 deletion Dockerfile.dapper
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM ubuntu:26.04@sha256:2260313b31c8c011cd2eebe728008efac1b3982be73eb71348ea2648d2c0e09b

COPY ubuntu-apt.lock /licenses/ubuntu-apt.lock
ADD --checksum=sha256:6077d27c6b6f8b23590cb01ff877ed8c804a67a5442cc32b5a33da10d2bd0e90 https://archive.ubuntu.com/ubuntu/pool/main/c/ca-certificates/ca-certificates_20260601~26.04.1_all.deb /tmp/ca-certificates.deb
ADD --checksum=sha256:5b6326f1932cfd7be57130561dc78192f09ed9f58bfbe6606ed0c50510c3b6cd https://archive.ubuntu.com/ubuntu/pool/main/c/ca-certificates/ca-certificates_20260816ubuntu0.26.04.1_all.deb /tmp/ca-certificates.deb

ARG GO_VERSION=1.27.3
ARG GO_SHA256_amd64=65efbc80fdc1fa2cd2631cad5b481777a68e8725f34e89f50fc6ac714e379b40
Expand All @@ -17,6 +17,7 @@ ENV DEBIAN_FRONTEND=noninteractive \
XDG_CONFIG_HOME=/tmp/go-config \
PATH=/go/bin:/usr/local/go/bin:${PATH}

ADD --checksum=sha256:5b6326f1932cfd7be57130561dc78192f09ed9f58bfbe6606ed0c50510c3b6cd https://archive.ubuntu.com/ubuntu/pool/main/c/ca-certificates/ca-certificates_20260816ubuntu0.26.04.1_all.deb /opt/pasturestack-ca-certificates.deb
RUN set -eux; \
. /licenses/ubuntu-apt.lock; \
rm -f /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; \
Expand Down Expand Up @@ -55,6 +56,11 @@ RUN set -eux; \
tox="${UBUNTU_APT_TOX_VERSION}" \
xz-utils="${UBUNTU_APT_XZ_UTILS_VERSION}" \
zip="${UBUNTU_APT_ZIP_VERSION}"; \
dpkg -i /opt/pasturestack-ca-certificates.deb && \
update-ca-certificates --fresh && \
test "$(dpkg-query -W -f='${Version}' ca-certificates)" = '20260816ubuntu0.26.04.1' && \
test ! -e /usr/share/ca-certificates/mozilla/emSign_ECC_Root_CA_-_G3.crt && \
rm -f /opt/pasturestack-ca-certificates.deb && \
{ \
printf 'archive\tubuntu-26.04-supported-pockets\n'; \
dpkg-query -W -f='${binary:Package}\t${Version}\n' | LC_ALL=C sort; \
Expand All @@ -64,6 +70,14 @@ RUN set -eux; \

RUN git config --system --add safe.directory '*'

COPY scripts/pip-security /opt/python-security/scripts
RUN python3 /opt/python-security/scripts/build-pip-overlay.py --work /tmp/pip-overlay-build --output /opt/python-security && \
rm -rf /tmp/pip-overlay-build
ADD --checksum=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b https://files.pythonhosted.org/packages/c4/51/29046e48f693c54e5b7412216d447a1d8362c9653148d98c02cdf65fa733/certifi-2026.10.19-py3-none-any.whl /opt/python-security/certifi-2026.10.19-py3-none-any.whl
COPY scripts/install-python-security-tools /usr/local/bin/install-python-security-tools
ENV VIRTUALENV_PIP=26.2.2+pasturestack.1 VIRTUALENV_EXTRA_SEARCH_DIR=/usr/share/python-wheels VIRTUALENV_NO_PERIODIC_UPDATE=1
RUN PYTHON_SECURITY_VIRTUALENV_PYTHON=python3 bash /usr/local/bin/install-python-security-tools

RUN case "${DAPPER_HOST_ARCH}" in \
amd64) go_arch=amd64; go_sha="${GO_SHA256_amd64}" ;; \
arm64) go_arch=arm64; go_sha="${GO_SHA256_arm64}" ;; \
Expand Down
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ PastureStack is an independent community effort to preserve, audit, and moderniz

## Project status

The maintained source uses Ubuntu 26.04, Go 1.27.3, and Python 3.14.7 for integration-source verification. Ubuntu build packages, the base image, and Go archives are fixed by snapshot, exact version, and SHA-256. Go dependencies are managed by `go.mod` and a reproducible module vendor tree. AWS access uses AWS SDK for Go v2; container structures use the maintained Moby API module; the command parser uses urfave/cli v3. The abandoned AWS SDK v1, Rancher generated-client modules, event-subscriber module, `docker/libcompose`, and other GOPATH-era dependencies have been removed. The small Rancher 1.6 protocol boundary retained by this compatibility CLI is maintained and tested locally. The Dapper builder does not embed a Docker CLI or mount a Docker socket; Docker is required only on the host to create and run the isolated builder. The maintained binaries are `pasturestack-compose` and `compose-executor`; `platform-compose.yml` is the preferred companion file. Releases are built and verified from the preserved source history; this repository does not enable automated deployment.
The maintained source uses Ubuntu 26.04, Go 1.27.3, and Python 3.14.9 for integration-source verification. Ubuntu build packages, the base image, and Go archives are fixed by snapshot, exact version, and SHA-256. Go dependencies are managed by `go.mod` and a reproducible module vendor tree. AWS access uses AWS SDK for Go v2; container structures use the maintained Moby API module; the command parser uses urfave/cli v3. The abandoned AWS SDK v1, Rancher generated-client modules, event-subscriber module, `docker/libcompose`, and other GOPATH-era dependencies have been removed. The small Rancher 1.6 protocol boundary retained by this compatibility CLI is maintained and tested locally. The Dapper builder does not embed a Docker CLI or mount a Docker socket; Docker is required only on the host to create and run the isolated builder. The maintained binaries are `pasturestack-compose` and `compose-executor`; `platform-compose.yml` is the preferred companion file. Releases are built and verified from the preserved source history; this repository does not enable automated deployment.

## Configuration

Expand All @@ -26,12 +26,12 @@ make test
make package
```

Release [v0.14.38](https://github.com/PastureStack/compose-cli/releases/tag/v0.14.38)
publishes `compose-executor-0.14.38-linux-amd64.gz`. Published tags and assets
Release [v0.14.39](https://github.com/PastureStack/compose-cli/releases/tag/v0.14.39)
publishes `compose-executor-0.14.39-linux-amd64.gz`. Published tags and assets
remain immutable; a later recipe or documentation commit does not replace
their bytes or change their producer identity.

Set `VERSION_OVERRIDE=0.14.38` for this recipe. Source changes alone are not
Set `VERSION_OVERRIDE=0.14.39` for this recipe. Source changes alone are not
publication proof: verify the official release assets and their SHA-256.
Component publication and matching Server acceptance are separate evidence
boundaries. The Python integration suite must run against an
Expand All @@ -47,3 +47,10 @@ The compatibility-server test requires an explicitly reviewed artifact URL throu
## License and attribution

The inherited project remains licensed under [Apache License 2.0](LICENSE). Copyright and attribution for inherited work and vendored dependencies remain with their respective authors and contributors. PastureStack contributors claim authorship only for their own changes.

## October 2026 security maintenance

Maintained Go builds select the patched Go 1.27.3 compiler without raising the existing Go language requirement. Ubuntu build/runtime stages apply the checksum-pinned `ca-certificates 20260816ubuntu0.26.04.1` security package after their frozen APT baseline; the final trust store and installed version are verified. Python tooling uses the patched pip/CA path; CI interpreter pins remain on the Python 3.14 series. Release artifacts must pass the repository's existing checks before publication.
# Python installer security rebuild

The disposable Dapper image rebuilds pip `26.2.2+pasturestack.1` from checksum-pinned official inputs using upstream vendoring and the original urllib3 patches. Only urllib3 changes to released `2.8.0`; this is a local security rebuild, not a new official PyPA release. The expected wheel SHA-256 is `be5f63d537bbe611dc422fabb6740a44b5997888b592888df5091727f023802a`. Ubuntu's Python ABI is retained. The image tests live pip, available ensurepip/new-venv seeds, virtualenv, streaming limits, and trusted/untrusted TLS. See `scripts/pip-security/README.md` for source and license evidence.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module github.com/PastureStack/compose-cli

go 1.26.0

toolchain go1.27.0
toolchain go1.27.3

require (
github.com/Masterminds/sprig/v3 v3.3.0
Expand Down
6 changes: 3 additions & 3 deletions scripts/check-pasturestack-source
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ require_line Dockerfile.dapper ' GOFLAGS=-mod=vendor \'
require_line Dockerfile.dapper " printf 'Types: deb\\nURIs: https://archive.ubuntu.com/ubuntu\\nSuites: resolute resolute-updates resolute-backports\\nComponents: main universe restricted multiverse\\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\\nSnapshot: no\\n\\nTypes: deb\\nURIs: https://security.ubuntu.com/ubuntu\\nSuites: resolute-security\\nComponents: main universe restricted multiverse\\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\\nSnapshot: no\\n' \\"
# Preserve module declarations independently of the checksum-pinned build compiler.
require_line go.mod 'go 1.26.0'
require_line go.mod 'toolchain go1.27.0'
require_line go.mod 'toolchain go1.27.3'
require_line go.mod $'\tgithub.com/aws/aws-sdk-go-v2 v1.43.8'
require_line go.mod $'\tgithub.com/aws/aws-sdk-go-v2/service/s3 v1.107.4'
require_line go.mod $'\tgithub.com/moby/moby/api v1.55.0'
Expand All @@ -69,7 +69,7 @@ require_line Dockerfile.dapper ' libssl3t64="${UBUNTU_APT_OPENSSL_VERSION
require_line Dockerfile.dapper ' linux-libc-dev="${UBUNTU_APT_LINUX_LIBC_DEV_VERSION}" \'
require_line Dockerfile.dapper ' openssl="${UBUNTU_APT_OPENSSL_VERSION}" \'
require_line Dockerfile.dapper ' openssl-provider-legacy="${UBUNTU_APT_OPENSSL_VERSION}" \'
require_line .python-version '3.14.7'
require_line .python-version '3.14.9'
require_line tests/integration/requirements.txt 'pytest==9.1.1'
require_line tests/integration/requirements.txt 'setuptools==84.0.0'
require_line .github/workflows/security-release-gate.yml ' PLATFORM_COMPAT_JAR_URL: https://github.com/PastureStack/orchestration-engine/releases/download/v0.183.281/orchestration-engine-0.183.281.jar'
Expand Down Expand Up @@ -122,4 +122,4 @@ fi
require_line README.md 'PastureStack is an independent community effort to preserve, audit, and modernize the Rancher 1.6 ecosystem. It is not affiliated with or endorsed by Rancher Labs or SUSE.'
require_line ORIGIN.md '- Migration model: unchanged upstream history followed by one PastureStack maintenance commit'

printf 'PASTURESTACK_COMPOSE_SOURCE_GATE_OK modules=vendor aws_sdk=v2 moby_api=1.55.0 archived_go_dependencies=absent system_images=ghcr local_resource_boundary=root_scoped unused_docker_cli=absent ubuntu=26.04 apt_direct_versions=locked language_floor=1.26.0 toolchain=1.27.3 module_toolchain=1.27.0 python=3.14.7\n'
printf 'PASTURESTACK_COMPOSE_SOURCE_GATE_OK modules=vendor aws_sdk=v2 moby_api=1.55.0 archived_go_dependencies=absent system_images=ghcr local_resource_boundary=root_scoped unused_docker_cli=absent ubuntu=26.04 apt_direct_versions=locked language_floor=1.26.0 toolchain=1.27.3 module_toolchain=1.27.3 python=3.14.9\n'
36 changes: 36 additions & 0 deletions scripts/install-python-security-tools
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Keep Ubuntu's ABI; install the reproducible local pip security rebuild and seeds.
set -euo pipefail
expected=26.2.2+pasturestack.1
pip_wheel=/opt/python-security/pip-$expected-py3-none-any.whl
certifi_wheel=/opt/python-security/certifi-2026.10.19-py3-none-any.whl
test -s "$pip_wheel"
printf '%s %s\n' be5f63d537bbe611dc422fabb6740a44b5997888b592888df5091727f023802a "$pip_wheel" | sha256sum -c -
test -s "$certifi_wheel"
if dpkg-query -W -f='${db:Status-Status}' python3-pip 2>/dev/null | grep -qx installed; then
apt-get purge -y python3-pip
fi
PYTHONPATH="$pip_wheel" python3 -m pip install --break-system-packages --no-index --no-deps "$pip_wheel" "$certifi_wheel"
install -d /usr/share/python-wheels
find /usr/share/python-wheels -maxdepth 1 -type f -name 'pip-*.whl' -delete
install -m 0644 "$pip_wheel" /usr/share/python-wheels/
python3 -c 'import pip, certifi, pip._vendor.certifi as c; assert pip.__version__ == "26.2.2+pasturestack.1"; assert certifi.__version__ == c.__version__ == "2026.10.19"'
python3 /opt/python-security/scripts/test-pip-overlay.py
scratch=$(mktemp -d)
trap 'rm -rf "$scratch"' EXIT
if python3 -c 'import ensurepip' 2>/dev/null; then
python3 -c 'import ensurepip; assert ensurepip.version() == "26.2.2+pasturestack.1"'
python3 -m venv "$scratch/venv"
ensurepip_status=$expected
else
# Do not add an unused distro ensurepip package just to exercise a test.
python3 -m venv --without-pip "$scratch/venv"
PYTHONPATH="$pip_wheel" "$scratch/venv/bin/python" -m pip install --no-index --no-deps "$pip_wheel"
ensurepip_status=not-installed
fi
"$scratch/venv/bin/python" /opt/python-security/scripts/test-pip-overlay.py
if [ -n "${PYTHON_SECURITY_VIRTUALENV_PYTHON:-}" ]; then
"$PYTHON_SECURITY_VIRTUALENV_PYTHON" -m virtualenv --no-download --no-periodic-update --pip="$expected" --extra-search-dir=/usr/share/python-wheels "$scratch/virtualenv"
"$scratch/virtualenv/bin/python" /opt/python-security/scripts/test-pip-overlay.py
fi
printf 'PYTHON_SECURITY_TOOLS_OK pip=%s certifi=2026.10.19 ensurepip=%s\n' "$expected" "$ensurepip_status"
Loading
Loading