Skip to content

Decline DNS management on macOS without root - #5

Merged
johnmaguire merged 5 commits into
mainfrom
darwin-nonroot-declined
Oct 28, 2026
Merged

johnmaguire merged 5 commits into
mainfrom
darwin-nonroot-declined

Conversation

@johnmaguire

@johnmaguire johnmaguire commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Consumers build a Manager at startup on every host and call Clear right away to recover a crashed predecessor's artifacts, whether or not DNS is configured. On macOS a process without root can never write: the dynamic store, /etc/resolver, and the lock directory /var/run/dnsconfig all require root. Until now New only logged a warning and built the live darwin backend, so every Set and Clear attempt failed on the identity lock, retried with backoff for the life of the Manager, and Close warned that cleanup failed. A non-root process that never configures DNS logged three warnings per start with nothing to do.

macOS without root: New puts the Manager in the existing declined mode used for unsupported platforms. It gets the no-op backend and no locker. Set returns ErrConfigurationDeclined with the reason ("darwin: requires root") and records it in Status.LastError. Clear converges without touching the host or taking a lock, so there is no retry loop and Close has nothing to warn about. Construction logs a single Info line instead of the Warn. Errors still name BackendDarwin so logs describe the real host. The root check lives in the root package (backend_darwin.go) behind a package variable tests replace; there is no new public Option, and the darwin backend's own IsRoot option is gone since the backend is never built without root.

A process running as root sees no change.

Windows: only the timing of the LocalSystem warning changes. It was logged at construction, so every Windows process logged it even if it never wrote. It is now logged once per backend, at the first registry write of a Set or of a Clear that found artifacts to remove. The check and its test injection point are unchanged.

Non-root after a crashed root run: such a process now stays silent about any root-owned leftovers, because its Clear converges without looking. It could not remove them anyway, and the only realistic case is a user who alternates between running a consumer with and without sudo. A lock-free probe at New could log one Warn when this identity's artifacts are present, since reading /etc/resolver and listing State keys needs no root. That is left out until a consumer needs it.

Forcing the darwin backend: a non-root process can no longer force it with ForceBackend: BackendDarwin. Every write it attempted failed, so the override bought only the retry loop. Tests that need the live backend set isRoot.

The dynamic store, /etc/resolver, and the lock directory all require
root on macOS. A non-root Manager was still built around the live
backend, so a startup Clear failed on the identity lock, retried with
backoff for the Manager's lifetime, and Close warned that cleanup
failed: several warnings per start on a host with nothing to do.

New now gives a non-root darwin Manager the declined mode: the no-op
backend and no locker, Set refused with ErrConfigurationDeclined and
the reason, Clear converging without touching the host, and one Info
line in place of the construction warning. Errors still name the
darwin backend.
The LocalSystem diagnostic ran at construction, so every Windows
process that built a Manager logged it, including one whose startup
Clear found nothing and never wrote. The warning matters only for a
process that changes the host, where Group Policy rules can stay
effective after cleanup.

The check now runs once per backend, before the first registry write
of a Set or of a Clear that found artifacts to remove.
@matt-defined

Copy link
Copy Markdown

One thing that's not critical, but would be nice: after this change, we leave the status as if we successfully converged on clear, but we didn't. We could store the error in m.st.lastErr on New, and check for declined in the success cases, to avoid clearing it.

@matt-defined
matt-defined self-requested a review October 28, 2026 19:44

@matt-defined matt-defined left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's one small thing it would be nice to change, but I don't think it's blocking

Comment thread internal/backend/windows/windows.go Resolved
@matt-defined

Copy link
Copy Markdown

Also looks like native_test.go won't test construction on darwin anymore, if you're not root?

@johnmaguire

Copy link
Copy Markdown
Member Author

Good catch. On a non-root runner that case only exercised the declined path, so it now skips on darwin. Construction is covered by TestNew_DarwinWithRootBuildsBackend, which forces the root check and asserts the live backend is built.

@johnmaguire
johnmaguire merged commit 617c971 into main Oct 28, 2026
20 checks passed
@johnmaguire
johnmaguire deleted the darwin-nonroot-declined branch October 28, 2026 20:18
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.

2 participants