mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-14 22:57:52 +00:00
Split Windows signing submission from approval-bound collection
Production SignPath signing requests require manual approval in the SignPath UI, so the previous single-job flow (submit with wait-for-completion inside a 40-minute window) let approval latency fail the Windows build, and any re-run rebuilt the binaries and submitted a second request needing a second approval. The Windows lane is now two jobs: sign-windows-agent builds the unsigned executables, submits the SignPath request without waiting, and uploads a 7-day signing-request record; collect-windows-signing absorbs approval latency by polling the recorded request, downloads the signed artifact by request id, and keeps the existing verification and evidence steps. If approval outlasts the 115-minute polling window, the collection job fails with re-run guidance and "Re-run failed jobs" collects the same recorded request - no rebuild, no resubmission. The legacy PFX break-glass backend rides the same two-job shape via an artifact hand-off. Workflow output wiring, artifact names, and evidence content are unchanged for downstream consumers. The shape test now pins the async invariants (no wait-for-completion: true in the candidate workflow), and the code signing policy plus the deployment-installability contract describe the two-phase flow.
This commit is contained in:
parent
d2e25dcb63
commit
3826316eec
5 changed files with 168 additions and 21 deletions
146
.github/workflows/build-release-candidate.yml
vendored
146
.github/workflows/build-release-candidate.yml
vendored
|
|
@ -31,7 +31,7 @@ on:
|
||||||
value: ${{ jobs.build.outputs.manifest_artifact_name }}
|
value: ${{ jobs.build.outputs.manifest_artifact_name }}
|
||||||
windows_signing_backend:
|
windows_signing_backend:
|
||||||
description: 'Windows signing backend used for the candidate'
|
description: 'Windows signing backend used for the candidate'
|
||||||
value: ${{ jobs.sign-windows-agent.outputs.signing_backend }}
|
value: ${{ jobs.collect-windows-signing.outputs.signing_backend }}
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
@ -210,16 +210,14 @@ jobs:
|
||||||
compression-level: 0
|
compression-level: 0
|
||||||
|
|
||||||
sign-windows-agent:
|
sign-windows-agent:
|
||||||
name: Authenticode Sign Windows Agent
|
name: Build and Submit Windows Agent Signing
|
||||||
needs: signing-configuration
|
needs: signing-configuration
|
||||||
if: ${{ inputs.require_windows_signing && needs.signing-configuration.result == 'success' }}
|
if: ${{ inputs.require_windows_signing && needs.signing-configuration.result == 'success' }}
|
||||||
runs-on: windows-2025
|
runs-on: windows-2025
|
||||||
timeout-minutes: 50
|
timeout-minutes: 25
|
||||||
permissions:
|
permissions:
|
||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
outputs:
|
|
||||||
signing_backend: ${{ steps.evidence.outputs.signing_backend }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
|
|
@ -272,6 +270,16 @@ jobs:
|
||||||
if ($LASTEXITCODE -ne 0) { throw "Authenticode signing failed for $($output.Name)." }
|
if ($LASTEXITCODE -ne 0) { throw "Authenticode signing failed for $($output.Name)." }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- name: Upload legacy signed binaries
|
||||||
|
if: ${{ inputs.windows_signing_backend == 'legacy-pfx' }}
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: legacy-signed-windows-agent-${{ github.sha }}-${{ inputs.version }}
|
||||||
|
path: unsigned-native-agent-binaries/
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
compression-level: 0
|
||||||
|
|
||||||
- name: Upload unsigned SignPath input
|
- name: Upload unsigned SignPath input
|
||||||
if: ${{ inputs.windows_signing_backend == 'signpath' }}
|
if: ${{ inputs.windows_signing_backend == 'signpath' }}
|
||||||
id: upload-unsigned-windows
|
id: upload-unsigned-windows
|
||||||
|
|
@ -283,6 +291,10 @@ jobs:
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
compression-level: 0
|
compression-level: 0
|
||||||
|
|
||||||
|
# Production release-signing requests need manual approval in the
|
||||||
|
# SignPath UI, so submission must not wait for completion here: the
|
||||||
|
# collect-windows-signing job absorbs the approval latency instead,
|
||||||
|
# and this build job finishes as soon as the request is on record.
|
||||||
- name: Submit SignPath Authenticode request
|
- name: Submit SignPath Authenticode request
|
||||||
if: ${{ inputs.windows_signing_backend == 'signpath' }}
|
if: ${{ inputs.windows_signing_backend == 'signpath' }}
|
||||||
id: signpath
|
id: signpath
|
||||||
|
|
@ -295,20 +307,128 @@ jobs:
|
||||||
artifact-configuration-slug: ${{ vars.SIGNPATH_ARTIFACT_CONFIGURATION_SLUG }}
|
artifact-configuration-slug: ${{ vars.SIGNPATH_ARTIFACT_CONFIGURATION_SLUG }}
|
||||||
github-artifact-id: ${{ steps.upload-unsigned-windows.outputs.artifact-id }}
|
github-artifact-id: ${{ steps.upload-unsigned-windows.outputs.artifact-id }}
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
wait-for-completion: true
|
wait-for-completion: false
|
||||||
wait-for-completion-timeout-in-seconds: 2400
|
|
||||||
output-artifact-directory: signed-native-agent-binaries
|
|
||||||
parameters: |
|
parameters: |
|
||||||
version: ${{ toJSON(inputs.version) }}
|
version: ${{ toJSON(inputs.version) }}
|
||||||
|
|
||||||
|
- name: Record SignPath signing request
|
||||||
|
if: ${{ inputs.windows_signing_backend == 'signpath' }}
|
||||||
|
shell: pwsh
|
||||||
|
env:
|
||||||
|
SIGNPATH_SIGNING_REQUEST_ID: ${{ steps.signpath.outputs.signing-request-id }}
|
||||||
|
SIGNPATH_SIGNING_REQUEST_URL: ${{ steps.signpath.outputs.signing-request-web-url }}
|
||||||
|
SIGNPATH_INPUT_ARTIFACT_ID: ${{ steps.upload-unsigned-windows.outputs.artifact-id }}
|
||||||
|
run: |
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
if ([string]::IsNullOrWhiteSpace($env:SIGNPATH_SIGNING_REQUEST_ID)) {
|
||||||
|
throw 'SignPath submission returned no signing request id.'
|
||||||
|
}
|
||||||
|
[ordered]@{
|
||||||
|
schemaVersion = 1
|
||||||
|
signingRequestId = $env:SIGNPATH_SIGNING_REQUEST_ID
|
||||||
|
signingRequestUrl = $env:SIGNPATH_SIGNING_REQUEST_URL
|
||||||
|
githubInputArtifactId = $env:SIGNPATH_INPUT_ARTIFACT_ID
|
||||||
|
} | ConvertTo-Json | Set-Content windows-signing-request.json -Encoding utf8NoBOM
|
||||||
|
Write-Host "::notice::SignPath signing request submitted and awaiting approval: $env:SIGNPATH_SIGNING_REQUEST_URL"
|
||||||
|
|
||||||
|
# 7-day retention (not 1) so a failed collection job can still be
|
||||||
|
# re-run against the recorded request days later without a rebuild.
|
||||||
|
- name: Upload SignPath signing request record
|
||||||
|
if: ${{ inputs.windows_signing_backend == 'signpath' }}
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
name: windows-signing-request-${{ github.sha }}-${{ inputs.version }}
|
||||||
|
path: windows-signing-request.json
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
# Production SignPath signing needs manual approval in the SignPath UI, so
|
||||||
|
# collection is decoupled from the build: if approval outlasts the polling
|
||||||
|
# window below, approve the request and use "Re-run failed jobs" - the
|
||||||
|
# recorded signing request is collected as-is, with no rebuild and no
|
||||||
|
# second submission or approval.
|
||||||
|
collect-windows-signing:
|
||||||
|
name: Collect and Verify Windows Authenticode
|
||||||
|
needs: sign-windows-agent
|
||||||
|
if: ${{ inputs.require_windows_signing && needs.sign-windows-agent.result == 'success' }}
|
||||||
|
runs-on: windows-2025
|
||||||
|
timeout-minutes: 120
|
||||||
|
outputs:
|
||||||
|
signing_backend: ${{ steps.evidence.outputs.signing_backend }}
|
||||||
|
steps:
|
||||||
|
- name: Download legacy signed binaries
|
||||||
|
if: ${{ inputs.windows_signing_backend == 'legacy-pfx' }}
|
||||||
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
|
with:
|
||||||
|
name: legacy-signed-windows-agent-${{ github.sha }}-${{ inputs.version }}
|
||||||
|
path: unsigned-native-agent-binaries
|
||||||
|
|
||||||
|
- name: Download SignPath signing request record
|
||||||
|
if: ${{ inputs.windows_signing_backend == 'signpath' }}
|
||||||
|
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||||
|
with:
|
||||||
|
name: windows-signing-request-${{ github.sha }}-${{ inputs.version }}
|
||||||
|
path: windows-signing-request
|
||||||
|
|
||||||
|
- name: Wait for SignPath approval and download signed binaries
|
||||||
|
if: ${{ inputs.windows_signing_backend == 'signpath' }}
|
||||||
|
id: signpath
|
||||||
|
shell: pwsh
|
||||||
|
env:
|
||||||
|
SIGNPATH_API_TOKEN: ${{ secrets.SIGNPATH_API_TOKEN }}
|
||||||
|
SIGNPATH_ORGANIZATION_ID: ${{ vars.SIGNPATH_ORGANIZATION_ID }}
|
||||||
|
run: |
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$record = Get-Content windows-signing-request/windows-signing-request.json -Raw | ConvertFrom-Json
|
||||||
|
$requestId = $record.signingRequestId
|
||||||
|
$requestUrl = $record.signingRequestUrl
|
||||||
|
if ([string]::IsNullOrWhiteSpace($requestId)) { throw 'Signing request record has no signing request id.' }
|
||||||
|
"signing_request_id=$requestId" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
||||||
|
"signing_request_url=$requestUrl" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
||||||
|
"github_input_artifact_id=$($record.githubInputArtifactId)" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
||||||
|
|
||||||
|
$statusUri = "https://app.signpath.io/API/v1/$($env:SIGNPATH_ORGANIZATION_ID)/SigningRequests/$requestId"
|
||||||
|
$headers = @{ Authorization = "Bearer $($env:SIGNPATH_API_TOKEN)" }
|
||||||
|
$deadline = (Get-Date).AddMinutes(115)
|
||||||
|
$transientFailures = 0
|
||||||
|
while ($true) {
|
||||||
|
try {
|
||||||
|
$request = Invoke-RestMethod -Uri $statusUri -Headers $headers -TimeoutSec 60
|
||||||
|
$transientFailures = 0
|
||||||
|
} catch {
|
||||||
|
$transientFailures++
|
||||||
|
if ($transientFailures -ge 10) { throw }
|
||||||
|
Write-Host "Transient SignPath status error ($transientFailures/10): $($_.Exception.Message)"
|
||||||
|
Start-Sleep -Seconds 60
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
$status = $request.status
|
||||||
|
Write-Host "SignPath signing request $requestId status: $status (workflow: $($request.workflowStatus))"
|
||||||
|
if ($status -eq 'Completed') { break }
|
||||||
|
if ($status -in @('Failed', 'Denied', 'Canceled')) {
|
||||||
|
throw "SignPath signing request $requestId finished as ${status}: $requestUrl"
|
||||||
|
}
|
||||||
|
if ((Get-Date) -gt $deadline) {
|
||||||
|
Write-Host "::error::SignPath signing request $requestId is still $status. Approve it in SignPath ($requestUrl), then use 'Re-run failed jobs' - the recorded request is collected without rebuilding or resubmitting."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Start-Sleep -Seconds 60
|
||||||
|
}
|
||||||
|
|
||||||
|
$zipPath = Join-Path $env:RUNNER_TEMP 'signpath-signed-artifact.zip'
|
||||||
|
Invoke-WebRequest -Uri "$statusUri/SignedArtifact" -Headers $headers -OutFile $zipPath -TimeoutSec 300
|
||||||
|
New-Item -ItemType Directory -Path signed-native-agent-binaries -Force | Out-Null
|
||||||
|
Expand-Archive -Path $zipPath -DestinationPath signed-native-agent-binaries
|
||||||
|
Get-ChildItem signed-native-agent-binaries
|
||||||
|
|
||||||
- name: Verify Authenticode signatures and write evidence
|
- name: Verify Authenticode signatures and write evidence
|
||||||
id: evidence
|
id: evidence
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
env:
|
env:
|
||||||
WINDOWS_SIGNING_BACKEND: ${{ inputs.windows_signing_backend }}
|
WINDOWS_SIGNING_BACKEND: ${{ inputs.windows_signing_backend }}
|
||||||
SIGNPATH_SIGNING_REQUEST_ID: ${{ steps.signpath.outputs.signing-request-id }}
|
SIGNPATH_SIGNING_REQUEST_ID: ${{ steps.signpath.outputs.signing_request_id }}
|
||||||
SIGNPATH_SIGNING_REQUEST_URL: ${{ steps.signpath.outputs.signing-request-web-url }}
|
SIGNPATH_SIGNING_REQUEST_URL: ${{ steps.signpath.outputs.signing_request_url }}
|
||||||
SIGNPATH_INPUT_ARTIFACT_ID: ${{ steps.upload-unsigned-windows.outputs.artifact-id }}
|
SIGNPATH_INPUT_ARTIFACT_ID: ${{ steps.signpath.outputs.github_input_artifact_id }}
|
||||||
SIGNPATH_EXPECTED_CERTIFICATE_SUBJECT: ${{ vars.SIGNPATH_EXPECTED_CERTIFICATE_SUBJECT }}
|
SIGNPATH_EXPECTED_CERTIFICATE_SUBJECT: ${{ vars.SIGNPATH_EXPECTED_CERTIFICATE_SUBJECT }}
|
||||||
run: |
|
run: |
|
||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
@ -366,8 +486,8 @@ jobs:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build and Validate Release Candidate
|
name: Build and Validate Release Candidate
|
||||||
needs: [sign-macos-agent, sign-windows-agent]
|
needs: [sign-macos-agent, collect-windows-signing]
|
||||||
if: ${{ always() && (!inputs.require_macos_signing || needs.sign-macos-agent.result == 'success') && (!inputs.require_windows_signing || needs.sign-windows-agent.result == 'success') }}
|
if: ${{ always() && (!inputs.require_macos_signing || needs.sign-macos-agent.result == 'success') && (!inputs.require_windows_signing || needs.collect-windows-signing.result == 'success') }}
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
outputs:
|
outputs:
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,16 @@ only a non-production JSON evidence record after verification. It never uploads
|
||||||
the test-signed binaries as a GitHub artifact or assembles a release candidate.
|
the test-signed binaries as a GitHub artifact or assembles a release candidate.
|
||||||
|
|
||||||
The canonical CI integration uses SignPath's GitHub trusted-build-system
|
The canonical CI integration uses SignPath's GitHub trusted-build-system
|
||||||
action. GitHub Actions uploads the three unsigned Windows agent executables as
|
action, split into two phases because production signing requests require
|
||||||
one immutable workflow artifact, submits it to SignPath, waits for approval and
|
manual approval in the SignPath UI. The Windows build job uploads the three
|
||||||
completion, downloads the signed result, and verifies every file before
|
unsigned agent executables as one immutable workflow artifact, submits it to
|
||||||
candidate assembly. A non-secret evidence artifact records the SignPath request
|
SignPath without waiting, and records the signing request id. A separate
|
||||||
|
collection job absorbs the approval latency: it waits for the recorded request
|
||||||
|
to complete, downloads the signed result by request id, and verifies every
|
||||||
|
file before candidate assembly. If approval outlasts the collection job's
|
||||||
|
polling window, that job fails with re-run guidance, and re-running it
|
||||||
|
collects the same recorded request — no rebuild, no second submission, no
|
||||||
|
second approval. A non-secret evidence artifact records the SignPath request
|
||||||
URL, source SHA, signer identity, and signed-file SHA-256 values.
|
URL, source SHA, signer identity, and signed-file SHA-256 values.
|
||||||
|
|
||||||
The artifact configuration accepts exactly these ZIP-root files and no others:
|
The artifact configuration accepts exactly these ZIP-root files and no others:
|
||||||
|
|
|
||||||
|
|
@ -495,6 +495,14 @@ upgrade, update, release, or artifact-selection behavior.
|
||||||
by id, verify every returned executable, and retain evidence binding the
|
by id, verify every returned executable, and retain evidence binding the
|
||||||
request, source SHA, signer identity, and file digests. A repository-secret
|
request, source SHA, signer identity, and file digests. A repository-secret
|
||||||
PFX backend is an explicitly selected break-glass fallback only.
|
PFX backend is an explicitly selected break-glass fallback only.
|
||||||
|
Production SignPath signing requests require manual approval in the
|
||||||
|
SignPath UI, so the Windows signing lane must split submission from
|
||||||
|
collection: the build job submits the immutable artifact without waiting
|
||||||
|
and records the signing request id, and a separate collection job absorbs
|
||||||
|
approval latency, downloads the signed result for the recorded request,
|
||||||
|
verifies it, and writes evidence. A collection timeout must fail with
|
||||||
|
operator re-run guidance, and re-running the failed collection job must
|
||||||
|
reuse the recorded request rather than rebuilding or resubmitting.
|
||||||
macOS command-line agent notarization must fail closed unless
|
macOS command-line agent notarization must fail closed unless
|
||||||
`notarytool --wait --output-format json` reports `Accepted`, then verify the
|
`notarytool --wait --output-format json` reports `Accepted`, then verify the
|
||||||
exact candidate bytes with strict `codesign`. Bare Mach-O command-line
|
exact candidate bytes with strict `codesign`. Bare Mach-O command-line
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,16 @@ only a non-production JSON evidence record after verification. It never uploads
|
||||||
the test-signed binaries as a GitHub artifact or assembles a release candidate.
|
the test-signed binaries as a GitHub artifact or assembles a release candidate.
|
||||||
|
|
||||||
The canonical CI integration uses SignPath's GitHub trusted-build-system
|
The canonical CI integration uses SignPath's GitHub trusted-build-system
|
||||||
action. GitHub Actions uploads the three unsigned Windows agent executables as
|
action, split into two phases because production signing requests require
|
||||||
one immutable workflow artifact, submits it to SignPath, waits for approval and
|
manual approval in the SignPath UI. The Windows build job uploads the three
|
||||||
completion, downloads the signed result, and verifies every file before
|
unsigned agent executables as one immutable workflow artifact, submits it to
|
||||||
candidate assembly. A non-secret evidence artifact records the SignPath request
|
SignPath without waiting, and records the signing request id. A separate
|
||||||
|
collection job absorbs the approval latency: it waits for the recorded request
|
||||||
|
to complete, downloads the signed result by request id, and verifies every
|
||||||
|
file before candidate assembly. If approval outlasts the collection job's
|
||||||
|
polling window, that job fails with re-run guidance, and re-running it
|
||||||
|
collects the same recorded request — no rebuild, no second submission, no
|
||||||
|
second approval. A non-secret evidence artifact records the SignPath request
|
||||||
URL, source SHA, signer identity, and signed-file SHA-256 values.
|
URL, source SHA, signer identity, and signed-file SHA-256 values.
|
||||||
|
|
||||||
The artifact configuration accepts exactly these ZIP-root files and no others:
|
The artifact configuration accepts exactly these ZIP-root files and no others:
|
||||||
|
|
|
||||||
|
|
@ -1049,9 +1049,13 @@ func TestReleaseCandidateRequiresPlatformNativeAgentSigning(t *testing.T) {
|
||||||
`result.get('status') != 'Accepted'`,
|
`result.get('status') != 'Accepted'`,
|
||||||
`codesign --verify --deep --strict --verbose=2`,
|
`codesign --verify --deep --strict --verbose=2`,
|
||||||
`sign-windows-agent:`,
|
`sign-windows-agent:`,
|
||||||
|
`collect-windows-signing:`,
|
||||||
`windows_signing_backend:`,
|
`windows_signing_backend:`,
|
||||||
`signpath/github-action-submit-signing-request@b9d91eadd323de506c0c81cf0c7fe7438f3360fd # v2`,
|
`signpath/github-action-submit-signing-request@b9d91eadd323de506c0c81cf0c7fe7438f3360fd # v2`,
|
||||||
`github-artifact-id: ${{ steps.upload-unsigned-windows.outputs.artifact-id }}`,
|
`github-artifact-id: ${{ steps.upload-unsigned-windows.outputs.artifact-id }}`,
|
||||||
|
`wait-for-completion: false`,
|
||||||
|
`windows-signing-request.json`,
|
||||||
|
`Re-run failed jobs`,
|
||||||
`SIGNPATH_API_TOKEN`,
|
`SIGNPATH_API_TOKEN`,
|
||||||
`SIGNPATH_ORGANIZATION_ID`,
|
`SIGNPATH_ORGANIZATION_ID`,
|
||||||
`SIGNPATH_PROJECT_SLUG`,
|
`SIGNPATH_PROJECT_SLUG`,
|
||||||
|
|
@ -1071,6 +1075,9 @@ func TestReleaseCandidateRequiresPlatformNativeAgentSigning(t *testing.T) {
|
||||||
if strings.Contains(string(candidateWorkflow), `spctl --assess --type execute`) {
|
if strings.Contains(string(candidateWorkflow), `spctl --assess --type execute`) {
|
||||||
t.Fatal("bare command-line Mach-O binaries must not use Gatekeeper app assessment after notarization")
|
t.Fatal("bare command-line Mach-O binaries must not use Gatekeeper app assessment after notarization")
|
||||||
}
|
}
|
||||||
|
if strings.Contains(string(candidateWorkflow), `wait-for-completion: true`) {
|
||||||
|
t.Fatal("SignPath submission must not block the Windows build job on manual approval; collection is a separate resumable job")
|
||||||
|
}
|
||||||
assertFileContainsAll(t, repoFile(".github", "workflows", "create-release.yml"),
|
assertFileContainsAll(t, repoFile(".github", "workflows", "create-release.yml"),
|
||||||
`require_macos_signing: true`,
|
`require_macos_signing: true`,
|
||||||
`require_windows_signing: ${{ needs.prepare.outputs.require_windows_signing == 'true' }}`,
|
`require_windows_signing: ${{ needs.prepare.outputs.require_windows_signing == 'true' }}`,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue