Skip to content

CI on "renovate/release-5.5-python-dependencies" by @renovate[bot] #38636

CI on "renovate/release-5.5-python-dependencies" by @renovate[bot]

CI on "renovate/release-5.5-python-dependencies" by @renovate[bot] #38636

Workflow file for this run

name: CI
run-name: CI on "${{ github.head_ref && github.head_ref || github.ref }}" by @${{ github.actor }}
on:
pull_request:
branches:
- main
- release-*
merge_group:
workflow_dispatch:
inputs:
force:
type: boolean
description: "Force rebuild"
required: false
default: false
run_tests:
type: boolean
description: "Run unit & e2e tests"
required: false
default: true
defaults:
run:
shell: bash
concurrency:
group: ${{ github.ref_name }}-ci
cancel-in-progress: true
permissions:
contents: read
jobs:
checks:
name: Checks and variables
if: github.repository == 'nginx/kubernetes-ingress'
runs-on: ubuntu-24.04
permissions:
contents: read
id-token: write
outputs:
docs_only: ${{ github.event.pull_request && steps.docs.outputs.docs_only == 'true' }}
k8s_latest: ${{ steps.vars.outputs.k8s_latest }}
go_path: ${{ steps.vars.outputs.go_path }}
go_code_md5: ${{ steps.vars.outputs.go_code_md5 }}
go_proxy: ${{ steps.vars.outputs.go_proxy }}
binary_cache_hit: ${{ steps.binary-cache.outputs.cache-hit }}
chart_version: ${{ steps.vars.outputs.chart_version }}
ic_version: ${{ steps.vars.outputs.ic_version }}
docker_md5: ${{ steps.vars.outputs.docker_md5 }}
build_tag: ${{ steps.vars.outputs.build_tag }}
stable_tag: ${{ steps.vars.outputs.stable_tag }}
forked_workflow: ${{ steps.vars.outputs.forked_workflow }}
stable_image_exists: ${{ steps.stable_exists.outputs.exists }}
additional_tag: ${{ steps.vars.outputs.additional_tag }}
image_matrix_oss: ${{ steps.vars.outputs.image_matrix_oss }}
image_matrix_plus: ${{ steps.vars.outputs.image_matrix_plus }}
image_matrix_nap: ${{ steps.vars.outputs.image_matrix_nap }}
docker_build: ${{ steps.docker_build.outputs.docker_build }}
run_tests: ${{ steps.run_tests.outputs.run_tests }}
steps:
- name: Checkout Repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
- name: Filter only docs changes
id: docs
run: |
./.github/scripts/variables.sh docs_only >> $GITHUB_OUTPUT
cat $GITHUB_OUTPUT
shell: bash --noprofile --norc -o pipefail {0}
- name: Setup Golang Environment
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Configure pipeline Variables
id: vars
run: |
./.github/scripts/variables.sh k8s_latest_version >> $GITHUB_OUTPUT
echo "go_path=$(go env GOPATH)" >> $GITHUB_OUTPUT
source .github/data/version.txt
echo "ic_version=${IC_VERSION}" >> $GITHUB_OUTPUT
echo "chart_version=${HELM_CHART_VERSION}" >> $GITHUB_OUTPUT
forked_workflow=${{ (github.event.pull_request && github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name) || github.repository != 'nginx/kubernetes-ingress' }}
echo "forked_workflow=${forked_workflow}" >> $GITHUB_OUTPUT
echo "go_proxy=https://proxy.golang.org,direct" >> $GITHUB_OUTPUT
./.github/scripts/variables.sh go_code_md5 >> $GITHUB_OUTPUT
./.github/scripts/variables.sh docker_md5 >> $GITHUB_OUTPUT
./.github/scripts/variables.sh build_tag >> $GITHUB_OUTPUT
./.github/scripts/variables.sh stable_tag >> $GITHUB_OUTPUT
REF=${{ github.ref_name }} ./.github/scripts/variables.sh additional_tag >> $GITHUB_OUTPUT
echo "image_matrix_oss=$(cat .github/data/matrix-images-oss.json | jq -c)" >> $GITHUB_OUTPUT
echo "image_matrix_plus=$(cat .github/data/matrix-images-plus.json | jq -c)" >> $GITHUB_OUTPUT
echo "image_matrix_nap=$(cat .github/data/matrix-images-nap.json | jq -c)" >> $GITHUB_OUTPUT
- name: Fetch Cached Binary Artifacts
id: binary-cache
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: ${{ github.workspace }}/dist
key: nginx-ingress-${{ steps.vars.outputs.go_code_md5 }}
lookup-only: true
- name: Azure login
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }}
if: ${{ steps.vars.outputs.forked_workflow == 'false' }}
- name: Setup secrets
id: secrets
run: |
echo "Setting secrets for job"
GCR_WORKLOAD_ID=$(az keyvault secret show --name gcr-workload-identity --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$GCR_WORKLOAD_ID"
echo "GCR_WORKLOAD_ID=$GCR_WORKLOAD_ID" >> $GITHUB_OUTPUT
GCR_SERVICE_ACCOUNT=$(az keyvault secret show --name kic-pipeline-gcr-sa --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$GCR_SERVICE_ACCOUNT"
echo "GCR_SERVICE_ACCOUNT=$GCR_SERVICE_ACCOUNT" >> $GITHUB_OUTPUT
if: ${{ steps.vars.outputs.forked_workflow == 'false' }}
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
token_format: access_token
workload_identity_provider: ${{ steps.secrets.outputs.GCR_WORKLOAD_ID }}
service_account: ${{ steps.secrets.outputs.GCR_SERVICE_ACCOUNT }}
if: ${{ steps.vars.outputs.forked_workflow == 'false' }}
- name: Login to GCR
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
registry: gcr.io
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
if: ${{ steps.vars.outputs.forked_workflow == 'false' }}
- name: Check if stable image exists
id: stable_exists
run: |
exists=false
if docker pull gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:${{ steps.vars.outputs.stable_tag }}; then
exists=true
fi
echo "exists=${exists}" >> $GITHUB_OUTPUT
if: ${{ steps.vars.outputs.forked_workflow == 'false' }}
- name: Check if docker build is needed
id: docker_build
run: |
docker_build="false"
if [ "${{ inputs.force }}" = "true" ]; then
docker_build="true"
elif [ "${{ steps.vars.outputs.forked_workflow }}" = "true" ] && [ "${{ steps.docs.outputs.docs_only }}" = "false" ]; then
docker_build="true"
elif [ "${{ steps.vars.outputs.forked_workflow }}" = "false" ] && [ "${{ steps.docs.outputs.docs_only }}" = "false" ] && [ "${{ steps.binary-cache.outputs.cache-hit }}" != "true" ]; then
docker_build="true"
elif [ "${{ steps.vars.outputs.forked_workflow }}" = "false" ] && [ "${{ steps.docs.outputs.docs_only }}" = "false" ] && [ "${{ steps.stable_exists.outputs.exists }}" != "true" ]; then
docker_build="true"
fi
echo "docker_build=${docker_build}" >> $GITHUB_OUTPUT
- name: Check if tests should be run
id: run_tests
run: |
run_tests="true"
if [ "${{ inputs.run_tests }}" = "false" ]; then
run_tests="false"
elif [ "${{ steps.docs.outputs.docs_only }}" = "true" ]; then
run_tests="false"
elif [ "${{ steps.binary-cache.outputs.cache-hit }}" = "true" ] && [ "${{ steps.vars.outputs.stable_image_exists }}" = "true" ]; then
run_tests="false"
fi
echo "run_tests=${run_tests}" >> $GITHUB_OUTPUT
- name: Output variables
run: |
echo docs_only: ${{ github.event.pull_request && steps.docs.outputs.docs_only == 'true' }}
echo k8s_latest: ${{ steps.vars.outputs.k8s_latest }}
echo go_path: ${{ steps.vars.outputs.go_path }}
echo go_code_md5: ${{ steps.vars.outputs.go_code_md5 }}
echo binary_cache_hit: ${{ steps.binary-cache.outputs.cache-hit }}
echo chart_version: ${{ steps.vars.outputs.chart_version }}
echo ic_version: ${{ steps.vars.outputs.ic_version }}
echo docker_md5: ${{ steps.vars.outputs.docker_md5 }}
echo build_tag: ${{ steps.vars.outputs.build_tag }}
echo stable_tag: ${{ steps.vars.outputs.stable_tag }}
echo forked_workflow: ${{ steps.vars.outputs.forked_workflow }}
echo stable_image_exists: ${{ steps.stable_exists.outputs.exists }}
echo additional_tag: ${{ steps.vars.outputs.additional_tag }}
echo 'image_matrix_oss: ${{ steps.vars.outputs.image_matrix_oss }}'
echo 'image_matrix_plus: ${{ steps.vars.outputs.image_matrix_plus }}'
echo 'image_matrix_nap: ${{ steps.vars.outputs.image_matrix_nap }}'
echo 'docker_build: ${{ steps.docker_build.outputs.docker_build }}'
echo 'run_tests: ${{ steps.run_tests.outputs.run_tests }}'
verify-codegen:
name: Verify generated code
runs-on: ubuntu-24.04
permissions:
contents: read
needs: checks
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
inputs.force ||
needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true'
)
env:
GOPROXY: ${{ needs.checks.outputs.go_proxy }}
steps:
- name: Checkout Repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Golang Environment
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Check if go.mod and go.sum are up to date
run: go mod tidy && git diff --exit-code -- go.mod go.sum
- name: Check if CRDs changed
run: make update-crds && git diff --name-only --exit-code config/crd/bases
- name: Check if Codegen changed
run: |
cd ../.. && mkdir -p github.com/nginx && mv kubernetes-ingress/kubernetes-ingress github.com/nginx/ && cd github.com/nginx/kubernetes-ingress
make update-codegen && git diff --name-only --exit-code pkg/**
cd ../../.. && mv github.com/nginx/kubernetes-ingress kubernetes-ingress/kubernetes-ingress
- name: Install gofumpt
run: go install mvdan.cc/gofumpt@v0.8.0
- name: Check if telemetry schema changed
run: |
export PATH=$PATH:$(go env GOPATH)/bin
make telemetry-schema && git diff --name-only --exit-code internal/telemetry
unit-tests:
name: Unit Tests
if: github.repository == 'nginx/kubernetes-ingress'
runs-on: ubuntu-24.04
permissions:
contents: read
id-token: write
needs: checks
env:
GOPROXY: ${{ needs.checks.outputs.go_proxy }}
steps:
- name: Checkout Repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
with:
version: v3.21.3 # renovate: datasource=github-releases depName=helm/helm
if: >-
inputs.force ||
needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true'
- name: Azure login
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }}
if: >-
inputs.force ||
needs.checks.outputs.forked_workflow == 'false' &&
(needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true')
- name: Setup secrets
id: secrets
run: |
echo "Setting secrets for job"
CODECOV_TOKEN=$(az keyvault secret show --name code-cov --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$CODECOV_TOKEN"
echo "CODECOV_TOKEN=$CODECOV_TOKEN" >> $GITHUB_OUTPUT
if: >-
inputs.force ||
needs.checks.outputs.forked_workflow == 'false' &&
(needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true')
- name: Setup Golang Environment
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
if: >-
inputs.force ||
needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true'
- name: Generate secrets for tests
run: |
make secrets
if: >-
inputs.force ||
needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true'
- name: Run Tests
run: make cover
if: >-
inputs.force ||
needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true'
- name: Upload coverage to Codecov
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v6.0.2
with:
files: ./coverage.txt
token: ${{ steps.secrets.outputs.CODECOV_TOKEN }} # required
if: >-
inputs.force ||
(needs.checks.outputs.forked_workflow == 'false' &&
(needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true'))
staticcheck:
name: Static Check
runs-on: ubuntu-24.04
permissions:
contents: read
needs: checks
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
inputs.force ||
needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true'
)
env:
GOPROXY: ${{ needs.checks.outputs.go_proxy }}
steps:
- name: Checkout Repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Golang Environment
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Generate secrets for tests
run: |
make secrets
- name: Run Static Check
uses: dominikh/staticcheck-action@9716614d4101e79b4340dd97b10e54d68234e431 # v1.4.1
with:
version: "2026.1" # renovate: datasource=github-releases depName=dominikh/go-tools
install-go: false
use-cache: true
govulncheck:
name: Vulnerability Check
runs-on: ubuntu-24.04
permissions:
contents: read
needs: checks
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
inputs.force ||
needs.checks.outputs.run_tests == 'true' &&
needs.checks.outputs.binary_cache_hit != 'true'
)
env:
GOPROXY: ${{ needs.checks.outputs.go_proxy }}
steps:
- name: Checkout Repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Golang Environment
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Run govulncheck
uses: golang/govulncheck-action@032d45514ae346b1db93c04b0c90b841c370344f # v1.1.0
with:
repo-checkout: false
cache: true
build-artifacts:
name: Build Artifacts
needs: [checks, unit-tests]
if: github.repository == 'nginx/kubernetes-ingress'
uses: ./.github/workflows/build-artifacts.yml
with:
force: ${{ needs.checks.outputs.docker_build == 'true' }}
branch: ${{ (github.head_ref && needs.checks.outputs.forked_workflow == 'false') && github.head_ref || github.ref }}
tag: ${{ needs.checks.outputs.build_tag }}
docker-md5: ${{ needs.checks.outputs.docker_md5 }}
go-md5: ${{ needs.checks.outputs.go_code_md5 }}
go-path: ${{ needs.checks.outputs.go_path }}
go-proxy: ${{ needs.checks.outputs.go_proxy }}
image-matrix-oss: ${{ needs.checks.outputs.image_matrix_oss }}
image-matrix-plus: ${{ needs.checks.outputs.image_matrix_plus }}
image-matrix-nap: ${{ needs.checks.outputs.image_matrix_nap }}
ic-version: ${{ needs.checks.outputs.ic_version }}
authenticated: ${{ needs.checks.outputs.forked_workflow == 'false' }}
runner: ubuntu-24.04
write-to-cache: ${{ github.ref_name == github.event.repository.default_branch && true || false }}
permissions:
contents: read
actions: read
id-token: write
packages: write
pull-requests: write # for scout report
secrets: inherit
tag-target:
name: Tag untested image with PR number
needs: [checks, build-artifacts]
permissions:
contents: read # To checkout repository
id-token: write # To sign into Google Container Registry
uses: ./.github/workflows/retag-images.yml
with:
source_tag: ${{ needs.checks.outputs.build_tag }}
target_tag: ${{ needs.checks.outputs.additional_tag }}
dry_run: false
secrets: inherit
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
needs.checks.outputs.forked_workflow == 'false' &&
(needs.checks.outputs.run_tests == 'true' ||
needs.checks.outputs.docker_build == 'true')
)
package-tests:
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
needs.checks.outputs.run_tests == 'true' ||
needs.checks.outputs.docker_build == 'true'
)
name: Package Tests
runs-on: ubuntu-24.04
needs: [checks, build-artifacts]
permissions:
contents: read
pull-requests: write # for package report
id-token: write
steps:
- name: Checkout Repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup QEMU
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
with:
platforms: arm64
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Azure login
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Setup secrets
id: secrets
run: |
echo "Setting secrets for job"
GCR_WORKLOAD_ID=$(az keyvault secret show --name gcr-workload-identity --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$GCR_WORKLOAD_ID"
echo "GCR_WORKLOAD_ID=$GCR_WORKLOAD_ID" >> $GITHUB_OUTPUT
GCR_SERVICE_ACCOUNT=$(az keyvault secret show --name kic-pipeline-gcr-sa --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$GCR_SERVICE_ACCOUNT"
echo "GCR_SERVICE_ACCOUNT=$GCR_SERVICE_ACCOUNT" >> $GITHUB_OUTPUT
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
token_format: access_token
workload_identity_provider: ${{ steps.secrets.outputs.GCR_WORKLOAD_ID }}
service_account: ${{ steps.secrets.outputs.GCR_SERVICE_ACCOUNT }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Login to GCR
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
registry: gcr.io
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Install Python dependencies
run: |
make -f tests/Makefile setup-venv
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Run tests
id: packages
run: |
source tests/venv/bin/activate
python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }} --log package_output.txt
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Add comment
run: |
# make sure the comment is formatted correctly, as a code block
echo '### Package Report' > output.txt
echo '<details>' >> output.txt
cat package_output.txt | sed -r 's#^(.*)$#\1<br>#' >> output.txt
echo '</details>' >> output.txt
gh pr comment --edit-last --create-if-none ${{ github.event.pull_request.number }} -F output.txt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: ${{ ( needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' ) && github.event.pull_request }}
helm-tests:
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
needs.checks.outputs.run_tests == 'true' ||
needs.checks.outputs.docker_build == 'true'
)
name: Helm Tests ${{ matrix.base-os }}
runs-on: ubuntu-24.04
needs: [checks, build-artifacts]
strategy:
fail-fast: false
matrix:
include:
- base-os: debian
image: gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress
tag: ${{ needs.checks.outputs.build_tag }}
type: oss
- base-os: debian-plus
image: gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress
tag: ${{ needs.checks.outputs.build_tag }}
type: plus
permissions:
contents: read
id-token: write
steps:
- name: Checkout Repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Setup Helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
with:
version: v3.21.3 # renovate: datasource=github-releases depName=helm/helm
- name: Azure login
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }}
if: ${{ needs.checks.outputs.forked_workflow != 'true' }}
- name: Setup secrets
id: secrets
run: |
echo "Setting secrets for job"
GCR_WORKLOAD_ID=$(az keyvault secret show --name gcr-workload-identity --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$GCR_WORKLOAD_ID"
echo "GCR_WORKLOAD_ID=$GCR_WORKLOAD_ID" >> $GITHUB_OUTPUT
GCR_SERVICE_ACCOUNT=$(az keyvault secret show --name kic-pipeline-gcr-sa --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$GCR_SERVICE_ACCOUNT"
echo "GCR_SERVICE_ACCOUNT=$GCR_SERVICE_ACCOUNT" >> $GITHUB_OUTPUT
PLUS_CREDS=$(az keyvault secret show --name plus-creds --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$PLUS_CREDS"
PLUS_JWT=$(echo $PLUS_CREDS | jq -r '.jwt')
echo "::add-mask::$PLUS_JWT"
echo "PLUS_JWT=$PLUS_JWT" >> $GITHUB_OUTPUT
IFS=@ CERT=$(echo $PLUS_CREDS | jq -r '.crt')
while read -r line; do
echo "::add-mask::${line}"
done <<< "${CERT}"
echo $CERT > nginx-repo.crt
IFS=@ KEY=$(echo $PLUS_CREDS | jq -r '.key')
while read -r line; do
echo "::add-mask::${line}"
done <<< "${KEY}"
echo $KEY > nginx-repo.key
if: ${{ needs.checks.outputs.forked_workflow != 'true' }}
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
token_format: access_token
workload_identity_provider: ${{ steps.secrets.outputs.GCR_WORKLOAD_ID }}
service_account: ${{ steps.secrets.outputs.GCR_SERVICE_ACCOUNT }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' }}
- name: Login to GCR
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
registry: gcr.io
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' }}
- name: Check if stable image exists
id: stable_exists
run: |
if docker pull ${{ matrix.image }}:${{ needs.checks.outputs.stable_tag }}; then
echo "exists=true" >> $GITHUB_OUTPUT
fi
if: ${{ needs.checks.outputs.forked_workflow == 'false' }}
- name: Pull build image
run: |
docker pull ${{ matrix.image }}:${{ needs.checks.outputs.build_tag }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' && steps.stable_exists.outputs.exists != 'true' }}
- name: Fetch Cached Artifacts
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0
with:
path: ${{ github.workspace }}/dist
key: nginx-ingress-${{ needs.checks.outputs.go_code_md5 }}
if: ${{ needs.checks.outputs.forked_workflow == 'true' }}
- name: Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
if: ${{ needs.checks.outputs.forked_workflow == 'true' }}
- name: Build Docker Image ${{ matrix.base-os }}
uses: ./.github/actions/build-push-retry
with:
file: build/Dockerfile
context: "."
cache-from: type=gha,scope=${{ matrix.base-os }}
target: goreleaser
tags: "${{ matrix.image }}:${{ matrix.tag }}"
pull: true
load: true
build-args: |
BUILD_OS=${{ matrix.base-os }}
IC_VERSION=CI
secret-files: |
${{ matrix.type == 'plus' && 'nginx-repo.crt=nginx-repo.crt' || '' }}
${{ matrix.type == 'plus' && 'nginx-repo.key=nginx-repo.key' || '' }}
if: ${{ needs.checks.outputs.forked_workflow == 'true' }}
- name: Deploy Kubernetes
id: k8s
run: |
kind create cluster --name ${{ github.run_id }} --image=kindest/node:v${{ needs.checks.outputs.k8s_latest }} --wait 75s
docker version
docker save "${{ matrix.image }}:${{ matrix.tag }}" | \
docker exec -i ${{ github.run_id }}-control-plane \
ctr --namespace=k8s.io images import -
echo "DEBUG: Kind setup complete!"
if: ${{ steps.stable_exists.outputs.exists != 'true' }}
- name: Create Plus Secret
run: kubectl create secret generic license-token --from-literal=license.jwt="${{ steps.secrets.outputs.PLUS_JWT }}" --type="nginx.com/license"
if: ${{ matrix.type == 'plus' && steps.stable_exists.outputs.exists != 'true' }}
- name: Install Chart
run: >
helm install
${{ matrix.type }}
.
--set controller.image.repository=${{ matrix.image }}
--set controller.image.tag=${{ matrix.tag }}
--set controller.service.type=NodePort
--set controller.nginxplus=${{ contains(matrix.type, 'plus') && 'true' || 'false' }}
--set controller.telemetryReporting.enable=false
--wait
working-directory: ${{ github.workspace }}/charts/nginx-ingress
if: ${{ steps.stable_exists.outputs.exists != 'true' }}
- name: Expose Test Ingresses
run: |
kubectl port-forward service/${{ matrix.type }}-nginx-ingress-controller 8080:80 8443:443 &
if: ${{ steps.stable_exists.outputs.exists != 'true' }}
- name: Test HTTP
run: |
counter=0
max_attempts=5
until [ $(curl --write-out %{http_code} -s --output /dev/null http://localhost:8080) -eq 404 ]; do
if [ ${counter} -eq ${max_attempts} ]; then
exit 1
fi
printf '.'; counter=$(($counter+1)); sleep 5;
done
if: ${{ steps.stable_exists.outputs.exists != 'true' }}
- name: Test HTTPS
run: |
counter=0
max_attempts=5
until [ $(curl --write-out %{http_code} -ks --output /dev/null https://localhost:8443) -eq 000 ]; do
if [ ${counter} -eq ${max_attempts} ]; then
exit 1
fi
printf '.'; counter=$(($counter+1)); sleep 5;
done
if: ${{ steps.stable_exists.outputs.exists != 'true' }}
- name: Clean up secrets
run: |
rm -f nginx-repo.crt nginx-repo.key
if: always()
setup-matrix:
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
needs.checks.outputs.run_tests == 'true' ||
needs.checks.outputs.docker_build == 'true'
)
name: Setup Matrix for Smoke Tests
runs-on: ubuntu-24.04
needs: [build-artifacts, checks]
permissions:
contents: read
id-token: write
outputs:
matrix_oss: ${{ steps.set-matrix.outputs.matrix_oss }}
matrix_plus: ${{ steps.set-matrix.outputs.matrix_plus }}
matrix_nap: ${{ steps.set-matrix.outputs.matrix_nap }}
steps:
- name: Checkout Repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- id: set-matrix
run: |
echo "matrix_oss=$(cat .github/data/matrix-smoke-oss.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT
echo "matrix_plus=$(cat .github/data/matrix-smoke-plus.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT
echo "matrix_nap=$(cat .github/data/matrix-smoke-nap.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT
- name: Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Azure login
uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43 # v3.0.0
with:
client-id: ${{ secrets.AZURE_VAULT_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_VAULT_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_VAULT_SUBSCRIPTION_ID }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' }}
- name: Setup secrets
id: secrets
run: |
echo "Setting secrets for job"
GCR_WORKLOAD_ID=$(az keyvault secret show --name gcr-workload-identity --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$GCR_WORKLOAD_ID"
echo "GCR_WORKLOAD_ID=$GCR_WORKLOAD_ID" >> $GITHUB_OUTPUT
GCR_SERVICE_ACCOUNT=$(az keyvault secret show --name kic-pipeline-gcr-sa --vault-name ${{ secrets.NIC_KEYVAULT_NAME }} --query value -o tsv)
echo "::add-mask::$GCR_SERVICE_ACCOUNT"
echo "GCR_SERVICE_ACCOUNT=$GCR_SERVICE_ACCOUNT" >> $GITHUB_OUTPUT
if: ${{ needs.checks.outputs.forked_workflow == 'false' }}
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
token_format: access_token
workload_identity_provider: ${{ steps.secrets.outputs.GCR_WORKLOAD_ID }}
service_account: ${{ steps.secrets.outputs.GCR_SERVICE_ACCOUNT }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' }}
- name: Login to GCR
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
registry: gcr.io
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' }}
- name: Check if test image exists
id: check-image
run: |
docker pull gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/test-runner:${{ hashFiles('./tests/requirements.txt', './tests/Dockerfile') || 'latest' }}
shell: bash
continue-on-error: true
if: ${{ needs.checks.outputs.forked_workflow == 'false' }}
- name: Build Test-Runner Container
uses: ./.github/actions/build-push-retry
with:
file: tests/Dockerfile
context: "."
cache-from: type=gha,scope=test-runner
tags: "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/test-runner:${{ hashFiles('./tests/requirements.txt', './tests/Dockerfile') || 'latest' }}"
pull: true
push: ${{ needs.checks.outputs.forked_workflow == 'false' }}
load: false
if: ${{ steps.check-image.outcome == 'failure' }}
smoke-tests-oss:
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
needs.checks.outputs.run_tests == 'true' ||
needs.checks.outputs.docker_build == 'true'
)
name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests
needs:
- checks
- setup-matrix
- build-artifacts
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_oss) }}
permissions:
contents: read
id-token: write
uses: ./.github/workflows/setup-smoke.yml
secrets: inherit
with:
image: ${{ matrix.images.image }}
target: ${{ matrix.images.target }}
nap-modules: ${{ matrix.images.nap_modules }}
marker: ${{ matrix.images.marker }}
label: ${{ matrix.images.label }}
go-md5: ${{ needs.checks.outputs.go_code_md5 }}
build-tag: ${{ needs.checks.outputs.build_tag }}
stable-tag: ${{ needs.checks.outputs.stable_tag }}
authenticated: ${{ needs.checks.outputs.forked_workflow == 'false' }}
k8s-version: ${{ matrix.k8s }}
force: ${{ needs.checks.outputs.run_tests == 'true' }}
smoke-tests-plus:
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
needs.checks.outputs.run_tests == 'true' ||
needs.checks.outputs.docker_build == 'true'
)
name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests
needs:
- checks
- setup-matrix
- build-artifacts
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_plus) }}
permissions:
contents: read
id-token: write
uses: ./.github/workflows/setup-smoke.yml
secrets: inherit
with:
image: ${{ matrix.images.image }}
target: ${{ matrix.images.target }}
nap-modules: ${{ matrix.images.nap_modules }}
marker: ${{ matrix.images.marker }}
label: ${{ matrix.images.label }}
go-md5: ${{ needs.checks.outputs.go_code_md5 }}
build-tag: ${{ needs.checks.outputs.build_tag }}
stable-tag: ${{ needs.checks.outputs.stable_tag }}
authenticated: ${{ needs.checks.outputs.forked_workflow == 'false' }}
k8s-version: ${{ matrix.k8s }}
force: ${{ needs.checks.outputs.run_tests == 'true' }}
smoke-tests-nap:
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
needs.checks.outputs.run_tests == 'true' ||
needs.checks.outputs.docker_build == 'true'
)
name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests
needs:
- checks
- setup-matrix
- build-artifacts
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_nap) }}
permissions:
contents: read
id-token: write
uses: ./.github/workflows/setup-smoke.yml
secrets: inherit
with:
image: ${{ matrix.images.image }}
target: ${{ matrix.images.target }}
nap-modules: ${{ matrix.images.nap_modules }}
marker: ${{ matrix.images.marker }}
label: ${{ matrix.images.label }}
go-md5: ${{ needs.checks.outputs.go_code_md5 }}
build-tag: ${{ needs.checks.outputs.build_tag }}
stable-tag: ${{ needs.checks.outputs.stable_tag }}
authenticated: ${{ needs.checks.outputs.forked_workflow == 'false' }}
k8s-version: ${{ matrix.k8s }}
force: ${{ needs.checks.outputs.run_tests == 'true' }}
tag-stable:
name: Tag tested image as stable
needs: [checks, build-artifacts, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap]
permissions:
contents: read # To checkout repository
id-token: write # To sign into Google Container Registry
uses: ./.github/workflows/retag-images.yml
with:
source_tag: ${{ needs.checks.outputs.build_tag }}
target_tag: ${{ needs.checks.outputs.stable_tag }}
dry_run: false
secrets: inherit
if: >-
github.repository == 'nginx/kubernetes-ingress' && (
(needs.checks.outputs.forked_workflow == 'false' &&
needs.checks.outputs.stable_image_exists != 'true')
)
final-results:
if: github.repository == 'nginx/kubernetes-ingress' && (!cancelled())
runs-on: ubuntu-24.04
name: Final CI Results
needs: [tag-stable, build-artifacts, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap, package-tests, helm-tests, staticcheck, govulncheck]
steps:
- run: |
tagResult="${{ needs.tag-stable.result }}"
packageResult="${{ needs.package-tests.result }}"
helmResult="${{ needs.helm-tests.result }}"
smokeOSSResult="${{ needs.smoke-tests-oss.result }}"
smokePlusResult="${{ needs.smoke-tests-plus.result }}"
smokeNAPResult="${{ needs.smoke-tests-nap.result }}"
buildArtifactsResult="${{ needs.build-artifacts.result }}"
staticcheckResult="${{ needs.staticcheck.result }}"
govulncheckResult="${{ needs.govulncheck.result }}"
if [[ $tagResult != "success" && $tagResult != "skipped" ]]; then
exit 1
fi
if [[ $smokeOSSResult != "success" && $smokeOSSResult != "skipped" ]]; then
exit 1
fi
if [[ $smokePlusResult != "success" && $smokePlusResult != "skipped" ]]; then
exit 1
fi
if [[ $smokeNAPResult != "success" && $smokeNAPResult != "skipped" ]]; then
exit 1
fi
if [[ $buildArtifactsResult != "success" && $buildArtifactsResult != "skipped" ]]; then
exit 1
fi
if [[ $helmResult != "success" && $helmResult != "skipped" ]]; then
exit 1
fi
if [[ $packageResult != "success" && $packageResult != "skipped" ]]; then
exit 1
fi
if [[ $staticcheckResult != "success" && $staticcheckResult != "skipped" ]]; then
exit 1
fi
if [[ $govulncheckResult != "success" && $govulncheckResult != "skipped" ]]; then
exit 1
fi
trigger-image-promotion:
name: Promote images on Force Run
needs:
- final-results
- build-artifacts
permissions:
contents: write # for pushing to Helm Charts repository
id-token: write # To sign into Google Container Registry
actions: read
packages: write # for helm to push to GHCR
security-events: write
pull-requests: write # for scout report
uses: ./.github/workflows/image-promotion.yml
secrets: inherit
if: github.repository == 'nginx/kubernetes-ingress' && (inputs.force && (github.ref_name == 'main' || startsWith(github.ref_name, 'release-')))