Skip to content

feat(config): live policy gate (drop+warn project lines) - config phase C3b - #103

Merged
helly25 merged 1 commit into
mainfrom
feat/config-gate-live
Jun 23, 2026
Merged

feat(config): live policy gate (drop+warn project lines) - config phase C3b#103
helly25 merged 1 commit into
mainfrom
feat/config-gate-live

Conversation

@helly25

@helly25 helly25 commented Jun 23, 2026

Copy link
Copy Markdown
Owner

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 gitignore-style 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 stderr 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. 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], --explain trace).

…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
helly25 enabled auto-merge (squash) June 23, 2026 21:47
@helly25
helly25 merged commit b848896 into main Jun 23, 2026
5 checks passed
@helly25
helly25 deleted the feat/config-gate-live branch June 23, 2026 21:50
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.
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