Skip to content

Add a consolidated security guidance page for developers - #735

Merged
Nikola Metulev (nmetulev) merged 10 commits into
mainfrom
azchohfi-security-guidance
Aug 12, 2026
Merged

Nikola Metulev (nmetulev) merged 10 commits into
mainfrom
azchohfi-security-guidance

Conversation

@azchohfi

Copy link
Copy Markdown
Collaborator

What was missing

The repo had no consolidated security guidance. SECURITY.md was only the standard vulnerability-reporting boilerplate, and certificate / Developer Mode guidance was spread across individual framework guides — they show the commands, but rarely the consequence of running them.

Several things had no coverage anywhere:

  • What trusting a certificate into LocalMachine\TrustedPeople actually grants, and how to remove it later.
  • What Developer Mode enables, and why it should not be left on for machines that only need to run the app.
  • Safe handling of devcert.pfx — keeping it out of source control and out of the packaged output.
  • That the documented default PFX password (password) leaves the private key effectively unprotected, and that this is fine only for a throwaway local test certificate.
  • Production signing options collected in one place.

What this adds

A single new page, docs/security.md, rather than warnings scattered through every guide:

  • Development certificates — exactly what winapp cert generate produces (RSA-2048 / SHA-256, code-signing EKU, non-CA, 365-day default, exportable key, plus a copy in Cert:\CurrentUser\My), what the default password means, why devcert.pfx must stay out of both git and the packaged folder, what winapp cert install grants via LocalMachine\TrustedPeople, and how to remove a certificate when you are done with it.
  • Developer Mode — the two HKLM\...\AppModelUnlock values the CLI writes, why there is a UAC prompt, what the machine will then accept, how winapp init prompts (and skips the prompt under --use-defaults / non-interactive, so CI is unaffected), and how to turn it back off.
  • Signing for production — Azure Trusted Signing via winapp az-sign, a CA-issued certificate via winapp sign, or Store submission, plus keeping certificate passwords in a CI secret store.
  • A short pre-publish checklist.

Supporting changes

  • docs/README.md — links the new page from the additional-guides list and Related topics (hand-maintained index, no auto-discovery).
  • llms.txt — adds the page to the Docs list.
  • SECURITY.md — adds a short section linking the new page. The existing Microsoft reporting block is untouched.
  • docs/guides/electron/packaging.md — the Electron Forge example previously showed certificatePassword: 'password' with no comment. The example still works, but now reads the password from an environment variable with the dev-certificate default as a fallback, and an admonition explains why a real signing password must never live in a committed forge.config.js.

Tone

Factual and proportionate. Development certificates and Developer Mode are the normal path for local testing and the page says so; the goal is that a reader understands the consequence of each command before running it.

Validation

No CLI or build surface changed, so nothing needed rebuilding. Every relative link and usage.md anchor referenced by the new page was verified to resolve against a real file/heading in the tree. The page satisfies the MS Learn front-matter rules used by scripts/validate-mslearn-docs.ps1: <!-- mslearn: true --> marker present, H1 title, a distinct <!-- description: ... --> of 137 characters (within the 115–145 range), YAML-safe as a plain scalar, no banned marketing words, and all callouts use MS Learn alert syntax.

Certificate and Developer Mode guidance was spread across individual
framework guides, which showed the commands to run but rarely explained
what they change on the machine. Several consequences had no coverage at
all: what trusting a certificate into LocalMachine\TrustedPeople actually
grants and how to undo it, what Developer Mode enables, how to handle
devcert.pfx, and why the documented default PFX password is only
acceptable for a throwaway local test certificate.

Add docs/security.md as the single authoritative page covering the
development certificate lifecycle, Developer Mode, and production signing
options, so a reader understands the consequence of each command before
running it. Link it from the docs index, llms.txt, and SECURITY.md
(keeping the existing reporting boilerplate intact), and update the
Electron Forge example so the default certificate password is shown as a
development-only value rather than a fine default.
Copilot AI balanced review requested due to automatic review settings August 11, 2026 23:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds consolidated security guidance for development certificates, Developer Mode, and production signing.

Changes:

  • Adds security guidance and cleanup instructions.
  • Links the guidance from documentation indexes.
  • Improves Electron signing-password handling.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
SECURITY.md Links developer security guidance.
llms.txt Adds the security page.
docs/security.md Documents certificates, Developer Mode, and signing.
docs/README.md Adds navigation links.
docs/guides/electron/packaging.md Uses an environment-based certificate password.
Suppressed comments (2)

docs/security.md:173

  • These are winapp pack options, not winapp sign options. winapp sign requires the certificate path as its second positional argument and uses --password, so following this production-signing guidance currently fails argument parsing.
- **A code-signing certificate from a trusted certificate authority** — use [`winapp sign`](usage.md#sign) with `--cert` and `--cert-password`. You are then responsible for storing the key material safely; keep it in a hardware token, a key vault, or your CI provider's secret store, and never in the repository.

docs/security.md:184

  • This example uses options that winapp sign does not accept. Pass the certificate path positionally and use --password; otherwise the documented CI command exits with parse errors.
winapp sign .\MyApp.msix --cert $env:SIGNING_CERT_PATH --cert-password $env:SIGNING_CERT_PASSWORD

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/security.md Outdated
Comment thread docs/security.md
Comment thread docs/guides/electron/packaging.md Outdated
@github-actions

github-actions Bot commented Aug 11, 2026 •

Copy link
Copy Markdown
Contributor

Build Metrics Report

Binary Sizes

Artifact Baseline Current Delta
CLI (ARM64) 38.62 MB 38.62 MB 📈 +1.5 KB (+0.00%)
CLI (x64) 38.73 MB 38.73 MB 📈 +1.5 KB (+0.00%)
MSIX (ARM64) N/A 16.02 MB N/A
MSIX (x64) N/A 17.01 MB N/A
NPM Package N/A 33.42 MB N/A
NuGet Package N/A 33.46 MB N/A

Test Results

✅ 4562 passed, 5 skipped out of 4567 tests in 575.6s (+7 tests, -258.0s vs. baseline)

Test Coverage

✅ 89.1% line coverage, 82.4% branch coverage · ✅ no change vs. baseline

CLI Startup Time

48ms median (x64, winapp --version) · ⚠️ +15ms vs. baseline

Try This Build

Installs the MSIX for your architecture, replacing any previously installed build. Needs the GitHub CLI — the command offers to install it and sign you in if it is missing.

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/microsoft/winappCli/main/scripts/winapp-pr.ps1))) 735
Switching between builds often?

Put the tool on your PATH once:

& ([scriptblock]::Create((irm https://raw.githubusercontent.com/microsoft/winappCli/main/scripts/winapp-pr.ps1))) -AddToPath

Then this build is just:

winapp-pr 735

Run winapp-pr with no arguments to pick from a list of open PRs.


Updated 2026-08-12 19:31:19 UTC · commit c1c5f82 · workflow run

…context

Three problems in the new security page taught commands that do not work, or
that leave state behind.

winapp sign takes the certificate as a positional argument with --password; the
page described a --cert-password option that only exists on winapp package. A
systematic pass over every command mentioned also turned up --no-prompt on
winapp init, which does not exist either -- only --use-defaults does, and its
documented behavior of leaving Developer Mode untouched is correct.

The certificate cleanup told the reader to remove the CurrentUser copy from an
elevated prompt. If elevation uses a different administrator account, that path
resolves to the administrator store and the private key survives in the
generating user account. Split the two removals and state which context each
one runs in.

The Electron guide linked ../security.md from docs/guides/electron/, which
resolves one directory short of the new page.
@azchohfi

Copy link
Copy Markdown
Collaborator Author

Thanks — all three were real. Fixed, plus two more of the same class that I found by checking the rest of the page systematically rather than only the flagged lines.

1. --cert-password on sign — correct, that option belongs to winapp package, not winapp sign. Verified against SignCommand.cs: the certificate is the second positional argument and the password option is --password. Fixed at all three sites (39, 173, 184).

2. Cert:\CurrentUser under elevation — also correct, and the consequence is that the private key survives in the generating user's store. Split into two blocks: the LocalMachine\TrustedPeople removal marked as elevated, the CurrentUser\My removal marked as non-elevated and run as the account that generated the certificate, with a callout explaining why mixing them up leaves the key behind.

3. Broken ../security.md link — fixed to ../../security.md.

Additionally found while checking the rest of the page:

  • winapp init --no-prompt does not exist. Only --use-defaults does. Removed the invented flag. The surrounding behavioral claim is accurate — AskShouldEnableDeveloperModeAsync returns false when UseDefaults is set, so Developer Mode really is left untouched.
  • winapp pack was flagged by my own check as not existing, but it is a legitimate alias of package, so it stays.

Verification performed:

  • Every relative link in the changed files resolved mechanically against disk — 74 links, 0 broken. The only two failures were pre-existing MS Learn site-root paths in docs/README.md (/windows/apps/...), which are correct for Learn publishing and untouched by this PR.
  • Every anchor link resolved against the actual headings in the target files — 37 anchors, 0 bad.
  • Every command and option mentioned in the page checked against docs/cli-schema.json, which is generated from the CLI.
  • Certificate facts re-checked against CertificateService.cs: RSA-2048 exportable, SHA-256 with PKCS#1 v1.5, EKU 1.3.6.1.5.5.7.3.3, 365-day default, devcert.pfx. All as documented.
  • The .gitignore claim checked against CertGenerateCommand.cs (updateGitignore: true).

usage.md documented winapp sign as taking --cert and --cert-password. Neither
exists on that command: the certificate is a second positional argument and the
password option is --password. It also omitted cert-path and --timestamp.

This is where the same error in the new security page came from, and the
security page links to this anchor, so a reader who followed the link still got
instructions that fail.

Verified against docs/cli-schema.json, which is generated from the CLI:
sign args=[file-path,cert-path] opts=[--password,--quiet,--timestamp,--verbose].
port-mslearn-docs.ps1 keeps a curated nav tree, and the Pester suite asserts
every ported page appears as a toc href. security.md is picked up by the port
glob, so adding the page without a nav entry broke that test -- which is the
check doing its job: a page that ports but never appears in the left nav is
invisible on Learn.

Listed top level after UI Automation, labelled from its H1.
@nmetulev
Nikola Metulev (nmetulev) merged commit 34201f0 into main Aug 12, 2026
30 checks passed
@nmetulev
Nikola Metulev (nmetulev) deleted the azchohfi-security-guidance branch August 12, 2026 23:31
Nikola Metulev (nmetulev) pushed a commit that referenced this pull request Sep 21, 2026
Resolves #902

## What

Adds a direct link to `docs/security.md` from the top-level `README.md`,
placed as a "See also" line under the **Certificates & Signing** section
of the Commands Overview — matching the existing pattern used for the
Debugging Guide.

## Why

`docs/security.md` (the consolidated security guidance page from #735)
was only reachable indirectly via the docs hub (`docs/README.md`), so a
developer starting from the repo root was unlikely to discover it. Its
content (certificates, Developer Mode, signing, trust) maps naturally to
the Certificates & Signing section.

The link points to the canonical page rather than duplicating any
content, per the repo's "state each user-facing fact once on its
canonical surface" guidance.

Docs-only change; no build impact.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants