diff --git a/.github/workflows/_release-rust.yml b/.github/workflows/_release-rust.yml index 0211677..a549d5b 100644 --- a/.github/workflows/_release-rust.yml +++ b/.github/workflows/_release-rust.yml @@ -67,6 +67,31 @@ on: required: false type: string default: "" + # --- Code signing (opt-in; default off → no change for existing callers) --- + enable_signing: + description: "Enable OS code signing of built binaries" + required: false + type: boolean + default: false + notarize_macos: + description: "Submit macOS binaries for Apple notarization" + required: false + type: boolean + default: true + # NOTE: the CODESIGN_*/PGP_SIGN_* config values are declared under `secrets:` + # below (not here). Callers in public repos store them as secrets, and the + # `secrets` context cannot be referenced from a reusable-workflow `with:` — + # so they must be passed through the `secrets:` block. + jsign_sha256: + description: "Pinned sha256 of the jsign jar" + required: false + type: string + default: "" + rcodesign_sha256: + description: "Pinned sha256 of the rcodesign tarball" + required: false + type: string + default: "" secrets: app_id: description: "GitHub App ID" @@ -74,9 +99,50 @@ on: app_pem: description: "GitHub App PEM" required: false + # Code-signing secrets. NOTE: no Apple secrets — macOS creds live in GCP + # Secret Manager (fetched via the CODESIGN_* identity). + pgp_cert_base64: + description: "Base64 OpenPGP public cert (Linux)" + required: false + pgp_signer_token: + description: "Token (GitHub App or PAT) with read on private kunobi-ninja/kunobi-pgp-kms" + required: false + windows_cert_chain: + description: "PKCS7 EV certificate chain (Windows Authenticode)" + required: false + # CODESIGN_*/PGP_SIGN_* config — passed as secrets (callers in public repos + # keep these out of Variables; secrets can't ride in a reusable-workflow `with:`). + codesign_wif_provider: + description: "WIF provider for code signing (Windows Authenticode + Apple Secret Manager)" + required: false + codesign_gcp_project: + description: "GCP project for code signing + Apple Secret Manager" + required: false + codesign_service_account: + description: "Service account to impersonate; empty = direct WIF" + required: false + codesign_kms_keyring: + description: "Authenticode KMS keyring" + required: false + codesign_kms_key_alias: + description: "Authenticode KMS key alias" + required: false + pgp_sign_wif_provider: + description: "WIF provider for OpenPGP KMS (Linux)" + required: false + pgp_sign_gcp_project_id: + description: "GCP project for OpenPGP KMS" + required: false + pgp_sign_service_account: + description: "Service account for OpenPGP KMS" + required: false + pgp_sign_kms_key_version: + description: "OpenPGP KMS key version path" + required: false permissions: contents: write + id-token: write jobs: # --- Job 1: Compute build matrix from target list --- @@ -316,6 +382,56 @@ jobs: strip "$BIN" fi + # --- Code signing: all platforms sign the BINARY before packaging. + # macOS/Windows embed the signature in the binary; Linux produces a + # detached .asc that gets bundled into the archive next to the binary. --- + - name: Sign macOS binary + if: inputs.enable_signing && contains(matrix.target, 'apple-darwin') + uses: zondax/actions/sign-macos-binary@v1 + with: + binary-path: target/${{ matrix.target }}/release/${{ inputs.binary_name }} + workload-identity-provider: ${{ secrets.codesign_wif_provider }} + gcp-project: ${{ secrets.codesign_gcp_project }} + service-account: ${{ secrets.codesign_service_account }} + notarize: ${{ inputs.notarize_macos }} + rcodesign-sha256: ${{ inputs.rcodesign_sha256 }} + + - name: Authenticate with GCP (Authenticode) + id: auth-codesign + if: inputs.enable_signing && contains(matrix.target, 'windows') + uses: zondax/actions/gcp-wif-auth@v1 + with: + workload_identity_provider: ${{ secrets.codesign_wif_provider }} + project_id: ${{ secrets.codesign_gcp_project }} + service_account: ${{ secrets.codesign_service_account }} + token_format: access_token + create_credentials_file: 'false' + setup_gcloud: 'false' + verify_authentication: 'false' + + - name: Sign Windows binary + if: inputs.enable_signing && contains(matrix.target, 'windows') + uses: zondax/actions/sign-windows-binary@v1 + with: + binary-path: target/${{ matrix.target }}/release/${{ inputs.binary_name }}.exe + gcp-access-token: ${{ steps.auth-codesign.outputs.access_token }} + kms-keyring: ${{ secrets.codesign_kms_keyring }} + kms-key-alias: ${{ secrets.codesign_kms_key_alias }} + cert-chain: ${{ secrets.windows_cert_chain }} + jsign-sha256: ${{ inputs.jsign_sha256 }} + + - name: Sign Linux binary + if: inputs.enable_signing && contains(matrix.target, 'linux') + uses: zondax/actions/sign-linux-binary@v1 + with: + target-path: target/${{ matrix.target }}/release/${{ inputs.binary_name }} + workload-identity-provider: ${{ secrets.pgp_sign_wif_provider }} + gcp-project-id: ${{ secrets.pgp_sign_gcp_project_id }} + service-account: ${{ secrets.pgp_sign_service_account }} + signer-token: ${{ secrets.pgp_signer_token }} + kms-key: ${{ secrets.pgp_sign_kms_key_version }} + cert-base64: ${{ secrets.pgp_cert_base64 }} + - name: Package env: TARGET: ${{ matrix.target }} @@ -335,9 +451,31 @@ jobs: (cd "target/$TARGET/release" && zip "$OLDPWD/$ARCHIVE" "${BINARY_NAME}${BINARY_EXT}") fi else - tar czf "$ARCHIVE" -C "target/$TARGET/release" "${BINARY_NAME}${BINARY_EXT}" + # Bundle the detached .asc (Linux binary signing) into the tarball + # next to the binary, so the signature travels with what it signs. + ASC="${BINARY_NAME}${BINARY_EXT}.asc" + if [ -f "target/$TARGET/release/$ASC" ]; then + tar czf "$ARCHIVE" -C "target/$TARGET/release" "${BINARY_NAME}${BINARY_EXT}" "$ASC" + else + tar czf "$ARCHIVE" -C "target/$TARGET/release" "${BINARY_NAME}${BINARY_EXT}" + fi fi + # Linux ALSO signs the packaged archive (detached .asc, top-level release + # asset) — in addition to the binary's .asc bundled inside it. Two PGP sigs: + # one over the ELF (inside the tarball), one over the .tar.gz (download). + - name: Sign Linux archive + if: inputs.enable_signing && contains(matrix.target, 'linux') + uses: zondax/actions/sign-linux-binary@v1 + with: + target-path: ${{ inputs.binary_name }}-${{ matrix.target }}.${{ matrix.archive_ext }} + workload-identity-provider: ${{ secrets.pgp_sign_wif_provider }} + gcp-project-id: ${{ secrets.pgp_sign_gcp_project_id }} + service-account: ${{ secrets.pgp_sign_service_account }} + signer-token: ${{ secrets.pgp_signer_token }} + kms-key: ${{ secrets.pgp_sign_kms_key_version }} + cert-base64: ${{ secrets.pgp_cert_base64 }} + - name: Checksum env: TARGET: ${{ matrix.target }} @@ -364,6 +502,7 @@ jobs: path: | ${{ inputs.binary_name }}-${{ matrix.target }}.${{ matrix.archive_ext }} ${{ inputs.binary_name }}-${{ matrix.target }}.${{ matrix.archive_ext }}.sha256 + ${{ inputs.binary_name }}-${{ matrix.target }}.${{ matrix.archive_ext }}.asc # --- Job 3: Create/upload GitHub Release --- release: