Skip to content

fix(file.flags): clear flags correctly on privileged path - #132

Merged
github-actions[bot] merged 2 commits into
mainfrom
fix/chflags-privileged-symbolic
Oct 17, 2026
Merged

github-actions[bot] merged 2 commits into
mainfrom
fix/chflags-privileged-symbolic

Conversation

@brujack

@brujack brujack commented Oct 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • On the file.flags privileged path (privileged: true, macOS) the code assumed chflags(1) replaces every flag. It doesn't: symbolic chflags is additive. Two symptoms followed:
    • removing a flag was a silent no-op.
    • clearing every flag ran chflags none, which fails with invalid flag: none (rc=1).
  • The new symbolic_delta names only the managed flags that change. It uses the no prefix to clear a flag and never emits none.

Changes

  • New ungated module lib/src/atoms/file/bsd_flags.rs contains:
    • symbolic_delta(current, desired) -> Option<String>.
    • UF_HIDDEN and UF_IMMUTABLE, moved here. The macOS-gated chflags module re-exports them.
    • Its tests run on Linux CI.
  • lib/src/actions/file/flags.rs:
    • The privileged branch now calls symbolic_delta.
    • Removed the comments that repeated the false "replaces all flags" claim.
    • Added a macOS wiring test.
  • Added a backlog row for two macOS package tests that were already non-hermetic.
  • The non-privileged path, which calls libc::chflags with a bitmask, is unchanged.

Test Plan

  • Semantics measured on a Mac Studio (macOS 27.0.1):
    • nohidden clears only hidden.
    • nodump survives hidden,nouchg.
    • hidden,nouchg and nouchg,hidden give the same result on a uchg file.
    • chflags none exits with rc=1.
  • 6 unit tests and 1 proptest (apply the delta under additive semantics and check the result equals desired). All run on Linux. They fail against the old logic, which emits none and the full flag set, and pass on the fix.
  • macOS wiring test plan_clears_a_flag_with_no_prefix_when_privileged, run on the Studio: fails on the pre-fix code and passes on the fix. macOS clippy and fmt are clean.
  • make test on Linux: 1136/1136 nextest, 64 pytest.
  • Coverage: floor 81% (Linux tarpaulin, CI). The new pure function is fully covered on Linux. The macOS-gated wiring is outside Linux coverage, as before.

Risk

Low. This code path only runs on macOS with privileged: true, and no etch-config manifest uses file.flags today. The new behaviour is strictly narrower: it touches only the bits that change, and flags file.flags doesn't manage are left alone.

Definition of Done

Phase 3 gates:

  • perf: PASS (worst 1.04x).
  • security: PASS.
  • dependency-review: SKIP (no manifests).
  • test-quality: PASS (12 of 13 mutants killed; the survivor is a constant value I checked against sys/stat.h).
  • diff-scope: PASS.
  • bug-scan: PASS.
  • migration-classifier: code-only.
  • maintainability: PASS.
  • pr-review: PASS.

Spec alignment

SKIP: no plan or spec (bug-fix-cycle normal mode).

Related

Reported by the ai-config session's claim-check sweep, which is correcting the cited memory etch-cli-chflags-replaces-all-flags separately. Depends on #131, which unblocked cargo-audit on main.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Aux8gVLuPWbaZnmeza37Mu

brujack and others added 2 commits October 17, 2026 15:45
Symbolic chflags(1) is additive: a name sets its flag, a no-prefixed
name clears it, and unnamed flags are untouched. The privileged path
assumed replace semantics, so it named the full desired set (removing
a flag was a silent no-op) and passed "none" to clear everything,
which chflags rejects with rc=1.

- Add ungated atoms/file/bsd_flags.rs with symbolic_delta, naming
  only the managed flags that change (hidden/nohidden, uchg/nouchg)
- Move UF_HIDDEN/UF_IMMUTABLE there; re-export from chflags
- Tests run on Linux CI, including a proptest against simulated
  chflags semantics

Verified on macOS 27.0.1: chflags nohidden clears only hidden,
nodump survives hidden,nouchg, and chflags none exits 1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Aux8gVLuPWbaZnmeza37Mu
Asserts the planned command is `chflags nohidden <path>` for a file
with hidden set. Fails on the pre-fix code, which planned
`chflags none`. Runs only on macOS, so it guards the action wiring
that the Linux-run symbolic_delta tests cannot reach.

Also backlogs two pre-existing macOS package tests that fail under a
non-login shell.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Aux8gVLuPWbaZnmeza37Mu
@github-actions
github-actions Bot merged commit 589000a into main Oct 17, 2026
12 checks passed
@brujack
brujack deleted the fix/chflags-privileged-symbolic branch October 17, 2026 20:12
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