Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .github/workflows/gateway-msix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,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: >
Expand Down Expand Up @@ -404,9 +409,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
Expand All @@ -416,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
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,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 dedicated
`openclaw-windows-msix-signing` Entra application;
- `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 |
Expand Down
37 changes: 37 additions & 0 deletions scripts/Test-WorkflowSigningConfiguration.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[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'
'files-folder-recurse: true'
'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.'