ODIN HEL Policy Engine
Lightweight, embeddable policy engine for governing AI egress (URLs/hosts/methods) with:
- Profiles:
strict,medium,open - Allowlist: per-tenant overrides
- Optional Rego (OPA) evaluation when
rego_pathprovided and theopabinary is available
Install:
pip install odin-hel
Quick Start
from odin_hel import PolicyEngine, Decision
# Create a PolicyEngine with the default 'medium' profile
engine = PolicyEngine(profile="medium")
# Prepare a context for evaluation (simulate an API call)
ctx = {
"tenant_id": "acme",
"forward_url": "https://api.openai.com/v1/chat/completions",
"method": "POST",
"headers": {"authorization": "Bearer ..."},
"payload_cid": "sha256:...",
"attrs": {"user": "alice"}
}
# Evaluate the context
decision = engine.evaluate(ctx)
print(decision)
assert decision.allow
# Use a strict profile (deny by default)
engine_strict = PolicyEngine(profile="strict")
decision_strict = engine_strict.evaluate(ctx)
print(decision_strict)
# Use a custom allowlist
engine_custom = PolicyEngine(profile="strict", allowlist=["api.openai.com"])
decision_custom = engine_custom.evaluate(ctx)
print(decision_custom)
FAQ: Common Errors
Q: I get ModuleNotFoundError: No module named 'odin_hel' when running tests.
A: Make sure your PYTHONPATH includes the src/ directory, e.g.:
export PYTHONPATH=./data/odin-hel/src
pytest
Or on Windows PowerShell:
$env:PYTHONPATH = 'data/odin-hel/src'; python -m pytest
Q: Why does my context get rejected with reason='no_host'?
A: The context must include either a host or a valid forward_url field. If both are missing or invalid, the engine cannot determine the target host.
Q: How do I add a custom allowlist?
A: Pass the allowlist argument to PolicyEngine, e.g. PolicyEngine(profile="strict", allowlist=["api.example.com"]).
Profiles
- strict: deny by default, only explicit allowlist permits
- medium: curated defaults for common AI API hosts + allowlist
- open: allow all (useful for local/dev)
Rego (OPA) optional
If you pass rego_path="policies/egress.rego" and an opa binary is on PATH, the engine will evaluate data.odin.allow against the provided context and return that decision. If OPA or the policy is unavailable, the engine falls back to the profile/allowlist result (fail-closed when explicitly configured).
VS Code + Copilot
Recommended tasks:
- Run tests:
pytest - Add or refine allowlist defaults under
profiles.py
Copilot prompts:
“Extend domain matching to support wildcards like
*.example.comand add unit tests.”
“Add reason codes and structured details when a host is rejected (e.g., policy=profile_denied, match=none).”
“Implement a sample Rego policy and a smoke-test that is skipped when
opais not installed.”
Publishing
Use the included GitHub Actions workflow to publish on tag push (set PYPI_API_TOKEN in repo secrets).
License
Apache-2.0
Metadata
Release files for odin-hel 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| odin_hel-0.5.0.tar.gz | 7.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| odin_hel-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 13.4 kB
Release files / odin_hel-0.5.0.tar.gz
| Download URL | odin_hel-0.5.0.tar.gz |
|---|---|
| Size | 7.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2e22390bf4d7178796d79cd1a313eeb33177a25f1151e3a1c195576b411f2176
|
|
BLAKE2b-256 checksum How to use checksums |
8bcaa904098472a717776e552b6a79b8e228672939f887c21e92c4a6eb385b7c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Release files / odin_hel-0.5.0-py3-none-any.whl
| Download URL | odin_hel-0.5.0-py3-none-any.whl |
|---|---|
| Size | 5.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0fe9cc3b5dd4cf498947da5c6b07fe8bfce8b328b060113b03a312bdbe471930
|
|
BLAKE2b-256 checksum How to use checksums |
a890143743e2651403412161ba9bf9213ac29afa9a2da710e3ecf388c0792f82
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|