fix(attest): don't preserve file ownership when packaging attachments… #357
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| jobs: | |
| notify-start: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 | |
| with: | |
| egress-policy: audit | |
| - uses: kosli-dev/reusable-actions/slack-release-notify@main | |
| with: | |
| slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }} | |
| slack-channel-id: ${{ vars.SLACK_CHANNEL_ID }} | |
| stage: start | |
| pre-build: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag: ${{ steps.tag.outputs.tag }} | |
| trail_name: ${{ steps.prep.outputs.trail_name }} | |
| trail_template_file: ${{ steps.prep.outputs.trail_template_file }} | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 | |
| with: | |
| egress-policy: audit | |
| - uses: actions/checkout@v7 | |
| - name: Get tag | |
| id: tag | |
| uses: dawidd6/action-get-tag@v1 | |
| - name: Verify annotated tag | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG_TYPE=$(gh api repos/${{ github.repository }}/git/refs/tags/${{ steps.tag.outputs.tag }} --jq '.object.type') | |
| if [ "$TAG_TYPE" != "tag" ]; then | |
| echo "::error::Tag ${{ steps.tag.outputs.tag }} is lightweight, not annotated. Use 'make release' to cut releases." | |
| exit 1 | |
| fi | |
| - name: Prepare | |
| id: prep | |
| run: | | |
| echo "TRAIL_NAME=${{ steps.tag.outputs.tag }}" >> $GITHUB_STATE | |
| echo "trail_name=${{ steps.tag.outputs.tag }}" >> $GITHUB_OUTPUT | |
| echo "TRAIL_TEMPLATE_FILE=release-flow-template.yml" >> $GITHUB_STATE | |
| echo "trail_template_file=release-flow-template.yml" >> $GITHUB_OUTPUT | |
| init-kosli: | |
| needs: [pre-build] | |
| uses: ./.github/workflows/init_kosli.yml | |
| with: | |
| FLOW_NAME: cli-release | |
| TRAIL_NAME: ${{ needs.pre-build.outputs.trail_name }} | |
| FLOW_TEMPLATE_FILE: ${{ needs.pre-build.outputs.trail_template_file }} | |
| KOSLI_ORG: kosli-public | |
| report_to_kosli: release | |
| secrets: | |
| kosli_api_token: ${{ secrets.KOSLI_PUBLIC_API_TOKEN }} | |
| pr_github_token: ${{ secrets.GITHUB_TOKEN }} | |
| never-alone-trail: | |
| needs: [pre-build, init-kosli] | |
| uses: ./.github/workflows/never_alone_trail.yml | |
| with: | |
| FLOW_NAME: cli-release-never-alone | |
| TRAIL_NAME: ${{ needs.pre-build.outputs.trail_name }} | |
| SOURCE_FLOW_NAME: cli | |
| ATTESTATION_NAME: never-alone-data | |
| PARENT_FLOW_NAME: cli-release | |
| PARENT_TRAIL_NAME: ${{ needs.pre-build.outputs.trail_name }} | |
| KOSLI_ORG: kosli-public | |
| secrets: | |
| kosli_api_token: ${{ secrets.KOSLI_PUBLIC_API_TOKEN }} | |
| pr_github_token: ${{ secrets.GITHUB_TOKEN }} | |
| test: | |
| needs: [pre-build, init-kosli] | |
| uses: ./.github/workflows/test.yml | |
| with: | |
| AWS_ACCOUNT_ID: 772819027869 | |
| AWS_REGION: eu-central-1 | |
| FLOW_NAME: cli-release | |
| TRAIL_NAME: ${{ needs.pre-build.outputs.trail_name }} | |
| KOSLI_ORG: kosli-public | |
| report_to_kosli: release | |
| secrets: | |
| github_access_token: ${{ secrets.KOSLI_GITHUB_TOKEN }} | |
| gitlab_access_token: ${{ secrets.KOSLI_GITLAB_TOKEN }} | |
| azure_access_token: ${{ secrets.KOSLI_AZURE_TOKEN }} | |
| azure_client_id: ${{ secrets.AZURE_CLIENT_ID }} | |
| azure_client_secret: ${{ secrets.AZURE_CLIENT_SECRET }} | |
| bitbucket_access_token: ${{ secrets.KOSLI_BITBUCKET_ACCESS_TOKEN }} | |
| slack_webhook: ${{ secrets.MERKELY_SLACK_CI_FAILURES_WEBHOOK }} | |
| slack_channel: ci-failures | |
| jira_api_token: ${{ secrets.KOSLI_JIRA_API_TOKEN }} | |
| snyk_token: ${{ secrets.SNYK_TOKEN }} | |
| kosli_reporting_api_token: ${{ secrets.KOSLI_PUBLIC_API_TOKEN }} | |
| kosli_querying_api_token: ${{ secrets.KOSLI_API_TOKEN_PROD }} | |
| sonarqube_token: ${{ secrets.KOSLI_SONARQUBE_TOKEN }} | |
| docker: | |
| needs: [pre-build, init-kosli, test] | |
| uses: ./.github/workflows/docker.yml | |
| with: | |
| tag: ${{ needs.pre-build.outputs.tag }} | |
| platforms: linux/amd64,linux/arm64 | |
| flow_name: cli-release | |
| trail_name: ${{ needs.pre-build.outputs.trail_name }} | |
| kosli_org: kosli-public | |
| report_to_kosli: release | |
| secrets: | |
| slack_webhook: ${{ secrets.MERKELY_SLACK_CI_FAILURES_WEBHOOK }} | |
| slack_channel: ci-failures | |
| kosli_api_token: ${{ secrets.KOSLI_PUBLIC_API_TOKEN }} | |
| snyk_token: ${{ secrets.SNYK_TOKEN }} | |
| goreleaser: | |
| needs: [test] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| id-token: write | |
| attestations: write | |
| outputs: | |
| artifacts: ${{ steps.prepare-artifacts-list.outputs.artifacts }} | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install Jq | |
| uses: dcarbone/install-jq-action@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: '.go-version' | |
| check-latest: true | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '24' | |
| registry-url: 'https://registry.npmjs.org' | |
| # Use release notes from the tag body when present (set by interactive `make release` or `make release tag=vX.Y.Z` with dist/release_notes.md). Otherwise GoReleaser uses its default changelog. | |
| # Write to repo root so GoReleaser's --clean (which removes dist/) does not delete the file before it is read. | |
| - name: Get release notes from tag | |
| id: get-tag-notes | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| # %(contents), not %(contents:body): the latter drops the tag message's | |
| # first paragraph as a "subject", silently swallowing the first heading | |
| # or bullet of the release notes. Unlike %(contents:body), %(contents) | |
| # keeps the signature of a signed tag, so cut it off at its marker. | |
| BODY=$(git tag -l --format='%(contents)' "$TAG" \ | |
| | sed '/^-----BEGIN [A-Z ]*SIGNATURE-----$/,$d') | |
| # `make release tag=vX.Y.Z` with no dist/release_notes.md tags with the | |
| # version as the whole message; that is not release notes. | |
| if [ "$(printf '%s' "$BODY" | tr -d '[:space:]')" = "$TAG" ]; then | |
| BODY="" | |
| fi | |
| if [ -n "$BODY" ]; then | |
| printf '%s' "$BODY" > release_notes.md | |
| echo "args=--release-notes=release_notes.md" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Run GoReleaser | |
| uses: goreleaser/goreleaser-action@v7 | |
| with: | |
| distribution: goreleaser-pro | |
| version: '~> v2' # latest | |
| args: release --clean ${{ steps.get-tag-notes.outputs.args }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| FURY_TOKEN: ${{ secrets.FURY_TOKEN }} | |
| GORELEASER_KEY: ${{ secrets.KOSLI_GORELEASERPRO }} | |
| - name: Copy npm packages into dist for provenance | |
| run: find npm -name "*.tgz" -exec cp {} dist/ \; | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: dist | |
| path: dist | |
| retention-days: 1 | |
| - name: Prepare artifacts list | |
| id: prepare-artifacts-list | |
| run: | | |
| GORELEASER_ARTIFACTS=$(jq '[reduce .[] as $item ( | |
| []; | |
| if ($item.type == "Archive") then | |
| . + [{ template_name: ($item.goos + "-" + $item.goarch), path: $item.path }] | |
| elif ($item.type == "Linux Package") then | |
| . + [{ template_name: (($item.extra.Ext | ltrimstr(".")) + "-pkg-" + $item.goarch), path: $item.path }] | |
| else | |
| . | |
| end | |
| )][]' dist/artifacts.json) | |
| NPM_ARTIFACTS=$(find dist -maxdepth 1 -name "*.tgz" -printf '%f\n' \ | |
| | jq -R '{ | |
| template_name: ("npm-" + sub("-[0-9]+\\.[0-9]+\\.[0-9]+.*\\.tgz$"; "")), | |
| path: ("dist/" + .) | |
| }' \ | |
| | jq -s '.') | |
| ARTIFACTS=$(jq -n \ | |
| --argjson g "$GORELEASER_ARTIFACTS" \ | |
| --argjson n "$NPM_ARTIFACTS" \ | |
| '$g + $n') | |
| echo "artifacts<<nEOFn" >> $GITHUB_OUTPUT | |
| echo "${ARTIFACTS}" >> $GITHUB_OUTPUT | |
| echo "nEOFn" >> $GITHUB_OUTPUT | |
| binary-provenance: | |
| needs: [goreleaser, pre-build] | |
| name: Artifacts Binary Provenance | |
| uses: ./.github/workflows/binary_provenance.yml | |
| with: | |
| dir: dist | |
| artifacts: ${{ needs.goreleaser.outputs.artifacts }} | |
| flow_name: cli-release | |
| trail_name: ${{ needs.pre-build.outputs.trail_name }} | |
| kosli_org: kosli-public | |
| secrets: | |
| kosli_api_token: ${{ secrets.KOSLI_PUBLIC_API_TOKEN }} | |
| docs-repo-dispatch: | |
| needs: [pre-build, goreleaser] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 | |
| with: | |
| egress-policy: audit | |
| - name: Repository Dispatch | |
| uses: peter-evans/repository-dispatch@v4 | |
| with: | |
| token: ${{ secrets.DOCS_REPO_ACCESS_TOKEN }} | |
| repository: kosli-dev/docs | |
| event-type: cli-release | |
| client-payload: '{"kosli_cli_tag": "${{ needs.pre-build.outputs.tag }}"}' | |
| evidence-reporter-upload-package-and-deploy: | |
| needs: [pre-build, goreleaser, environment-reporter-upload-layer] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 | |
| with: | |
| egress-policy: audit | |
| - name: Repository Dispatch | |
| uses: peter-evans/repository-dispatch@v4 | |
| with: | |
| token: ${{ secrets.KOSLI_REPORTER_REPO_ACCESS_TOKEN }} | |
| repository: kosli-dev/terraform-aws-evidence-reporter | |
| event-type: upload-package | |
| client-payload: '{"kosli_cli_tag": "${{ needs.pre-build.outputs.tag }}"}' | |
| environment-reporter-upload-package-and-deploy: | |
| needs: [pre-build, goreleaser, environment-reporter-upload-layer] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 | |
| with: | |
| egress-policy: audit | |
| - name: Repository Dispatch | |
| uses: peter-evans/repository-dispatch@v4 | |
| with: | |
| token: ${{ secrets.KOSLI_REPORTER_REPO_ACCESS_TOKEN }} | |
| repository: kosli-dev/terraform-aws-kosli-reporter | |
| event-type: upload-package | |
| client-payload: '{"kosli_cli_tag": "${{ needs.pre-build.outputs.tag }}"}' | |
| environment-reporter-upload-layer: | |
| needs: [pre-build, goreleaser] | |
| uses: ./.github/workflows/upload-cli-layer.yml | |
| with: | |
| tag: ${{ needs.pre-build.outputs.tag }} | |
| AWS_ACCOUNT_ID: 585008075785 | |
| AWS_REGION: eu-central-1 | |
| notify-finish: | |
| needs: | |
| [ | |
| notify-start, | |
| pre-build, | |
| init-kosli, | |
| never-alone-trail, | |
| test, | |
| docker, | |
| goreleaser, | |
| binary-provenance, | |
| docs-repo-dispatch, | |
| evidence-reporter-upload-package-and-deploy, | |
| environment-reporter-upload-package-and-deploy, | |
| environment-reporter-upload-layer | |
| ] | |
| if: always() && needs.notify-start.result == 'success' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read # ← needed to fetch run_started_at for duration | |
| contents: read # ← needed to read release notes via `gh release view` | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 | |
| with: | |
| egress-policy: audit | |
| - name: Determine status | |
| id: status | |
| run: | | |
| if [[ "${{ !contains(join(needs.*.result, ','), 'failure') && !contains(join(needs.*.result, ','), 'cancelled') }}" == "true" ]]; then | |
| echo "value=success" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "value=failure" >> "$GITHUB_OUTPUT" | |
| fi | |
| - uses: kosli-dev/reusable-actions/slack-release-notify@main | |
| with: | |
| slack-bot-token: ${{ secrets.SLACK_BOT_TOKEN }} | |
| slack-channel-id: ${{ vars.SLACK_CHANNEL_ID }} | |
| stage: finish | |
| status: ${{ steps.status.outputs.value }} |