action.yml 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. name: Code-sign Windows binaries
  2. description: >
  3. Sign every .exe under a given path in place via the DefinedNet code-signer
  4. Lambda. If `role` or `bucket` is empty, logs a notice and skips signing so
  5. forks and dev branches without AWS access still produce usable builds.
  6. inputs:
  7. path:
  8. description: "Directory whose .exe files should be signed in place"
  9. required: true
  10. role:
  11. description: "IAM role ARN to assume via OIDC; empty disables signing"
  12. required: false
  13. default: ""
  14. bucket:
  15. description: "S3 staging bucket the code-signer Lambda reads from; empty disables signing"
  16. required: false
  17. default: ""
  18. region:
  19. description: "AWS region for the role and Lambda"
  20. required: false
  21. default: "us-east-2"
  22. function-name:
  23. description: "Code-signer Lambda function name"
  24. required: false
  25. default: "code-signer"
  26. key-prefix:
  27. description: "S3 key prefix to write under; defaults to code-signing/<owner>/<repo> of the calling repo"
  28. required: false
  29. default: ""
  30. runs:
  31. using: composite
  32. steps:
  33. - name: Skip notice
  34. if: inputs.role == '' || inputs.bucket == ''
  35. shell: sh
  36. run: echo "::notice::code-signer role or bucket not set; skipping code signing."
  37. - name: Configure AWS credentials
  38. if: inputs.role != '' && inputs.bucket != ''
  39. uses: aws-actions/configure-aws-credentials@v6
  40. with:
  41. role-to-assume: ${{ inputs.role }}
  42. aws-region: ${{ inputs.region }}
  43. # Default is 12 retries to ride out IAM trust-policy propagation; once
  44. # the role is stable we want a real misconfiguration to fail fast.
  45. retry-max-attempts: 5
  46. - name: Sign .exe files
  47. if: inputs.role != '' && inputs.bucket != ''
  48. shell: sh
  49. env:
  50. SIGN_PATH: ${{ inputs.path }}
  51. BUCKET: ${{ inputs.bucket }}
  52. FUNCTION_NAME: ${{ inputs.function-name }}
  53. KEY_PREFIX: ${{ inputs.key-prefix }}
  54. run: |
  55. set -eu
  56. # Default the prefix to this repo so the S3 key attributes the sign correctly.
  57. # nebula-nightly runs this same action but writes under its own repo's prefix.
  58. KEY_PREFIX="${KEY_PREFIX:-code-signing/$GITHUB_REPOSITORY}"
  59. RUN="${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
  60. find "$SIGN_PATH" -name '*.exe' -print | while read -r path
  61. do
  62. rel=${path#"$SIGN_PATH"/}
  63. file=$(basename "$path")
  64. name=${file%.exe}
  65. prefix="${KEY_PREFIX}/${RUN}"
  66. src="${prefix}/unsigned/${rel}"
  67. dst="${prefix}/signed/${rel}"
  68. echo "::group::Sign ${rel}"
  69. echo "Uploading unsigned to s3://${BUCKET}/${src}"
  70. aws s3 cp --no-progress "$path" "s3://${BUCKET}/${src}" >/dev/null
  71. echo "Invoking ${FUNCTION_NAME} Lambda"
  72. payload=$(jq -nc \
  73. --arg s "$src" \
  74. --arg d "$dst" \
  75. --arg p "$name" \
  76. '{source_key: $s, dest_key: $d, program_name: $p}')
  77. meta=$(aws lambda invoke \
  78. --function-name "$FUNCTION_NAME" \
  79. --cli-binary-format raw-in-base64-out \
  80. --payload "$payload" \
  81. --output json \
  82. /tmp/sign-resp.json)
  83. if echo "$meta" | jq -e '.FunctionError != null' >/dev/null
  84. then
  85. echo "::endgroup::"
  86. echo "::error::code-signer Lambda failed for ${rel}"
  87. cat /tmp/sign-resp.json >&2
  88. exit 1
  89. fi
  90. echo "Downloading signed back to ${path}"
  91. aws s3 cp --no-progress "s3://${BUCKET}/${dst}" "$path" >/dev/null
  92. aws s3 rm "s3://${BUCKET}/${src}" >/dev/null 2>&1 || true
  93. aws s3 rm "s3://${BUCKET}/${dst}" >/dev/null 2>&1 || true
  94. # Sanity-check the bytes we got back actually carry an Authenticode
  95. # signature that this machine can validate end to end.
  96. status=$(powershell -NoProfile -Command "(Get-AuthenticodeSignature -FilePath '$path').Status" | tr -d '\r')
  97. if [ "$status" != "Valid" ]
  98. then
  99. echo "::endgroup::"
  100. echo "::error::${rel} signature status: ${status} (expected Valid)"
  101. exit 1
  102. fi
  103. echo "Signed ${rel} (sha256=$(jq -r '.sha256' /tmp/sign-resp.json), status=${status})"
  104. echo "::endgroup::"
  105. done