## What Brings AppKit into conformance with [KofTwentyTwo/standards](https://github.com/KofTwentyTwo/standards). Reviewable commit by commit: | Commit | Change | | --- | --- | | build | Quality gate from `configs/dotnet` (analyzers incl. Meziantou, warnings as errors), `packages.lock.json` per project, locked-mode restore | | style | Kingsrook layout and LF line endings, produced mechanically by `dotnet format` (formatting only) | | docs | SPDX license header on every C# file | | refactor | Real code changes: analyzer findings fixed (one type per file, regex timeouts, async void, …) and header comments on every type and member | | ci | Old workflows replaced by callers of the shared standards workflows (PR gates, security, CodeQL, .NET CI, NuGet release with SBOM + attestation + trusted publishing), Scorecard | | docs | README, CONTRIBUTING (GitHub Flow, DCO, signing), SECURITY, CODEOWNERS, templates, Dependabot, threat model, ADRs, RELEASING | Also includes `dev`'s CI fix, so it supersedes #1; the `dev` branch goes away under GitHub Flow. ## Why AppKit is the first Product repository to adopt the standards. Static conformance before: 16 FAIL; after: 0 FAIL, 0 WARN (the remaining UNKNOWN rows are GitHub settings and rulesets, applied separately). ## How tested Locally with `CI=true` (lock files enforced): locked restore x64 and ARM64; zero-warning x64 build; 115 unit tests with 100% line coverage of `KofTwentyTwo.AppKit` and `KofTwentyTwo.AppKit.Updates`; 12 FlaUI UI tests (WinUI + WPF samples); `dotnet format --verify-no-changes --severity warn` clean; pack produces 4 packages + symbols; actionlint, zizmor (pedantic), gitleaks clean. The UI tests caught a regression introduced while fixing MA0147 (the WPF splash stopped dismissing because no UI context existed yet); fixed by starting the countdown through the dispatcher in both packages. ## Notes - `ci.yml` and `release.yml` are pinned to KofTwentyTwo/standards#3's head commit; they are repinned after that PR merges. - This pull request's new check names become required checks once the repository's rulesets are updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: James Maes <james@kof22.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
6.6 KiB
6.6 KiB
Threat model: AppKit
AppKit is a set of libraries, so its threats are the ones it creates inside the apps that use it. This model covers every external interface the four packages open; each app's own threat model starts from this one (K22-SDLC-03).
- Version reviewed: 0.1.0-dev (before the first release) · Last reviewed: 2026-10-09
1. What the product is and does
Four NuGet packages that give a KofTwentyTwo Windows desktop app its identity, per-user data paths, logging, settings, secret storage, splash/About/log-viewer UI, crash net, theming, and Velopack self-update from the app's GitHub Releases. AppKit runs inside the host app's process, with the logged-in user's rights; it has no server side and opens no listening sockets.
2. Actors and components
| Actor or component | Description | Trust level |
|---|---|---|
| User | The person running the host app | Trusted for their own data |
| Host app | The application that references AppKit | Trusted (same process) |
| Other local processes of the same user | Can read and write the user's files | Not trusted, but AppKit cannot defend against them |
| GitHub Releases (update feed) | Serves release metadata and Velopack packages over HTTPS | Untrusted network content; integrity checked |
| Velopack | Downloads, verifies, and applies update packages | Trusted dependency |
| Windows Credential Manager | Stores secrets per user, protected by DPAPI | Trusted OS component |
3. Data flow and trust boundaries
flowchart LR
user([User]) --> app[Host app + AppKit]
app -- HTTPS --> gh[(GitHub Releases)]
app --> settings[(settings.json)]
app --> logs[(logs/*.log)]
app --> vault[(Credential Manager)]
app -. opens .-> browser[Default browser]
subgraph machine [Trust boundary: the user's Windows session]
app
settings
logs
vault
end
4. External interfaces
| Interface | Direction | Data | Authenticated? | Validated where? |
|---|---|---|---|---|
Update check and download (VelopackUpdateService) |
In | Release metadata, update packages | HTTPS to github.com; Velopack verifies package hashes from the release feed | Velopack; versions parsed by Velopack |
settings.json (SettingsStore<T>) |
In and out | User preferences | No (user-writable file) | ISanitizable.Sanitize clamps and validates every value on load; a corrupt file yields defaults |
Log files (FileActivityLog) |
Out (and in for LogTail) |
Operational messages | No (user-writable files) | Viewers display text only; nothing is executed or parsed beyond line timestamps (regex with a timeout) |
Credential Manager (CredentialManagerVault) |
In and out | Secrets the host app stores (tokens) | Windows logon session (DPAPI) | Keys validated; secrets never logged |
<ID>_DATA_DIR environment variable (AppPaths) |
In | Data folder path | No | Used as a folder path only |
Velopack process hooks (VelopackStartup) |
In | Command-line arguments from the installer/updater | No | Velopack handles them and exits; other arguments pass through untouched |
| Links in the About dialog and log window | Out | Repository URL, log folder path | No | Values come from the host app's AppInfo, not from input |
5. Assets
- The user's secrets in the Credential Manager (for example GitHub tokens in gclo).
- The integrity of the host app's code: a malicious update would run as the user.
- The user's data and preferences under
%LOCALAPPDATA%\<id>. - The availability of the host app (a crash or hang at startup).
6. Threats (STRIDE)
| # | Boundary / component | Category | Threat | Likelihood | Impact | Mitigation | Status |
|---|---|---|---|---|---|---|---|
| T1 | Update feed | Tampering | An attacker serves a malicious update package | Low | Critical | HTTPS only; Velopack verifies package hashes; releases are immutable and every asset is attested by the shared release workflow (SLSA Build L3); prerelease builds follow only the dev channel | Mitigated |
| T2 | Update feed | Spoofing | A look-alike repository URL is configured | Low | Critical | The feed is the host app's own AppInfo.RepositoryUrl, fixed at build time, not user input |
Mitigated |
| T3 | Update flow | Denial of service | A failing or slow update check crashes or blocks the app | Medium | Medium | Every update member is guarded and returns errors as values; the check runs after startup | Mitigated |
| T4 | Secrets | Information disclosure | A token leaks through logs, settings, or memory | Medium | High | Secrets only in the Credential Manager; never in settings or logs; the pinned plaintext buffer is cleared after writing | Mitigated |
| T5 | settings.json | Tampering | A crafted settings file sets out-of-range values or crashes parsing | Low | Low | Source-generated JSON parsing inside a catch-all; values sanitized; failure means defaults | Mitigated |
| T6 | Log files | Tampering / denial of service | A huge or crafted log file hangs the log viewer | Low | Low | The viewer reads only the last 2,000 lines; the entry regex has a match timeout | Mitigated |
| T7 | UI thread | Denial of service | An exception escaping an async handler kills the app | Medium | Medium | Crash net logs and handles dispatcher exceptions; one-dialog-at-a-time guard prevents the stowed-exception crash | Mitigated |
| T8 | Data folder | Elevation of privilege | <ID>_DATA_DIR points the app at another location |
Low | Low | The variable is set by the same user; the app gains no rights it did not have | Accepted |
| T9 | Dependencies | Tampering | A compromised package in AppKit's graph | Low | High | Central versions, lock files with locked restore, dependency review, Trivy and OSV-Scanner in CI, Dependabot with a cooldown | Mitigated |
| T10 | Repudiation | Repudiation | Not applicable: AppKit makes no security decisions on behalf of a remote party | n/a | n/a | n/a | n/a |
7. Accepted risks
- T8: another process running as the same user can redirect or read AppKit's data; defending against the user's own processes is outside a desktop library's reach.
- Unsigned binaries until code signing is available: apps built on AppKit ship without an Authenticode signature until the KofTwentyTwo signing identity is validated (exception EX-0002); provenance attestations and checksums remain verifiable.
8. Review log
| Date | Version | Reviewer | Changes |
|---|---|---|---|
| 2026-10-09 | 0.1.0-dev | James Maes | Initial model |