Skip to content

v2.2.1

v2.2.1 #1

Workflow file for this run

name: Docker
on:
release:
types:
- published
env:
REGISTRY: docker.io
IMAGE_NAME: invarianttech/client
jobs:
build:
name: Build and sign artifacts
runs-on: ubuntu-latest
permissions:
id-token: write
outputs:
hashes: ${{ steps.hash.outputs.hashes }}
steps:
- uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
- uses: actions/setup-python@5ccb29d8773c3f3f653e1705f474dfaa8a06a912 # v4.4.0
with:
python-version: "3.12"
- name: deps
run: |
python -m pip install -U build
python -m pip install -U sigstore
- name: build
run: python -m build
- name: sign
run: |
mkdir -p smoketest-artifacts
# we smoke-test sigstore by installing each of the distributions
# we've built in a fresh environment and using each to sign and
# verify for itself, using the ambient OIDC identity
for dist in dist/*; do
dist_base="$(basename "${dist}")"
python -m venv smoketest-env
./smoketest-env/bin/python -m pip install "${dist}"
./smoketest-env/bin/python -m pip install sigstore
# NOTE: signing artifacts currently go in a separate directory,
# to avoid confusing the package uploader (which otherwise tries
# to upload them to PyPI and fails). Future versions of twine
# and the gh-action-pypi-publish action should support these artifacts.
./smoketest-env/bin/python -m \
sigstore sign "${dist}" \
--output-signature smoketest-artifacts/"${dist_base}.sig" \
--output-certificate smoketest-artifacts/"${dist_base}.crt"
./smoketest-env/bin/python -m \
sigstore verify identity "${dist}" \
--cert "smoketest-artifacts/${dist_base}.crt" \
--signature "smoketest-artifacts/${dist_base}.sig" \
--cert-oidc-issuer https://token.actions.githubusercontent.com \
--cert-identity ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/.github/workflows/release.yml@${GITHUB_REF}
rm -rf smoketest-env
done
- name: Generate hashes for provenance
shell: bash
id: hash
run: |
# sha256sum generates sha256 hash for all artifacts.
# base64 -w0 encodes to base64 and outputs on a single line.
# sha256sum artifact1 artifact2 ... | base64 -w0
echo "hashes=$(cd dist && sha256sum * | base64 -w0)" >> $GITHUB_OUTPUT
- name: Upload built packages
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: built-packages
path: ./dist/
if-no-files-found: warn
generate-provenance:
needs: [build]
name: Generate build provenance
permissions:
actions: read # To read the workflow path.
id-token: write # To sign the provenance.
contents: write # To add assets to a release.
# Currently this action needs to be referred by tag. More details at:
# https://github.com/slsa-framework/slsa-github-generator#verification-of-provenance
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 # v2.1.0
with:
provenance-name: provenance-sigstore-${{ github.event.release.tag_name }}.intoto.jsonl
base64-subjects: "${{ needs.build.outputs.hashes }}"
upload-assets: true
release-pypi:
needs: [build, generate-provenance]
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Download artifacts directories # goes to current working directory
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
- name: Remove signature # pypi will not ignore the signatures anymore and does not support them.
run: rm -f built-packages/*.sigstore
- name: Remove signature json
run: rm -f built-packages/*.sigstore.json
- name: publish
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
with:
user: __token__
password: ${{ secrets.PYPI_TOKEN }}
packages_dir: built-packages/
release-github:
needs: [build, generate-provenance]
runs-on: ubuntu-latest
permissions:
# Needed to upload release assets.
contents: write
steps:
- name: Download artifacts directories # goes to current working directory
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
- name: Upload artifacts to github
# Confusingly, this action also supports updating releases, not
# just creating them. This is what we want here, since we've manually
# created the release that triggered the action.
uses: softprops/action-gh-release@b21b43df682dab285bf5146c1955e7f3560805f8 # v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# smoketest-artifacts/ contains the signatures and certificates.
files: |
built-packages/*
release-docker:
runs-on: ubuntu-latest
needs: [release-pypi]
permissions:
contents: read
packages: write
id-token: write # required for cosign keyless
steps:
- name: Checkout repository
uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0
# Install cosign (skip on PRs)
- name: Install cosign
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
with:
cosign-release: 'v2.2.4'
- name: Resolve package and Python versions
id: versions
run: |
set -euo pipefail
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
echo "Waiting for invariant-client==$TAG_VERSION..."
for i in {1..30}; do
if pip install --disable-pip-version-check --quiet "invariant-client==$TAG_VERSION"; then
break
fi
echo "Version $TAG_VERSION not found, retrying in 10s..."
sleep 10
done
INVARIANT_VERSION=$(python3 - <<'EOF'
from importlib.metadata import version
print(version("invariant-client"))
EOF
)
echo "invariant_version=${INVARIANT_VERSION}" >> "$GITHUB_OUTPUT"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Log into Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=tag,pattern=v(.*),group=1
type=sha
- name: Validate version matches git tag
run: |
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
if [ "$TAG_VERSION" != "${{ steps.versions.outputs.invariant_version }}" ]; then
echo "❌ Git tag v$TAG_VERSION does not match invariant version ${{ steps.versions.outputs.invariant_version }}"
exit 1
fi
- name: Get current date
id: date
run: echo "date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
# ---- BUILD (SBOM ENABLED) ----
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5.4.0
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
INVARIANT_VERSION=${{ steps.versions.outputs.invariant_version }}
BUILD_DATE=${{ steps.date.outputs.date }}
VCS_REF=${{ github.sha }}
sbom: true
provenance: true
cache-from: type=gha
cache-to: type=gha,mode=max
# ---- IMAGE SIGNING ----
- name: Sign the published Docker image
env:
TAGS: ${{ steps.meta.outputs.tags }}
DIGEST: ${{ steps.build-and-push.outputs.digest }}
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
# ---- SBOM ATTESTATION ----
- name: Cosign attest SBOM
env:
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
DIGEST: ${{ steps.build-and-push.outputs.digest }}
run: |
cosign attest \
--yes \
--predicate <(cosign download sbom ${IMAGE}@${DIGEST}) \
--type spdx \
${IMAGE}@${DIGEST}