Skip to content

The owner list is read from a file spec a set may ship, and foreign_hosts extends a built-in list that quiets claude.ai - #206

Merged
HackingGate merged 1 commit into
mainfrom
the-owner-list-is-read-from-a-file-spec-a-set-may-ship-and-foreign-hosts-has-a-default
Sep 20, 2026
Merged

HackingGate merged 1 commit into
mainfrom
the-owner-list-is-read-from-a-file-spec-a-set-may-ship-and-foreign-hosts-has-a-default

Conversation

@HackingGate

@HackingGate HackingGate commented Sep 20, 2026

Copy link
Copy Markdown
Owner

Closes #198.

What the fleet repeated

97 copies of one private_owners_from shell line across 87 policy files, and 84 copies of foreign_hosts = ["claude.ai"]. Neither is a fact about the repository it sits in, and neither could be shipped by a set: the first because a set may not carry a shell command, the second because nothing was quieted by default.

Part A: private_owners_file

A non-shell spelling of the owner source, accepted at the top of the policy file and on any rule that accepts private_owners_from.

spec resolves to
xdg:principles/private-owners $XDG_CONFIG_HOME/principles/private-owners, else $HOME/.config/principles/private-owners
home:.private-owners $HOME/.private-owners
/etc/uphold/private-owners itself

A bare relative path (or ~, or an absolute path behind a prefix) is refused at load. The file is read by the binary, one owner per line, # comments and blank lines dropped, exactly as the command form's stdout is. private_owners_optional keeps its meaning: an absent file with it is a stderr notice naming the two forms not checked; without it, exit 2 exactly like a failing command. private_owners_from beside private_owners_file at one level is refused naming both.

A set may ship it. A bundled set's top-level private_owners_file and private_owners_optional are the default for every inheriting policy. The policy's own top-level line, in either spelling, overrides it; a rule's own line overrides both for that rule. The set's optional reaches only the set's file. private-names now ships xdg:principles/private-owners with private_owners_optional = true; the default prints in uphold rules --set private-names and is in sets.lock.json field for field. A set carrying private_owners_from is refused where it is parsed, as is private_owners_optional with no file in the set, and an inherit.paths file carrying a top-level private_owners_file (not adopted, so refused rather than dropped). The notice for an absent set-default file names the set, since no line in the reader's tree names the source.

uphold's own policy/principles.toml drops its two lines.

Part B: foreign_hosts default

FOREIGN_HOSTS_DEFAULT = ["claude.ai"] is compiled in; a policy's list, and a rule's own list, extend it rather than replace it. docs/REFERENCE.md no longer says nothing is quieted by default.

Tests

  • src/config.rs: the three spec forms and the refused fourth; resolution against a supplied environment (XDG set, unset, empty; HOME unset); both spellings refused at top level and on a rule; a bad spec refused; the set default adopted where the policy writes no line and not where it does; a set may not carry the shell form or a bare optional; an inherited file's top-level private_owners_file refused.
  • src/guard/names.rs: the file read as the command form reads stdout (comments, blank lines, trimming); absent is exit 2 naming private_owners_optional; with it, an empty list; the built-in hosts stay quiet under a declared list.
  • tests/base_sets_cli.rs: a fixture inheriting private-names with no own private_owners_* line reads $XDG_CONFIG_HOME/principles/private-owners from a temp XDG dir and refuses secretcorp/thing; absent, exit 0 with a notice naming the set; a policy's own home: line is not read through the set default; foreign_hosts = ["example.test"] still quiets claude.ai while other.test is refused under refuse_unknown. The guard helpers now set XDG_CONFIG_HOME to a per-fixture directory so the suite never reads the developer's real owner list.

cargo test: 905 passed, 0 failed. cargo run -- check, cargo run -- scan, scripts/validate.py, scripts/build_reference.py --check, and the Python unittest suite all pass.

Summary by CodeRabbit

  • New Features

    • Private-owner names can now be read from a configuration file using xdg:, home:, or absolute paths.
    • Missing optional owner files report a notice while allowing the operation to continue.
    • Foreign-host checks now include built-in protections, including claude.ai, alongside configured patterns.
    • Rule and set information now displays private-owner file settings.
  • Documentation

    • Updated configuration, reference, design, and contribution guidance for file-based private-owner lists.

@coderabbitai

coderabbitai Bot commented Sep 20, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Warning

Review limit reached

Next included review available in 36 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 8d5ee94c-3ca7-4017-969f-13580def79f7

📥 Commits

Reviewing files that changed from the base of the PR and between b6788d1 and 90e20d2.

📒 Files selected for processing (2)
  • docs/REFERENCE.md
  • src/config.rs

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 9300edba-8e38-45b7-8622-1b0aac11eb92

📥 Commits

Reviewing files that changed from the base of the PR and between ab694be and b6788d1.

📒 Files selected for processing (14)
  • CONTRIBUTING.md
  • docs/DESIGN.md
  • docs/REFERENCE.md
  • policy/base/private-names.toml
  • policy/base/sets.lock.json
  • policy/principles.toml
  • src/audit.rs
  • src/config.rs
  • src/config/rule.rs
  • src/guard/mod.rs
  • src/guard/names.rs
  • src/main.rs
  • tests/audit_cli.rs
  • tests/base_sets_cli.rs

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds private_owners_file support, bundled file-based defaults, built-in foreign-host matching, optional missing-file handling, CLI metadata, documentation, and tests.

Changes

Private owner source model

Layer / File(s) Summary
Source parsing and policy resolution
src/config.rs, src/config/rule.rs
Policies and rules accept validated file-based owner sources. Policy declarations override bundled defaults, and conflicting or unsupported declarations are refused.
Guard execution and host matching
src/guard/names.rs, src/guard/mod.rs
The guard reads owner names from commands or files. Optional missing files produce notices, while required failures remain fatal. Built-in foreign-host patterns include claude.ai and are combined with configured patterns.
Bundled defaults and CLI metadata
policy/base/private-names.toml, policy/base/sets.lock.json, policy/principles.toml, src/main.rs
The private-names set supplies an optional XDG-based owner file. Rule and set commands expose the configured source and optional status.
Documentation and validation
CONTRIBUTING.md, docs/DESIGN.md, docs/REFERENCE.md, tests/*, src/audit.rs
Documentation describes file path forms, precedence, and failure handling. Tests cover inherited files, policy overrides, missing files, foreign hosts, and publication audit output.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Policy
  participant Guard
  participant ConfigFile
  participant Stderr
  Policy->>Guard: provide resolved owner source
  Guard->>ConfigFile: read private_owners_file
  ConfigFile-->>Guard: owner names or missing-file error
  Guard->>Stderr: report optional missing source
  Guard-->>Policy: continue checks with resolved owners
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes both primary changes: set-shipped file-based owner lists and the built-in foreign_hosts list that includes claude.ai.
Linked Issues check ✅ Passed The PR meets the coding requirements in [#198]. It adds native private_owners_file loading for xdg:, home:, and absolute paths. It preserves optional missing-file behavior. It implements policy …
Out of Scope Changes check ✅ Passed The changes stay within [#198]. The Rust changes implement owner-file loading, set inheritance, validation, and additive foreign_hosts behavior. The policy changes remove duplicated declarations and…
Docstring Coverage ✅ Passed Docstring coverage is 82.35% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 51 functions across 8 files. (6 skipped: 6 …
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.13619% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.63%. Comparing base (310ebab) to head (b6788d1).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/config.rs 96.50% 12 Missing ⚠️
src/guard/names.rs 93.07% 9 Missing ⚠️
src/main.rs 78.94% 4 Missing ⚠️

❌ Your patch status has failed because the patch coverage (95.13%) is below the target coverage (100.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@           Coverage Diff            @@
##             main     #206    +/-   ##
========================================
  Coverage   93.63%   93.63%            
========================================
  Files          44       44            
  Lines       17057    17576   +519     
========================================
+ Hits        15971    16458   +487     
- Misses       1086     1118    +32     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…osts extends a built-in list that quiets claude.ai

Two top-level lines were the same in nearly every consumer: 97 copies of one
`private_owners_from` shell line across 87 policy files, and 84 copies of
`foreign_hosts = ["claude.ai"]`. Neither was a fact about the repository it
sat in, and neither could be shipped by a set -- the first because a set may
not carry a shell command, the second because nothing was quieted by default.

`private_owners_file` is the non-shell spelling of the owner source. It takes
`xdg:<path>` under `$XDG_CONFIG_HOME` (else `$HOME/.config`), `home:<path>`
under `$HOME`, or an absolute path; a bare relative path is refused at load.
The file is read by the binary, one owner per line with comments and blank
lines dropped, exactly as the command form's stdout is. `private_owners_optional`
keeps its meaning for a file that is not there. Both spellings at one level,
top of the file or on one rule, are refused naming both.

A bundled set may carry `private_owners_file` and `private_owners_optional`
at its top level as the default for every inheriting policy; the policy's
own top-level line, in either spelling, overrides it, and a rule's own line
overrides both for that rule. `private-names` ships
`xdg:principles/private-owners` with the absence reported rather than
refused, the default is printed by `uphold rules --set` and held in
`sets.lock.json`, and a set carrying the shell form is refused where it is
parsed. This repository's own policy drops its two lines in favour of the
set's.

`foreign_hosts` now extends a compiled-in list, `["claude.ai"]`, of hosts
that serve no `owner/repo` path for anybody; a policy's or a rule's list
adds to it rather than starting from nothing.

Closes #198
@HackingGate
HackingGate force-pushed the the-owner-list-is-read-from-a-file-spec-a-set-may-ship-and-foreign-hosts-has-a-default branch from b6788d1 to 90e20d2 Compare September 20, 2026 07:18
@HackingGate
HackingGate merged commit c61ffdc into main Sep 20, 2026
11 checks passed
@HackingGate
HackingGate deleted the the-owner-list-is-read-from-a-file-spec-a-set-may-ship-and-foreign-hosts-has-a-default branch September 20, 2026 07:26
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.

private_owners_from is the same shell line in 97 consumer declarations and foreign_hosts the same one-item list in 84, because a set may not ship either

2 participants