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
28 changes: 23 additions & 5 deletions .github/workflows/security-release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 120
env:
CANDIDATE_VERSION: 0.38.5
CANDIDATE_VERSION: 0.38.6
DAPPER_IMAGE: pasturestack-host-api-dapper:security-gate
TRIVY_IMAGE: ghcr.io/aquasecurity/trivy:0.73.0@sha256:7cced7cae583819fc7806d4cbc0dbbc7cad18b99f7d3e235192e6da8c091045c
COSIGN_IMAGE: ghcr.io/sigstore/cosign/cosign:v3.1.3@sha256:9e5c2f2edc34351160407ca3416c61855bdf9403c3c5936e0f0be7fc261611b8
Expand All @@ -35,8 +35,9 @@ jobs:
set -euo pipefail
test -z "$(git status --porcelain)"
test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
test "$(git rev-list --count d56f3d0..HEAD)" = 1
test "$(git rev-list --count --merges d56f3d0..HEAD)" = 0
# Exactly one reviewed maintenance commit after the existing published main.
test "$(git rev-list --count b124a9cce56cc3e1082d2f72434592bccb15f6ef..HEAD)" = 1
test "$(git rev-list --count --merges b124a9cce56cc3e1082d2f72434592bccb15f6ef..HEAD)" = 0
private_pattern=$(printf '%s|%s|%s' 'chen''21019' '10\.0\.0\.''125' 'C:\\''Users\\')
if git grep -n -E "$private_pattern" -- .; then
echo 'Private operator data is present in the public source tree.' >&2
Expand Down Expand Up @@ -67,6 +68,10 @@ jobs:
"$DAPPER_IMAGE" bash -lc \
'go version -m /go/src/github.com/PastureStack/host-api/bin/host-api' \
> evidence/host-api-go-version.txt
test "$(awk 'NR == 1 {print $2}' evidence/host-api-go-version.txt)" = go1.27.3
grep -F 'CGO_ENABLED=0' evidence/host-api-go-version.txt
grep -F "vcs.revision=$GITHUB_SHA" evidence/host-api-go-version.txt
grep -F 'vcs.modified=false' evidence/host-api-go-version.txt
awk '$1 == "#" && ($3 ~ /^v/ || $3 ~ /^[0-9]/) { print $2 "\t" $3 }' \
vendor/modules.txt > evidence/go-modules.tsv
test -s evidence/go-modules.tsv
Expand Down Expand Up @@ -140,6 +145,16 @@ jobs:
--output /evidence/source-secret-scan.json /workspace
rm -rf -- "$source_snapshot"

# Scan the delivered executable, not only the compressed outer package.
product_snapshot=$(mktemp -d "${RUNNER_TEMP}/host-api-product.XXXXXX")
tar --no-same-owner -xzf "dist/artifacts/host-api-${CANDIDATE_VERSION}.tar.gz" -C "$product_snapshot"
product_binary=$(find "$product_snapshot" -type f -path '*/bin/host-api')
test -n "$product_binary"
test "$(find "$product_snapshot" -type f -path '*/bin/host-api' | wc -l)" = 1
cmp evidence/host-api-linux-amd64 "$product_binary"
(cd "$product_snapshot"; sha256sum -c */SHA256SUMSSUM; sha256sum -c */SHA256SUMS)
test "$("$product_binary" --version)" = "$CANDIDATE_VERSION"

docker run --rm \
-v "$TRIVY_CACHE:/root/.cache/trivy" \
"$TRIVY_IMAGE" image --cache-dir /root/.cache/trivy --download-db-only
Expand All @@ -152,11 +167,14 @@ jobs:
--output /evidence/source-vulnerability-scan.json /workspace
docker run --rm --network none \
-v "$TRIVY_CACHE:/root/.cache/trivy" \
-v "$GITHUB_WORKSPACE/dist/artifacts:/artifacts:ro" \
-v "$product_snapshot:/artifacts:ro" \
-v "$GITHUB_WORKSPACE/evidence:/evidence" \
"$TRIVY_IMAGE" fs --cache-dir /root/.cache/trivy --skip-db-update --offline-scan \
"$TRIVY_IMAGE" rootfs --cache-dir /root/.cache/trivy --skip-db-update --offline-scan \
--scanners vuln,secret --severity CRITICAL,HIGH --format json \
--output /evidence/artifact-scan.json /artifacts
jq -e '[.Results[]? | select(.Type == "gobinary" and (.Target | endswith("/bin/host-api")))] | length == 1' \
evidence/artifact-scan.json >/dev/null
rm -rf -- "$product_snapshot"
docker run --rm --network none \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$TRIVY_CACHE:/root/.cache/trivy" \
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/bin/
/host-api
/dist/
/evidence/
/gopath/

*.sw[mnop]
Expand Down
2 changes: 1 addition & 1 deletion COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Preferred settings use `platform-*` names. Historical `cattle-*` flags, legacy D

Operator lifecycle messages support `en-US` and `zh-TW`. HTTP response bodies, log streams, statistics payloads, Docker output, identifiers, and protocol errors are not translated.

The current candidate is `0.38.5`, built with Go 1.27.2 on a digest-pinned Ubuntu 26.04 image and an exact Ubuntu package snapshot. Server packaging consumes `host-api-0.38.5.tar.gz`; its filename, executable layout, architecture, legacy SHA-1 compatibility files, and SHA-256 integrity files are release contracts. Product versions must remain pure numeric `MAJOR.MINOR.PATCH` values without branding or maintenance suffixes.
The source package version is `0.38.6`, built with Go 1.27.3 on a digest-pinned Ubuntu 26.04 image, a frozen bootstrap package snapshot, and checksum-pinned official security fixes. The final builder inventory records installed versions separately from the bootstrap lock. A published package must retain its reviewed producer revision, byte-identical packaging evidence, and successful security checks of the unpacked binary. Server packaging consumes `host-api-0.38.6.tar.gz`; its filename, executable layout, architecture, legacy SHA-1 compatibility files, and SHA-256 integrity files are release contracts. Product versions must remain pure numeric `MAJOR.MINOR.PATCH` values without branding or maintenance suffixes.

Before release, validate token acquisition, event forwarding, logs, stats, exec, console, Docker socket proxy, container proxy, disabled-proxy behavior, key parsing, and restart behavior.

Expand Down
37 changes: 34 additions & 3 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ COPY --from=snapshot-ca-certificates /etc/ssl/certs/ca-certificates.crt /etc/ssl
COPY package/ubuntu-apt.lock /licenses/ubuntu-apt.lock

ARG DAPPER_HOST_ARCH=amd64
ARG GO_VERSION=1.27.2
ARG GO_SHA256_amd64=ecbadb99091a3f46e31f5f934b068b1864eafa7995211b39eaddf76996045fe5
ARG GO_SHA256_arm=e25a174051d8675f87ac720aedcd25bf89ac652c4b82f26aa47919524725ed95
ARG GO_VERSION=1.27.3
ARG GO_SHA256_amd64=65efbc80fdc1fa2cd2631cad5b481777a68e8725f34e89f50fc6ac714e379b40
ARG GO_SHA256_arm=d6f4e11dd7157030d7ac11c51c8f73201a2db932d593c3106b1da11cc32bfdf8

ENV DEBIAN_FRONTEND=noninteractive
ENV HOST_ARCH=${DAPPER_HOST_ARCH} \
Expand All @@ -25,6 +25,16 @@ ENV HOST_ARCH=${DAPPER_HOST_ARCH} \

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

# Official fixed packages overlay the frozen bootstrap snapshot at build time.
# Keep both original bootstrap locks and the final installed inventory.
ADD --checksum=sha256:2c418a61d7165d0cde01d9cb05ae025cc41fc75ef6d3f095996bd045ba0945dc https://security.ubuntu.com/ubuntu/pool/main/c/curl/curl_8.18.0-1ubuntu2.8_amd64.deb /tmp/curl.deb
ADD --checksum=sha256:8db913e1fa5a694ca6ba7b828bd18c5204e6853ac07fe7ed9c6e1f94e3444d8e https://security.ubuntu.com/ubuntu/pool/main/c/curl/libcurl3t64-gnutls_8.18.0-1ubuntu2.8_amd64.deb /tmp/libcurl3t64-gnutls.deb
ADD --checksum=sha256:7c0b37592f83a629cc22f0c98effa176da9edbd6d77b3f38184a9d0ddc5e0266 https://security.ubuntu.com/ubuntu/pool/main/c/curl/libcurl4t64_8.18.0-1ubuntu2.8_amd64.deb /tmp/libcurl4t64.deb
ADD --checksum=sha256:3ff73e121f6cd4f19e80ab4329dfd914108b3936c9db3708200203a9b245b34d https://security.ubuntu.com/ubuntu/pool/main/o/openssl/libssl3t64_3.5.5-1ubuntu3.7_amd64.deb /tmp/libssl3t64.deb
ADD --checksum=sha256:6965aafe69e0a49ef34d2e26f8e83d09d1c6037b7e9ee37f19b292a3c6851621 https://security.ubuntu.com/ubuntu/pool/main/o/openssl/openssl_3.5.5-1ubuntu3.7_amd64.deb /tmp/openssl.deb
ADD --checksum=sha256:51cf418571059831096abd40e0bd5debaa1ae48a6f8d87d9e4e5f7f12aa4db52 https://security.ubuntu.com/ubuntu/pool/main/o/openssl/openssl-provider-legacy_3.5.5-1ubuntu3.7_amd64.deb /tmp/openssl-provider-legacy.deb
ADD --checksum=sha256:0498bc9510149ef06abd6c09b8932e43c5bc71b68634b4b8f84488b2e0a20e82 https://security.ubuntu.com/ubuntu/pool/main/l/linux/linux-libc-dev_7.0.0-38.38_amd64.deb /tmp/linux-libc-dev.deb

RUN set -eux; \
. /licenses/ubuntu-apt.lock; \
find /etc/apt -type f \( -name '*.list' -o -name '*.sources' \) -exec sed -i \
Expand All @@ -50,6 +60,27 @@ RUN set -eux; \
runc="${UBUNTU_APT_RUNC_VERSION}" \
tar="${UBUNTU_APT_TAR_VERSION}" \
xz-utils="${UBUNTU_APT_XZ_UTILS_VERSION}"; \
for package in curl libcurl3t64-gnutls libcurl4t64 libssl3t64 openssl openssl-provider-legacy linux-libc-dev; do \
case "$package" in \
curl|libcurl*) expected=8.18.0-1ubuntu2.8 ;; \
linux-libc-dev) expected=7.0.0-38.38 ;; \
*) expected=3.5.5-1ubuntu3.7 ;; \
esac; \
test "$(dpkg-deb -f "/tmp/${package}.deb" Package)" = "$package"; \
test "$(dpkg-deb -f "/tmp/${package}.deb" Version)" = "$expected"; \
test "$(dpkg-deb -f "/tmp/${package}.deb" Architecture)" = amd64; \
done; \
dpkg -i /tmp/curl.deb /tmp/libcurl3t64-gnutls.deb /tmp/libcurl4t64.deb \
/tmp/libssl3t64.deb /tmp/openssl.deb /tmp/openssl-provider-legacy.deb /tmp/linux-libc-dev.deb; \
for package in curl libcurl3t64-gnutls libcurl4t64 libssl3t64 openssl openssl-provider-legacy linux-libc-dev; do \
case "$package" in \
curl|libcurl*) expected=8.18.0-1ubuntu2.8 ;; \
linux-libc-dev) expected=7.0.0-38.38 ;; \
*) expected=3.5.5-1ubuntu3.7 ;; \
esac; \
test "$(dpkg-query -W -f='${Version}' "$package")" = "$expected"; \
rm -f "/tmp/${package}.deb"; \
done; \
{ \
printf 'snapshot\t%s\n' "${UBUNTU_APT_SNAPSHOT}"; \
dpkg-query -W -f='${binary:Package}\t${Version}\n' | LC_ALL=C sort; \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ PastureStack is an independent community effort to preserve, audit, and moderniz

## Capabilities

The source package version is `0.38.5`. Target-bound API Key tickets require matching Engine introspection at handshake and during logs, exec, and statistics streams. Revocation or expiry closes the stream; it does not stop its container or kill an already started exec process. Legacy and full-without-expiry tokens retain their authentication contract.
The source package version is `0.38.6`, built with Go 1.27.3. Use a published release only after its source, reproducibility, vulnerability, and packaged-binary checks pass; a source version is not publication evidence. Target-bound API Key tickets require matching Engine introspection at handshake and during logs, exec, and statistics streams. Revocation or expiry closes the stream; it does not stop its container or kill an already started exec process. Legacy and full-without-expiry tokens retain their authentication contract.

The authenticated backend connection declares the exact `key-audit-v1,key-delegation-v1` capabilities. A compatible Proxy requires that declaration for every verified API Key stream, including full keys, so an older embedded backend cannot bypass terminal audit. Ordinary non-Key streams retain their existing backend compatibility.

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module github.com/PastureStack/host-api

go 1.26.0

toolchain go1.27.2
toolchain go1.27.3

require (
github.com/PastureStack/websocket-proxy v0.23.13-0.20260809214500-903576e1d20a
Expand All @@ -15,6 +15,7 @@ require (
github.com/sirupsen/logrus v1.10.2
github.com/vishvananda/netlink v1.3.1
github.com/vishvananda/netns v0.0.5
golang.org/x/sys v0.47.0
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
)

Expand Down Expand Up @@ -59,6 +60,5 @@ require (
go.opentelemetry.io/otel v1.45.0 // indirect
go.opentelemetry.io/otel/metric v1.45.0 // indirect
go.opentelemetry.io/otel/trace v1.45.0 // indirect
golang.org/x/sys v0.47.0 // indirect
pgregory.net/rapid v1.3.0 // indirect
)
2 changes: 1 addition & 1 deletion scripts/build
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if [ -f ./build/bootstrap.envs ];then
. ./build/bootstrap.envs
fi

BUILD_VERSION=${VERSION_OVERRIDE:-0.38.5}
BUILD_VERSION=${VERSION_OVERRIDE:-0.38.6}
BUILD_VERSION=${BUILD_VERSION#v}
if [[ ! "$BUILD_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo 'VERSION_OVERRIDE must use MAJOR.MINOR.PATCH with no suffix' >&2
Expand Down
2 changes: 1 addition & 1 deletion scripts/package
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ cd "$(dirname "$0")/.."
ARCH=${ARCH:?"ARCH not set"}
SUFFIX=""
[ "${ARCH}" != "amd64" ] && SUFFIX="_${ARCH}"
RELEASE_VERSION=${VERSION_OVERRIDE:-v0.38.5}
RELEASE_VERSION=${VERSION_OVERRIDE:-v0.38.6}
RELEASE_VERSION=${RELEASE_VERSION#v}
CONTENT=${PASTURESTACK_PACKAGE_ID:-$(git rev-parse --short=32 HEAD)}
SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH:-$(git show -s --format=%ct HEAD)}
Expand Down
Loading