From 83117238fcb4e9b70be1996a493bc049be182e57 Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Thu, 10 Sep 2026 13:35:25 -0700 Subject: [PATCH 1/4] chore(ci): finalize Artifact Signing setup --- .github/workflows/gateway-msix.yml | 11 ++++-- README.md | 29 +++++++++++++++ scripts/Test-WorkflowSigningConfiguration.ps1 | 36 +++++++++++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 scripts/Test-WorkflowSigningConfiguration.ps1 diff --git a/.github/workflows/gateway-msix.yml b/.github/workflows/gateway-msix.yml index 15d1530d..d2b36fe7 100644 --- a/.github/workflows/gateway-msix.yml +++ b/.github/workflows/gateway-msix.yml @@ -62,6 +62,11 @@ jobs: run: > .\scripts\Test-SigningInputs.Tests.ps1 + - name: Test signing workflow configuration + shell: pwsh + run: > + .\scripts\Test-WorkflowSigningConfiguration.ps1 + - name: Test workflow package version shell: pwsh run: > @@ -377,9 +382,9 @@ jobs: - name: Azure login uses: azure/login@v3 with: - client-id: ${{ secrets.AZURE_CLIENT_ID }} - tenant-id: ${{ secrets.AZURE_TENANT_ID }} - subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + client-id: ${{ vars.AZURE_CLIENT_ID }} + tenant-id: ${{ vars.AZURE_TENANT_ID }} + subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} - name: Sign MSIX packages uses: azure/artifact-signing-action@v2 diff --git a/README.md b/README.md index f5d4df6d..af3daaae 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,35 @@ Test-signing private keys are generated only on the temporary GitHub runner and are deleted before artifacts are uploaded. No signing secret or private key is stored in the repository. +### Official signing setup + +The `release-signing` GitHub environment must define these environment +variables (they are identifiers, not credentials): + +- `AZURE_CLIENT_ID`: application (client) ID of the Entra application used by + the Windows Companion release workflow; +- `AZURE_TENANT_ID`: Entra tenant ID; +- `AZURE_SUBSCRIPTION_ID`: Azure subscription containing the signing resource. + +Do not create an `AZURE_CLIENT_SECRET`. The `sign-msix` job requests a +short-lived Azure token with GitHub OIDC. The Entra application must have a +federated identity credential with: + +- issuer: `https://token.actions.githubusercontent.com`; +- subject: + `repo:openclaw@252820863/openclaw-windows-packaging@1347889239:environment:release-signing`; +- audience: `api://AzureADTokenExchange`. + +This repository was created after GitHub's immutable OIDC subject rollout, so +the subject includes the organization and repository IDs. The older mutable +`repo:openclaw/openclaw-windows-packaging:...` form will not match its tokens. + +The service principal must have `Artifact Signing Certificate Profile Signer` +on the `openclaw` certificate profile (or a containing scope). The workflow +uses account `openclaw`, certificate profile `openclaw`, and endpoint +`https://eus.codesigning.azure.net/`. The expected public certificate subject +is recorded in `release-policy.json`. + ## Installed data | Data | Default path | diff --git a/scripts/Test-WorkflowSigningConfiguration.ps1 b/scripts/Test-WorkflowSigningConfiguration.ps1 new file mode 100644 index 00000000..1be424b5 --- /dev/null +++ b/scripts/Test-WorkflowSigningConfiguration.ps1 @@ -0,0 +1,36 @@ +[CmdletBinding()] +param() + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$repositoryRoot = Split-Path $PSScriptRoot -Parent +$workflowPath = Join-Path ` + $repositoryRoot ` + '.github\workflows\gateway-msix.yml' +$workflow = Get-Content -LiteralPath $workflowPath -Raw + +$requiredFragments = @( + 'environment: release-signing' + 'id-token: write' + 'uses: azure/login@v3' + 'client-id: ${{ vars.AZURE_CLIENT_ID }}' + 'tenant-id: ${{ vars.AZURE_TENANT_ID }}' + 'subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}' + 'uses: azure/artifact-signing-action@v2' + 'endpoint: https://eus.codesigning.azure.net/' + 'signing-account-name: openclaw' + 'certificate-profile-name: openclaw' +) + +foreach ($fragment in $requiredFragments) { + if (-not $workflow.Contains($fragment, [StringComparison]::Ordinal)) { + throw "Signing workflow is missing required configuration: $fragment" + } +} + +if ($workflow.Contains('AZURE_CLIENT_SECRET', [StringComparison]::Ordinal)) { + throw 'Signing workflow must use OIDC, not an Azure client secret.' +} + +Write-Host 'Gateway MSIX signing workflow configuration passed.' From d8b3825f4d33ef8cd7d1daed7c39cb6787369bf8 Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Fri, 11 Sep 2026 18:00:18 -0700 Subject: [PATCH 2/4] docs: name the dedicated packaging signer --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index af3daaae..034270e0 100644 --- a/README.md +++ b/README.md @@ -154,8 +154,8 @@ key is stored in the repository. The `release-signing` GitHub environment must define these environment variables (they are identifiers, not credentials): -- `AZURE_CLIENT_ID`: application (client) ID of the Entra application used by - the Windows Companion release workflow; +- `AZURE_CLIENT_ID`: application (client) ID of the dedicated + `openclaw-windows-packaging-signing` Entra application; - `AZURE_TENANT_ID`: Entra tenant ID; - `AZURE_SUBSCRIPTION_ID`: Azure subscription containing the signing resource. From 421f38d26f3655f54e1165fb7633f02b2e426cdb Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Fri, 11 Sep 2026 18:01:04 -0700 Subject: [PATCH 3/4] docs: use the MSIX signing identity name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 034270e0..f29240da 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ The `release-signing` GitHub environment must define these environment variables (they are identifiers, not credentials): - `AZURE_CLIENT_ID`: application (client) ID of the dedicated - `openclaw-windows-packaging-signing` Entra application; + `openclaw-windows-msix-signing` Entra application; - `AZURE_TENANT_ID`: Entra tenant ID; - `AZURE_SUBSCRIPTION_ID`: Azure subscription containing the signing resource. From c4f56ba483bde91e93067562a8f213df87096726 Mon Sep 17 00:00:00 2001 From: Dallin Romney Date: Fri, 11 Sep 2026 18:43:58 -0700 Subject: [PATCH 4/4] fix(ci): recurse into signing artifact folders --- .github/workflows/gateway-msix.yml | 1 + scripts/Test-WorkflowSigningConfiguration.ps1 | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/gateway-msix.yml b/.github/workflows/gateway-msix.yml index 7d35af6f..2aff1cb8 100644 --- a/.github/workflows/gateway-msix.yml +++ b/.github/workflows/gateway-msix.yml @@ -421,6 +421,7 @@ jobs: certificate-profile-name: openclaw files-folder: artifacts files-folder-filter: msix + files-folder-recurse: true files-folder-depth: 2 file-digest: SHA256 timestamp-rfc3161: http://timestamp.acs.microsoft.com diff --git a/scripts/Test-WorkflowSigningConfiguration.ps1 b/scripts/Test-WorkflowSigningConfiguration.ps1 index 1be424b5..b47146f9 100644 --- a/scripts/Test-WorkflowSigningConfiguration.ps1 +++ b/scripts/Test-WorkflowSigningConfiguration.ps1 @@ -18,6 +18,7 @@ $requiredFragments = @( 'tenant-id: ${{ vars.AZURE_TENANT_ID }}' 'subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}' 'uses: azure/artifact-signing-action@v2' + 'files-folder-recurse: true' 'endpoint: https://eus.codesigning.azure.net/' 'signing-account-name: openclaw' 'certificate-profile-name: openclaw'