aquasecurity/trivy
22 workflows · maturity 50% · 7 patterns · GitHub ↗
Practices
✓ Matrix○ Permissions✓ Security scan○ AI review✓ Cache○ Concurrency✓ Reusable workflows
Detected patterns
Security dimensions
Tools: ./.github/actions/trivy-triage, knqyf263/trivy-issue-action
Workflows (22)
auto-close-issue .github/workflows/auto-close-issue.yaml
View raw YAML
name: Auto-close issues
on:
issues:
types: [opened]
jobs:
close_issue:
runs-on: ubuntu-latest
steps:
- name: Close issue if user does not have write or admin permissions
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
// Get the issue creator's username
const issueCreator = context.payload.issue.user.login;
// Check the user's permissions for the repository
const repoPermissions = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: issueCreator
});
const permission = repoPermissions.data.permission;
// If the user does not have write or admin permissions, leave a comment and close the issue
if (permission !== 'write' && permission !== 'admin') {
const commentBody = "Please see https://trivy.dev/docs/latest/community/contribute/issue/";
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
body: commentBody
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
state: 'closed',
state_reason: 'not_planned'
});
console.log(`Issue #${context.payload.issue.number} closed because ${issueCreator} does not have sufficient permissions.`);
}auto-ready-for-review .github/workflows/auto-ready-for-review.yaml
View raw YAML
name: Auto Ready for Review
on:
# workflow_run runs in the context of the base repo with full permissions, but this workflow
# does not check out any PR code — it only reads PR metadata via the GitHub API and marks
# the PR as ready for review. No code execution from forks occurs.
workflow_run: # zizmor: ignore[dangerous-triggers]
workflows: ["Test", "Validate PR Title"]
types: [completed]
jobs:
auto-ready-for-review:
runs-on: ubuntu-24.04
if: github.event.workflow_run.event == 'pull_request'
steps:
- name: Get PR context
id: pr-context
env:
GH_TOKEN: ${{ github.token }}
PR_BRANCH: |-
${{
(github.event.workflow_run.head_repository.owner.login != github.event.workflow_run.repository.owner.login)
&& format('{0}:{1}', github.event.workflow_run.head_repository.owner.login, github.event.workflow_run.head_branch)
|| github.event.workflow_run.head_branch
}}
run: |
echo "[INFO] Searching for PR with branch: ${PR_BRANCH}"
if gh pr view --repo "${{ github.repository }}" "${PR_BRANCH}" --json 'number' --jq '"number=\(.number)"' >> "${GITHUB_OUTPUT}"; then
echo "[INFO] PR found successfully"
else
echo "[INFO] No PR found for branch ${PR_BRANCH}, skipping"
echo "skip=true" >> "${GITHUB_OUTPUT}"
fi
- name: Check PR and all workflows status
if: steps.pr-context.outputs.skip != 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
PR_NUMBER: ${{ steps.pr-context.outputs.number }}
with:
script: |
const prNumber = parseInt(process.env.PR_NUMBER, 10);
console.log(`[INFO] Processing PR #${prNumber}`);
// Get PR info
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
console.log(`[INFO] PR #${prNumber} - Draft: ${pr.draft}, Labels: ${pr.labels.map(l => l.name).join(', ')}`);
// Check if PR has autoready label and is draft
const hasAutoreadyLabel = pr.labels.some(label => label.name === 'autoready');
if (!pr.draft) {
console.log(`[INFO] PR #${prNumber} is not draft, skipping`);
return;
}
if (!hasAutoreadyLabel) {
console.log(`[INFO] PR #${prNumber} doesn't have autoready label, skipping`);
return;
}
// Get all workflow runs for this PR's head commit (head_sha)
const { data: workflowRuns } = await github.rest.actions.listWorkflowRunsForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
head_sha: pr.head.sha,
per_page: 100
});
console.log(`[INFO] Found ${workflowRuns.workflow_runs.length} workflow runs for PR #${prNumber}`);
// Check workflow status
const runningWorkflows = workflowRuns.workflow_runs.filter(run =>
run.status === 'in_progress' || run.status === 'queued'
);
const failedWorkflows = workflowRuns.workflow_runs.filter(run =>
run.conclusion === 'failure' || run.conclusion === 'cancelled'
);
const successfulWorkflows = workflowRuns.workflow_runs.filter(run =>
run.conclusion === 'success'
);
console.log(`[INFO] Workflow status - Running: ${runningWorkflows.length}, Failed: ${failedWorkflows.length}, Success: ${successfulWorkflows.length}`);
if (runningWorkflows.length > 0) {
console.log(`[INFO] Some workflows are still running: ${runningWorkflows.map(w => w.name).join(', ')}`);
return;
}
if (failedWorkflows.length > 0) {
console.log(`[INFO] Some workflows failed: ${failedWorkflows.map(w => w.name).join(', ')}`);
return;
}
console.log(`[INFO] All workflows passed! Marking PR #${prNumber} as ready for review...`);
// Mark PR as ready for review using GraphQL API
// Reference: https://github.com/orgs/community/discussions/70061
try {
const mutation = `
mutation MarkPullRequestReadyForReview($pullRequestId: ID!) {
markPullRequestReadyForReview(input: { pullRequestId: $pullRequestId }) {
pullRequest {
id
isDraft
number
}
}
}
`;
const updateResult = await github.graphql(mutation, {
pullRequestId: pr.node_id
});
const isDraft = updateResult.markPullRequestReadyForReview.pullRequest.isDraft;
console.log(`[SUCCESS] PR #${prNumber} marked as ready for review. Draft status: ${isDraft}`);
} catch (error) {
console.log(`[ERROR] Failed to mark PR #${prNumber} as ready for review: ${error.message}`);
console.log(`[ERROR] Error details: ${JSON.stringify(error.response?.data || error, null, 2)}`);
return;
}
// Remove autoready label
try {
const labelResult = await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'autoready'
});
console.log(`[SUCCESS] autoready label removed from PR #${prNumber}. Status: ${labelResult.status}`);
} catch (error) {
console.log(`[WARNING] Could not remove autoready label from PR #${prNumber}: ${error.message}`);
console.log(`[WARNING] Error details: ${JSON.stringify(error.response?.data || error, null, 2)}`);
}auto-update-labels .github/workflows/auto-update-labels.yaml
View raw YAML
name: Auto-update labels
on:
push:
paths:
- 'misc/triage/labels.yaml'
branches:
- main
jobs:
deploy:
name: Auto-update labels
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: update labels
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: mage labelbackport .github/workflows/backport.yaml
View raw YAML
name: Automatic Backporting
on:
issue_comment:
types: [created]
jobs:
check_permission:
name: Check comment author permissions
runs-on: ubuntu-latest
outputs:
is_maintainer: ${{ steps.check_permission.outputs.is_maintainer }}
steps:
- name: Check permission
id: check_permission
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PERMISSION=$(gh api /repos/$GITHUB_REPOSITORY/collaborators/$GITHUB_ACTOR/permission --jq '.permission')
if [ "$PERMISSION" == "admin" ] || [ "$PERMISSION" == "write" ]; then
echo "is_maintainer=true" >> $GITHUB_OUTPUT
else
echo "is_maintainer=false" >> $GITHUB_OUTPUT
fi
backport:
name: Backport PR
needs: check_permission # run this job after checking permissions
if: |
needs.check_permission.outputs.is_maintainer == 'true' &&
github.event.issue.pull_request &&
github.event.issue.pull_request.merged_at != null &&
startsWith(github.event.comment.body, '@aqua-bot backport release/')
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: true # backport.sh runs git push
- name: Extract branch name
env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
BRANCH_NAME=$(echo "$COMMENT_BODY" | grep -oE '@aqua-bot backport\s+(\S+)' | awk '{print $3}')
if [[ -z "$BRANCH_NAME" || "$BRANCH_NAME" == *".."* || ! "$BRANCH_NAME" =~ ^[A-Za-z0-9._-]+(/[A-Za-z0-9._-]+)*$ ]]; then
echo "Error: Invalid branch name extracted (unsafe characters detected)." >&2
exit 1
fi
echo "BRANCH_NAME=$BRANCH_NAME" >> "$GITHUB_ENV"
- name: Set up Git user
run: |
git config --global user.email "actions@github.com"
git config --global user.name "GitHub Actions"
- name: Run backport script
env:
# Use ORG_REPO_TOKEN instead of GITHUB_TOKEN
# This allows the created PR to trigger tests and other workflows
GITHUB_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
run: ./misc/backport/backport.sh "$BRANCH_NAME" "$ISSUE_NUMBER"
bypass-cla .github/workflows/bypass-cla.yaml
View raw YAML
# This workflow is used to bypass the required status checks in merge queue.
# cf. https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/troubleshooting-required-status-checks
name: CLA
on:
merge_group:
jobs:
cla:
name: license/cla
runs-on: ubuntu-latest
steps:
- run: 'echo "No test required"'bypass-test matrix .github/workflows/bypass-test.yaml
View raw YAML
# This workflow is used to bypass the required status checks.
# cf. https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/troubleshooting-required-status-checks
name: Test
on:
push:
paths:
- '**.md'
- 'docs/**'
- 'mkdocs.yml'
- 'LICENSE'
- '.release-please-manifest.json'
- 'helm/trivy/Chart.yaml'
pull_request:
paths:
- '**.md'
- 'docs/**'
- 'mkdocs.yml'
- 'LICENSE'
- '.release-please-manifest.json'
- 'helm/trivy/Chart.yaml'
jobs:
test:
name: Test
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-latest]
steps:
- run: 'echo "No test required"'
integration:
name: Integration Test
runs-on: ubuntu-latest
steps:
- run: 'echo "No test required"'cache-test-assets .github/workflows/cache-test-assets.yaml
View raw YAML
name: Cache test assets
# This workflow runs on the main branch to create caches that can be accessed by PRs.
# GitHub Actions cache isolation restricts access:
# - PRs can only restore caches from: current branch, base branch, and default branch (main)
# - PRs cannot restore caches from sibling branches or other PR branches
# - By creating caches on the main branch, all PRs can benefit from shared cache
on:
push:
branches: [main]
workflow_dispatch:
jobs:
test-images:
name: Cache test images
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Generate image list digest
id: image-digest
run: |
source integration/testimages.ini
IMAGE_LIST=$(skopeo list-tags docker://$TEST_IMAGES)
DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags += ["containerd"] | .Tags |= sort' | sha256sum | cut -d' ' -f1)
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
- name: Restore and save test images cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: integration/testdata/fixtures/images
key: cache-test-images-${{ steps.image-digest.outputs.digest }}
- name: Download test images
run: mage test:fixtureContainerImages
test-vm-images:
name: Cache test VM images
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Generate image list digest
id: image-digest
run: |
source integration/testimages.ini
IMAGE_LIST=$(skopeo list-tags docker://$TEST_VM_IMAGES)
DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags |= sort' | sha256sum | cut -d' ' -f1)
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
- name: Restore and save test VM images cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: integration/testdata/fixtures/vm-images
key: cache-test-vm-images-${{ steps.image-digest.outputs.digest }}
- name: Download test VM images
run: mage test:fixtureVMImages
lint-cache:
name: Cache lint results
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Run golangci-lint for caching
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v2.10
args: --verbose
env:
GOEXPERIMENT: jsonv2
canary .github/workflows/canary.yaml
View raw YAML
name: Canary build
on:
push:
branches:
- 'main'
paths:
- '**.go'
- 'go.mod'
- 'Dockerfile.canary'
- '.github/workflows/canary.yaml'
workflow_dispatch:
jobs:
build-binaries:
name: Build binaries
uses: ./.github/workflows/reusable-release.yaml
with:
goreleaser_config: goreleaser-canary.yml
goreleaser_options: '--snapshot --clean --timeout 60m' # will not release
secrets:
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
ECR_ACCESS_KEY_ID: ${{ secrets.ECR_ACCESS_KEY_ID }}
ECR_SECRET_ACCESS_KEY: ${{ secrets.ECR_SECRET_ACCESS_KEY }}
GPG_KEY: ${{ secrets.GPG_KEY }}
ORG_REPO_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
upload-binaries:
name: Upload binaries
needs: build-binaries # run this job after 'build-binaries' job completes
runs-on: ubuntu-latest
steps:
- name: Restore Trivy binaries from cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: dist/
key: ${{ runner.os }}-bins-${{ github.workflow }}-${{ github.sha }}
# Upload artifacts
- name: Upload artifacts (trivy_Linux-64bit)
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: trivy_Linux-64bit
path: dist/trivy_*_Linux-64bit.tar.gz
if-no-files-found: error
- name: Upload artifacts (trivy_Linux-ARM64)
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: trivy_Linux-ARM64
path: dist/trivy_*_Linux-ARM64.tar.gz
if-no-files-found: error
- name: Upload artifacts (trivy_macOS-64bit)
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: trivy_macOS-64bit
path: dist/trivy_*_macOS-64bit.tar.gz
if-no-files-found: error
- name: Upload artifacts (trivy_macOS-ARM64)
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: trivy_macOS-ARM64
path: dist/trivy_*_macOS-ARM64.tar.gz
if-no-files-found: error
- name: Delete cache after upload
run: |
gh cache delete "$CACHE_KEY" --repo "${{ github.repository }}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CACHE_KEY: ${{ runner.os }}-bins-${{ github.workflow }}-${{ github.sha }}mkdocs-dev .github/workflows/mkdocs-dev.yaml
View raw YAML
name: Deploy the dev documentation
on:
push:
paths:
- 'docs/**'
- mkdocs.yml
branches:
- main
jobs:
deploy:
name: Deploy the dev documentation
runs-on: ubuntu-22.04
steps:
- name: Checkout main
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: true
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: 3.x
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git@9.5.44-insiders-4.53.14
pip install -r docs/build/requirements.txt
env:
GH_TOKEN: ${{ secrets.MKDOCS_AQUA_BOT }}
- name: Configure the git user
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Deploy the dev documents
run: mike deploy --push dev
mkdocs-latest .github/workflows/mkdocs-latest.yaml
View raw YAML
name: Deploy the latest documentation
on:
workflow_dispatch:
inputs:
version:
description: Version to be deployed
required: true
push:
tags:
- "v*"
jobs:
deploy:
name: Deploy the latest documentation
runs-on: ubuntu-22.04
steps:
- name: Checkout main
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: true
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: 3.x
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install git+https://${GH_TOKEN}@github.com/squidfunk/mkdocs-material-insiders.git@9.5.44-insiders-4.53.14
pip install -r docs/build/requirements.txt
env:
GH_TOKEN: ${{ secrets.MKDOCS_AQUA_BOT }}
- name: Configure the git user
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Deploy the latest documents from new tag push
if: ${{ github.event.inputs.version == '' }}
run: |
VERSION=$(echo "$GITHUB_REF" | sed -e "s#refs/tags/##g")
mike deploy --push --update-aliases ${VERSION%.*} latest
- name: Deploy the latest documents from manual trigger
if: ${{ github.event.inputs.version != '' }}
env:
DOCS_VERSION: ${{ github.event.inputs.version }}
run: mike deploy --push --update-aliases "$DOCS_VERSION" latest
# This workflow is used to trigger the trivy-www deployment
trigger-trivy-www-deploy:
needs: deploy
runs-on: ubuntu-22.04
steps:
- name: Trigger update_version workflow in trivy-telemetry
env:
# Use ORG_REPO_TOKEN instead of GITHUB_TOKEN
# This allows triggering workflows in other repositories
GH_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
run: |
gh workflow run build-docs.yml \
--repo "$GITHUB_REPOSITORY_OWNER/trivy-www" \
--ref main \
--field "from_version=$GITHUB_REF_NAME"publish-chart .github/workflows/publish-chart.yaml
View raw YAML
name: Publish Helm chart
on:
workflow_dispatch:
pull_request:
types:
- opened
- synchronize
- reopened
- closed
branches:
- main
paths:
- 'helm/trivy/**'
env:
HELM_REP: helm-charts
GH_OWNER: aquasecurity
CHART_DIR: helm/trivy
KIND_VERSION: "v0.14.0"
KIND_IMAGE: "kindest/node:v1.23.6@sha256:b1fa224cc6c7ff32455e0b1fd9cbfd3d3bc87ecaa8fcb06961ed1afb3db0f9ae"
jobs:
# `test-chart` job starts if a PR with Helm Chart is created, merged etc.
test-chart:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Install Helm
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1
with:
version: v3.14.4
- name: Set up python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.x'
check-latest: true
- name: Setup Chart Linting
id: lint
uses: helm/chart-testing-action@6ec842c01de15ebb84c8627d2744a0c2f2755c9f # v2.8.0
with:
# v6.0.0 resolved the compatibility issue with Python > 3.13. may be removed after the action itself is updated
yamale_version: "6.0.0"
- name: Setup Kubernetes cluster (KIND)
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0
with:
version: ${{ env.KIND_VERSION }}
image: ${{ env.KIND_IMAGE }}
- name: Run chart-testing
run: ct lint-and-install --validate-maintainers=false --charts helm/trivy
- name: Run chart-testing (Ingress enabled)
run: |
sed -i -e '136s,false,'true',g' ./helm/trivy/values.yaml
ct lint-and-install --validate-maintainers=false --charts helm/trivy
# `publish-chart` job starts if a PR with a new Helm Chart is merged or manually
publish-chart:
if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
needs:
- test-chart
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Install chart-releaser
run: |
wget https://github.com/helm/chart-releaser/releases/download/v1.3.0/chart-releaser_1.3.0_linux_amd64.tar.gz
echo "baed2315a9bb799efb71d512c5198a2a3b8dcd139d7f22f878777cffcd649a37 chart-releaser_1.3.0_linux_amd64.tar.gz" | sha256sum -c -
tar xzvf chart-releaser_1.3.0_linux_amd64.tar.gz cr
- name: Package helm chart
run: |
./cr package ${{ env.CHART_DIR }}
- name: Upload helm chart
# Failed with upload the same version: https://github.com/helm/chart-releaser/issues/101
continue-on-error: true
run: |
./cr upload -o ${{ env.GH_OWNER }} -r ${{ env.HELM_REP }} --token ${{ secrets.ORG_REPO_TOKEN }} -p .cr-release-packages
- name: Index helm chart
run: |
./cr index -o ${{ env.GH_OWNER }} -r ${{ env.HELM_REP }} -c https://${{ env.GH_OWNER }}.github.io/${{ env.HELM_REP }}/ -i index.yaml
- name: Push index file
uses: dmnemec/copy_file_to_another_repo_action@c93037aa10fa8893de271f19978c980d0c1a9b37 #v1.1.1
env:
API_TOKEN_GITHUB: ${{ secrets.ORG_REPO_TOKEN }}
with:
source_file: 'index.yaml'
destination_repo: '${{ env.GH_OWNER }}/${{ env.HELM_REP }}'
destination_folder: '.'
destination_branch: 'gh-pages'
user_email: aqua-bot@users.noreply.github.com
user_name: 'aqua-bot'
release .github/workflows/release.yaml
View raw YAML
name: Release
on:
push:
tags:
- "v*"
jobs:
release:
name: Release
uses: ./.github/workflows/reusable-release.yaml
with:
goreleaser_config: goreleaser.yml
goreleaser_options: '--clean --timeout 90m'
secrets:
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
ECR_ACCESS_KEY_ID: ${{ secrets.ECR_ACCESS_KEY_ID }}
ECR_SECRET_ACCESS_KEY: ${{ secrets.ECR_SECRET_ACCESS_KEY }}
GPG_KEY: ${{ secrets.GPG_KEY }}
ORG_REPO_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
deploy-packages:
name: Deploy rpm/dep packages
needs: release # run this job after 'release' job completes
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
# Cache is keyed by github.sha and scoped to tag-push events triggered by maintainers only.
# Cache is written exclusively by the release job (reusable-release.yaml) on the same
# tag-push event. Only maintainers can push tags, so external contributors cannot influence
# the cache contents. The key includes github.sha to prevent collisions across runs.
- name: Restore Trivy binaries from cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 # zizmor: ignore[cache-poisoning]
with:
path: dist/
key: ${{ runner.os }}-bins-${{github.workflow}}-${{github.sha}}
- name: Install dependencies
run: |
sudo apt-get -y update
sudo apt-get -y install rpm reprepro createrepo-c distro-info
- name: Checkout trivy-repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: ${{ github.repository_owner }}/trivy-repo
path: trivy-repo
token: ${{ secrets.ORG_REPO_TOKEN }}
persist-credentials: true # deploy-rpm.sh and deploy-deb.sh run git push
- name: Setup git settings
run: |
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
- name: Create rpm repository
run: ci/deploy-rpm.sh
- name: Import GPG key
run: echo -e "${{ secrets.GPG_KEY }}" | gpg --import
- name: Create deb repository
run: ci/deploy-deb.sh
# `update-chart-version` creates a new PR for updating the helm chart
update-chart-version:
needs: deploy-packages
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: true # mage helm:updateVersion runs git push
- name: Set up Git user
run: |
git config --global user.email "actions@github.com"
git config --global user.name "GitHub Actions"
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Create a PR with Trivy version
run: mage helm:updateVersion
env:
# Use ORG_REPO_TOKEN instead of GITHUB_TOKEN
# This allows the created PR to trigger tests and other workflows
GITHUB_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
# `trigger-version-update` triggers workflows in the `aqua` repositories to update the Trivy version.
trigger-version-update:
needs: deploy-packages
runs-on: ubuntu-22.04
steps:
- name: Trigger update_version workflow in trivy-telemetry
if: always()
env:
# Use ORG_REPO_TOKEN instead of GITHUB_TOKEN
# This allows triggering workflows in other repositories
GH_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
run: |
gh workflow run update_version.yml \
--repo "$GITHUB_REPOSITORY_OWNER/trivy-telemetry" \
--ref main \
--field "version=$GITHUB_REF_NAME"
- name: Trigger update_version workflow in trivy-downloads
if: always()
env:
# Use ORG_REPO_TOKEN instead of GITHUB_TOKEN
# This allows triggering workflows in other repositories
GH_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
run: |
gh workflow run update_version.yml \
--repo "$GITHUB_REPOSITORY_OWNER/trivy-downloads" \
--ref main \
--field "version=$GITHUB_REF_NAME" \
--field artifact=trivy
- name: Trigger version update and release workflow in trivy-chocolatey
if: always()
env:
# Use ORG_REPO_TOKEN instead of GITHUB_TOKEN
# This allows triggering workflows in other repositories
GH_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
run: |
gh workflow run release.yml \
--repo "$GITHUB_REPOSITORY_OWNER/trivy-chocolatey" \
--ref main \
--field "version=$GITHUB_REF_NAME"
- name: Run version bump in trivy-action
if: always()
env:
# Use ORG_REPO_TOKEN instead of GITHUB_TOKEN
# This allows triggering workflows in other repositories
GH_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
run: |
VERSION="${GITHUB_REF_NAME#v}"
gh workflow run bump-trivy.yaml \
--repo "$GITHUB_REPOSITORY_OWNER/trivy-action" \
--ref master \
--field "trivy_version=$VERSION"
release-please .github/workflows/release-please.yaml
View raw YAML
name: Release Please
on:
push:
branches:
- main
- 'release/v*'
workflow_dispatch:
inputs:
version:
required: true
description: 'Release version without the "v" prefix (e.g., 0.51.0)'
type: string
jobs:
release-please:
runs-on: ubuntu-latest
if: ${{ !startsWith(github.event.head_commit.message, 'release:') && !github.event.inputs.version }}
steps:
- name: Release Please
id: release
uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0
with:
token: ${{ secrets.ORG_REPO_TOKEN }}
target-branch: ${{ github.ref_name }}
manual-release-please:
runs-on: ubuntu-latest
if: ${{ github.event.inputs.version }}
steps:
- name: Install Release Please CLI
run: npm install release-please -g
- name: Release Please
env:
RELEASE_VERSION: ${{ github.event.inputs.version }}
run: |
release-please release-pr --repo-url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" \
--token="${{ secrets.ORG_REPO_TOKEN }}" \
--release-as="$RELEASE_VERSION" \
--target-branch="$GITHUB_REF_NAME"
release-tag:
runs-on: ubuntu-latest
if: ${{ startsWith(github.event.head_commit.message, 'release:') }}
steps:
# Since skip-github-release is specified, the outputs of googleapis/release-please-action cannot be used.
# Therefore, we need to parse the version ourselves.
- name: Extract version and PR number from commit message
id: extract_info
shell: bash
env:
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
run: |
echo "version=$( echo "$COMMIT_MESSAGE" | sed 's/^release: v\([0-9]\+\.[0-9]\+\.[0-9]\+\).*$/\1/' )" >> $GITHUB_OUTPUT
echo "pr_number=$( echo "$COMMIT_MESSAGE" | sed 's/.*(\#\([0-9]\+\)).*$/\1/' )" >> $GITHUB_OUTPUT
echo "release_branch=release/v$( echo "$COMMIT_MESSAGE" | sed 's/^release: v\([0-9]\+\.[0-9]\+\).*$/\1/' )" >> $GITHUB_OUTPUT
- name: Tag release
if: ${{ steps.extract_info.outputs.version }}
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
VERSION: ${{ steps.extract_info.outputs.version }}
with:
github-token: ${{ secrets.ORG_REPO_TOKEN }} # To trigger another workflow
script: |
await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/tags/v${process.env.VERSION}`,
sha: context.sha
});
# When v0.50.0 is released, a release branch "release/v0.50" is created.
- name: Create release branch for patch versions
if: ${{ endsWith(steps.extract_info.outputs.version, '.0') }}
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
RELEASE_BRANCH: ${{ steps.extract_info.outputs.release_branch }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }} # Should not trigger the workflow again
script: |
const releaseBranch = process.env.RELEASE_BRANCH;
await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/heads/${releaseBranch}`,
sha: context.sha
});
# Add release branch to rulesets to enable merge queue
- name: Add release branch to rulesets
if: ${{ endsWith(steps.extract_info.outputs.version, '.0') }}
env:
GITHUB_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
RELEASE_BRANCH: ${{ steps.extract_info.outputs.release_branch }}
shell: bash
run: |
RULESET_ID=$(gh api /repos/${GITHUB_REPOSITORY}/rulesets --jq '.[] | select(.name=="release") | .id')
gh api /repos/${GITHUB_REPOSITORY}/rulesets/$RULESET_ID | jq '{conditions}' | jq ".conditions.ref_name.include += [\"refs/heads/${RELEASE_BRANCH}\"]" | gh api --method put --input - /repos/${GITHUB_REPOSITORY}/rulesets/$RULESET_ID
# Since skip-github-release is specified, googleapis/release-please-action doesn't delete the label from PR.
# This label prevents the subsequent PRs from being created. Therefore, we need to delete it ourselves.
# cf. https://github.com/googleapis/release-please?tab=readme-ov-file#release-please-bot-does-not-create-a-release-pr-why
- name: Remove the label from PR
if: ${{ steps.extract_info.outputs.pr_number }}
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
PR_NUMBER: ${{ steps.extract_info.outputs.pr_number }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = parseInt(process.env.PR_NUMBER, 10);
github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'autorelease: pending'
});
release-pr-check .github/workflows/release-pr-check.yaml
View raw YAML
name: Backport PR Check
on:
pull_request:
branches:
- 'release/v*'
jobs:
check-pr-author:
runs-on: ubuntu-latest
steps:
- name: Check PR author
id: check_author
env:
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
run: |
if [ "$PR_AUTHOR" != "aqua-bot" ]; then
echo "::error::This branch is intended for automated backporting by bot. Please refer to the documentation:"
echo "::error::https://trivy.dev/docs/latest/community/maintainer/backporting/"
exit 1
fireusable-release .github/workflows/reusable-release.yaml
View raw YAML
name: Reusable release
on:
workflow_call:
inputs:
goreleaser_config:
description: 'file path to GoReleaser config'
required: true
type: string
goreleaser_options:
description: 'GoReleaser options separated by spaces'
default: ''
required: false
type: string
secrets:
DOCKERHUB_USER:
required: true
DOCKERHUB_TOKEN:
required: true
ECR_ACCESS_KEY_ID:
required: true
ECR_SECRET_ACCESS_KEY:
required: true
GPG_KEY:
required: true
ORG_REPO_TOKEN:
required: true
GPG_PASSPHRASE:
required: true
env:
GH_USER: "aqua-bot"
jobs:
release:
name: Release
runs-on: ubuntu-latest-m
env:
DOCKER_CLI_EXPERIMENTAL: "enabled"
permissions:
id-token: write # For cosign
packages: write # For GHCR
contents: read # Not required for public repositories, but for clarity
attestations: write # For build provenance attestations
steps:
- name: Cosign install
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Show available Docker Buildx platforms
env:
PLATFORMS: ${{ steps.buildx.outputs.platforms }}
run: echo "${PLATFORMS}"
- name: Login to docker.io registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to ghcr.io registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ env.GH_USER }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to ECR
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: public.ecr.aws
username: ${{ secrets.ECR_ACCESS_KEY_ID }}
password: ${{ secrets.ECR_SECRET_ACCESS_KEY }}
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Go
uses: ./.github/actions/setup-go
- name: Generate SBOM
uses: CycloneDX/gh-gomod-generate-sbom@efc74245d6802c8cefd925620515442756c70d8f # v2.0.0
with:
args: mod -licenses -json -output bom.json
version: ^v1
- name: "save gpg key"
env:
GPG_KEY: ${{ secrets.GPG_KEY }}
run: |
echo "$GPG_KEY" > gpg.key
# Create tmp dir for GoReleaser
- name: "create tmp dir"
run: |
mkdir tmp
- name: GoReleaser
id: goreleaser
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
with:
version: v2.1.0
args: release -f=${{ inputs.goreleaser_config}} ${{ inputs.goreleaser_options}}
env:
GITHUB_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
NFPM_DEFAULT_RPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_FILE: "gpg.key"
TMPDIR: "tmp"
- name: "remove gpg key"
run: |
rm gpg.key
# Push images to registries (only for canary build)
# The custom Dockerfile.canary is necessary
# because GoReleaser Free doesn't support pushing images with the `--snapshot` flag.
- name: Build and push
if: ${{ inputs.goreleaser_config == 'goreleaser-canary.yml' }}
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
platforms: linux/amd64, linux/arm64
file: ./Dockerfile.canary # path to Dockerfile
context: .
push: true
tags: |
aquasec/trivy:canary
ghcr.io/aquasecurity/trivy:canary
public.ecr.aws/aquasecurity/trivy:canary
- name: Generate build provenance attestations
if: ${{ inputs.goreleaser_config != 'goreleaser-canary.yml' }}
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
with:
subject-checksums: dist/trivy_${{ fromJSON(steps.goreleaser.outputs.metadata).version }}_checksums.txt
# This workflow is only triggered by tag pushes (release.yaml: on.push.tags), which require
# maintainer access. Fork PRs cannot reach this code path, so the cache cannot be poisoned
# by external contributors. The key is scoped to github.sha, making cross-run collisions
# impossible. Cache is written here and read only by the deploy-packages job in release.yaml.
- name: Cache Trivy binaries
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 # zizmor: ignore[cache-poisoning]
with:
path: dist/
# use 'github.sha' to create a unique cache folder for each run.
# use 'github.workflow' to create a unique cache folder if some runs have same commit sha.
# e.g. build and release runs
key: ${{ runner.os }}-bins-${{github.workflow}}-${{github.sha}}
scan security .github/workflows/scan.yaml
View raw YAML
name: Scan vulnerabilities
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
jobs:
build:
name: Scan Go vulnerabilities
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Run Trivy vulnerability scanner and create GitHub issues
uses: knqyf263/trivy-issue-action@4466f52d1401b66dd2a2ab9e0c40cddc021829ec # v0.0.6
with:
assignee: knqyf263
severity: CRITICAL
skip-dirs: integration,examples,pkg
label: kind/security
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}semantic-pr .github/workflows/semantic-pr.yaml
View raw YAML
name: "Validate PR Title"
on:
pull_request:
types:
- opened
- edited
- synchronize
jobs:
validate:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- name: Validate PR title
shell: bash
env:
PR_TITLE: ${{ github.event.pull_request.title }}
# Valid types
VALID_TYPES: |
feat
fix
docs
style
refactor
perf
test
build
ci
chore
revert
release
# Valid scopes categorized by area
VALID_SCOPES: |
# Scanners
vuln
misconf
secret
license
# Targets
image
fs
repo
sbom
server
k8s
aws
vm
plugin
# OS
activestate
alpine
wolfi
chainguard
redhat
alma
rocky
mariner
oracle
debian
ubuntu
amazon
suse
photon
echo
distroless
windows
minimos
rootio
seal
# Languages
ruby
php
python
nodejs
rust
dotnet
java
go
c
c++
elixir
dart
swift
bitnami
conda
julia
# Package types
os
lang
# IaC
kubernetes
dockerfile
terraform
cloudformation
# Container
docker
podman
containerd
oci
# SBOM
sbom
spdx
cyclonedx
# Misc
cli
flag
purl
vex
helm
report
db
parser
deps
run: |
set -euo pipefail
# Convert env vars to regex alternatives, excluding comments and empty lines
TYPES_REGEX=$(echo "$VALID_TYPES" | grep -v '^$' | paste -sd '|')
SCOPES_REGEX=$(echo "$VALID_SCOPES" | grep -v '^$' | grep -v '^#' | paste -sd '|')
# Basic format check (should match: type(scope): description or type: description)
FORMAT_REGEX="^[a-z]+(\([a-z0-9+]+\))?!?: .+$"
if ! echo "$PR_TITLE" | grep -qE "$FORMAT_REGEX"; then
echo "Error: Invalid PR title format"
echo "Expected format: <type>(<scope>): <description> or <type>: <description>"
echo "Examples:"
echo " feat(vuln): add new vulnerability detection"
echo " fix: correct parsing logic"
echo " docs(kubernetes): update installation guide"
echo -e "\nCurrent title: $PR_TITLE"
exit 1
fi
# Extract type and scope for validation
TYPE=$(echo "$PR_TITLE" | sed -E 's/^([a-z]+)(\([a-z0-9+]+\))?!?: .+$/\1/')
SCOPE=$(echo "$PR_TITLE" | sed -E 's/^[a-z]+\(([a-z0-9+]+)\)!?: .+$/\1/; t; s/.*//')
# Validate type
if ! echo "$VALID_TYPES" | grep -qx "$TYPE"; then
echo "Error: Invalid type '${TYPE}'"
echo -e "\nValid types:"
echo "$VALID_TYPES" | grep -v '^$' | sed 's/^/- /'
echo -e "\nCurrent title: $PR_TITLE"
exit 1
fi
# Validate scope if present
if [ -n "$SCOPE" ]; then
if ! echo "$VALID_SCOPES" | grep -v '^#' | grep -qx "$SCOPE"; then
echo "Error: Invalid scope '${SCOPE}'"
echo -e "\nValid scopes:"
echo "$VALID_SCOPES" | grep -v '^$' | grep -v '^#' | sed 's/^/- /'
echo -e "\nCurrent title: $PR_TITLE"
exit 1
fi
fi
echo "PR title validation passed ✅"
echo "Current title: $PR_TITLE"
spdx-cron .github/workflows/spdx-cron.yaml
View raw YAML
name: SPDX licenses cron
on:
schedule:
- cron: '0 0 * * 0' # every Sunday at 00:00
workflow_dispatch:
jobs:
build:
name: Check if SPDX exceptions
runs-on: ubuntu-24.04
steps:
- name: Check out code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Check if SPDX license IDs and exceptions are up-to-date
id: exceptions_check
run: |
mage spdx:updateLicenseEntries
if [ -n "$(git status --porcelain)" ]; then
echo "Run 'mage spdx:updateLicenseEntries' and push it"
echo "send_notify=true" >> $GITHUB_OUTPUT
fi
- name: Microsoft Teams Notification
uses: Skitionek/notify-microsoft-teams@b65dda7f5e6fd0960b97f923629b911890dc60b1 # main
if: steps.exceptions_check.outputs.send_notify == 'true'
with:
webhook_url: ${{ secrets.TRIVY_MSTEAMS_WEBHOOK }}
needs: ${{ toJson(needs) }}
job: ${{ toJson(job) }}
steps: ${{ toJson(steps) }}stale-issues .github/workflows/stale-issues.yaml
View raw YAML
name: "Stale PR's"
on:
schedule:
- cron: '0 0 * * *'
jobs:
stale:
timeout-minutes: 1
runs-on: ubuntu-latest
steps:
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: 'This PR is stale because it has been labeled with inactivity.'
exempt-pr-labels: 'lifecycle/active'
stale-pr-label: 'lifecycle/stale'
days-before-stale: 60
days-before-issue-stale: '-1'
days-before-close: 20
days-before-issue-close: '-1'
test matrix .github/workflows/test.yaml
View raw YAML
name: Test
on:
pull_request:
paths-ignore:
- '**.md'
- 'docs/**'
- 'mkdocs.yml'
- 'LICENSE'
- '.release-please-manifest.json' ## don't run tests for release-please PRs
- 'helm/trivy/Chart.yaml'
merge_group:
workflow_dispatch:
jobs:
test:
name: Test
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: go mod tidy
run: |
go mod tidy
if [ -n "$(git status --porcelain)" ]; then
echo "Run 'go mod tidy' and push it"
exit 1
fi
if: matrix.operating-system == 'ubuntu-latest'
- name: Lint
id: lint
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v2.10
args: --verbose
skip-save-cache: true # Restore cache from main branch but don't save new cache
env:
GOEXPERIMENT: jsonv2
if: matrix.operating-system == 'ubuntu-latest'
- name: Check if linter failed
run: |
echo "Linter failed, running 'mage lint:fix' might help to correct some errors"
exit 1
if: ${{ failure() && steps.lint.conclusion == 'failure' }}
- name: Install tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Check if CLI references are up-to-date
run: |
mage docs:generate
if [ -n "$(git status --porcelain)" ]; then
echo "Run 'mage docs:generate' and push it"
exit 1
fi
if: matrix.operating-system == 'ubuntu-latest'
- name: Run unit tests
run: mage test:unit
integration:
name: Integration Test
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# GitHub runners were rolled back to Docker Engine v28, while tests rely on Docker Engine v29.
# This version mismatch leads to differences in image IDs and causes integration tests to fail.
# We explicitly install Docker Engine v29 to ensure consistent behavior.
# Remove this temporary solution when the issue is resolved.
# https://github.com/actions/runner-images/issues/13474
- name: Set up Docker
uses: docker/setup-docker-action@e43656e248c0bd0647d3f5c195d116aacf6fcaf4 # v4.7.0
with:
version: v29.2.1
set-host: true
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Generate image list digest
id: image-digest
run: |
source integration/testimages.ini
IMAGE_LIST=$(skopeo list-tags docker://$TEST_IMAGES)
DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags += ["containerd"] | .Tags |= sort' | sha256sum | cut -d' ' -f1)
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
- name: Restore test images from cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: integration/testdata/fixtures/images
key: cache-test-images-${{ steps.image-digest.outputs.digest }}
- name: Run integration tests
run: mage test:integration
k8s-integration:
name: K8s Integration Test
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Run k8s integration tests
run: mage test:k8s
module-test:
name: Module Integration Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Generate image list digest
id: image-digest
run: |
source integration/testimages.ini
IMAGE_LIST=$(skopeo list-tags docker://$TEST_IMAGES)
DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags += ["containerd"] | .Tags |= sort' | sha256sum | cut -d' ' -f1)
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
- name: Restore test images from cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: integration/testdata/fixtures/images
key: cache-test-images-${{ steps.image-digest.outputs.digest }}
- name: Run module integration tests
shell: bash
run: |
mage test:module
vm-test:
name: VM Integration Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Generate image list digest
id: image-digest
run: |
source integration/testimages.ini
IMAGE_LIST=$(skopeo list-tags docker://$TEST_VM_IMAGES)
DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags |= sort' | sha256sum | cut -d' ' -f1)
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
- name: Restore test VM images from cache
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: integration/testdata/fixtures/vm-images
key: cache-test-vm-images-${{ steps.image-digest.outputs.digest }}
- name: Run vm integration tests
run: |
mage test:vm
e2e-test:
name: E2E Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
- name: Run E2E tests
run: mage test:e2e
build-test:
name: Build Test
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-latest]
env:
DOCKER_CLI_EXPERIMENTAL: "enabled"
steps:
# The go-build (GOCACHE env) directory requires a large amount of free disk space.
- name: Free up disk space
if: matrix.operating-system == 'ubuntu-latest'
run: |
sudo rm -rf /usr/local/lib/android
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force
df -h
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Determine GoReleaser ID
id: goreleaser_id
shell: bash
run: |
if [ "${{ matrix.operating-system }}" == "windows-latest" ]; then
echo "id=--id build-windows" >> $GITHUB_OUTPUT
elif [ "${{ matrix.operating-system }}" == "macos-latest" ]; then
echo "id=--id build-macos --id build-bsd" >> $GITHUB_OUTPUT
else
echo "id=--id build-linux" >> $GITHUB_OUTPUT
fi
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
with:
version: v2.1.0
args: build --snapshot --clean --timeout 90m ${{ steps.goreleaser_id.outputs.id }}
# This job intentionally runs on all PRs (not scoped to .github/ path changes)
# to keep all checks in one place. The scan itself is scoped to .github/ via the action input.
zizmor:
name: Lint GitHub Actions
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
with:
inputs: .github/
advanced-security: false
test-docs .github/workflows/test-docs.yaml
View raw YAML
name: Test docs
on:
pull_request:
paths:
- 'docs/**'
- 'mkdocs.yml'
jobs:
build-documents:
name: Documentation Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: true
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: 3.x
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install -r docs/build/requirements.txt
- name: Configure the git user
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Deploy the dev documents
run: mike deploy test
triage security .github/workflows/triage.yaml
View raw YAML
name: Triage Discussion
on:
discussion:
types: [created]
workflow_dispatch:
inputs:
discussion_num:
required: true
jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: ./.github/actions/trivy-triage
with:
discussion_num: ${{ github.event.inputs.discussion_num }}