Harden cfgutil device actions + add end-to-end architecture docs#124
Merged
Conversation
Two safety defects in the cfgutil backup/delete flow, both invisible to CI because tests used synthetic bare-hex ECIDs and never exercised the gate ordering. ECID normalization: cfgutil keys its JSON output by 0x-prefixed ECIDs (e.g. 0x9118908BB6027), but isValidEcid rejected the `x`. With a real device, recordBackup threw, the backup stamp was never written, and checkUninstallGate always returned backup_missing — silently breaking the freshness gate and the audit trail. Replace isValidEcid with normalizeEcid (strip 0x, upper-case, validate hex body); key stamps off the canonical form so any spelling round-trips. The backup route now 400s on a malformed ECID instead of throwing a 500. Gate ordering: the wizard ran the destructive cfgutil call before the server gate, so the server could only refuse to *log*, never to *act*. runBulkUninstall now pre-flights GET /api/device-actions/uninstall before the first removal and fails closed on denial or an unreachable service. Backup/uninstall recording POSTs check res.ok and surface failures as visible warnings instead of vanishing into the console. Tests pin the 0x round-trip and the pre-flight behaviour; correct two route/comment claims that overstated what the server gate can prevent (the native Touch ID prompt is the real control). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document every process the app runs — system map, add/track, cfgutil device import, backup+delete, background jobs, wayback, and the feature- flag gate chain — as Mermaid diagrams that render on GitHub and stay diffable. Weak points are marked inline and collected into an improvement backlog keyed to each diagram, so findings and their fix status live in one place instead of drifting apart. Add docs/specs/3-5-server-stamp-backup-variant.md, a self-contained good-first-issue spec (drive the delete-confirm modal's backup variant from the server stamp) sized for an external agent — TypeScript-only, self-verifiable in the node:test suite, no hardware. Wire both into the AGENTS.md architecture section and the README docs list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two threads from a source-level audit of the macOS/Tauri cfgutil "back up then delete apps off the phone" flow:
Fix — device-action safety (
fix(device-actions)): two defects that were invisible to CI because tests used synthetic bare-hex ECIDs and never exercised gate ordering.0x-prefixed ECIDs (0x9118908BB6027), butisValidEcidrejected thex. On a real device,recordBackupthrew → no backup stamp →checkUninstallGatealways returnedbackup_missing, silently breaking the freshness gate and the audit trail. Replaced withnormalizeEcid(strip0x, upper-case, validate hex body); stamps key off the canonical form so any spelling round-trips. The backup route now400s on a malformed ECID instead of500-ing.runBulkUninstallnow pre-flightsGET /api/device-actions/uninstallbefore the first removal and fails closed; recording POSTs checkres.okand surface failures instead of swallowing them.Docs — end-to-end architecture dossier (
docs): Mermaid diagrams of every process (system map, add/track, cfgutil import, backup+delete, background jobs, wayback, gate chain) with weak points marked inline and gathered into an improvement backlog keyed to each diagram. Renders on GitHub, stays diffable — no duplicate raster images to drift. Plus a self-contained good-first-issue spec (backlog §3·5) sized for an external agent.What's verified
pnpm test— 438 pass / 0 fail (4 new tests pin the0xround-trip + pre-flight)pnpm typecheck,pnpm lint,pnpm lint:i18n— all clean (en/zh parity at 4759 keys)Not addressed here (tracked in the backlog)
The two highest-severity findings need a Mac with Apple Configurator to verify and are out of scope for this PR:
cfgutil backup --backup-outputappears in no public cfgutil docs; may fail on real hardware. Check:cfgutil help backup.See
docs/ARCHITECTURE.md§7 for the full backlog and suggested order.🤖 Generated with Claude Code