|
|
1 неделя назад | |
|---|---|---|
| .. | ||
| framework | 1 неделя назад | |
| k8s | 2 недель назад | |
| suites | 2 недель назад | |
| Dockerfile | 2 недель назад | |
| Makefile | 1 неделя назад | |
| README.md | 1 неделя назад | |
| entrypoint.sh | 8 месяцев назад | |
| go.mod | 2 недель назад | |
| go.sum | 2 недель назад | |
| kind.yaml | 4 лет назад | |
| matrix.py | 1 неделя назад | |
| matrix.yaml | 1 неделя назад | |
| run.sh | 2 недель назад | |
| tools.go | 4 месяцев назад | |
This document explains how the e2e suite is built and run in CI after the fan-out change: what the moving parts are, how a run flows, how credentials are scoped per provider, and how to add or enable a provider.
| File | Role |
|---|---|
e2e/suites/<suite>/ |
Ginkgo suites, compiled to <suite>.test binaries: provider, generator, flux, argocd. |
e2e/suites/provider/cases/import.go |
Blank-imports every provider case into the single provider.test binary. Providers are told apart at run time by Ginkgo label. |
e2e/matrix.yaml |
Source of truth for the fan-out: one area (leg) per provider, with its suite, label filter, secret groups, and trigger paths. |
e2e/matrix.py |
Validates the matrix (check), emits the CI matrix JSON (json), and prints the per-leg credential plan (plan). |
e2e/run.sh |
Host-side launcher. Runs kubectl run to start the e2e pod, forwarding TEST_SUITES, GINKGO_LABELS, and the (scoped) credentials as pod env. |
e2e/entrypoint.sh |
In-pod entry (image CMD). Loops over TEST_SUITES and runs ginkgo -label-filter="$GINKGO_LABELS" against each <suite>.test. |
.github/workflows/e2e.yml |
Non-managed e2e. Fans out into per-provider legs. Owns the e2e-required gate. |
.github/workflows/e2e-reusable.yml |
The reusable build + matrix-test pipeline that e2e.yml calls. |
.github/workflows/e2e-managed.yml |
Managed e2e (real cloud IRSA / workload-identity), run on demand via /ok-to-test-managed. Already per-provider. |
flowchart TD
T[pull_request or /ok-to-test] --> P[prepare-matrix: matrix.py check + plan + json]
T --> B[build: compile controller + e2e images once, upload tarball]
P --> M{fan out over enabled areas}
B --> M
M --> L1[test core-smoke]
M --> L2[test vault]
M --> L3[test aws]
M --> Ln[test ...]
L1 --> R[e2e-required]
L2 --> R
L3 --> R
Ln --> R
R --> G[single stable green/red status]
matrix.py check (fail early if the matrix is
inconsistent), prints the credential plan, and emits the enabled-areas
matrix as JSON. This job has no secrets in scope.fail-fast: false matrix over the enabled areas. Each leg gets
its own runner and its own kind cluster, loads the shared image tarball, and
runs one suite under one label filter (TEST_SUITES + GINKGO_LABELS).e2e/matrix.yaml)Each area is one leg:
- name: aws # leg id, shown as "test (aws)"
suite: provider # which suite binary (TEST_SUITES)
labels: "aws && !managed" # Ginkgo -label-filter (GINKGO_LABELS)
providers: [aws] # for the coverage check only
secret_groups: [aws] # which credential groups this leg receives
needs_secrets: true # mirror of "secret_groups is non-empty"
paths: # phase 2 seed (affected-only), unused today
- "providers/v1/aws/**"
- "e2e/suites/provider/cases/aws/**"
enabled: true # whether the phase 1 matrix runs it now
Notes:
suite: provider; generator, flux, and
argocd are their own suites.!managed everywhere. This workflow runs only the non-managed specs; the
managed IRSA / workload-identity specs run in e2e-managed.yml.enabled lets the matrix grow gradually. Disabled areas still count for
coverage and document the intended full matrix; flip to true to run them.A leg receives a provider's secrets only when its secret_groups lists that
group. In e2e-reusable.yml every secret is gated:
GCP_SERVICE_ACCOUNT_KEY: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_SERVICE_ACCOUNT_KEY || '' }}
So a vault or core-smoke leg (secret_groups: []) gets empty strings for
every cloud credential, and the aws leg gets only the aws group. The
group -> variable mapping lives in e2e-reusable.yml.
Scoping is proven without reading any secret: matrix.py plan runs in
prepare-matrix (which has no secrets in scope) and derives each leg's
credential list from matrix.yaml plus the group mapping parsed out of the
workflow text. It never references the secrets context, so nothing depends on
GitHub's log masking. Example:
core-smoke: groups=[] -> (none: in-cluster only)
vault: groups=[] -> (none: in-cluster only)
aws: groups=['aws'] -> AWS_OIDC_ROLE_ARN, AWS_SA_NAME, AWS_SA_NAMESPACE
Which providers actually need external credentials: fake, kubernetes,
template, vault, openbao, conjur, and infisical run against in-cluster
addons and need none. The rest hit real APIs and are scoped to their group.
e2e-required gateThe individual leg names change as the matrix grows, which makes them a poor
target for branch protection. e2e-required (in e2e.yml) is one job that
needs the trusted and fork callers and reports a single status:
Point branch protection at e2e-required and it stays stable regardless of how
many legs exist.
integration-trusted): runs automatically with secrets./ok-to-test sha=<40-char-sha> (or submits
a review whose body contains /ok-to-test, which pins the reviewed commit).
guard-fork rejects a bare command without a pinned SHA; integration-fork
then runs. Note that the fork path runs the workflow from main, not from the
PR branch.e2e-managed.yml): /ok-to-test-managed, one job per cloud
provider, GINKGO_LABELS="<provider> && managed".# validate the matrix (coverage, secret-scoping consistency, wiring)
make -C e2e matrix.check
# show which credentials each enabled leg will receive (reads no secrets)
make -C e2e matrix.plan
# run a single provider locally (overrides the Makefile defaults)
make -C e2e test.run TEST_SUITES=provider GINKGO_LABELS="vault && !managed"
e2e/suites/provider/cases/<name>/ and blank
import it in import.go.area for it in matrix.yaml (its label, providers: [<name>], and
paths).secret_groups
and wire that group's env vars in e2e-reusable.yml.enabled: true when you want CI to run it.matrix.py check (run in prepare-matrix) enforces steps 1-3: it fails the
build if a provider is compiled into the suite but not covered by an area, if
needs_secrets disagrees with secret_groups, or if an area names a secret
group that the workflow does not wire.