diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04b97e0..48b2fb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: actionlint - uses: raven-actions/actionlint@v1 + uses: raven-actions/actionlint@v2.0.1 test-actions: runs-on: ubuntu-latest @@ -50,15 +50,16 @@ jobs: sudo apt-get install -y ruby ruby-dev build-essential rpm gnupg gem install --user-install --no-document fpm # Ensure Ruby gem bin dir is in PATH for future steps - echo "$(ruby -e 'print Gem.bindir')" >> $GITHUB_PATH + ruby -e 'print Gem.bindir' >> "$GITHUB_PATH" - name: Build dummy RPM run: | # Ensure Gem.bindir is in PATH so fpm can be found - export PATH="$(ruby -e 'print Gem.bindir'):$PATH" + gem_bindir=$(ruby -e 'print Gem.bindir') + export PATH="${gem_bindir}:$PATH" # Show where fpm is - echo "Gem.bindir is: $(ruby -e 'print Gem.bindir')" + echo "Gem.bindir is: ${gem_bindir}" which /root/.local/share/gem/ruby/3.0.0/bin/fpm || { echo "ERROR: fpm not found"; exit 1; } /root/.local/share/gem/ruby/3.0.0/bin/fpm --version mkdir -p dist diff --git a/.github/workflows/docker-build-release.yml b/.github/workflows/docker-build-release.yml new file mode 100644 index 0000000..ddb4c70 --- /dev/null +++ b/.github/workflows/docker-build-release.yml @@ -0,0 +1,164 @@ +name: Build image +run-name: Dockeer image build for ${{ github.event.push.ref }} + +on: + workflow_call: + inputs: + fetch-depth: + description: 'Git fetch depth for checkout' + required: false + type: number + default: 0 + fetch-tags: + description: 'Whether to fetch tags during checkout' + required: false + type: number + default: 1 + cgo-enabled: + description: 'Set CGO_ENABLED environment variable' + required: false + type: string + default: '' + additional-env-vars: + description: 'Additional environment variables to set (KEY=value format, one per line)' + required: false + type: string + default: '' + registry-name: + description: 'Container registry name (e.g., ghcr.io/openchami/project-name) to Generate build provenance for container' + required: true + type: string + docker-file: + description: 'Dockerfile to use' + required: false + type: string + default: 'Dockerfile' + docker-target: + description: 'Dockerfile target to build' + required: false + type: string + default: 'main' + platforms: + description: 'Platforms to build for' + type: string + default: 'linux/amd64, linux/arm64' + +permissions: write-all # Necessary for the generate-build-provenance action with containers + +jobs: + build-push-images: + environment: 'Docker Push' + runs-on: ubuntu-latest + steps: + - name: checkout repository + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 0 + + - name: Setup golang + uses: actions/setup-go@v5.5.0 + with: + go-version-file: go.mod + + - run: echo "GOPATH=$(go env GOPATH)" >> "$GITHUB_ENV" + + - run: echo "GOCACHE=$(go env GOCACHE)" >> "$GITHUB_ENV" + + - name: Set CGO_ENABLED if specified + if: ${{ inputs.cgo-enabled != '' }} + run: echo "CGO_ENABLED=${{ inputs.cgo-enabled }}" >> "$GITHUB_ENV" + + - name: Set additional environment variables + if: ${{ inputs.additional-env-vars != '' }} + run: | + # Process additional environment variables + echo "${{ inputs.additional-env-vars }}" | while IFS= read -r line; do + if [[ -n "$line" && "$line" == *"="* ]]; then + echo "$line" >> "$GITHUB_ENV" + fi + done + + - name: Set up Docker Buildkit + uses: docker/setup-buildx-action@v3.11.1 + + - name: Cache Docker layers + uses: actions/cache@v4.2.3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Fill image meta + id: meta + uses: docker/metadata-action@v5.8.0 + with: + images: ${{ inputs.registry-name }} + tags: | + # branch event + type=ref,event=branch + # tag event + type=ref,event=tag + # pull request event + type=ref,event=pr + + - name: Auth to registry + uses: docker/login-action@v3.5.0 + with: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io + + - name: Build and push image + id: docker_build + uses: docker/build-push-action@v6.18.0 + with: + push: true + file: ${{ inputs.docker-file }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + # Unclear how https://docs.docker.com/build/ci/github-actions/attestations/ interacts with + # multi-stage builds and cache. A separate build and cache step is useful if we copy the + # same binary to multiple images, but a single invocation may still be able to handle that? + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + provenance: mode=max + sbom: true + target: ${{ inputs.docker-target }} + platforms: ${{ inputs.platforms }} + build-args: | + "TAG=${{ steps.meta.outputs.version }}" + "COMMIT=${{ github.sha }}" + "REPO_INFO=https://github.com/${{ github.repository }}.git" + "GOPATH=${{ env.GOPATH}}" + "GOCACHE=${{ env.GOCACHE}}" + "CGO_ENABLED=${{ env.CGO_ENABLED }}" + "CC=${{ env.CC }}" + - name: Attest + uses: actions/attest-build-provenance@v3 + id: attest + with: + subject-name: ${{ inputs.registry-name }} + subject-digest: ${{ steps.docker_build.outputs.digest }} + push-to-registry: true + + publish-release: + runs-on: ubuntu-latest + needs: build-push-images + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + permissions: + contents: write + steps: + - name: Parse semver string + id: semver_parser + uses: booxmedialtd/ws-action-parse-semver@v1.4.7 + with: + input_string: ${{ github.event.ref }} + version_extractor_regex: 'refs/tags/v(.*)$' + - uses: ncipollo/release-action@v1.18.0 + with: + # by default this will use the tag push tag as the tag and name + # if we want to trigger tagging from the workflow, "tag" and "commit" + # need to be set to create a new one + prerelease: ${{ steps.semver_parser.outputs.prerelease != '' }} + skipIfReleaseExists: true diff --git a/.github/workflows/go-build-release.yml b/.github/workflows/go-build-release.yml index 26635c5..df510d2 100644 --- a/.github/workflows/go-build-release.yml +++ b/.github/workflows/go-build-release.yml @@ -58,6 +58,16 @@ on: required: false type: string default: 'auto' + devel: + description: 'Create and upload a development build' + type: boolean + required: false + default: false + ref: + description: 'The commit hash for development builds' + required: false + type: string + default: '' permissions: write-all # Necessary for the generate-build-provenance action with containers @@ -86,17 +96,28 @@ jobs: with: fetch-tags: ${{ inputs.fetch-tags }} fetch-depth: ${{ inputs.fetch-depth }} + ref: ${{ inputs.ref }} - name: Set build environment variables run: | - echo "GIT_STATE=$(if git diff-index --quiet HEAD --; then echo 'clean'; else echo 'dirty'; fi)" >> $GITHUB_ENV - echo "BUILD_HOST=$(hostname)" >> $GITHUB_ENV - echo "GO_VERSION=$(go version | awk '{print $3}')" >> $GITHUB_ENV - echo "BUILD_USER=$(whoami)" >> $GITHUB_ENV + if git diff-index --quiet HEAD --; then + git_state='clean' + else + git_state='dirty' + fi + build_host=$(hostname) + go_version=$(go version | awk '{print $3}') + build_user=$(whoami) + { + echo "GIT_STATE=${git_state}" + echo "BUILD_HOST=${build_host}" + echo "GO_VERSION=${go_version}" + echo "BUILD_USER=${build_user}" + } >> "$GITHUB_ENV" - name: Set CGO_ENABLED if specified if: ${{ inputs.cgo-enabled != '' }} - run: echo "CGO_ENABLED=${{ inputs.cgo-enabled }}" >> $GITHUB_ENV + run: echo "CGO_ENABLED=${{ inputs.cgo-enabled }}" >> "$GITHUB_ENV" - name: Set additional environment variables if: ${{ inputs.additional-env-vars != '' }} @@ -104,7 +125,7 @@ jobs: # Process additional environment variables echo "${{ inputs.additional-env-vars }}" | while IFS= read -r line; do if [[ -n "$line" && "$line" == *"="* ]]; then - echo "$line" >> $GITHUB_ENV + echo "$line" >> "$GITHUB_ENV" fi done @@ -116,15 +137,16 @@ jobs: id: snapshot_flags run: | if [[ "${{ inputs.snapshot }}" == "true" ]]; then - echo "flags=--snapshot" >> $GITHUB_OUTPUT + echo "flags=--snapshot" >> "$GITHUB_OUTPUT" elif [[ "${{ inputs.snapshot }}" == "false" ]]; then - echo "flags=" >> $GITHUB_OUTPUT + echo "flags=" >> "$GITHUB_OUTPUT" else # auto mode - snapshot if not a tag - if [[ "${{ github.ref }}" != refs/tags/v* ]]; then - echo "flags=--snapshot" >> $GITHUB_OUTPUT + github_ref="${{ github.ref }}" + if [[ "$github_ref" != refs/tags/v* ]]; then + echo "flags=--snapshot" >> "$GITHUB_OUTPUT" else - echo "flags=" >> $GITHUB_OUTPUT + echo "flags=" >> "$GITHUB_OUTPUT" fi fi @@ -141,13 +163,16 @@ jobs: id: process_goreleaser_output if: ${{ !contains(steps.snapshot_flags.outputs.flags, '--snapshot') }} run: | - echo "const fs = require('fs');" > process.js - echo 'const artifacts = ${{ steps.goreleaser.outputs.artifacts }}' >> process.js - echo "const firstNonNullDigest = artifacts.find(artifact => artifact.extra && artifact.extra.Digest != null)?.extra.Digest;" >> process.js - echo "console.log(firstNonNullDigest);" >> process.js - echo "fs.writeFileSync('digest.txt', firstNonNullDigest);" >> process.js + { + echo "const fs = require('fs');" + echo 'const artifacts = ${{ steps.goreleaser.outputs.artifacts }}' + echo "const firstNonNullDigest = artifacts.find(artifact => artifact.extra && artifact.extra.Digest != null)?.extra.Digest;" + echo "console.log(firstNonNullDigest);" + echo "fs.writeFileSync('digest.txt', firstNonNullDigest);" + } > process.js node process.js - echo "digest=$(cat digest.txt)" >> $GITHUB_OUTPUT + digest=$(cat digest.txt) + echo "digest=${digest}" >> "$GITHUB_OUTPUT" - name: Attest Binaries uses: actions/attest-build-provenance@v1 @@ -161,3 +186,23 @@ jobs: subject-name: ${{ inputs.registry-name }} subject-digest: ${{ steps.process_goreleaser_output.outputs.digest }} push-to-registry: true + + # Credit to the https://github.com/goreleaser/goreleaser/issues/2828#issuecomment-1311662146 workaround + # for nightly/snapshot builds being locked behind the paid version of goreleaser. + - name: List snapshot images + # types are hard vov https://github.com/actions/runner/issues/2238 + if: true + run: | + short_sha=$(git rev-parse --short HEAD) + docker image ls --format "{{.Repository}}:{{.Tag}}" | \ + grep -e "$GITHUB_REPOSITORY:.*${short_sha}.*" | \ + paste -sd ' ' /dev/stdin > images + - name: Push snapshot images + if: true + run: | + xargs -d ' ' -I{} -n1 sh -c "docker push {}" < images + - name: Create and push manifest for :snapshot tag + if: true + run: | + docker manifest create "$GITHUB_REPOSITORY:snapshot" "$(cat images)" + docker manifest push "$GITHUB_REPOSITORY:snapshot" diff --git a/actions/gpg-ephemeral-key/action.yml b/actions/gpg-ephemeral-key/action.yml index 70b2027..0d6df0b 100644 --- a/actions/gpg-ephemeral-key/action.yml +++ b/actions/gpg-ephemeral-key/action.yml @@ -1,7 +1,7 @@ name: 'Generate and Sign Ephemeral GPG Key' author: 'OpenCHAMI' branding: - icon: 'key' + icon: 'lock' color: 'purple' description: 'Creates an ephemeral GPG key per build and signs it with a repo-scoped subkey'