name: CI on: pull_request: # The default types for pull_request are [opened, synchronize, reopened]. This is insufficient # for our needs, since we're skipping stuff on PRs in draft mode.By adding the ready_for_review # type, when a draft pr is marked ready, we run everything, including the stuff we'd have # skipped up until now. types: - opened - synchronize - reopened - ready_for_review push: branches: - main - release/** - ce/** workflow_dispatch: concurrency: group: ${{ github.head_ref || github.run_id }}-ci cancel-in-progress: true jobs: setup: runs-on: ${{ github.repository == 'hashicorp/vault' && 'ubuntu-latest' || fromJSON('["self-hosted","ubuntu-22.04-x64"]') }} permissions: actions: read contents: read id-token: write issues: read pull-requests: read outputs: changed-files: ${{ steps.changed-files.outputs.changed-files }} checkout-ref: ${{ steps.checkout.outputs.ref }} compute-build: ${{ steps.metadata.outputs.compute-build }} compute-small: ${{ steps.metadata.outputs.compute-small }} compute-test-go: ${{ steps.metadata.outputs.compute-test-go }} compute-test-ui: ${{ steps.metadata.outputs.compute-test-ui }} go-tags: ${{ steps.metadata.outputs.go-tags }} is-draft: ${{ steps.metadata.outputs.is-draft }} is-ent-branch: ${{ steps.metadata.outputs.is-ent-branch }} is-ent-repo: ${{ steps.metadata.outputs.is-ent-repo }} is-fork: ${{ steps.metadata.outputs.is-fork }} labels: ${{ steps.metadata.outputs.labels }} workflow-trigger: ${{ steps.metadata.outputs.workflow-trigger }} run-ui-tests: ${{ steps.ui-should-run.outputs.run-ui-tests }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # Make sure we check out correct ref based on PR labels and such - uses: ./.github/actions/checkout id: checkout - uses: ./.github/actions/metadata id: metadata # Get the elevated github token - if: steps.metadata.outputs.is-ent-repo == 'true' id: vault-auth name: Vault Authenticate run: vault-auth - if: steps.metadata.outputs.is-ent-repo == 'true' id: vault-secrets name: Fetch Vault Secrets uses: hashicorp/vault-action@892a26828f195e65540a40b4768ae4571f51ebfc # v4.0.0 with: url: ${{ steps.vault-auth.outputs.addr }} caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }} token: ${{ steps.vault-auth.outputs.token }} secrets: | kv/data/github/${{ github.repository }}/github-token token | ELEVATED_GITHUB_TOKEN; # Determine the changed files - uses: ./.github/actions/changed-files id: changed-files with: github-token: ${{ steps.metadata.outputs.is-ent-repo != 'true' && secrets.ELEVATED_GITHUB_TOKEN || steps.vault-secrets.outputs.ELEVATED_GITHUB_TOKEN }} - name: Ensure Go modules are cached uses: ./.github/actions/set-up-go with: github-token: ${{ steps.metadata.outputs.is-ent-repo != 'true' && secrets.ELEVATED_GITHUB_TOKEN || steps.vault-secrets.outputs.ELEVATED_GITHUB_TOKEN }} no-restore: true # don't download them on a cache hit # Make sure all required vault tools are cached at this point. We don't want all of the Go # tests and build jobs to build the tools and race to upload them to the cache. - uses: ./.github/actions/install-tools name: Ensure Vault tools are cached with: # Don't download them on a cache hit during setup, just make sure they're cached before # subsequent workflows are run. no-restore: true # Run the UI tests if our UI has changed, or a 'ui' label is present, or our workflow trigger # was triggered by a merge to main or releases/*. - id: ui-should-run name: Determine whether or not we should run UI tests run: | echo "run-ui-tests=${{ contains(fromJSON(steps.changed-files.outputs.changed-files).groups, 'ui') || steps.metadata.outputs.workflow-trigger == 'push' || contains(steps.metadata.outputs.labels, 'ui') }}" | tee -a "$GITHUB_OUTPUT" test-autopilot-upgrade: name: Run Autopilot upgrade tool # Run the Autopilot upgrade tests if: # - The Autopilot code has changed. # - We're in the context of the vault enterprise repository and enterprise branch. # - The workflow was triggered by a push to main or a PR targeting main. # # The reason for the main branch restriction, is that the logic for automatically determining the source versions # to test depends on the .release/versions.hcl file, which might not be up-to-date nor exist outside of main. # If you'd like to run the autopilot tests for a specific git checkout or set of source versions, # you can manually trigger the workflow, see the .github/workflows/run-apupgrade-tests-ent.yml file in the ENT repo. if: | contains(fromJSON(needs.setup.outputs.changed-files).groups, 'autopilot') && needs.setup.outputs.is-ent-branch == 'true' && (github.base_ref == 'main' || github.ref == 'refs/heads/main') needs: setup permissions: id-token: write contents: read runs-on: ${{ fromJSON(needs.setup.outputs.compute-small) }} steps: - name: Check out the .release/versions.hcl file from Vault Enterprise repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ needs.setup.outputs.checkout-ref }} sparse-checkout: | .release/versions.hcl .github - name: Get Vault versions to test id: get-versions env: GH_TOKEN: ${{ secrets.ELEVATED_GITHUB_TOKEN }} run: | # Change to the Vault Enterprise repository directory or exit if it fails cd "${GITHUB_WORKSPACE}" || exit 1 # Extract active major versions from the versions.hcl file, which is used for managing active release branches active_major_versions=$(grep -Eo 'version\s+"[0-9]+\.[0-9]+\.x"' .release/versions.hcl | sed -E 's/version\s+"([0-9]+\.[0-9]+)\.x"/\1/') active_major_versions=$(sort <<< "${active_major_versions}") # List releases from the GitHub repository, process them with sed, and sort them in reverse order releases=$(gh -R hashicorp/vault-enterprise release list --exclude-drafts --exclude-pre-releases --json=name --jq '.[].name' | \ sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+(\-rc[0-9]+)?)\+ent$/\1/' | \ sort -r) # Initialize a variable to collect matched versions matched_versions="" # Read each version from the active major versions and match it against the newest release available while IFS= read -r version; do match=$(grep -m 1 "^${version}" <<< "${releases}" || true) if [ -n "${match}" ]; then if [ -n "${matched_versions}" ]; then matched_versions+="," fi # Append the matched version to the variable, adding the +ent suffix, which is used for Vault Enterprise releases matched_versions+="${match}+ent" fi done <<< "${active_major_versions}" # Export the matched versions as a comma-separated string to an environment variable echo "VAULT_SOURCE_VERSIONS=${matched_versions}" >> "${GITHUB_ENV}" - name: Run Autopilot upgrade tests uses: ./.github/actions/run-apupgrade-tests env: GOPATH: /home/runner/go GOPRIVATE: github.com/hashicorp/* with: checkout-ref: ${{ needs.setup.outputs.checkout-ref }} github-token: ${{ secrets.ELEVATED_GITHUB_TOKEN }} source-versions: ${{ env.VAULT_SOURCE_VERSIONS }} test-go: # Run Go tests if the vault app changed if: | contains(fromJSON(needs.setup.outputs.changed-files).groups, 'app') || contains(fromJSON(needs.setup.outputs.changed-files).groups, 'gotoolchain') || contains(fromJSON(needs.setup.outputs.changed-files).groups, 'pipeline') name: Run Go tests needs: setup uses: ./.github/workflows/test-go.yml permissions: actions: read contents: read id-token: write issues: read pull-requests: write with: # The regular Go tests use an extra runner to execute the binary-dependent tests. We isolate # them there so that the other tests aren't slowed down waiting for a binary build. binary-tests: true checkout-ref: ${{ needs.setup.outputs.checkout-ref }} go-arch: amd64 go-tags: '${{ needs.setup.outputs.go-tags }},deadlock' name: standard runs-on: ${{ needs.setup.outputs.compute-test-go }} runs-on-small: ${{ needs.setup.outputs.compute-small }} test-timing-cache-key: go-test-timing-standard-${{ needs.setup.outputs.is-ent-branch && 'ent' || 'ce' }} total-runners: 16 secrets: inherit test-go-testonly: # Run Go tests tagged with "testonly" if the vault app changed if: | contains(fromJSON(needs.setup.outputs.changed-files).groups, 'app') || contains(fromJSON(needs.setup.outputs.changed-files).groups, 'gotoolchain') name: Run Go tests tagged with testonly needs: setup uses: ./.github/workflows/test-go.yml permissions: actions: read contents: read id-token: write issues: read pull-requests: write with: checkout-ref: ${{ needs.setup.outputs.checkout-ref }} go-arch: amd64 go-tags: '${{ needs.setup.outputs.go-tags }},deadlock,testonly' name: testonly runs-on: ${{ needs.setup.outputs.compute-test-go }} runs-on-small: ${{ needs.setup.outputs.compute-small }} testonly: true test-timing-cache-restore: false test-timing-cache-save: false total-runners: 2 # test runners cannot be less than 2 secrets: inherit test-go-race: # Run Go test with the data race detector enabled if the vault app changed and we're out of # drafts mode. if: | needs.setup.outputs.is-draft == 'false' && ( contains(fromJSON(needs.setup.outputs.changed-files).groups, 'app') || contains(fromJSON(needs.setup.outputs.changed-files).groups, 'gotoolchain') ) name: Run Go tests with data race detection needs: setup uses: ./.github/workflows/test-go.yml permissions: actions: read contents: read id-token: write issues: read pull-requests: write with: checkout-ref: ${{ needs.setup.outputs.checkout-ref }} env-vars: | { "VAULT_CI_GO_TEST_RACE": 1 } extra-flags: '-race' name: race go-arch: amd64 go-tags: ${{ needs.setup.outputs.go-tags }} runs-on: ${{ needs.setup.outputs.compute-test-go }} runs-on-small: ${{ needs.setup.outputs.compute-small }} test-timing-cache-key: go-test-timing-race-${{ needs.setup.outputs.is-ent-branch && 'ent' || 'ce' }} total-runners: 16 secrets: inherit test-go-fips: name: Run Go tests with FIPS configuration # Run the Go tests with fips if the vault app changed, we're in the context vault enterprise # and our trigger is a merge to main or releases/* or if the 'fips' label is present on a PR. if: | contains(fromJSON(needs.setup.outputs.changed-files).groups, 'app') && needs.setup.outputs.is-ent-branch == 'true' && ( needs.setup.outputs.workflow-trigger == 'push' || contains(needs.setup.outputs.labels, 'fips') ) needs: setup uses: ./.github/workflows/test-go.yml permissions: actions: read contents: read id-token: write issues: read pull-requests: write with: checkout-ref: ${{ needs.setup.outputs.checkout-ref }} env-vars: | { "GOEXPERIMENT": "boringcrypto" } name: fips go-arch: amd64 go-tags: '${{ needs.setup.outputs.go-tags }},deadlock,cgo,fips,fips_140_3' runs-on: ${{ needs.setup.outputs.compute-test-go }} runs-on-small: ${{ needs.setup.outputs.compute-small }} test-timing-cache-key: go-test-timing-fips total-runners: 16 secrets: inherit test-ui: name: Test UI needs: setup if: needs.setup.outputs.run-ui-tests == 'true' uses: ./.github/workflows/test-ui.yml permissions: actions: read contents: read id-token: write issues: read pull-requests: write with: checkout-ref: ${{ needs.setup.outputs.checkout-ref }} runs-on: ${{ needs.setup.outputs.compute-build }} runs-on-small: ${{ needs.setup.outputs.compute-test-ui }} is-ent-repo: ${{ needs.setup.outputs.is-ent-repo }} is-ent-branch: ${{ needs.setup.outputs.is-ent-branch }} secrets: inherit tests-completed: needs: - setup - test-autopilot-upgrade - test-go - test-go-testonly - test-go-race - test-go-fips - test-ui if: always() runs-on: ${{ github.repository == 'hashicorp/vault' && 'ubuntu-latest' || fromJSON('["self-hosted","ubuntu-22.04-x64"]') }} permissions: actions: read contents: read id-token: write pull-requests: write steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # Determine the overall status of our required test jobs. - name: Determine status id: status run: | # Determine the overall status of the job. We allow fips and race tests to fail so we # don't consider their result here. # # Encode the needs context into JSON, filter out unrequired workflows, shape the result # into a more useful schema. Determine the overall status by comparing the total number of # successful results with the number of required jobs. if results=$(jq -rec 'del(.["test-go-fips"], .["test-go-race"]) as $required | $required | keys as $jobs | reduce $jobs[] as $job ([]; . + [{job: $job}+$required[$job]])' <<< '${{ toJSON(needs) }}' ); then # Determine if all of our required jobs have succeeded. if jq -rec 'length as $expected | [.[] | select((.result == "success") or (.result == "skipped"))] | length as $got | $expected == $got' <<< "$results"; then msg="All required test jobs succeeded!" result="success" else msg="One or more required test jobs failed!" result="failed" fi else msg="Failed to decode and filter test results" result="failed" results="''" fi { echo "msg=${msg}" echo "result=${result}" echo "results<> "$GITHUB_OUTPUT" - if: | always() && needs.setup.outputs.workflow-trigger == 'push' && ( needs.setup.result == 'failure' || needs.test-autopilot-upgrade.result == 'failure' || needs.test-go.result == 'failure' || needs.test-go-race.result == 'failure' || needs.test-go-race.outputs.data-race-result == 'failure' || needs.test-go-testonly.result == 'failure' || needs.test-ui.result == 'failure' ) name: Notify build failures in Slack uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3 with: errors: true # exit with an error if the payload is invalid retries: rapid # retry if we're being rated limited webhook: ${{ steps.slackbot-webhook-url.outputs.slackbot-webhook-url }} webhook-type: incoming-webhook payload: | text: ${{ needs.setup.outputs.is-ent-branch == 'true' && 'vault-enterprise' || 'vault' }} test failures on ${{ github.ref_name }} blocks: - type: header text: type: plain_text text: ':flashing-light: ${{ needs.setup.outputs.is-ent-branch == 'true' && 'vault-enterprise' || 'vault' }} test failures on ${{ github.ref_name }} :flashing-light:' emoji: true - type: divider - type: section text: type: mrkdwn text: | ${{ needs.setup.result == 'failure' && ':x: Setup' || '' }} ${{ needs.test-autopilot-upgrade.result == 'failure' && ':x: Autopilot upgrade' || '' }} ${{ needs.test-go.result == 'failure' && ':x: Go tests' || '' }} ${{ needs.test-go-testonly.result == 'failure' && ':x: Go testonly tests' || '' }} ${{ needs.test-go-fips.result == 'failure' && ':x: Go FIPS tests' || '' }} ${{ needs.test-ui.result == 'failure' && ':x: UI tests' || '' }} ${{ needs.test-go-race.result != 'skipped' && ( ((needs.test-go-race.outputs.data-race-result != '' && needs.test-go-race.outputs.data-race-result != 'success') && ':x: Go race tests (Data race(s) detected)') || (needs.test-go-race.result == 'failure' && ':x: Go race tests' || '') ) || '' }} accessory: type: button text: type: plain_text text: View Failing Workflow emoji: true url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} # Only create the PR summary if it's a pull request and it is not a fork as we need access # to secrets. - if: ${{ needs.setup.outputs.is-fork == 'false' }} id: download-summaries name: Download failure summaries uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: failure-summary-*.md path: failure-summaries merge-multiple: true # Don't allow failure summary aggregation to fail this workflow continue-on-error: true - if: needs.setup.outputs.is-fork == 'false' && steps.download-summaries.outcome == 'success' id: prepare-failure-summary name: Prepare failure summary run: | # Sort all of the summary table rows and push them to a temp file. temp_file_name=temp-$(date +%s) cat failure-summaries/*.md | sort >> "$temp_file_name" # If there are test failures, present them in a format of a GitHub Markdown table. if [ -s "$temp_file_name" ]; then # Here we create the headings for the summary table { echo "| Test Type | Package | Test | Elapsed | Runner Index | Logs |" echo "| --------- | ------- | ---- | ------- | ------------ | ---- |" cat "$temp_file_name" } | tee -a "$GITHUB_STEP_SUMMARY" else if [ "${{ steps.status.outputs.result }}" == 'success' ]; then echo "### All required Go tests passed! :white_check_mark:" | tee -a "$GITHUB_STEP_SUMMARY" fi fi { echo 'table-test-results<