aegis-devops 0.1.2__tar.gz → 0.1.3__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 (108) hide show
  1. {aegis_devops-0.1.2/src/aegis_devops.egg-info → aegis_devops-0.1.3}/PKG-INFO +20 -6
  2. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/README.md +19 -5
  3. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/__init__.py +1 -1
  4. aegis_devops-0.1.3/src/aegis_core/_examples/__pycache__/__init__.cpython-312.pyc +0 -0
  5. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/constraints.example.yaml +115 -0
  6. aegis_devops-0.1.3/src/aegis_core/_examples/constraints.example.yaml.sig +2 -0
  7. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/AEGIS-MANIFEST.sig +10 -2
  8. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/PRINCIPALS.yaml +8 -0
  9. aegis_devops-0.1.3/src/aegis_core/_examples/sources/git-6001.json +15 -0
  10. aegis_devops-0.1.3/src/aegis_core/_examples/sources/git-6002.json +15 -0
  11. aegis_devops-0.1.3/src/aegis_core/_examples/sources/git-6003.json +15 -0
  12. aegis_devops-0.1.3/src/aegis_core/_examples/sources/git-6004.json +15 -0
  13. aegis_devops-0.1.3/src/aegis_core/_examples/sources/git-6005.json +15 -0
  14. aegis_devops-0.1.3/src/aegis_core/_examples/sources/git-6006.json +15 -0
  15. aegis_devops-0.1.3/src/aegis_core/_examples/sources/git-6007.json +15 -0
  16. aegis_devops-0.1.3/src/aegis_core/_examples/sources/git-6008.json +15 -0
  17. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/baselines/__init__.py +1 -1
  18. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/baselines/llm.py +1 -1
  19. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/baselines/metrics.py +1 -1
  20. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/baselines/opa.py +2 -2
  21. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/cli.py +45 -0
  22. aegis_devops-0.1.3/src/aegis_core/hook.py +481 -0
  23. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/parser.py +41 -0
  24. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/shell.py +9 -3
  25. {aegis_devops-0.1.2 → aegis_devops-0.1.3/src/aegis_devops.egg-info}/PKG-INFO +20 -6
  26. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_devops.egg-info/SOURCES.txt +11 -0
  27. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_baselines.py +1 -1
  28. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_benchmark.py +1 -1
  29. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_cli.py +18 -13
  30. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_corpus.py +1 -1
  31. aegis_devops-0.1.3/tests/test_default_rules.py +110 -0
  32. aegis_devops-0.1.3/tests/test_hook.py +627 -0
  33. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_parsers_sql.py +1 -1
  34. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_store.py +2 -2
  35. aegis_devops-0.1.2/src/aegis_core/_examples/__pycache__/__init__.cpython-312.pyc +0 -0
  36. aegis_devops-0.1.2/src/aegis_core/_examples/constraints.example.yaml.sig +0 -2
  37. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/LICENSE +0 -0
  38. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/MANIFEST.in +0 -0
  39. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/pyproject.toml +0 -0
  40. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/setup.cfg +0 -0
  41. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/__init__.py +0 -0
  42. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/authority.example.yaml +0 -0
  43. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/authority.example.yaml.sig +0 -0
  44. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/environments.example.yaml +0 -0
  45. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/environments.example.yaml.sig +0 -0
  46. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/example-signing.key +0 -0
  47. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/plan_constraints.example.yaml +0 -0
  48. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/plan_constraints.example.yaml.sig +0 -0
  49. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/git-4001.json +0 -0
  50. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/git-789abc.json +0 -0
  51. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/git-abc123.json +0 -0
  52. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/git-bcd234.json +0 -0
  53. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/git-def456.json +0 -0
  54. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-1001.json +0 -0
  55. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-1002.json +0 -0
  56. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-2001.json +0 -0
  57. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-2002.json +0 -0
  58. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-3001.json +0 -0
  59. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-3002.json +0 -0
  60. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-3003.json +0 -0
  61. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-3004.json +0 -0
  62. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-3005.json +0 -0
  63. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-5001.json +0 -0
  64. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-5002.json +0 -0
  65. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-5003.json +0 -0
  66. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-5004.json +0 -0
  67. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/jira-5006.json +0 -0
  68. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/plan-1001.json +0 -0
  69. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/plan-1002.json +0 -0
  70. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/plan-1003.json +0 -0
  71. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/plan-1004.json +0 -0
  72. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/plan-5005.json +0 -0
  73. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/_examples/sources/slack-perma-1.json +0 -0
  74. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/adversarial.py +0 -0
  75. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/authority.py +0 -0
  76. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/baselines/base.py +0 -0
  77. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/baselines/external.py +0 -0
  78. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/config.py +0 -0
  79. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/environments.py +0 -0
  80. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/intent.py +0 -0
  81. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/interceptor.py +0 -0
  82. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/ledger.py +0 -0
  83. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/parsers/__init__.py +0 -0
  84. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/parsers/pulumi.py +0 -0
  85. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/parsers/sql.py +0 -0
  86. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/plan.py +0 -0
  87. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/provenance.py +0 -0
  88. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/signing.py +0 -0
  89. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_core/store.py +0 -0
  90. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_devops.egg-info/dependency_links.txt +0 -0
  91. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_devops.egg-info/entry_points.txt +0 -0
  92. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_devops.egg-info/requires.txt +0 -0
  93. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/src/aegis_devops.egg-info/top_level.txt +0 -0
  94. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_adversarial.py +0 -0
  95. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_authority.py +0 -0
  96. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_config.py +0 -0
  97. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_docs_consistency.py +0 -0
  98. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_environments.py +0 -0
  99. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_intent.py +0 -0
  100. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_interceptor.py +0 -0
  101. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_ledger.py +0 -0
  102. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_parser.py +0 -0
  103. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_parsers_pulumi.py +0 -0
  104. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_plan.py +0 -0
  105. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_provenance.py +0 -0
  106. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_shell.py +0 -0
  107. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/tests/test_signing.py +0 -0
  108. {aegis_devops-0.1.2 → aegis_devops-0.1.3}/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.3
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
@@ -81,7 +81,7 @@ BLOCK: kubernetes scale deployment/api-server
81
81
  citations: no-scale-prod-peak
82
82
  covered: True latency_ms: 0.20
83
83
  PLAN BLOCK: 1 intent(s)
84
- STORE: loaded=21 quarantined=0 principals=3
84
+ STORE: loaded=29 quarantined=0 principals=3
85
85
  warning: using example signing key
86
86
  ```
87
87
 
@@ -92,6 +92,20 @@ a key everyone has. `aegis init` prints the two commands that replace it with yo
92
92
  replace `constraints.example.yaml` with your own `constraints.yaml` (a real file wins over the
93
93
  `.example` one when both exist).
94
94
 
95
+ ### In your coding agent
96
+
97
+ Aegis can check every shell command Claude Code, Codex, GitHub Copilot (CLI and VS Code) or
98
+ Cursor wants to run, before it runs. In Claude Code:
99
+
100
+ ```bash
101
+ pip install aegis-devops && aegis init .aegis
102
+ claude plugin marketplace add moneytool/aegis-devops
103
+ claude plugin install aegis-devops@aegis-devops
104
+ ```
105
+
106
+ For the others, `aegis install codex|copilot|vscode|cursor`. It only acts in projects with a
107
+ `.aegis/` policy, and only blocks what that policy blocks. See [Coding agents](docs/agents.md).
108
+
95
109
  ### From a clone
96
110
 
97
111
  ```bash
@@ -207,13 +221,13 @@ v0.1.0 is on PyPI as an **alpha**. Real LLM baselines have been run: Claude Sonn
207
221
  the API (cached in `results/llm-external.md`), Haiku through the Claude Code CLI, `gpt-6-astra`
208
222
  through the Codex CLI, and a local `mistral:latest`.
209
223
 
210
- What is *not* done is the part the threat model leans on hardest. See `PLAN.md §8`, but in
224
+ What is *not* done is the part the threat model leans on hardest. See `docs/dev/PLAN.md §8`, but in
211
225
  short: sources are verified against files on disk rather than real Git/Slack/Jira connectors,
212
226
  signing uses a shared secret rather than per-principal public keys, and a `principal` is a
213
227
  signed name rather than an identity bound to a commit signature or an SSO group. Until those
214
228
  land, Aegis demonstrates that the *decision procedure* is sound; it does not yet prove the
215
229
  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
230
+ production-ready: read `docs/dev/PLAN.md §8` for the full list of open gaps before putting it in front
217
231
  of anything you care about.
218
232
 
219
233
  ## Documentation
@@ -225,10 +239,10 @@ of anything you care about.
225
239
  | [`docs/configuration.md`](docs/configuration.md) | Configuration/config-dir discovery, signing, source verification, rate limits & ledger |
226
240
  | [`docs/benchmark.md`](docs/benchmark.md) | Benchmark methodology, full results table, real LLM baselines, agent-harness baselines, corpus, adversarial suite |
227
241
  | [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) | Adding a new parser or tool |
228
- | [`PLAN.md`](PLAN.md) | Design plan and open gaps |
242
+ | [`docs/dev/PLAN.md`](docs/dev/PLAN.md) | Design plan and open gaps |
229
243
  | [`SECURITY.md`](SECURITY.md) | Reporting a bypass |
230
244
  | [`CHANGELOG.md`](CHANGELOG.md) | Release history |
231
- | [`REVIEW-4.md`](REVIEW-4.md) | Corpus/oracle rewrite (independent oracle, intent-level holdout) |
245
+ | [`docs/dev/REVIEW-4.md`](docs/dev/REVIEW-4.md) | Corpus/oracle rewrite (independent oracle, intent-level holdout) |
232
246
 
233
247
  ## Development
234
248
 
@@ -49,7 +49,7 @@ BLOCK: kubernetes scale deployment/api-server
49
49
  citations: no-scale-prod-peak
50
50
  covered: True latency_ms: 0.20
51
51
  PLAN BLOCK: 1 intent(s)
52
- STORE: loaded=21 quarantined=0 principals=3
52
+ STORE: loaded=29 quarantined=0 principals=3
53
53
  warning: using example signing key
54
54
  ```
55
55
 
@@ -60,6 +60,20 @@ a key everyone has. `aegis init` prints the two commands that replace it with yo
60
60
  replace `constraints.example.yaml` with your own `constraints.yaml` (a real file wins over the
61
61
  `.example` one when both exist).
62
62
 
63
+ ### In your coding agent
64
+
65
+ Aegis can check every shell command Claude Code, Codex, GitHub Copilot (CLI and VS Code) or
66
+ Cursor wants to run, before it runs. In Claude Code:
67
+
68
+ ```bash
69
+ pip install aegis-devops && aegis init .aegis
70
+ claude plugin marketplace add moneytool/aegis-devops
71
+ claude plugin install aegis-devops@aegis-devops
72
+ ```
73
+
74
+ For the others, `aegis install codex|copilot|vscode|cursor`. It only acts in projects with a
75
+ `.aegis/` policy, and only blocks what that policy blocks. See [Coding agents](docs/agents.md).
76
+
63
77
  ### From a clone
64
78
 
65
79
  ```bash
@@ -175,13 +189,13 @@ v0.1.0 is on PyPI as an **alpha**. Real LLM baselines have been run: Claude Sonn
175
189
  the API (cached in `results/llm-external.md`), Haiku through the Claude Code CLI, `gpt-6-astra`
176
190
  through the Codex CLI, and a local `mistral:latest`.
177
191
 
178
- What is *not* done is the part the threat model leans on hardest. See `PLAN.md §8`, but in
192
+ What is *not* done is the part the threat model leans on hardest. See `docs/dev/PLAN.md §8`, but in
179
193
  short: sources are verified against files on disk rather than real Git/Slack/Jira connectors,
180
194
  signing uses a shared secret rather than per-principal public keys, and a `principal` is a
181
195
  signed name rather than an identity bound to a commit signature or an SSO group. Until those
182
196
  land, Aegis demonstrates that the *decision procedure* is sound; it does not yet prove the
183
197
  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
198
+ production-ready: read `docs/dev/PLAN.md §8` for the full list of open gaps before putting it in front
185
199
  of anything you care about.
186
200
 
187
201
  ## Documentation
@@ -193,10 +207,10 @@ of anything you care about.
193
207
  | [`docs/configuration.md`](docs/configuration.md) | Configuration/config-dir discovery, signing, source verification, rate limits & ledger |
194
208
  | [`docs/benchmark.md`](docs/benchmark.md) | Benchmark methodology, full results table, real LLM baselines, agent-harness baselines, corpus, adversarial suite |
195
209
  | [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) | Adding a new parser or tool |
196
- | [`PLAN.md`](PLAN.md) | Design plan and open gaps |
210
+ | [`docs/dev/PLAN.md`](docs/dev/PLAN.md) | Design plan and open gaps |
197
211
  | [`SECURITY.md`](SECURITY.md) | Reporting a bypass |
198
212
  | [`CHANGELOG.md`](CHANGELOG.md) | Release history |
199
- | [`REVIEW-4.md`](REVIEW-4.md) | Corpus/oracle rewrite (independent oracle, intent-level holdout) |
213
+ | [`docs/dev/REVIEW-4.md`](docs/dev/REVIEW-4.md) | Corpus/oracle rewrite (independent oracle, intent-level holdout) |
200
214
 
201
215
  ## Development
202
216
 
@@ -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.3"
@@ -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
@@ -87,6 +87,7 @@ from datetime import UTC, datetime, timedelta
87
87
  import yaml
88
88
 
89
89
  from aegis_core import config as config_module
90
+ from aegis_core import hook as hook_module
90
91
  from aegis_core import signing
91
92
  from aegis_core.authority import load_authority_map
92
93
  from aegis_core.environments import (
@@ -449,6 +450,40 @@ def _build_parser() -> argparse.ArgumentParser:
449
450
  "--out", default="aegis-signing.key", help="path to write the key to"
450
451
  )
451
452
 
453
+ hook_parser = subparsers.add_parser(
454
+ "hook",
455
+ help="Run as a coding agent's pre-tool hook: read its JSON payload on stdin, answer "
456
+ "in its format (see 'aegis install')",
457
+ )
458
+ hook_parser.add_argument("agent", choices=hook_module.AGENTS)
459
+ hook_parser.add_argument(
460
+ "--escalate-as",
461
+ choices=("ask", "deny"),
462
+ default="ask",
463
+ help="what an ESCALATE verdict becomes: 'ask' the user (default, where the agent "
464
+ "supports it; Codex does not, so it always denies) or 'deny'",
465
+ )
466
+ hook_parser.add_argument(
467
+ "check_args",
468
+ nargs=argparse.REMAINDER,
469
+ help="extra 'aegis check command' options after --, e.g. -- --fail-closed",
470
+ )
471
+
472
+ install_parser = subparsers.add_parser(
473
+ "install", help="Register 'aegis hook' in a coding agent's hook config"
474
+ )
475
+ install_parser.add_argument("agent", choices=hook_module.AGENTS)
476
+ scope = install_parser.add_mutually_exclusive_group()
477
+ scope.add_argument(
478
+ "--user", action="store_true", help="install for every project (the user's config)"
479
+ )
480
+ scope.add_argument(
481
+ "--project", default=".", help="project directory to install into (default: .)"
482
+ )
483
+ install_parser.add_argument(
484
+ "--remove", action="store_true", help="remove the aegis hook instead"
485
+ )
486
+
452
487
  return parser
453
488
 
454
489
 
@@ -1000,6 +1035,16 @@ def _run(argv: list[str]) -> int:
1000
1035
  return _run_init(args)
1001
1036
  if args.command == "keygen":
1002
1037
  return _run_keygen(args)
1038
+ if args.command == "hook":
1039
+ return hook_module.main_hook(
1040
+ args.agent,
1041
+ escalate_as=args.escalate_as,
1042
+ extra_args=_strip_leading_separator(args.check_args),
1043
+ )
1044
+ if args.command == "install":
1045
+ return hook_module.main_install(
1046
+ args.agent, user=args.user, project=args.project, remove=args.remove
1047
+ )
1003
1048
  if args.command != "check":
1004
1049
  raise UsageError("unknown command")
1005
1050