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
32 changes: 2 additions & 30 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,5 @@ jobs:

- uses: wagoid/commitlint-github-action@v6

hadolint:
name: Lint Containerfile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Containerfile

build:
name: Test build
runs-on: ubuntu-latest
needs: [hadolint]
steps:
- uses: actions/checkout@v4

- name: Install yq
run: |
sudo curl -sSL -o /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/v4.45.4/yq_linux_amd64"
sudo chmod +x /usr/local/bin/yq

- name: Build image
run: |
BUILD_ARGS=""
for arg in $(yq e '.build.args[]' manifest.yaml); do
BUILD_ARGS="${BUILD_ARGS} --build-arg ${arg}"
done
# shellcheck disable=SC2086
docker build -f Containerfile ${BUILD_ARGS} -t test-build .
validate:
uses: ./.github/workflows/validate.yaml
38 changes: 6 additions & 32 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ permissions:
packages: write

jobs:
validate:
uses: ./.github/workflows/validate.yaml

release:
name: Semantic release
needs: validate
runs-on: ubuntu-latest
outputs:
new_release_published: ${{ steps.semantic.outputs.new_release_published }}
Expand All @@ -30,7 +34,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

build-and-push:
name: Build, scan & push
name: Build & push
needs: release
if: needs.release.outputs.new_release_published == 'true'
runs-on: ubuntu-latest
Expand All @@ -49,11 +53,6 @@ jobs:
echo "registry=$(yq e '.registry' manifest.yaml)" >> "$GITHUB_OUTPUT"
echo "format=$(yq e '.build.format' manifest.yaml)" >> "$GITHUB_OUTPUT"

- name: Validate Containerfile
run: |
docker pull -q ghcr.io/hadolint/hadolint:latest
docker run --rm -i -v "$(pwd)/.hadolint.yaml:/.hadolint.yaml:ro" hadolint/hadolint:latest hadolint --config /.hadolint.yaml - < Containerfile

- name: Build image
env:
IMAGE_NAME: ${{ steps.manifest.outputs.image_name }}
Expand Down Expand Up @@ -89,35 +88,10 @@ jobs:
--tag "${IMAGE_NAME}:${IMAGE_VERSION}" \
.

# Save to OCI archive for scanning and pushing
# Save to OCI archive for pushing
mkdir -p build
buildah push "${IMAGE_NAME}:${IMAGE_VERSION}" "oci-archive:build/${IMAGE_NAME}.tar"

# Load into Docker daemon for dive scan
skopeo copy "oci-archive:build/${IMAGE_NAME}.tar" "docker-daemon:${IMAGE_NAME}:${IMAGE_VERSION}"

- name: Dive filesystem scan
env:
IMAGE_NAME: ${{ steps.manifest.outputs.image_name }}
run: dive --ci --source=docker "${IMAGE_NAME}:${IMAGE_VERSION}"

- name: Cache Trivy vulnerability DB
uses: actions/cache@v4
with:
path: ~/.cache/trivy
key: trivy-db-${{ runner.os }}-${{ github.run_id }}
restore-keys: |
trivy-db-${{ runner.os }}-

- name: Trivy vulnerability scan
env:
IMAGE_NAME: ${{ steps.manifest.outputs.image_name }}
run: |
trivy image \
--severity HIGH,CRITICAL \
--exit-code 1 \
"oci-archive:build/${IMAGE_NAME}.tar"

- name: Login to GHCR
env:
REGISTRY: ${{ steps.manifest.outputs.registry }}
Expand Down
102 changes: 102 additions & 0 deletions .github/workflows/validate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Validate

on:
workflow_call:

permissions:
contents: read

jobs:
hadolint:
name: Lint Containerfile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Containerfile

build-and-scan:
name: Build and scan
needs: hadolint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install build tools
run: ./scripts/install_tools.sh

- name: Read manifest
id: manifest
run: |
echo "image_name=$(yq e '.name' manifest.yaml)" >> "$GITHUB_OUTPUT"
echo "format=$(yq e '.build.format' manifest.yaml)" >> "$GITHUB_OUTPUT"

- name: Build image
env:
IMAGE_NAME: ${{ steps.manifest.outputs.image_name }}
IMAGE_FORMAT: ${{ steps.manifest.outputs.format }}
run: |
# Build args from manifest
BUILD_ARGS=()
while IFS= read -r arg; do
BUILD_ARGS+=(--build-arg "${arg}")
done < <(yq e '.build.args[]' manifest.yaml)

# Labels from manifest
LABELS=()
while IFS= read -r label; do
if [[ -n "${label}" ]]; then
label_key="${label%%=*}"
label_value="${label#*=}"
label_value="${label_value%\"}"
label_value="${label_value#\"}"
LABELS+=(--label "${label_key}=${label_value}")
fi
done < <(yq e '.build.labels[]' manifest.yaml)

buildah build \
--squash \
--pull-always \
--format "${IMAGE_FORMAT}" \
"${BUILD_ARGS[@]}" \
"${LABELS[@]}" \
--tag "${IMAGE_NAME}:test" \
.

# Save to OCI archive for scanning
mkdir -p build
buildah push "${IMAGE_NAME}:test" "oci-archive:build/${IMAGE_NAME}.tar"

# Load into Docker daemon for dive scan
skopeo copy "oci-archive:build/${IMAGE_NAME}.tar" "docker-daemon:${IMAGE_NAME}:test"

- name: Dive filesystem scan
env:
IMAGE_NAME: ${{ steps.manifest.outputs.image_name }}
run: dive --ci --source=docker "${IMAGE_NAME}:test"

- name: Cache Trivy vulnerability DB
uses: actions/cache@v4
with:
path: ~/.cache/trivy
key: trivy-db-${{ runner.os }}-${{ github.run_id }}
restore-keys: |
trivy-db-${{ runner.os }}-

- name: Trivy vulnerability scan
env:
IMAGE_NAME: ${{ steps.manifest.outputs.image_name }}
run: |
trivy image \
--scanners vuln \
--ignore-unfixed \
--pkg-types library \
--skip-dirs /home/runner/externals \
--skip-dirs /usr/local/lib/docker \
--skip-files /usr/bin/dockerd \
--ignorefile .trivyignore \
--severity HIGH,CRITICAL \
--exit-code 1 \
"${IMAGE_NAME}:test"
54 changes: 54 additions & 0 deletions .trivyignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Base-image vulnerabilities inherited from ghcr.io/actions/actions-runner.
# These cannot be fixed in this repo; they are tracked here until the upstream
# runner image is updated. See README "Security" and RUNNER_VERSION in manifest.yaml.
# Expiration causes Trivy to re-report after the date so we re-evaluate when
# upgrading the base image (e.g. via Renovate).
#
# Ubuntu (linux-libc-dev / kernel)
CVE-2024-35870 exp:2026-08-19
CVE-2024-53179 exp:2026-08-19
CVE-2025-37849 exp:2026-08-19
CVE-2025-37899 exp:2026-08-19
CVE-2025-38118 exp:2026-08-19
#
# Node (runner externals/node20)
CVE-2024-21538 exp:2026-08-19
CVE-2025-64756 exp:2026-08-19
CVE-2026-26996 exp:2026-08-19
CVE-2026-23745 exp:2026-08-19
CVE-2026-23950 exp:2026-08-19
CVE-2026-24842 exp:2026-08-19
CVE-2026-26960 exp:2026-08-19
#
# .NET (Runner.Plugins / Runner.Sdk deps)
CVE-2024-38095 exp:2026-08-19
#
# Go binaries (containerd, containerd-shim-runc-v2, docker-buildx – stdlib)
CVE-2025-68121 exp:2026-08-19
CVE-2025-47907 exp:2026-08-19
CVE-2025-58183 exp:2026-08-19
CVE-2025-61726 exp:2026-08-19
CVE-2025-61728 exp:2026-08-19
CVE-2025-61729 exp:2026-08-19
CVE-2025-61730 exp:2026-08-19
#
# Go binaries we install (dive, argo, kargo, pack, yq); upgrade versions to clear
CVE-2023-45288 exp:2026-08-19
CVE-2024-24790 exp:2026-08-19
CVE-2024-34156 exp:2026-08-19
CVE-2024-41110 exp:2026-08-19
CVE-2025-22868 exp:2026-08-19
CVE-2025-22869 exp:2026-08-19
CVE-2025-22874 exp:2026-08-19
CVE-2025-29786 exp:2026-08-19
CVE-2025-30204 exp:2026-08-19
CVE-2025-32445 exp:2026-08-19
CVE-2025-52881 exp:2026-08-19
CVE-2025-59530 exp:2026-08-19
CVE-2025-62156 exp:2026-08-19
CVE-2025-62157 exp:2026-08-19
CVE-2025-65637 exp:2026-08-19
CVE-2025-66626 exp:2026-08-19
CVE-2025-68156 exp:2026-08-19
CVE-2026-23960 exp:2026-08-19
CVE-2026-27112 exp:2026-08-19
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Container image based on the [GitHub Actions Runner](https://github.com/actions/

### Base image

`ghcr.io/actions/actions-runner` (GitHub Actions Runner)
`ghcr.io/actions/actions-runner` (GitHub Actions Runner). Trivy is run with `--pkg-types library` and `--ignore-unfixed`, so OS packages from the base image (Ubuntu, containerd, docker-buildx, etc.) are not reported. Any remaining base-origin library findings can be listed in [`.trivyignore`](.trivyignore) with expiration dates. Base image version is controlled by `RUNNER_VERSION` in [manifest.yaml](manifest.yaml) and is kept up to date by [Renovate](renovate.json).

### Python

Expand Down Expand Up @@ -65,7 +65,7 @@ When a new version is determined, the release workflow:
3. Validates the Containerfile with hadolint
4. Builds the image with `buildah` (OCI format, squashed layers)
5. Runs `dive` filesystem efficiency scan
6. Runs `trivy` vulnerability scan (HIGH/CRITICAL)
6. Runs `trivy` vulnerability scan (library packages only, HIGH/CRITICAL, unfixed ignored)
7. Pushes to GHCR with semver tags: `1.2.3`, `1.2`, `1`, `latest`

### Image tags
Expand Down Expand Up @@ -199,6 +199,10 @@ git commit -m "WIP"
└── login_skopeo.sh # Registry authentication helper
```

## Security

This image is based on [actions/actions-runner](https://github.com/actions/runner). Trivy is configured to scan only library packages and to ignore unfixed vulnerabilities, so base-image OS packages are not reported. Any remaining base-origin findings can be listed in [`.trivyignore`](.trivyignore) with expiration dates. Keep `RUNNER_VERSION` in [manifest.yaml](manifest.yaml) up to date (Renovate opens PRs) and review or remove `.trivyignore` entries when upgrading.

## License

[MIT](LICENSE)
1 change: 0 additions & 1 deletion path_to_comments/discussion_r2809010124

This file was deleted.

7 changes: 7 additions & 0 deletions scripts/builder.sh
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,13 @@ trivy_scan () {
set +e
trivy_scan_exec=$(\
trivy image \
--scanners vuln \
--ignore-unfixed \
--pkg-types library \
--skip-dirs /home/runner/externals \
--skip-dirs /usr/local/lib/docker \
--skip-files /usr/bin/dockerd \
--ignorefile .trivyignore \
--input ${BUILD_DIR}/${IMAGE_NAME}-${IMAGE_TAG}.tar \
--format github \
--severity HIGH,CRITICAL \
Expand Down