diff --git a/TODO.md b/TODO.md index cf5f66f..40f789a 100644 --- a/TODO.md +++ b/TODO.md @@ -297,6 +297,138 @@ Reasons: --- +## Code-sign the installer (SmartScreen / Authenticode) + +**Problem.** The v0.1.0-alpha.1 installer is unsigned. Downloading it in +Edge / Chrome trips SmartScreen's "this file isn't commonly downloaded — +make sure you trust it" warning, and running it shows the blue "Windows +protected your PC" dialog. Every user has to click through "More info → +Run anyway", which is a terrible first impression and a real deterrent. + +**Cause.** SmartScreen reputation is built from a combination of valid +Authenticode signatures plus aggregate download counts. An unsigned +binary with zero downloads is automatic prompt-territory. Signing solves +the warning immediately for EV certs and over time (as downloads +accumulate) for OV certs. + +**Options.** + +- **Azure Trusted Signing** (recommended). Microsoft's new managed + signing service, ~$10/month, gives you a cloud-hosted signing identity + with no HSM to manage. Velopack supports it natively via + `--azureTrustedSigningAccount` / `--azureTrustedSigningCertProfile` + flags on `vpk pack`. Wants an Azure subscription and an OIDC trust + relationship from the GitHub Actions runner — five-step setup, no + long-lived secrets in the repo. +- **Standard OV code-signing certificate.** From DigiCert / Sectigo / + GlobalSign, ~$200–400/year. Comes as a cert + key the runner imports. + SmartScreen reputation builds gradually rather than instantly. Easier + if you already have an account with a CA. +- **EV code-signing certificate.** ~$400–600/year, requires an HSM / + USB token (hard to use from CI without a paid signing service in front + of it) but gets immediate SmartScreen reputation. Probably overkill + for an alpha; revisit pre-1.0 stable. + +**Sketch — Azure Trusted Signing path.** + +1. Create the Azure resources (Trusted Signing account, certificate + profile, OIDC trust to the GitHub repo) per + . +2. Add the federated-identity secrets / variables to the repo: tenant + id, client id, account / profile names. +3. In `release.yml`, extend the `vpk pack` step with + `--azureTrustedSigningAccount`, `--azureTrustedSigningCertProfile`, + `--azureTrustedSigningEndpoint` (region URL) and an `azure/login@v2` + step ahead of it for federated auth. +4. Verify with `signtool verify /pa /v Snipdeck-*-Setup.exe` locally + after a download, and re-do the manual install smoke test. + +**Open questions.** + +- Whether the cost ($10/month indefinitely) is acceptable for a hobby / + side project. If not, the OV cert path is a single annual payment. +- Whether the Velopack-generated update packages (the `.nupkg` deltas + used by self-update) also need signing for self-update to keep working + smoothly under SmartScreen. Worth reading the Velopack signing docs + carefully before flipping the switch. + +Not urgent — alpha users can click through the prompt — but blocking +for any kind of broader distribution. + +--- + +## Tighten the iteration loop (build/CI feedback) + +**Problem.** During the phase build-out and post-release fixes, the +build-and-debug cycle relied heavily on PRs as the feedback loop: +local Linux can't build the `Snipdeck.App` project (the WinUI XAML +compiler is Windows-only), so analyser errors / build breaks only +surface in CI. Each round-trip is a PR, which generates churn and +sometimes ends with master broken (PR #13 was merged with red CI). + +**Idea.** Three independent improvements; each is small, all three +together would make the iteration loop tight. + +**Sketch.** + +- **`EnableWindowsTargeting=true` for local builds.** Adding this to + `Snipdeck.App.csproj` (or passing as `-p:EnableWindowsTargeting=true` + on Linux) lets the restore + compile step run on non-Windows hosts. + The WinUI XAML pass still requires Windows, but most analyser / + C# compiler rules fire under plain `dotnet build` and would catch + editorconfig violations (IDE0058, IDE0330, IDE0370, IDE0005 — all + hit in this session) before the push. +- **Branch protection: require status checks to pass.** Add a rule to + the existing branch ruleset on `master` that requires the + `App build (windows)` and `Core build + tests (ubuntu)` checks to be + green before the Merge button activates. Mechanical guardrail + against the merged-red scenario. +- **Draft PRs with force-push fixups during iteration.** Convention, + not config: open PRs as **Draft** while iterating, and amend + + force-push fixup commits into the original commit instead of stacking + "fix lint" follow-ups. The final merged history shows one clean + commit per change, which is what the project's commit log wants. + Auto-mode currently blocks `git push --force-with-lease` — would + need an explicit settings.json permission or a one-off approval + to enable. Force-push to `master` itself stays blocked. + +**Sequencing.** Do `EnableWindowsTargeting` first (cheapest, biggest +quality-of-life win for me); then branch protection (one-off setup, +done forever); then adopt the draft-PR convention. + +--- + +## Final UI polish pass + +A deliberate sweep of visual / interaction rough edges, done **at the end** +once the feature surface has settled — batching the nitpicks avoids +re-polishing the same screens after every feature lands. Known items so far: + +- **Snip card Copy button is too wide.** It currently stretches further than + it should; size it to its content (or a sensible fixed width) so the card + action row reads cleanly. +- **"Delete CLI" button should be styled as a danger action.** It's a + destructive, hard-to-reverse operation — give it the red/danger accent + (e.g. a danger `Button` style / `Foreground` from the theme palette) + rather than the neutral default, so it visually distinguishes itself from + benign actions. +- **Inconsistent button corner radii.** Cancel buttons render with square + corners while Save / Copy buttons are rounded. Standardise on rounded + corners for *all* buttons (the dialog `CloseButton` is the likely culprit — + align it with the themed `CornerRadius` the primary buttons pick up). +- **Consider making the whole Snip card the Copy target.** Rather than a + dedicated Copy button on the card, let a click anywhere on the card trigger + the copy / parameter-fill flow. Weigh the trade-offs before committing: + discoverability and a cleaner card vs. losing an explicit affordance and + the risk of accidental copies / conflicts with the overflow menu and + favourite star hit-targets. Decide, then either remove the button or keep + it. + +Add to this list as other cosmetic / interaction snags turn up during +feature work, then knock them out in one pass before a stable cut. + +--- + ## Carried over from the phase stack These were trimmed out of Phase 4–6 to keep the PRs reviewable. None are @@ -310,16 +442,20 @@ load-bearing for the v1 demo, but they're the obvious next-pulls. the user changes the storage path we need three flows: move the existing store to the new path; adopt a store already at the new path; warn when both exist. UI: a "Change…" button next to the read-only path display. -- **Backup retention configurable.** Plumbing: `BackupService` takes - retention at construction time today; either re-create it on the relevant - config change or have it read from `AppConfig` lazily. -- **CLI delete.** Settle cascade semantics — must-be-empty vs trash-all-child-snips — - before wiring the UI. -- **Nerdbank.GitVersioning.** Right now `InformationalVersion` falls back to - the assembly's compile-time version. NBGV would give us a real git-tag-derived - string at build time (`v1.2.3+gabcdef0`). -- **Markdown rendering for Snip descriptions.** Stored as plain text right - now; render via a markdown control on the parameter-fill / detail view. -- **Trash UI.** Soft-deleted Snips currently just vanish from the views. - Need a "Trash" entry in the pane footer that lists trashed Snips with a - restore action and a hard-delete option. +- **Re-enable `PublishTrimmed` once JSON serialisation is trim-safe.** + Disabled in `Snipdeck.App.csproj` to unblock the first release. To + turn it back on: + 1. Move `JsonSnipStore` / `JsonSettingsStore` onto + `JsonSerializerContext` source generation + (`[JsonSerializable(typeof(SnipStoreDocument))]` etc.) so the + untyped `Serialize/Deserialize` calls disappear. Removes IL2026. + 2. Audit Jdenticon-net, Microsoft.Windows.SDK.NET and WinRT.Runtime + trim warnings (IL2104); either suppress per-assembly with + `` entries / `[DynamicallyAccessedMembers]` + attributes, or accept them via targeted + `false` carve-outs. + 3. Flip `PublishTrimmed` back to `True` for Release. + + Payoff is a meaningfully smaller self-contained Velopack package + (probably ~80 MB instead of ~150–200 MB). Not urgent for alpha but + worth doing before a stable cut.