e2e-reusable.yml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. # Reusable kind-based e2e pipeline, split into two jobs so the disk-heavy build
  2. # and the kind test run never share a runner. The build job compiles the
  3. # controller + e2e images and exports them as tarballs; the test job loads those
  4. # tarballs into kind and runs the suite, needing no Go toolchain or buildx.
  5. name: e2e reusable
  6. on:
  7. workflow_call:
  8. secrets:
  9. GCP_SERVICE_ACCOUNT_KEY:
  10. required: false
  11. GCP_FED_REGION:
  12. required: false
  13. GCP_GSA_NAME:
  14. required: false
  15. GCP_KSA_NAME:
  16. required: false
  17. GCP_FED_PROJECT_ID:
  18. required: false
  19. AWS_OIDC_ROLE_ARN:
  20. required: false
  21. AWS_SA_NAME:
  22. required: false
  23. AWS_SA_NAMESPACE:
  24. required: false
  25. TFC_AZURE_CLIENT_ID:
  26. required: false
  27. TFC_AZURE_CLIENT_SECRET:
  28. required: false
  29. TFC_AZURE_TENANT_ID:
  30. required: false
  31. TFC_AZURE_SUBSCRIPTION_ID:
  32. required: false
  33. TFC_VAULT_URL:
  34. required: false
  35. SCALEWAY_API_URL:
  36. required: false
  37. SCALEWAY_REGION:
  38. required: false
  39. SCALEWAY_PROJECT_ID:
  40. required: false
  41. SCALEWAY_ACCESS_KEY:
  42. required: false
  43. SCALEWAY_SECRET_KEY:
  44. required: false
  45. DELINEA_TLD:
  46. required: false
  47. DELINEA_URL_TEMPLATE:
  48. required: false
  49. DELINEA_TENANT:
  50. required: false
  51. DELINEA_CLIENT_ID:
  52. required: false
  53. DELINEA_CLIENT_SECRET:
  54. required: false
  55. SECRETSERVER_USERNAME:
  56. required: false
  57. SECRETSERVER_PASSWORD:
  58. required: false
  59. SECRETSERVER_URL:
  60. required: false
  61. GRAFANA_URL:
  62. required: false
  63. GRAFANA_TOKEN:
  64. required: false
  65. AKEYLESS_ACCESS_ID:
  66. required: false
  67. AKEYLESS_ACCESS_TYPE:
  68. required: false
  69. AKEYLESS_ACCESS_TYPE_PARAM:
  70. required: false
  71. GITLAB_TOKEN:
  72. required: false
  73. GITLAB_PROJECT_ID:
  74. required: false
  75. GITLAB_ENVIRONMENT:
  76. required: false
  77. ORACLE_USER_OCID:
  78. required: false
  79. ORACLE_TENANCY_OCID:
  80. required: false
  81. ORACLE_REGION:
  82. required: false
  83. ORACLE_FINGERPRINT:
  84. required: false
  85. ORACLE_KEY:
  86. required: false
  87. permissions:
  88. contents: read
  89. env:
  90. KIND_VERSION: 'v0.30.0'
  91. KIND_IMAGE: 'kindest/node:v1.33.4'
  92. AWS_REGION: "eu-central-1"
  93. # SHA under test on the fork path. Populated by a dispatcher: an explicit
  94. # `/ok-to-test sha=<sha>` comment (ok-to-test.yml), or the reviewed commit_id
  95. # of a PR review carrying /ok-to-test (ok-to-test-review.yml). Empty on the
  96. # trusted pull_request path, where the checkout falls back to github.sha (the
  97. # PR merge ref).
  98. TARGET_SHA: ${{ github.event.client_payload.slash_command.args.named.sha }}
  99. # Ephemeral tag: images are only ever loaded into kind, never pushed, so a
  100. # fixed tag keeps the build and test jobs in sync without passing a version.
  101. VERSION: "e2e"
  102. jobs:
  103. # Turn e2e/matrix.yaml into the test job's strategy matrix. Validating here
  104. # (check-matrix.sh) fails the run early if a provider was added to the suite
  105. # without a covering leg, rather than letting it go silently untested.
  106. prepare-matrix:
  107. runs-on: ubuntu-latest
  108. permissions:
  109. contents: read
  110. outputs:
  111. matrix: ${{ steps.set.outputs.matrix }}
  112. steps:
  113. - uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
  114. with:
  115. egress-policy: audit
  116. - name: Checkout
  117. uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
  118. with:
  119. ref: ${{ env.TARGET_SHA || github.sha }}
  120. persist-credentials: false
  121. - name: Validate and build the e2e matrix
  122. id: set
  123. # This job has no secrets in scope. matrix.py reads only matrix.yaml and
  124. # the workflow text, so the plan below proves per-leg credential scoping
  125. # without ever touching a secret value.
  126. run: |
  127. ./e2e/matrix.py check
  128. ./e2e/matrix.py plan
  129. matrix="$(./e2e/matrix.py json)"
  130. echo "matrix=${matrix}" >> "$GITHUB_OUTPUT"
  131. build:
  132. runs-on: ubuntu-latest
  133. permissions:
  134. contents: read
  135. steps:
  136. - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
  137. with:
  138. egress-policy: audit
  139. - name: Checkout
  140. uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
  141. with:
  142. ref: ${{ env.TARGET_SHA || github.sha }}
  143. persist-credentials: false
  144. - name: Fetch History
  145. run: git fetch --prune --unshallow
  146. - name: Free Disk Space
  147. uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
  148. with:
  149. tool-cache: true
  150. android: true
  151. dotnet: true
  152. haskell: true
  153. large-packages: false
  154. docker-images: false
  155. swap-storage: false
  156. - name: Setup Go
  157. uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
  158. with:
  159. go-version-file: go.mod
  160. - name: Find the Go Cache
  161. id: go
  162. run: |
  163. echo "build-cache=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
  164. echo "mod-cache=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
  165. - name: Cache the Go Build Cache
  166. uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
  167. with:
  168. path: ${{ steps.go.outputs.build-cache }}
  169. key: ${{ runner.os }}-build-unit-tests-${{ github.sha }}-${{ hashFiles('**/go.sum') }}
  170. restore-keys: ${{ runner.os }}-build-unit-tests-
  171. - name: Cache Go Dependencies
  172. uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
  173. with:
  174. path: ${{ steps.go.outputs.mod-cache }}
  175. key: ${{ runner.os }}-pkg-${{ github.sha }}-${{ hashFiles('**/go.sum') }}
  176. restore-keys: ${{ runner.os }}-pkg-
  177. - name: Setup Docker Buildx
  178. uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
  179. with:
  180. install: true
  181. - name: Build images
  182. env:
  183. DOCKER_BUILD_ARGS: --load
  184. run: make -C e2e test.build
  185. - name: Upload image tarballs
  186. uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
  187. with:
  188. name: e2e-images
  189. path: e2e/image-artifacts/*.tar
  190. retention-days: 1
  191. test:
  192. needs: [build, prepare-matrix]
  193. # One leg per enabled area in e2e/matrix.yaml. Each leg builds its own kind
  194. # cluster and runs a single suite under one label filter, so a flaky addon
  195. # in one provider cannot fail the others. fail-fast is off so one red leg
  196. # does not cancel the rest.
  197. strategy:
  198. fail-fast: false
  199. matrix: ${{ fromJSON(needs.prepare-matrix.outputs.matrix) }}
  200. name: test (${{ matrix.name }})
  201. runs-on: ubuntu-latest
  202. permissions:
  203. id-token: write # for oidc auth with aws/gcp/azure
  204. contents: read # for checkout
  205. env:
  206. # AWS_OIDC_ROLE_ARN is an identifier, not a credential, but it is still
  207. # injected only for legs whose secret_groups include "aws", so the
  208. # Configure AWS step (and AWS auth) is skipped on every other leg. The
  209. # per-provider credentials are scoped the same way, per leg, in the Run
  210. # e2e step below: a vault or core-smoke leg receives no cloud secrets.
  211. AWS_OIDC_ROLE_ARN: ${{ contains(matrix.secret_groups, 'aws') && secrets.AWS_OIDC_ROLE_ARN || '' }}
  212. # Selects the suite binary and label filter for this leg. run.sh forwards
  213. # both into the e2e pod; entrypoint.sh runs ginkgo with them.
  214. TEST_SUITES: ${{ matrix.suite }}
  215. GINKGO_LABELS: ${{ matrix.labels }}
  216. steps:
  217. - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
  218. with:
  219. egress-policy: audit
  220. - name: Checkout
  221. uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
  222. with:
  223. ref: ${{ env.TARGET_SHA || github.sha }}
  224. persist-credentials: false
  225. - name: Configure AWS Credentials
  226. if: env.AWS_OIDC_ROLE_ARN != ''
  227. uses: aws-actions/configure-aws-credentials@e6de054238d6b7531b4efff3b6587d9aade6a06c # v6.2.3
  228. with:
  229. role-to-assume: ${{ env.AWS_OIDC_ROLE_ARN }}
  230. aws-region: ${{ env.AWS_REGION }}
  231. - name: Setup kind
  232. uses: engineerd/setup-kind@aa272fe2a7309878ffc2a81c56cfe3ef108ae7d0 # v0.5.0
  233. with:
  234. version: ${{ env.KIND_VERSION }}
  235. wait: 10m
  236. image: ${{ env.KIND_IMAGE }}
  237. name: external-secrets
  238. - name: Download image tarballs
  239. uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
  240. with:
  241. name: e2e-images
  242. path: e2e/image-artifacts
  243. - name: Run e2e
  244. # Each provider's secrets are injected only when this leg's
  245. # secret_groups (from e2e/matrix.yaml) lists that group; otherwise the
  246. # value is empty. So a leg receives exactly the credentials it needs and
  247. # nothing else, instead of every leg seeing every secret.
  248. env:
  249. GCP_SERVICE_ACCOUNT_KEY: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_SERVICE_ACCOUNT_KEY || '' }}
  250. GCP_FED_REGION: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_FED_REGION || '' }}
  251. GCP_GSA_NAME: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_GSA_NAME || '' }}
  252. GCP_KSA_NAME: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_KSA_NAME || '' }}
  253. GCP_FED_PROJECT_ID: ${{ contains(matrix.secret_groups, 'gcp') && secrets.GCP_FED_PROJECT_ID || '' }}
  254. AWS_SA_NAME: ${{ contains(matrix.secret_groups, 'aws') && secrets.AWS_SA_NAME || '' }}
  255. AWS_SA_NAMESPACE: ${{ contains(matrix.secret_groups, 'aws') && secrets.AWS_SA_NAMESPACE || '' }}
  256. TFC_AZURE_CLIENT_ID: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_AZURE_CLIENT_ID || '' }}
  257. TFC_AZURE_CLIENT_SECRET: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_AZURE_CLIENT_SECRET || '' }}
  258. TFC_AZURE_TENANT_ID: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_AZURE_TENANT_ID || '' }}
  259. TFC_AZURE_SUBSCRIPTION_ID: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_AZURE_SUBSCRIPTION_ID || '' }}
  260. TFC_VAULT_URL: ${{ contains(matrix.secret_groups, 'azure') && secrets.TFC_VAULT_URL || '' }}
  261. SCALEWAY_API_URL: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_API_URL || '' }}
  262. SCALEWAY_REGION: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_REGION || '' }}
  263. SCALEWAY_PROJECT_ID: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_PROJECT_ID || '' }}
  264. SCALEWAY_ACCESS_KEY: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_ACCESS_KEY || '' }}
  265. SCALEWAY_SECRET_KEY: ${{ contains(matrix.secret_groups, 'scaleway') && secrets.SCALEWAY_SECRET_KEY || '' }}
  266. DELINEA_TLD: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_TLD || '' }}
  267. DELINEA_URL_TEMPLATE: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_URL_TEMPLATE || '' }}
  268. DELINEA_TENANT: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_TENANT || '' }}
  269. DELINEA_CLIENT_ID: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_CLIENT_ID || '' }}
  270. DELINEA_CLIENT_SECRET: ${{ contains(matrix.secret_groups, 'delinea') && secrets.DELINEA_CLIENT_SECRET || '' }}
  271. SECRETSERVER_USERNAME: ${{ contains(matrix.secret_groups, 'secretserver') && secrets.SECRETSERVER_USERNAME || '' }}
  272. SECRETSERVER_PASSWORD: ${{ contains(matrix.secret_groups, 'secretserver') && secrets.SECRETSERVER_PASSWORD || '' }}
  273. SECRETSERVER_URL: ${{ contains(matrix.secret_groups, 'secretserver') && secrets.SECRETSERVER_URL || '' }}
  274. GRAFANA_URL: ${{ contains(matrix.secret_groups, 'grafana') && secrets.GRAFANA_URL || '' }}
  275. GRAFANA_TOKEN: ${{ contains(matrix.secret_groups, 'grafana') && secrets.GRAFANA_TOKEN || '' }}
  276. AKEYLESS_ACCESS_ID: ${{ contains(matrix.secret_groups, 'akeyless') && secrets.AKEYLESS_ACCESS_ID || '' }}
  277. AKEYLESS_ACCESS_TYPE: ${{ contains(matrix.secret_groups, 'akeyless') && secrets.AKEYLESS_ACCESS_TYPE || '' }}
  278. AKEYLESS_ACCESS_TYPE_PARAM: ${{ contains(matrix.secret_groups, 'akeyless') && secrets.AKEYLESS_ACCESS_TYPE_PARAM || '' }}
  279. GITLAB_TOKEN: ${{ contains(matrix.secret_groups, 'gitlab') && secrets.GITLAB_TOKEN || '' }}
  280. GITLAB_PROJECT_ID: ${{ contains(matrix.secret_groups, 'gitlab') && secrets.GITLAB_PROJECT_ID || '' }}
  281. GITLAB_ENVIRONMENT: ${{ contains(matrix.secret_groups, 'gitlab') && secrets.GITLAB_ENVIRONMENT || '' }}
  282. ORACLE_USER_OCID: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_USER_OCID || '' }}
  283. ORACLE_TENANCY_OCID: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_TENANCY_OCID || '' }}
  284. ORACLE_REGION: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_REGION || '' }}
  285. ORACLE_FINGERPRINT: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_FINGERPRINT || '' }}
  286. ORACLE_KEY: ${{ contains(matrix.secret_groups, 'oracle') && secrets.ORACLE_KEY || '' }}
  287. run: make -C e2e test.run