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
60 changes: 41 additions & 19 deletions .depot/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ permissions:
contents: read
packages: write
id-token: write
env:
IMAGE_NAME: ghcr.io/getarcaneapp/tools
PUBLISH_PLATFORMS: linux/amd64,linux/386,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
jobs:
validate:
if: ${{ github.repository_owner != 'getarcaneapp' && github.actor !=
Expand All @@ -30,28 +27,46 @@ jobs:
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Install just
uses: extractions/setup-just@v3
- name: Install yq
run: |
sudo curl -fsSL -o /usr/local/bin/yq \
https://github.com/mikefarah/yq/releases/download/v4.45.1/yq_linux_amd64
sudo chmod +x /usr/local/bin/yq
- name: Set up Depot CLI
uses: depot/setup-action@v1
- name: Build validation image
uses: depot/build-push-action@v1
with:
project: np622krb2x
context: .
load: true
platforms: linux/amd64
tags: arcane-toolbox:ci
run: just build-ci
- name: Validate runtime contract
run: ./scripts/validate.sh arcane-toolbox:ci
run: just validate
publish:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
needs: validate
runs-on: depot-ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Install just
uses: extractions/setup-just@v3
- name: Install yq
run: |
sudo curl -fsSL -o /usr/local/bin/yq \
https://github.com/mikefarah/yq/releases/download/v4.45.1/yq_linux_amd64
sudo chmod +x /usr/local/bin/yq
- name: Resolve build inputs from build.yaml
id: cfg
run: |
just prepare
{
echo "alpine=$(yq -r '.versions.alpine' build.yaml)"
echo "trivy=$(yq -r '.versions.trivy' build.yaml)"
echo "busybox=$(yq -r '.versions.busybox' build.yaml)"
echo "platforms=$(yq -r '.platforms.publish | join(",")' build.yaml)"
echo "image=$(yq -r '.image.name' build.yaml)"
} >> "$GITHUB_OUTPUT"
- name: Set up Depot CLI
uses: depot/setup-action@v1

- name: Install cosign
uses: sigstore/cosign-installer@v4.1.1
- name: Log in to GHCR
Expand All @@ -64,7 +79,9 @@ jobs:
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.IMAGE_NAME }}
images: ${{ steps.cfg.outputs.image }}
flavor: |
latest=true
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
Expand All @@ -77,26 +94,31 @@ jobs:
project: np622krb2x
context: .
file: ./Dockerfile
platforms: ${{ env.PUBLISH_PLATFORMS }}
platforms: ${{ steps.cfg.outputs.platforms }}
push: true
build-args: |
ALPINE_VERSION=${{ steps.cfg.outputs.alpine }}
TRIVY_VERSION=${{ steps.cfg.outputs.trivy }}
BUSYBOX_VERSION=${{ steps.cfg.outputs.busybox }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Sign published image
run: cosign sign --yes --key env://COSIGN_PRIVATE_KEY "${IMAGE_NAME}@${{ steps.build.outputs.digest }}"
run: cosign sign --yes --key env://COSIGN_PRIVATE_KEY "${IMAGE}@${{ steps.build.outputs.digest }}"
env:
IMAGE: ${{ steps.cfg.outputs.image }}
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
- name: Generate image digest attestation
uses: actions/attest@v4
with:
subject-name: ${{ env.IMAGE_NAME }}
subject-name: ${{ steps.cfg.outputs.image }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
- name: Record published digest
run: |
{
echo "Published image: ${{ env.IMAGE_NAME }}"
echo "Published platforms: ${{ env.PUBLISH_PLATFORMS }}"
echo "Published image: ${{ steps.cfg.outputs.image }}"
echo "Published platforms: ${{ steps.cfg.outputs.platforms }}"
echo "Published digest: ${{ steps.build.outputs.digest }}"
echo "Published attestation: ${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}"
echo "Published attestation: ${{ steps.cfg.outputs.image }}@${{ steps.build.outputs.digest }}"
} >> "$GITHUB_STEP_SUMMARY"
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@
./scripts/
LICENSE
README.md
third_party
64 changes: 46 additions & 18 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ permissions:
packages: write
id-token: write

env:
IMAGE_NAME: ghcr.io/getarcaneapp/tools
PUBLISH_PLATFORMS: linux/amd64,linux/386,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x

jobs:
validate:
if: ${{ github.repository_owner != 'getarcaneapp' && github.actor !=
Expand All @@ -29,19 +25,23 @@ jobs:
- name: Check out repository
uses: actions/checkout@v6

- name: Install just
uses: extractions/setup-just@v3

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

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4

- name: Build validation image
uses: docker/build-push-action@v7
with:
context: .
load: true
platforms: linux/amd64
tags: arcane-toolbox:ci
run: just build-ci

- name: Validate runtime contract
run: ./scripts/validate.sh arcane-toolbox:ci
run: just validate

publish:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
Expand All @@ -51,6 +51,27 @@ jobs:
- name: Check out repository
uses: actions/checkout@v6

- name: Install just
uses: extractions/setup-just@v3

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

- name: Resolve build inputs from build.yaml
id: cfg
run: |
just prepare
{
echo "alpine=$(yq -r '.versions.alpine' build.yaml)"
echo "trivy=$(yq -r '.versions.trivy' build.yaml)"
echo "busybox=$(yq -r '.versions.busybox' build.yaml)"
echo "platforms=$(yq -r '.platforms.publish | join(",")' build.yaml)"
echo "image=$(yq -r '.image.name' build.yaml)"
} >> "$GITHUB_OUTPUT"

- name: Set up Depot CLI
uses: depot/setup-action@v1

Expand All @@ -68,7 +89,9 @@ jobs:
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.IMAGE_NAME }}
images: ${{ steps.cfg.outputs.image }}
flavor: |
latest=true
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
Expand All @@ -82,30 +105,35 @@ jobs:
project: np622krb2x
context: .
file: ./Dockerfile
platforms: ${{ env.PUBLISH_PLATFORMS }}
platforms: ${{ steps.cfg.outputs.platforms }}
push: true
build-args: |
ALPINE_VERSION=${{ steps.cfg.outputs.alpine }}
TRIVY_VERSION=${{ steps.cfg.outputs.trivy }}
BUSYBOX_VERSION=${{ steps.cfg.outputs.busybox }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

- name: Sign published image
run: cosign sign --yes --key env://COSIGN_PRIVATE_KEY "${IMAGE_NAME}@${{
run: cosign sign --yes --key env://COSIGN_PRIVATE_KEY "${IMAGE}@${{
steps.build.outputs.digest }}"
env:
IMAGE: ${{ steps.cfg.outputs.image }}
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}

- name: Generate image digest attestation
uses: actions/attest@v4
with:
subject-name: ${{ env.IMAGE_NAME }}
subject-name: ${{ steps.cfg.outputs.image }}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true

- name: Record published digest
run: |
{
echo "Published image: ${{ env.IMAGE_NAME }}"
echo "Published platforms: ${{ env.PUBLISH_PLATFORMS }}"
echo "Published image: ${{ steps.cfg.outputs.image }}"
echo "Published platforms: ${{ steps.cfg.outputs.platforms }}"
echo "Published digest: ${{ steps.build.outputs.digest }}"
echo "Published attestation: ${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}"
echo "Published attestation: ${{ steps.cfg.outputs.image }}@${{ steps.build.outputs.digest }}"
} >> "$GITHUB_STEP_SUMMARY"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist/
25 changes: 8 additions & 17 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ RUN apk add --no-cache ca-certificates curl tar

WORKDIR /work

COPY checksums/trivy_0.70.0_checksums.txt /checksums/trivy_checksums.txt
COPY checksums/trivy.txt /checksums/trivy_checksums.txt

RUN case "${TARGETARCH}/${TARGETVARIANT}" in \
amd64/*) trivy_arch='64bit' ;; \
Expand All @@ -38,8 +38,9 @@ RUN apk add --no-cache build-base bzip2 curl linux-headers perl

WORKDIR /work

COPY checksums/busybox-1.37.0.tar.bz2.sha256 /checksums/busybox.tar.bz2.sha256
COPY busybox.config /tmp/busybox.config
COPY checksums/busybox.sha256 /checksums/busybox.tar.bz2.sha256
COPY dist/busybox.config /tmp/busybox.config
COPY dist/applets.txt /tmp/applets.txt

RUN curl -fsSLO "https://busybox.net/downloads/busybox-${BUSYBOX_VERSION}.tar.bz2" && \
sha256sum -c /checksums/busybox.tar.bz2.sha256 && \
Expand All @@ -62,20 +63,10 @@ RUN make -j"$(getconf _NPROCESSORS_ONLN)"

RUN install -Dm755 busybox /out/bin/busybox && \
mkdir -p /out/tmp /out/root/.cache && \
ln -s /bin/busybox /out/bin/sh && \
ln -s /bin/busybox /out/bin/sleep && \
ln -s /bin/busybox /out/bin/find && \
ln -s /bin/busybox /out/bin/gzip && \
ln -s /bin/busybox /out/bin/stat && \
ln -s /bin/busybox /out/bin/readlink && \
ln -s /bin/busybox /out/bin/head && \
ln -s /bin/busybox /out/bin/rm && \
ln -s /bin/busybox /out/bin/mkdir && \
ln -s /bin/busybox /out/bin/mv && \
ln -s /bin/busybox /out/bin/rmdir && \
ln -s /bin/busybox /out/bin/mktemp && \
ln -s /bin/busybox /out/bin/tar && \
ln -s /bin/busybox /out/bin/test && \
while IFS= read -r applet; do \
[ -n "${applet}" ] || continue; \
ln -s /bin/busybox "/out/bin/${applet}"; \
done < /tmp/applets.txt && \
chmod 1777 /out/tmp

FROM scratch
Expand Down
88 changes: 88 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Justfile — orchestrates the arcane-toolbox build from build.yaml.
# Prereqs: just, yq (github.com/mikefarah/yq, v4+), docker (with buildx).

set shell := ["bash", "-eu", "-o", "pipefail", "-c"]

config := "build.yaml"

# Resolved at startup so a broken build.yaml fails before any work runs.
alpine_version := `yq -r '.versions.alpine' build.yaml`
trivy_version := `yq -r '.versions.trivy' build.yaml`
busybox_version := `yq -r '.versions.busybox' build.yaml`
image_name := `yq -r '.image.name' build.yaml`
local_tag := `yq -r '.image.local_tag' build.yaml`
ci_tag := `yq -r '.image.ci_tag' build.yaml`
validate_plat := `yq -r '.platforms.validate' build.yaml`
publish_plats := `yq -r '.platforms.publish | join(",")' build.yaml`

default: list

list:
@just --list

versions:
@echo "alpine: {{alpine_version}}"
@echo "trivy: {{trivy_version}}"
@echo "busybox: {{busybox_version}}"
@echo "image: {{image_name}}"
@echo "local_tag: {{local_tag}}"
@echo "ci_tag: {{ci_tag}}"
@echo "validate: {{validate_plat}}"
@echo "publish: {{publish_plats}}"

# Materialize YAML-derived inputs the Dockerfile expects.
prepare: manifest
mkdir -p dist
yq -r '.busybox.config[] | . + "=y"' {{config}} > dist/busybox.config
yq -r '.busybox.applets[]' {{config}} > dist/applets.txt

# Regenerate checksums/manifest.md from build.yaml.
manifest:
@printf '# Third-Party Manifest\n\nGenerated from `build.yaml`; run `just prepare` to regenerate.\n\nThird-party binaries shipped in the final runtime image.\n\n| Binary | Version | Source | Checksum | License |\n|---|---|---|---|---|\n| Trivy | %s | <https://github.com/aquasecurity/trivy/releases/tag/v%s> | [trivy.txt](trivy.txt) | Apache-2.0 |\n| BusyBox | %s | <https://busybox.net/downloads/busybox-%s.tar.bz2> | [busybox.sha256](busybox.sha256) | GPL-2.0-only |\n\nThe CA certificate bundle is copied from Alpine %s during the build and is not\ntreated as a separately versioned executable binary.\n' \
'{{trivy_version}}' '{{trivy_version}}' \
'{{busybox_version}}' '{{busybox_version}}' \
'{{alpine_version}}' \
> checksums/manifest.md

# Build for the validate platform, load into local docker as local_tag.
build: prepare
docker buildx build \
--load \
--platform {{validate_plat}} \
--build-arg ALPINE_VERSION={{alpine_version}} \
--build-arg TRIVY_VERSION={{trivy_version}} \
--build-arg BUSYBOX_VERSION={{busybox_version}} \
-t {{local_tag}} \
.

# Build the CI validation image. Tag is parameterized so the workflow can
# pass arcane-toolbox:ci explicitly.
build-ci tag=ci_tag: prepare
docker buildx build \
--load \
--platform {{validate_plat}} \
--build-arg ALPINE_VERSION={{alpine_version}} \
--build-arg TRIVY_VERSION={{trivy_version}} \
--build-arg BUSYBOX_VERSION={{busybox_version}} \
-t {{tag}} \
.

# Run the runtime contract checks against an already-built image.
validate tag=ci_tag:
./scripts/validate.sh {{tag}}

# Multi-platform build + push via Depot CLI. Workstation convenience —
# CI uses depot/build-push-action so it can hand the digest to cosign/attest.
publish tags: prepare
depot build \
--project np622krb2x \
--platform {{publish_plats}} \
--build-arg ALPINE_VERSION={{alpine_version}} \
--build-arg TRIVY_VERSION={{trivy_version}} \
--build-arg BUSYBOX_VERSION={{busybox_version}} \
$(printf -- '--tag %s ' {{tags}}) \
--push \
.

clean:
rm -rf dist
Loading