Skip to content

feat(handlers): dconf_set writes system policy via direct file IO (Phase 7)#114

Merged
remyluslosius merged 1 commit into
mainfrom
feat/kernelio-dconf
Jun 20, 2026
Merged

feat(handlers): dconf_set writes system policy via direct file IO (Phase 7)#114
remyluslosius merged 1 commit into
mainfrom
feat/kernelio-dconf

Conversation

@remyluslosius

Copy link
Copy Markdown
Contributor

Phase 7 — the final handler port, completing the kernel-primitive migration. dconf_set now writes the system dconf policy files (profile, keyfile snippet, optional lock) via direct atomic file IO (fsatomic), instead of the shell printf + mkdir pipeline, in agent mode.

Two founder-ratified scope decisions baked in

  • dconf is file writes, not D-Bus. The migration doc's "D-Bus to ca.desrt.dconf" is the user-session dconf API; dconf_set manages system policy, which is file-based (profiles/keyfiles/locks compiled by dconf update). The honest port is fsatomic file writes + dconf update shell compile — the file+compile pattern (same as mount's fstab+remount, audit's drop-in+augenrules).
  • selinux_boolean_set stays on setsebool -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: MkdirAll primitive added to the FileTransport capability (a drop-in dir must exist before an atomic write); local.Transport + FakeSysctlTransport implement it.
  • dconf_set Apply/Capture/Rollback gain a kernel-IO branch via transport.(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 identical PreState shape, and run dconf update.
  • spec 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-lint 0; comment-lint clean (checked post-commit); specter sync all pass.

Failure-mode analysis

  1. Wrong in prod? Corrupting dconf policy. Mitigated: atomic writes (fsatomic temp+rename); profile is create-if-absent (operator profile never clobbered); snippet/lock are Kensa-owned drop-ins; dconf update compiles on both paths.
  2. Captured-state sufficiency: rollback consumes 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.)
  3. Edge case / gated: dconf update compile stays shell (the toolchain's job). ⚠️ LIVE validation needs a real dconf host; kensa-fuzz + two-human rollback review (CONTRIBUTING) are the founder's gate.

🤖 Generated with Claude Code

…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) <[email protected]>
@remyluslosius remyluslosius merged commit 52b312d into main Jun 20, 2026
18 checks passed
@remyluslosius remyluslosius deleted the feat/kernelio-dconf branch June 20, 2026 04:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant