aegis-devops 0.1.2__tar.gz → 0.1.4__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 (109) hide show
  1. {aegis_devops-0.1.2/src/aegis_devops.egg-info → aegis_devops-0.1.4}/PKG-INFO +52 -14
  2. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/README.md +51 -13
  3. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/__init__.py +1 -1
  4. aegis_devops-0.1.4/src/aegis_core/_examples/__pycache__/__init__.cpython-312.pyc +0 -0
  5. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/constraints.example.yaml +115 -0
  6. aegis_devops-0.1.4/src/aegis_core/_examples/constraints.example.yaml.sig +2 -0
  7. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/AEGIS-MANIFEST.sig +10 -2
  8. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/PRINCIPALS.yaml +8 -0
  9. aegis_devops-0.1.4/src/aegis_core/_examples/sources/git-6001.json +15 -0
  10. aegis_devops-0.1.4/src/aegis_core/_examples/sources/git-6002.json +15 -0
  11. aegis_devops-0.1.4/src/aegis_core/_examples/sources/git-6003.json +15 -0
  12. aegis_devops-0.1.4/src/aegis_core/_examples/sources/git-6004.json +15 -0
  13. aegis_devops-0.1.4/src/aegis_core/_examples/sources/git-6005.json +15 -0
  14. aegis_devops-0.1.4/src/aegis_core/_examples/sources/git-6006.json +15 -0
  15. aegis_devops-0.1.4/src/aegis_core/_examples/sources/git-6007.json +15 -0
  16. aegis_devops-0.1.4/src/aegis_core/_examples/sources/git-6008.json +15 -0
  17. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/baselines/__init__.py +1 -1
  18. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/baselines/llm.py +1 -1
  19. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/baselines/metrics.py +1 -1
  20. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/baselines/opa.py +2 -2
  21. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/cli.py +45 -0
  22. aegis_devops-0.1.4/src/aegis_core/hook.py +490 -0
  23. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/parser.py +41 -0
  24. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/shell.py +9 -3
  25. {aegis_devops-0.1.2 → aegis_devops-0.1.4/src/aegis_devops.egg-info}/PKG-INFO +52 -14
  26. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_devops.egg-info/SOURCES.txt +12 -0
  27. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_baselines.py +1 -1
  28. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_benchmark.py +1 -1
  29. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_cli.py +18 -13
  30. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_corpus.py +1 -1
  31. aegis_devops-0.1.4/tests/test_default_rules.py +126 -0
  32. aegis_devops-0.1.4/tests/test_hook.py +636 -0
  33. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_parsers_sql.py +1 -1
  34. aegis_devops-0.1.4/tests/test_plugins.py +76 -0
  35. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_store.py +2 -2
  36. aegis_devops-0.1.2/src/aegis_core/_examples/__pycache__/__init__.cpython-312.pyc +0 -0
  37. aegis_devops-0.1.2/src/aegis_core/_examples/constraints.example.yaml.sig +0 -2
  38. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/LICENSE +0 -0
  39. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/MANIFEST.in +0 -0
  40. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/pyproject.toml +0 -0
  41. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/setup.cfg +0 -0
  42. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/__init__.py +0 -0
  43. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/authority.example.yaml +0 -0
  44. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/authority.example.yaml.sig +0 -0
  45. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/environments.example.yaml +0 -0
  46. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/environments.example.yaml.sig +0 -0
  47. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/example-signing.key +0 -0
  48. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/plan_constraints.example.yaml +0 -0
  49. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/plan_constraints.example.yaml.sig +0 -0
  50. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/git-4001.json +0 -0
  51. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/git-789abc.json +0 -0
  52. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/git-abc123.json +0 -0
  53. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/git-bcd234.json +0 -0
  54. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/git-def456.json +0 -0
  55. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-1001.json +0 -0
  56. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-1002.json +0 -0
  57. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-2001.json +0 -0
  58. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-2002.json +0 -0
  59. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-3001.json +0 -0
  60. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-3002.json +0 -0
  61. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-3003.json +0 -0
  62. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-3004.json +0 -0
  63. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-3005.json +0 -0
  64. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-5001.json +0 -0
  65. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-5002.json +0 -0
  66. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-5003.json +0 -0
  67. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-5004.json +0 -0
  68. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/jira-5006.json +0 -0
  69. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/plan-1001.json +0 -0
  70. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/plan-1002.json +0 -0
  71. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/plan-1003.json +0 -0
  72. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/plan-1004.json +0 -0
  73. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/plan-5005.json +0 -0
  74. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/_examples/sources/slack-perma-1.json +0 -0
  75. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/adversarial.py +0 -0
  76. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/authority.py +0 -0
  77. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/baselines/base.py +0 -0
  78. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/baselines/external.py +0 -0
  79. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/config.py +0 -0
  80. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/environments.py +0 -0
  81. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/intent.py +0 -0
  82. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/interceptor.py +0 -0
  83. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/ledger.py +0 -0
  84. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/parsers/__init__.py +0 -0
  85. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/parsers/pulumi.py +0 -0
  86. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/parsers/sql.py +0 -0
  87. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/plan.py +0 -0
  88. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/provenance.py +0 -0
  89. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/signing.py +0 -0
  90. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_core/store.py +0 -0
  91. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_devops.egg-info/dependency_links.txt +0 -0
  92. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_devops.egg-info/entry_points.txt +0 -0
  93. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_devops.egg-info/requires.txt +0 -0
  94. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/src/aegis_devops.egg-info/top_level.txt +0 -0
  95. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_adversarial.py +0 -0
  96. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_authority.py +0 -0
  97. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_config.py +0 -0
  98. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_docs_consistency.py +0 -0
  99. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_environments.py +0 -0
  100. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_intent.py +0 -0
  101. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_interceptor.py +0 -0
  102. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_ledger.py +0 -0
  103. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_parser.py +0 -0
  104. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_parsers_pulumi.py +0 -0
  105. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_plan.py +0 -0
  106. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_provenance.py +0 -0
  107. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_shell.py +0 -0
  108. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_signing.py +0 -0
  109. {aegis_devops-0.1.2 → aegis_devops-0.1.4}/tests/test_store_match.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aegis-devops
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Provenance-backed, authority-aware policy verifier for agentic DevOps actions.
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/moneytool/aegis-devops
@@ -30,19 +30,34 @@ Provides-Extra: llm
30
30
  Requires-Dist: anthropic; extra == "llm"
31
31
  Dynamic: license-file
32
32
 
33
- # Aegis-DevOps — Policy Verifier for AI DevOps Agents
33
+ # Aegis-DevOps
34
34
 
35
35
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22950337.svg)](https://doi.org/10.5281/zenodo.22950337)
36
36
  [![PyPI](https://img.shields.io/pypi/v/aegis-devops)](https://pypi.org/project/aegis-devops/)
37
37
 
38
- **Provenance-backed, authority-aware guardrails that stop context poisoning and agentic drift
39
- before an AI agent's `kubectl` or `terraform` action reaches your infrastructure.**
38
+ **Stop AI agents from running `kubectl delete`, `terraform destroy` or `DROP TABLE` because a
39
+ ticket told them to.**
40
40
 
41
- **Keywords:** AI agent security · AgentOps · prompt injection · context poisoning · policy
42
- enforcement · policy-as-code · Kubernetes · Terraform · OPA · SRE · LLM guardrails ·
43
- provenance · infrastructure-as-code
41
+ Aegis-DevOps checks every command an agent wants to run before it runs, and blocks it if your
42
+ policy says no. A policy rule only counts if nobody has edited it since it was signed, and if
43
+ its author was allowed to write that kind of rule. So a planted line in a Jira ticket can't
44
+ become policy.
44
45
 
45
- ![Aegis demo](docs/demo.gif)
46
+ ![Aegis-DevOps blocking an injected kubectl delete](docs/where-it-sits.gif)
47
+
48
+ ### Install in Claude Code
49
+
50
+ ```bash
51
+ pip install aegis-devops && aegis init .aegis
52
+ claude plugin marketplace add moneytool/aegis-devops
53
+ claude plugin install aegis-devops@aegis-devops
54
+ ```
55
+
56
+ Codex, GitHub Copilot (CLI and VS Code) and Cursor: `aegis install codex|copilot|vscode|cursor`
57
+ (see [Coding agents](docs/agents.md)). It only acts in projects with a `.aegis/` policy, and
58
+ only blocks what that policy blocks. It also works as a CI step
59
+ (`aegis check terraform plan.json --exit-style ci`) and as a Python library; see
60
+ [Quick start](#quick-start).
46
61
 
47
62
  ## What it does
48
63
 
@@ -81,7 +96,7 @@ BLOCK: kubernetes scale deployment/api-server
81
96
  citations: no-scale-prod-peak
82
97
  covered: True latency_ms: 0.20
83
98
  PLAN BLOCK: 1 intent(s)
84
- STORE: loaded=21 quarantined=0 principals=3
99
+ STORE: loaded=29 quarantined=0 principals=3
85
100
  warning: using example signing key
86
101
  ```
87
102
 
@@ -92,6 +107,8 @@ a key everyone has. `aegis init` prints the two commands that replace it with yo
92
107
  replace `constraints.example.yaml` with your own `constraints.yaml` (a real file wins over the
93
108
  `.example` one when both exist).
94
109
 
110
+ ![Aegis CLI demo](docs/demo.gif)
111
+
95
112
  ### From a clone
96
113
 
97
114
  ```bash
@@ -199,36 +216,57 @@ OPA/Gatekeeper evaluates **structured API objects** against **hand-authored rule
199
216
  derives **unstructured human constraints** (from Slack, Jira, Git) and applies
200
217
  **authority-driven validation** to the agent's intent *before* it reaches the infrastructure.
201
218
 
219
+ ## How it compares
220
+
221
+ Other tools stop destructive commands in coding agents, and cover more agents and more kinds of
222
+ command than Aegis does today. The difference is where the rules come from: Aegis treats every
223
+ rule as a claim that has to be checked (was it changed since it was signed, does its cited
224
+ source back it, was its author allowed to write that kind of rule), because in an agent's
225
+ context a rule can arrive from a ticket or a chat message as easily as from you.
226
+
227
+ | | Aegis-DevOps | [nah](https://github.com/manuelschipper/nah) | [claude-code-safety-net](https://github.com/kenryu42/claude-code-safety-net) | [destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard) |
228
+ |---|---|---|---|---|
229
+ | Guards | Infra commands and plans: kubectl, terraform/tofu, aws/az/gcloud, helm, argocd, flux, git/gh, SQL, pulumi | Git, filesystem, infra CLIs (Terraform, OpenTofu, Pulumi, kubectl, Docker), secrets, publishing | Destructive git and filesystem commands, secret access; cloud CLIs via optional rulebooks | Git, filesystem, databases, Kubernetes, IaC, clouds, Docker and more (50+ packs) |
230
+ | Agents | Claude Code, Codex, Copilot CLI, VS Code, Cursor | Claude Code, Codex, Cursor, Copilot and 10+ more | Claude Code, Codex, Cursor, Copilot CLI, Gemini CLI and 8+ more | Claude Code, Codex, Copilot, Cursor, Gemini CLI and 9+ more |
231
+ | Rules | Signed rules, each citing a source and an author; checked against an authority map (who may assert what) | Built-in deterministic guards; custom guards can only make it stricter | Built-in AST-based protections, configurable presets, community rulebooks | Built-in regex/AST packs, TOML config, custom YAML packs |
232
+ | Rule provenance and authority | Yes: a tampered, forged or unauthorised rule gets no vote | — | — | — |
233
+ | Terraform/Pulumi plan checks | Yes (plan JSON) | Whole-stack destroy commands | Commands via rulebooks | Destroy commands |
234
+ | CI / non-agent use | `aegis check ... --exit-style ci`, Python library | `nah test` | Node.js library mode | `dcg scan` (SARIF) |
235
+
236
+ "—" means the project's README does not describe it. Checked against each project's README on
237
+ 2026-09-27; corrections welcome.
238
+
202
239
  ## Project status / roadmap
203
240
 
204
241
  The engine (constraint store, interceptor, environment mapping, dry-run handling, rate limits,
205
242
  plan-level constraints, and parsers for every tool in "Supported tools") is complete, and
206
- v0.1.0 is on PyPI as an **alpha**. Real LLM baselines have been run: Claude Sonnet 5 through
243
+ v0.1.3 is on PyPI as an **alpha**. Real LLM baselines have been run: Claude Sonnet 5 through
207
244
  the API (cached in `results/llm-external.md`), Haiku through the Claude Code CLI, `gpt-6-astra`
208
245
  through the Codex CLI, and a local `mistral:latest`.
209
246
 
210
- What is *not* done is the part the threat model leans on hardest. See `PLAN.md §8`, but in
247
+ What is *not* done is the part the threat model leans on hardest. See `docs/dev/PLAN.md §8`, but in
211
248
  short: sources are verified against files on disk rather than real Git/Slack/Jira connectors,
212
249
  signing uses a shared secret rather than per-principal public keys, and a `principal` is a
213
250
  signed name rather than an identity bound to a commit signature or an SSO group. Until those
214
251
  land, Aegis demonstrates that the *decision procedure* is sound; it does not yet prove the
215
252
  identities feeding it are. Resource matching is also case-sensitive on names. It is not
216
- production-ready: read `PLAN.md §8` for the full list of open gaps before putting it in front
253
+ production-ready: read `docs/dev/PLAN.md §8` for the full list of open gaps before putting it in front
217
254
  of anything you care about.
218
255
 
219
256
  ## Documentation
220
257
 
221
258
  | Page | Covers |
222
259
  | :--- | :--- |
260
+ | [`docs/agents.md`](docs/agents.md) | Claude Code, Codex, Copilot, VS Code and Cursor: install, what gets blocked |
223
261
  | [`docs/cli.md`](docs/cli.md) | Exit codes, store health, the Claude Code hook, argv forms, compound commands, dry runs, library usage |
224
262
  | [`docs/constraints.md`](docs/constraints.md) | Writing constraints, metadata vocabulary, authority policy, environment mapping |
225
263
  | [`docs/configuration.md`](docs/configuration.md) | Configuration/config-dir discovery, signing, source verification, rate limits & ledger |
226
264
  | [`docs/benchmark.md`](docs/benchmark.md) | Benchmark methodology, full results table, real LLM baselines, agent-harness baselines, corpus, adversarial suite |
227
265
  | [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) | Adding a new parser or tool |
228
- | [`PLAN.md`](PLAN.md) | Design plan and open gaps |
266
+ | [`docs/dev/PLAN.md`](docs/dev/PLAN.md) | Design plan and open gaps |
229
267
  | [`SECURITY.md`](SECURITY.md) | Reporting a bypass |
230
268
  | [`CHANGELOG.md`](CHANGELOG.md) | Release history |
231
- | [`REVIEW-4.md`](REVIEW-4.md) | Corpus/oracle rewrite (independent oracle, intent-level holdout) |
269
+ | [`docs/dev/REVIEW-4.md`](docs/dev/REVIEW-4.md) | Corpus/oracle rewrite (independent oracle, intent-level holdout) |
232
270
 
233
271
  ## Development
234
272
 
@@ -1,16 +1,31 @@
1
- # Aegis-DevOps — Policy Verifier for AI DevOps Agents
1
+ # Aegis-DevOps
2
2
 
3
3
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22950337.svg)](https://doi.org/10.5281/zenodo.22950337)
4
4
  [![PyPI](https://img.shields.io/pypi/v/aegis-devops)](https://pypi.org/project/aegis-devops/)
5
5
 
6
- **Provenance-backed, authority-aware guardrails that stop context poisoning and agentic drift
7
- before an AI agent's `kubectl` or `terraform` action reaches your infrastructure.**
6
+ **Stop AI agents from running `kubectl delete`, `terraform destroy` or `DROP TABLE` because a
7
+ ticket told them to.**
8
8
 
9
- **Keywords:** AI agent security · AgentOps · prompt injection · context poisoning · policy
10
- enforcement · policy-as-code · Kubernetes · Terraform · OPA · SRE · LLM guardrails ·
11
- provenance · infrastructure-as-code
9
+ Aegis-DevOps checks every command an agent wants to run before it runs, and blocks it if your
10
+ policy says no. A policy rule only counts if nobody has edited it since it was signed, and if
11
+ its author was allowed to write that kind of rule. So a planted line in a Jira ticket can't
12
+ become policy.
12
13
 
13
- ![Aegis demo](docs/demo.gif)
14
+ ![Aegis-DevOps blocking an injected kubectl delete](docs/where-it-sits.gif)
15
+
16
+ ### Install in Claude Code
17
+
18
+ ```bash
19
+ pip install aegis-devops && aegis init .aegis
20
+ claude plugin marketplace add moneytool/aegis-devops
21
+ claude plugin install aegis-devops@aegis-devops
22
+ ```
23
+
24
+ Codex, GitHub Copilot (CLI and VS Code) and Cursor: `aegis install codex|copilot|vscode|cursor`
25
+ (see [Coding agents](docs/agents.md)). It only acts in projects with a `.aegis/` policy, and
26
+ only blocks what that policy blocks. It also works as a CI step
27
+ (`aegis check terraform plan.json --exit-style ci`) and as a Python library; see
28
+ [Quick start](#quick-start).
14
29
 
15
30
  ## What it does
16
31
 
@@ -49,7 +64,7 @@ BLOCK: kubernetes scale deployment/api-server
49
64
  citations: no-scale-prod-peak
50
65
  covered: True latency_ms: 0.20
51
66
  PLAN BLOCK: 1 intent(s)
52
- STORE: loaded=21 quarantined=0 principals=3
67
+ STORE: loaded=29 quarantined=0 principals=3
53
68
  warning: using example signing key
54
69
  ```
55
70
 
@@ -60,6 +75,8 @@ a key everyone has. `aegis init` prints the two commands that replace it with yo
60
75
  replace `constraints.example.yaml` with your own `constraints.yaml` (a real file wins over the
61
76
  `.example` one when both exist).
62
77
 
78
+ ![Aegis CLI demo](docs/demo.gif)
79
+
63
80
  ### From a clone
64
81
 
65
82
  ```bash
@@ -167,36 +184,57 @@ OPA/Gatekeeper evaluates **structured API objects** against **hand-authored rule
167
184
  derives **unstructured human constraints** (from Slack, Jira, Git) and applies
168
185
  **authority-driven validation** to the agent's intent *before* it reaches the infrastructure.
169
186
 
187
+ ## How it compares
188
+
189
+ Other tools stop destructive commands in coding agents, and cover more agents and more kinds of
190
+ command than Aegis does today. The difference is where the rules come from: Aegis treats every
191
+ rule as a claim that has to be checked (was it changed since it was signed, does its cited
192
+ source back it, was its author allowed to write that kind of rule), because in an agent's
193
+ context a rule can arrive from a ticket or a chat message as easily as from you.
194
+
195
+ | | Aegis-DevOps | [nah](https://github.com/manuelschipper/nah) | [claude-code-safety-net](https://github.com/kenryu42/claude-code-safety-net) | [destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard) |
196
+ |---|---|---|---|---|
197
+ | Guards | Infra commands and plans: kubectl, terraform/tofu, aws/az/gcloud, helm, argocd, flux, git/gh, SQL, pulumi | Git, filesystem, infra CLIs (Terraform, OpenTofu, Pulumi, kubectl, Docker), secrets, publishing | Destructive git and filesystem commands, secret access; cloud CLIs via optional rulebooks | Git, filesystem, databases, Kubernetes, IaC, clouds, Docker and more (50+ packs) |
198
+ | Agents | Claude Code, Codex, Copilot CLI, VS Code, Cursor | Claude Code, Codex, Cursor, Copilot and 10+ more | Claude Code, Codex, Cursor, Copilot CLI, Gemini CLI and 8+ more | Claude Code, Codex, Copilot, Cursor, Gemini CLI and 9+ more |
199
+ | Rules | Signed rules, each citing a source and an author; checked against an authority map (who may assert what) | Built-in deterministic guards; custom guards can only make it stricter | Built-in AST-based protections, configurable presets, community rulebooks | Built-in regex/AST packs, TOML config, custom YAML packs |
200
+ | Rule provenance and authority | Yes: a tampered, forged or unauthorised rule gets no vote | — | — | — |
201
+ | Terraform/Pulumi plan checks | Yes (plan JSON) | Whole-stack destroy commands | Commands via rulebooks | Destroy commands |
202
+ | CI / non-agent use | `aegis check ... --exit-style ci`, Python library | `nah test` | Node.js library mode | `dcg scan` (SARIF) |
203
+
204
+ "—" means the project's README does not describe it. Checked against each project's README on
205
+ 2026-09-27; corrections welcome.
206
+
170
207
  ## Project status / roadmap
171
208
 
172
209
  The engine (constraint store, interceptor, environment mapping, dry-run handling, rate limits,
173
210
  plan-level constraints, and parsers for every tool in "Supported tools") is complete, and
174
- v0.1.0 is on PyPI as an **alpha**. Real LLM baselines have been run: Claude Sonnet 5 through
211
+ v0.1.3 is on PyPI as an **alpha**. Real LLM baselines have been run: Claude Sonnet 5 through
175
212
  the API (cached in `results/llm-external.md`), Haiku through the Claude Code CLI, `gpt-6-astra`
176
213
  through the Codex CLI, and a local `mistral:latest`.
177
214
 
178
- What is *not* done is the part the threat model leans on hardest. See `PLAN.md §8`, but in
215
+ What is *not* done is the part the threat model leans on hardest. See `docs/dev/PLAN.md §8`, but in
179
216
  short: sources are verified against files on disk rather than real Git/Slack/Jira connectors,
180
217
  signing uses a shared secret rather than per-principal public keys, and a `principal` is a
181
218
  signed name rather than an identity bound to a commit signature or an SSO group. Until those
182
219
  land, Aegis demonstrates that the *decision procedure* is sound; it does not yet prove the
183
220
  identities feeding it are. Resource matching is also case-sensitive on names. It is not
184
- production-ready: read `PLAN.md §8` for the full list of open gaps before putting it in front
221
+ production-ready: read `docs/dev/PLAN.md §8` for the full list of open gaps before putting it in front
185
222
  of anything you care about.
186
223
 
187
224
  ## Documentation
188
225
 
189
226
  | Page | Covers |
190
227
  | :--- | :--- |
228
+ | [`docs/agents.md`](docs/agents.md) | Claude Code, Codex, Copilot, VS Code and Cursor: install, what gets blocked |
191
229
  | [`docs/cli.md`](docs/cli.md) | Exit codes, store health, the Claude Code hook, argv forms, compound commands, dry runs, library usage |
192
230
  | [`docs/constraints.md`](docs/constraints.md) | Writing constraints, metadata vocabulary, authority policy, environment mapping |
193
231
  | [`docs/configuration.md`](docs/configuration.md) | Configuration/config-dir discovery, signing, source verification, rate limits & ledger |
194
232
  | [`docs/benchmark.md`](docs/benchmark.md) | Benchmark methodology, full results table, real LLM baselines, agent-harness baselines, corpus, adversarial suite |
195
233
  | [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) | Adding a new parser or tool |
196
- | [`PLAN.md`](PLAN.md) | Design plan and open gaps |
234
+ | [`docs/dev/PLAN.md`](docs/dev/PLAN.md) | Design plan and open gaps |
197
235
  | [`SECURITY.md`](SECURITY.md) | Reporting a bypass |
198
236
  | [`CHANGELOG.md`](CHANGELOG.md) | Release history |
199
- | [`REVIEW-4.md`](REVIEW-4.md) | Corpus/oracle rewrite (independent oracle, intent-level holdout) |
237
+ | [`docs/dev/REVIEW-4.md`](docs/dev/REVIEW-4.md) | Corpus/oracle rewrite (independent oracle, intent-level holdout) |
200
238
 
201
239
  ## Development
202
240
 
@@ -4,4 +4,4 @@ infrastructure actions of AI agents.
4
4
  See the README for what this does and, importantly, what it does not yet do.
5
5
  """
6
6
 
7
- __version__ = "0.1.2"
7
+ __version__ = "0.1.4"
@@ -336,3 +336,118 @@ constraints:
336
336
  rule_text: Block deleting Helm releases in any production environment (resolved
337
337
  from the kube context), whatever the namespace; use the decommission runbook instead.
338
338
  provenance_hash: 747653b3b34300a18e4773a0784706fcb0147fb10507e88ce93f2fb5cdcd4df8
339
+ - id: block-terraform-destroy
340
+ provider: terraform
341
+ resource_pattern: workspace/*
342
+ actions:
343
+ - delete
344
+ scope: {}
345
+ time_window: null
346
+ effect: BLOCK
347
+ constraint_class: deletion
348
+ principal: admin
349
+ source_ref: git-6001
350
+ source_timestamp: '2026-09-27T12:00:00+00:00'
351
+ rule_text: 'Block ''terraform destroy'' and ''tofu destroy'' (and apply -destroy):
352
+ tearing down a whole configuration needs a reviewed plan, not an agent''s command.'
353
+ provenance_hash: 48bd0974d281efa45af89240c0ffc997a4ee7323d07471bb97a4a047081c4178
354
+ - id: block-pulumi-destroy
355
+ provider: pulumi
356
+ resource_pattern: stack/*
357
+ actions:
358
+ - delete
359
+ scope: {}
360
+ time_window: null
361
+ effect: BLOCK
362
+ constraint_class: deletion
363
+ principal: admin
364
+ source_ref: git-6002
365
+ source_timestamp: '2026-09-27T12:00:00+00:00'
366
+ rule_text: 'Block ''pulumi destroy'' and ''pulumi stack rm'': removing a whole stack
367
+ needs a human.'
368
+ provenance_hash: 41428597dfe6a997f0797c3c700db953399d515447b2857552cbf4635d3e1782
369
+ - id: block-namespace-delete
370
+ provider: kubernetes
371
+ resource_pattern: namespace/*
372
+ actions:
373
+ - delete
374
+ scope: {}
375
+ time_window: null
376
+ effect: BLOCK
377
+ constraint_class: deletion
378
+ principal: admin
379
+ source_ref: git-6003
380
+ source_timestamp: '2026-09-27T12:00:00+00:00'
381
+ rule_text: 'Block deleting Kubernetes namespaces: it deletes everything inside them.'
382
+ provenance_hash: 44ee6f6790b2e4996f1fa03bc8d79782e876d1aae27dca7630b81a88206de572
383
+ - id: block-s3-bucket-delete
384
+ provider: aws
385
+ resource_pattern: s3/bucket/*
386
+ actions:
387
+ - delete
388
+ scope: {}
389
+ time_window: null
390
+ effect: BLOCK
391
+ constraint_class: deletion
392
+ principal: admin
393
+ source_ref: git-6004
394
+ source_timestamp: '2026-09-27T12:00:00+00:00'
395
+ rule_text: Block deleting S3 buckets (aws s3 rb, s3api delete-bucket).
396
+ provenance_hash: 27e8b1723128c747f4780969cf2b44f639235bc1e83e4188686618cb23d42125
397
+ - id: block-rds-delete
398
+ provider: aws
399
+ resource_pattern: rds/*
400
+ actions:
401
+ - delete
402
+ scope: {}
403
+ time_window: null
404
+ effect: BLOCK
405
+ constraint_class: deletion
406
+ principal: admin
407
+ source_ref: git-6005
408
+ source_timestamp: '2026-09-27T12:00:00+00:00'
409
+ rule_text: Block deleting RDS databases, clusters and snapshots.
410
+ provenance_hash: e44c7617a771c4f53260e751bf23b1bf6c1df648e1b0aa6a6629a2a344b60b0d
411
+ - id: block-gcp-project-delete
412
+ provider: gcp
413
+ resource_pattern: project/*
414
+ actions:
415
+ - delete
416
+ scope: {}
417
+ time_window: null
418
+ effect: BLOCK
419
+ constraint_class: deletion
420
+ principal: admin
421
+ source_ref: git-6006
422
+ source_timestamp: '2026-09-27T12:00:00+00:00'
423
+ rule_text: Block deleting GCP projects.
424
+ provenance_hash: 7e6fe5ce1001c1c8849af9bbbc66ce4c9f4c2303772f77dcbf9fef0d58f2b4a0
425
+ - id: block-azure-resource-group-delete
426
+ provider: azure
427
+ resource_pattern: resource/group/*
428
+ actions:
429
+ - delete
430
+ scope: {}
431
+ time_window: null
432
+ effect: BLOCK
433
+ constraint_class: deletion
434
+ principal: admin
435
+ source_ref: git-6007
436
+ source_timestamp: '2026-09-27T12:00:00+00:00'
437
+ rule_text: 'Block deleting Azure resource groups: it deletes every resource in them.'
438
+ provenance_hash: 733126d10190f8cdcde09cbbcd6a6aef719b97e9dc8bd070cf3b84aa381029b9
439
+ - id: escalate-argocd-app-delete
440
+ provider: argocd
441
+ resource_pattern: app/*
442
+ actions:
443
+ - delete
444
+ scope: {}
445
+ time_window: null
446
+ effect: ESCALATE
447
+ constraint_class: deletion
448
+ principal: admin
449
+ source_ref: git-6008
450
+ source_timestamp: '2026-09-27T12:00:00+00:00'
451
+ rule_text: Escalate deleting Argo CD applications (with cascade this deletes the
452
+ deployed resources) for human review.
453
+ provenance_hash: dc24eb69ac5c8b66279284b6df19095e3f0096303f3ef18da712a53e5e339aeb
@@ -0,0 +1,2 @@
1
+ aegis-sig-v1
2
+ 245908109e5e1ecf20ba80c41aa725c57dfbd5b2f185da1bc6708b3cbd3ce42d
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "files": {
3
- "PRINCIPALS.yaml": "bdc9ca4ae562397b203242031e960dc4a45eae1bf1ba6d8951f7e17d819a7cfb",
3
+ "PRINCIPALS.yaml": "e2e7025a2092240acede6a88c7f1a4f22d3cdbf5821772fba9e0f91fbfcbcc8f",
4
4
  "git-4001.json": "8be2dd6c37ef643b3bc375b15d5d97889b00456285f594e21a3b4d52521e21de",
5
+ "git-6001.json": "6592ca4568f767d71a431490ff3cacdbc699ad92be966f57aed3b0a485844dc5",
6
+ "git-6002.json": "e6286c5fb8a0d2b3c34ca0c841ccede2a477a02f4781115caf4650f4f7c019b8",
7
+ "git-6003.json": "b077ac2d1119f9a90453e762f2186f3f37837d348822016c01a6f145f528b197",
8
+ "git-6004.json": "57d2dc91b3014c3cad329266f7ba57472b2d5053635827afc7ddeda02cd73ee3",
9
+ "git-6005.json": "3fe8ba5cc4cd123fe78f5f4e60f81f8ab38dc0da395d4dbf82634f1359f01803",
10
+ "git-6006.json": "3f6fbfeb34afb3bcb8075f0864047b3641f0016b8817f67288db7f64afd36b58",
11
+ "git-6007.json": "eb84394208274b79792e285c5143dde320a2f4755d9b2922ffb55df07e7c5b9e",
12
+ "git-6008.json": "34d29df94b55a3fa29521246fa17e0966eda93f718a6c41082e6c648569aafa5",
5
13
  "git-789abc.json": "48ac500e13d36240ec5c72bf90e96b433a5873d636e9e36f99a73468e7fb5757",
6
14
  "git-abc123.json": "ee3751fdcd64cf1dd374bf9f7b73cda723a4aced5053f32501ba9416de89afc7",
7
15
  "git-bcd234.json": "a0de7b32bde75735c91504aa7156e7b2ba2ef961d0f439218507e40d0bdfd89a",
@@ -28,5 +36,5 @@
28
36
  "slack-perma-1.json": "2c8945a68e413c300ef58fc6a6d3daa8e4d0029a26a454dfad983e2091a188d1"
29
37
  },
30
38
  "header": "aegis-manifest-v1",
31
- "sig": "16b0f5f348626c74d6b40cfe21fe92d3e37703668fa51e9428fdc026cc297bc0"
39
+ "sig": "034812f78b7f502ebcbb9183bfcf88023324ffcd83e82e5d698aee252cd3b824"
32
40
  }
@@ -29,3 +29,11 @@ principals:
29
29
  plan-1004: admin
30
30
  plan-5005: admin
31
31
  slack-perma-1: admin
32
+ git-6001: admin
33
+ git-6002: admin
34
+ git-6003: admin
35
+ git-6004: admin
36
+ git-6005: admin
37
+ git-6006: admin
38
+ git-6007: admin
39
+ git-6008: admin
@@ -0,0 +1,15 @@
1
+ {
2
+ "provider": "terraform",
3
+ "resource_pattern": "workspace/*",
4
+ "actions": [
5
+ "delete"
6
+ ],
7
+ "scope": {},
8
+ "time_window": null,
9
+ "effect": "BLOCK",
10
+ "constraint_class": "deletion",
11
+ "principal": "admin",
12
+ "source_ref": "git-6001",
13
+ "source_timestamp": "2026-09-27T12:00:00+00:00",
14
+ "rule_text": "Block 'terraform destroy' and 'tofu destroy' (and apply -destroy): tearing down a whole configuration needs a reviewed plan, not an agent's command."
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "provider": "pulumi",
3
+ "resource_pattern": "stack/*",
4
+ "actions": [
5
+ "delete"
6
+ ],
7
+ "scope": {},
8
+ "time_window": null,
9
+ "effect": "BLOCK",
10
+ "constraint_class": "deletion",
11
+ "principal": "admin",
12
+ "source_ref": "git-6002",
13
+ "source_timestamp": "2026-09-27T12:00:00+00:00",
14
+ "rule_text": "Block 'pulumi destroy' and 'pulumi stack rm': removing a whole stack needs a human."
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "provider": "kubernetes",
3
+ "resource_pattern": "namespace/*",
4
+ "actions": [
5
+ "delete"
6
+ ],
7
+ "scope": {},
8
+ "time_window": null,
9
+ "effect": "BLOCK",
10
+ "constraint_class": "deletion",
11
+ "principal": "admin",
12
+ "source_ref": "git-6003",
13
+ "source_timestamp": "2026-09-27T12:00:00+00:00",
14
+ "rule_text": "Block deleting Kubernetes namespaces: it deletes everything inside them."
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "provider": "aws",
3
+ "resource_pattern": "s3/bucket/*",
4
+ "actions": [
5
+ "delete"
6
+ ],
7
+ "scope": {},
8
+ "time_window": null,
9
+ "effect": "BLOCK",
10
+ "constraint_class": "deletion",
11
+ "principal": "admin",
12
+ "source_ref": "git-6004",
13
+ "source_timestamp": "2026-09-27T12:00:00+00:00",
14
+ "rule_text": "Block deleting S3 buckets (aws s3 rb, s3api delete-bucket)."
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "provider": "aws",
3
+ "resource_pattern": "rds/*",
4
+ "actions": [
5
+ "delete"
6
+ ],
7
+ "scope": {},
8
+ "time_window": null,
9
+ "effect": "BLOCK",
10
+ "constraint_class": "deletion",
11
+ "principal": "admin",
12
+ "source_ref": "git-6005",
13
+ "source_timestamp": "2026-09-27T12:00:00+00:00",
14
+ "rule_text": "Block deleting RDS databases, clusters and snapshots."
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "provider": "gcp",
3
+ "resource_pattern": "project/*",
4
+ "actions": [
5
+ "delete"
6
+ ],
7
+ "scope": {},
8
+ "time_window": null,
9
+ "effect": "BLOCK",
10
+ "constraint_class": "deletion",
11
+ "principal": "admin",
12
+ "source_ref": "git-6006",
13
+ "source_timestamp": "2026-09-27T12:00:00+00:00",
14
+ "rule_text": "Block deleting GCP projects."
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "provider": "azure",
3
+ "resource_pattern": "resource/group/*",
4
+ "actions": [
5
+ "delete"
6
+ ],
7
+ "scope": {},
8
+ "time_window": null,
9
+ "effect": "BLOCK",
10
+ "constraint_class": "deletion",
11
+ "principal": "admin",
12
+ "source_ref": "git-6007",
13
+ "source_timestamp": "2026-09-27T12:00:00+00:00",
14
+ "rule_text": "Block deleting Azure resource groups: it deletes every resource in them."
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "provider": "argocd",
3
+ "resource_pattern": "app/*",
4
+ "actions": [
5
+ "delete"
6
+ ],
7
+ "scope": {},
8
+ "time_window": null,
9
+ "effect": "ESCALATE",
10
+ "constraint_class": "deletion",
11
+ "principal": "admin",
12
+ "source_ref": "git-6008",
13
+ "source_timestamp": "2026-09-27T12:00:00+00:00",
14
+ "rule_text": "Escalate deleting Argo CD applications (with cascade this deletes the deployed resources) for human review."
15
+ }
@@ -1,5 +1,5 @@
1
1
  """Baseline verifiers compared against Aegis in the Week 7-8 benchmark
2
- (PLAN.md §4).
2
+ (docs/dev/PLAN.md §4).
3
3
 
4
4
  Every verifier here implements the same tiny protocol (see ``base.py``) so
5
5
  ``scripts/benchmark.py`` can run Aegis and the baselines through one loop
@@ -1,4 +1,4 @@
1
- """Baseline B — LLM Self-Check (PLAN.md §4).
1
+ """Baseline B — LLM Self-Check (docs/dev/PLAN.md §4).
2
2
 
3
3
  The model is handed the *same* 500 constraints Aegis loads into its store
4
4
  (constraint parity) as a YAML blob in the system prompt, and the intent as
@@ -1,4 +1,4 @@
1
- """Benchmark metrics (PLAN.md §4): confusion matrix, over-block rate,
1
+ """Benchmark metrics (docs/dev/PLAN.md §4): confusion matrix, over-block rate,
2
2
  coverage, poison susceptibility (per attack kind) and latency percentiles.
3
3
 
4
4
  The harness consumes ``Decision`` objects duck-typed: only ``verdict``,
@@ -1,10 +1,10 @@
1
- """Baseline C — OPA/Rego (PLAN.md §4).
1
+ """Baseline C — OPA/Rego (docs/dev/PLAN.md §4).
2
2
 
3
3
  Like the LLM baseline, this one loads *every* constraint — tampered,
4
4
  unauthorized, and forged included — because OPA/Gatekeeper has no concept
5
5
  of provenance or authority. It evaluates structured input against
6
6
  hand-authored (here, generated) rules, which is exactly the "why not
7
- OPA/Gatekeeper" distinction PLAN.md §3 draws.
7
+ OPA/Gatekeeper" distinction docs/dev/PLAN.md §3 draws.
8
8
 
9
9
  Known limitation: constraint ``time_window`` is NOT evaluated by the
10
10
  generated Rego (OPA has ``time.now_ns`` but wiring day-of-week + local-tz