Skip to content

Commit 06e10bf

Browse files
Add permission audit trail — policy-based tool call checking (#13)
* Add permission audit trail (closes #7) - audit.py: checks every tool_call against .agent-scope.json policy (file read/write glob patterns, command allow/deny list, network deny_all with allow exceptions via fnmatch) - Auto-flags sensitive files (.env, *.pem, .ssh/*, .github/workflows/*) even without a policy file - Exits with code 1 when violations found (CI-friendly) - 26 new tests (198 total passing) Co-authored-by: Ona <no-reply@ona.com> * Fix _cmd_matches word-boundary false-positive and str(None) path bug - _cmd_matches: prefix match now requires space or end-of-string after the pattern, preventing 'curl' from matching 'curling --help' - _audit_event: use 'or' chaining instead of str(args.get(..., ...)) to avoid str(None) == 'None' passing the path guard Co-authored-by: Ona <no-reply@ona.com> * Warn on malformed policy file; clarify generic tool verdict reason - Policy.load: distinguish json.JSONDecodeError from OSError and write a warning to stderr for both. Previously a malformed policy was silently treated as missing, giving no indication to the user. - _audit_event generic branch: clarify reason string to explain that no policy rule covers arbitrary tool types, not that no policy file exists. Co-authored-by: Ona <no-reply@ona.com> * Fix glob matching, add Grep/Glob support, fix double-entry, tighten sensitive patterns audit.py: - _glob_match: replace fnmatch with pathlib.PurePath.match() so src/** correctly matches src/auth.py and src/utils/path.py (fnmatch treats ** as two * wildcards and does not match across path separators) - Add Grep and Glob to the file-read branch so file read policy applies to directory listings and content searches, not just Read/View calls - Network+command double-entry: skip command policy check when a network violation has already been recorded for the same event - SENSITIVE_PATTERNS: remove *secret* (too broad — matches secret_manager.py, test_secrets.py, etc.); replace with explicit secrets.json/yaml/toml/yml tests: - test_glob_pattern_nested: src/utils/path.py matches src/** - test_secret_manager_not_sensitive: source files no longer false-positive - test_secrets_json/yaml_is_sensitive: explicit secrets files still caught - TestGrepGlobPolicy: Grep denied path, Glob allowed path, Grep sensitive flag - TestNetworkCommandDoubleEntry: curl to denied URL = 1 entry not 2; curl to allowed host still checked against command policy - TestMalformedPolicy: malformed JSON returns None, audit continues as no-policy Co-authored-by: Ona <no-reply@ona.com> * Fix glob matching: implement ** recursive wildcard without pathlib.match PurePath.match() with ** is unreliable across Python 3.10-3.13 (the semantics changed in 3.12). Replace with a recursive segment-by-segment matcher (_match_parts) that correctly handles ** as zero-or-more path components on all supported versions. src/** now matches src/auth.py, src/utils/path.py, src/a/b/c/deep.py. Co-authored-by: Ona <no-reply@ona.com> --------- Co-authored-by: Ona <no-reply@ona.com>
1 parent a724556 commit 06e10bf

3 files changed

Lines changed: 850 additions & 0 deletions

File tree

0 commit comments

Comments
 (0)