agent-firewall-security 2.3.0__tar.gz → 2.4.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 (216) hide show
  1. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/PKG-INFO +136 -5
  2. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/README.md +135 -4
  3. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/agent_firewall_security.egg-info/PKG-INFO +136 -5
  4. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/agent_firewall_security.egg-info/SOURCES.txt +22 -1
  5. agent_firewall_security-2.4.0/firewall/a2a/__init__.py +34 -0
  6. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/a2a/auth.py +81 -4
  7. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/adapters/anthropic.py +57 -46
  8. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/adapters/generic.py +60 -46
  9. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/adapters/openai.py +57 -46
  10. agent_firewall_security-2.4.0/firewall/aegis/__init__.py +209 -0
  11. agent_firewall_security-2.4.0/firewall/aegis/blast.py +450 -0
  12. agent_firewall_security-2.4.0/firewall/aegis/controller.py +1177 -0
  13. agent_firewall_security-2.4.0/firewall/aegis/decay.py +267 -0
  14. agent_firewall_security-2.4.0/firewall/aegis/envelope.py +979 -0
  15. agent_firewall_security-2.4.0/firewall/aegis/explain.py +451 -0
  16. agent_firewall_security-2.4.0/firewall/aegis/preflight.py +614 -0
  17. agent_firewall_security-2.4.0/firewall/aegis/response.py +557 -0
  18. agent_firewall_security-2.4.0/firewall/aegis/restriction.py +523 -0
  19. agent_firewall_security-2.4.0/firewall/aegis/state.py +384 -0
  20. agent_firewall_security-2.4.0/firewall/attenuation.py +134 -0
  21. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/authorization.py +22 -1
  22. agent_firewall_security-2.4.0/firewall/benchmarks.py +1191 -0
  23. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/cli_v21.py +20 -4
  24. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/delegation.py +14 -0
  25. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/invariants/__init__.py +14 -2
  26. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/invariants/__main__.py +16 -12
  27. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/invariants/exercise.py +144 -14
  28. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/invariants/registry.py +74 -9
  29. agent_firewall_security-2.4.0/firewall/invariants/runtime.py +2683 -0
  30. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/invariants/source.py +1 -1
  31. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/sdk.py +394 -1
  32. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/introspect.py +43 -0
  33. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/pyproject.toml +1 -1
  34. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_2_invariants.py +36 -19
  35. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_3_invariant_gate.py +150 -18
  36. agent_firewall_security-2.4.0/tests/test_v2_4_aegis_adversarial.py +1468 -0
  37. agent_firewall_security-2.4.0/tests/test_v2_4_aegis_concurrency.py +1155 -0
  38. agent_firewall_security-2.4.0/tests/test_v2_4_aegis_controller.py +1450 -0
  39. agent_firewall_security-2.4.0/tests/test_v2_4_aegis_corrections.py +477 -0
  40. agent_firewall_security-2.4.0/tests/test_v2_4_aegis_fuzz.py +949 -0
  41. agent_firewall_security-2.4.0/tests/test_v2_4_aegis_gate.py +504 -0
  42. agent_firewall_security-2.4.0/tests/test_v2_4_aegis_state.py +633 -0
  43. agent_firewall_security-2.4.0/tests/test_v2_4_attenuation_narrowing.py +369 -0
  44. agent_firewall_security-2.4.0/tests/test_v2_4_benchmarks.py +337 -0
  45. agent_firewall_security-2.4.0/tests/test_v2_4_envelope_soundness.py +154 -0
  46. agent_firewall_security-2.4.0/tests/test_v2_4_integration_boundary.py +979 -0
  47. agent_firewall_security-2.3.0/firewall/a2a/__init__.py +0 -21
  48. agent_firewall_security-2.3.0/firewall/attenuation.py +0 -159
  49. agent_firewall_security-2.3.0/firewall/benchmarks.py +0 -295
  50. agent_firewall_security-2.3.0/firewall/invariants/runtime.py +0 -1173
  51. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/agent_firewall_security.egg-info/dependency_links.txt +0 -0
  52. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/agent_firewall_security.egg-info/entry_points.txt +0 -0
  53. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/agent_firewall_security.egg-info/requires.txt +0 -0
  54. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/agent_firewall_security.egg-info/top_level.txt +0 -0
  55. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/__init__.py +0 -0
  56. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/adapters/__init__.py +0 -0
  57. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/adapters/normalize.py +0 -0
  58. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/adversarial/__init__.py +0 -0
  59. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/agents/__init__.py +0 -0
  60. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/agents/adapters.py +0 -0
  61. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/agents/base.py +0 -0
  62. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/artifact/__init__.py +0 -0
  63. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/artifact/reader.py +0 -0
  64. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/artifact/writer.py +0 -0
  65. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/attackgraph/__init__.py +0 -0
  66. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/attackgraph/engine.py +0 -0
  67. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/attest/__init__.py +0 -0
  68. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/attest/authority.py +0 -0
  69. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/capability.py +0 -0
  70. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/capability2/__init__.py +0 -0
  71. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/capability2/constraints.py +0 -0
  72. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/cli.py +0 -0
  73. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/cli_v19.py +0 -0
  74. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/cli_v20.py +0 -0
  75. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/containment/__init__.py +0 -0
  76. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/containment/controller.py +0 -0
  77. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/continuous_auth/__init__.py +0 -0
  78. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/continuous_auth/engine.py +0 -0
  79. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/continuous_auth/monitor.py +0 -0
  80. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/continuous_auth/predicates.py +0 -0
  81. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/deception/__init__.py +0 -0
  82. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/defense/__init__.py +0 -0
  83. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/defense/mesh.py +0 -0
  84. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/delegation_budget.py +0 -0
  85. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/delegation_lineage.py +0 -0
  86. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/delegation_store.py +0 -0
  87. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/engine.py +0 -0
  88. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/evidence.py +0 -0
  89. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/evidence_graph/__init__.py +0 -0
  90. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/evidence_graph/graph.py +0 -0
  91. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/evidence_integrity/__init__.py +0 -0
  92. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/explain.py +0 -0
  93. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/http.py +0 -0
  94. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ident/__init__.py +0 -0
  95. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ident/registry.py +0 -0
  96. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/identity.py +0 -0
  97. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/immune/__init__.py +0 -0
  98. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/immune/engine.py +0 -0
  99. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/incident/__init__.py +0 -0
  100. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/incident/package.py +0 -0
  101. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/intel/__init__.py +0 -0
  102. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/intel/engine.py +0 -0
  103. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/invariants/model.py +0 -0
  104. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/invariants/static.py +0 -0
  105. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/key_management.py +0 -0
  106. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/key_store.py +0 -0
  107. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/lab/__init__.py +0 -0
  108. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/lab/engine.py +0 -0
  109. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/lifecycle.py +0 -0
  110. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/lifecycle_store.py +0 -0
  111. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/mcp.py +0 -0
  112. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/namespace.py +0 -0
  113. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/network/__init__.py +0 -0
  114. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/network/attack_path.py +0 -0
  115. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/network/behavior.py +0 -0
  116. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/network/correlation.py +0 -0
  117. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/network/graph.py +0 -0
  118. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/network/model.py +0 -0
  119. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/network/response.py +0 -0
  120. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/network/simulator.py +0 -0
  121. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/network/state.py +0 -0
  122. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/north_star.py +0 -0
  123. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/passport/__init__.py +0 -0
  124. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/passport/builder.py +0 -0
  125. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/platform/__init__.py +0 -0
  126. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/platform/provenance.py +0 -0
  127. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/policy.py +0 -0
  128. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/policy_analysis/__init__.py +0 -0
  129. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/posture/__init__.py +0 -0
  130. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/posture/engine.py +0 -0
  131. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/protect.py +0 -0
  132. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/provenance/__init__.py +0 -0
  133. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/provenance/registry.py +0 -0
  134. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/recorder/__init__.py +0 -0
  135. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/recorder/checkpoint.py +0 -0
  136. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/recorder/encoding.py +0 -0
  137. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/recorder/events.py +0 -0
  138. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/recorder/identity.py +0 -0
  139. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/recorder/recorder.py +0 -0
  140. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/recorder/redact.py +0 -0
  141. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/refusal_state.py +0 -0
  142. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/replay.py +0 -0
  143. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/replay_store.py +0 -0
  144. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/replaylab/__init__.py +0 -0
  145. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/replaylab/laboratory.py +0 -0
  146. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/research/__init__.py +0 -0
  147. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/research/lab.py +0 -0
  148. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/response2/__init__.py +0 -0
  149. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/response2/adaptive.py +0 -0
  150. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/revocation.py +0 -0
  151. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/revocation_store.py +0 -0
  152. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/risk_context.py +0 -0
  153. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/security_context.py +0 -0
  154. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/security_decision.py +0 -0
  155. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/security_memory/__init__.py +0 -0
  156. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/semantic_chain.py +0 -0
  157. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/simulation/__init__.py +0 -0
  158. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/simulation/case.py +0 -0
  159. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/simulation/recorder.py +0 -0
  160. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/simulation/replay.py +0 -0
  161. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/simulation/report.py +0 -0
  162. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/simulation/rollout.py +0 -0
  163. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/simulation/ruleset.py +0 -0
  164. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/task/__init__.py +0 -0
  165. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/task/registry.py +0 -0
  166. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/timeline/__init__.py +0 -0
  167. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/timeline/graph.py +0 -0
  168. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/timeline/timeline.py +0 -0
  169. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/timeline/trajectory.py +0 -0
  170. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/tools.py +0 -0
  171. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/transport.py +0 -0
  172. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/trust/__init__.py +0 -0
  173. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/trust/graph.py +0 -0
  174. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/twin/__init__.py +0 -0
  175. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/twin/adversarial.py +0 -0
  176. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/twin/twin.py +0 -0
  177. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/__init__.py +0 -0
  178. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/__main__.py +0 -0
  179. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/control.py +0 -0
  180. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/demo.py +0 -0
  181. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/server.py +0 -0
  182. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/service.py +0 -0
  183. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/console.css +0 -0
  184. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/console.js +0 -0
  185. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/control.js +0 -0
  186. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/index.html +0 -0
  187. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/recorder.css +0 -0
  188. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/recorder.js +0 -0
  189. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/soc.css +0 -0
  190. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/soc.js +0 -0
  191. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/v20.css +0 -0
  192. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/v20.js +0 -0
  193. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/v21.css +0 -0
  194. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/static/v21.js +0 -0
  195. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/v18.py +0 -0
  196. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/v19.py +0 -0
  197. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/v20.py +0 -0
  198. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/ui/v21.py +0 -0
  199. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/verify/__init__.py +0 -0
  200. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/firewall/verify/verifier.py +0 -0
  201. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/setup.cfg +0 -0
  202. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_continuous_auth.py +0 -0
  203. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_engine.py +0 -0
  204. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_sdk_continuous_auth.py +0 -0
  205. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_security_decision.py +0 -0
  206. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_2_adversarial_defense.py +0 -0
  207. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_2_adversarial_twin.py +0 -0
  208. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_2_capability_delegation.py +0 -0
  209. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_2_deception_integrity.py +0 -0
  210. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_2_evidence_integrity.py +0 -0
  211. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_2_platform_provenance.py +0 -0
  212. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_2_security_memory.py +0 -0
  213. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_3_duplicate_concepts.py +0 -0
  214. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_3_intel_coordination.py +0 -0
  215. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_3_policy_analysis.py +0 -0
  216. {agent_firewall_security-2.3.0 → agent_firewall_security-2.4.0}/tests/test_v2_3_self_attack.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-firewall-security
3
- Version: 2.3.0
3
+ Version: 2.4.0
4
4
  Summary: Security and canonical authorization infrastructure for AI agents and automated tool use.
5
5
  Project-URL: Homepage, https://github.com/Shubhbhangoo/agent-firewall
6
6
  Project-URL: Repository, https://github.com/Shubhbhangoo/agent-firewall
@@ -28,6 +28,8 @@ Requires-Dist: hypothesis>=6.0; extra == "dev"
28
28
 
29
29
  Agent Firewall is built around one security boundary: **authorization remains deterministic, explicit, and fail-closed**. Identity, provenance, monitoring, behavioral analysis, simulation, evidence, and response provide security context around that boundary, but they do not become an alternative path to authorization.
30
30
 
31
+ > **v2.4** adds **Aegis**, an adaptive authority control plane: a live grant can be narrowed, suspended, revalidated or revoked while a task is running. It adds no second authorization path — Aegis reaches `FirewallSDK.authorize()` through one gate that can only deny or abstain, and learns what happened through one callback the SDK invokes *after* the decision exists.
32
+ >
31
33
  > **v2.3** is a correctness release. It adds no subsystem and no authorization path: the work was to attack v2.2's shipped behaviour, fix the three fail-open paths that broke, stop analytical output from reading as verified when it was not, and make the strict invariant gate something CI can actually fail on.
32
34
  >
33
35
  > **v2.2** makes the control plane adaptive: authority is re-evaluated when the state it rested on changes, contradictions between independent claim sources are reported rather than resolved, and the architectural properties the design rests on are checked by code instead of asserted in prose.
@@ -92,6 +94,96 @@ When required evidence is unavailable, verification fails, identity is unknown,
92
94
 
93
95
  ---
94
96
 
97
+ ## What v2.4 adds
98
+
99
+ v2.2 made the platform adaptive *above* the boundary: when watched state
100
+ changed, a decision was re-run. v2.4 makes **authority itself** adaptive. A
101
+ grant that is already in use can be narrowed, suspended, revalidated or
102
+ revoked, and the change is enforced on the next authorization — and, for
103
+ suspension, inside the commit transaction of one already in flight.
104
+
105
+ Aegis is off by default. `FirewallSDK(aegis_enabled=True)` opts in; with no
106
+ controller attached the adaptive gate abstains and v2.3 behaviour is exact.
107
+
108
+ ### One deny-only seam
109
+
110
+ Nine modules, 5,382 lines, none of which imports `firewall.sdk`. Everything
111
+ Aegis does reaches the outside world through two points: `_gate_aegis`, the
112
+ ninth of eleven gates, which can only deny or abstain; and
113
+ `observe_authorization`, which the SDK calls *after* a decision exists.
114
+ Because the callback runs after, no Aegis state can be a precondition of the
115
+ allow it observes. Authority flows from the boundary into Aegis and never the
116
+ other way.
117
+
118
+ ```text
119
+ change -> classify -> KEEP | REVALIDATE | NARROW | SUSPEND | REVOKE
120
+ |
121
+ v
122
+ restriction written
123
+ |
124
+ v
125
+ FirewallSDK.authorize() -> _gate_aegis -> DENY
126
+ ```
127
+
128
+ There is no arrow from Aegis to ALLOW. That absence is the design.
129
+
130
+ ### The authority envelope
131
+
132
+ An `AuthorityEnvelope` is a bound on what a capability may still do, folded
133
+ across its delegation chain by a per-dimension greatest-lower-bound. Twelve
134
+ fields — patterns, tool, time window, constraint bounds, depth, its ceiling,
135
+ issuers, issuer trust, revocation, budget, chain membership, and a bottom
136
+ marker — and every dimension that bounds a request has a named enforcement
137
+ site at the boundary. A dimension with no enforcement site would be
138
+ decoration.
139
+
140
+ The theorem is one-directional and stated that way: if the envelope
141
+ **excludes** a request, the boundary denies it. The converse does not hold,
142
+ and the API is named so that misuse reads wrong — `excludes()` returns a
143
+ reason, `may_admit()` means "this envelope does not itself refuse", and
144
+ `__bool__` **raises** on an envelope, a grant, a preflight, a blast radius
145
+ and a classification, so `if preflight(...)` is an error rather than an
146
+ accidental allow.
147
+
148
+ ### Seven states ordered by residual authority
149
+
150
+ `ISSUED`, `ACTIVE`, `REVALIDATING`, `NARROWED`, `SUSPENDED`, `REVOKED`,
151
+ `EXPIRED`. A transition is legal only if it does not increase residual
152
+ authority. `REVALIDATING -> ACTIVE` is the only edge that restores authority,
153
+ and it requires an `AuthorizationResult` that is allowed, reasoned
154
+ `authorized`, and traced to that capability's fingerprint. `REVOKED` and
155
+ `EXPIRED` are terminal and checked before the ordering rule, so no evidence
156
+ or clock change produces an edge out of either.
157
+
158
+ The state machine is a record and a legality check. It is deliberately **not**
159
+ an enforcement channel: the gate reads restrictions, not states, because
160
+ wiring the state model into the gate would make the authorization path depend
161
+ on a structure whose own updates require an authorization result.
162
+
163
+ ### Unknown never becomes safe
164
+
165
+ An unrecognised trigger is `REVALIDATE`, not `KEEP` (which would make an
166
+ unknown event benign) and not `REVOKE` (which would make any unknown string a
167
+ denial-of-service lever). Nothing maps to `KEEP` at all — it is reachable
168
+ only by establishing five positive conditions, so "nothing changed" must be
169
+ shown rather than assumed. An unreadable budget is exhausted, not unlimited;
170
+ an unreadable restriction matches; unestablished issuer trust is `None`, not
171
+ `True`; an unresolvable chain yields the bottom envelope; a traversal that
172
+ exceeds its bounds is `UNANALYZABLE` rather than a partial answer presented
173
+ as complete. `UNKNOWN_NON_AUTHORIZATION` checks these exhaustively.
174
+
175
+ ### What it does not claim
176
+
177
+ Envelope soundness runs in one direction. `canonical_allow_for` is a
178
+ structural check, not a cryptographic one — it bounds mistakes, not an
179
+ adversary already inside the process. The commit-time re-read covers
180
+ suspension only. The restriction cap trades availability for integrity:
181
+ sixteen narrowings drive a grant to `SUSPEND`, which is fail-closed and still
182
+ a lever. §16 of [`docs/v2.4-aegis.md`](docs/v2.4-aegis.md) is the full list,
183
+ and §17 maps each guarantee to the test file that establishes it.
184
+
185
+ ---
186
+
95
187
  ## What v2.3 changes
96
188
 
97
189
  v2.3 adds no subsystem. Three requests that v2.2 allowed are now denied,
@@ -137,9 +229,9 @@ section, so deleting one fails rather than quietly shrinking the suite. See
137
229
  ### A strict invariant gate that can pass
138
230
 
139
231
  `python -m firewall.invariants --strict` exited 2 on every invocation,
140
- because five of the eleven invariants are claims about live state that a
232
+ because seven of the fifteen invariants are claims about live state that a
141
233
  source-only run never reaches. A gate that always fails is a gate that gets
142
- removed, so those five were effectively ungated in CI.
234
+ removed, so those seven were effectively ungated in CI.
143
235
  `firewall/invariants/exercise.py` builds the canonical estate through the
144
236
  SDK's public API only, and CI now runs the source-only and exercised gates
145
237
  as separate steps. What a green exercised run establishes is bounded to that
@@ -430,7 +522,7 @@ The architecture is designed around explicit security invariants.
430
522
  - **A check that could not run is not a check that passed.**
431
523
  - **Security failures default toward refusal rather than implicit trust.**
432
524
 
433
- These are implementation properties of the system, not a claim that any deployment is universally secure. Eleven such properties are additionally stated once in `firewall.invariants` and checked by code rather than asserted in prose alone; see [`docs/v2.2-invariants.md`](docs/v2.2-invariants.md) for the invariants themselves and [`docs/v2.3-invariant-gate.md`](docs/v2.3-invariant-gate.md) for what a green gate run does and does not establish.
525
+ These are implementation properties of the system, not a claim that any deployment is universally secure. Fifteen such properties are additionally stated once in `firewall.invariants` and checked by code rather than asserted in prose alone; see [`docs/v2.2-invariants.md`](docs/v2.2-invariants.md) for the invariants themselves, [`docs/v2.3-invariant-gate.md`](docs/v2.3-invariant-gate.md) for what a green gate run does and does not establish, and [`docs/v2.4-aegis.md`](docs/v2.4-aegis.md) for the four the authority control plane adds.
434
526
 
435
527
  Where a property does **not** hold, it is stated rather than left to be inferred. A posture change is detected but does not by itself flip a verdict; `retire_key` is not containment for a stolen key, since a retired key's signatures keep verifying so that rotation does not invalidate capabilities in flight; an `amount_max` ceiling is per request, so two siblings each holding one can spend it twice unless a lineage budget is configured; and possession of a trusted signing key is authority, which no cryptography can undo. [`docs/v2.3-self-attack.md`](docs/v2.3-self-attack.md) records each of these against the test that pins it.
436
528
 
@@ -516,9 +608,15 @@ The authorization path evaluates the security conditions required by the capabil
516
608
 
517
609
  ## Command surface
518
610
 
611
+ v2.4 adds no new CLI subcommands. One existing command changes what it
612
+ prints: `firewall delegate-authorize` now labels an allow it reached without
613
+ an attached `sdk_provider` as `ALLOWED (relationship only)` and says not to
614
+ enforce on it. The exit status stays 0 — the question asked was answered
615
+ affirmatively — but the answer no longer overstates itself.
616
+
519
617
  v2.3 adds no new CLI subcommands. It adds one flag to the invariant
520
618
  checker: `python -m firewall.invariants --exercise --strict` builds the
521
- canonical estate so that all eleven invariants can be reached, which makes
619
+ canonical estate so that all fifteen invariants can be reached, which makes
522
620
  `--strict` a gate that can pass and is therefore worth failing.
523
621
 
524
622
  v2.2 adds no new CLI subcommands. Its one new entry point is the invariant
@@ -571,6 +669,35 @@ python -m firewall.benchmarks
571
669
 
572
670
  The repository contains unit, integration, adversarial, hardening, evidence, UI/API, benchmark, and research tests.
573
671
 
672
+ The v2.4 test surface adds 384 tests across eleven files — 4,087 in the suite
673
+ as a whole, on Python 3.10, 3.11 and 3.12 — including stateful security-state
674
+ fuzzing, eight named concurrency races, and an integration-boundary sweep.
675
+ Among the properties covered:
676
+
677
+ - no path from adaptive analysis to an allow, and no Aegis module able to
678
+ construct an `AuthorizationResult`
679
+ - every forbidden transition refused individually: out of `REVOKED`, out of
680
+ `EXPIRED`, `NARROWED` to wider, `SUSPENDED` to `ACTIVE` without a canonical
681
+ allow, and a child exceeding its parent
682
+ - an envelope that excludes a request always accompanied by a boundary that
683
+ denies it
684
+ - no field of the envelope widening under delegation or attenuation
685
+ - a `nan` bound bounding nothing being denied, while an `inf` bound still
686
+ means unbounded
687
+ - a 400-digit integer producing a decision rather than an exception out of
688
+ `authorize()`
689
+ - every authorization-reachable Aegis method total, including against an
690
+ injected hostile controller
691
+ - a restriction written mid-flight being observed, and a suspension being
692
+ caught inside the commit transaction
693
+ - `__bool__` raising on every analysis object, so a truthiness test cannot
694
+ become an allow
695
+ - every integration surface reaching the canonical boundary, with no local
696
+ allow anywhere
697
+ - no dataclass field in the package carrying a default that Python 3.11
698
+ rejects, so a defect that hides on the development interpreter cannot wait
699
+ for CI to find it
700
+
574
701
  The v2.3 test surface adds the thirteen-question self-attack suite, which
575
702
  covers, among other properties:
576
703
 
@@ -697,6 +824,10 @@ See [`SECURITY.md`](SECURITY.md) for the project's security reporting policy.
697
824
 
698
825
  Detailed specifications are maintained in the repository:
699
826
 
827
+ - `docs/v2.4-aegis.md`
828
+ - `docs/v2.4-aegis-design.md`
829
+ - `docs/v2.4-performance.md`
830
+ - `docs/v2.4-migration.md`
700
831
  - `docs/v2.3-security-corrections.md`
701
832
  - `docs/v2.3-self-attack.md`
702
833
  - `docs/v2.3-invariant-gate.md`
@@ -4,6 +4,8 @@
4
4
 
5
5
  Agent Firewall is built around one security boundary: **authorization remains deterministic, explicit, and fail-closed**. Identity, provenance, monitoring, behavioral analysis, simulation, evidence, and response provide security context around that boundary, but they do not become an alternative path to authorization.
6
6
 
7
+ > **v2.4** adds **Aegis**, an adaptive authority control plane: a live grant can be narrowed, suspended, revalidated or revoked while a task is running. It adds no second authorization path — Aegis reaches `FirewallSDK.authorize()` through one gate that can only deny or abstain, and learns what happened through one callback the SDK invokes *after* the decision exists.
8
+ >
7
9
  > **v2.3** is a correctness release. It adds no subsystem and no authorization path: the work was to attack v2.2's shipped behaviour, fix the three fail-open paths that broke, stop analytical output from reading as verified when it was not, and make the strict invariant gate something CI can actually fail on.
8
10
  >
9
11
  > **v2.2** makes the control plane adaptive: authority is re-evaluated when the state it rested on changes, contradictions between independent claim sources are reported rather than resolved, and the architectural properties the design rests on are checked by code instead of asserted in prose.
@@ -68,6 +70,96 @@ When required evidence is unavailable, verification fails, identity is unknown,
68
70
 
69
71
  ---
70
72
 
73
+ ## What v2.4 adds
74
+
75
+ v2.2 made the platform adaptive *above* the boundary: when watched state
76
+ changed, a decision was re-run. v2.4 makes **authority itself** adaptive. A
77
+ grant that is already in use can be narrowed, suspended, revalidated or
78
+ revoked, and the change is enforced on the next authorization — and, for
79
+ suspension, inside the commit transaction of one already in flight.
80
+
81
+ Aegis is off by default. `FirewallSDK(aegis_enabled=True)` opts in; with no
82
+ controller attached the adaptive gate abstains and v2.3 behaviour is exact.
83
+
84
+ ### One deny-only seam
85
+
86
+ Nine modules, 5,382 lines, none of which imports `firewall.sdk`. Everything
87
+ Aegis does reaches the outside world through two points: `_gate_aegis`, the
88
+ ninth of eleven gates, which can only deny or abstain; and
89
+ `observe_authorization`, which the SDK calls *after* a decision exists.
90
+ Because the callback runs after, no Aegis state can be a precondition of the
91
+ allow it observes. Authority flows from the boundary into Aegis and never the
92
+ other way.
93
+
94
+ ```text
95
+ change -> classify -> KEEP | REVALIDATE | NARROW | SUSPEND | REVOKE
96
+ |
97
+ v
98
+ restriction written
99
+ |
100
+ v
101
+ FirewallSDK.authorize() -> _gate_aegis -> DENY
102
+ ```
103
+
104
+ There is no arrow from Aegis to ALLOW. That absence is the design.
105
+
106
+ ### The authority envelope
107
+
108
+ An `AuthorityEnvelope` is a bound on what a capability may still do, folded
109
+ across its delegation chain by a per-dimension greatest-lower-bound. Twelve
110
+ fields — patterns, tool, time window, constraint bounds, depth, its ceiling,
111
+ issuers, issuer trust, revocation, budget, chain membership, and a bottom
112
+ marker — and every dimension that bounds a request has a named enforcement
113
+ site at the boundary. A dimension with no enforcement site would be
114
+ decoration.
115
+
116
+ The theorem is one-directional and stated that way: if the envelope
117
+ **excludes** a request, the boundary denies it. The converse does not hold,
118
+ and the API is named so that misuse reads wrong — `excludes()` returns a
119
+ reason, `may_admit()` means "this envelope does not itself refuse", and
120
+ `__bool__` **raises** on an envelope, a grant, a preflight, a blast radius
121
+ and a classification, so `if preflight(...)` is an error rather than an
122
+ accidental allow.
123
+
124
+ ### Seven states ordered by residual authority
125
+
126
+ `ISSUED`, `ACTIVE`, `REVALIDATING`, `NARROWED`, `SUSPENDED`, `REVOKED`,
127
+ `EXPIRED`. A transition is legal only if it does not increase residual
128
+ authority. `REVALIDATING -> ACTIVE` is the only edge that restores authority,
129
+ and it requires an `AuthorizationResult` that is allowed, reasoned
130
+ `authorized`, and traced to that capability's fingerprint. `REVOKED` and
131
+ `EXPIRED` are terminal and checked before the ordering rule, so no evidence
132
+ or clock change produces an edge out of either.
133
+
134
+ The state machine is a record and a legality check. It is deliberately **not**
135
+ an enforcement channel: the gate reads restrictions, not states, because
136
+ wiring the state model into the gate would make the authorization path depend
137
+ on a structure whose own updates require an authorization result.
138
+
139
+ ### Unknown never becomes safe
140
+
141
+ An unrecognised trigger is `REVALIDATE`, not `KEEP` (which would make an
142
+ unknown event benign) and not `REVOKE` (which would make any unknown string a
143
+ denial-of-service lever). Nothing maps to `KEEP` at all — it is reachable
144
+ only by establishing five positive conditions, so "nothing changed" must be
145
+ shown rather than assumed. An unreadable budget is exhausted, not unlimited;
146
+ an unreadable restriction matches; unestablished issuer trust is `None`, not
147
+ `True`; an unresolvable chain yields the bottom envelope; a traversal that
148
+ exceeds its bounds is `UNANALYZABLE` rather than a partial answer presented
149
+ as complete. `UNKNOWN_NON_AUTHORIZATION` checks these exhaustively.
150
+
151
+ ### What it does not claim
152
+
153
+ Envelope soundness runs in one direction. `canonical_allow_for` is a
154
+ structural check, not a cryptographic one — it bounds mistakes, not an
155
+ adversary already inside the process. The commit-time re-read covers
156
+ suspension only. The restriction cap trades availability for integrity:
157
+ sixteen narrowings drive a grant to `SUSPEND`, which is fail-closed and still
158
+ a lever. §16 of [`docs/v2.4-aegis.md`](docs/v2.4-aegis.md) is the full list,
159
+ and §17 maps each guarantee to the test file that establishes it.
160
+
161
+ ---
162
+
71
163
  ## What v2.3 changes
72
164
 
73
165
  v2.3 adds no subsystem. Three requests that v2.2 allowed are now denied,
@@ -113,9 +205,9 @@ section, so deleting one fails rather than quietly shrinking the suite. See
113
205
  ### A strict invariant gate that can pass
114
206
 
115
207
  `python -m firewall.invariants --strict` exited 2 on every invocation,
116
- because five of the eleven invariants are claims about live state that a
208
+ because seven of the fifteen invariants are claims about live state that a
117
209
  source-only run never reaches. A gate that always fails is a gate that gets
118
- removed, so those five were effectively ungated in CI.
210
+ removed, so those seven were effectively ungated in CI.
119
211
  `firewall/invariants/exercise.py` builds the canonical estate through the
120
212
  SDK's public API only, and CI now runs the source-only and exercised gates
121
213
  as separate steps. What a green exercised run establishes is bounded to that
@@ -406,7 +498,7 @@ The architecture is designed around explicit security invariants.
406
498
  - **A check that could not run is not a check that passed.**
407
499
  - **Security failures default toward refusal rather than implicit trust.**
408
500
 
409
- These are implementation properties of the system, not a claim that any deployment is universally secure. Eleven such properties are additionally stated once in `firewall.invariants` and checked by code rather than asserted in prose alone; see [`docs/v2.2-invariants.md`](docs/v2.2-invariants.md) for the invariants themselves and [`docs/v2.3-invariant-gate.md`](docs/v2.3-invariant-gate.md) for what a green gate run does and does not establish.
501
+ These are implementation properties of the system, not a claim that any deployment is universally secure. Fifteen such properties are additionally stated once in `firewall.invariants` and checked by code rather than asserted in prose alone; see [`docs/v2.2-invariants.md`](docs/v2.2-invariants.md) for the invariants themselves, [`docs/v2.3-invariant-gate.md`](docs/v2.3-invariant-gate.md) for what a green gate run does and does not establish, and [`docs/v2.4-aegis.md`](docs/v2.4-aegis.md) for the four the authority control plane adds.
410
502
 
411
503
  Where a property does **not** hold, it is stated rather than left to be inferred. A posture change is detected but does not by itself flip a verdict; `retire_key` is not containment for a stolen key, since a retired key's signatures keep verifying so that rotation does not invalidate capabilities in flight; an `amount_max` ceiling is per request, so two siblings each holding one can spend it twice unless a lineage budget is configured; and possession of a trusted signing key is authority, which no cryptography can undo. [`docs/v2.3-self-attack.md`](docs/v2.3-self-attack.md) records each of these against the test that pins it.
412
504
 
@@ -492,9 +584,15 @@ The authorization path evaluates the security conditions required by the capabil
492
584
 
493
585
  ## Command surface
494
586
 
587
+ v2.4 adds no new CLI subcommands. One existing command changes what it
588
+ prints: `firewall delegate-authorize` now labels an allow it reached without
589
+ an attached `sdk_provider` as `ALLOWED (relationship only)` and says not to
590
+ enforce on it. The exit status stays 0 — the question asked was answered
591
+ affirmatively — but the answer no longer overstates itself.
592
+
495
593
  v2.3 adds no new CLI subcommands. It adds one flag to the invariant
496
594
  checker: `python -m firewall.invariants --exercise --strict` builds the
497
- canonical estate so that all eleven invariants can be reached, which makes
595
+ canonical estate so that all fifteen invariants can be reached, which makes
498
596
  `--strict` a gate that can pass and is therefore worth failing.
499
597
 
500
598
  v2.2 adds no new CLI subcommands. Its one new entry point is the invariant
@@ -547,6 +645,35 @@ python -m firewall.benchmarks
547
645
 
548
646
  The repository contains unit, integration, adversarial, hardening, evidence, UI/API, benchmark, and research tests.
549
647
 
648
+ The v2.4 test surface adds 384 tests across eleven files — 4,087 in the suite
649
+ as a whole, on Python 3.10, 3.11 and 3.12 — including stateful security-state
650
+ fuzzing, eight named concurrency races, and an integration-boundary sweep.
651
+ Among the properties covered:
652
+
653
+ - no path from adaptive analysis to an allow, and no Aegis module able to
654
+ construct an `AuthorizationResult`
655
+ - every forbidden transition refused individually: out of `REVOKED`, out of
656
+ `EXPIRED`, `NARROWED` to wider, `SUSPENDED` to `ACTIVE` without a canonical
657
+ allow, and a child exceeding its parent
658
+ - an envelope that excludes a request always accompanied by a boundary that
659
+ denies it
660
+ - no field of the envelope widening under delegation or attenuation
661
+ - a `nan` bound bounding nothing being denied, while an `inf` bound still
662
+ means unbounded
663
+ - a 400-digit integer producing a decision rather than an exception out of
664
+ `authorize()`
665
+ - every authorization-reachable Aegis method total, including against an
666
+ injected hostile controller
667
+ - a restriction written mid-flight being observed, and a suspension being
668
+ caught inside the commit transaction
669
+ - `__bool__` raising on every analysis object, so a truthiness test cannot
670
+ become an allow
671
+ - every integration surface reaching the canonical boundary, with no local
672
+ allow anywhere
673
+ - no dataclass field in the package carrying a default that Python 3.11
674
+ rejects, so a defect that hides on the development interpreter cannot wait
675
+ for CI to find it
676
+
550
677
  The v2.3 test surface adds the thirteen-question self-attack suite, which
551
678
  covers, among other properties:
552
679
 
@@ -673,6 +800,10 @@ See [`SECURITY.md`](SECURITY.md) for the project's security reporting policy.
673
800
 
674
801
  Detailed specifications are maintained in the repository:
675
802
 
803
+ - `docs/v2.4-aegis.md`
804
+ - `docs/v2.4-aegis-design.md`
805
+ - `docs/v2.4-performance.md`
806
+ - `docs/v2.4-migration.md`
676
807
  - `docs/v2.3-security-corrections.md`
677
808
  - `docs/v2.3-self-attack.md`
678
809
  - `docs/v2.3-invariant-gate.md`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-firewall-security
3
- Version: 2.3.0
3
+ Version: 2.4.0
4
4
  Summary: Security and canonical authorization infrastructure for AI agents and automated tool use.
5
5
  Project-URL: Homepage, https://github.com/Shubhbhangoo/agent-firewall
6
6
  Project-URL: Repository, https://github.com/Shubhbhangoo/agent-firewall
@@ -28,6 +28,8 @@ Requires-Dist: hypothesis>=6.0; extra == "dev"
28
28
 
29
29
  Agent Firewall is built around one security boundary: **authorization remains deterministic, explicit, and fail-closed**. Identity, provenance, monitoring, behavioral analysis, simulation, evidence, and response provide security context around that boundary, but they do not become an alternative path to authorization.
30
30
 
31
+ > **v2.4** adds **Aegis**, an adaptive authority control plane: a live grant can be narrowed, suspended, revalidated or revoked while a task is running. It adds no second authorization path — Aegis reaches `FirewallSDK.authorize()` through one gate that can only deny or abstain, and learns what happened through one callback the SDK invokes *after* the decision exists.
32
+ >
31
33
  > **v2.3** is a correctness release. It adds no subsystem and no authorization path: the work was to attack v2.2's shipped behaviour, fix the three fail-open paths that broke, stop analytical output from reading as verified when it was not, and make the strict invariant gate something CI can actually fail on.
32
34
  >
33
35
  > **v2.2** makes the control plane adaptive: authority is re-evaluated when the state it rested on changes, contradictions between independent claim sources are reported rather than resolved, and the architectural properties the design rests on are checked by code instead of asserted in prose.
@@ -92,6 +94,96 @@ When required evidence is unavailable, verification fails, identity is unknown,
92
94
 
93
95
  ---
94
96
 
97
+ ## What v2.4 adds
98
+
99
+ v2.2 made the platform adaptive *above* the boundary: when watched state
100
+ changed, a decision was re-run. v2.4 makes **authority itself** adaptive. A
101
+ grant that is already in use can be narrowed, suspended, revalidated or
102
+ revoked, and the change is enforced on the next authorization — and, for
103
+ suspension, inside the commit transaction of one already in flight.
104
+
105
+ Aegis is off by default. `FirewallSDK(aegis_enabled=True)` opts in; with no
106
+ controller attached the adaptive gate abstains and v2.3 behaviour is exact.
107
+
108
+ ### One deny-only seam
109
+
110
+ Nine modules, 5,382 lines, none of which imports `firewall.sdk`. Everything
111
+ Aegis does reaches the outside world through two points: `_gate_aegis`, the
112
+ ninth of eleven gates, which can only deny or abstain; and
113
+ `observe_authorization`, which the SDK calls *after* a decision exists.
114
+ Because the callback runs after, no Aegis state can be a precondition of the
115
+ allow it observes. Authority flows from the boundary into Aegis and never the
116
+ other way.
117
+
118
+ ```text
119
+ change -> classify -> KEEP | REVALIDATE | NARROW | SUSPEND | REVOKE
120
+ |
121
+ v
122
+ restriction written
123
+ |
124
+ v
125
+ FirewallSDK.authorize() -> _gate_aegis -> DENY
126
+ ```
127
+
128
+ There is no arrow from Aegis to ALLOW. That absence is the design.
129
+
130
+ ### The authority envelope
131
+
132
+ An `AuthorityEnvelope` is a bound on what a capability may still do, folded
133
+ across its delegation chain by a per-dimension greatest-lower-bound. Twelve
134
+ fields — patterns, tool, time window, constraint bounds, depth, its ceiling,
135
+ issuers, issuer trust, revocation, budget, chain membership, and a bottom
136
+ marker — and every dimension that bounds a request has a named enforcement
137
+ site at the boundary. A dimension with no enforcement site would be
138
+ decoration.
139
+
140
+ The theorem is one-directional and stated that way: if the envelope
141
+ **excludes** a request, the boundary denies it. The converse does not hold,
142
+ and the API is named so that misuse reads wrong — `excludes()` returns a
143
+ reason, `may_admit()` means "this envelope does not itself refuse", and
144
+ `__bool__` **raises** on an envelope, a grant, a preflight, a blast radius
145
+ and a classification, so `if preflight(...)` is an error rather than an
146
+ accidental allow.
147
+
148
+ ### Seven states ordered by residual authority
149
+
150
+ `ISSUED`, `ACTIVE`, `REVALIDATING`, `NARROWED`, `SUSPENDED`, `REVOKED`,
151
+ `EXPIRED`. A transition is legal only if it does not increase residual
152
+ authority. `REVALIDATING -> ACTIVE` is the only edge that restores authority,
153
+ and it requires an `AuthorizationResult` that is allowed, reasoned
154
+ `authorized`, and traced to that capability's fingerprint. `REVOKED` and
155
+ `EXPIRED` are terminal and checked before the ordering rule, so no evidence
156
+ or clock change produces an edge out of either.
157
+
158
+ The state machine is a record and a legality check. It is deliberately **not**
159
+ an enforcement channel: the gate reads restrictions, not states, because
160
+ wiring the state model into the gate would make the authorization path depend
161
+ on a structure whose own updates require an authorization result.
162
+
163
+ ### Unknown never becomes safe
164
+
165
+ An unrecognised trigger is `REVALIDATE`, not `KEEP` (which would make an
166
+ unknown event benign) and not `REVOKE` (which would make any unknown string a
167
+ denial-of-service lever). Nothing maps to `KEEP` at all — it is reachable
168
+ only by establishing five positive conditions, so "nothing changed" must be
169
+ shown rather than assumed. An unreadable budget is exhausted, not unlimited;
170
+ an unreadable restriction matches; unestablished issuer trust is `None`, not
171
+ `True`; an unresolvable chain yields the bottom envelope; a traversal that
172
+ exceeds its bounds is `UNANALYZABLE` rather than a partial answer presented
173
+ as complete. `UNKNOWN_NON_AUTHORIZATION` checks these exhaustively.
174
+
175
+ ### What it does not claim
176
+
177
+ Envelope soundness runs in one direction. `canonical_allow_for` is a
178
+ structural check, not a cryptographic one — it bounds mistakes, not an
179
+ adversary already inside the process. The commit-time re-read covers
180
+ suspension only. The restriction cap trades availability for integrity:
181
+ sixteen narrowings drive a grant to `SUSPEND`, which is fail-closed and still
182
+ a lever. §16 of [`docs/v2.4-aegis.md`](docs/v2.4-aegis.md) is the full list,
183
+ and §17 maps each guarantee to the test file that establishes it.
184
+
185
+ ---
186
+
95
187
  ## What v2.3 changes
96
188
 
97
189
  v2.3 adds no subsystem. Three requests that v2.2 allowed are now denied,
@@ -137,9 +229,9 @@ section, so deleting one fails rather than quietly shrinking the suite. See
137
229
  ### A strict invariant gate that can pass
138
230
 
139
231
  `python -m firewall.invariants --strict` exited 2 on every invocation,
140
- because five of the eleven invariants are claims about live state that a
232
+ because seven of the fifteen invariants are claims about live state that a
141
233
  source-only run never reaches. A gate that always fails is a gate that gets
142
- removed, so those five were effectively ungated in CI.
234
+ removed, so those seven were effectively ungated in CI.
143
235
  `firewall/invariants/exercise.py` builds the canonical estate through the
144
236
  SDK's public API only, and CI now runs the source-only and exercised gates
145
237
  as separate steps. What a green exercised run establishes is bounded to that
@@ -430,7 +522,7 @@ The architecture is designed around explicit security invariants.
430
522
  - **A check that could not run is not a check that passed.**
431
523
  - **Security failures default toward refusal rather than implicit trust.**
432
524
 
433
- These are implementation properties of the system, not a claim that any deployment is universally secure. Eleven such properties are additionally stated once in `firewall.invariants` and checked by code rather than asserted in prose alone; see [`docs/v2.2-invariants.md`](docs/v2.2-invariants.md) for the invariants themselves and [`docs/v2.3-invariant-gate.md`](docs/v2.3-invariant-gate.md) for what a green gate run does and does not establish.
525
+ These are implementation properties of the system, not a claim that any deployment is universally secure. Fifteen such properties are additionally stated once in `firewall.invariants` and checked by code rather than asserted in prose alone; see [`docs/v2.2-invariants.md`](docs/v2.2-invariants.md) for the invariants themselves, [`docs/v2.3-invariant-gate.md`](docs/v2.3-invariant-gate.md) for what a green gate run does and does not establish, and [`docs/v2.4-aegis.md`](docs/v2.4-aegis.md) for the four the authority control plane adds.
434
526
 
435
527
  Where a property does **not** hold, it is stated rather than left to be inferred. A posture change is detected but does not by itself flip a verdict; `retire_key` is not containment for a stolen key, since a retired key's signatures keep verifying so that rotation does not invalidate capabilities in flight; an `amount_max` ceiling is per request, so two siblings each holding one can spend it twice unless a lineage budget is configured; and possession of a trusted signing key is authority, which no cryptography can undo. [`docs/v2.3-self-attack.md`](docs/v2.3-self-attack.md) records each of these against the test that pins it.
436
528
 
@@ -516,9 +608,15 @@ The authorization path evaluates the security conditions required by the capabil
516
608
 
517
609
  ## Command surface
518
610
 
611
+ v2.4 adds no new CLI subcommands. One existing command changes what it
612
+ prints: `firewall delegate-authorize` now labels an allow it reached without
613
+ an attached `sdk_provider` as `ALLOWED (relationship only)` and says not to
614
+ enforce on it. The exit status stays 0 — the question asked was answered
615
+ affirmatively — but the answer no longer overstates itself.
616
+
519
617
  v2.3 adds no new CLI subcommands. It adds one flag to the invariant
520
618
  checker: `python -m firewall.invariants --exercise --strict` builds the
521
- canonical estate so that all eleven invariants can be reached, which makes
619
+ canonical estate so that all fifteen invariants can be reached, which makes
522
620
  `--strict` a gate that can pass and is therefore worth failing.
523
621
 
524
622
  v2.2 adds no new CLI subcommands. Its one new entry point is the invariant
@@ -571,6 +669,35 @@ python -m firewall.benchmarks
571
669
 
572
670
  The repository contains unit, integration, adversarial, hardening, evidence, UI/API, benchmark, and research tests.
573
671
 
672
+ The v2.4 test surface adds 384 tests across eleven files — 4,087 in the suite
673
+ as a whole, on Python 3.10, 3.11 and 3.12 — including stateful security-state
674
+ fuzzing, eight named concurrency races, and an integration-boundary sweep.
675
+ Among the properties covered:
676
+
677
+ - no path from adaptive analysis to an allow, and no Aegis module able to
678
+ construct an `AuthorizationResult`
679
+ - every forbidden transition refused individually: out of `REVOKED`, out of
680
+ `EXPIRED`, `NARROWED` to wider, `SUSPENDED` to `ACTIVE` without a canonical
681
+ allow, and a child exceeding its parent
682
+ - an envelope that excludes a request always accompanied by a boundary that
683
+ denies it
684
+ - no field of the envelope widening under delegation or attenuation
685
+ - a `nan` bound bounding nothing being denied, while an `inf` bound still
686
+ means unbounded
687
+ - a 400-digit integer producing a decision rather than an exception out of
688
+ `authorize()`
689
+ - every authorization-reachable Aegis method total, including against an
690
+ injected hostile controller
691
+ - a restriction written mid-flight being observed, and a suspension being
692
+ caught inside the commit transaction
693
+ - `__bool__` raising on every analysis object, so a truthiness test cannot
694
+ become an allow
695
+ - every integration surface reaching the canonical boundary, with no local
696
+ allow anywhere
697
+ - no dataclass field in the package carrying a default that Python 3.11
698
+ rejects, so a defect that hides on the development interpreter cannot wait
699
+ for CI to find it
700
+
574
701
  The v2.3 test surface adds the thirteen-question self-attack suite, which
575
702
  covers, among other properties:
576
703
 
@@ -697,6 +824,10 @@ See [`SECURITY.md`](SECURITY.md) for the project's security reporting policy.
697
824
 
698
825
  Detailed specifications are maintained in the repository:
699
826
 
827
+ - `docs/v2.4-aegis.md`
828
+ - `docs/v2.4-aegis-design.md`
829
+ - `docs/v2.4-performance.md`
830
+ - `docs/v2.4-migration.md`
700
831
  - `docs/v2.3-security-corrections.md`
701
832
  - `docs/v2.3-self-attack.md`
702
833
  - `docs/v2.3-invariant-gate.md`
@@ -53,6 +53,16 @@ firewall/adapters/generic.py
53
53
  firewall/adapters/normalize.py
54
54
  firewall/adapters/openai.py
55
55
  firewall/adversarial/__init__.py
56
+ firewall/aegis/__init__.py
57
+ firewall/aegis/blast.py
58
+ firewall/aegis/controller.py
59
+ firewall/aegis/decay.py
60
+ firewall/aegis/envelope.py
61
+ firewall/aegis/explain.py
62
+ firewall/aegis/preflight.py
63
+ firewall/aegis/response.py
64
+ firewall/aegis/restriction.py
65
+ firewall/aegis/state.py
56
66
  firewall/agents/__init__.py
57
67
  firewall/agents/adapters.py
58
68
  firewall/agents/base.py
@@ -186,4 +196,15 @@ tests/test_v2_3_duplicate_concepts.py
186
196
  tests/test_v2_3_intel_coordination.py
187
197
  tests/test_v2_3_invariant_gate.py
188
198
  tests/test_v2_3_policy_analysis.py
189
- tests/test_v2_3_self_attack.py
199
+ tests/test_v2_3_self_attack.py
200
+ tests/test_v2_4_aegis_adversarial.py
201
+ tests/test_v2_4_aegis_concurrency.py
202
+ tests/test_v2_4_aegis_controller.py
203
+ tests/test_v2_4_aegis_corrections.py
204
+ tests/test_v2_4_aegis_fuzz.py
205
+ tests/test_v2_4_aegis_gate.py
206
+ tests/test_v2_4_aegis_state.py
207
+ tests/test_v2_4_attenuation_narrowing.py
208
+ tests/test_v2_4_benchmarks.py
209
+ tests/test_v2_4_envelope_soundness.py
210
+ tests/test_v2_4_integration_boundary.py
@@ -0,0 +1,34 @@
1
+ """v2.1 Agent-to-Agent Zero Trust (firewall.a2a).
2
+
3
+ Authenticated agent relationships: mutual cryptographic authentication,
4
+ scoped permissions, task-bound delegation, capability attenuation,
5
+ delegation-chain verification, expiring delegation, recursive
6
+ revocation, and cross-agent authorization decisions.
7
+
8
+ A decision from :meth:`~firewall.a2a.auth.AgentToAgent.authorize` reports
9
+ what established it. ``basis == BASIS_CANONICAL`` (equivalently
10
+ ``decision.is_canonical``) means ``FirewallSDK.authorize()`` ran and
11
+ allowed the action; ``BASIS_RELATIONSHIP_ONLY`` means only this module's
12
+ own relationship bookkeeping did, which is necessary for a cross-agent
13
+ call and not sufficient to authorize one.
14
+ """
15
+
16
+ from firewall.a2a.auth import (
17
+ BASIS_CANONICAL,
18
+ BASIS_RELATIONSHIP_ONLY,
19
+ BASIS_UNAVAILABLE,
20
+ A2AError,
21
+ A2ADecision,
22
+ AgentRelationship,
23
+ AgentToAgent,
24
+ )
25
+
26
+ __all__ = [
27
+ "BASIS_CANONICAL",
28
+ "BASIS_RELATIONSHIP_ONLY",
29
+ "BASIS_UNAVAILABLE",
30
+ "A2AError",
31
+ "A2ADecision",
32
+ "AgentRelationship",
33
+ "AgentToAgent",
34
+ ]