| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- # Reusable kind-based e2e pipeline, split into two jobs so the disk-heavy build
- # and the kind test run never share a runner. The build job compiles the
- # controller + e2e images and exports them as tarballs; the test job loads those
- # tarballs into kind and runs the suite, needing no Go toolchain or buildx.
- name: e2e reusable
- on:
- workflow_call:
- secrets:
- GCP_SERVICE_ACCOUNT_KEY:
- required: false
- GCP_FED_REGION:
- required: false
- GCP_GSA_NAME:
- required: false
- GCP_KSA_NAME:
- required: false
- GCP_FED_PROJECT_ID:
- required: false
- AWS_OIDC_ROLE_ARN:
- required: false
- AWS_SA_NAME:
- required: false
- AWS_SA_NAMESPACE:
- required: false
- TFC_AZURE_CLIENT_ID:
- required: false
- TFC_AZURE_CLIENT_SECRET:
- required: false
- TFC_AZURE_TENANT_ID:
- required: false
- TFC_AZURE_SUBSCRIPTION_ID:
- required: false
- TFC_VAULT_URL:
- required: false
- SCALEWAY_API_URL:
- required: false
- SCALEWAY_REGION:
- required: false
- SCALEWAY_PROJECT_ID:
- required: false
- SCALEWAY_ACCESS_KEY:
- required: false
- SCALEWAY_SECRET_KEY:
- required: false
- DELINEA_TLD:
- required: false
- DELINEA_URL_TEMPLATE:
- required: false
- DELINEA_TENANT:
- required: false
- DELINEA_CLIENT_ID:
- required: false
- DELINEA_CLIENT_SECRET:
- required: false
- SECRETSERVER_USERNAME:
- required: false
- SECRETSERVER_PASSWORD:
- required: false
- SECRETSERVER_URL:
- required: false
- GRAFANA_URL:
- required: false
- GRAFANA_TOKEN:
- required: false
- AKEYLESS_ACCESS_ID:
- required: false
- AKEYLESS_ACCESS_TYPE:
- required: false
- AKEYLESS_ACCESS_TYPE_PARAM:
- required: false
- GITLAB_TOKEN:
- required: false
- GITLAB_PROJECT_ID:
- required: false
- GITLAB_ENVIRONMENT:
- required: false
- ORACLE_USER_OCID:
- required: false
- ORACLE_TENANCY_OCID:
- required: false
- ORACLE_REGION:
- required: false
- ORACLE_FINGERPRINT:
- required: false
- ORACLE_KEY:
- required: false
- ORACLE_VAULT_OCID:
- required: false
- ORACLE_COMPARTMENT_OCID:
- required: false
- ORACLE_ENCRYPTION_KEY_OCID:
- required: false
- permissions:
- contents: read
- env:
- KIND_VERSION: 'v0.30.0'
- KIND_IMAGE: 'kindest/node:v1.33.4'
- AWS_REGION: "eu-central-1"
- # SHA under test on the fork path. Populated by a dispatcher: an explicit
- # `/ok-to-test sha=<sha>` comment (ok-to-test.yml), or the reviewed commit_id
- # of a PR review carrying /ok-to-test (ok-to-test-review.yml). Empty on the
- # trusted pull_request path, where the checkout falls back to github.sha (the
- # PR merge ref).
- TARGET_SHA: ${{ github.event.client_payload.slash_command.args.named.sha }}
- # Ephemeral tag: images are only ever loaded into kind, never pushed, so a
- # fixed tag keeps the build and test jobs in sync without passing a version.
- VERSION: "e2e"
- jobs:
- # Turn e2e/matrix.yaml into the test job's strategy matrix. Validating here
- # (check-matrix.sh) fails the run early if a provider was added to the suite
- # without a covering leg, rather than letting it go silently untested.
- prepare-matrix:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- outputs:
- matrix: ${{ steps.set.outputs.matrix }}
- steps:
- - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
- with:
- egress-policy: audit
- - name: Checkout
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- ref: ${{ env.TARGET_SHA || github.sha }}
- persist-credentials: false
- - name: Validate and build the e2e matrix
- id: set
- # This job has no secrets in scope. matrix.py reads only matrix.yaml and
- # the workflow text, so the plan below proves per-leg credential scoping
- # without ever touching a secret value.
- run: |
- ./e2e/matrix.py check
- ./e2e/matrix.py plan
- matrix="$(./e2e/matrix.py json)"
- echo "matrix=${matrix}" >> "$GITHUB_OUTPUT"
- build:
- runs-on: ubuntu-latest
- permissions:
- contents: read
- steps:
- - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
- with:
- egress-policy: audit
- - name: Checkout
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- ref: ${{ env.TARGET_SHA || github.sha }}
- persist-credentials: false
- - name: Fetch History
- run: git fetch --prune --unshallow
- - name: Free Disk Space
- uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
- with:
- tool-cache: true
- android: true
- dotnet: true
- haskell: true
- large-packages: false
- docker-images: false
- swap-storage: false
- - name: Setup Go
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
- with:
- go-version-file: go.mod
- - name: Find the Go Cache
- id: go
- run: |
- echo "build-cache=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
- echo "mod-cache=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
- - name: Cache the Go Build Cache
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
- with:
- path: ${{ steps.go.outputs.build-cache }}
- key: ${{ runner.os }}-build-unit-tests-${{ github.sha }}-${{ hashFiles('**/go.sum') }}
- restore-keys: ${{ runner.os }}-build-unit-tests-
- - name: Cache Go Dependencies
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
- with:
- path: ${{ steps.go.outputs.mod-cache }}
- key: ${{ runner.os }}-pkg-${{ github.sha }}-${{ hashFiles('**/go.sum') }}
- restore-keys: ${{ runner.os }}-pkg-
- - name: Setup Docker Buildx
- uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
- with:
- install: true
- - name: Build images
- env:
- DOCKER_BUILD_ARGS: --load
- run: make -C e2e test.build
- - name: Upload image tarballs
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
- with:
- name: e2e-images
- path: e2e/image-artifacts/*.tar
- retention-days: 1
- test:
- needs: [build, prepare-matrix]
- # One leg per enabled area in e2e/matrix.yaml. Each leg builds its own kind
- # cluster and runs a single suite under one label filter, so a flaky addon
- # in one provider cannot fail the others. fail-fast is off so one red leg
- # does not cancel the rest.
- strategy:
- fail-fast: false
- matrix: ${{ fromJSON(needs.prepare-matrix.outputs.matrix) }}
- name: test (${{ matrix.name }})
- runs-on: ubuntu-latest
- permissions:
- id-token: write # for oidc auth with aws/gcp/azure
- contents: read # for checkout
- env:
- # AWS_OIDC_ROLE_ARN is an identifier, not a credential, but it is still
- # injected only for legs whose secret_groups include "aws", so the
- # Configure AWS step (and AWS auth) is skipped on every other leg. The
- # per-provider credentials are scoped the same way, per leg, in the Run
- # e2e step below: a vault or core-smoke leg receives no cloud secrets.
- AWS_OIDC_ROLE_ARN: ${{ contains(matrix.secret_groups, 'aws') && secrets.AWS_OIDC_ROLE_ARN || '' }}
- # Selects the suite binary and label filter for this leg. run.sh forwards
- # both into the e2e pod; entrypoint.sh runs ginkgo with them.
- TEST_SUITES: ${{ matrix.suite }}
- GINKGO_LABELS: ${{ matrix.labels }}
- # The kind cluster goes away with the runner, so uninstalling the global
- # addons costs about a minute and buys nothing. Safe because TEST_SUITES
- # above is a single suite; the helper refuses this for several.
- E2E_SKIP_GLOBAL_TEARDOWN: "true"
- steps:
- - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0
- with:
- egress-policy: audit
- - name: Checkout
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- with:
- ref: ${{ env.TARGET_SHA || github.sha }}
- persist-credentials: false
- - name: Configure AWS Credentials
- if: env.AWS_OIDC_ROLE_ARN != ''
- uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6.2.3
- with:
- role-to-assume: ${{ env.AWS_OIDC_ROLE_ARN }}
- aws-region: ${{ env.AWS_REGION }}
- - name: Setup kind
- uses: engineerd/setup-kind@aa272fe2a7309878ffc2a81c56cfe3ef108ae7d0 # v0.5.0
- with:
- version: ${{ env.KIND_VERSION }}
- wait: 10m
- image: ${{ env.KIND_IMAGE }}
- name: external-secrets
- - name: Download image tarballs
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- with:
- name: e2e-images
- path: e2e/image-artifacts
- - name: Run e2e
- # Each provider's secrets are injected only when this leg's
- # secret_groups (from e2e/matrix.yaml) lists that group; otherwise the
- # value is empty. So a leg receives exactly the credentials it needs and
- # nothing else, instead of every leg seeing every secret.
- env:
- GCP_SERVICE_ACCOUNT_KEY: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_SERVICE_ACCOUNT_KEY || '' }}
- GCP_FED_REGION: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_FED_REGION || '' }}
- GCP_GSA_NAME: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_GSA_NAME || '' }}
- GCP_KSA_NAME: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_KSA_NAME || '' }}
- GCP_FED_PROJECT_ID: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_FED_PROJECT_ID || '' }}
- AWS_SA_NAME: ${{ contains(matrix.secret_groups, 'aws') && secrets.AWS_SA_NAME || '' }}
- AWS_SA_NAMESPACE: ${{ contains(matrix.secret_groups, 'aws') && secrets.AWS_SA_NAMESPACE || '' }}
- TFC_AZURE_CLIENT_ID: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_AZURE_CLIENT_ID || '' }}
- TFC_AZURE_CLIENT_SECRET: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_AZURE_CLIENT_SECRET || '' }}
- TFC_AZURE_TENANT_ID: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_AZURE_TENANT_ID || '' }}
- TFC_AZURE_SUBSCRIPTION_ID: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_AZURE_SUBSCRIPTION_ID || '' }}
- TFC_VAULT_URL: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_VAULT_URL || '' }}
- SCALEWAY_API_URL: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_API_URL || '' }}
- SCALEWAY_REGION: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_REGION || '' }}
- SCALEWAY_PROJECT_ID: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_PROJECT_ID || '' }}
- SCALEWAY_ACCESS_KEY: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_ACCESS_KEY || '' }}
- SCALEWAY_SECRET_KEY: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_SECRET_KEY || '' }}
- DELINEA_TLD: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_TLD || '' }}
- DELINEA_URL_TEMPLATE: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_URL_TEMPLATE || '' }}
- DELINEA_TENANT: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_TENANT || '' }}
- DELINEA_CLIENT_ID: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_CLIENT_ID || '' }}
- DELINEA_CLIENT_SECRET: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_CLIENT_SECRET || '' }}
- SECRETSERVER_USERNAME: ${{ contains(matrix.secret_groups, 'secretserver') && secrets.SECRETSERVER_USERNAME || '' }}
- SECRETSERVER_PASSWORD: ${{ contains(matrix.secret_groups, 'secretserver') && secrets.SECRETSERVER_PASSWORD || '' }}
- SECRETSERVER_URL: ${{ contains(matrix.secret_groups, 'secretserver') && secrets.SECRETSERVER_URL || '' }}
- GRAFANA_URL: ${{ contains(matrix.secret_groups, 'grafana') && secrets.GRAFANA_URL || '' }}
- GRAFANA_TOKEN: ${{ contains(matrix.secret_groups, 'grafana') && secrets.GRAFANA_TOKEN || '' }}
- AKEYLESS_ACCESS_ID: ${{ contains(matrix.secret_groups, 'akeyless') && secrets.AKEYLESS_ACCESS_ID || '' }}
- AKEYLESS_ACCESS_TYPE: ${{ contains(matrix.secret_groups, 'akeyless') && secrets.AKEYLESS_ACCESS_TYPE || '' }}
- AKEYLESS_ACCESS_TYPE_PARAM: ${{ contains(matrix.secret_groups, 'akeyless') && secrets.AKEYLESS_ACCESS_TYPE_PARAM || '' }}
- GITLAB_TOKEN: ${{ contains(matrix.secret_groups, 'gitlab') && secrets.GITLAB_TOKEN || '' }}
- GITLAB_PROJECT_ID: ${{ contains(matrix.secret_groups, 'gitlab') && secrets.GITLAB_PROJECT_ID || '' }}
- GITLAB_ENVIRONMENT: ${{ contains(matrix.secret_groups, 'gitlab') && secrets.GITLAB_ENVIRONMENT || '' }}
- ORACLE_USER_OCID: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_USER_OCID || '' }}
- ORACLE_TENANCY_OCID: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_TENANCY_OCID || '' }}
- ORACLE_REGION: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_REGION || '' }}
- ORACLE_FINGERPRINT: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_FINGERPRINT || '' }}
- ORACLE_KEY: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_KEY || '' }}
- ORACLE_VAULT_OCID: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_VAULT_OCID || '' }}
- ORACLE_COMPARTMENT_OCID: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_COMPARTMENT_OCID || '' }}
- ORACLE_ENCRYPTION_KEY_OCID: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_ENCRYPTION_KEY_OCID || '' }}
- run: make -C e2e test.run
|