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
18 changes: 9 additions & 9 deletions .github/workflows/security-release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
DAPPER_IMAGE: pasturestack/cli-dapper:${{ github.sha }}
RUNTIME_IMAGE: pasturestack/cli-runtime:${{ github.sha }}
TRIVY_IMAGE: aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969
VERSION_OVERRIDE: 0.6.19
VERSION_OVERRIDE: 0.6.20
CROSS: 'true'
SKIP_IMAGE_BUILD: 'true'

Expand Down Expand Up @@ -79,15 +79,15 @@ jobs:
}

run_ci
artifact="dist/artifacts/0.6.19/pasturestack-cli-linux-amd64-0.6.19.tar.gz"
artifact="dist/artifacts/0.6.20/pasturestack-cli-linux-amd64-0.6.20.tar.gz"
test -s "$artifact"
find dist/artifacts/0.6.19 -type f -print0 \
find dist/artifacts/0.6.20 -type f -print0 \
| LC_ALL=C sort -z \
| xargs -0 sha256sum > /tmp/first-artifacts.sha256

rm -rf bin build dist
run_ci
find dist/artifacts/0.6.19 -type f -print0 \
find dist/artifacts/0.6.20 -type f -print0 \
| LC_ALL=C sort -z \
| xargs -0 sha256sum > /tmp/second-artifacts.sha256
diff -u /tmp/first-artifacts.sha256 /tmp/second-artifacts.sha256
Expand All @@ -96,8 +96,8 @@ jobs:
mkdir -p evidence/product
tar -xzf "$artifact" -C evidence/product --strip-components=1
test -x evidence/product/pasturestack
evidence/product/pasturestack --version | grep -F '0.6.19' >/dev/null
find dist/artifacts/0.6.19 -type f -print0 \
evidence/product/pasturestack --version | grep -F '0.6.20' >/dev/null
find dist/artifacts/0.6.20 -type f -print0 \
| LC_ALL=C sort -z \
| xargs -0 sha256sum > evidence/artifacts.sha256
docker run --rm --entrypoint go \
Expand All @@ -119,7 +119,7 @@ jobs:
--tag "$RUNTIME_IMAGE" \
--file package/Dockerfile \
.
docker run --rm "$RUNTIME_IMAGE" --version | grep -F '0.6.19' >/dev/null
docker run --rm "$RUNTIME_IMAGE" --version | grep -F '0.6.20' >/dev/null

- name: Record resolved build inputs
shell: bash
Expand Down Expand Up @@ -226,9 +226,9 @@ jobs:
if: success()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: cli-release-candidate-0.6.19-${{ github.sha }}
name: cli-release-candidate-0.6.20-${{ github.sha }}
path: |
dist/artifacts/0.6.19/
dist/artifacts/0.6.20/
evidence/artifacts.sha256
evidence/source-revision.txt
evidence/source-tree.txt
Expand Down
13 changes: 11 additions & 2 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
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
COPY ubuntu-security-packages.lock /licenses/ubuntu-security-packages.lock
COPY scripts/install-ubuntu-security-updates /usr/local/libexec/pasturestack/install-ubuntu-security-updates
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 DAPPER_HOST_ARCH=amd64
ARG GO_VERSION=1.27.3
Expand All @@ -25,6 +27,7 @@ ENV HOST_ARCH=${DAPPER_HOST_ARCH} \
PATH=/go/bin:/usr/local/go/bin:${PATH} \
SHELL=/bin/bash

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 All @@ -43,7 +46,7 @@ RUN set -eux; \
apt-get upgrade -y; \
apt-get install -y --no-install-recommends \
bash="${UBUNTU_APT_BASH_VERSION}" \
ca-certificates="${UBUNTU_APT_CA_CERTIFICATES_VERSION}" \
ca-certificates="${UBUNTU_APT_CA_CERTIFICATES_BOOTSTRAP_VERSION}" \
curl="${UBUNTU_APT_CURL_VERSION}" \
gcc="${UBUNTU_APT_GCC_VERSION}" \
git="${UBUNTU_APT_GIT_VERSION}" \
Expand All @@ -55,6 +58,12 @@ RUN set -eux; \
tar="${UBUNTU_APT_TAR_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 && \
sh /usr/local/libexec/pasturestack/install-ubuntu-security-updates /licenses/ubuntu-security-packages.lock /etc/ssl/certs/ca-certificates.crt && \
{ \
printf 'snapshot\t%s\n' "${UBUNTU_APT_SNAPSHOT}"; \
dpkg-query -W -f='${binary:Package}\t${Version}\n' | LC_ALL=C sort; \
Expand Down
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ PastureStack is an independent community effort to preserve, audit, and moderniz

## Project status

Published CLI [`0.6.19`](https://github.com/PastureStack/cli/releases/tag/v0.6.19) is maintained from the latest reviewed upstream `v1.6` branch. It uses Go 1.27.3, the checksum-pinned official Docker 29.9.2 builder input, Go Modules with a checked-in vendor lock, and reproducible archives. Runtime packaging uses a digest-pinned Ubuntu 26.04 base, the `20261015T000000Z` signed Ubuntu snapshot and a non-root user. It is CI-qualified, not a published registry image. The maintained command name is `pasturestack`.
Published CLI [`0.6.20`](https://github.com/PastureStack/cli/releases/tag/v0.6.20) is maintained from the latest reviewed upstream `v1.6` branch. It uses Go 1.27.3, the checksum-pinned official Docker 29.9.2 builder input, Go Modules with a checked-in vendor lock, and reproducible archives. Runtime packaging uses a digest-pinned Ubuntu 26.04 base, the `20261015T000000Z` signed Ubuntu snapshot and a non-root user. It is CI-qualified, not a published registry image. The maintained command name is `pasturestack`.

The immutable, non-prerelease archives were produced from signed, normally merged source [`60a13c6ef8e60018e6409fb7b510bcf0d44c5030`](https://github.com/PastureStack/cli/commit/60a13c6ef8e60018e6409fb7b510bcf0d44c5030), after the complete [exact-main release gate](https://github.com/PastureStack/cli/actions/runs/39679384298). All 26 assets were anonymously downloaded and matched their recorded bytes and SHA-256. Later documentation commits are not a different producer and do not rebuild or overwrite these assets.

CLI `0.6.19` applies the Go crypto/x509 security fix without changing CLI functionality or API-key permissions. `inspect` uses the existing schema URL, flushes successful JSON and returns setup or HTTP errors. Environment URL normalization and Compose delegation remain unchanged. See [release notes](RELEASE-0.6.19.md).
CLI `0.6.20` applies the Go crypto/x509 security fix without changing CLI functionality or API-key permissions. `inspect` uses the existing schema URL, flushes successful JSON and returns setup or HTTP errors. Environment URL normalization and Compose delegation remain unchanged. See [release notes](RELEASE-0.6.20.md).

The vendored Logrus path also matches its lowercase import path on case-sensitive Linux filesystems, with file contents and logging behavior unchanged.

The archived `docker/libcompose` source tree and duplicated Compose executor have been removed. The `up` command delegates to the matching maintained `pasturestack-compose` binary; set `PASTURESTACK_COMPOSE_BINARY` only when it is not on `PATH`. API keys are passed through the child environment rather than command-line arguments.

The GitHub security release gate builds and packages twice, runs tests with the race detector, validates source contracts, produces SBOMs, and preserves raw source, binary, build-image and runtime-image scans. Critical/High, available fixes, secrets, and unregistered findings block publication. Only unfixed Medium/Low records may use the exact package/version/CVE tracker with an official vendor source and review date. Reviewed builder kernel-header VEX records do not apply to the shipped runtime. Numeric archives, checksums and source identity are retained for reviewed publication; a green source check alone is not a release or native-acceptance receipt.

For this release, source and shipped-binary vulnerability scans are zero; raw builder/runtime findings are not zero. Exact findings, current vendor-review dates and upstream CVSS are retained in the immutable release's [tracker](https://github.com/PastureStack/cli/releases/download/v0.6.19/cli-vendor-pending.json) and [security summary](https://github.com/PastureStack/cli/releases/download/v0.6.19/cli-security-summary.json). Builder `linux-libc-dev` header VEX rows are supported by retained package inventory (no kernel image/modules) and CGO-disabled binary metadata; they do not exempt runtime packages or executable code. Native CLI/Server interoperability and the broader compatibility matrix remain separately evidenced; publication alone is not a whole-matrix PASS.
For this release, source and shipped-binary vulnerability scans are zero; raw builder/runtime findings are not zero. Exact findings, current vendor-review dates and upstream CVSS are retained in the immutable release's [tracker](https://github.com/PastureStack/cli/releases/download/v0.6.20/cli-vendor-pending.json) and [security summary](https://github.com/PastureStack/cli/releases/download/v0.6.20/cli-security-summary.json). Builder `linux-libc-dev` header VEX rows are supported by retained package inventory (no kernel image/modules) and CGO-disabled binary metadata; they do not exempt runtime packages or executable code. Native CLI/Server interoperability and the broader compatibility matrix remain separately evidenced; publication alone is not a whole-matrix PASS.

## Configuration

Expand All @@ -34,8 +34,14 @@ make test
make package
```

Packaging is local only and does not publish an image. Official numeric release archives use names such as `pasturestack-cli-linux-amd64-0.6.19.tar.gz`; the upstream-boundary `v0.6.14` tag remains immutable. The reviewed `scripts/publish-reviewed-release.py` entry verifies the normal protected source merge, required checks and exact-main gate; it publishes source-bound checked bytes with `SHA256SUMS`, raw reports, SBOMs and producer proof, then anonymously verifies them. Without `--execute` it only prints an offline plan. An existing tag is never overwritten. See [COMPATIBILITY.md](COMPATIBILITY.md), [SECURITY.md](SECURITY.md), and [ORIGIN.md](ORIGIN.md).
Packaging is local only and does not publish an image. Official numeric release archives use names such as `pasturestack-cli-linux-amd64-0.6.20.tar.gz`; the upstream-boundary `v0.6.14` tag remains immutable. The reviewed `scripts/publish-reviewed-release.py` entry verifies the normal protected source merge, required checks and exact-main gate; it publishes source-bound checked bytes with `SHA256SUMS`, raw reports, SBOMs and producer proof, then anonymously verifies them. Without `--execute` it only prints an offline plan. An existing tag is never overwritten. See [COMPATIBILITY.md](COMPATIBILITY.md), [SECURITY.md](SECURITY.md), and [ORIGIN.md](ORIGIN.md).

## License and attribution

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

## October 2026 security maintenance

Both builder and runtime apply Ubuntu's fixed `zlib1g 1:1.3.dfsg+really1.3.1-1ubuntu3.2` package for CVE-2026-85091. The fixed finding is removed from the vendor-pending register rather than suppressed.

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. Release artifacts must pass the repository's existing checks before publication.
13 changes: 11 additions & 2 deletions package/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
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
COPY ubuntu-security-packages.lock /licenses/ubuntu-security-packages.lock
COPY scripts/install-ubuntu-security-updates /usr/local/libexec/pasturestack/install-ubuntu-security-updates
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 IMAGE_VERSION=dev
ENV DEBIAN_FRONTEND=noninteractive \
HOME=/home/pasturestack

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 All @@ -24,11 +27,17 @@ RUN set -eux; \
apt-get update; \
apt-get upgrade -y; \
apt-get install -y --no-install-recommends \
ca-certificates="${UBUNTU_APT_CA_CERTIFICATES_VERSION}" \
ca-certificates="${UBUNTU_APT_CA_CERTIFICATES_BOOTSTRAP_VERSION}" \
libssl3t64="${UBUNTU_APT_OPENSSL_VERSION}" \
openssl="${UBUNTU_APT_OPENSSL_VERSION}" \
openssl-provider-legacy="${UBUNTU_APT_OPENSSL_VERSION}" \
openssh-client="${UBUNTU_APT_OPENSSH_CLIENT_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 && \
sh /usr/local/libexec/pasturestack/install-ubuntu-security-updates /licenses/ubuntu-security-packages.lock /etc/ssl/certs/ca-certificates.crt && \
{ \
printf 'snapshot\t%s\n' "${UBUNTU_APT_SNAPSHOT}"; \
dpkg-query -W -f='${binary:Package}\t${Version}\n' | LC_ALL=C sort; \
Expand Down
3 changes: 3 additions & 0 deletions package/Dockerfile.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
!bin/
!bin/pasturestack
!ubuntu-apt.lock
!ubuntu-security-packages.lock
!scripts/
!scripts/install-ubuntu-security-updates
!LICENSE
!SECURITY.md
!ORIGIN.md
Expand Down
2 changes: 1 addition & 1 deletion scripts/check-reproducible-artifacts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -euo pipefail

repo=$(cd "$(dirname "$0")/.." && pwd)
version=${VERSION_OVERRIDE:-0.6.19}
version=${VERSION_OVERRIDE:-0.6.20}
: "${SOURCE_DATE_EPOCH:?SOURCE_DATE_EPOCH must be set to the authoritative commit epoch}"

workspace=$(mktemp -d)
Expand Down
51 changes: 51 additions & 0 deletions scripts/install-ubuntu-security-updates
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/sh
# Same-series official micro-updates. Never install a package just for a scan.
set -eu
test "$#" -eq 2 || { echo 'usage: security-updates LOCK TRUSTED_CA_BUNDLE' >&2; exit 2; }
lock=$1
trusted_ca=$2
. /etc/os-release
test "$ID:$VERSION_ID" = ubuntu:26.04
test -s "$lock"
test -s "$trusted_ca"
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT HUP INT TERM
dpkg-query -W -f='${binary:Package}\t${db:Status-Status}\n' | LC_ALL=C sort > "$tmp/before"
set --
while IFS= read -r entry || test -n "$entry"; do
case "$entry" in ''|'#'*) continue;; esac
case "$entry" in *[!a-zA-Z0-9.:+~=_-]*) echo "Invalid lock entry" >&2; exit 1;; esac
package=${entry%%=*}
version=${entry#*=}
test "$package" != "$version"
status=$(dpkg-query -W -f='${db:Status-Status}' "$package" 2>/dev/null || true)
test "$status" = installed || continue
installed=$(dpkg-query -W -f='${Version}' "$package")
# A newer base may already contain the fix; never downgrade it.
dpkg --compare-versions "$installed" ge "$version" && continue
set -- "$@" "$entry"
done < "$lock"
if test "$#" -gt 0; then
printf 'Types: deb\nURIs: https://snapshot.ubuntu.com/ubuntu/20261023T000000Z\nSuites: resolute-updates resolute-security\nComponents: main\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\nSnapshot: no\n' > "$tmp/security.sources"
apt_security() {
apt-get -o Dir::Etc::sourcelist="$tmp/security.sources" \
-o Dir::Etc::sourceparts=- -o Acquire::https::CaInfo="$trusted_ca" \
-o Acquire::https::Verify-Peer=true -o Acquire::https::Verify-Host=true \
-o Acquire::AllowInsecureRepositories=false -o APT::Get::AllowUnauthenticated=false \
-o Acquire::Retries=5 "$@"
}
apt_security update
DEBIAN_FRONTEND=noninteractive apt_security install -y --only-upgrade --no-install-recommends --no-remove "$@"
fi
while IFS= read -r entry || test -n "$entry"; do
case "$entry" in ''|'#'*) continue;; esac
package=${entry%%=*}
version=${entry#*=}
status=$(dpkg-query -W -f='${db:Status-Status}' "$package" 2>/dev/null || true)
test "$status" = installed || continue
dpkg --compare-versions "$(dpkg-query -W -f='${Version}' "$package")" ge "$version"
done < "$lock"
dpkg-query -W -f='${binary:Package}\t${db:Status-Status}\n' | LC_ALL=C sort > "$tmp/after"
# A security micro-update must not add/remove packages or change installed status.
cmp "$tmp/before" "$tmp/after"
printf 'UBUNTU_SECURITY_MICRO_UPDATES_OK\n'
4 changes: 2 additions & 2 deletions scripts/publish-reviewed-release.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Publish only checked numeric CLI0.6.19 bytes from an exact successful main run.
"""Publish only checked numeric CLI0.6.20 bytes from an exact successful main run.

Default --plan has no network activity. Explicit --execute requires normal
protected/signed merge, exact required checks, complete security/repro gate,
Expand All @@ -17,7 +17,7 @@
import tempfile
from urllib.request import Request, urlopen

REPO, VERSION, TAG = 'PastureStack/cli', '0.6.19', 'v0.6.19'
REPO, VERSION, TAG = 'PastureStack/cli', '0.6.20', 'v0.6.20'


def need(ok, code):
Expand Down
Loading
Loading