Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Some packages have import-time side effects that raise sensitive audit events. F
mypkg = "mypkg"
```

The entries are module prefixes, so `mypkg` also covers `mypkg.submodule`. `fastaudit` does not import these modules when reading metadata. During an audit context, if the stack contains a frame for an allowed module whose `__spec__` is currently initializing, audit events from that import are allowed. Hosts can also pass `allow_imports=('mypkg',)` to `mk_audit()` or call `audit_perms.add_imports('mypkg')` outside the sandbox.
The entries are module prefixes, so `mypkg` also covers `mypkg.submodule`. `fastaudit` does not import these modules when reading metadata. During an audit context, if the stack contains a frame for an allowed module whose `__spec__` is currently initializing, audit events from that import are allowed. Hosts can also pass `allow_imports=('mypkg',)` to `mk_audit()` or call `audit_perms.add_imports('mypkg')` outside the sandbox. A host that passes `data=` with an `import_approved` list gets every event the allowance let through appended to it as `(event, args)`, so it can reconcile what a trusted import did.

### get/set attr hooks

Expand Down
4 changes: 3 additions & 1 deletion fastaudit/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,9 @@ def chk(cfg, event, args):
if event in audit_allow or event.startswith(audit_allow_prefix): return
if event in ('_thread.start_new_thread','_thread.start_joinable_thread') and asyncio_executor_thread(args): return
if event.startswith('audit_perms.'): return deny(cfg, event, args, err_msg(event, args))
if importing_allowed_module(cfg.import_allow): return
if importing_allowed_module(cfg.import_allow):
if (rec := (cfg.data or {}).get('import_approved')) is not None: rec.append((event, args))
return
if event in ('os.putenv','os.unsetenv'):
if env_denied(args[0]): return deny(cfg, event, args, err_msg(event, args))
return
Expand Down
6 changes: 6 additions & 0 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ def import_mod(nm):
with expect_fail(PermissionError): audit_perms.add_imports('blocked_import')
audit_perms.add_imports('blocked_import')
with audit_perms(): assert import_mod('blocked_import').f() is None

# Passing `data` with an `import_approved` list records the events the allowance let through.
rec = []
with mk_audit([tmp_path], allow_imports=('runtime_import_ok',), monitor_calls=False, data=dict(import_approved=rec))():
import_mod('runtime_import_ok')
assert any(ev=='object.__setattr__' for ev,_ in rec)
finally: sys.path.remove(str(tmp_path))


Expand Down