445 lines
19 KiB
YAML
445 lines
19 KiB
YAML
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/**
|
|
workflow_dispatch:
|
|
concurrency:
|
|
group: ${{ github.head_ref || github.run_id }}-ci
|
|
cancel-in-progress: true
|
|
jobs:
|
|
setup:
|
|
name: Setup
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
compute-tiny: ${{ steps.setup-outputs.outputs.compute-tiny }}
|
|
compute-standard: ${{ steps.setup-outputs.outputs.compute-standard }}
|
|
compute-larger: ${{ steps.setup-outputs.outputs.compute-larger }}
|
|
compute-huge: ${{ steps.setup-outputs.outputs.compute-huge }}
|
|
enterprise: ${{ steps.setup-outputs.outputs.enterprise }}
|
|
go-build-tags: ${{ steps.setup-outputs.outputs.go-build-tags }}
|
|
steps:
|
|
- id: setup-outputs
|
|
name: Setup outputs
|
|
run: |
|
|
github_repository="${{ github.repository }}"
|
|
|
|
if [ "${github_repository##*/}" == "vault-enterprise" ] ; then
|
|
# shellcheck disable=SC2129
|
|
echo 'compute-tiny=["self-hosted","ondemand","linux","type=m5.large"]' >> "$GITHUB_OUTPUT"
|
|
echo 'compute-standard=["self-hosted","ondemand","linux","type=m5.xlarge"]' >> "$GITHUB_OUTPUT"
|
|
echo 'compute-larger=["self-hosted","ondemand","linux","type=m5.2xlarge"]' >> "$GITHUB_OUTPUT"
|
|
echo 'compute-huge=["self-hosted","ondemand","linux","type=m5.4xlarge"]' >> "$GITHUB_OUTPUT"
|
|
echo 'enterprise=1' >> "$GITHUB_OUTPUT"
|
|
echo 'go-build-tags=ent,enterprise' >> "$GITHUB_OUTPUT"
|
|
else
|
|
# shellcheck disable=SC2129
|
|
echo 'compute-tiny="ubuntu-latest"' >> "$GITHUB_OUTPUT" # 2 cores, 7 GB RAM, 14 GB SSD
|
|
echo 'compute-standard="custom-linux-small-vault-latest"' >> "$GITHUB_OUTPUT" # 8 cores, 32 GB RAM, 300 GB SSD
|
|
echo 'compute-larger="custom-linux-medium-vault-latest"' >> "$GITHUB_OUTPUT" # 16 cores, 64 GB RAM, 600 GB SSD
|
|
echo 'compute-huge="custom-linux-xl-vault-latest"' >> "$GITHUB_OUTPUT" # 32-cores, 128 GB RAM, 1200 GB SSD
|
|
echo 'enterprise=' >> "$GITHUB_OUTPUT"
|
|
echo 'go-build-tags=' >> "$GITHUB_OUTPUT"
|
|
fi
|
|
semgrep:
|
|
name: Semgrep
|
|
needs:
|
|
- setup
|
|
runs-on: ${{ fromJSON(needs.setup.outputs.compute-tiny) }}
|
|
container:
|
|
image: returntocorp/semgrep@sha256:ffc6f3567654f9431456d49fd059dfe548f007c494a7eb6cd5a1a3e50d813fb3
|
|
steps:
|
|
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
|
- name: Run Semgrep Rules
|
|
id: semgrep
|
|
run: semgrep ci --include '*.go' --config 'tools/semgrep/ci'
|
|
setup-go-cache:
|
|
name: Go Caches
|
|
needs:
|
|
- setup
|
|
uses: ./.github/workflows/setup-go-cache.yml
|
|
with:
|
|
runs-on: ${{ needs.setup.outputs.compute-standard }}
|
|
secrets: inherit
|
|
fmt:
|
|
name: Check Format
|
|
needs:
|
|
- setup
|
|
runs-on: ${{ fromJSON(needs.setup.outputs.compute-tiny) }}
|
|
steps:
|
|
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
|
- uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
|
with:
|
|
go-version-file: ./.go-version
|
|
cache: true
|
|
- id: format
|
|
run: |
|
|
echo "Using gofumpt version $(go run mvdan.cc/gofumpt -version)"
|
|
make fmt
|
|
if ! git diff --exit-code; then
|
|
echo "Code has formatting errors. Run 'make fmt' to fix"
|
|
exit 1
|
|
fi
|
|
diff-oss-ci:
|
|
name: Diff OSS
|
|
needs:
|
|
- setup
|
|
if: ${{ needs.setup.outputs.enterprise != '' && github.base_ref != '' }}
|
|
runs-on: ${{ fromJSON(needs.setup.outputs.compute-tiny) }}
|
|
steps:
|
|
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
|
with:
|
|
fetch-depth: 0
|
|
- id: determine-branch
|
|
run: |
|
|
branch="${{ github.base_ref }}"
|
|
|
|
if [[ $branch = release/* ]] ; then
|
|
branch=${branch%%+ent}
|
|
|
|
# Add OSS remote
|
|
git config --global user.email "github-team-secret-vault-core@hashicorp.com"
|
|
git config --global user.name "hc-github-team-secret-vault-core"
|
|
git remote add oss https://github.com/hashicorp/vault.git
|
|
git fetch oss "$branch"
|
|
|
|
branch="oss/$branch"
|
|
else
|
|
branch="origin/$branch"
|
|
fi
|
|
|
|
echo "BRANCH=$branch" >> "$GITHUB_OUTPUT"
|
|
- id: diff
|
|
run: |
|
|
./.github/scripts/oss-diff.sh ${{ steps.determine-branch.outputs.BRANCH }} HEAD
|
|
test-go:
|
|
name: Run Go tests
|
|
needs:
|
|
- setup
|
|
- setup-go-cache
|
|
# Don't run this job for PR branches starting with:
|
|
# 'ui/', 'backport/ui/', 'docs/', or 'backport/docs/'
|
|
# OR
|
|
# the 'docs' label is present
|
|
if: |
|
|
!startsWith(github.head_ref, 'ui/') &&
|
|
!startsWith(github.head_ref, 'backport/ui/') &&
|
|
!startsWith(github.head_ref, 'docs/') &&
|
|
!startsWith(github.head_ref, 'backport/docs/') &&
|
|
!contains(github.event.pull_request.labels.*.name, 'docs')
|
|
uses: ./.github/workflows/test-go.yml
|
|
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.
|
|
total-runners: 17
|
|
go-arch: amd64
|
|
go-build-tags: '${{ needs.setup.outputs.go-build-tags }},deadlock'
|
|
runs-on: ${{ needs.setup.outputs.compute-larger }}
|
|
enterprise: ${{ needs.setup.outputs.enterprise }}
|
|
secrets: inherit
|
|
test-go-race:
|
|
name: Run Go tests with data race detection
|
|
needs:
|
|
- setup
|
|
- setup-go-cache
|
|
# Don't run this job for PR branches starting with:
|
|
# 'ui/', 'backport/ui/', 'docs/', or 'backport/docs/'
|
|
# OR
|
|
# the 'docs' label is present
|
|
if: |
|
|
github.event.pull_request.draft == false &&
|
|
!startsWith(github.head_ref, 'ui/') &&
|
|
!startsWith(github.head_ref, 'backport/ui/') &&
|
|
!startsWith(github.head_ref, 'docs/') &&
|
|
!startsWith(github.head_ref, 'backport/docs/') &&
|
|
!contains(github.event.pull_request.labels.*.name, 'docs')
|
|
uses: ./.github/workflows/test-go.yml
|
|
with:
|
|
total-runners: 16
|
|
env-vars: |
|
|
{
|
|
"VAULT_CI_GO_TEST_RACE": 1
|
|
}
|
|
extra-flags: '-race'
|
|
go-arch: amd64
|
|
go-build-tags: ${{ needs.setup.outputs.go-build-tags }}
|
|
runs-on: ${{ needs.setup.outputs.compute-huge }}
|
|
enterprise: ${{ needs.setup.outputs.enterprise }}
|
|
name: "-race"
|
|
secrets: inherit
|
|
test-go-fips:
|
|
name: Run Go tests with FIPS configuration
|
|
# Only run this job for the enterprise repo if the PR branch doesn't start with:
|
|
# 'ui/', 'backport/ui/', 'docs/', or 'backport/docs/'
|
|
# OR
|
|
# the 'docs' label is not present
|
|
if: |
|
|
github.event.pull_request.draft == false &&
|
|
needs.setup.outputs.enterprise == 1 &&
|
|
!startsWith(github.head_ref, 'ui/') &&
|
|
!startsWith(github.head_ref, 'backport/ui/') &&
|
|
!startsWith(github.head_ref, 'docs/') &&
|
|
!startsWith(github.head_ref, 'backport/docs/') &&
|
|
!contains(github.event.pull_request.labels.*.name, 'docs')
|
|
needs:
|
|
- setup
|
|
- setup-go-cache
|
|
uses: ./.github/workflows/test-go.yml
|
|
with:
|
|
total-runners: 16
|
|
env-vars: |
|
|
{
|
|
"GOEXPERIMENT": "boringcrypto"
|
|
}
|
|
go-arch: amd64
|
|
go-build-tags: '${{ needs.setup.outputs.go-build-tags }},deadlock,cgo,fips,fips_140_2'
|
|
runs-on: ${{ needs.setup.outputs.compute-larger }}
|
|
enterprise: ${{ needs.setup.outputs.enterprise }}
|
|
name: "-fips"
|
|
secrets: inherit
|
|
test-ui:
|
|
name: Test UI
|
|
# The test-ui job is only run on:
|
|
# - pushes to main and branches starting with "release/"
|
|
# - PRs where the branch starts with "ui/", "backport/ui/", "merge", or when base branch starts with "release/"
|
|
# - PRs with the "ui" label on github
|
|
if: |
|
|
github.ref_name == 'main' ||
|
|
startsWith(github.ref_name, 'release/') ||
|
|
startsWith(github.head_ref, 'ui/') ||
|
|
startsWith(github.head_ref, 'backport/ui/') ||
|
|
startsWith(github.head_ref, 'merge') ||
|
|
contains(github.event.pull_request.labels.*.name, 'ui')
|
|
needs:
|
|
- setup
|
|
permissions:
|
|
id-token: write
|
|
contents: read
|
|
runs-on: ${{ fromJSON(needs.setup.outputs.compute-larger) }}
|
|
steps:
|
|
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
|
- uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # v4.0.1
|
|
with:
|
|
go-version-file: ./.go-version
|
|
cache: true
|
|
# Setup node.js without caching to allow running npm install -g yarn (next step)
|
|
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
|
with:
|
|
node-version-file: './ui/package.json'
|
|
- id: install-yarn
|
|
run: |
|
|
npm install -g yarn
|
|
# Setup node.js with caching using the yarn.lock file
|
|
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
|
with:
|
|
node-version-file: './ui/package.json'
|
|
cache: yarn
|
|
cache-dependency-path: ui/yarn.lock
|
|
- id: install-browser
|
|
uses: browser-actions/setup-chrome@c485fa3bab6be59dce18dbc18ef6ab7cbc8ff5f1 # v1.2.0
|
|
- id: ui-dependencies
|
|
name: ui-dependencies
|
|
working-directory: ./ui
|
|
run: |
|
|
yarn install --frozen-lockfile
|
|
npm rebuild node-sass
|
|
- id: vault-auth
|
|
name: Authenticate to Vault
|
|
if: github.repository == 'hashicorp/vault-enterprise'
|
|
run: vault-auth
|
|
- id: secrets
|
|
name: Fetch secrets
|
|
if: github.repository == 'hashicorp/vault-enterprise'
|
|
uses: hashicorp/vault-action@130d1f5f4fe645bb6c83e4225c04d64cfb62de6e
|
|
with:
|
|
url: ${{ steps.vault-auth.outputs.addr }}
|
|
caCertificate: ${{ steps.vault-auth.outputs.ca_certificate }}
|
|
token: ${{ steps.vault-auth.outputs.token }}
|
|
secrets: |
|
|
kv/data/github/hashicorp/vault-enterprise/github-token token | PRIVATE_REPO_GITHUB_TOKEN;
|
|
kv/data/github/hashicorp/vault-enterprise/license license_1 | VAULT_LICENSE;
|
|
- id: setup-git
|
|
name: Setup Git
|
|
if: github.repository == 'hashicorp/vault-enterprise'
|
|
run: |
|
|
git config --global url."https://${{ steps.secrets.outputs.PRIVATE_REPO_GITHUB_TOKEN }}@github.com".insteadOf https://github.com
|
|
- id: build-go-dev
|
|
name: build-go-dev
|
|
run: |
|
|
rm -rf ./pkg
|
|
mkdir ./pkg
|
|
|
|
make ci-bootstrap dev
|
|
- id: test-ui
|
|
name: test-ui
|
|
env:
|
|
VAULT_LICENSE: ${{ steps.secrets.outputs.VAULT_LICENSE }}
|
|
run: |
|
|
export PATH="${PWD}/bin:${PATH}"
|
|
|
|
if [ "${{ github.repository }}" == 'hashicorp/vault' ] ; then
|
|
export VAULT_LICENSE="${{ secrets.VAULT_LICENSE }}"
|
|
fi
|
|
|
|
# Run Ember tests
|
|
cd ui
|
|
mkdir -p test-results/qunit
|
|
yarn test:oss
|
|
- uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
|
with:
|
|
name: test-results-ui
|
|
path: ui/test-results
|
|
if: success() || failure()
|
|
- uses: test-summary/action@62bc5c68de2a6a0d02039763b8c754569df99e3f # TSCCR: no entry for repository "test-summary/action"
|
|
with:
|
|
paths: "ui/test-results/qunit/results.xml"
|
|
show: "fail"
|
|
if: always()
|
|
tests-completed:
|
|
needs:
|
|
- setup
|
|
- setup-go-cache
|
|
- test-go
|
|
- test-ui
|
|
# We force a failure if any of the dependent jobs fail,
|
|
# this is a workaround for the issue reported https://github.com/actions/runner/issues/2566
|
|
if: |
|
|
always() && (cancelled() ||
|
|
contains(needs.*.result, 'cancelled') ||
|
|
contains(needs.*.result, 'failure'))
|
|
runs-on: ${{ fromJSON(needs.setup.outputs.compute-tiny) }}
|
|
steps:
|
|
- run: |
|
|
tr -d '\n' <<< '${{ toJSON(needs.*.result) }}' | grep -q -v -E '(failure|cancelled)'
|
|
notify-tests-completed-failures-oss:
|
|
if: ${{ always() && github.repository == 'hashicorp/vault' && needs.tests-completed.result == 'failure' && (github.ref_name == 'main' || startsWith(github.ref_name, 'release/')) }}
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
id-token: write
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
needs:
|
|
- tests-completed
|
|
steps:
|
|
- name: send-notification
|
|
uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0
|
|
# We intentionally aren't using the following here since it's from an internal repo
|
|
# uses: hashicorp/cloud-gha-slack-notifier@730a033037b8e603adf99ebd3085f0fdfe75e2f4 #v1
|
|
env:
|
|
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
|
with:
|
|
channel-id: "C05AABYEA9Y" # sent to #feed-vault-ci-official
|
|
payload: |
|
|
{"text":"OSS test failures on ${{ github.ref_name }}","blocks":[{"type":"header","text":{"type":"plain_text","text":":rotating_light: OSS test failures :rotating_light:","emoji":true}},{"type":"divider"},{"type":"section","text":{"type":"mrkdwn","text":"test(s) failed on ${{ github.ref_name }}"},"accessory":{"type":"button","text":{"type":"plain_text","text":"View Failing Workflow","emoji":true},"url":"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}}]}
|
|
|
|
notify-tests-completed-failures-ent:
|
|
if: ${{ always() && github.repository == 'hashicorp/vault-enterprise' && needs.tests-completed.result == 'failure' && (github.ref_name == 'main' || startsWith(github.ref_name, 'release/')) }}
|
|
runs-on: ['self-hosted', 'linux', 'small']
|
|
permissions:
|
|
id-token: write
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
needs:
|
|
- tests-completed
|
|
steps:
|
|
- id: vault-auth
|
|
name: Vault Authenticate
|
|
run: vault-auth
|
|
- id: secrets
|
|
name: Fetch Vault Secrets
|
|
uses: hashicorp/vault-action@130d1f5f4fe645bb6c83e4225c04d64cfb62de6e
|
|
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_actions_notifications_bot token | SLACK_BOT_TOKEN;
|
|
- name: send-notification
|
|
uses: hashicorp/cloud-gha-slack-notifier@730a033037b8e603adf99ebd3085f0fdfe75e2f4 #v1
|
|
with:
|
|
channel-id: "C05AABYEA9Y" # sent to #feed-vault-ci-official
|
|
slack-bot-token: ${{ steps.secrets.outputs.SLACK_BOT_TOKEN }}
|
|
payload: |
|
|
{"text":"Enterprise test failures on ${{ github.ref_name }}","blocks":[{"type":"header","text":{"type":"plain_text","text":":rotating_light: Enterprise test failures :rotating_light:","emoji":true}},{"type":"divider"},{"type":"section","text":{"type":"mrkdwn","text":"test(s) failed on ${{ github.ref_name }}"},"accessory":{"type":"button","text":{"type":"plain_text","text":"View Failing Workflow","emoji":true},"url":"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}}]}
|
|
|
|
test-summary:
|
|
name: Go test failures
|
|
runs-on: ubuntu-latest
|
|
if: success() || failure() || needs.tests-completed.result == 'skipped'
|
|
needs:
|
|
- test-go
|
|
- test-go-fips
|
|
- test-go-race
|
|
- tests-completed
|
|
steps:
|
|
- name: Download failure summary
|
|
uses: actions/download-artifact@v3
|
|
with:
|
|
name: failure-summary
|
|
- name: Prepare failure summary
|
|
run: |
|
|
# We will store the jq query results in a temp file
|
|
temp_file_name=temp-$(date +%s)
|
|
|
|
# The 'jq' command below filters and formats JSON data from input files to generate a failure summary report.
|
|
# The query is a bit of a nightmare, though, so let's have a closer look at it.
|
|
#
|
|
# The command takes input from files matching the pattern "failure-summary-*.json".
|
|
# The input files should contain streams of JSON objects(with no commas in between),
|
|
# one per line, representing test results.
|
|
# Each object should have the "Action" and "Package" keys.
|
|
#
|
|
# We invoke the command with two flags:
|
|
# - '-r' specifies that the output should be in raw format,
|
|
# without any JSON formatting. (I.e. no quotes).
|
|
# - '-n' tells 'jq' not to read any input from the command line.
|
|
# It is used when input is provided through the 'inputs' function or other methods.
|
|
#
|
|
# 'inputs':
|
|
# Read JSON objects from the input files specified after the 'jq' command.
|
|
# We assume that the input files contain one JSON object per line.
|
|
#
|
|
# 'select(.Action == "fail") | select(.Test != null)':
|
|
# Filter JSON array to contain only objects where the value of "Action" is "fail"
|
|
# and the value of "Test" key is not null.
|
|
#
|
|
# The remaining part of the query constructs a formatted string for each filtered JSON object`:
|
|
# - '\(.Package)' and '\(.Test)' insert the values of the "Package" and "Test" keys into the string,
|
|
# respectively.
|
|
# - 'input_filename' is a special variable in 'jq' that represents the name of the input file being processed.
|
|
# - 'split("-")' splits the input filename on the hyphen ("-") character and returns an array of the
|
|
# resulting parts.
|
|
# - '.sub(".json"; "")' removes the ".json" extension from the string.
|
|
# - The third part of the filename is extracted using '.split("-") | .[2]'.
|
|
# - If the fourth part of the filename exists, it contains the test type.
|
|
# Otherwise, the default value "normal" is used.
|
|
# - The '.sub(".json"; "")' removes the ".json" extension from the string.
|
|
#
|
|
# The filtered and formatted data is outputted as rows of a Markdown table, like this:
|
|
# | pkg1 | test1 | 1 | normal |
|
|
# | pkg2 | test2 | 4 | race |
|
|
# | pkg3 | test3 | 6 | fips |
|
|
|
|
jq -r -n 'inputs | select(.Action == "fail") | select(.Test != null) | "| \(.Package) | \(.Test) | \(input_filename | split("-") | .[2] | sub(".json"; "")) | \(input_filename | split("-") | .[3] // "normal" | sub(".json";"") )"' failure-summary-*.json | sort >> "$temp_file_name"
|
|
|
|
# if there are test failures, present them in a format of a GH Markdown table
|
|
if [ -s "$temp_file_name" ]; then
|
|
# shellcheck disable=SC2129
|
|
# Here we create the headings for the summary table
|
|
echo "### Go test failures" >> "$GITHUB_STEP_SUMMARY"
|
|
echo "| Package | Test | Runner Index | Test Type |" >> "$GITHUB_STEP_SUMMARY"
|
|
echo "| ------- | ---- | ------------ | --------- |" >> "$GITHUB_STEP_SUMMARY"
|
|
cat "$temp_file_name" >> "$GITHUB_STEP_SUMMARY"
|
|
else
|
|
echo "### All Go tests passed! :white_check_mark:" >> "$GITHUB_STEP_SUMMARY"
|
|
fi |