Originally created by: Maqbool61
Closes [#442]
Adds examples/plugin-audit-sink/ — a minimal AuditSink tutorial that
mirrors examples/plugin-guardrail/ in structure and scope.
ExampleAuditSink.emit(record) appends one JSON line to a local file
controlled by DOBERMAN_AUDIT_SINK_FILE. Deliberately hello-world: no
batching, no retries, no network — the built-in webhook sink covers those.
The package registers itself via [project.entry-points."doberman.audit_sinks"]
so discover_audit_sinks() picks it up with no core change.
| File | What |
|---|---|
examples/plugin-audit-sink/pyproject.toml |
Package metadata + doberman.audit_sinks entry point |
examples/plugin-audit-sink/src/example_audit_sink/sinks.py |
ExampleAuditSink — emit, never-raises, thread-safe |
examples/plugin-audit-sink/src/example_audit_sink/__init__.py |
Lazy re-export, no import-time side effects |
examples/plugin-audit-sink/tests/test_example_sink.py |
11 tests: discovery, emit, append, read-only, never-raises, env-var, threads |
examples/plugin-audit-sink/README.md |
Round-trip guide, invariants table, what-never-to-log table, copy checklist |
tests/unit/test_core_is_standalone.py |
Fix test_no_audit_sinks_registered_by_default to exclude example_* packages |
test_no_audit_sinks_registered_by_default asserted discover_audit_sinks() == []
— a hard zero that fails whenever any tutorial package is installed locally.
The fix filters out anything whose module starts with example_, matching the
same pattern already used for discover_rules(). The plugin can stay installed
during a full core suite run — no uninstall step needed.
pytest examples/plugin-audit-sink/tests — 11 passed (plugin installed)pytest -n auto — 3354 passed, 0 failed, 91.69% coverage (plugin installed)ruff check / ruff format --check — all cleanlint-imports — 4 contracts kept, 0 brokenpython scripts/check_markdown_links.py — 64 files, no broken linkspython -m tools.parity.generate_parity --check — passed
Originally posted by: vinayjagan03
all CI tests pass. and visual inspection of commit looks okay. good to go :)
Ticket changed by: vinayjagan03
Originally posted by: fu351
Thanks @Maqbool61, this one's in! The sink matches core's AuditSink protocol to the letter, emit(self, record: dict) -> None, and the lazy getattr re-export in init.py is the same shape as the guardrail tutorial, so the two examples read as one series. One thing I changed after the merge, in [#501]: your local editable install made discover_audit_sinks() non-empty, so the standalone guarantee test got a filter that ignores example_ modules. CI never installs the example, so the filter wasn't needed, and the guardrail tutorial solves the same problem by importing the class through sys.path in tests/unit without installing it. I moved yours to that pattern, restored the hard == [] assert, and pointed the README's CI note at the new test. If you want a bigger one, [#236] (level-6) is the ambient activity bus with a doberman.collectors entry-point seam, and after the webhook and OTel sinks you already know the seam pattern.
Related
Tickets: #236
Tickets:
#501