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
53 changes: 43 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
set -euo pipefail
test "$GITHUB_REF" = refs/heads/main
[[ "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]
test "$RELEASE_TAG" = 'v0.10.6'
test "$RELEASE_TAG" = 'v0.10.7'
test -z "$(git status --porcelain)"
test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
test "$(gh api "repos/$GITHUB_REPOSITORY/git/ref/heads/main" --jq .object.sha)" = "$GITHUB_SHA"
Expand Down Expand Up @@ -80,7 +80,7 @@ jobs:
- name: Build supported executables
env:
CROSS: "1"
VERSION_OVERRIDE: "0.10.6"
VERSION_OVERRIDE: "0.10.7"
run: bash ./scripts/build

- name: Verify builder and runtime security inputs
Expand All @@ -105,19 +105,21 @@ jobs:
mkdir -p "$context/licenses/third-party"
install -m 0644 LICENSE COMPATIBILITY.md ORIGIN.md SECURITY.md THIRD_PARTY_NOTICES.md "$context/licenses/"
cp -a LICENSES/. "$context/licenses/third-party/"
docker build --build-arg PASTURESTACK_IMAGE_VERSION=0.10.6 \
docker build --build-arg PASTURESTACK_IMAGE_VERSION=0.10.7 \
--build-arg PASTURESTACK_IMAGE_REVISION="$GITHUB_SHA" \
--build-arg PASTURESTACK_IMAGE_CREATED="$(git show -s --format=%cI HEAD)" \
-t local/metadata-service:security "$context"
mkdir -p evidence
test "$(docker image inspect --format '{{index .Config.Labels "org.opencontainers.image.revision"}}' local/metadata-service:security)" = "$GITHUB_SHA"
test "$(docker image inspect --format '{{index .Config.Labels "org.opencontainers.image.version"}}' local/metadata-service:security)" = '0.10.6'
test "$(docker image inspect --format '{{index .Config.Labels "org.opencontainers.image.version"}}' local/metadata-service:security)" = '0.10.7'
docker image inspect local/metadata-service:security > evidence/image-inspect.json
docker run --rm --entrypoint dpkg-query local/metadata-service:security -W '-f=${Version}\n' ca-certificates | tee evidence/ca-version.txt
grep -Fx '20260816ubuntu0.26.04.1' evidence/ca-version.txt
container=$(docker create local/metadata-service:security)
docker cp "$container:/usr/bin/metadata-service" evidence/product
docker cp "$container:/usr/share/pasturestack/ubuntu-security-packages.tsv" evidence/ubuntu-security-packages.tsv
docker cp "$container:/usr/share/pasturestack/security/ubuntu-backports" evidence/ubuntu-backports
(cd evidence/ubuntu-backports && sha256sum --check SHA256SUMS)
go version -m evidence/product | tee evidence/product-go-version.txt
grep -F 'go1.27.3' evidence/product-go-version.txt

Expand All @@ -128,15 +130,46 @@ jobs:
TESTED_IMAGE: local/metadata-service:security
run: |
set -euo pipefail
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v "$PWD/evidence:/evidence" \
"$TRIVY_IMAGE" image --scanners vuln,secret --severity UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL \
cache="$RUNNER_TEMP/ubuntu-backports-trivy-cache"
mkdir -p "$cache"
docker run --rm -v "$cache:/root/.cache/trivy" "$TRIVY_IMAGE" image --download-db-only
# Retain the untouched all-severity raw report and the actual image SBOM.
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
-v "$cache:/root/.cache/trivy" -v "$PWD/evidence:/evidence" "$TRIVY_IMAGE" \
image --skip-db-update --scanners vuln,secret --severity UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL \
--exit-code 0 --format json --output /evidence/image-security.json "$TESTED_IMAGE"
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v "$PWD/evidence:/evidence" \
"$TRIVY_IMAGE" image --format cyclonedx --output /evidence/image.cdx.json "$TESTED_IMAGE"
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
-v "$cache:/root/.cache/trivy" -v "$PWD/evidence:/evidence" "$TRIVY_IMAGE" \
image --skip-db-update --format cyclonedx --output /evidence/image.cdx.json "$TESTED_IMAGE"
bundle_image='ghcr.io/pasturestack/ubuntu-security-backports:v0.1.0@sha256:2742a3d429e4e14bc587f6dedc51ded4246cf90bbaedcd86c67d0885e32a6f2a'
mkdir -p evidence/bundle-tools
bundle_container=$(docker create "$bundle_image" unused)
trap 'docker rm "$bundle_container" >/dev/null' EXIT
docker cp "$bundle_container:/out/verify-consumer-evidence.py" evidence/bundle-tools/verify-consumer-evidence.py
docker cp "$bundle_container:/out/SHA256SUMS" evidence/bundle-tools/SHA256SUMS
docker rm "$bundle_container" >/dev/null
trap - EXIT
(cd evidence/bundle-tools && \
test "$(grep -Ec '^[0-9a-f]{64} verify-consumer-evidence\.py$' SHA256SUMS)" -eq 1 && \
grep -E '^[0-9a-f]{64} verify-consumer-evidence\.py$' SHA256SUMS | sha256sum --check -)
python3 evidence/bundle-tools/verify-consumer-evidence.py \
--evidence-dir evidence/ubuntu-backports --sbom evidence/image.cdx.json \
--bundle-checksums evidence/bundle-tools/SHA256SUMS \
--expected-bundle-digest 'sha256:2742a3d429e4e14bc587f6dedc51ded4246cf90bbaedcd86c67d0885e32a6f2a' > evidence/ubuntu-backports-validation.json
# Only native Trivy interprets the exact qualified OpenVEX statements.
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
-v "$cache:/root/.cache/trivy" -v "$PWD/evidence:/evidence" "$TRIVY_IMAGE" \
image --skip-db-update --scanners vuln,secret --severity UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL \
--vex /evidence/ubuntu-backports/openvex.json --exit-code 0 --format json \
--output /evidence/image-security.effective.json "$TESTED_IMAGE"
PYTHONDONTWRITEBYTECODE=1 python3 .github/scripts/test_runtime_vulnerability_policy.py
python3 .github/scripts/enforce-runtime-vulnerabilities.py \
evidence/image-security.json .github/runtime-unfixed.json \
evidence/image-security.effective.json .github/runtime-unfixed.json \
--repository "$GITHUB_REPOSITORY"
tar -cf evidence/ubuntu-backports-evidence.tar -C evidence ubuntu-backports
sha256sum evidence/image-security.json evidence/image-security.effective.json \
evidence/image.cdx.json evidence/ubuntu-backports-validation.json \
evidence/ubuntu-backports-evidence.tar >> evidence/SHA256SUMS

- name: Publish the tested image once
id: publish
Expand Down Expand Up @@ -188,7 +221,7 @@ jobs:
-f ref="refs/tags/$RELEASE_TAG" -f sha="$tag_sha" >/dev/null
gh release create "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --verify-tag \
--title "$RELEASE_TAG" --notes-file evidence/published.txt \
evidence/published.txt evidence/published.sha256 evidence/*.json
evidence/published.txt evidence/published.sha256 evidence/*.json evidence/ubuntu-backports-evidence.tar

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
Expand Down
34 changes: 9 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Metadata Service

Current source builds use Go 1.27.3 while the Go language minimum remains 1.26.0. Ubuntu 26.04 images install the checksum-pinned `ca-certificates` 20260816ubuntu0.26.04.1 package with only officially fixed, already-installed packages advanced by the reviewed security overlay. These source inputs take effect in newly built artifacts; existing published release coordinates below describe their original artifacts.
Linux runtime **`v0.10.7`** integrates shared Ubuntu 26.04 security backports for already-installed packages while preserving the selected coreutils provider.

The image retains bundle manifests, source inputs and installation receipts under `/usr/share/pasturestack/security/ubuntu-backports/`.

Metadata Service is a source-IP-aware HTTP service for environment, host, service, and workload metadata. It supports dated API views, JSON/YAML/plain-text responses, long polling, file reloads, and an optional platform event subscription.

Expand All @@ -18,42 +20,24 @@ PastureStack is an independent community effort to preserve, audit, and moderniz

See [COMPATIBILITY.md](COMPATIBILITY.md) before changing paths, answer shapes, event names, or long-poll behavior.

## Release status

Current source targets `v0.10.6`. Install only tags listed in the
[official published releases](https://github.com/PastureStack/metadata-service/releases).
A source target alone is not publication or real-host acceptance.
This update preserves opaque per-dataset change tokens, including the
platform's `revision-hash` values, instead of coercing them to numeric `0`.
Long-poll clients can therefore observe local data changes without changing
their polling protocol. Explicit aggregate-source version overrides, dated
views, payloads and source-IP authorization remain unchanged.

Use the selected release's checksum-covered publication evidence for its exact
producer, image digest, SBOM and provenance. Windows Server 2022 remains on
`v0.9.12`; the Linux source update does not replace that separately versioned
image. Catalog selection and deployment acceptance remain separate.

## Run from an answers file

```bash
docker run --rm -p 8080:80 \
--mount type=bind,src="$PWD/example/answers.json",dst=/var/lib/pasturestack-metadata/answers.json,readonly \
ghcr.io/pasturestack/metadata-service:v0.10.6 \
ghcr.io/pasturestack/metadata-service:v0.10.7 \
metadata-service --answers /var/lib/pasturestack-metadata/answers.json
```

The top level of an answers file is a map of dated versions. Each dated version maps client IP addresses (or `default`) to arbitrary JSON/YAML values. Examples are available under `example/`.

The image runs as UID/GID `10001` by default and can bind port 80 through a file capability. A managed system deployment starts the container as root with `NET_ADMIN` only long enough to add `169.254.169.250/32`, then immediately drops to UID/GID `10001`. The image does not require root for file-backed standalone use.

The Windows Server 2022 Catalog uses
`ghcr.io/pasturestack/metadata-service-windows:v0.9.12`. That pure numeric
coordinate is an exact manifest alias of the reviewed Windows build
(`sha256:e957230b715e7fbebd2c9709d1a3c38be5ee4f8694f8c1c1fda0d4bf27c36836`),
so the naming correction does not change image bytes. The separately versioned
image assigns the same link-local address through the Windows networking API
and runs the cross-compiled service in subscription mode.
The separately versioned Windows Server 2022 Catalog image remains
`ghcr.io/pasturestack/metadata-service-windows:v0.9.12`; it is not rebuilt or
revalidated by this Linux preparation. It assigns the same link-local address
through the Windows networking API and runs the cross-compiled service in
subscription mode.

## Platform subscription mode

Expand Down
17 changes: 17 additions & 0 deletions package/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# syntax=docker/dockerfile:1.7
FROM ghcr.io/pasturestack/ubuntu-security-backports:v0.1.0@sha256:2742a3d429e4e14bc587f6dedc51ded4246cf90bbaedcd86c67d0885e32a6f2a AS ubuntu_security_backports
FROM ubuntu:26.04@sha256:2260313b31c8c011cd2eebe728008efac1b3982be73eb71348ea2648d2c0e09b

ARG UBUNTU_SNAPSHOT=20260825T000000Z
Expand Down Expand Up @@ -52,6 +53,22 @@ LABEL org.opencontainers.image.title="metadata-service" \
org.opencontainers.image.revision="${PASTURESTACK_IMAGE_REVISION}" \
org.opencontainers.image.created="${PASTURESTACK_IMAGE_CREATED}"

# Install only qualified packages already present after the final Ubuntu update.
# This read-only build mount leaves no installer, archive or extra runtime tool.
RUN --mount=from=ubuntu_security_backports,source=/out,target=/opt/pasturestack/ubuntu-security-backports,ro \
set -eux; \
evidence=/usr/share/pasturestack/security/ubuntu-backports; \
mkdir -p "${evidence}"; \
/opt/pasturestack/ubuntu-security-backports/install-existing-backports --install-in-docker-build > "${evidence}/install.json"; \
/opt/pasturestack/ubuntu-security-backports/install-existing-backports --verify-installed > "${evidence}/verify.json"; \
for document in manifest.json qualification.json openvex.json source-inputs.lock.json; do \
cp "/opt/pasturestack/ubuntu-security-backports/${document}" "${evidence}/${document}"; \
done; \
printf '%s\n' 'ghcr.io/pasturestack/ubuntu-security-backports:v0.1.0@sha256:2742a3d429e4e14bc587f6dedc51ded4246cf90bbaedcd86c67d0885e32a6f2a' > "${evidence}/bundle-image.txt"; \
(cd "${evidence}" && sha256sum manifest.json qualification.json openvex.json source-inputs.lock.json install.json verify.json bundle-image.txt > SHA256SUMS); \
dpkg-query -W -f='${binary:Package}\t${Version}\n' | LC_ALL=C sort > /usr/share/pasturestack/ubuntu-security-packages.tsv; \
rm -f /var/cache/ldconfig/aux-cache

USER 10001:10001

ENTRYPOINT ["/usr/bin/platform-entrypoint.sh", "/usr/bin/start.sh"]
Expand Down
Loading