mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-21 23:00:42 -08:00
ci(helm): auto public Helm chart after PR merged (#7526)
This commit is contained in:
2
.github/workflows/bypass-test.yaml
vendored
2
.github/workflows/bypass-test.yaml
vendored
@@ -9,6 +9,7 @@ on:
|
|||||||
- 'mkdocs.yml'
|
- 'mkdocs.yml'
|
||||||
- 'LICENSE'
|
- 'LICENSE'
|
||||||
- '.release-please-manifest.json'
|
- '.release-please-manifest.json'
|
||||||
|
- 'helm/trivy/Chart.yaml'
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
@@ -16,6 +17,7 @@ on:
|
|||||||
- 'mkdocs.yml'
|
- 'mkdocs.yml'
|
||||||
- 'LICENSE'
|
- 'LICENSE'
|
||||||
- '.release-please-manifest.json'
|
- '.release-please-manifest.json'
|
||||||
|
- 'helm/trivy/Chart.yaml'
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
name: Test
|
name: Test
|
||||||
|
|||||||
46
.github/workflows/publish-chart.yaml
vendored
46
.github/workflows/publish-chart.yaml
vendored
@@ -4,6 +4,11 @@ name: Publish Helm chart
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- synchronize
|
||||||
|
- reopened
|
||||||
|
- closed
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
@@ -18,8 +23,10 @@ env:
|
|||||||
KIND_VERSION: "v0.14.0"
|
KIND_VERSION: "v0.14.0"
|
||||||
KIND_IMAGE: "kindest/node:v1.23.6@sha256:b1fa224cc6c7ff32455e0b1fd9cbfd3d3bc87ecaa8fcb06961ed1afb3db0f9ae"
|
KIND_IMAGE: "kindest/node:v1.23.6@sha256:b1fa224cc6c7ff32455e0b1fd9cbfd3d3bc87ecaa8fcb06961ed1afb3db0f9ae"
|
||||||
jobs:
|
jobs:
|
||||||
|
# `test-chart` job starts if a PR with Helm Chart is created, merged etc.
|
||||||
test-chart:
|
test-chart:
|
||||||
runs-on: ubuntu-20.04
|
if: github.event_name != 'push'
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.1.6
|
uses: actions/checkout@v4.1.6
|
||||||
@@ -28,11 +35,12 @@ jobs:
|
|||||||
- name: Install Helm
|
- name: Install Helm
|
||||||
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
|
uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814
|
||||||
with:
|
with:
|
||||||
version: v3.5.0
|
version: v3.14.4
|
||||||
- name: Set up python
|
- name: Set up python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.7
|
python-version: '3.x'
|
||||||
|
check-latest: true
|
||||||
- name: Setup Chart Linting
|
- name: Setup Chart Linting
|
||||||
id: lint
|
id: lint
|
||||||
uses: helm/chart-testing-action@e6669bcd63d7cb57cb4380c33043eebe5d111992
|
uses: helm/chart-testing-action@e6669bcd63d7cb57cb4380c33043eebe5d111992
|
||||||
@@ -48,11 +56,39 @@ jobs:
|
|||||||
sed -i -e '136s,false,'true',g' ./helm/trivy/values.yaml
|
sed -i -e '136s,false,'true',g' ./helm/trivy/values.yaml
|
||||||
ct lint-and-install --validate-maintainers=false --charts helm/trivy
|
ct lint-and-install --validate-maintainers=false --charts helm/trivy
|
||||||
|
|
||||||
|
# `update-chart-version` job starts if a new tag is pushed
|
||||||
|
update-chart-version:
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.1.6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Set up Git user
|
||||||
|
run: |
|
||||||
|
git config --global user.email "actions@github.com"
|
||||||
|
git config --global user.name "GitHub Actions"
|
||||||
|
|
||||||
|
- name: Install tools
|
||||||
|
uses: aquaproj/aqua-installer@v3.0.1
|
||||||
|
with:
|
||||||
|
aqua_version: v1.25.0
|
||||||
|
aqua_opts: ""
|
||||||
|
|
||||||
|
- 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 }}
|
||||||
|
|
||||||
|
# `publish-chart` job starts if a PR with a new Helm Chart is merged or manually
|
||||||
publish-chart:
|
publish-chart:
|
||||||
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
|
||||||
needs:
|
needs:
|
||||||
- test-chart
|
- test-chart
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4.1.6
|
uses: actions/checkout@v4.1.6
|
||||||
|
|||||||
1
.github/workflows/test.yaml
vendored
1
.github/workflows/test.yaml
vendored
@@ -7,6 +7,7 @@ on:
|
|||||||
- 'mkdocs.yml'
|
- 'mkdocs.yml'
|
||||||
- 'LICENSE'
|
- 'LICENSE'
|
||||||
- '.release-please-manifest.json' ## don't run tests for release-please PRs
|
- '.release-please-manifest.json' ## don't run tests for release-please PRs
|
||||||
|
- 'helm/trivy/Chart.yaml'
|
||||||
merge_group:
|
merge_group:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
|||||||
117
magefiles/helm.go
Normal file
117
magefiles/helm.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
//go:build mage_helm
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/go-version/pkg/semver"
|
||||||
|
|
||||||
|
"github.com/magefile/mage/sh"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
const chartFile = "./helm/trivy/Chart.yaml"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
trivyVersion, err := version()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not determine Trivy version: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newHelmVersion, err := bumpHelmChart(chartFile, trivyVersion)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not bump Trivy version to %q: %v", trivyVersion, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Current helm version will bump up %q with Trivy %q", newHelmVersion, trivyVersion)
|
||||||
|
|
||||||
|
newBranch := fmt.Sprintf("ci/helm-chart/bump-trivy-to-%s", trivyVersion)
|
||||||
|
title := fmt.Sprintf("ci(helm): bump Trivy version to %s for Trivy Helm Chart %s", trivyVersion, newHelmVersion)
|
||||||
|
description := fmt.Sprintf("This PR bumps Trivy up to the %s version for the Trivy Helm chart %s.",
|
||||||
|
trivyVersion, newHelmVersion)
|
||||||
|
|
||||||
|
cmds := [][]string{
|
||||||
|
[]string{"git", "switch", "-c", newBranch},
|
||||||
|
[]string{"git", "add", chartFile},
|
||||||
|
[]string{"git", "commit", "-m", title},
|
||||||
|
[]string{"git", "push", "origin", newBranch},
|
||||||
|
[]string{"gh", "pr", "create", "--base", "main", "--head", newBranch, "--title", title, "--body", description, "--repo", "$GITHUB_REPOSITORY"},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runShCommands(cmds); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Print("Successfully created PR with a new helm version")
|
||||||
|
}
|
||||||
|
|
||||||
|
type Chart struct {
|
||||||
|
Version string `yaml:"version"`
|
||||||
|
AppVersion string `yaml:"appVersion"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// bumpHelmChart bumps up helm and trivy versions inside a file (Chart.yaml)
|
||||||
|
// it returns a new helm version and error
|
||||||
|
func bumpHelmChart(filename, trivyVersion string) (string, error) {
|
||||||
|
input, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return "", xerrors.Errorf("could not read file %q: %w", filename, err)
|
||||||
|
}
|
||||||
|
currentHelmChart := &Chart{}
|
||||||
|
if err := yaml.Unmarshal(input, currentHelmChart); err != nil {
|
||||||
|
return "", xerrors.Errorf("could not unmarshal helm chart %q: %w", filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newHelmVersion, err := buildNewHelmVersion(currentHelmChart.Version, currentHelmChart.AppVersion, trivyVersion)
|
||||||
|
if err != nil {
|
||||||
|
return "", xerrors.Errorf("could not build new helm version: %v", err)
|
||||||
|
}
|
||||||
|
cmds := [][]string{
|
||||||
|
[]string{"sed", "-i", "-e", fmt.Sprintf("s/appVersion: %s/appVersion: %s/g", currentHelmChart.AppVersion, trivyVersion), filename},
|
||||||
|
[]string{"sed", "-i", "-e", fmt.Sprintf("s/version: %s/version: %s/g", currentHelmChart.Version, newHelmVersion), filename},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runShCommands(cmds); err != nil {
|
||||||
|
return "", xerrors.Errorf("could not update Helm Chart %q: %w", newHelmVersion, err)
|
||||||
|
}
|
||||||
|
return newHelmVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runShCommands(cmds [][]string) error {
|
||||||
|
for _, cmd := range cmds {
|
||||||
|
if err := sh.Run(cmd[0], cmd[1:]...); err != nil {
|
||||||
|
return xerrors.Errorf("failed to run %v: %w", cmd, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildNewHelmVersion(currentHelm, currentTrivy, newTrivy string) (string, error) {
|
||||||
|
currentHelmVersion, err := semver.Parse(currentHelm)
|
||||||
|
if err != nil {
|
||||||
|
return "", xerrors.Errorf("could not parse current helm version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTrivyVersion, err := semver.Parse(currentTrivy)
|
||||||
|
if err != nil {
|
||||||
|
return "", xerrors.Errorf("could not parse current trivy version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newTrivyVersion, err := semver.Parse(newTrivy)
|
||||||
|
if err != nil {
|
||||||
|
return "", xerrors.Errorf("could not parse new trivy version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if newTrivyVersion.Major().Compare(currentTrivyVersion.Major()) > 0 {
|
||||||
|
return currentHelmVersion.IncMajor().String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if newTrivyVersion.Minor().Compare(currentTrivyVersion.Minor()) > 0 {
|
||||||
|
return currentHelmVersion.IncMinor().String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentHelmVersion.IncPatch().String(), nil
|
||||||
|
}
|
||||||
92
magefiles/helm_test.go
Normal file
92
magefiles/helm_test.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
//go:build mage_helm
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewVersion(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
currentHelmVersion string
|
||||||
|
currentTrivyVersion string
|
||||||
|
newTrivyVersion string
|
||||||
|
newHelmVersion string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"created the first patch",
|
||||||
|
"0.1.0",
|
||||||
|
"0.55.0",
|
||||||
|
"0.55.1",
|
||||||
|
"0.1.1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"created the second patch",
|
||||||
|
"0.1.1",
|
||||||
|
"0.55.1",
|
||||||
|
"0.55.2",
|
||||||
|
"0.1.2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"created the second patch but helm chart was changed",
|
||||||
|
"0.1.2",
|
||||||
|
"0.55.1",
|
||||||
|
"0.55.2",
|
||||||
|
"0.1.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"created a new minor version",
|
||||||
|
"0.1.1",
|
||||||
|
"0.55.1",
|
||||||
|
"0.56.0",
|
||||||
|
"0.2.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"created a new major version",
|
||||||
|
"0.1.1",
|
||||||
|
"0.55.1",
|
||||||
|
"1.0.0",
|
||||||
|
"1.0.0",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
newHelmVersion, err := buildNewHelmVersion(test.currentHelmVersion, test.currentTrivyVersion, test.newTrivyVersion)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, test.newHelmVersion, newHelmVersion)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBumpHelmChart_Success(t *testing.T) {
|
||||||
|
tempFile, err := os.CreateTemp(t.TempDir(), "Chart-*.yaml")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
content := `
|
||||||
|
apiVersion: v2
|
||||||
|
name: trivy
|
||||||
|
version: 0.8.0
|
||||||
|
appVersion: 0.55.0
|
||||||
|
description: Trivy helm chart
|
||||||
|
keywords:
|
||||||
|
- scanner
|
||||||
|
- trivy
|
||||||
|
- vulnerability
|
||||||
|
`
|
||||||
|
err = os.WriteFile(tempFile.Name(), []byte(content), 0644)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
newVersion, err := bumpHelmChart(tempFile.Name(), "0.55.1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "0.8.1", newVersion)
|
||||||
|
|
||||||
|
updatedContent, err := os.ReadFile(tempFile.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Contains(t, string(updatedContent), "appVersion: 0.55.1")
|
||||||
|
assert.Contains(t, string(updatedContent), "version: 0.8.1")
|
||||||
|
}
|
||||||
@@ -489,3 +489,10 @@ func (CloudActions) Generate() error {
|
|||||||
func VEX(_ context.Context, dir string) error {
|
func VEX(_ context.Context, dir string) error {
|
||||||
return sh.RunWith(ENV, "go", "run", "-tags=mage_vex", "./magefiles/vex.go", "--dir", dir)
|
return sh.RunWith(ENV, "go", "run", "-tags=mage_vex", "./magefiles/vex.go", "--dir", dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Helm mg.Namespace
|
||||||
|
|
||||||
|
// UpdateVersion updates a version for Trivy Helm Chart and creates a PR
|
||||||
|
func (Helm) UpdateVersion() error {
|
||||||
|
return sh.RunWith(ENV, "go", "run", "-tags=mage_helm", "./magefiles")
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user