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
8 changes: 4 additions & 4 deletions .github/workflows/codeql-verification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ jobs:
set -euo pipefail
test -z "$(git status --porcelain)"
git merge-base --is-ancestor c8663d12dd253ef13258750dca056d4b1219fc10 HEAD
grep -Fq 'VERSION_OVERRIDE: v0.13.29' .github/workflows/validate.yml
grep -Fq 'VERSION_OVERRIDE: v0.13.30' .github/workflows/validate.yml
grep -Fq 'SHA256SUMS' scripts/package
grep -Fq 'bash scripts/verify-package "$linux_asset"' .github/workflows/validate.yml
grep -Fq 'bash scripts/verify-package dist/artifacts/node-agent-0.13.29.tar.gz' .github/workflows/security-release-gate.yml
grep -Fq 'bash scripts/verify-package dist/artifacts/node-agent-0.13.30.tar.gz' .github/workflows/security-release-gate.yml

- name: Install the release Go toolchain
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: 1.27.2
go-version: 1.27.3
check-latest: false
cache: false

Expand All @@ -68,7 +68,7 @@ jobs:
export GOFLAGS=-mod=vendor
mkdir -p "$GITHUB_WORKSPACE/bin"
CGO_ENABLED=0 go build -trimpath -tags 'netgo osusergo' \
-ldflags='-w -s -X main.VERSION=v0.13.29' \
-ldflags='-w -s -X main.VERSION=v0.13.30' \
-o "$GITHUB_WORKSPACE/bin/node-agent" ./

- name: Analyze without publishing temporary alerts
Expand Down
52 changes: 39 additions & 13 deletions .github/workflows/security-release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ jobs:
timeout-minutes: 120
env:
DAPPER_IMAGE: pasturestack/node-agent-dapper:${{ github.sha }}
RUNTIME_IMAGE: pasturestack/node-agent:v0.13.29
RUNTIME_IMAGE: pasturestack/node-agent:v0.13.30
TRIVY_IMAGE: aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969
VERSION_OVERRIDE: v0.13.29
VERSION_OVERRIDE: v0.13.30
steps:
- name: Check out candidate
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -50,20 +50,25 @@ jobs:
set -euo pipefail
CROSS=1 VERSION_OVERRIDE="$VERSION_OVERRIDE" make DAPPER_IMAGE="$DAPPER_IMAGE" ci
make DAPPER_IMAGE="$DAPPER_IMAGE" IMAGE_NAME=pasturestack/node-agent \
TAG=v0.13.29 VERSION_OVERRIDE="$VERSION_OVERRIDE" package-image
test -s dist/artifacts/node-agent-0.13.29.tar.gz
test -s dist/artifacts/node-agent-0.13.29-windows-amd64.zip
TAG=v0.13.30 VERSION_OVERRIDE="$VERSION_OVERRIDE" package-image
test -s dist/artifacts/node-agent-0.13.30.tar.gz
test -s dist/artifacts/node-agent-0.13.30-windows-amd64.zip
test "$(cat dist/image)" = "$RUNTIME_IMAGE"
gzip -t dist/artifacts/node-agent-0.13.29.tar.gz
bash scripts/verify-package dist/artifacts/node-agent-0.13.29.tar.gz
unzip -t dist/artifacts/node-agent-0.13.29-windows-amd64.zip
sha256sum dist/artifacts/node-agent-0.13.29.tar.gz \
dist/artifacts/node-agent-0.13.29-windows-amd64.zip \
bin/node-agent > evidence/product-artifacts.sha256
gzip -t dist/artifacts/node-agent-0.13.30.tar.gz
bash scripts/verify-package dist/artifacts/node-agent-0.13.30.tar.gz
unzip -t dist/artifacts/node-agent-0.13.30-windows-amd64.zip
(
cd dist/artifacts
sha256sum node-agent-0.13.30.tar.gz node-agent-0.13.30-windows-amd64.zip > SHA256SUMS
sha256sum -c SHA256SUMS
)
sha256sum dist/artifacts/node-agent-0.13.30.tar.gz \
dist/artifacts/node-agent-0.13.30-windows-amd64.zip \
bin/node-agent bin/windows/amd64/node-agent.exe > evidence/product-artifacts.sha256
docker image inspect "$RUNTIME_IMAGE" > evidence/runtime-image-inspect.json
docker run --rm --entrypoint /usr/bin/node-agent "$RUNTIME_IMAGE" --version \
> evidence/runtime-version.txt
grep -Fxq 'node-agent version v0.13.29' evidence/runtime-version.txt
grep -Fxq 'node-agent version v0.13.30' evidence/runtime-version.txt

- name: Verify reproducible Linux binary
shell: bash
Expand All @@ -75,7 +80,16 @@ jobs:
cmp /tmp/node-agent.first bin/node-agent
docker run --rm --entrypoint go -v "$PWD:/work:ro" "$DAPPER_IMAGE" \
version -m /work/bin/node-agent > evidence/product-go-version.txt
grep -F 'go1.27.3' evidence/product-go-version.txt >/dev/null
grep -F $'build\tCGO_ENABLED=0' evidence/product-go-version.txt >/dev/null
docker run --rm --entrypoint go -v "$PWD:/work:ro" "$DAPPER_IMAGE" \
version -m /work/bin/windows/amd64/node-agent.exe > evidence/windows-product-go-version.txt
grep -F 'go1.27.3' evidence/windows-product-go-version.txt >/dev/null
grep -F $'build\tGOOS=windows' evidence/windows-product-go-version.txt >/dev/null
for report in evidence/product-go-version.txt evidence/windows-product-go-version.txt; do
grep -Fx $'\tbuild\tvcs.revision='"$GITHUB_SHA" "$report" >/dev/null
grep -Fx $'\tbuild\tvcs.modified=false' "$report" >/dev/null
done

- name: Scan source, product, runtime, and build image
shell: bash
Expand Down Expand Up @@ -143,7 +157,7 @@ jobs:
and ((.impact_statement | length) > 0)
)
' security/dapper.openvex.json >/dev/null
grep -F $'linux-libc-dev:amd64\t7.0.0-30.30' evidence/dapper-dpkg.tsv >/dev/null
grep -F $'linux-libc-dev:amd64\t7.0.0-38.38' evidence/dapper-dpkg.tsv >/dev/null
if grep -Eq '^linux-(image|modules)([-:]|[[:space:]])' evidence/dapper-dpkg.tsv; then
printf 'Unexpected Linux kernel runtime package in Dapper image\n' >&2
exit 1
Expand Down Expand Up @@ -229,6 +243,18 @@ jobs:
print('{}_components={}'.format(scope, len(bom['components'])))
PY

- name: Retain exact scanned release packages
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: node-agent-scanned-0.13.30
path: |
dist/artifacts/node-agent-0.13.30.tar.gz
dist/artifacts/node-agent-0.13.30-windows-amd64.zip
dist/artifacts/SHA256SUMS
if-no-files-found: error
retention-days: 30
compression-level: 0

- name: Upload reviewed evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand Down
23 changes: 12 additions & 11 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ jobs:
set -euo pipefail
git init .
git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
git fetch --depth=1 origin "$SOURCE_SHA"
# Match the Security gate's fetch-depth: 0 history and tags.
git fetch --tags origin "$SOURCE_SHA"
git -c advice.detachedHead=false checkout --detach FETCH_HEAD
test "$(git rev-parse HEAD)" = "$SOURCE_SHA"
test -z "$(git status --short)"
Expand All @@ -43,15 +44,15 @@ jobs:
if: github.event_name == 'workflow_dispatch' && inputs.validation_scope == 'host-disk'
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: 1.27.2
go-version: 1.27.3
check-latest: false
cache: false

- name: Test and package immutable artifacts
id: package
env:
CROSS: "1"
VERSION_OVERRIDE: v0.13.29
VERSION_OVERRIDE: v0.13.30
VALIDATION_SCOPE: ${{ inputs.validation_scope || 'full' }}
run: |
set -euo pipefail
Expand All @@ -63,7 +64,7 @@ jobs:
export GOTOOLCHAIN=local GOTELEMETRY=off GOWORK=off
export GOFLAGS=-mod=vendor GOPROXY=off GOSUMDB=off
export GOOS=linux GOARCH=amd64 GOAMD64=v1 CGO_ENABLED=0
test "$(go version)" = 'go version go1.27.2 linux/amd64'
test "$(go version)" = 'go version go1.27.3 linux/amd64'
test -z "$(gofmt -l core/hostinfo/disk_info_linux.go core/hostinfo/disk_info_linux_test.go)"
go test -count=1 -v ./core/hostinfo ./core/ping
bash scripts/build
Expand All @@ -74,8 +75,8 @@ jobs:
exit 1
;;
esac
linux_asset="dist/artifacts/node-agent-0.13.29.tar.gz"
windows_asset="dist/artifacts/node-agent-0.13.29-windows-amd64.zip"
linux_asset="dist/artifacts/node-agent-0.13.30.tar.gz"
windows_asset="dist/artifacts/node-agent-0.13.30-windows-amd64.zip"
test -s "$linux_asset"
test -s "$windows_asset"
gzip -t "$linux_asset"
Expand All @@ -91,8 +92,8 @@ jobs:
(
cd dist/artifacts
sha256sum \
node-agent-0.13.29.tar.gz \
node-agent-0.13.29-windows-amd64.zip >SHA256SUMS
node-agent-0.13.30.tar.gz \
node-agent-0.13.30-windows-amd64.zip >SHA256SUMS
sha256sum -c SHA256SUMS
)
printf 'NODE_AGENT_VALIDATION_OK source=%s version=%s scope=%s artifacts=linux,windows\n' \
Expand All @@ -101,10 +102,10 @@ jobs:
- name: Retain reviewed release candidate
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: node-agent-0.13.29
name: node-agent-0.13.30
path: |
dist/artifacts/node-agent-0.13.29.tar.gz
dist/artifacts/node-agent-0.13.29-windows-amd64.zip
dist/artifacts/node-agent-0.13.30.tar.gz
dist/artifacts/node-agent-0.13.30-windows-amd64.zip
dist/artifacts/SHA256SUMS
if-no-files-found: error
retention-days: 30
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/.dapper
/bin
/dist
/evidence/
*.swp
/.trash-cache
.idea/*
Expand Down
35 changes: 32 additions & 3 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ ENV DEBIAN_FRONTEND=noninteractive

ARG UBUNTU_SNAPSHOT=20260825T000000Z

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

ADD --checksum=sha256:6077d27c6b6f8b23590cb01ff877ed8c804a67a5442cc32b5a33da10d2bd0e90 \
https://snapshot.ubuntu.com/ubuntu/20260825T000000Z/pool/main/c/ca-certificates/ca-certificates_20260601~26.04.1_all.deb \
/tmp/ca-certificates.deb
Expand Down Expand Up @@ -44,15 +52,36 @@ RUN set -eux; \
uuid-runtime \
xz-utils \
zip && \
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" || exit 1; \
test "$(dpkg-deb -f "/tmp/${package}.deb" Version)" = "$expected" || exit 1; \
test "$(dpkg-deb -f "/tmp/${package}.deb" Architecture)" = amd64 || exit 1; \
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" || exit 1; \
rm -f "/tmp/${package}.deb"; \
done && \
rm -rf /var/lib/apt/lists/* && \
rm -f /usr/bin/pebble && \
rm -f /bin/sh && ln -s /bin/bash /bin/sh

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

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
ARG PIP_VERSION=26.1.2
ARG SETUPTOOLS_VERSION=83.0.0
ARG WHEEL_VERSION=0.47.0
Expand Down
18 changes: 10 additions & 8 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

This is a migration proof of concept. The existing Ubuntu 26.04, Go 1.27.2, modern Docker test harness, runtime hardening, and dependency maintenance are retained. Product-owned import paths, binaries, archives, images, Windows service names, and operator messages use PastureStack naming. Python test dependencies are fully pinned and cached in the disposable build image so clean-checkout tests do not depend on live PyPI availability. GitHub Actions runs repository validation and security checks. Release packaging remains manual, and no automatic production deployment is enabled.
This is a migration proof of concept. The existing Ubuntu 26.04, modern Docker test harness, runtime hardening, and dependency maintenance are retained, with the compiler updated to checksum-pinned Go 1.27.3. Product-owned import paths, binaries, archives, images, Windows service names, and operator messages use PastureStack naming. Python test dependencies are fully pinned and cached in the disposable build image so clean-checkout tests do not depend on live PyPI availability. GitHub Actions runs repository validation and security checks. Release packaging remains manual, and no automatic production deployment is enabled.

## Configuration

Expand All @@ -22,26 +22,28 @@ From a Docker-capable Linux host:
make test
make build
make package
make package-image IMAGE_NAME=pasturestack/node-agent TAG=v0.13.29
make package-image IMAGE_NAME=pasturestack/node-agent TAG=v0.13.30
```

Packaging is local only and does not push an image. See [COMPATIBILITY.md](COMPATIBILITY.md), [SECURITY.md](SECURITY.md), and [ORIGIN.md](ORIGIN.md).

The published Linux package is [Node Agent v0.13.29](https://github.com/PastureStack/node-agent/releases/tag/v0.13.29).
Its release contains the original validated archive and SHA-256 checksum; the
outer bootstrap image version and the Go package version are separate identities.
The current recipe packages version `0.13.30`. Source changes alone are not
publication proof: use the [official releases](https://github.com/PastureStack/node-agent/releases)
and their SHA-256 checksums to verify published packages. Published tags and assets
remain immutable; later documentation commits do not change their producer identity.
The outer bootstrap image version and the Go package version are separate identities.

The authoritative build is Go modules with the checked-in `vendor/` tree. The
runtime dependency baseline uses Go 1.27, AWS SDK for Go v2, Moby API 1.55 and
client 0.5, gopsutil v4.26, mapstructure v2.5, netlink v1.3, and netns v0.0.5.
The retired AWS SDK v1, Aliyungo, root Docker module, GOPATH/Godeps, and Trash
dependency paths are not part of the build.

`VERSION_OVERRIDE=v0.13.29 make package` produces the deterministic Linux asset `node-agent-0.13.29.tar.gz`. The archive carries the legacy SHA-1 and current SHA-256 manifests required by the authenticated configcontent installer. The producer release is published by this repository; Server can embed that verified archive and distribute it through the existing configuration channel.
`VERSION_OVERRIDE=v0.13.30 make package` produces the deterministic Linux asset `node-agent-0.13.30.tar.gz`. The archive carries the legacy SHA-1 and current SHA-256 manifests required by the authenticated configcontent installer. The producer release is published by this repository; Server can embed that verified archive and distribute it through the existing configuration channel. Component publication and matching Server acceptance are separate evidence boundaries.

On Linux, Node supervises the separately maintained `host-api` producer at `${PASTURESTACK_HOME:-${CATTLE_HOME:-/var/lib/pasturestack}}/bin/host-api`. Host API `0.38.5` must be installed before the Node package by the existing `pyagent` package sequence. Node verifies its exact version, forwards the current agent/host identity only through process environment, restarts an exited child, and binds its lifetime to Node. Missing or incompatible producers never fall back to the embedded legacy Host API. Stream authorization, target binding, and private durable terminal evidence remain owned by the Host API producer.
On Linux, Node supervises the separately maintained `host-api` producer at `${PASTURESTACK_HOME:-${CATTLE_HOME:-/var/lib/pasturestack}}/bin/host-api`. Host API `0.38.6` must be installed before the Node package by the existing `pyagent` package sequence. Node verifies its exact version, forwards the current agent/host identity only through process environment, restarts an exited child, and binds its lifetime to Node. Missing or incompatible producers never fall back to the embedded legacy Host API. Stream authorization, target binding, and private durable terminal evidence remain owned by the Host API producer.

Windows retains the existing embedded compatibility path; this release does not provide Windows stream delegation or durable terminal evidence support. A replacement Windows bootstrap image and upgrade/rollback tests are still required before Windows hosts are supported. The Server-distributed Windows artifact remains independently pinned to `0.13.27`; Linux `0.13.29` and CI cross-builds do not establish new Windows runtime acceptance.
Windows retains the existing embedded compatibility path; this release does not provide Windows stream delegation or durable terminal evidence support. A replacement Windows bootstrap image and upgrade/rollback tests are still required before Windows hosts are supported. The Server recipe independently pins its Windows artifact; a Linux package publication and CI cross-builds do not establish new Windows runtime acceptance.

The `host.port.check` event performs a read-only host-port preflight through the existing agent event channel. It reports Docker bindings from running and stopped containers and, on Linux, listening TCP/UDP sockets visible through the existing host `/proc` mount. Incomplete host socket inspection is reported as unknown; it is never presented as an available port.

Expand Down
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/node-agent

go 1.26.0

toolchain go1.27.2
toolchain go1.27.3

require (
github.com/PastureStack/websocket-proxy v0.0.0-00010101000000-000000000000
Expand Down
Loading
Loading