From 9c7a0d83d28e45a066118e0908100fd75bec1696 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 17:54:17 +0300 Subject: [PATCH 01/20] chore(ci): encrypt test artifacts Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 124 ++++++++++++++++++-- 1 file changed, 112 insertions(+), 12 deletions(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index 030a0cdbbe..c7d226bfcd 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -122,6 +122,8 @@ on: required: true BOOTSTRAP_DEV_PROXY: required: true + E2E_ARTIFACTS_GPG_PASSPHRASE: + required: true outputs: artifact-name: description: "Name of the uploaded artifact with E2E report" @@ -434,33 +436,72 @@ jobs: yq e '.discovered.registry_auth = "None"' -i ./${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp/discovered-values.yaml || echo "The discovered-values.yaml file is not generated, skipping editing registry_auth" echo "${{ steps.generate-kubeconfig.outputs.kubeconfig }}" | base64 -d | base64 -d > ./${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config || echo "kubeconfig not available, skipping" + - name: Encrypt generated files artifact + if: success() || failure() + env: + GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + run: | + pushd ${{ env.SETUP_CLUSTER_TYPE_PATH }} + zip -r $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip tmp values.yaml + popd + gpg --symmetric --batch --yes --pinentry-mode loopback \ + --passphrase "$GPG_PASSPHRASE" \ + --cipher-algo AES256 \ + --output $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip.gpg \ + $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip + rm -f $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip + - name: Upload generated files uses: actions/upload-artifact@v4 if: success() || failure() with: name: ${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }} - path: | - ${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp - ${{ env.SETUP_CLUSTER_TYPE_PATH }}/values.yaml + path: ${{ runner.temp }}/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip.gpg overwrite: true include-hidden-files: true retention-days: 3 + - name: Encrypt ssh config artifact + if: always() + env: + GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + run: | + pushd ${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp + zip -r $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip ssh + popd + gpg --symmetric --batch --yes --pinentry-mode loopback \ + --passphrase "$GPG_PASSPHRASE" \ + --cipher-algo AES256 \ + --output $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip.gpg \ + $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip + rm -f $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip + - name: Upload ssh config uses: actions/upload-artifact@v4 if: always() with: name: ${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }} - path: ${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp/ssh + path: ${{ runner.temp }}/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip.gpg overwrite: true include-hidden-files: true retention-days: 3 + - name: Encrypt kubeconfig artifact + if: always() + env: + GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + run: | + gpg --symmetric --batch --yes --pinentry-mode loopback \ + --passphrase "$GPG_PASSPHRASE" \ + --cipher-algo AES256 \ + --output $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-kubeconfig-${{ inputs.date_start }}.gpg \ + ${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config + - name: Upload kubeconfig uses: actions/upload-artifact@v4 with: name: ${{ inputs.storage_type }}-generated-files-kubeconfig-${{ inputs.date_start }} - path: ${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config + path: ${{ runner.temp }}/${{ inputs.storage_type }}-generated-files-kubeconfig-${{ inputs.date_start }}.gpg overwrite: true include-hidden-files: true retention-days: 3 @@ -1429,26 +1470,68 @@ jobs: echo "[INFO] Exit code: $GINKGO_EXIT_CODE" exit $GINKGO_EXIT_CODE + - name: Encrypt summary test results artifact + if: always() && steps.e2e-report.outcome != 'skipped' + env: + GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + run: | + shopt -s nullglob + files=( + test/e2e/e2e_summary_*.json + test/e2e/ginkgo_report_*.json + test/e2e/e2e_summary_*.xml + test/e2e/*junit*.xml + ) + if [ ${#files[@]} -eq 0 ]; then + echo "[INFO] No E2E summary files found, skipping encryption" + exit 0 + fi + zip -r $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip "${files[@]}" + gpg --symmetric --batch --yes --pinentry-mode loopback \ + --passphrase "$GPG_PASSPHRASE" \ + --cipher-algo AES256 \ + --output $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip.gpg \ + $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip + rm -f $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip + - name: Upload summary test results (junit/xml) uses: actions/upload-artifact@v4 id: e2e-report-artifact if: always() && steps.e2e-report.outcome != 'skipped' with: name: e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }} - path: | - test/e2e/e2e_summary_*.json - test/e2e/ginkgo_report_*.json - test/e2e/e2e_summary_*.xml - test/e2e/*junit*.xml + path: ${{ runner.temp }}/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip.gpg if-no-files-found: ignore retention-days: 3 + - name: Encrypt resources from failed tests artifact + if: always() && steps.e2e-report.outcome != 'skipped' + env: + GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + run: | + shopt -s nullglob + files=($RUNNER_TEMP/e2e_failed__*) + if [ ${#files[@]} -eq 0 ]; then + echo "[INFO] No failed test resources found, skipping encryption" + exit 0 + fi + pushd $RUNNER_TEMP + zip -r $RUNNER_TEMP/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip $(printf '%s +' "${files[@]##$RUNNER_TEMP/}") + popd + gpg --symmetric --batch --yes --pinentry-mode loopback \ + --passphrase "$GPG_PASSPHRASE" \ + --cipher-algo AES256 \ + --output $RUNNER_TEMP/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip.gpg \ + $RUNNER_TEMP/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip + rm -f $RUNNER_TEMP/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip + - name: Upload resources from failed tests uses: actions/upload-artifact@v4 if: always() && steps.e2e-report.outcome != 'skipped' with: name: resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }} - path: ${{ runner.temp }}/e2e_failed__* + path: ${{ runner.temp }}/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip.gpg if-no-files-found: ignore retention-days: 3 @@ -1471,7 +1554,24 @@ jobs: continue-on-error: true with: name: e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }} - path: test/e2e/ + path: ${{ runner.temp }}/encrypted-e2e-results + + - name: Decrypt E2E test results if available + continue-on-error: true + env: + GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + run: | + mkdir -p test/e2e + artifact_path=${{ runner.temp }}/encrypted-e2e-results/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }}.zip.gpg + if [ ! -f "$artifact_path" ]; then + echo "[INFO] Encrypted E2E results artifact not found, skipping decryption" + exit 0 + fi + gpg --decrypt --batch --yes --pinentry-mode loopback \ + --passphrase "$GPG_PASSPHRASE" \ + --output $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }}.zip \ + "$artifact_path" + unzip -o $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }}.zip - name: Determine failed stage and prepare report id: determine-stage From abe5df19bf6bcb8dd88df7735f429308202cf883 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 18:09:43 +0300 Subject: [PATCH 02/20] move boilerplate to env Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 73 +++++++++++---------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index c7d226bfcd..3a557f3ce7 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -137,6 +137,8 @@ env: GO_VERSION: ${{ inputs.go_version }} SETUP_CLUSTER_TYPE_PATH: test/dvp-static-cluster K8S_VERSION: ${{ inputs.cluster_config_k8s_version }} + STORAGE_TYPE: ${{ inputs.storage_type }} + E2E_START_TIME: ${{ inputs.date_start }} defaults: run: @@ -440,23 +442,24 @@ jobs: if: success() || failure() env: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + ARTIFACT_NAME: ${STORAGE_TYPE}-generated-files-${E2E_START_TIME} run: | pushd ${{ env.SETUP_CLUSTER_TYPE_PATH }} - zip -r $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip tmp values.yaml + zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip tmp values.yaml popd gpg --symmetric --batch --yes --pinentry-mode loopback \ --passphrase "$GPG_PASSPHRASE" \ --cipher-algo AES256 \ - --output $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip.gpg \ - $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip - rm -f $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip + --output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \ + $RUNNER_TEMP/${ARTIFACT_NAME}.zip + rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip - name: Upload generated files uses: actions/upload-artifact@v4 if: success() || failure() with: - name: ${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }} - path: ${{ runner.temp }}/${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}.zip.gpg + name: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }} + path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }}.zip.gpg overwrite: true include-hidden-files: true retention-days: 3 @@ -465,23 +468,24 @@ jobs: if: always() env: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + ARTIFACT_NAME: ${STORAGE_TYPE}-generated-files-ssh-${E2E_START_TIME} run: | pushd ${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp - zip -r $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip ssh + zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip ssh popd gpg --symmetric --batch --yes --pinentry-mode loopback \ --passphrase "$GPG_PASSPHRASE" \ --cipher-algo AES256 \ - --output $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip.gpg \ - $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip - rm -f $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip + --output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \ + $RUNNER_TEMP/${ARTIFACT_NAME}.zip + rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip - name: Upload ssh config uses: actions/upload-artifact@v4 if: always() with: - name: ${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }} - path: ${{ runner.temp }}/${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}.zip.gpg + name: ${{ env.STORAGE_TYPE }}-generated-files-ssh-${{ env.E2E_START_TIME }} + path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-ssh-${{ env.E2E_START_TIME }}.zip.gpg overwrite: true include-hidden-files: true retention-days: 3 @@ -490,18 +494,19 @@ jobs: if: always() env: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + ARTIFACT_NAME: ${STORAGE_TYPE}-generated-files-kubeconfig-${E2E_START_TIME} run: | gpg --symmetric --batch --yes --pinentry-mode loopback \ --passphrase "$GPG_PASSPHRASE" \ --cipher-algo AES256 \ - --output $RUNNER_TEMP/${{ inputs.storage_type }}-generated-files-kubeconfig-${{ inputs.date_start }}.gpg \ + --output $RUNNER_TEMP/${ARTIFACT_NAME}.gpg \ ${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config - name: Upload kubeconfig uses: actions/upload-artifact@v4 with: - name: ${{ inputs.storage_type }}-generated-files-kubeconfig-${{ inputs.date_start }} - path: ${{ runner.temp }}/${{ inputs.storage_type }}-generated-files-kubeconfig-${{ inputs.date_start }}.gpg + name: ${{ env.STORAGE_TYPE }}-generated-files-kubeconfig-${{ env.E2E_START_TIME }} + path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-kubeconfig-${{ env.E2E_START_TIME }}.gpg overwrite: true include-hidden-files: true retention-days: 3 @@ -1370,10 +1375,8 @@ jobs: - name: Set vars id: vars - env: - DATE_START: ${{ inputs.date_start }} run: | - echo "e2e-start-time=$DATE_START" >> $GITHUB_OUTPUT + echo "e2e-start-time=${E2E_START_TIME}" >> $GITHUB_OUTPUT - name: Run E2E id: e2e-report @@ -1474,6 +1477,7 @@ jobs: if: always() && steps.e2e-report.outcome != 'skipped' env: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + ARTIFACT_NAME: e2e-test-results-${STORAGE_TYPE}-${GITHUB_RUN_ID}-${E2E_START_TIME} run: | shopt -s nullglob files=( @@ -1486,21 +1490,21 @@ jobs: echo "[INFO] No E2E summary files found, skipping encryption" exit 0 fi - zip -r $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip "${files[@]}" + zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip "${files[@]}" gpg --symmetric --batch --yes --pinentry-mode loopback \ --passphrase "$GPG_PASSPHRASE" \ --cipher-algo AES256 \ - --output $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip.gpg \ - $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip - rm -f $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip + --output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \ + $RUNNER_TEMP/${ARTIFACT_NAME}.zip + rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip - name: Upload summary test results (junit/xml) uses: actions/upload-artifact@v4 id: e2e-report-artifact if: always() && steps.e2e-report.outcome != 'skipped' with: - name: e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }} - path: ${{ runner.temp }}/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}.zip.gpg + name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }} + path: ${{ runner.temp }}/e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}.zip.gpg if-no-files-found: ignore retention-days: 3 @@ -1508,6 +1512,7 @@ jobs: if: always() && steps.e2e-report.outcome != 'skipped' env: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + ARTIFACT_NAME: resources_from_failed_tests-${STORAGE_TYPE}-${E2E_START_TIME} run: | shopt -s nullglob files=($RUNNER_TEMP/e2e_failed__*) @@ -1516,22 +1521,22 @@ jobs: exit 0 fi pushd $RUNNER_TEMP - zip -r $RUNNER_TEMP/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip $(printf '%s + zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip $(printf '%s ' "${files[@]##$RUNNER_TEMP/}") popd gpg --symmetric --batch --yes --pinentry-mode loopback \ --passphrase "$GPG_PASSPHRASE" \ --cipher-algo AES256 \ - --output $RUNNER_TEMP/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip.gpg \ - $RUNNER_TEMP/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip - rm -f $RUNNER_TEMP/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip + --output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \ + $RUNNER_TEMP/${ARTIFACT_NAME}.zip + rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip - name: Upload resources from failed tests uses: actions/upload-artifact@v4 if: always() && steps.e2e-report.outcome != 'skipped' with: - name: resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }} - path: ${{ runner.temp }}/resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}.zip.gpg + name: resources_from_failed_tests-${{ env.STORAGE_TYPE }}-${{ env.E2E_START_TIME }} + path: ${{ runner.temp }}/resources_from_failed_tests-${{ env.STORAGE_TYPE }}-${{ env.E2E_START_TIME }}.zip.gpg if-no-files-found: ignore retention-days: 3 @@ -1553,7 +1558,7 @@ jobs: uses: actions/download-artifact@v5 continue-on-error: true with: - name: e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }} + name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }} path: ${{ runner.temp }}/encrypted-e2e-results - name: Decrypt E2E test results if available @@ -1562,16 +1567,16 @@ jobs: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} run: | mkdir -p test/e2e - artifact_path=${{ runner.temp }}/encrypted-e2e-results/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }}.zip.gpg + artifact_path=${{ runner.temp }}/encrypted-e2e-results/e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}.zip.gpg if [ ! -f "$artifact_path" ]; then echo "[INFO] Encrypted E2E results artifact not found, skipping decryption" exit 0 fi gpg --decrypt --batch --yes --pinentry-mode loopback \ --passphrase "$GPG_PASSPHRASE" \ - --output $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }}.zip \ + --output $RUNNER_TEMP/e2e-test-results-${STORAGE_TYPE}-${GITHUB_RUN_ID}-${E2E_START_TIME}.zip \ "$artifact_path" - unzip -o $RUNNER_TEMP/e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }}.zip + unzip -o $RUNNER_TEMP/e2e-test-results-${STORAGE_TYPE}-${GITHUB_RUN_ID}-${E2E_START_TIME}.zip - name: Determine failed stage and prepare report id: determine-stage From 3b51fbabb687ede037712cb585dc0ed5cba56289 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 18:16:19 +0300 Subject: [PATCH 03/20] revertme: test Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-matrix.yml | 27 --------------------- .github/workflows/e2e-reusable-pipeline.yml | 2 +- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/.github/workflows/e2e-matrix.yml b/.github/workflows/e2e-matrix.yml index 0bf8ab0e0f..862371a543 100644 --- a/.github/workflows/e2e-matrix.yml +++ b/.github/workflows/e2e-matrix.yml @@ -413,32 +413,6 @@ jobs: echo "date-start=$(date +%Y%m%d-%H%M%S)" >> $GITHUB_OUTPUT echo "randuuid4c=$(openssl rand -hex 2)" >> $GITHUB_OUTPUT - e2e-replicated: - name: E2E Pipeline (Replicated) - needs: - - set-vars - uses: ./.github/workflows/e2e-reusable-pipeline.yml - with: - storage_type: replicated - nested_storageclass_name: nested-thin-r1 - nested_cluster_network_name: cn-4006-for-e2e-test - branch: main - virtualization_tag: main - deckhouse_channel: alpha - default_user: cloud - go_version: "1.25.9" - e2e_timeout: "3.5h" - date_start: ${{ needs.set-vars.outputs.date_start }} - randuuid4c: ${{ needs.set-vars.outputs.randuuid4c }} - cluster_config_workers_memory: "9Gi" - cluster_config_k8s_version: "1.34" - apt_mirror_enabled: true - secrets: - DEV_REGISTRY_DOCKER_CFG: ${{ secrets.DEV_REGISTRY_DOCKER_CFG }} - VIRT_E2E_NIGHTLY_SA_TOKEN: ${{ secrets.VIRT_E2E_NIGHTLY_SA_TOKEN }} - PROD_IO_REGISTRY_DOCKER_CFG: ${{ secrets.PROD_IO_REGISTRY_DOCKER_CFG }} - BOOTSTRAP_DEV_PROXY: ${{ secrets.BOOTSTRAP_DEV_PROXY }} - e2e-nfs: name: E2E Pipeline (NFS) needs: @@ -469,7 +443,6 @@ jobs: runs-on: ubuntu-latest name: End-to-End tests report needs: - - e2e-replicated - e2e-nfs if: ${{ always()}} env: diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index 3a557f3ce7..c7ce8ffc81 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -1395,7 +1395,7 @@ jobs: summary_file_name_junit="e2e_summary_${CSI}_${DATE}.xml" ginkgo_json_report="ginkgo_report_${CSI}_${DATE}.json" summary_file_name_json="e2e_summary_${CSI}_${DATE}.json" - FOCUS="${{ inputs.e2e_focus_tests }}" + FOCUS="VirtualMachineMigration" cp -a legacy/testdata /tmp/testdata From 63326ac7a93337a9a25176ff1bb166dbb1908b6a Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 18:19:44 +0300 Subject: [PATCH 04/20] revertme: test channel Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-matrix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e-matrix.yml b/.github/workflows/e2e-matrix.yml index 862371a543..b688048d81 100644 --- a/.github/workflows/e2e-matrix.yml +++ b/.github/workflows/e2e-matrix.yml @@ -710,4 +710,4 @@ jobs: curl --request POST --header 'Content-Type: application/json' --data "{\"text\": \"${COMBINED_SUMMARY}\"}" "$LOOP_WEBHOOK_URL" fi env: - LOOP_WEBHOOK_URL: ${{ secrets.LOOP_WEBHOOK_URL }} + LOOP_WEBHOOK_URL: ${{ secrets.LOOP_TEST_CHANNEL }} From 2dd49377aa6d74026c465f8f28e657db2e11a107 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 18:23:30 +0300 Subject: [PATCH 05/20] revertme: exit 0 Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index c7ce8ffc81..af484fd527 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -1472,7 +1472,7 @@ jobs: echo $SUMMARY > "${summary_file_name_json}" echo "[INFO] Exit code: $GINKGO_EXIT_CODE" - exit $GINKGO_EXIT_CODE + exit 0 - name: Encrypt summary test results artifact if: always() && steps.e2e-report.outcome != 'skipped' env: From 3d633cf31c002ce639497235083d0095b2d19d3d Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 18:25:52 +0300 Subject: [PATCH 06/20] fix yaml Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index af484fd527..8535e0c049 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -1521,8 +1521,7 @@ jobs: exit 0 fi pushd $RUNNER_TEMP - zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip $(printf '%s -' "${files[@]##$RUNNER_TEMP/}") + zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip ${files[@]##$RUNNER_TEMP/} popd gpg --symmetric --batch --yes --pinentry-mode loopback \ --passphrase "$GPG_PASSPHRASE" \ From f0688cb68d191d9716efdb4c013d9852ad0cdf3f Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 18:27:33 +0300 Subject: [PATCH 07/20] add e2e secret Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-matrix.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/e2e-matrix.yml b/.github/workflows/e2e-matrix.yml index b688048d81..1c4fc7e5e0 100644 --- a/.github/workflows/e2e-matrix.yml +++ b/.github/workflows/e2e-matrix.yml @@ -438,6 +438,7 @@ jobs: VIRT_E2E_NIGHTLY_SA_TOKEN: ${{ secrets.VIRT_E2E_NIGHTLY_SA_TOKEN }} PROD_IO_REGISTRY_DOCKER_CFG: ${{ secrets.PROD_IO_REGISTRY_DOCKER_CFG }} BOOTSTRAP_DEV_PROXY: ${{ secrets.BOOTSTRAP_DEV_PROXY }} + E2E_ARTIFACTS_GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} report-to-channel: runs-on: ubuntu-latest From 275b7e249f721bbe3d08801a0bab9e42383ab673 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 19:37:27 +0300 Subject: [PATCH 08/20] fix issues Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 30 ++++++--------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index 8535e0c049..bdebc6f97a 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -438,28 +438,14 @@ jobs: yq e '.discovered.registry_auth = "None"' -i ./${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp/discovered-values.yaml || echo "The discovered-values.yaml file is not generated, skipping editing registry_auth" echo "${{ steps.generate-kubeconfig.outputs.kubeconfig }}" | base64 -d | base64 -d > ./${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config || echo "kubeconfig not available, skipping" - - name: Encrypt generated files artifact - if: success() || failure() - env: - GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} - ARTIFACT_NAME: ${STORAGE_TYPE}-generated-files-${E2E_START_TIME} - run: | - pushd ${{ env.SETUP_CLUSTER_TYPE_PATH }} - zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip tmp values.yaml - popd - gpg --symmetric --batch --yes --pinentry-mode loopback \ - --passphrase "$GPG_PASSPHRASE" \ - --cipher-algo AES256 \ - --output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \ - $RUNNER_TEMP/${ARTIFACT_NAME}.zip - rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip - - name: Upload generated files uses: actions/upload-artifact@v4 if: success() || failure() with: - name: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }} - path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }}.zip.gpg + name: ${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }} + path: | + ${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp + ${{ env.SETUP_CLUSTER_TYPE_PATH }}/values.yaml overwrite: true include-hidden-files: true retention-days: 3 @@ -468,7 +454,7 @@ jobs: if: always() env: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} - ARTIFACT_NAME: ${STORAGE_TYPE}-generated-files-ssh-${E2E_START_TIME} + ARTIFACT_NAME: ${{ env.STORAGE_TYPE }}-generated-files-ssh-${{ env.E2E_START_TIME }} run: | pushd ${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip ssh @@ -494,7 +480,7 @@ jobs: if: always() env: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} - ARTIFACT_NAME: ${STORAGE_TYPE}-generated-files-kubeconfig-${E2E_START_TIME} + ARTIFACT_NAME: ${{ env.STORAGE_TYPE }}-generated-files-kubeconfig-${{ env.E2E_START_TIME }} run: | gpg --symmetric --batch --yes --pinentry-mode loopback \ --passphrase "$GPG_PASSPHRASE" \ @@ -1477,7 +1463,7 @@ jobs: if: always() && steps.e2e-report.outcome != 'skipped' env: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} - ARTIFACT_NAME: e2e-test-results-${STORAGE_TYPE}-${GITHUB_RUN_ID}-${E2E_START_TIME} + ARTIFACT_NAME: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }} run: | shopt -s nullglob files=( @@ -1512,7 +1498,7 @@ jobs: if: always() && steps.e2e-report.outcome != 'skipped' env: GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} - ARTIFACT_NAME: resources_from_failed_tests-${STORAGE_TYPE}-${E2E_START_TIME} + ARTIFACT_NAME: resources_from_failed_tests-${{ env.STORAGE_TYPE }}-${{ env.E2E_START_TIME }} run: | shopt -s nullglob files=($RUNNER_TEMP/e2e_failed__*) From da485c76b027d238d586cdc03bef22fb9aef5c34 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 22:12:54 +0300 Subject: [PATCH 09/20] disable archive Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index bdebc6f97a..0c8e6ac3a7 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -475,6 +475,7 @@ jobs: overwrite: true include-hidden-files: true retention-days: 3 + archive: false - name: Encrypt kubeconfig artifact if: always() @@ -496,6 +497,7 @@ jobs: overwrite: true include-hidden-files: true retention-days: 3 + archive: false configure-sdn: name: Configure SDN @@ -1493,6 +1495,7 @@ jobs: path: ${{ runner.temp }}/e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}.zip.gpg if-no-files-found: ignore retention-days: 3 + archive: false - name: Encrypt resources from failed tests artifact if: always() && steps.e2e-report.outcome != 'skipped' @@ -1524,6 +1527,7 @@ jobs: path: ${{ runner.temp }}/resources_from_failed_tests-${{ env.STORAGE_TYPE }}-${{ env.E2E_START_TIME }}.zip.gpg if-no-files-found: ignore retention-days: 3 + archive: false prepare-report: name: Prepare E2E report From 5fc5eac104cf8f1c08fec2caf8879130f4494530 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 22:14:02 +0300 Subject: [PATCH 10/20] revert test stuff Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-matrix.yml | 29 ++++++++++++++++++++- .github/workflows/e2e-reusable-pipeline.yml | 4 +-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-matrix.yml b/.github/workflows/e2e-matrix.yml index 1c4fc7e5e0..89ce6bfe6f 100644 --- a/.github/workflows/e2e-matrix.yml +++ b/.github/workflows/e2e-matrix.yml @@ -413,6 +413,32 @@ jobs: echo "date-start=$(date +%Y%m%d-%H%M%S)" >> $GITHUB_OUTPUT echo "randuuid4c=$(openssl rand -hex 2)" >> $GITHUB_OUTPUT + e2e-replicated: + name: E2E Pipeline (Replicated) + needs: + - set-vars + uses: ./.github/workflows/e2e-reusable-pipeline.yml + with: + storage_type: replicated + nested_storageclass_name: nested-thin-r1 + nested_cluster_network_name: cn-4006-for-e2e-test + branch: main + virtualization_tag: main + deckhouse_channel: alpha + default_user: cloud + go_version: "1.25.9" + e2e_timeout: "3.5h" + date_start: ${{ needs.set-vars.outputs.date_start }} + randuuid4c: ${{ needs.set-vars.outputs.randuuid4c }} + cluster_config_workers_memory: "9Gi" + cluster_config_k8s_version: "1.34" + apt_mirror_enabled: true + secrets: + DEV_REGISTRY_DOCKER_CFG: ${{ secrets.DEV_REGISTRY_DOCKER_CFG }} + VIRT_E2E_NIGHTLY_SA_TOKEN: ${{ secrets.VIRT_E2E_NIGHTLY_SA_TOKEN }} + PROD_IO_REGISTRY_DOCKER_CFG: ${{ secrets.PROD_IO_REGISTRY_DOCKER_CFG }} + BOOTSTRAP_DEV_PROXY: ${{ secrets.BOOTSTRAP_DEV_PROXY }} + e2e-nfs: name: E2E Pipeline (NFS) needs: @@ -444,6 +470,7 @@ jobs: runs-on: ubuntu-latest name: End-to-End tests report needs: + - e2e-replicated - e2e-nfs if: ${{ always()}} env: @@ -711,4 +738,4 @@ jobs: curl --request POST --header 'Content-Type: application/json' --data "{\"text\": \"${COMBINED_SUMMARY}\"}" "$LOOP_WEBHOOK_URL" fi env: - LOOP_WEBHOOK_URL: ${{ secrets.LOOP_TEST_CHANNEL }} + LOOP_WEBHOOK_URL: ${{ secrets.LOOP_WEBHOOK_URL }} diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index 0c8e6ac3a7..45f1f78509 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -1383,7 +1383,7 @@ jobs: summary_file_name_junit="e2e_summary_${CSI}_${DATE}.xml" ginkgo_json_report="ginkgo_report_${CSI}_${DATE}.json" summary_file_name_json="e2e_summary_${CSI}_${DATE}.json" - FOCUS="VirtualMachineMigration" + FOCUS="${{ inputs.e2e_focus_tests }}" cp -a legacy/testdata /tmp/testdata @@ -1460,7 +1460,7 @@ jobs: echo $SUMMARY > "${summary_file_name_json}" echo "[INFO] Exit code: $GINKGO_EXIT_CODE" - exit 0 + exit $GINKGO_EXIT_CODE - name: Encrypt summary test results artifact if: always() && steps.e2e-report.outcome != 'skipped' env: From b4684d060723932c248074f3c1dc958954eb8f36 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 22:14:16 +0300 Subject: [PATCH 11/20] add secret to replicated Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-matrix.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/e2e-matrix.yml b/.github/workflows/e2e-matrix.yml index 89ce6bfe6f..2590f8cb8f 100644 --- a/.github/workflows/e2e-matrix.yml +++ b/.github/workflows/e2e-matrix.yml @@ -438,6 +438,7 @@ jobs: VIRT_E2E_NIGHTLY_SA_TOKEN: ${{ secrets.VIRT_E2E_NIGHTLY_SA_TOKEN }} PROD_IO_REGISTRY_DOCKER_CFG: ${{ secrets.PROD_IO_REGISTRY_DOCKER_CFG }} BOOTSTRAP_DEV_PROXY: ${{ secrets.BOOTSTRAP_DEV_PROXY }} + E2E_ARTIFACTS_GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} e2e-nfs: name: E2E Pipeline (NFS) From 3dd4112944e93718d9cf24bdf51543db3fa88844 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Wed, 6 May 2026 22:23:56 +0300 Subject: [PATCH 12/20] up to v7 Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index 45f1f78509..d397cb629e 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -439,7 +439,7 @@ jobs: echo "${{ steps.generate-kubeconfig.outputs.kubeconfig }}" | base64 -d | base64 -d > ./${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config || echo "kubeconfig not available, skipping" - name: Upload generated files - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: ${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }} @@ -467,7 +467,7 @@ jobs: rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip - name: Upload ssh config - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: always() with: name: ${{ env.STORAGE_TYPE }}-generated-files-ssh-${{ env.E2E_START_TIME }} @@ -490,7 +490,7 @@ jobs: ${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config - name: Upload kubeconfig - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ env.STORAGE_TYPE }}-generated-files-kubeconfig-${{ env.E2E_START_TIME }} path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-kubeconfig-${{ env.E2E_START_TIME }}.gpg @@ -1487,7 +1487,7 @@ jobs: rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip - name: Upload summary test results (junit/xml) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 id: e2e-report-artifact if: always() && steps.e2e-report.outcome != 'skipped' with: @@ -1520,7 +1520,7 @@ jobs: rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip - name: Upload resources from failed tests - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: always() && steps.e2e-report.outcome != 'skipped' with: name: resources_from_failed_tests-${{ env.STORAGE_TYPE }}-${{ env.E2E_START_TIME }} @@ -1720,7 +1720,7 @@ jobs: - name: Upload E2E report artifact id: upload-artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: e2e-report-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }} path: ${{ steps.determine-stage.outputs.report_file }} From 86aa3c3c88228114f37421aa1d52c2d06dd5e062 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Thu, 7 May 2026 11:25:08 +0300 Subject: [PATCH 13/20] remove old env e2e-start-time Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index d397cb629e..e0229792a6 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -1361,11 +1361,6 @@ jobs: echo "[INFO] Showing exists vmclasses" kubectl get vmclass - - name: Set vars - id: vars - run: | - echo "e2e-start-time=${E2E_START_TIME}" >> $GITHUB_OUTPUT - - name: Run E2E id: e2e-report env: From 3744d050a91f54783e9ade05718f9a6c60ae4226 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Thu, 7 May 2026 11:38:59 +0300 Subject: [PATCH 14/20] decrypt Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 39 +++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index e0229792a6..077a31a85e 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -438,17 +438,32 @@ jobs: yq e '.discovered.registry_auth = "None"' -i ./${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp/discovered-values.yaml || echo "The discovered-values.yaml file is not generated, skipping editing registry_auth" echo "${{ steps.generate-kubeconfig.outputs.kubeconfig }}" | base64 -d | base64 -d > ./${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config || echo "kubeconfig not available, skipping" + - name: Encrypt generated files artifact + if: success() || failure() + env: + GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + ARTIFACT_NAME: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }} + run: | + pushd ${{ env.SETUP_CLUSTER_TYPE_PATH }} + zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip tmp values.yaml + popd + gpg --symmetric --batch --yes --pinentry-mode loopback \ + --passphrase "$GPG_PASSPHRASE" \ + --cipher-algo AES256 \ + --output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \ + $RUNNER_TEMP/${ARTIFACT_NAME}.zip + rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip + - name: Upload generated files uses: actions/upload-artifact@v7 if: success() || failure() with: - name: ${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }} - path: | - ${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp - ${{ env.SETUP_CLUSTER_TYPE_PATH }}/values.yaml + name: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }} + path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }}.zip.gpg overwrite: true include-hidden-files: true retention-days: 3 + archive: false - name: Encrypt ssh config artifact if: always() @@ -1755,8 +1770,20 @@ jobs: - name: Download artifacts uses: actions/download-artifact@v5 with: - name: ${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }} - path: ${{ env.SETUP_CLUSTER_TYPE_PATH }}/ + name: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }} + path: ${{ runner.temp }}/encrypted-generated-files + + - name: Decrypt generated files artifact + env: + GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + ARTIFACT_NAME: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }} + run: | + artifact_path=${{ runner.temp }}/encrypted-generated-files/${ARTIFACT_NAME}.zip.gpg + gpg --decrypt --batch --yes --pinentry-mode loopback \ + --passphrase "$GPG_PASSPHRASE" \ + --output $RUNNER_TEMP/${ARTIFACT_NAME}.zip \ + "$artifact_path" + unzip -o $RUNNER_TEMP/${ARTIFACT_NAME}.zip -d ${{ env.SETUP_CLUSTER_TYPE_PATH }} - name: Configure kubectl via azure/k8s-set-context@v4 uses: azure/k8s-set-context@v4 From c861db9170d2dad15de63ddc5c4ca8748efaf0a6 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Thu, 7 May 2026 11:47:13 +0300 Subject: [PATCH 15/20] revertme: test Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-matrix.yml | 30 +-------------------- .github/workflows/e2e-reusable-pipeline.yml | 4 +-- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/.github/workflows/e2e-matrix.yml b/.github/workflows/e2e-matrix.yml index 2590f8cb8f..1c4fc7e5e0 100644 --- a/.github/workflows/e2e-matrix.yml +++ b/.github/workflows/e2e-matrix.yml @@ -413,33 +413,6 @@ jobs: echo "date-start=$(date +%Y%m%d-%H%M%S)" >> $GITHUB_OUTPUT echo "randuuid4c=$(openssl rand -hex 2)" >> $GITHUB_OUTPUT - e2e-replicated: - name: E2E Pipeline (Replicated) - needs: - - set-vars - uses: ./.github/workflows/e2e-reusable-pipeline.yml - with: - storage_type: replicated - nested_storageclass_name: nested-thin-r1 - nested_cluster_network_name: cn-4006-for-e2e-test - branch: main - virtualization_tag: main - deckhouse_channel: alpha - default_user: cloud - go_version: "1.25.9" - e2e_timeout: "3.5h" - date_start: ${{ needs.set-vars.outputs.date_start }} - randuuid4c: ${{ needs.set-vars.outputs.randuuid4c }} - cluster_config_workers_memory: "9Gi" - cluster_config_k8s_version: "1.34" - apt_mirror_enabled: true - secrets: - DEV_REGISTRY_DOCKER_CFG: ${{ secrets.DEV_REGISTRY_DOCKER_CFG }} - VIRT_E2E_NIGHTLY_SA_TOKEN: ${{ secrets.VIRT_E2E_NIGHTLY_SA_TOKEN }} - PROD_IO_REGISTRY_DOCKER_CFG: ${{ secrets.PROD_IO_REGISTRY_DOCKER_CFG }} - BOOTSTRAP_DEV_PROXY: ${{ secrets.BOOTSTRAP_DEV_PROXY }} - E2E_ARTIFACTS_GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} - e2e-nfs: name: E2E Pipeline (NFS) needs: @@ -471,7 +444,6 @@ jobs: runs-on: ubuntu-latest name: End-to-End tests report needs: - - e2e-replicated - e2e-nfs if: ${{ always()}} env: @@ -739,4 +711,4 @@ jobs: curl --request POST --header 'Content-Type: application/json' --data "{\"text\": \"${COMBINED_SUMMARY}\"}" "$LOOP_WEBHOOK_URL" fi env: - LOOP_WEBHOOK_URL: ${{ secrets.LOOP_WEBHOOK_URL }} + LOOP_WEBHOOK_URL: ${{ secrets.LOOP_TEST_CHANNEL }} diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index 077a31a85e..b14cc0e5ac 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -1393,7 +1393,7 @@ jobs: summary_file_name_junit="e2e_summary_${CSI}_${DATE}.xml" ginkgo_json_report="ginkgo_report_${CSI}_${DATE}.json" summary_file_name_json="e2e_summary_${CSI}_${DATE}.json" - FOCUS="${{ inputs.e2e_focus_tests }}" + FOCUS="VirtualMachineMigration" cp -a legacy/testdata /tmp/testdata @@ -1470,7 +1470,7 @@ jobs: echo $SUMMARY > "${summary_file_name_json}" echo "[INFO] Exit code: $GINKGO_EXIT_CODE" - exit $GINKGO_EXIT_CODE + exit 0 - name: Encrypt summary test results artifact if: always() && steps.e2e-report.outcome != 'skipped' env: From d7026f536f303620a0520837290cedd82bce4a49 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Thu, 7 May 2026 14:38:16 +0300 Subject: [PATCH 16/20] update download-artifact Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-matrix.yml | 2 +- .github/workflows/e2e-reusable-pipeline.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-matrix.yml b/.github/workflows/e2e-matrix.yml index 1c4fc7e5e0..98be739c2b 100644 --- a/.github/workflows/e2e-matrix.yml +++ b/.github/workflows/e2e-matrix.yml @@ -452,7 +452,7 @@ jobs: - uses: actions/checkout@v4 - name: Download E2E report artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 continue-on-error: true id: download-artifacts-pattern with: diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index b14cc0e5ac..f33591f010 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -1554,7 +1554,7 @@ jobs: - uses: actions/checkout@v4 - name: Download E2E test results if available - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 continue-on-error: true with: name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }} @@ -1768,7 +1768,7 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Download artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }} path: ${{ runner.temp }}/encrypted-generated-files From d1804d2fffaaf532e2e07ddde46c925091409371 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Thu, 7 May 2026 19:02:39 +0300 Subject: [PATCH 17/20] refer to full name in download Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index f33591f010..a40ccd8a13 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -458,7 +458,6 @@ jobs: uses: actions/upload-artifact@v7 if: success() || failure() with: - name: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }} path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }}.zip.gpg overwrite: true include-hidden-files: true @@ -485,7 +484,6 @@ jobs: uses: actions/upload-artifact@v7 if: always() with: - name: ${{ env.STORAGE_TYPE }}-generated-files-ssh-${{ env.E2E_START_TIME }} path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-ssh-${{ env.E2E_START_TIME }}.zip.gpg overwrite: true include-hidden-files: true @@ -507,7 +505,6 @@ jobs: - name: Upload kubeconfig uses: actions/upload-artifact@v7 with: - name: ${{ env.STORAGE_TYPE }}-generated-files-kubeconfig-${{ env.E2E_START_TIME }} path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-kubeconfig-${{ env.E2E_START_TIME }}.gpg overwrite: true include-hidden-files: true @@ -1501,7 +1498,6 @@ jobs: id: e2e-report-artifact if: always() && steps.e2e-report.outcome != 'skipped' with: - name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }} path: ${{ runner.temp }}/e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}.zip.gpg if-no-files-found: ignore retention-days: 3 @@ -1533,7 +1529,6 @@ jobs: uses: actions/upload-artifact@v7 if: always() && steps.e2e-report.outcome != 'skipped' with: - name: resources_from_failed_tests-${{ env.STORAGE_TYPE }}-${{ env.E2E_START_TIME }} path: ${{ runner.temp }}/resources_from_failed_tests-${{ env.STORAGE_TYPE }}-${{ env.E2E_START_TIME }}.zip.gpg if-no-files-found: ignore retention-days: 3 @@ -1557,7 +1552,7 @@ jobs: uses: actions/download-artifact@v8 continue-on-error: true with: - name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }} + name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}.zip.gpg path: ${{ runner.temp }}/encrypted-e2e-results - name: Decrypt E2E test results if available @@ -1770,7 +1765,7 @@ jobs: - name: Download artifacts uses: actions/download-artifact@v8 with: - name: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }} + name: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }}.zip.gpg path: ${{ runner.temp }}/encrypted-generated-files - name: Decrypt generated files artifact From d97ca39ef06a2f575f19681bea48055bff42b30f Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Thu, 7 May 2026 19:02:53 +0300 Subject: [PATCH 18/20] remove encrypt/decrypt of results Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 54 +++------------------ 1 file changed, 8 insertions(+), 46 deletions(-) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index a40ccd8a13..b0adb08868 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -1468,40 +1468,19 @@ jobs: echo "[INFO] Exit code: $GINKGO_EXIT_CODE" exit 0 - - name: Encrypt summary test results artifact - if: always() && steps.e2e-report.outcome != 'skipped' - env: - GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} - ARTIFACT_NAME: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }} - run: | - shopt -s nullglob - files=( - test/e2e/e2e_summary_*.json - test/e2e/ginkgo_report_*.json - test/e2e/e2e_summary_*.xml - test/e2e/*junit*.xml - ) - if [ ${#files[@]} -eq 0 ]; then - echo "[INFO] No E2E summary files found, skipping encryption" - exit 0 - fi - zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip "${files[@]}" - gpg --symmetric --batch --yes --pinentry-mode loopback \ - --passphrase "$GPG_PASSPHRASE" \ - --cipher-algo AES256 \ - --output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \ - $RUNNER_TEMP/${ARTIFACT_NAME}.zip - rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip - - name: Upload summary test results (junit/xml) uses: actions/upload-artifact@v7 id: e2e-report-artifact if: always() && steps.e2e-report.outcome != 'skipped' with: - path: ${{ runner.temp }}/e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}.zip.gpg + name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }} + path: | + test/e2e/e2e_summary_*.json + test/e2e/ginkgo_report_*.json + test/e2e/e2e_summary_*.xml + test/e2e/*junit*.xml if-no-files-found: ignore retention-days: 3 - archive: false - name: Encrypt resources from failed tests artifact if: always() && steps.e2e-report.outcome != 'skipped' @@ -1552,25 +1531,8 @@ jobs: uses: actions/download-artifact@v8 continue-on-error: true with: - name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}.zip.gpg - path: ${{ runner.temp }}/encrypted-e2e-results - - - name: Decrypt E2E test results if available - continue-on-error: true - env: - GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} - run: | - mkdir -p test/e2e - artifact_path=${{ runner.temp }}/encrypted-e2e-results/e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}.zip.gpg - if [ ! -f "$artifact_path" ]; then - echo "[INFO] Encrypted E2E results artifact not found, skipping decryption" - exit 0 - fi - gpg --decrypt --batch --yes --pinentry-mode loopback \ - --passphrase "$GPG_PASSPHRASE" \ - --output $RUNNER_TEMP/e2e-test-results-${STORAGE_TYPE}-${GITHUB_RUN_ID}-${E2E_START_TIME}.zip \ - "$artifact_path" - unzip -o $RUNNER_TEMP/e2e-test-results-${STORAGE_TYPE}-${GITHUB_RUN_ID}-${E2E_START_TIME}.zip + name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }} + path: test/e2e/ - name: Determine failed stage and prepare report id: determine-stage From ef65cf499e4790dc8d81812bd5adba6c9e81e467 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Fri, 8 May 2026 10:21:52 +0300 Subject: [PATCH 19/20] revert test stuff Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-matrix.yml | 30 ++++++++++++++++++++- .github/workflows/e2e-reusable-pipeline.yml | 4 +-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-matrix.yml b/.github/workflows/e2e-matrix.yml index 98be739c2b..66f03355c3 100644 --- a/.github/workflows/e2e-matrix.yml +++ b/.github/workflows/e2e-matrix.yml @@ -413,6 +413,33 @@ jobs: echo "date-start=$(date +%Y%m%d-%H%M%S)" >> $GITHUB_OUTPUT echo "randuuid4c=$(openssl rand -hex 2)" >> $GITHUB_OUTPUT + e2e-replicated: + name: E2E Pipeline (Replicated) + needs: + - set-vars + uses: ./.github/workflows/e2e-reusable-pipeline.yml + with: + storage_type: replicated + nested_storageclass_name: nested-thin-r1 + nested_cluster_network_name: cn-4006-for-e2e-test + branch: main + virtualization_tag: main + deckhouse_channel: alpha + default_user: cloud + go_version: "1.25.9" + e2e_timeout: "3.5h" + date_start: ${{ needs.set-vars.outputs.date_start }} + randuuid4c: ${{ needs.set-vars.outputs.randuuid4c }} + cluster_config_workers_memory: "9Gi" + cluster_config_k8s_version: "1.34" + apt_mirror_enabled: true + secrets: + DEV_REGISTRY_DOCKER_CFG: ${{ secrets.DEV_REGISTRY_DOCKER_CFG }} + VIRT_E2E_NIGHTLY_SA_TOKEN: ${{ secrets.VIRT_E2E_NIGHTLY_SA_TOKEN }} + PROD_IO_REGISTRY_DOCKER_CFG: ${{ secrets.PROD_IO_REGISTRY_DOCKER_CFG }} + BOOTSTRAP_DEV_PROXY: ${{ secrets.BOOTSTRAP_DEV_PROXY }} + E2E_ARTIFACTS_GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }} + e2e-nfs: name: E2E Pipeline (NFS) needs: @@ -444,6 +471,7 @@ jobs: runs-on: ubuntu-latest name: End-to-End tests report needs: + - e2e-replicated - e2e-nfs if: ${{ always()}} env: @@ -711,4 +739,4 @@ jobs: curl --request POST --header 'Content-Type: application/json' --data "{\"text\": \"${COMBINED_SUMMARY}\"}" "$LOOP_WEBHOOK_URL" fi env: - LOOP_WEBHOOK_URL: ${{ secrets.LOOP_TEST_CHANNEL }} + LOOP_WEBHOOK_URL: ${{ secrets.LOOP_WEBHOOK_URL }} diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index b0adb08868..6c8ff81bed 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -1390,7 +1390,7 @@ jobs: summary_file_name_junit="e2e_summary_${CSI}_${DATE}.xml" ginkgo_json_report="ginkgo_report_${CSI}_${DATE}.json" summary_file_name_json="e2e_summary_${CSI}_${DATE}.json" - FOCUS="VirtualMachineMigration" + FOCUS="${{ inputs.e2e_focus_tests }}" cp -a legacy/testdata /tmp/testdata @@ -1467,7 +1467,7 @@ jobs: echo $SUMMARY > "${summary_file_name_json}" echo "[INFO] Exit code: $GINKGO_EXIT_CODE" - exit 0 + exit $GINKGO_EXIT_CODE - name: Upload summary test results (junit/xml) uses: actions/upload-artifact@v7 id: e2e-report-artifact From 90903d9ac076e501f888d376badaa0fcaf4c7d79 Mon Sep 17 00:00:00 2001 From: Maksim Fedotov Date: Fri, 8 May 2026 17:09:26 +0300 Subject: [PATCH 20/20] add job summary Signed-off-by: Maksim Fedotov --- .github/workflows/e2e-reusable-pipeline.yml | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.github/workflows/e2e-reusable-pipeline.yml b/.github/workflows/e2e-reusable-pipeline.yml index 6c8ff81bed..3828253dc5 100644 --- a/.github/workflows/e2e-reusable-pipeline.yml +++ b/.github/workflows/e2e-reusable-pipeline.yml @@ -511,6 +511,42 @@ jobs: retention-days: 3 archive: false + - name: Add encrypted artifacts help to job summary + if: always() + run: | + cat >> "$GITHUB_STEP_SUMMARY" <<'EOF' + ## Encrypted artifacts + + Some uploaded artifacts in this workflow are encrypted with GPG symmetric encryption. + + Secret used for decryption passphrase: + - `E2E_ARTIFACTS_GPG_PASSPHRASE` + + Encrypted artifact types: + - `*-generated-files-*.zip.gpg` + - `*-generated-files-ssh-*.zip.gpg` + - `*-generated-files-kubeconfig-*.gpg` + - `resources_from_failed_tests-*.zip.gpg` + + Decrypt commands: + + ```bash + # zip.gpg artifact + gpg --decrypt --batch --yes --pinentry-mode loopback \ + --passphrase "$E2E_ARTIFACTS_GPG_PASSPHRASE" \ + --output artifact.zip \ + artifact.zip.gpg + + unzip -o artifact.zip + + # single-file .gpg artifact + gpg --decrypt --batch --yes --pinentry-mode loopback \ + --passphrase "$E2E_ARTIFACTS_GPG_PASSPHRASE" \ + --output kube-config \ + artifact.gpg + ``` + EOF + configure-sdn: name: Configure SDN runs-on: ubuntu-latest