e2e-reusable.yml 14 KB

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