feat(security): integrate trust context policy with global read roots and channel audiences - #387
Merged
Merged
Conversation
…, channel audiences, and doctor checks
Unblocks Slack sessions that were stuck in empty response loops due to
Team audience defaulting to session-only file access (blocking skill
loading) and missing Tools/Security config sections.
- Add GlobalReadRoots to ToolAudienceProfiles with {skills_dir} and
{identity_dir} tokens so skills and identity files are readable
regardless of audience profile
- Add ChannelAudiences dictionary to SlackChannelOptions for per-channel
audience overrides (explicit channel ID → "dm" key → heuristic fallback)
- Add Security section to config schema (DeploymentPosture,
ShellExecutionMode, StrictDefaults)
- Init wizard now emits Security section and ChannelAudiences with smart
defaults derived from deployment posture
- Escalate missing Tools section from Warning → Error in doctor check
- Add SecurityPolicyDoctorCheck (missing Security → Error, null posture
with relaxed defaults → Error)
- Make CreateProfiles() explicitly set GlobalReadRoots (fragile initializer)
- Extract shared ResolvePathToken() in ToolAudienceProfileResolver to
eliminate duplicated token matching for {skills_dir}/{identity_dir}
- Extract ResolveAndMergeRoots() in ScopedFileAccessPolicy to eliminate
duplicated global-read-root merge logic
- Use StringComparer.Ordinal for ChannelAudiences (Slack IDs are case-sensitive)
- Add test: DM channel ID takes precedence over "dm" key
- Add test: invalid audience value falls through to heuristic
- Pin exact severity in SecurityPolicyDoctorCheck missing-config test
- Add clarifying comment for channel audience defaults (channels always Team)
…dRoots literal path bug - Hard fail when a ChannelAudiences key matches but the value is not a recognized audience string — a typo like "persoanl" now denies the message instead of silently degrading to the heuristic fallback - Fix ResolveGlobalReadRoots skipping literal absolute paths when NetclawPaths is not injected (early return on null _paths) - Cache resolved global read roots in ScopedFileAccessPolicy to avoid re-resolving config-static paths on every file access - Align InitWizardViewModel.ChannelAudiences comparer to Ordinal, matching SlackChannelOptions runtime behavior - Broaden CLAUDE.md silent fallback rule to a general principle - Add tests for PopulateChannelAudiences, literal GlobalReadRoots, and invalid audience value denial
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.
Summary
ToolAudienceProfileswith{skills_dir}and{identity_dir}tokens — skills and identity files are now readable regardless of audience profile, unblocking skill loading under Team/Public audiencesSlackChannelOptionsfor per-channel audience overrides (resolution: explicit channel ID →"dm"key → existing heuristic fallback)DeploymentPosture,ShellExecutionMode,StrictDefaults)Securitysection andSlack.ChannelAudienceswith smart defaults derived from deployment postureToolssection from Warning → Error in doctor checkContext
PRs #380 (memory quality overhaul) and #249 (trust context policy) both merged to dev, but the system was broken: Slack sessions default to Team audience with no Tools config section, blocking
shell_execute, restrictingfile_readto session directory (can't load skills), and causing empty response loops.Test plan
dotnet build— 0 errors, 0 warningsdotnet test— 1,311 tests pass (0 failures)dotnet slopwatch analyze— 0 violationsnetclaw initgenerates Security + Tools + ChannelAudiencesnetclaw doctorpasses with complete config, fails without Security/Toolsshell_executeworks, skills loadableshell_executeblocked, skills readable via global roots