Commit 06e10bf
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
0 commit comments