@@ -503,3 +503,154 @@ jobs:
503503 if git ls-remote --exit-code --heads origin "${branch}" >/dev/null 2>&1; then
504504 git push origin --delete "${branch}"
505505 fi
506+
507+ gpg-signed-commit :
508+ name : GPG-signed commit
509+ needs : [preflight]
510+ runs-on : ubuntu-latest
511+ steps :
512+ - name : Checkout repository
513+ uses : actions/checkout@v6
514+ with :
515+ fetch-depth : 0
516+
517+ - name : Generate GPG signing material
518+ if : ${{ inputs.mode == 'ref' }}
519+ id : gpg
520+ run : |
521+ set -euo pipefail
522+ export GNUPGHOME
523+ GNUPGHOME="$(mktemp -d)"
524+ chmod 700 "${GNUPGHOME}"
525+ cat > gpg-batch <<EOF
526+ Key-Type: RSA
527+ Key-Length: 2048
528+ Name-Real: Triglav E2E
529+ Name-Email: ${{ github.actor }}@users.noreply.github.com
530+ Passphrase: triglav-passphrase
531+ Expire-Date: 0
532+ %commit
533+ EOF
534+ gpg --batch --generate-key gpg-batch
535+ gpg --batch --pinentry-mode loopback --passphrase triglav-passphrase --armor --export-secret-keys "${{ github.actor }}@users.noreply.github.com" > gpg-private.asc
536+ gpg --armor --export "${{ github.actor }}@users.noreply.github.com" > gpg-public.asc
537+ {
538+ echo "secret_key<<EOF"
539+ cat gpg-private.asc
540+ echo "EOF"
541+ echo "public_key<<EOF"
542+ cat gpg-public.asc
543+ echo "EOF"
544+ } >> "${GITHUB_OUTPUT}"
545+
546+ - name : Create test file
547+ run : echo "E2E gpg signing test $(date -u)" > e2e-gpg-signing.md
548+
549+ - name : Commit and push signed changes with GPG
550+ if : ${{ inputs.mode == 'ref' }}
551+ id : gpg_commit
552+ uses : devops-infra/action-commit-push@master
553+ with :
554+ github_token : ${{ secrets.GITHUB_TOKEN }}
555+ commit_message : " test(commit-push): gpg signed commit"
556+ target_branch : test/e2e-commit-push-gpg-${{ github.run_id }}
557+ signing_mode : gpg
558+ signing_key : ${{ steps.gpg.outputs.secret_key }}
559+ signing_passphrase : triglav-passphrase
560+
561+ - name : GPG signing via docker image (preview)
562+ if : ${{ inputs.mode == 'image' }}
563+ run : |
564+ if [ -z "${{ inputs.image_tag }}" ]; then
565+ echo "image_tag is required when mode=image"
566+ exit 1
567+ fi
568+ echo "Image mode placeholder for devopsinfra/action-commit-push:${{ inputs.image_tag }}"
569+ echo "Use ref mode for authoritative validation until image-mode harness is finalized."
570+
571+ - name : Verify GPG commit signature
572+ if : ${{ inputs.mode == 'ref' }}
573+ run : |
574+ set -euo pipefail
575+ export GNUPGHOME
576+ GNUPGHOME="$(mktemp -d)"
577+ chmod 700 "${GNUPGHOME}"
578+ printf '%s\n' "${{ steps.gpg.outputs.public_key }}" > gpg-public.asc
579+ gpg --import gpg-public.asc >/dev/null 2>&1
580+ git fetch origin "test/e2e-commit-push-gpg-${{ github.run_id }}"
581+ git verify-commit "origin/test/e2e-commit-push-gpg-${{ github.run_id }}"
582+
583+ - name : Cleanup - delete test branch
584+ if : ${{ always() && inputs.mode == 'ref' }}
585+ run : |
586+ branch="test/e2e-commit-push-gpg-${{ github.run_id }}"
587+ if git ls-remote --exit-code --heads origin "${branch}" >/dev/null 2>&1; then
588+ git push origin --delete "${branch}"
589+ fi
590+
591+ ssh-signed-commit :
592+ name : SSH-signed commit
593+ needs : [preflight]
594+ runs-on : ubuntu-latest
595+ steps :
596+ - name : Checkout repository
597+ uses : actions/checkout@v6
598+ with :
599+ fetch-depth : 0
600+
601+ - name : Generate SSH signing material
602+ if : ${{ inputs.mode == 'ref' }}
603+ id : ssh
604+ run : |
605+ set -euo pipefail
606+ ssh-keygen -q -t ed25519 -N '' -C "${{ github.actor }}@users.noreply.github.com" -f ssh-signing-key
607+ {
608+ echo "private_key<<EOF"
609+ cat ssh-signing-key
610+ echo "EOF"
611+ echo "public_key<<EOF"
612+ cat ssh-signing-key.pub
613+ echo "EOF"
614+ } >> "${GITHUB_OUTPUT}"
615+
616+ - name : Create test file
617+ run : echo "E2E ssh signing test $(date -u)" > e2e-ssh-signing.md
618+
619+ - name : Commit and push signed changes with SSH
620+ if : ${{ inputs.mode == 'ref' }}
621+ id : ssh_commit
622+ uses : devops-infra/action-commit-push@master
623+ with :
624+ github_token : ${{ secrets.GITHUB_TOKEN }}
625+ commit_message : " test(commit-push): ssh signed commit"
626+ target_branch : test/e2e-commit-push-ssh-${{ github.run_id }}
627+ signing_mode : ssh
628+ signing_key : ${{ steps.ssh.outputs.private_key }}
629+
630+ - name : SSH signing via docker image (preview)
631+ if : ${{ inputs.mode == 'image' }}
632+ run : |
633+ if [ -z "${{ inputs.image_tag }}" ]; then
634+ echo "image_tag is required when mode=image"
635+ exit 1
636+ fi
637+ echo "Image mode placeholder for devopsinfra/action-commit-push:${{ inputs.image_tag }}"
638+ echo "Use ref mode for authoritative validation until image-mode harness is finalized."
639+
640+ - name : Verify SSH commit signature
641+ if : ${{ inputs.mode == 'ref' }}
642+ run : |
643+ set -euo pipefail
644+ printf '%s %s\n' "${{ github.actor }}@users.noreply.github.com" "${{ steps.ssh.outputs.public_key }}" > allowed_signers
645+ git config gpg.format ssh
646+ git config gpg.ssh.allowedSignersFile "$PWD/allowed_signers"
647+ git fetch origin "test/e2e-commit-push-ssh-${{ github.run_id }}"
648+ git verify-commit "origin/test/e2e-commit-push-ssh-${{ github.run_id }}"
649+
650+ - name : Cleanup - delete test branch
651+ if : ${{ always() && inputs.mode == 'ref' }}
652+ run : |
653+ branch="test/e2e-commit-push-ssh-${{ github.run_id }}"
654+ if git ls-remote --exit-code --heads origin "${branch}" >/dev/null 2>&1; then
655+ git push origin --delete "${branch}"
656+ fi
0 commit comments