Release Notes¶
v2.6.0 (2026-05-12)¶
Configurable rules and status loop intervals (v2.6.0)¶
- Added —
AgentConfig.dynamic_rule_interval: int(default 300, ge=60) — interval in seconds between dynamic rule polls. - Added —
AgentConfig.status_interval: int(default 300, ge=60) — interval in seconds between agent status reports. - Changed —
_rules_loopnow sleepsself.config.dynamic_rule_intervalinstead of a hardcoded300._status_loopnow sleepsself.config.status_intervalinstead of a hardcoded300. Both loops were previously ignoring any caller-configured value, soSecurityConfig.dynamic_rule_interval(and the newSecurityConfig.agent_status_intervalin guard-core >= 3.1.0) had no effect on the agent's poll cadence. The fields are now honored end-to-end. - Tests added in
tests/test_loop_intervals.pycovering field defaults, persistence, lower-bound rejection (ge=60), and end-to-end assertions that both loops invokeasyncio.sleepwith the configured value.
v2.5.0 (2026-05-06)¶
Install ID fingerprinting and optional HMAC payload signing (v2.5.0)¶
- Added — Persistent install ID. Each agent process now resolves a stable UUID per installation (default storage at
~/.guard-agent/install-id, override viaAgentConfig.install_id), sent on every request asX-Agent-Install-Id. The server uses this to detect when a single API key is being used from many distinct installs (a signal that the key has leaked or is being shared across hosts). Auto-creates the file on first call; OSError on read or write is logged vialogger.exceptionand falls through to a fresh UUID rather than failing the start-up. New module:guard_agent.install_idexposingresolve_install_id(*, state_path, override). - Added — Opt-in HMAC-SHA256 payload signing. When
AgentConfig.payload_signing_secretis set, every outbound request carriesX-Payload-Signature: v1=<hex>computed over the exact bytes that go on the wire — post-gzip and post-encryption — so the server can verify integrity againstrequest.body()without re-decoding. No header is sent when the secret is unset, preserving the existing default behavior. New module:guard_agent.signingexposingsign_payload(body, *, secret). - Added — Two new fields on
AgentConfig:install_id: str | None(override the auto-resolved install ID) andpayload_signing_secret: str | None(HMAC secret; both default toNone). - Changed — Transport sets the install-ID header once on the cached
httpx.AsyncClientdefault headers (applies to every request) and computes the signature per-request inside both encrypted and unencrypted send paths. - Tests added for both modules, full suite at 363 passed / 2 skipped.
v2.4.1 (2026-04-29)¶
Diagnostic-friendly transport error logging (v2.4.1)¶
- Fixed —
HTTPTransport._log_request_errornow formats the captured exception as<ClassName>: <repr>instead ofstr(exc). Several httpx exception classes raised on transport-level connection drops (RemoteProtocolError,WriteError, somehttpcorewrappers) carry no message body, sostr(exc)rendered empty and the previous error line wasHTTP client error for POST <url>:with no diagnostic suffix. Operators chasing a CloudFlare/origin RST storm could not tell which httpx class actually fired without attaching a debugger. The new format always shows the class identity even when the message is empty, e.g.HTTP client error for POST https://example/api/v1/events/encrypted: RemoteProtocolError: RemoteProtocolError(''). No behavior change beyond log accuracy. Coverage onguard_agent/transport.pymaintained at 100% line + 100% branch.
v2.4.0 (2026-04-29)¶
Per-event idempotency keys, configurable overflow policy, and framework-version reporting (v2.4.0)¶
Added¶
SecurityEvent.idempotency_key: UUID— every emitted event now carries a stable per-event identifier (defaultuuid4()viadefault_factory). Combined with the existing batch-stablebatch_id, this lets the SaaS dedup at the event level when an ACK is lost mid-batch and the batch is retried. The field is namedidempotency_key, notevent_id, to avoid collision with the SaaS API's existingevent_id(the prefixed external id, e.g.evt_abc123). Backward-compatible: callers that don't set the field automatically get a generated one.AgentConfig.guard_version: str | None— new optional config field set by the framework adapter (e.g. fastapi-guard middleware) at agent init time, identifying the wrapper package's version. DefaultNonefor callers that constructAgentConfigdirectly without going through a framework wrapper. Framework adapters should setconfig.guard_version = framework_package.__version__immediately before passing the config toGuardAgentHandler.EventBatch.guard_version: str | None— propagated through the wire payload on both the plaintext (/api/v1/events,/api/v1/metrics) and encrypted (/api/v1/events/encrypted) ingestion paths. Sourced fromAgentConfig.guard_version. The SaaS persists this on the project record so analytics can attribute telemetry to the wrapper version, not just the agent version. Without this field the SaaS could only seeagent_version(guard-agent's own version) and had no way to know which middleware version the customer was running.encryption._default_json_handlernow serializesUUIDvalues to their string form alongside the existingdatetime→isoformat()branch. Required for the encrypted-payload path to handle events carrying the newidempotency_key.AgentConfig.buffer_overflow_policy: Literal["drop", "block", "raise"] = "drop"— operators can now choose how the in-memory event/metric buffer behaves at capacity:drop(default) — silent eviction of the oldest entry; preserves prior behavior verbatim. Production-safe for high-throughput; loses events when the SaaS is unreachable.block— backpressures the caller until a flush frees space. Appropriate when event integrity is critical. Use only whenstart_auto_flushis wired or a flush callback is in place; otherwiseclear_bufferis the manual escape hatch.raise—BufferFullErrorpropagates to the caller. Appropriate for tests or strict environments where dropping events is unacceptable.BufferFullError(GuardAgentError)exception class added inguard_agent.exceptionsand re-exported from the top-levelguard_agentmodule.
Fixed¶
HTTPTransport._make_requestwas logging the wrong URL on POST failures. When encryption was enabled, the actual request hit/api/v1/events/encryptedbut the error log printed the unencrypted endpoint string (url = f"{endpoint}{plain_path}"). Operators chasing down 503s and decrypt errors sawPOST .../api/v1/eventsin their logs even though the wire request went to/api/v1/events/encrypted. Fix: compute the actual posted URL (encrypted vs plain) up-front and pass that to_log_request_error. No behavior change beyond log accuracy.
Compatibility¶
- Default behavior unchanged for callers that don't opt into either feature:
idempotency_keyhas adefault_factory, andbuffer_overflow_policydefaults to"drop"(which preserves prior eviction semantics including the silent-overflow counter and warning-every-100th log). - SaaS-side coordination: this release is paired with the SaaS dedup work that ships the
idempotency_keycolumn onsecurity_events, the unique constraint, and thepg_insert ... on_conflict_do_nothingingest path. SaaS deployments that don't yet recognize the field treat it as an unknown column and silently drop the bytes — no behavior change to those callers.
v2.2.0 (2026-04-25)¶
TITLE (v2.2.0)¶
CONTENT
v2.1.0 (2026-04-24)¶
Multi-Adapter Coverage (v2.1.0)¶
- Added per-adapter integration smoke tests:
tests/test_adapter_fastapi.py,test_adapter_flask.py,test_adapter_django.py. Each verifiesSecurityConfig.to_agent_config()roundtrip and request delivery through the adapter's middleware withenable_agent=True. - Added per-adapter documentation pages under
docs/adapters/: FastAPI, Flask, Django, Tornado. Each page covers install, minimal example, and agent wiring specific to that framework. mkdocs.ymlnavigation updated with a new top-level Adapters section.
Dependency Changes (v2.1.0)¶
- Added
django,djapi-guard>=2.0.0,flask,flaskapi-guard>=2.0.0,tornadoto[project.optional-dependencies].devso the test suite can exercise every adapter. tornadoapi-guardis not yet included in dev extras — it has not been published to PyPI (only a yanked 0.0.1 exists). Integration tests for Tornado are stubbed withpytest.mark.skipintests/test_adapter_tornado.py. Re-enable once the adapter ships a 1.0.0+ release.
v2.0.0 (2026-04-24)¶
Package Rename (v2.0.0)¶
- Renamed on PyPI:
fastapi-guard-agent→guard-agent. The Python import path (from guard_agent import ...) is unchanged — no code changes are required in consuming applications. - Repositioned as a framework-agnostic telemetry agent serving
fastapi-guard,flaskapi-guard,djangoapi-guard, andtornadoapi-guard. - Legacy name preserved: a meta-package
fastapi-guard-agent==1.2.0is published alongside this release, whose only dependency isguard-agent>=2.0.0,<3.0.0. Existingpip install fastapi-guard-agentinvocations continue to resolve correctly and pull the renamed distribution transitively. - Repository renamed on GitHub:
rennf93/fastapi-guard-agent→rennf93/guard-agent. GitHub auto-redirects the old URLs. - Documentation site moved to
https://rennf93.github.io/guard-agent/.
Dependency Changes (v2.0.0)¶
- Removed
fastapiandfastapi-guardfrom runtime dependencies — the agent is framework-agnostic and speaks HTTP to the dashboard, not to any web framework. - Runtime deps are now:
cryptography,httpx,pydantic,typing-extensions. fastapiandfastapi-guardremain as dev extras so the existing test suite keeps passing. Each framework adapter brings its own web framework.- Dropped
Framework :: FastAPIclassifier; development status promoted fromAlphatoBeta.
Breaking Changes (v2.0.0)¶
- None in Python API —
from guard_agent import ...,GuardAgentHandler,AgentConfig, and every public symbol behave identically. - Distribution name change only: scripts, Dockerfiles, and lockfiles that install
fastapi-guard-agentdirectly should migrate toguard-agent. The shim keeps old commands working but new projects should installguard-agentdirectly.
Migration Guide (v2.0.0)¶
- Existing code: no changes.
- Install commands (uv): replace
uv add fastapi-guard-agentwithuv add guard-agentat your leisure — both resolve to the same underlying package. - Poetry / pip equivalents:
poetry add guard-agent/pip install guard-agent. - Lockfiles: running
uv lock,poetry lock, orpip-compileafter bumping will transparently update entries toguard-agent.
v1.1.1 (2026-03-11)¶
Bug Fixes (v1.1.1)¶
- Fixed misalignment on documentation headers and model parameters.
- Added support for Python 3.14.
Maintenance (v1.1.1)¶
- Code alignment and cleanup.
v1.1.0 (2025-10-14)¶
New Features (v1.1.0)¶
- Added end-to-end payload encryption for secure telemetry transmission using AES-256-GCM.
- Implemented
PayloadEncryptorclass with project-specific encryption keys. - Added encrypted endpoint support for events and metrics (
/api/v1/events/encrypted). - Integrated automatic datetime serialization in encrypted payloads via custom JSON handler.
- Added encryption key verification during transport initialization.
Technical Details (v1.1.0)¶
- Encryption uses AES-256-GCM with 96-bit nonces and 128-bit authentication tags.
- Pydantic models are serialized using
.model_dump(mode="json")before encryption. - Custom
_default_json_handlerensures datetime objects are properly ISO-formatted.
v1.0.2 (2025-09-12)¶
Enhancements (v1.0.2)¶
- Added dynamic rule updated event type.
v1.0.1 (2025-08-07)¶
Enhancements (v1.0.1)¶
- Added path_excluded event type.
v1.0.0 (2025-07-24)¶
Official Release
v0.1.1 (2025-07-09)¶
Enhancements (v0.1.1)¶
- Standardized Redis Protocl/Manager methods across libraries.
v0.1.0 (2025-07-08)¶
Enhancements (v0.1.0)¶
- Switched from aiohttp to httpx for HTTP client.
- Completed implementation.
- 100% test coverage.
v0.0.1 (2025-06-22)¶
New Features (v0.0.1)¶
- Initial release FastAPI Guard Agent.