feat(handlers): dconf_set writes system policy via direct file IO (Phase 7)#114
Merged
Conversation
…al-path) Final handler port of the kernel-primitive migration. dconf_set now writes the system dconf policy files — profile (/etc/dconf/profile/<db>), keyfile snippet (/etc/dconf/db/<db>.d/<file>), and optional lock — via direct atomic file IO (fsatomic), instead of the shell printf + mkdir pipeline, when running in agent mode. The `dconf update` compile step DELIBERATELY stays shell on both paths: it is the dconf toolchain's job to compile the keyfile drop-ins into the binary database — the file+compile pattern, exactly as mount keeps the remount on mount(8) and audit keeps the load on augenrules. The migration doc's "D-Bus to ca.desrt.dconf" does NOT apply: that is the user-session dconf API, whereas dconf_set manages SYSTEM policy, which is file-based. (Founder-ratified scope: file writes via fsatomic, not D-Bus.) selinux_boolean_set is intentionally LEFT ON setsebool -P (founder-ratified): that one command does runtime + persist correctly, and the selinuxfs split (/sys/fs/selinux + commit_pending_bools) would add untestable ABI risk for a marginal win — the same "don't reimplement the risky low-level op" call as the mount remount. - kernelio: MkdirAll primitive (os.MkdirAll) added to the FileTransport capability (a config drop-in dir must exist before an atomic write); local.Transport + FakeSysctlTransport implement it. - dconf_set Apply/Capture/Rollback gain a kernel-IO branch selected by transport.(kernelio.FileTransport), falling back to the shell path. Apply writes the profile (create-if-absent — an existing operator profile is preserved), snippet, and lock atomically; Capture/Rollback track the snippet as before. Both paths write byte-identical files, record an identical PreState shape, and run `dconf update`. - spec kernelio-dconf (Tier 1, 3 ACs); handler round-trip tests (apply writes+updates, keep-existing-profile, remove-when-absent, restore-when-existed, shell fallback). Existing shell-path tests unchanged. Failure-mode analysis: 1. What could this do wrong in production? Corrupting an operator's dconf policy. Mitigated: each file write is atomic (fsatomic temp+rename — crash leaves old or new, never truncated); the profile is create-if-absent so an existing operator profile is never clobbered; the snippet/lock are Kensa-owned drop-ins. dconf update compiles the result on both paths. 2. Captured-state sufficiency: rollback consumes file_path + prior_content + file_existed (the same tuple Capture records on both paths) — it restores the snippet's prior content or removes it if absent. A capture read error surfaces ErrCaptureIncomplete. (As before this change, Capture tracks only the snippet, not the profile/lock — the profile is create-if-absent and the lock is Kensa-owned; unchanged scope.) 3. Edge case not safe for / gated: the dconf update compile stays shell (the toolchain's job; reimplementing the keyfile→binary compile is out of scope and risk). LIVE validation that dconf update applies the atomic writes needs a real dconf host; kensa-fuzz atomicity + the two-human rollback-handler review (CONTRIBUTING) remain the founder's gate. Co-Authored-By: Claude Opus 4.8 (1M context) <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.
Phase 7 — the final handler port, completing the kernel-primitive migration.
dconf_setnow writes the system dconf policy files (profile, keyfile snippet, optional lock) via direct atomic file IO (fsatomic), instead of the shellprintf+mkdirpipeline, in agent mode.Two founder-ratified scope decisions baked in
dconfis file writes, not D-Bus. The migration doc's "D-Bus toca.desrt.dconf" is the user-session dconf API;dconf_setmanages system policy, which is file-based (profiles/keyfiles/locks compiled bydconf update). The honest port isfsatomicfile writes +dconf updateshell compile — the file+compile pattern (same as mount's fstab+remount, audit's drop-in+augenrules).selinux_boolean_setstays onsetsebool -P(left untouched): that one command does runtime+persist correctly; the selinuxfs split (/sys/fs/selinux+commit_pending_bools) would add untestable ABI risk for a marginal win — the same "don't reimplement the risky low-level op" call as the mount remount.What
kernelio:MkdirAllprimitive added to theFileTransportcapability (a drop-in dir must exist before an atomic write);local.Transport+FakeSysctlTransportimplement it.dconf_setApply/Capture/Rollback gain a kernel-IO branch viatransport.(kernelio.FileTransport), falling back to the shell path. Apply writes the profile (create-if-absent — existing operator profile preserved), snippet, and lock atomically; both paths write byte-identical files, record an identicalPreStateshape, and rundconf update.kernelio-dconf(Tier 1, 3 ACs) + round-trip tests (writes+updates, keep-existing-profile, remove-when-absent, restore-when-existed, shell fallback).Verification
go test ./...green;go build ./...clean;golangci-lint0;comment-lintclean (checked post-commit);specter syncall pass.Failure-mode analysis
fsatomictemp+rename); profile is create-if-absent (operator profile never clobbered); snippet/lock are Kensa-owned drop-ins;dconf updatecompiles on both paths.file_path/prior_content/file_existed(same tuple on both paths) → restores or removes the snippet; read error →ErrCaptureIncomplete. (Capture tracks only the snippet, as before — unchanged scope.)dconf updatecompile stays shell (the toolchain's job).kensa-fuzz+ two-human rollback review (CONTRIBUTING) are the founder's gate.🤖 Generated with Claude Code