Skip to content
Open
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
17 changes: 16 additions & 1 deletion .claude/agents/winapp.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ Does the project already have an appxmanifest.xml?
│ └─ Is the exe separate from your app code? (Electron, sparse package testing)
│ └─ winapp create-debug-identity <exe-path> (registers sparse package)
├─ Need to sign an existing MSIX or exe?
│ └─ winapp sign <file> <cert>
│ ├─ With a local dev/CA certificate (PFX)?
│ │ └─ winapp sign <file> <cert>
│ └─ With Azure Trusted Signing (cloud-managed identity, no local PFX)?
│ └─ winapp az-sign <file>
└─ Need to run a Windows SDK tool directly (makeappx, signtool, makepri)?
└─ winapp tool <toolname> <args>

Expand Down Expand Up @@ -165,6 +168,18 @@ Want to inspect or interact with a running app's UI?
- `--password <pwd>` — certificate password
- `--timestamp <url>` — timestamp server URL (recommended for production to stay valid after cert expires)

### `winapp az-sign <file-path>`
**Purpose:** Code-sign an exe, MSIX, or MSIX bundle using Azure Trusted Signing (a cloud-managed signing identity — no local PFX).
**When to use:** For production signing when the certificate is managed in Azure rather than as a local PFX file. Works in CI/CD and interactively.
**Key options:**
- `--subscription <id>` (`-s`) — Azure subscription ID (prompts if omitted and multiple exist)
- `--resource-group <rg>` (`-r`) — resource group to narrow down signing accounts
- `--account <name>` — signing account name (requires `--resource-group`)
- `--profile <name>` (`-p`) — certificate profile name (requires `--account`)
- `--metadata-file <path>` (`-m`) — reuse an existing `metadata.json`, skipping all prompting
**Auth:** Uses `DefaultAzureCredential`. For CI/CD set `AZURE_TENANT_ID`/`AZURE_CLIENT_ID`/`AZURE_CLIENT_SECRET` (or OIDC/managed identity); interactively falls back to `az login`.
**Requires:** An Azure Trusted Signing account + certificate profile, and the Trusted Signing Certificate Profile Signer role.

### `winapp manifest generate [directory]`
**Purpose:** Create an `appxmanifest.xml` without full project setup.
**When to use:** When you only need a manifest and image assets, without SDK installation or config file creation.
Expand Down
42 changes: 42 additions & 0 deletions .claude/skills/winapp-signing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Use this skill when:
- **Generating a development certificate** for local MSIX signing and testing
- **Installing (trusting) a certificate** on a machine so MSIX packages can be installed
- **Signing an MSIX package or executable** for distribution
- **Signing with Azure Trusted Signing** (cloud-managed signing identity) via `winapp az-sign`

## Prerequisites

Expand Down Expand Up @@ -80,6 +81,25 @@ When packaging multiple architectures into an `.msixbundle`, only the bundle nee

Note: The `package` command can sign automatically when you pass `--cert`, so you often don't need `sign` separately.

### Sign with Azure Trusted Signing (cloud signing)

For production-grade signing without managing a PFX file, use `winapp az-sign` to sign with [Azure Trusted Signing](https://learn.microsoft.com/azure/trusted-signing/). The signing identity (certificate) is managed in Azure, so no private key ever lives on the machine.

```powershell
# Interactive: discover subscription, account, and profile (prompts for any not provided)
winapp az-sign ./app.msix

# Fully specified — no prompting (ideal for CI/CD)
winapp az-sign ./app.msix --subscription <sub-id> --resource-group <rg> --account <account> --profile <profile>

# Reuse an existing metadata.json (skips all discovery/prompting)
winapp az-sign ./app.msix --metadata-file ./metadata.json
```

**Authentication:** `az-sign` uses Azure's standard credential chain (`DefaultAzureCredential`). In CI/CD, set `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET` (or GitHub Actions OIDC / managed identity). Interactively, if no credentials are found and the Azure CLI is installed, `az-sign` runs `az login` for you.

**Prerequisites:** An Azure Trusted Signing account and certificate profile (created in the Azure portal after identity validation), plus a role assignment granting your identity the **Trusted Signing Certificate Profile Signer** role.

## Recommended workflow

1. **Generate cert** — `winapp cert generate` (auto-infers publisher from manifest)
Expand Down Expand Up @@ -108,6 +128,8 @@ Note: The `package` command can sign automatically when you pass `--cert`, so yo
| "Certificate not trusted" | Cert not installed on machine | `winapp cert install ./devcert.pfx` (admin) |
| "Certificate file already exists" | `devcert.pfx` already present | Use `--if-exists overwrite` or `--if-exists skip` |
| Signature invalid after time passes | No timestamp used during signing | Re-sign with `--timestamp http://timestamp.digicert.com` |
| `az-sign` fails with "No credentials found" | No Azure auth in environment | Run `az login`, or set `AZURE_TENANT_ID`/`AZURE_CLIENT_ID`/`AZURE_CLIENT_SECRET` for CI/CD |
| `az-sign` "No Trusted Signing accounts found" | No account in the subscription/resource group | Create a Trusted Signing account and certificate profile in the Azure portal |


## Command Reference
Expand Down Expand Up @@ -181,3 +203,23 @@ Code-sign an MSIX package or executable. Example: winapp sign ./app.msix ./devce
|--------|-------------|---------|
| `--password` | Certificate password | `password` |
| `--timestamp` | Timestamp server URL | (none) |

### `winapp az-sign`

Code-sign a file using Azure Trusted Signing. Signs executables, MSIX packages, or MSIX bundles using a cloud-managed signing identity. Example: winapp az-sign ./app.msix

#### Arguments
<!-- auto-generated from cli-schema.json -->
| Argument | Required | Description |
|----------|----------|-------------|
| `<file-path>` | Yes | Path to the file to sign (exe, msix, or msixbundle) |

#### Options
<!-- auto-generated from cli-schema.json -->
| Option | Description | Default |
|--------|-------------|---------|
| `--account` | Signing account name. Must be used with --resource-group | (none) |
| `--metadata-file` | Path to an existing metadata.json file. Skips all prompting and uses this file directly for signing. | (none) |
| `--profile` | Certificate profile name. Must be used with --account | (none) |
| `--resource-group` | Resource group to narrow down signing accounts | (none) |
| `--subscription` | Azure subscription ID to use. If not provided and multiple subscriptions exist, you will be prompted. | (none) |
17 changes: 16 additions & 1 deletion .github/plugin/agents/winapp.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ Does the project already have an appxmanifest.xml?
│ └─ Is the exe separate from your app code? (Electron, sparse package testing)
│ └─ winapp create-debug-identity <exe-path> (registers sparse package)
├─ Need to sign an existing MSIX or exe?
│ └─ winapp sign <file> <cert>
│ ├─ With a local dev/CA certificate (PFX)?
│ │ └─ winapp sign <file> <cert>
│ └─ With Azure Trusted Signing (cloud-managed identity, no local PFX)?
│ └─ winapp az-sign <file>
└─ Need to run a Windows SDK tool directly (makeappx, signtool, makepri)?
└─ winapp tool <toolname> <args>

Expand Down Expand Up @@ -166,6 +169,18 @@ Want to inspect or interact with a running app's UI?
- `--password <pwd>` — certificate password
- `--timestamp <url>` — timestamp server URL (recommended for production to stay valid after cert expires)

### `winapp az-sign <file-path>`
**Purpose:** Code-sign an exe, MSIX, or MSIX bundle using Azure Trusted Signing (a cloud-managed signing identity — no local PFX).
**When to use:** For production signing when the certificate is managed in Azure rather than as a local PFX file. Works in CI/CD and interactively.
**Key options:**
- `--subscription <id>` (`-s`) — Azure subscription ID (prompts if omitted and multiple exist)
- `--resource-group <rg>` (`-r`) — resource group to narrow down signing accounts
- `--account <name>` — signing account name (requires `--resource-group`)
- `--profile <name>` (`-p`) — certificate profile name (requires `--account`)
- `--metadata-file <path>` (`-m`) — reuse an existing `metadata.json`, skipping all prompting
**Auth:** Uses `DefaultAzureCredential`. For CI/CD set `AZURE_TENANT_ID`/`AZURE_CLIENT_ID`/`AZURE_CLIENT_SECRET` (or OIDC/managed identity); interactively falls back to `az login`.
**Requires:** An Azure Trusted Signing account + certificate profile, and the Trusted Signing Certificate Profile Signer role.

### `winapp manifest generate [directory]`
**Purpose:** Create an `appxmanifest.xml` without full project setup.
**When to use:** When you only need a manifest and image assets, without SDK installation or config file creation.
Expand Down
42 changes: 42 additions & 0 deletions .github/plugin/skills/winapp-cli/signing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Use this skill when:
- **Generating a development certificate** for local MSIX signing and testing
- **Installing (trusting) a certificate** on a machine so MSIX packages can be installed
- **Signing an MSIX package or executable** for distribution
- **Signing with Azure Trusted Signing** (cloud-managed signing identity) via `winapp az-sign`

## Prerequisites

Expand Down Expand Up @@ -80,6 +81,25 @@ When packaging multiple architectures into an `.msixbundle`, only the bundle nee

Note: The `package` command can sign automatically when you pass `--cert`, so you often don't need `sign` separately.

### Sign with Azure Trusted Signing (cloud signing)

For production-grade signing without managing a PFX file, use `winapp az-sign` to sign with [Azure Trusted Signing](https://learn.microsoft.com/azure/trusted-signing/). The signing identity (certificate) is managed in Azure, so no private key ever lives on the machine.

```powershell
# Interactive: discover subscription, account, and profile (prompts for any not provided)
winapp az-sign ./app.msix

# Fully specified — no prompting (ideal for CI/CD)
winapp az-sign ./app.msix --subscription <sub-id> --resource-group <rg> --account <account> --profile <profile>

# Reuse an existing metadata.json (skips all discovery/prompting)
winapp az-sign ./app.msix --metadata-file ./metadata.json
```

**Authentication:** `az-sign` uses Azure's standard credential chain (`DefaultAzureCredential`). In CI/CD, set `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET` (or GitHub Actions OIDC / managed identity). Interactively, if no credentials are found and the Azure CLI is installed, `az-sign` runs `az login` for you.

**Prerequisites:** An Azure Trusted Signing account and certificate profile (created in the Azure portal after identity validation), plus a role assignment granting your identity the **Trusted Signing Certificate Profile Signer** role.

## Recommended workflow

1. **Generate cert** — `winapp cert generate` (auto-infers publisher from manifest)
Expand Down Expand Up @@ -108,6 +128,8 @@ Note: The `package` command can sign automatically when you pass `--cert`, so yo
| "Certificate not trusted" | Cert not installed on machine | `winapp cert install ./devcert.pfx` (admin) |
| "Certificate file already exists" | `devcert.pfx` already present | Use `--if-exists overwrite` or `--if-exists skip` |
| Signature invalid after time passes | No timestamp used during signing | Re-sign with `--timestamp http://timestamp.digicert.com` |
| `az-sign` fails with "No credentials found" | No Azure auth in environment | Run `az login`, or set `AZURE_TENANT_ID`/`AZURE_CLIENT_ID`/`AZURE_CLIENT_SECRET` for CI/CD |
| `az-sign` "No Trusted Signing accounts found" | No account in the subscription/resource group | Create a Trusted Signing account and certificate profile in the Azure portal |


## Command Reference
Expand Down Expand Up @@ -181,3 +203,23 @@ Code-sign an MSIX package or executable. Example: winapp sign ./app.msix ./devce
|--------|-------------|---------|
| `--password` | Certificate password | `password` |
| `--timestamp` | Timestamp server URL | (none) |

### `winapp az-sign`

Code-sign a file using Azure Trusted Signing. Signs executables, MSIX packages, or MSIX bundles using a cloud-managed signing identity. Example: winapp az-sign ./app.msix

#### Arguments
<!-- auto-generated from cli-schema.json -->
| Argument | Required | Description |
|----------|----------|-------------|
| `<file-path>` | Yes | Path to the file to sign (exe, msix, or msixbundle) |

#### Options
<!-- auto-generated from cli-schema.json -->
| Option | Description | Default |
|--------|-------------|---------|
| `--account` | Signing account name. Must be used with --resource-group | (none) |
| `--metadata-file` | Path to an existing metadata.json file. Skips all prompting and uses this file directly for signing. | (none) |
| `--profile` | Certificate profile name. Must be used with --account | (none) |
| `--resource-group` | Resource group to narrow down signing accounts | (none) |
| `--subscription` | Azure subscription ID to use. If not provided and multiple subscriptions exist, you will be prompted. | (none) |
123 changes: 123 additions & 0 deletions docs/cli-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,129 @@
}
},
"subcommands": {
"az-sign": {
"description": "Code-sign a file using Azure Trusted Signing. Signs executables, MSIX packages, or MSIX bundles using a cloud-managed signing identity. Example: winapp az-sign ./app.msix",
"hidden": false,
"arguments": {
"file-path": {
"description": "Path to the file to sign (exe, msix, or msixbundle)",
"order": 0,
"hidden": false,
"valueType": "System.IO.FileInfo",
"hasDefaultValue": false,
"arity": {
"minimum": 1,
"maximum": 1
}
}
},
"options": {
"--account": {
"description": "Signing account name. Must be used with --resource-group",
"hidden": false,
"valueType": "System.String",
"hasDefaultValue": false,
"arity": {
"minimum": 1,
"maximum": 1
},
"required": false,
"recursive": false
},
"--metadata-file": {
"description": "Path to an existing metadata.json file. Skips all prompting and uses this file directly for signing.",
"hidden": false,
"aliases": [
"-m"
],
"valueType": "System.IO.FileInfo",
"hasDefaultValue": false,
"arity": {
"minimum": 1,
"maximum": 1
},
"required": false,
"recursive": false
},
"--profile": {
"description": "Certificate profile name. Must be used with --account",
"hidden": false,
"aliases": [
"-p"
],
"valueType": "System.String",
"hasDefaultValue": false,
"arity": {
"minimum": 1,
"maximum": 1
},
"required": false,
"recursive": false
},
"--quiet": {
"description": "Suppress progress messages",
"hidden": false,
"aliases": [
"-q"
],
"valueType": "System.Boolean",
"hasDefaultValue": true,
"defaultValue": false,
"arity": {
"minimum": 0,
"maximum": 1
},
"required": false,
"recursive": false
},
"--resource-group": {
"description": "Resource group to narrow down signing accounts",
"hidden": false,
"aliases": [
"-r"
],
"valueType": "System.String",
"hasDefaultValue": false,
"arity": {
"minimum": 1,
"maximum": 1
},
"required": false,
"recursive": false
},
"--subscription": {
"description": "Azure subscription ID to use. If not provided and multiple subscriptions exist, you will be prompted.",
"hidden": false,
"aliases": [
"-s"
],
"valueType": "System.String",
"hasDefaultValue": false,
"arity": {
"minimum": 1,
"maximum": 1
},
"required": false,
"recursive": false
},
"--verbose": {
"description": "Enable verbose output",
"hidden": false,
"aliases": [
"-v"
],
"valueType": "System.Boolean",
"hasDefaultValue": true,
"defaultValue": false,
"arity": {
"minimum": 0,
"maximum": 1
},
"required": false,
"recursive": false
}
}
},
"cert": {
"description": "Manage development certificates for code signing. Use 'cert generate' to create a self-signed certificate for testing, or 'cert install' (requires elevation) to trust an existing certificate on this machine.",
"hidden": false,
Expand Down
22 changes: 22 additions & 0 deletions docs/fragments/skills/winapp-cli/signing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Use this skill when:
- **Generating a development certificate** for local MSIX signing and testing
- **Installing (trusting) a certificate** on a machine so MSIX packages can be installed
- **Signing an MSIX package or executable** for distribution
- **Signing with Azure Trusted Signing** (cloud-managed signing identity) via `winapp az-sign`

## Prerequisites

Expand Down Expand Up @@ -75,6 +76,25 @@ When packaging multiple architectures into an `.msixbundle`, only the bundle nee

Note: The `package` command can sign automatically when you pass `--cert`, so you often don't need `sign` separately.

### Sign with Azure Trusted Signing (cloud signing)

For production-grade signing without managing a PFX file, use `winapp az-sign` to sign with [Azure Trusted Signing](https://learn.microsoft.com/azure/trusted-signing/). The signing identity (certificate) is managed in Azure, so no private key ever lives on the machine.

```powershell
# Interactive: discover subscription, account, and profile (prompts for any not provided)
winapp az-sign ./app.msix

# Fully specified — no prompting (ideal for CI/CD)
winapp az-sign ./app.msix --subscription <sub-id> --resource-group <rg> --account <account> --profile <profile>

# Reuse an existing metadata.json (skips all discovery/prompting)
winapp az-sign ./app.msix --metadata-file ./metadata.json
```

**Authentication:** `az-sign` uses Azure's standard credential chain (`DefaultAzureCredential`). In CI/CD, set `AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, and `AZURE_CLIENT_SECRET` (or GitHub Actions OIDC / managed identity). Interactively, if no credentials are found and the Azure CLI is installed, `az-sign` runs `az login` for you.

**Prerequisites:** An Azure Trusted Signing account and certificate profile (created in the Azure portal after identity validation), plus a role assignment granting your identity the **Trusted Signing Certificate Profile Signer** role.

## Recommended workflow

1. **Generate cert** — `winapp cert generate` (auto-infers publisher from manifest)
Expand Down Expand Up @@ -103,3 +123,5 @@ Note: The `package` command can sign automatically when you pass `--cert`, so yo
| "Certificate not trusted" | Cert not installed on machine | `winapp cert install ./devcert.pfx` (admin) |
| "Certificate file already exists" | `devcert.pfx` already present | Use `--if-exists overwrite` or `--if-exists skip` |
| Signature invalid after time passes | No timestamp used during signing | Re-sign with `--timestamp http://timestamp.digicert.com` |
| `az-sign` fails with "No credentials found" | No Azure auth in environment | Run `az login`, or set `AZURE_TENANT_ID`/`AZURE_CLIENT_ID`/`AZURE_CLIENT_SECRET` for CI/CD |
| `az-sign` "No Trusted Signing accounts found" | No account in the subscription/resource group | Create a Trusted Signing account and certificate profile in the Azure portal |
Loading
Loading