chore: Update deps #361
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build & Push Images | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ["v*"] | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_PREFIX: ghcr.io/${{ github.repository_owner }}/rhacs-manager | |
| HELM_CHART_REGISTRY: oci://ghcr.io/${{ github.repository_owner }}/charts | |
| jobs: | |
| build-backend: | |
| name: Backend Image | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | |
| - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 | |
| - uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 | |
| id: meta | |
| with: | |
| images: ${{ env.IMAGE_PREFIX }}-backend | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=semver,pattern=v{{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern=v{{major}}.{{minor}} | |
| type=sha | |
| - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7 | |
| with: | |
| context: backend | |
| file: backend/Containerfile | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-frontend: | |
| name: Frontend Image | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | |
| - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 | |
| - uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 | |
| id: meta | |
| with: | |
| images: ${{ env.IMAGE_PREFIX }}-frontend | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=semver,pattern=v{{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern=v{{major}}.{{minor}} | |
| type=sha | |
| - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7 | |
| with: | |
| context: frontend | |
| file: frontend/Containerfile | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-auth-header-injector: | |
| name: Auth Header Injector Image | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | |
| - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 | |
| - uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 | |
| id: meta | |
| with: | |
| images: ${{ env.IMAGE_PREFIX }}-auth-header-injector | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=semver,pattern=v{{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern=v{{major}}.{{minor}} | |
| type=sha | |
| - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7 | |
| with: | |
| context: auth-header-injector | |
| file: auth-header-injector/Containerfile | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-mcp-server: | |
| name: MCP Server Image | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | |
| - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 | |
| - uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 | |
| id: meta | |
| with: | |
| images: ${{ env.IMAGE_PREFIX }}-mcp-server | |
| tags: | | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=semver,pattern=v{{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=semver,pattern=v{{major}}.{{minor}} | |
| type=sha | |
| - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7 | |
| with: | |
| context: mcp-server | |
| file: mcp-server/Containerfile | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-helm-chart: | |
| name: Helm Chart (OCI) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | |
| - uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5 | |
| - name: Login to GHCR for Helm OCI push | |
| run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ${{ env.REGISTRY }} -u "${{ github.actor }}" --password-stdin | |
| - name: Package Helm chart | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p .artifacts/helm | |
| base_version="$(helm show chart deploy/helm/rhacs-manager | awk '/^version:/ {print $2}')" | |
| if [[ "${{ github.ref_type }}" == "tag" ]]; then | |
| package_version="${base_version}" | |
| app_version="${base_version}" | |
| else | |
| package_version="${base_version}-main.${GITHUB_SHA::7}" | |
| app_version="${GITHUB_SHA::7}" | |
| fi | |
| helm package deploy/helm/rhacs-manager \ | |
| --destination .artifacts/helm \ | |
| --version "${package_version}" \ | |
| --app-version "${app_version}" | |
| - name: Push Helm chart to GHCR as OCI artifact | |
| run: | | |
| chart_archive="$(ls .artifacts/helm/rhacs-manager-*.tgz)" | |
| helm push "${chart_archive}" "${{ env.HELM_CHART_REGISTRY }}" | |
| create-release: | |
| name: Create GitHub Release | |
| if: ${{ startsWith(github.ref, 'refs/tags/') }} | |
| needs: | |
| - build-backend | |
| - build-frontend | |
| - build-auth-header-injector | |
| - build-mcp-server | |
| - build-helm-chart | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| packages: read | |
| env: | |
| RELEASE_TAG: ${{ github.ref_name }} | |
| BACKEND_IMAGE: ghcr.io/${{ github.repository_owner }}/rhacs-manager-backend:${{ github.ref_name }} | |
| FRONTEND_IMAGE: ghcr.io/${{ github.repository_owner }}/rhacs-manager-frontend:${{ github.ref_name }} | |
| AUTH_HEADER_INJECTOR_IMAGE: ghcr.io/${{ github.repository_owner }}/rhacs-manager-auth-header-injector:${{ github.ref_name }} | |
| MCP_SERVER_IMAGE: ghcr.io/${{ github.repository_owner }}/rhacs-manager-mcp-server:${{ github.ref_name }} | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | |
| with: | |
| fetch-depth: 0 | |
| - uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5 | |
| - name: Render Helm manifests | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p .artifacts/manifests | |
| helm template rhacs-manager deploy/helm/rhacs-manager \ | |
| -n rhacs-manager \ | |
| --set frontend.oauthProxy.cookieSecret=CHANGE_ME \ | |
| > .artifacts/manifests/rhacs-manager-hub.yaml | |
| helm template rhacs-manager-spoke deploy/helm/rhacs-manager \ | |
| -n rhacs-manager \ | |
| --set mode=spoke \ | |
| --set spoke.oauthProxy.cookieSecret=CHANGE_ME \ | |
| > .artifacts/manifests/rhacs-manager-spoke.yaml | |
| helm template rhacs-manager-hub-mcp deploy/helm/rhacs-manager \ | |
| -n rhacs-manager \ | |
| --set frontend.oauthProxy.cookieSecret=CHANGE_ME \ | |
| --set mcp.enabled=true \ | |
| --set mcp.secret.stringData.MCP_API_KEY=CHANGE_ME \ | |
| --show-only templates/frontend-deployment.yaml \ | |
| > .artifacts/manifests/rhacs-manager-hub-mcp.yaml | |
| helm template rhacs-manager-spoke-mcp deploy/helm/rhacs-manager \ | |
| -n rhacs-manager \ | |
| --set mode=spoke \ | |
| --set spoke.oauthProxy.cookieSecret=CHANGE_ME \ | |
| --set spoke.mcp.enabled=true \ | |
| --show-only templates/frontend-deployment.yaml \ | |
| > .artifacts/manifests/rhacs-manager-spoke-mcp.yaml | |
| # Strip Helm-injected labels from rendered plain YAML manifests | |
| for f in .artifacts/manifests/*.yaml; do | |
| yq -i 'del( | |
| .. | select(has("helm.sh/chart")).["helm.sh/chart"], | |
| .. | select(has("app.kubernetes.io/name")).["app.kubernetes.io/name"], | |
| .. | select(has("app.kubernetes.io/instance")).["app.kubernetes.io/instance"], | |
| .. | select(has("app.kubernetes.io/version")).["app.kubernetes.io/version"], | |
| .. | select(has("app.kubernetes.io/managed-by")).["app.kubernetes.io/managed-by"] | |
| )' "$f" | |
| yq -i 'del(.metadata.labels | select(length == 0))' "$f" | |
| yq -i 'del(.spec.template.metadata.labels | select(length == 0))' "$f" | |
| done | |
| - name: Package Helm chart | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p .artifacts/helm | |
| base_version="$(helm show chart deploy/helm/rhacs-manager | awk '/^version:/ {print $2}')" | |
| helm package deploy/helm/rhacs-manager \ | |
| --destination .artifacts/helm \ | |
| --version "${base_version}" \ | |
| --app-version "${base_version}" | |
| - uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Generate changelog for current release tag | |
| uses: orhun/git-cliff-action@v4 | |
| with: | |
| config: cliff.toml | |
| args: --current --verbose | |
| env: | |
| OUTPUT: release-notes.md | |
| GITHUB_REPO: ${{ github.repository }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Scan backend image with Trivy | |
| continue-on-error: true | |
| uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 | |
| env: | |
| TRIVY_USERNAME: ${{ github.actor }} | |
| TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| scan-type: image | |
| image-ref: ${{ env.BACKEND_IMAGE }} | |
| scanners: vuln | |
| format: json | |
| output: trivy-report-backend.json | |
| exit-code: "0" | |
| ignore-unfixed: false | |
| - name: Scan frontend image with Trivy | |
| continue-on-error: true | |
| uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 | |
| env: | |
| TRIVY_USERNAME: ${{ github.actor }} | |
| TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| scan-type: image | |
| image-ref: ${{ env.FRONTEND_IMAGE }} | |
| scanners: vuln | |
| format: json | |
| output: trivy-report-frontend.json | |
| exit-code: "0" | |
| ignore-unfixed: false | |
| - name: Scan MCP server image with Trivy | |
| continue-on-error: true | |
| uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 | |
| env: | |
| TRIVY_USERNAME: ${{ github.actor }} | |
| TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| scan-type: image | |
| image-ref: ${{ env.MCP_SERVER_IMAGE }} | |
| scanners: vuln | |
| format: json | |
| output: trivy-report-mcp-server.json | |
| exit-code: "0" | |
| ignore-unfixed: false | |
| - name: Scan auth-header-injector image with Trivy | |
| continue-on-error: true | |
| uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 | |
| env: | |
| TRIVY_USERNAME: ${{ github.actor }} | |
| TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| scan-type: image | |
| image-ref: ${{ env.AUTH_HEADER_INJECTOR_IMAGE }} | |
| scanners: vuln | |
| format: json | |
| output: trivy-report-auth-header-injector.json | |
| exit-code: "0" | |
| ignore-unfixed: false | |
| - name: Build vulnerability summary for release notes | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| shopt -s nullglob | |
| reports=(trivy-report-*.json) | |
| { | |
| echo | |
| echo "## Vulnerability Scan Summary (Trivy)" | |
| echo | |
| echo "| Image | Total | CRITICAL | HIGH | MEDIUM | LOW | UNKNOWN |" | |
| echo "| --- | ---: | ---: | ---: | ---: | ---: | ---: |" | |
| } >> release-notes.md | |
| if (( ${#reports[@]} == 0 )); then | |
| echo "| n/a | 0 | 0 | 0 | 0 | 0 | 0 |" >> release-notes.md | |
| echo >> release-notes.md | |
| echo "Trivy did not produce any JSON report files in this job." >> release-notes.md | |
| fi | |
| for report in "${reports[@]}"; do | |
| image_name="${report#trivy-report-}" | |
| image_name="${image_name%.json}" | |
| if ! jq -e . "${report}" >/dev/null 2>&1; then | |
| echo "| ${image_name} | 0 | 0 | 0 | 0 | 0 | 0 |" >> release-notes.md | |
| { | |
| echo | |
| echo "> Warning: Trivy report \`${report}\` is not valid JSON." | |
| } >> release-notes.md | |
| continue | |
| fi | |
| total="$(jq -r '[.Results[]? | (.Vulnerabilities[]?, .Packages[]?.Vulnerabilities[]?)] | length' "${report}")" | |
| critical="$(jq -r '[.Results[]? | (.Vulnerabilities[]?, .Packages[]?.Vulnerabilities[]?) | select(.Severity == "CRITICAL")] | length' "${report}")" | |
| high="$(jq -r '[.Results[]? | (.Vulnerabilities[]?, .Packages[]?.Vulnerabilities[]?) | select(.Severity == "HIGH")] | length' "${report}")" | |
| medium="$(jq -r '[.Results[]? | (.Vulnerabilities[]?, .Packages[]?.Vulnerabilities[]?) | select(.Severity == "MEDIUM")] | length' "${report}")" | |
| low="$(jq -r '[.Results[]? | (.Vulnerabilities[]?, .Packages[]?.Vulnerabilities[]?) | select(.Severity == "LOW")] | length' "${report}")" | |
| unknown="$(jq -r '[.Results[]? | (.Vulnerabilities[]?, .Packages[]?.Vulnerabilities[]?) | select(.Severity == "UNKNOWN")] | length' "${report}")" | |
| echo "| ${image_name} | ${total} | ${critical} | ${high} | ${medium} | ${low} | ${unknown} |" >> release-notes.md | |
| done | |
| { | |
| echo | |
| echo "## High/Critical Findings" | |
| echo | |
| } >> release-notes.md | |
| if (( ${#reports[@]} == 0 )); then | |
| { | |
| echo "No Trivy JSON reports were generated, so no HIGH/CRITICAL details are available." | |
| echo | |
| } >> release-notes.md | |
| fi | |
| for report in "${reports[@]}"; do | |
| image_name="${report#trivy-report-}" | |
| image_name="${image_name%.json}" | |
| { | |
| echo "### ${image_name}" | |
| echo | |
| } >> release-notes.md | |
| if ! jq -e . "${report}" >/dev/null 2>&1; then | |
| echo "Trivy report is invalid JSON." >> release-notes.md | |
| echo >> release-notes.md | |
| continue | |
| fi | |
| high_critical_count="$(jq -r '[.Results[]? | (.Vulnerabilities[]?, .Packages[]?.Vulnerabilities[]?) | select(.Severity == "CRITICAL" or .Severity == "HIGH")] | length' "${report}")" | |
| if [[ "${high_critical_count}" == "0" ]]; then | |
| echo "No HIGH/CRITICAL vulnerabilities found." >> release-notes.md | |
| echo >> release-notes.md | |
| continue | |
| fi | |
| { | |
| echo "| Severity | Vulnerability | Package | Installed | Fixed |" | |
| echo "| --- | --- | --- | --- | --- |" | |
| } >> release-notes.md | |
| jq -r ' | |
| .Results[]? | |
| | (.Vulnerabilities[]?, .Packages[]?.Vulnerabilities[]?) | |
| | select(.Severity == "CRITICAL" or .Severity == "HIGH") | |
| | [.Severity, .VulnerabilityID, .PkgName, .InstalledVersion, (.FixedVersion // "n/a")] | |
| | @tsv | |
| ' "${report}" | awk 'NR<=20' | while IFS=$'\t' read -r severity vuln_id pkg installed fixed; do | |
| echo "| ${severity} | ${vuln_id} | ${pkg} | ${installed} | ${fixed} |" >> release-notes.md | |
| done | |
| echo >> release-notes.md | |
| done | |
| - name: Create GitHub release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| shopt -s nullglob | |
| report_files=(trivy-report-*.json) | |
| manifest_files=(.artifacts/manifests/*.yaml) | |
| chart_files=(.artifacts/helm/*.tgz) | |
| attach_files=("${report_files[@]}" "${manifest_files[@]}" "${chart_files[@]}") | |
| if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then | |
| gh release edit "${RELEASE_TAG}" \ | |
| --title "Release ${RELEASE_TAG}" \ | |
| --notes-file release-notes.md | |
| if (( ${#attach_files[@]} > 0 )); then | |
| gh release upload "${RELEASE_TAG}" "${attach_files[@]}" --clobber | |
| fi | |
| exit 0 | |
| fi | |
| if (( ${#attach_files[@]} > 0 )); then | |
| gh release create "${RELEASE_TAG}" \ | |
| --title "Release ${RELEASE_TAG}" \ | |
| --notes-file release-notes.md \ | |
| "${attach_files[@]}" | |
| exit 0 | |
| fi | |
| gh release create "${RELEASE_TAG}" \ | |
| --title "Release ${RELEASE_TAG}" \ | |
| --notes-file release-notes.md |