Skip to content

feat(workspace): add PATH_ALLOW_BROAD override for too-shallow roots - #2017

Open
kobaz wants to merge 1 commit into
DeusData:mainfrom
kobaz:feat/path-allow-broad-too-shallow-override
Open

feat(workspace): add PATH_ALLOW_BROAD override for too-shallow roots#2017
kobaz wants to merge 1 commit into
DeusData:mainfrom
kobaz:feat/path-allow-broad-too-shallow-override

Conversation

@kobaz

@kobaz kobaz commented Sep 2, 2026

Copy link
Copy Markdown

CBM_WS_DENY_TOO_SHALLOW ("path is too broad to index as one root") has no override today: cbm_workspace_verdict_is_overridable() only lifts CBM_WS_DENY_SENSITIVE, and allow-root --list already documents shallow/absolute refusals as "always-refused" rather than configurable. That default is right -- a bare top-level tree like "/etc" or "/home" is almost always a mistake -- but it leaves no way to say "I mean this one specific broad root, on purpose." That's a real case: a person who deliberately wants one combined project spanning several sibling repos under a shared parent has no path forward today short of physically restructuring their checkout.

PATH_ALLOW_BROAD names one exact canonical path that lifts a CBM_WS_DENY_TOO_SHALLOW verdict, and only that verdict:

  • exact match only, not a prefix -- naming one broad root must not quietly approve every root below it too, the same "/Users"-style breadth this depth rule exists to catch in the first place
  • process environment, not a recorded grant: it never appears in cbm_workspace_grant_list, and cbm_workspace_verdict_is_overridable() is untouched, so CBM_WS_DENY_ABSOLUTE and CBM_WS_DENY_SENSITIVE stay exactly as unliftable as before
  • read once per call site with getenv(), mirroring how CBM_ALLOWED_ROOT is already threaded into cbm_workspace_root_allowed() from each of its four callers, rather than read inside cbm_workspace_classify_root() itself -- that function is documented as a pure function of its arguments precisely so it stays host-independent and directly testable

Also updates the refusal message to name the fix, the same way the sensitive-root refusal already names allow-root --approve-sensitive.

Adds ws_allow_broad_root_lifts_too_shallow_for_an_exact_match_only alongside the existing too-shallow coverage, checking the exact-match requirement, the untouched sensitive/absolute paths, and that nothing is written to the grant store.

What does this PR do?

Checklist

  • Every commit is signed off (git commit -s) — required, CI rejects
    unsigned commits (DCO, see CONTRIBUTING.md)
  • Tests pass locally (make -f Makefile.cbm test)
  • Lint passes (make -f Makefile.cbm lint-ci)
  • New behavior is covered by a test (reproduce-first for bug fixes)

CBM_WS_DENY_TOO_SHALLOW ("path is too broad to index as one root") has
no override today: cbm_workspace_verdict_is_overridable() only lifts
CBM_WS_DENY_SENSITIVE, and `allow-root --list` already documents
shallow/absolute refusals as "always-refused" rather than configurable.
That default is right -- a bare top-level tree like "/etc" or "/home"
is almost always a mistake -- but it leaves no way to say "I mean this
one specific broad root, on purpose." That's a real case: a person who
deliberately wants one combined project spanning several sibling repos
under a shared parent has no path forward today short of physically
restructuring their checkout.

PATH_ALLOW_BROAD names one exact canonical path that lifts a
CBM_WS_DENY_TOO_SHALLOW verdict, and only that verdict:

- exact match only, not a prefix -- naming one broad root must not
  quietly approve every root below it too, the same "/Users"-style
  breadth this depth rule exists to catch in the first place
- process environment, not a recorded grant: it never appears in
  cbm_workspace_grant_list, and cbm_workspace_verdict_is_overridable()
  is untouched, so CBM_WS_DENY_ABSOLUTE and CBM_WS_DENY_SENSITIVE stay
  exactly as unliftable as before
- read once per call site with getenv(), mirroring how CBM_ALLOWED_ROOT
  is already threaded into cbm_workspace_root_allowed() from each of
  its four callers, rather than read inside
  cbm_workspace_classify_root() itself -- that function is documented
  as a pure function of its arguments precisely so it stays
  host-independent and directly testable

Also updates the refusal message to name the fix, the same way the
sensitive-root refusal already names `allow-root --approve-sensitive`.

Adds ws_allow_broad_root_lifts_too_shallow_for_an_exact_match_only
alongside the existing too-shallow coverage, checking the exact-match
requirement, the untouched sensitive/absolute paths, and that nothing
is written to the grant store.

Signed-off-by: Mark Murawski <github@kobaz.net>
@kobaz
kobaz requested a review from DeusData as a code owner September 2, 2026 17:46
@DeusData

DeusData commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Actionable note ahead of the review verdict, so you are not blocked on me for it.

lint / lint is red and it is yours — unusually, this is not the false positive several contributors have hit this week. CI's own pinned formatter reports violations on the exact lines you added:

src/daemon/application.c:441:63: error: code should be clang-formatted
                                   getenv("PATH_ALLOW_BROAD"), boundary_error,

src/daemon/application.c:438-441. Running the formatter over that file should clear it.

(For context, since it has caught others: our gate requires the Homebrew LLVM clang-format; a distro or standalone clang-format-20 reports spurious whole-file drift on some large files. That is not what this is — these are your own new lines.)

On the change itself, I have verified the three boundary claims in your description and they hold:

  • the lift is guarded on verdict == CBM_WS_DENY_TOO_SHALLOW alone, so CBM_WS_DENY_SENSITIVE and CBM_WS_DENY_ABSOLUTE are untouched;
  • ws_paths_equal(canonical_path, allow_broad_root) is exact equality rather than a prefix test, so naming one broad root does not quietly approve everything beneath it;
  • the decision lives in cbm_workspace_root_allowed and not in cbm_workspace_classify_root, which stays a pure function of its arguments, and cbm_workspace_verdict_is_overridable really is untouched — the two occurrences in the diff are a context line and a comment saying it is deliberately excluded.

That is a carefully drawn boundary and it is the reason this is reviewable at all.

What I cannot decide on my own is whether we want a new environment variable that lifts a workspace security refusal. A new env var is a one-way door, and this one weakens a guard by design, however narrowly. That is a maintainer call and I have put it in front of ours; I will come back with an answer rather than leaving it open-ended.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

@DeusData DeusData added enhancement New feature or request security Security vulnerabilities, hardening priority/normal Standard review queue; useful PR with ordinary maintainer urgency. labels Sep 3, 2026
@DeusData DeusData mentioned this pull request Sep 3, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request priority/normal Standard review queue; useful PR with ordinary maintainer urgency. security Security vulnerabilities, hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants