Menu

#132 docs(examples): add a custom Guardrail plugin tutorial

closed
nobody
None
2026-07-30
2026-07-19
Anonymous
No

Originally created by: snowyukitty

Slice

What this PR does

Doberman’s extensibility story is that third parties can ship rules without core importing them — via the doberman.rules entry-point group. Until now there was no worked example to copy.

This PR adds a small, opt-in tutorial package at examples/plugin-guardrail/ that shows the full round trip:

  1. implement a minimal Guardrail (ExampleRule)
  2. register it in the package’s own pyproject.toml
  3. pip install -e → the rule appears in discover_rules() / ObjectiveGuardrail
  4. prove it with focused tests

Demo behavior: a file_write whose canonical basename is SECRETS_TODO.md steps up to AUTH (sensitive_path_access). Everything else abstains (PASS). Harmless on purpose — easy to read in five minutes.

Closes [#91].

What the example teaches

  • The real entry-point contract (doberman.rules), not a hypothetical API
  • Path matching that mirrors ProtectedPathRule (prefer raw_arguments, canonicalize, normalize \/)
  • Raise-only discipline: the plugin only ever abstains or steps up
  • Explanations that name the rule, never the raw path or payload

Why this is isolated and safe

  • No core engine change — discovery stays in registry.discover_rules() as today
  • Opt-in — default CI does not install the package, so standalone / empty-registry checks stay green
  • CI unit tests path-import the rule and inject it with ObjectiveGuardrail(load_plugins=False, extra_rules=[…])
  • Real entry-point discovery is covered by the package’s own tests after editable install (documented uninstall afterward)
  • No new production dependency on core; no secrets, network, or payload logging

Tests added (run in CI)

  • tests/unit/test_examples_plugin_guardrail.py — layout, entry-point declaration, AUTH/PASS behavior, redacted-target + raw path, backslash normalize, near-miss basenames, explanation redaction, raise-only vs built-in .env BLOCK, Guardrail shape
  • examples/plugin-guardrail/tests/test_example_rule.py — install-time discovery + objective-guardrail fire (run after pip install -e examples/plugin-guardrail; not in default testpaths by design)

Local validation (Python 3.12, rebased on current main):

  • ruff check . / ruff format --check . — clean
  • lint-imports — both contracts kept
  • pytest tests/unit/test_examples_plugin_guardrail.py tests/unit/test_core_is_standalone.py -q — green
  • pip install -e examples/plugin-guardrail && pytest examples/plugin-guardrail/tests -q — green (11)
  • uninstall → standalone still green

Public-release safety (doberman-core only)

  • [x] Contains nothing from the "not allowed" list: no enterprise/hosted code, no proprietary detection, no customer data, no secrets, no commercial-license code
  • [x] Core still builds/tests/runs with NO enterprise package installed

Security checklist

  • [x] Fails closed on error / uncertainty (example has no fail-open catch-to-PASS; core isolation unchanged)
  • [x] No secret, full file, or unredacted prompt logged or committed
  • [x] Any guardrail/learning change is raise-only (no silent loosening) — tutorial returns only PASS/AUTH; cannot lower a built-in BLOCK
  • [x] Every BLOCK/AUTH carries reason codes + a human explanation
  • [x] doberman-core does not import doberman_enterprise

Edge cases covered / Deviations from plan / Risks introduced

Covered: case-insensitive basename; Windows-style separators on any OS; redacted action.target with raw path; target-only fallback; near-miss basenames; read/empty abstain; explanation omits path; raise-only vs .env.

Deviations: none material vs [#91]. CI unit tests were added so default pytest covers evaluate/raise-only without registering the entry point (avoids polluting discover_rules() == []).

Risks / notes:

  • While the example package is installed, core “no plugins registered” assertions fail — expected; README shows uninstall.
  • examples/ is git-checkout oriented (not added to the locked core sdist include list).
  • Root README links the tutorial and reminds readers to uninstall for a clean core-only env.

AI assistance was used during implementation and review. The contributor independently verified the design, complete diff, and reported test results.

Related

Tickets: #231
Tickets: #91

Discussion

  • Anonymous

    Anonymous - 2026-07-19

    Originally posted by: fu351

    Welcome @snowyukitty, and thanks for contributing! A custom Guardrail plugin tutorial is exactly the kind of example we want alongside the plugin interfaces. Taking a review pass now - feedback shortly.

     
  • Anonymous

    Anonymous - 2026-07-22

    Ticket changed by: fu351

    • status: open --> closed
     
  • Anonymous

    Anonymous - 2026-07-22

    Originally posted by: fu351

    🎉 Merged — thank you, @snowyukitty!

    This is exactly the kind of contribution that makes Doberman's plugin system real for people: a complete, tested, copy-pasteable example of a custom Guardrail plugin, wired through the entry-point registry the right way. A full tutorial plus tests with green CI, as a first-time contributor — genuinely appreciated. 🙏

    If you're up for more, I'd love to have you around as we build this out:

    • 💬 We just started a community Discord — come say hi: https://discord.gg/Sfy5XGNqty
    • 🏗️ I'll be opening some meatier help wanted issues shortly (real, hard parts of the system, not busywork). Would be great to have you take a crack at one.

    Thanks again for helping make Doberman something more than a solo project. 🐕

     
  • Anonymous

    Anonymous - 2026-07-30

    Originally posted by: fu351

    Congrats on [#184] landing today too — busy week for you. The custom-guardrail plugin tutorial in this PR is thorough (a full working example plugin, its own tests, and the walkthrough docs), and since you're the one who wrote it, [#200] (plugins+docs: complete the doberman.detectors extension seam, level-9) is squarely your lane — it needs the same example-plugin-plus-docs treatment applied to a different seam. Levels run 1-10 on every open issue now, and commenting on one claims it.

     

    Related

    Tickets: #184
    Tickets: #200


Log in to post a comment.