fastapi-observer 0.4.1__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. {fastapi_observer-0.4.1/src/fastapi_observer.egg-info → fastapi_observer-1.2.0}/PKG-INFO +126 -5
  2. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/README.md +118 -3
  3. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/pyproject.toml +9 -1
  4. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0/src/fastapi_observer.egg-info}/PKG-INFO +126 -5
  5. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapi_observer.egg-info/SOURCES.txt +7 -0
  6. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapi_observer.egg-info/requires.txt +8 -0
  7. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/__init__.py +22 -0
  8. fastapi_observer-1.2.0/src/fastapiobserver/_version.py +1 -0
  9. fastapi_observer-1.2.0/src/fastapiobserver/audit/__init__.py +14 -0
  10. fastapi_observer-1.2.0/src/fastapiobserver/audit/formatter.py +96 -0
  11. fastapi_observer-1.2.0/src/fastapiobserver/audit/providers.py +51 -0
  12. fastapi_observer-1.2.0/src/fastapiobserver/audit/verify.py +129 -0
  13. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/config.py +8 -0
  14. fastapi_observer-1.2.0/src/fastapiobserver/db_tracing.py +143 -0
  15. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/fastapi.py +36 -1
  16. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/logging/setup.py +15 -2
  17. fastapi_observer-1.2.0/tests/test_audit_chain.py +287 -0
  18. fastapi_observer-1.2.0/tests/test_db_tracing.py +166 -0
  19. fastapi_observer-0.4.1/src/fastapiobserver/_version.py +0 -1
  20. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/LICENSE +0 -0
  21. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/setup.cfg +0 -0
  22. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapi_observer.egg-info/dependency_links.txt +0 -0
  23. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapi_observer.egg-info/top_level.txt +0 -0
  24. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/control_plane.py +0 -0
  25. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/integrations/__init__.py +0 -0
  26. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/integrations/strawberry.py +0 -0
  27. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/logging/__init__.py +0 -0
  28. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/logging/circuit_breaker.py +0 -0
  29. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/logging/filters.py +0 -0
  30. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/logging/formatter.py +0 -0
  31. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/logging/queueing.py +0 -0
  32. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/logging/state.py +0 -0
  33. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/loguru.py +0 -0
  34. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/__init__.py +0 -0
  35. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/builder.py +0 -0
  36. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/contracts.py +0 -0
  37. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/endpoint.py +0 -0
  38. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/noop.py +0 -0
  39. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/pathing.py +0 -0
  40. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/prometheus/__init__.py +0 -0
  41. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/prometheus/backend.py +0 -0
  42. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/prometheus/client.py +0 -0
  43. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/prometheus/collector.py +0 -0
  44. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/prometheus/exemplars.py +0 -0
  45. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/prometheus/multiprocess.py +0 -0
  46. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/metrics/registry.py +0 -0
  47. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/middleware/__init__.py +0 -0
  48. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/middleware/body_capture.py +0 -0
  49. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/middleware/context.py +0 -0
  50. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/middleware/events.py +0 -0
  51. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/middleware/headers.py +0 -0
  52. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/middleware/ip.py +0 -0
  53. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/middleware/metrics.py +0 -0
  54. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/middleware/request_logging.py +0 -0
  55. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/middleware/span_errors.py +0 -0
  56. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/otel/__init__.py +0 -0
  57. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/otel/lifecycle.py +0 -0
  58. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/otel/logs.py +0 -0
  59. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/otel/metrics.py +0 -0
  60. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/otel/resource.py +0 -0
  61. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/otel/settings.py +0 -0
  62. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/otel/tracing.py +0 -0
  63. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/otel/types.py +0 -0
  64. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/plugins.py +0 -0
  65. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/propagation.py +0 -0
  66. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/py.typed +0 -0
  67. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/request_context.py +0 -0
  68. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/security/__init__.py +0 -0
  69. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/security/normalize.py +0 -0
  70. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/security/policy.py +0 -0
  71. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/security/proxies.py +0 -0
  72. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/security/redaction.py +0 -0
  73. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/__init__.py +0 -0
  74. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/builtin.py +0 -0
  75. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/discovery.py +0 -0
  76. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/factory.py +0 -0
  77. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/logtail/__init__.py +0 -0
  78. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/logtail/dlq.py +0 -0
  79. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/logtail/handler.py +0 -0
  80. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/logtail/sink.py +0 -0
  81. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/protocol.py +0 -0
  82. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/registry.py +0 -0
  83. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/sinks/stats.py +0 -0
  84. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/src/fastapiobserver/utils.py +0 -0
  85. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_body_media_allowlist.py +0 -0
  86. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_config_settings.py +0 -0
  87. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_dx_parity.py +0 -0
  88. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_excluded_url_precedence.py +0 -0
  89. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_fastapi_install.py +0 -0
  90. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_graphql_integrations.py +0 -0
  91. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_log_queue_controls.py +0 -0
  92. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_logging_schema_contract.py +0 -0
  93. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_logtail_dlq.py +0 -0
  94. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_loguru_bridge.py +0 -0
  95. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_metrics_contracts.py +0 -0
  96. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_metrics_optional_dependency.py +0 -0
  97. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_middleware.py +0 -0
  98. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_negotiate_content_type.py +0 -0
  99. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_otel_integration.py +0 -0
  100. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_otel_lifecycle.py +0 -0
  101. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_otel_log_correlation.py +0 -0
  102. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_otel_logs_from_env.py +0 -0
  103. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_otel_logs_pipeline.py +0 -0
  104. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_otel_metrics_from_env.py +0 -0
  105. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_otlp_export_integration.py +0 -0
  106. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_plugin_isolation.py +0 -0
  107. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_propagation.py +0 -0
  108. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_redaction_presets.py +0 -0
  109. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_route_template_cardinality.py +0 -0
  110. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_runtime_control_auth.py +0 -0
  111. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_security_audit_fixes.py +0 -0
  112. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_security_redaction.py +0 -0
  113. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_sink_circuit_breaker.py +0 -0
  114. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_sinks.py +0 -0
  115. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_trust_boundary.py +0 -0
  116. {fastapi_observer-0.4.1 → fastapi_observer-1.2.0}/tests/test_utils_refactors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-observer
3
- Version: 0.4.1
3
+ Version: 1.2.0
4
4
  Summary: Zero-glue FastAPI observability with security presets and runtime controls
5
5
  Author-email: Vitaee <opensource@vitaee.dev>
6
6
  License-Expression: MIT
@@ -10,7 +10,7 @@ Project-URL: Repository, https://github.com/Vitaee/FastapiObserver.git
10
10
  Project-URL: Issues, https://github.com/Vitaee/FastapiObserver/issues
11
11
  Project-URL: Funding, https://buymeacoffee.com/FYbPCSu
12
12
  Keywords: fastapi,observability,logging,metrics,opentelemetry
13
- Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Development Status :: 5 - Production/Stable
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: Operating System :: OS Independent
16
16
  Classifier: Programming Language :: Python :: 3
@@ -45,6 +45,10 @@ Provides-Extra: otel-httpx
45
45
  Requires-Dist: opentelemetry-instrumentation-httpx>=0.60b1; extra == "otel-httpx"
46
46
  Provides-Extra: otel-requests
47
47
  Requires-Dist: opentelemetry-instrumentation-requests>=0.60b1; extra == "otel-requests"
48
+ Provides-Extra: audit
49
+ Requires-Dist: cryptography>=46.0.5; extra == "audit"
50
+ Provides-Extra: otel-sqlalchemy
51
+ Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.60b1; extra == "otel-sqlalchemy"
48
52
  Provides-Extra: all
49
53
  Requires-Dist: orjson>=3.11.7; extra == "all"
50
54
  Requires-Dist: prometheus-client>=0.24.1; extra == "all"
@@ -56,6 +60,8 @@ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.60b1; extra == "all"
56
60
  Requires-Dist: opentelemetry-instrumentation-logging>=0.60b1; extra == "all"
57
61
  Requires-Dist: opentelemetry-instrumentation-httpx>=0.60b1; extra == "all"
58
62
  Requires-Dist: opentelemetry-instrumentation-requests>=0.60b1; extra == "all"
63
+ Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.60b1; extra == "all"
64
+ Requires-Dist: cryptography>=46.0.5; extra == "all"
59
65
  Provides-Extra: dev
60
66
  Requires-Dist: httpx>=0.28.1; extra == "dev"
61
67
  Requires-Dist: loguru>=0.7.2; extra == "dev"
@@ -645,6 +651,8 @@ The `examples/` directory contains runnable demos:
645
651
  | [`security_presets_app.py`](examples/security_presets_app.py) | Preset-based security policy |
646
652
  | [`allowlist_app.py`](examples/allowlist_app.py) | Allowlist-only sanitization |
647
653
  | [`otel_app.py`](examples/otel_app.py) | OTel tracing and resource attributes |
654
+ | [`audit_app.py`](examples/audit_app.py) | Tamper-evident cryptographic log signatures |
655
+ | [`db_tracing_app.py`](examples/db_tracing_app.py) | SQLCommenter and database trace injection |
648
656
  | [`graphql_app.py`](examples/graphql_app.py) | Native Strawberry GraphQL observability |
649
657
  | [`benchmarks/`](examples/benchmarks/) | Baseline vs observer benchmark harness |
650
658
  | [`k8s/`](examples/k8s/) | Kubernetes-native stack with Prometheus + Loki + Tempo + Grafana |
@@ -776,6 +784,111 @@ Notes:
776
784
  > [!TIP]
777
785
  > The Logtail Dead Letter Queue (DLQ) provides best-effort local durability. If the internal memory queue overflows under immense API pressure (`queue.Full`), or if an external network partition completely exhausts the outbound HTTP retry backoff, the dropped log payloads are immediately salvaged into local NDJSON envelopes. You can replay these files to BetterStack later using the provided `scripts/replay_dlq.py` utility.
778
786
 
787
+ ### Tamper-evident audit logging
788
+
789
+ For regulated industries (Fintech, Healthcare, SOC 2) where you must prove logs were not altered, deleted, or reordered:
790
+
791
+ ```bash
792
+ pip install "fastapi-observer[audit]"
793
+ export OBS_AUDIT_SECRET_KEY="your-signing-secret"
794
+ export OBS_AUDIT_LOGGING_ENABLED="true"
795
+ ```
796
+
797
+ ```python
798
+ install_observability(app, settings)
799
+ # Every JSON log now contains _audit_seq and _audit_sig fields
800
+ ```
801
+
802
+ Each log record is chained via HMAC-SHA256: record B's signature includes the signature of record A. Breaking any link (tamper, delete, reorder) invalidates the chain.
803
+
804
+ | Variable | Default | Description |
805
+ |---|---|---|
806
+ | `OBS_AUDIT_LOGGING_ENABLED` | `false` | Enable HMAC-SHA256 hash chain |
807
+ | `OBS_AUDIT_KEY_ENV_VAR` | `OBS_AUDIT_SECRET_KEY` | Name of env var containing the signing key |
808
+ | `OBS_AUDIT_SECRET_KEY` | - | The HMAC signing key (read by `LocalHMACProvider`) |
809
+
810
+ Custom key provider (e.g. KMS / Vault):
811
+
812
+ ```python
813
+ from fastapiobserver import AuditKeyProvider
814
+
815
+ class VaultKeyProvider:
816
+ def get_key(self) -> bytes:
817
+ return vault_client.get_secret("audit-signing-key").encode()
818
+
819
+ install_observability(app, settings, audit_key_provider=VaultKeyProvider())
820
+ ```
821
+
822
+ Verify logs with the CLI:
823
+
824
+ ```bash
825
+ export OBS_AUDIT_SECRET_KEY="your-signing-secret"
826
+ python scripts/verify_audit_chain.py exported_logs.ndjson
827
+ # PASS — 1042 records verified, chain intact.
828
+ ```
829
+
830
+ ### SQLCommenter & database tracing
831
+
832
+ Bridges the gap between FastAPI application traces and database performance monitoring. When enabled, the `trace_id` is automatically injected into raw SQL queries as a comment:
833
+
834
+ ```sql
835
+ SELECT * FROM users /*traceparent='00-abc123def456-01',route='/api/users'*/
836
+ ```
837
+
838
+ This lets DBAs correlate slow Postgres/MySQL queries directly back to the originating HTTP request.
839
+
840
+ ```bash
841
+ pip install "fastapi-observer[otel-sqlalchemy]"
842
+ ```
843
+
844
+ **Automatic** (via `install_observability`):
845
+
846
+ ```python
847
+ from sqlalchemy import create_engine
848
+
849
+ engine = create_engine("postgresql://...")
850
+ install_observability(app, settings, otel_settings=otel_settings, db_engine=engine)
851
+ ```
852
+
853
+ Multiple engines (e.g. read/write replicas):
854
+
855
+ ```python
856
+ write_engine = create_engine("postgresql://primary/...")
857
+ read_engine = create_engine("postgresql://replica/...")
858
+ install_observability(
859
+ app, settings,
860
+ otel_settings=otel_settings,
861
+ db_engine=[write_engine, read_engine],
862
+ db_commenter_options={"opentelemetry_values": True, "route": False},
863
+ )
864
+ ```
865
+
866
+ **Manual** (standalone):
867
+
868
+ ```python
869
+ from fastapiobserver import instrument_sqlalchemy, instrument_sqlalchemy_async
870
+
871
+ # Sync engine
872
+ instrument_sqlalchemy(engine)
873
+
874
+ # Async engine (extracts .sync_engine automatically)
875
+ instrument_sqlalchemy_async(async_engine)
876
+ ```
877
+
878
+ Custom commenter options:
879
+
880
+ ```python
881
+ instrument_sqlalchemy(engine, commenter_options={
882
+ "opentelemetry_values": True, # traceparent (default: True)
883
+ "db_driver": True, # e.g. psycopg2 (default: True)
884
+ "route": True, # e.g. /api/users (default: True)
885
+ "db_framework": True, # e.g. sqlalchemy (default: False)
886
+ })
887
+ ```
888
+
889
+ > [!CAUTION]
890
+ > **Database statement PII risk:** The OpenTelemetry SQLAlchemy instrumentor captures raw SQL as the `db.statement` span attribute and exports it directly to your tracing backend (Jaeger, Tempo, Datadog). These span attributes are **not** scrubbed by `fastapi-observer`'s `SecurityPolicy`. If your application has poorly parameterized queries (e.g. `WHERE email = 'user@example.com'`), PII will leak into your trace storage. Always use parameterized queries and review your `db.statement` exports in production.
891
+
779
892
  ---
780
893
 
781
894
  ## Advanced Operations
@@ -1053,10 +1166,12 @@ Reproducible benchmark harness and methodology:
1053
1166
 
1054
1167
  - `0.1.x`: secure-by-default core
1055
1168
  - `0.2.x`: OTel interoperability, security presets, allowlists
1056
- - `0.3.x`: package modularization, sink/metrics hardening, and performance reliability updates
1057
- - `1.0.0`: dynamic runtime controls and plugin stability
1169
+ - `0.3.x`: GraphQL observability, error fingerprinting, and Logtail DLQ durability
1170
+ - `0.4.x`: package modularization, sink/registry hardening, and runtime control token rotation
1171
+ - `1.0.x`: first stable release contract for production deployments
1172
+ - `1.2.0`: tamper-evident audit logging and SQLAlchemy trace/commenter integration
1058
1173
 
1059
- Current release version: `0.4.1`
1174
+ Current release version: `1.2.0`
1060
1175
 
1061
1176
  ## Changelog Policy
1062
1177
 
@@ -1066,6 +1181,12 @@ Breaking changes must be listed under a `Breaking Changes` section in `CHANGELOG
1066
1181
 
1067
1182
  ## Packaging and Publishing (Maintainers)
1068
1183
 
1184
+ Recommended release command (uses `.env` with `PYPI_TOKEN`):
1185
+
1186
+ ```bash
1187
+ scripts/deploy_pypi.sh --tag v1.2.0 --push-tag
1188
+ ```
1189
+
1069
1190
  ### 1) Build distributions
1070
1191
 
1071
1192
  ```bash
@@ -575,6 +575,8 @@ The `examples/` directory contains runnable demos:
575
575
  | [`security_presets_app.py`](examples/security_presets_app.py) | Preset-based security policy |
576
576
  | [`allowlist_app.py`](examples/allowlist_app.py) | Allowlist-only sanitization |
577
577
  | [`otel_app.py`](examples/otel_app.py) | OTel tracing and resource attributes |
578
+ | [`audit_app.py`](examples/audit_app.py) | Tamper-evident cryptographic log signatures |
579
+ | [`db_tracing_app.py`](examples/db_tracing_app.py) | SQLCommenter and database trace injection |
578
580
  | [`graphql_app.py`](examples/graphql_app.py) | Native Strawberry GraphQL observability |
579
581
  | [`benchmarks/`](examples/benchmarks/) | Baseline vs observer benchmark harness |
580
582
  | [`k8s/`](examples/k8s/) | Kubernetes-native stack with Prometheus + Loki + Tempo + Grafana |
@@ -706,6 +708,111 @@ Notes:
706
708
  > [!TIP]
707
709
  > The Logtail Dead Letter Queue (DLQ) provides best-effort local durability. If the internal memory queue overflows under immense API pressure (`queue.Full`), or if an external network partition completely exhausts the outbound HTTP retry backoff, the dropped log payloads are immediately salvaged into local NDJSON envelopes. You can replay these files to BetterStack later using the provided `scripts/replay_dlq.py` utility.
708
710
 
711
+ ### Tamper-evident audit logging
712
+
713
+ For regulated industries (Fintech, Healthcare, SOC 2) where you must prove logs were not altered, deleted, or reordered:
714
+
715
+ ```bash
716
+ pip install "fastapi-observer[audit]"
717
+ export OBS_AUDIT_SECRET_KEY="your-signing-secret"
718
+ export OBS_AUDIT_LOGGING_ENABLED="true"
719
+ ```
720
+
721
+ ```python
722
+ install_observability(app, settings)
723
+ # Every JSON log now contains _audit_seq and _audit_sig fields
724
+ ```
725
+
726
+ Each log record is chained via HMAC-SHA256: record B's signature includes the signature of record A. Breaking any link (tamper, delete, reorder) invalidates the chain.
727
+
728
+ | Variable | Default | Description |
729
+ |---|---|---|
730
+ | `OBS_AUDIT_LOGGING_ENABLED` | `false` | Enable HMAC-SHA256 hash chain |
731
+ | `OBS_AUDIT_KEY_ENV_VAR` | `OBS_AUDIT_SECRET_KEY` | Name of env var containing the signing key |
732
+ | `OBS_AUDIT_SECRET_KEY` | - | The HMAC signing key (read by `LocalHMACProvider`) |
733
+
734
+ Custom key provider (e.g. KMS / Vault):
735
+
736
+ ```python
737
+ from fastapiobserver import AuditKeyProvider
738
+
739
+ class VaultKeyProvider:
740
+ def get_key(self) -> bytes:
741
+ return vault_client.get_secret("audit-signing-key").encode()
742
+
743
+ install_observability(app, settings, audit_key_provider=VaultKeyProvider())
744
+ ```
745
+
746
+ Verify logs with the CLI:
747
+
748
+ ```bash
749
+ export OBS_AUDIT_SECRET_KEY="your-signing-secret"
750
+ python scripts/verify_audit_chain.py exported_logs.ndjson
751
+ # PASS — 1042 records verified, chain intact.
752
+ ```
753
+
754
+ ### SQLCommenter & database tracing
755
+
756
+ Bridges the gap between FastAPI application traces and database performance monitoring. When enabled, the `trace_id` is automatically injected into raw SQL queries as a comment:
757
+
758
+ ```sql
759
+ SELECT * FROM users /*traceparent='00-abc123def456-01',route='/api/users'*/
760
+ ```
761
+
762
+ This lets DBAs correlate slow Postgres/MySQL queries directly back to the originating HTTP request.
763
+
764
+ ```bash
765
+ pip install "fastapi-observer[otel-sqlalchemy]"
766
+ ```
767
+
768
+ **Automatic** (via `install_observability`):
769
+
770
+ ```python
771
+ from sqlalchemy import create_engine
772
+
773
+ engine = create_engine("postgresql://...")
774
+ install_observability(app, settings, otel_settings=otel_settings, db_engine=engine)
775
+ ```
776
+
777
+ Multiple engines (e.g. read/write replicas):
778
+
779
+ ```python
780
+ write_engine = create_engine("postgresql://primary/...")
781
+ read_engine = create_engine("postgresql://replica/...")
782
+ install_observability(
783
+ app, settings,
784
+ otel_settings=otel_settings,
785
+ db_engine=[write_engine, read_engine],
786
+ db_commenter_options={"opentelemetry_values": True, "route": False},
787
+ )
788
+ ```
789
+
790
+ **Manual** (standalone):
791
+
792
+ ```python
793
+ from fastapiobserver import instrument_sqlalchemy, instrument_sqlalchemy_async
794
+
795
+ # Sync engine
796
+ instrument_sqlalchemy(engine)
797
+
798
+ # Async engine (extracts .sync_engine automatically)
799
+ instrument_sqlalchemy_async(async_engine)
800
+ ```
801
+
802
+ Custom commenter options:
803
+
804
+ ```python
805
+ instrument_sqlalchemy(engine, commenter_options={
806
+ "opentelemetry_values": True, # traceparent (default: True)
807
+ "db_driver": True, # e.g. psycopg2 (default: True)
808
+ "route": True, # e.g. /api/users (default: True)
809
+ "db_framework": True, # e.g. sqlalchemy (default: False)
810
+ })
811
+ ```
812
+
813
+ > [!CAUTION]
814
+ > **Database statement PII risk:** The OpenTelemetry SQLAlchemy instrumentor captures raw SQL as the `db.statement` span attribute and exports it directly to your tracing backend (Jaeger, Tempo, Datadog). These span attributes are **not** scrubbed by `fastapi-observer`'s `SecurityPolicy`. If your application has poorly parameterized queries (e.g. `WHERE email = 'user@example.com'`), PII will leak into your trace storage. Always use parameterized queries and review your `db.statement` exports in production.
815
+
709
816
  ---
710
817
 
711
818
  ## Advanced Operations
@@ -983,10 +1090,12 @@ Reproducible benchmark harness and methodology:
983
1090
 
984
1091
  - `0.1.x`: secure-by-default core
985
1092
  - `0.2.x`: OTel interoperability, security presets, allowlists
986
- - `0.3.x`: package modularization, sink/metrics hardening, and performance reliability updates
987
- - `1.0.0`: dynamic runtime controls and plugin stability
1093
+ - `0.3.x`: GraphQL observability, error fingerprinting, and Logtail DLQ durability
1094
+ - `0.4.x`: package modularization, sink/registry hardening, and runtime control token rotation
1095
+ - `1.0.x`: first stable release contract for production deployments
1096
+ - `1.2.0`: tamper-evident audit logging and SQLAlchemy trace/commenter integration
988
1097
 
989
- Current release version: `0.4.1`
1098
+ Current release version: `1.2.0`
990
1099
 
991
1100
  ## Changelog Policy
992
1101
 
@@ -996,6 +1105,12 @@ Breaking changes must be listed under a `Breaking Changes` section in `CHANGELOG
996
1105
 
997
1106
  ## Packaging and Publishing (Maintainers)
998
1107
 
1108
+ Recommended release command (uses `.env` with `PYPI_TOKEN`):
1109
+
1110
+ ```bash
1111
+ scripts/deploy_pypi.sh --tag v1.2.0 --push-tag
1112
+ ```
1113
+
999
1114
  ### 1) Build distributions
1000
1115
 
1001
1116
  ```bash
@@ -12,7 +12,7 @@ authors = [
12
12
  { name = "Vitaee", email = "opensource@vitaee.dev" },
13
13
  ]
14
14
  classifiers = [
15
- "Development Status :: 3 - Alpha",
15
+ "Development Status :: 5 - Production/Stable",
16
16
  "Intended Audience :: Developers",
17
17
  "Operating System :: OS Independent",
18
18
  "Programming Language :: Python :: 3",
@@ -65,6 +65,12 @@ otel-httpx = [
65
65
  otel-requests = [
66
66
  "opentelemetry-instrumentation-requests>=0.60b1",
67
67
  ]
68
+ audit = [
69
+ "cryptography>=46.0.5",
70
+ ]
71
+ otel-sqlalchemy = [
72
+ "opentelemetry-instrumentation-sqlalchemy>=0.60b1",
73
+ ]
68
74
  all = [
69
75
  "orjson>=3.11.7",
70
76
  "prometheus-client>=0.24.1",
@@ -76,6 +82,8 @@ all = [
76
82
  "opentelemetry-instrumentation-logging>=0.60b1",
77
83
  "opentelemetry-instrumentation-httpx>=0.60b1",
78
84
  "opentelemetry-instrumentation-requests>=0.60b1",
85
+ "opentelemetry-instrumentation-sqlalchemy>=0.60b1",
86
+ "cryptography>=46.0.5",
79
87
  ]
80
88
  dev = [
81
89
  "httpx>=0.28.1",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-observer
3
- Version: 0.4.1
3
+ Version: 1.2.0
4
4
  Summary: Zero-glue FastAPI observability with security presets and runtime controls
5
5
  Author-email: Vitaee <opensource@vitaee.dev>
6
6
  License-Expression: MIT
@@ -10,7 +10,7 @@ Project-URL: Repository, https://github.com/Vitaee/FastapiObserver.git
10
10
  Project-URL: Issues, https://github.com/Vitaee/FastapiObserver/issues
11
11
  Project-URL: Funding, https://buymeacoffee.com/FYbPCSu
12
12
  Keywords: fastapi,observability,logging,metrics,opentelemetry
13
- Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Development Status :: 5 - Production/Stable
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: Operating System :: OS Independent
16
16
  Classifier: Programming Language :: Python :: 3
@@ -45,6 +45,10 @@ Provides-Extra: otel-httpx
45
45
  Requires-Dist: opentelemetry-instrumentation-httpx>=0.60b1; extra == "otel-httpx"
46
46
  Provides-Extra: otel-requests
47
47
  Requires-Dist: opentelemetry-instrumentation-requests>=0.60b1; extra == "otel-requests"
48
+ Provides-Extra: audit
49
+ Requires-Dist: cryptography>=46.0.5; extra == "audit"
50
+ Provides-Extra: otel-sqlalchemy
51
+ Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.60b1; extra == "otel-sqlalchemy"
48
52
  Provides-Extra: all
49
53
  Requires-Dist: orjson>=3.11.7; extra == "all"
50
54
  Requires-Dist: prometheus-client>=0.24.1; extra == "all"
@@ -56,6 +60,8 @@ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.60b1; extra == "all"
56
60
  Requires-Dist: opentelemetry-instrumentation-logging>=0.60b1; extra == "all"
57
61
  Requires-Dist: opentelemetry-instrumentation-httpx>=0.60b1; extra == "all"
58
62
  Requires-Dist: opentelemetry-instrumentation-requests>=0.60b1; extra == "all"
63
+ Requires-Dist: opentelemetry-instrumentation-sqlalchemy>=0.60b1; extra == "all"
64
+ Requires-Dist: cryptography>=46.0.5; extra == "all"
59
65
  Provides-Extra: dev
60
66
  Requires-Dist: httpx>=0.28.1; extra == "dev"
61
67
  Requires-Dist: loguru>=0.7.2; extra == "dev"
@@ -645,6 +651,8 @@ The `examples/` directory contains runnable demos:
645
651
  | [`security_presets_app.py`](examples/security_presets_app.py) | Preset-based security policy |
646
652
  | [`allowlist_app.py`](examples/allowlist_app.py) | Allowlist-only sanitization |
647
653
  | [`otel_app.py`](examples/otel_app.py) | OTel tracing and resource attributes |
654
+ | [`audit_app.py`](examples/audit_app.py) | Tamper-evident cryptographic log signatures |
655
+ | [`db_tracing_app.py`](examples/db_tracing_app.py) | SQLCommenter and database trace injection |
648
656
  | [`graphql_app.py`](examples/graphql_app.py) | Native Strawberry GraphQL observability |
649
657
  | [`benchmarks/`](examples/benchmarks/) | Baseline vs observer benchmark harness |
650
658
  | [`k8s/`](examples/k8s/) | Kubernetes-native stack with Prometheus + Loki + Tempo + Grafana |
@@ -776,6 +784,111 @@ Notes:
776
784
  > [!TIP]
777
785
  > The Logtail Dead Letter Queue (DLQ) provides best-effort local durability. If the internal memory queue overflows under immense API pressure (`queue.Full`), or if an external network partition completely exhausts the outbound HTTP retry backoff, the dropped log payloads are immediately salvaged into local NDJSON envelopes. You can replay these files to BetterStack later using the provided `scripts/replay_dlq.py` utility.
778
786
 
787
+ ### Tamper-evident audit logging
788
+
789
+ For regulated industries (Fintech, Healthcare, SOC 2) where you must prove logs were not altered, deleted, or reordered:
790
+
791
+ ```bash
792
+ pip install "fastapi-observer[audit]"
793
+ export OBS_AUDIT_SECRET_KEY="your-signing-secret"
794
+ export OBS_AUDIT_LOGGING_ENABLED="true"
795
+ ```
796
+
797
+ ```python
798
+ install_observability(app, settings)
799
+ # Every JSON log now contains _audit_seq and _audit_sig fields
800
+ ```
801
+
802
+ Each log record is chained via HMAC-SHA256: record B's signature includes the signature of record A. Breaking any link (tamper, delete, reorder) invalidates the chain.
803
+
804
+ | Variable | Default | Description |
805
+ |---|---|---|
806
+ | `OBS_AUDIT_LOGGING_ENABLED` | `false` | Enable HMAC-SHA256 hash chain |
807
+ | `OBS_AUDIT_KEY_ENV_VAR` | `OBS_AUDIT_SECRET_KEY` | Name of env var containing the signing key |
808
+ | `OBS_AUDIT_SECRET_KEY` | - | The HMAC signing key (read by `LocalHMACProvider`) |
809
+
810
+ Custom key provider (e.g. KMS / Vault):
811
+
812
+ ```python
813
+ from fastapiobserver import AuditKeyProvider
814
+
815
+ class VaultKeyProvider:
816
+ def get_key(self) -> bytes:
817
+ return vault_client.get_secret("audit-signing-key").encode()
818
+
819
+ install_observability(app, settings, audit_key_provider=VaultKeyProvider())
820
+ ```
821
+
822
+ Verify logs with the CLI:
823
+
824
+ ```bash
825
+ export OBS_AUDIT_SECRET_KEY="your-signing-secret"
826
+ python scripts/verify_audit_chain.py exported_logs.ndjson
827
+ # PASS — 1042 records verified, chain intact.
828
+ ```
829
+
830
+ ### SQLCommenter & database tracing
831
+
832
+ Bridges the gap between FastAPI application traces and database performance monitoring. When enabled, the `trace_id` is automatically injected into raw SQL queries as a comment:
833
+
834
+ ```sql
835
+ SELECT * FROM users /*traceparent='00-abc123def456-01',route='/api/users'*/
836
+ ```
837
+
838
+ This lets DBAs correlate slow Postgres/MySQL queries directly back to the originating HTTP request.
839
+
840
+ ```bash
841
+ pip install "fastapi-observer[otel-sqlalchemy]"
842
+ ```
843
+
844
+ **Automatic** (via `install_observability`):
845
+
846
+ ```python
847
+ from sqlalchemy import create_engine
848
+
849
+ engine = create_engine("postgresql://...")
850
+ install_observability(app, settings, otel_settings=otel_settings, db_engine=engine)
851
+ ```
852
+
853
+ Multiple engines (e.g. read/write replicas):
854
+
855
+ ```python
856
+ write_engine = create_engine("postgresql://primary/...")
857
+ read_engine = create_engine("postgresql://replica/...")
858
+ install_observability(
859
+ app, settings,
860
+ otel_settings=otel_settings,
861
+ db_engine=[write_engine, read_engine],
862
+ db_commenter_options={"opentelemetry_values": True, "route": False},
863
+ )
864
+ ```
865
+
866
+ **Manual** (standalone):
867
+
868
+ ```python
869
+ from fastapiobserver import instrument_sqlalchemy, instrument_sqlalchemy_async
870
+
871
+ # Sync engine
872
+ instrument_sqlalchemy(engine)
873
+
874
+ # Async engine (extracts .sync_engine automatically)
875
+ instrument_sqlalchemy_async(async_engine)
876
+ ```
877
+
878
+ Custom commenter options:
879
+
880
+ ```python
881
+ instrument_sqlalchemy(engine, commenter_options={
882
+ "opentelemetry_values": True, # traceparent (default: True)
883
+ "db_driver": True, # e.g. psycopg2 (default: True)
884
+ "route": True, # e.g. /api/users (default: True)
885
+ "db_framework": True, # e.g. sqlalchemy (default: False)
886
+ })
887
+ ```
888
+
889
+ > [!CAUTION]
890
+ > **Database statement PII risk:** The OpenTelemetry SQLAlchemy instrumentor captures raw SQL as the `db.statement` span attribute and exports it directly to your tracing backend (Jaeger, Tempo, Datadog). These span attributes are **not** scrubbed by `fastapi-observer`'s `SecurityPolicy`. If your application has poorly parameterized queries (e.g. `WHERE email = 'user@example.com'`), PII will leak into your trace storage. Always use parameterized queries and review your `db.statement` exports in production.
891
+
779
892
  ---
780
893
 
781
894
  ## Advanced Operations
@@ -1053,10 +1166,12 @@ Reproducible benchmark harness and methodology:
1053
1166
 
1054
1167
  - `0.1.x`: secure-by-default core
1055
1168
  - `0.2.x`: OTel interoperability, security presets, allowlists
1056
- - `0.3.x`: package modularization, sink/metrics hardening, and performance reliability updates
1057
- - `1.0.0`: dynamic runtime controls and plugin stability
1169
+ - `0.3.x`: GraphQL observability, error fingerprinting, and Logtail DLQ durability
1170
+ - `0.4.x`: package modularization, sink/registry hardening, and runtime control token rotation
1171
+ - `1.0.x`: first stable release contract for production deployments
1172
+ - `1.2.0`: tamper-evident audit logging and SQLAlchemy trace/commenter integration
1058
1173
 
1059
- Current release version: `0.4.1`
1174
+ Current release version: `1.2.0`
1060
1175
 
1061
1176
  ## Changelog Policy
1062
1177
 
@@ -1066,6 +1181,12 @@ Breaking changes must be listed under a `Breaking Changes` section in `CHANGELOG
1066
1181
 
1067
1182
  ## Packaging and Publishing (Maintainers)
1068
1183
 
1184
+ Recommended release command (uses `.env` with `PYPI_TOKEN`):
1185
+
1186
+ ```bash
1187
+ scripts/deploy_pypi.sh --tag v1.2.0 --push-tag
1188
+ ```
1189
+
1069
1190
  ### 1) Build distributions
1070
1191
 
1071
1192
  ```bash
@@ -10,6 +10,7 @@ src/fastapiobserver/__init__.py
10
10
  src/fastapiobserver/_version.py
11
11
  src/fastapiobserver/config.py
12
12
  src/fastapiobserver/control_plane.py
13
+ src/fastapiobserver/db_tracing.py
13
14
  src/fastapiobserver/fastapi.py
14
15
  src/fastapiobserver/loguru.py
15
16
  src/fastapiobserver/plugins.py
@@ -17,6 +18,10 @@ src/fastapiobserver/propagation.py
17
18
  src/fastapiobserver/py.typed
18
19
  src/fastapiobserver/request_context.py
19
20
  src/fastapiobserver/utils.py
21
+ src/fastapiobserver/audit/__init__.py
22
+ src/fastapiobserver/audit/formatter.py
23
+ src/fastapiobserver/audit/providers.py
24
+ src/fastapiobserver/audit/verify.py
20
25
  src/fastapiobserver/integrations/__init__.py
21
26
  src/fastapiobserver/integrations/strawberry.py
22
27
  src/fastapiobserver/logging/__init__.py
@@ -72,8 +77,10 @@ src/fastapiobserver/sinks/logtail/__init__.py
72
77
  src/fastapiobserver/sinks/logtail/dlq.py
73
78
  src/fastapiobserver/sinks/logtail/handler.py
74
79
  src/fastapiobserver/sinks/logtail/sink.py
80
+ tests/test_audit_chain.py
75
81
  tests/test_body_media_allowlist.py
76
82
  tests/test_config_settings.py
83
+ tests/test_db_tracing.py
77
84
  tests/test_dx_parity.py
78
85
  tests/test_excluded_url_precedence.py
79
86
  tests/test_fastapi_install.py
@@ -13,6 +13,11 @@ opentelemetry-instrumentation-fastapi>=0.60b1
13
13
  opentelemetry-instrumentation-logging>=0.60b1
14
14
  opentelemetry-instrumentation-httpx>=0.60b1
15
15
  opentelemetry-instrumentation-requests>=0.60b1
16
+ opentelemetry-instrumentation-sqlalchemy>=0.60b1
17
+ cryptography>=46.0.5
18
+
19
+ [audit]
20
+ cryptography>=46.0.5
16
21
 
17
22
  [dev]
18
23
  httpx>=0.28.1
@@ -44,5 +49,8 @@ opentelemetry-instrumentation-httpx>=0.60b1
44
49
  [otel-requests]
45
50
  opentelemetry-instrumentation-requests>=0.60b1
46
51
 
52
+ [otel-sqlalchemy]
53
+ opentelemetry-instrumentation-sqlalchemy>=0.60b1
54
+
47
55
  [prometheus]
48
56
  prometheus-client>=0.24.1
@@ -1,6 +1,18 @@
1
1
  from ._version import __version__
2
+ from .audit import (
3
+ AuditChainFormatter,
4
+ AuditKeyProvider,
5
+ AuditVerificationResult,
6
+ LocalHMACProvider,
7
+ verify_audit_chain,
8
+ )
2
9
  from .config import ObservabilitySettings
3
10
  from .control_plane import RuntimeControlSettings, mount_control_plane
11
+ from .db_tracing import (
12
+ instrument_sqlalchemy,
13
+ instrument_sqlalchemy_async,
14
+ uninstrument_sqlalchemy,
15
+ )
4
16
  from .fastapi import install_observability
5
17
  from .logging import (
6
18
  LOG_SCHEMA_VERSION,
@@ -165,4 +177,14 @@ __all__ = [
165
177
  "set_user_context",
166
178
  # Version
167
179
  "__version__",
180
+ # Audit
181
+ "AuditChainFormatter",
182
+ "AuditKeyProvider",
183
+ "AuditVerificationResult",
184
+ "LocalHMACProvider",
185
+ "verify_audit_chain",
186
+ # Database tracing
187
+ "instrument_sqlalchemy",
188
+ "instrument_sqlalchemy_async",
189
+ "uninstrument_sqlalchemy",
168
190
  ]
@@ -0,0 +1 @@
1
+ __version__ = "1.2.0"
@@ -0,0 +1,14 @@
1
+ """Tamper-evident audit logging — optional HMAC-SHA256 hash chain."""
2
+ from __future__ import annotations
3
+
4
+ from .formatter import AuditChainFormatter
5
+ from .providers import AuditKeyProvider, LocalHMACProvider
6
+ from .verify import AuditVerificationResult, verify_audit_chain
7
+
8
+ __all__ = [
9
+ "AuditChainFormatter",
10
+ "AuditKeyProvider",
11
+ "AuditVerificationResult",
12
+ "LocalHMACProvider",
13
+ "verify_audit_chain",
14
+ ]