Skip to content

Commit eb8b3b3

Browse files
authored
chore(ci): encrypt test artifacts (#2327)
Signed-off-by: Maksim Fedotov <maksim.fedotov@flant.com>
1 parent 49ff468 commit eb8b3b3

2 files changed

Lines changed: 141 additions & 30 deletions

File tree

.github/workflows/e2e-matrix.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ jobs:
438438
VIRT_E2E_NIGHTLY_SA_TOKEN: ${{ secrets.VIRT_E2E_NIGHTLY_SA_TOKEN }}
439439
PROD_IO_REGISTRY_DOCKER_CFG: ${{ secrets.PROD_IO_REGISTRY_DOCKER_CFG }}
440440
BOOTSTRAP_DEV_PROXY: ${{ secrets.BOOTSTRAP_DEV_PROXY }}
441+
E2E_ARTIFACTS_GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }}
441442

442443
e2e-nfs:
443444
name: E2E Pipeline (NFS)
@@ -464,6 +465,7 @@ jobs:
464465
VIRT_E2E_NIGHTLY_SA_TOKEN: ${{ secrets.VIRT_E2E_NIGHTLY_SA_TOKEN }}
465466
PROD_IO_REGISTRY_DOCKER_CFG: ${{ secrets.PROD_IO_REGISTRY_DOCKER_CFG }}
466467
BOOTSTRAP_DEV_PROXY: ${{ secrets.BOOTSTRAP_DEV_PROXY }}
468+
E2E_ARTIFACTS_GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }}
467469

468470
report-to-channel:
469471
runs-on: ubuntu-latest
@@ -478,7 +480,7 @@ jobs:
478480
- uses: actions/checkout@v4
479481

480482
- name: Download E2E report artifacts
481-
uses: actions/download-artifact@v5
483+
uses: actions/download-artifact@v8
482484
continue-on-error: true
483485
id: download-artifacts-pattern
484486
with:

.github/workflows/e2e-reusable-pipeline.yml

Lines changed: 138 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ on:
122122
required: true
123123
BOOTSTRAP_DEV_PROXY:
124124
required: true
125+
E2E_ARTIFACTS_GPG_PASSPHRASE:
126+
required: true
125127
outputs:
126128
artifact-name:
127129
description: "Name of the uploaded artifact with E2E report"
@@ -135,6 +137,8 @@ env:
135137
GO_VERSION: ${{ inputs.go_version }}
136138
SETUP_CLUSTER_TYPE_PATH: test/dvp-static-cluster
137139
K8S_VERSION: ${{ inputs.cluster_config_k8s_version }}
140+
STORAGE_TYPE: ${{ inputs.storage_type }}
141+
E2E_START_TIME: ${{ inputs.date_start }}
138142

139143
defaults:
140144
run:
@@ -434,36 +438,114 @@ jobs:
434438
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"
435439
echo "${{ steps.generate-kubeconfig.outputs.kubeconfig }}" | base64 -d | base64 -d > ./${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config || echo "kubeconfig not available, skipping"
436440
441+
- name: Encrypt generated files artifact
442+
if: success() || failure()
443+
env:
444+
GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }}
445+
ARTIFACT_NAME: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }}
446+
run: |
447+
pushd ${{ env.SETUP_CLUSTER_TYPE_PATH }}
448+
zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip tmp values.yaml
449+
popd
450+
gpg --symmetric --batch --yes --pinentry-mode loopback \
451+
--passphrase "$GPG_PASSPHRASE" \
452+
--cipher-algo AES256 \
453+
--output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \
454+
$RUNNER_TEMP/${ARTIFACT_NAME}.zip
455+
rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip
456+
437457
- name: Upload generated files
438-
uses: actions/upload-artifact@v4
458+
uses: actions/upload-artifact@v7
439459
if: success() || failure()
440460
with:
441-
name: ${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}
442-
path: |
443-
${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp
444-
${{ env.SETUP_CLUSTER_TYPE_PATH }}/values.yaml
461+
path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }}.zip.gpg
445462
overwrite: true
446463
include-hidden-files: true
447464
retention-days: 3
465+
archive: false
466+
467+
- name: Encrypt ssh config artifact
468+
if: always()
469+
env:
470+
GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }}
471+
ARTIFACT_NAME: ${{ env.STORAGE_TYPE }}-generated-files-ssh-${{ env.E2E_START_TIME }}
472+
run: |
473+
pushd ${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp
474+
zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip ssh
475+
popd
476+
gpg --symmetric --batch --yes --pinentry-mode loopback \
477+
--passphrase "$GPG_PASSPHRASE" \
478+
--cipher-algo AES256 \
479+
--output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \
480+
$RUNNER_TEMP/${ARTIFACT_NAME}.zip
481+
rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip
448482
449483
- name: Upload ssh config
450-
uses: actions/upload-artifact@v4
484+
uses: actions/upload-artifact@v7
451485
if: always()
452486
with:
453-
name: ${{ inputs.storage_type }}-generated-files-ssh-${{ inputs.date_start }}
454-
path: ${{ env.SETUP_CLUSTER_TYPE_PATH }}/tmp/ssh
487+
path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-ssh-${{ env.E2E_START_TIME }}.zip.gpg
455488
overwrite: true
456489
include-hidden-files: true
457490
retention-days: 3
491+
archive: false
492+
493+
- name: Encrypt kubeconfig artifact
494+
if: always()
495+
env:
496+
GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }}
497+
ARTIFACT_NAME: ${{ env.STORAGE_TYPE }}-generated-files-kubeconfig-${{ env.E2E_START_TIME }}
498+
run: |
499+
gpg --symmetric --batch --yes --pinentry-mode loopback \
500+
--passphrase "$GPG_PASSPHRASE" \
501+
--cipher-algo AES256 \
502+
--output $RUNNER_TEMP/${ARTIFACT_NAME}.gpg \
503+
${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config
458504
459505
- name: Upload kubeconfig
460-
uses: actions/upload-artifact@v4
506+
uses: actions/upload-artifact@v7
461507
with:
462-
name: ${{ inputs.storage_type }}-generated-files-kubeconfig-${{ inputs.date_start }}
463-
path: ${{ env.SETUP_CLUSTER_TYPE_PATH }}/kube-config
508+
path: ${{ runner.temp }}/${{ env.STORAGE_TYPE }}-generated-files-kubeconfig-${{ env.E2E_START_TIME }}.gpg
464509
overwrite: true
465510
include-hidden-files: true
466511
retention-days: 3
512+
archive: false
513+
514+
- name: Add encrypted artifacts help to job summary
515+
if: always()
516+
run: |
517+
cat >> "$GITHUB_STEP_SUMMARY" <<'EOF'
518+
## Encrypted artifacts
519+
520+
Some uploaded artifacts in this workflow are encrypted with GPG symmetric encryption.
521+
522+
Secret used for decryption passphrase:
523+
- `E2E_ARTIFACTS_GPG_PASSPHRASE`
524+
525+
Encrypted artifact types:
526+
- `*-generated-files-*.zip.gpg`
527+
- `*-generated-files-ssh-*.zip.gpg`
528+
- `*-generated-files-kubeconfig-*.gpg`
529+
- `resources_from_failed_tests-*.zip.gpg`
530+
531+
Decrypt commands:
532+
533+
```bash
534+
# zip.gpg artifact
535+
gpg --decrypt --batch --yes --pinentry-mode loopback \
536+
--passphrase "$E2E_ARTIFACTS_GPG_PASSPHRASE" \
537+
--output artifact.zip \
538+
artifact.zip.gpg
539+
540+
unzip -o artifact.zip
541+
542+
# single-file .gpg artifact
543+
gpg --decrypt --batch --yes --pinentry-mode loopback \
544+
--passphrase "$E2E_ARTIFACTS_GPG_PASSPHRASE" \
545+
--output kube-config \
546+
artifact.gpg
547+
```
548+
EOF
467549
468550
configure-sdn:
469551
name: Configure SDN
@@ -1327,13 +1409,6 @@ jobs:
13271409
echo "[INFO] Showing exists vmclasses"
13281410
kubectl get vmclass
13291411
1330-
- name: Set vars
1331-
id: vars
1332-
env:
1333-
DATE_START: ${{ inputs.date_start }}
1334-
run: |
1335-
echo "e2e-start-time=$DATE_START" >> $GITHUB_OUTPUT
1336-
13371412
- name: Run E2E
13381413
id: e2e-report
13391414
env:
@@ -1430,11 +1505,11 @@ jobs:
14301505
echo "[INFO] Exit code: $GINKGO_EXIT_CODE"
14311506
exit $GINKGO_EXIT_CODE
14321507
- name: Upload summary test results (junit/xml)
1433-
uses: actions/upload-artifact@v4
1508+
uses: actions/upload-artifact@v7
14341509
id: e2e-report-artifact
14351510
if: always() && steps.e2e-report.outcome != 'skipped'
14361511
with:
1437-
name: e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ steps.vars.outputs.e2e-start-time }}
1512+
name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}
14381513
path: |
14391514
test/e2e/e2e_summary_*.json
14401515
test/e2e/ginkgo_report_*.json
@@ -1443,14 +1518,36 @@ jobs:
14431518
if-no-files-found: ignore
14441519
retention-days: 3
14451520

1521+
- name: Encrypt resources from failed tests artifact
1522+
if: always() && steps.e2e-report.outcome != 'skipped'
1523+
env:
1524+
GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }}
1525+
ARTIFACT_NAME: resources_from_failed_tests-${{ env.STORAGE_TYPE }}-${{ env.E2E_START_TIME }}
1526+
run: |
1527+
shopt -s nullglob
1528+
files=($RUNNER_TEMP/e2e_failed__*)
1529+
if [ ${#files[@]} -eq 0 ]; then
1530+
echo "[INFO] No failed test resources found, skipping encryption"
1531+
exit 0
1532+
fi
1533+
pushd $RUNNER_TEMP
1534+
zip -r $RUNNER_TEMP/${ARTIFACT_NAME}.zip ${files[@]##$RUNNER_TEMP/}
1535+
popd
1536+
gpg --symmetric --batch --yes --pinentry-mode loopback \
1537+
--passphrase "$GPG_PASSPHRASE" \
1538+
--cipher-algo AES256 \
1539+
--output $RUNNER_TEMP/${ARTIFACT_NAME}.zip.gpg \
1540+
$RUNNER_TEMP/${ARTIFACT_NAME}.zip
1541+
rm -f $RUNNER_TEMP/${ARTIFACT_NAME}.zip
1542+
14461543
- name: Upload resources from failed tests
1447-
uses: actions/upload-artifact@v4
1544+
uses: actions/upload-artifact@v7
14481545
if: always() && steps.e2e-report.outcome != 'skipped'
14491546
with:
1450-
name: resources_from_failed_tests-${{ inputs.storage_type }}-${{ steps.vars.outputs.e2e-start-time }}
1451-
path: ${{ runner.temp }}/e2e_failed__*
1547+
path: ${{ runner.temp }}/resources_from_failed_tests-${{ env.STORAGE_TYPE }}-${{ env.E2E_START_TIME }}.zip.gpg
14521548
if-no-files-found: ignore
14531549
retention-days: 3
1550+
archive: false
14541551

14551552
prepare-report:
14561553
name: Prepare E2E report
@@ -1467,10 +1564,10 @@ jobs:
14671564
- uses: actions/checkout@v4
14681565

14691566
- name: Download E2E test results if available
1470-
uses: actions/download-artifact@v5
1567+
uses: actions/download-artifact@v8
14711568
continue-on-error: true
14721569
with:
1473-
name: e2e-test-results-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }}
1570+
name: e2e-test-results-${{ env.STORAGE_TYPE }}-${{ github.run_id }}-${{ env.E2E_START_TIME }}
14741571
path: test/e2e/
14751572

14761573
- name: Determine failed stage and prepare report
@@ -1626,7 +1723,7 @@ jobs:
16261723
16271724
- name: Upload E2E report artifact
16281725
id: upload-artifact
1629-
uses: actions/upload-artifact@v4
1726+
uses: actions/upload-artifact@v7
16301727
with:
16311728
name: e2e-report-${{ inputs.storage_type }}-${{ github.run_id }}-${{ inputs.date_start }}
16321729
path: ${{ steps.determine-stage.outputs.report_file }}
@@ -1664,10 +1761,22 @@ jobs:
16641761
repo-token: ${{ secrets.GITHUB_TOKEN }}
16651762

16661763
- name: Download artifacts
1667-
uses: actions/download-artifact@v5
1764+
uses: actions/download-artifact@v8
16681765
with:
1669-
name: ${{ inputs.storage_type }}-generated-files-${{ inputs.date_start }}
1670-
path: ${{ env.SETUP_CLUSTER_TYPE_PATH }}/
1766+
name: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }}.zip.gpg
1767+
path: ${{ runner.temp }}/encrypted-generated-files
1768+
1769+
- name: Decrypt generated files artifact
1770+
env:
1771+
GPG_PASSPHRASE: ${{ secrets.E2E_ARTIFACTS_GPG_PASSPHRASE }}
1772+
ARTIFACT_NAME: ${{ env.STORAGE_TYPE }}-generated-files-${{ env.E2E_START_TIME }}
1773+
run: |
1774+
artifact_path=${{ runner.temp }}/encrypted-generated-files/${ARTIFACT_NAME}.zip.gpg
1775+
gpg --decrypt --batch --yes --pinentry-mode loopback \
1776+
--passphrase "$GPG_PASSPHRASE" \
1777+
--output $RUNNER_TEMP/${ARTIFACT_NAME}.zip \
1778+
"$artifact_path"
1779+
unzip -o $RUNNER_TEMP/${ARTIFACT_NAME}.zip -d ${{ env.SETUP_CLUSTER_TYPE_PATH }}
16711780
16721781
- name: Configure kubectl via azure/k8s-set-context@v4
16731782
uses: azure/k8s-set-context@v4

0 commit comments

Comments
 (0)