feat(config): live policy gate (drop+warn project lines) - config phase C3b - #103
Merged
Conversation
…ig phase C3b) Third and final slice of the config policy gate (#58, phase C); the safe-by-default gate is now live end to end. - loader: Discover now reads ./.xffrc (the cwd) as the untrusted project layer (the full cascade up the tree is phase E; the policy gate is what makes loading this layer safe). - policy: DropMessage(drop) renders a one-line description for the warning and --explain; ClassName maps the safety class. - cli/main.cc: GateConfig filters the discovered user+project lines through the policy; denied lines are dropped (never fatal) and warned on stderr; --explain lists them; only the survivors are resolved and prepended. The canonical threat now holds: cd into an untrusted repo, run xff, and a .xffrc carrying -exec is dropped+warned while a safe --color line still applies. Tests: loader project discovery; policy DropMessage; the hostile-.xffrc binary test (bashtest) asserting via --explain that the project -exec is dropped and the safe line survives. Also: trailing comma on the Drop{} aggregate (clang-format one-per-line). Green on default + clang-asan. Config phase C complete.
helly25
enabled auto-merge (squash)
June 23, 2026 21:47
This was referenced Jul 5, 2026
helly25
added a commit
that referenced
this pull request
Jul 5, 2026
* Make a per-directory .xffrc opt-in: --project-config=on|warn|off
A project (per-directory) .xffrc lives in a tree the user may not control - running xff there
should not let that tree silently change the run. It was already limited to the safe subset
(sensitive/destructive lines are dropped from the project layer by the policy gate), but its safe
lines still applied automatically. Now the whole project layer is off unless explicitly enabled.
New global --project-config=on|warn|off (last wins; default warn):
- on - apply the project .xffrc (still safe-subset only; sensitive/destructive lines and style
selectors are never honored from a project file - full config lives in user/system files)
- warn - (default) ignore it, but print one stderr note when a project .xffrc was actually found
- off - ignore it silently (suppresses the note)
The note fires only when a project file is present, so the common no-project-config case stays
quiet. User and system config (XFF_CONFIG / ~/.config/xff / /etc/xff.ini) are unaffected and still
apply, including the powerful settings a project file may not carry.
config::ResolveProjectConfigMode reads the flag; main() drops gated.project before ResolveConfig
unless the mode is on, and emits the note under warn when inputs.sources shows a found project
source. --explain reflects the cleared layer.
Tests: config_test (mode resolution: default warn, on/off/warn, unknown -> warn, last-wins);
explain_test.sh (off-by-default + stderr note under warn, silent under off, applied under on; the
existing project cases now pass --project-config=on). design-config.md worked examples + CLI
selectors updated for the new default. `bazel test //xff/...` green (67).
Note: letting a USER/SYSTEM .xffrc relax the argv[0]=find style baseline (the other half of #103)
is a separate follow-up; this PR only makes the per-directory layer opt-in.
* Iterate globals as string_view in ResolveProjectConfigMode
Loop over std::string_view (by value; a view is never const) rather than const std::string&, so
the value line reads global.substr(kFlag.size()) directly instead of wrapping each element in
std::string_view(global). No behavior change.
helly25
added a commit
that referenced
this pull request
Jul 5, 2026
An invocation name that is not a built-in style is now the leading --config selector verbatim, so it activates a same-named NAMED config while the base style stays the modern xff default. A `mytool` symlink to xff picks up the user/system `mytool:` block with no --config - the sanctioned way to ship a personal preset without overloading a built-in one (which the gate forbids). DefaultStyleForProgram: basename it, "fd" -> "xfd" (the one alias), empty -> "xff", and every other name is returned verbatim (a built-in style name selects that preset; any other name is a named-config selector that ActiveStyle leaves at the xff base). Previously unknown names collapsed to "xff", discarding the alias. Tests: config_test (custom names pass through verbatim: myfind/findutils/mytool; presets + fd + "" unchanged); style_test.sh (a `mytool` symlink activates a `mytool:` config block -> jsonl output, while a plain xff run leaves it inert). design-config.md argv[0]-dispatch bullet updated. `bazel test //xff/...` green (67). Completes the config-model finalization (#103): presets are fixed and not overloadable; customize via named configs activated by --config=NAME or a same-named argv[0] alias.
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.
Third and final slice of the config policy gate (#58, phase C) - the safe-by-default gate is now live end to end.
Discovernow reads./.xffrc(the cwd) as the untrusted project layer (the full gitignore-style cascade up the tree is phase E; the policy gate is what makes loading this layer safe).DropMessage(drop)renders a one-line description for the stderr warning and--explain;ClassNamemaps the safety class.cli/main.cc:GateConfigfilters the discovered user+project lines through the policy; denied lines are dropped (never fatal) and warned on stderr;--explainlists them; only the survivors are resolved and prepended.The canonical threat now holds:
cdinto an untrusted repo, runxff, and a.xffrccarrying-execis dropped+warned while a safe--colorline still applies.Tests
loader project discovery; policy
DropMessage; the hostile-.xffrcbinary test (bashtest) asserting via--explainthat the project-execis dropped and the safe line survives. Green on default +--config=clang --config=asan.Config phase C complete. Next: #68 (descriptor binding metadata), then phase D (styles/features) + E (cascade, argv[0],
--explaintrace).