Ownership journal for installer-managed allow rules: crash-safe install, repair and uninstall
How a CLI installer that inserts a fixed set of exact allow rules into a shared settings file should journal ownership so repair and uninstall preserve user allows and denies, and how to recover when setup crashes between the journal write and the settings write. Reasoned design, not executed tests.
Ownership journal for installer-managed allow rules
When to use
Use this when a CLI installer adds a small fixed set of exact permission allow rules to a settings file that the developer also edits by hand and that may contain explicit deny rules. The installer must offer repair and uninstall that never remove a rule the user wrote and never add, remove or bypass a deny. The settings write and the ownership record cannot share one transaction.
This is a reasoned design. No executed tests back it.
Invariant
The journal must always claim at least as much as the installer has placed in settings. Every write order follows from this.
- Install: journal first as a pending intent, settings second, journal confirmation third.
- Uninstall: settings first, journal release second, journal deletion last.
Why: a stale pending intent is harmless noise that the next run discards. An installer-added allow with no journal record is an orphaned permission that uninstall can never distinguish from a user rule, so it leaks forever.
Journal record per rule
One record per target settings file and rule string, with a state and a snapshot taken at intent time.
- pending: intent recorded, settings write not confirmed.
- owned: the installer inserted this allow and may remove it.
- preexisting: the exact allow was already present before install. Never remove it, never re-add it.
- vetoed: a matching deny existed at install time, so the allow was not inserted.
- released: uninstall removed the allow or found it already gone.
Also store: installer version, the set of managed rule strings for that version, a commit witness, and the pre-write digest of the settings file.
Commit witness
Preferred: generate a random token per install attempt, record it in the pending intent, and write it into an installer-namespaced metadata key in the same atomic settings replacement that adds the rules. On recovery, token present means the write landed and pending becomes owned. Token absent means it did not land and the intent is discarded.
Fallback when the settings format forbids extra keys: record the pre-write file digest in the intent. Rule present and digest changed means landed. Rule absent and digest unchanged means not landed. Rule present and digest unchanged is impossible under atomic replace. Rule present with a different digest and no witness is ambiguous; report it and keep the record pending rather than guess.
Deny handling
- A deny that matches a managed rule at install time vetoes insertion. Record vetoed and tell the user.
- A deny added later for an owned rule blocks repair from re-adding; uninstall still removes the installer allow.
- The installer never adds, removes or rewrites a deny under any command.
Repair
Run recovery first. Then for each record: owned and missing and not denied, re-add and keep owned. Preexisting and missing, do nothing. Vetoed with the deny now gone, insert and promote to owned. Rules newly added in this installer version get a fresh intent. Rules the installer version no longer manages but still owns are removed as in uninstall.
Uninstall
Run recovery first. For each owned rule, remove the smaller of the recorded count and the current count of exact matches, leaving preexisting entries and every deny untouched. Write settings atomically, mark each record released, and delete the journal only when all records are released. A crash after the settings write leaves owned records for absent rules, which the next uninstall marks released without touching settings.
Concurrency and scope
Hold a lock around each read-modify-write pair. Re-read settings immediately before writing and abort if the digest changed since the snapshot. Key journal records by target file so user and project scopes cannot cross-contaminate. Keep the journal in installer state, not inside the settings file.
Anti-patterns
- Inferring ownership from rule text alone.
- Writing settings before recording intent.
- Deleting the journal before the settings change is confirmed.
- Removing every instance of a managed string on uninstall.
- Touching deny lists for any reason.