aegis-devops 0.3.1__tar.gz → 1.0.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.
- {aegis_devops-0.3.1/src/aegis_devops.egg-info → aegis_devops-1.0.0}/PKG-INFO +83 -19
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/README.md +80 -17
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/pyproject.toml +3 -2
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/__init__.py +1 -1
- aegis_devops-1.0.0/src/aegis_core/_examples/__pycache__/__init__.cpython-312.pyc +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/agents.example.yaml +3 -0
- aegis_devops-1.0.0/src/aegis_core/_examples/agents.example.yaml.sig +2 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/authority.example.yaml +1 -0
- aegis_devops-1.0.0/src/aegis_core/_examples/authority.example.yaml.sig +2 -0
- aegis_devops-1.0.0/src/aegis_core/_examples/budget.example.yaml +21 -0
- aegis_devops-1.0.0/src/aegis_core/_examples/budget.example.yaml.sig +2 -0
- aegis_devops-1.0.0/src/aegis_core/budget/__init__.py +27 -0
- aegis_devops-1.0.0/src/aegis_core/budget/accounting.py +693 -0
- aegis_devops-1.0.0/src/aegis_core/budget/evaluate.py +259 -0
- aegis_devops-1.0.0/src/aegis_core/budget/gate.py +124 -0
- aegis_devops-1.0.0/src/aegis_core/budget/logs.py +678 -0
- aegis_devops-1.0.0/src/aegis_core/budget/policy.py +235 -0
- aegis_devops-1.0.0/src/aegis_core/budget/prices.json +282 -0
- aegis_devops-1.0.0/src/aegis_core/budget/prices.yaml +77 -0
- aegis_devops-1.0.0/src/aegis_core/budget/pricing.py +186 -0
- aegis_devops-1.0.0/src/aegis_core/budget/report.py +205 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/cli.py +175 -2
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/environments.py +98 -28
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/hook.py +208 -42
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/identity.py +17 -3
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/integrations/opencode-plugin.js +51 -12
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/interceptor.py +30 -6
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/parser.py +11 -3
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/store.py +99 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0/src/aegis_devops.egg-info}/PKG-INFO +83 -19
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_devops.egg-info/SOURCES.txt +19 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_adversarial.py +14 -12
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_authority.py +2 -2
- aegis_devops-1.0.0/tests/test_budget_accounting.py +492 -0
- aegis_devops-1.0.0/tests/test_budget_cli.py +247 -0
- aegis_devops-1.0.0/tests/test_budget_evaluate.py +130 -0
- aegis_devops-1.0.0/tests/test_budget_hook.py +274 -0
- aegis_devops-1.0.0/tests/test_budget_logs.py +365 -0
- aegis_devops-1.0.0/tests/test_budget_policy.py +304 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_docs_consistency.py +31 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_environments.py +47 -1
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_identity.py +36 -0
- aegis_devops-1.0.0/tests/test_kubectl_namespace_and_manifests.py +222 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_opencode_plugin.py +37 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_parser.py +7 -5
- aegis_devops-1.0.0/tests/test_plugins.py +253 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_signing.py +2 -1
- aegis_devops-0.3.1/src/aegis_core/_examples/__pycache__/__init__.cpython-312.pyc +0 -0
- aegis_devops-0.3.1/src/aegis_core/_examples/agents.example.yaml.sig +0 -2
- aegis_devops-0.3.1/src/aegis_core/_examples/authority.example.yaml.sig +0 -2
- aegis_devops-0.3.1/tests/test_plugins.py +0 -112
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/LICENSE +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/MANIFEST.in +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/setup.cfg +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/__init__.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/constraints.example.yaml +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/constraints.example.yaml.sig +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/environments.example.yaml +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/environments.example.yaml.sig +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/example-signing.key +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/plan_constraints.example.yaml +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/plan_constraints.example.yaml.sig +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/repos.example.yaml +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/repos.example.yaml.sig +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/signers.example.yaml +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/signers.example.yaml.sig +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/AEGIS-MANIFEST.sig +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/PRINCIPALS.yaml +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-4001.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-6001.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-6002.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-6003.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-6004.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-6005.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-6006.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-6007.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-6008.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-6009.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-789abc.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-abc123.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-bcd234.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/git-def456.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-1001.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-1002.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-2001.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-2002.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-3001.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-3002.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-3003.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-3004.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-3005.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-5001.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-5002.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-5003.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-5004.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/jira-5006.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/plan-1001.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/plan-1002.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/plan-1003.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/plan-1004.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/plan-5005.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/_examples/sources/slack-perma-1.json +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/adversarial.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/audit_aws.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/audit_kubernetes.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/authority.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/baselines/__init__.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/baselines/base.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/baselines/external.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/baselines/llm.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/baselines/metrics.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/baselines/opa.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/compile/__init__.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/compile/actions/aws.yaml +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/compile/aws.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/compile/kubernetes.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/config.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/gitsource.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/intent.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/ledger.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/parsers/__init__.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/parsers/pulumi.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/parsers/sql.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/plan.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/provenance.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/shell.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_core/signing.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_devops.egg-info/dependency_links.txt +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_devops.egg-info/entry_points.txt +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_devops.egg-info/requires.txt +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/src/aegis_devops.egg-info/top_level.txt +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_audit_aws.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_audit_kubernetes.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_baselines.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_benchmark.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_cli.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_compile_aws.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_compile_kubernetes.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_config.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_corpus.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_default_rules.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_gitsource.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_hook.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_intent.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_interceptor.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_ledger.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_parsers_pulumi.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_parsers_sql.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_plan.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_provenance.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_shell.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_snapshot.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_store.py +0 -0
- {aegis_devops-0.3.1 → aegis_devops-1.0.0}/tests/test_store_match.py +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aegis-devops
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Provenance-backed, authority-aware policy verifier for agentic DevOps actions.
|
|
5
|
+
Author: Vamshidher Reddy Jannapu Reddy
|
|
5
6
|
License-Expression: Apache-2.0
|
|
6
7
|
Project-URL: Homepage, https://github.com/moneytool/aegis-devops
|
|
7
8
|
Project-URL: Repository, https://github.com/moneytool/aegis-devops
|
|
8
9
|
Keywords: agentops,agent-security,policy-as-code,provenance,kubernetes,terraform,guardrails,prompt-injection,context-poisoning
|
|
9
|
-
Classifier: Development Status ::
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
11
|
Classifier: Environment :: Console
|
|
11
12
|
Classifier: Intended Audience :: System Administrators
|
|
12
13
|
Classifier: Intended Audience :: Developers
|
|
@@ -45,30 +46,43 @@ become policy.
|
|
|
45
46
|
|
|
46
47
|

|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
## Try it in 60 seconds
|
|
50
|
+
|
|
51
|
+
**1. Watch it block a pull request (nothing to install).** Open the demo's
|
|
52
|
+
[example PR](https://github.com/moneytool/aegis-devops-demo/pull/1): it deletes a production
|
|
53
|
+
database, and the failing check is Aegis blocking it, with the verdict posted as a comment. Fork
|
|
54
|
+
the [demo repository](https://github.com/moneytool/aegis-devops-demo) to try your own change; no
|
|
55
|
+
cloud account needed.
|
|
56
|
+
|
|
57
|
+
**2. Check a command yourself:**
|
|
49
58
|
|
|
50
59
|
```bash
|
|
51
60
|
pip install aegis-devops && aegis init .aegis
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
aegis check command --pretty -- "kubectl delete namespace prod" # BLOCK (exit 3)
|
|
62
|
+
aegis check command --pretty -- "kubectl get pods -n prod" # ALLOW (exit 0)
|
|
54
63
|
```
|
|
55
64
|
|
|
56
|
-
|
|
65
|
+
**3. Put it in front of your coding agent.** In the same project:
|
|
57
66
|
|
|
58
67
|
```bash
|
|
59
|
-
|
|
60
|
-
|
|
68
|
+
claude plugin marketplace add moneytool/aegis-devops
|
|
69
|
+
claude plugin install aegis-devops@aegis-devops
|
|
61
70
|
```
|
|
62
71
|
|
|
63
|
-
|
|
64
|
-
`
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
[
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
Then ask Claude Code to delete the `prod` namespace: the hook blocks the command before it runs.
|
|
73
|
+
Gemini CLI: `gemini extensions install https://github.com/moneytool/aegis-devops`. Codex, GitHub
|
|
74
|
+
Copilot (CLI and VS Code), Cursor and OpenCode: `aegis install codex|copilot|vscode|cursor|opencode`
|
|
75
|
+
(see [Coding agents](docs/agents.md)). Aegis only acts in projects with a `.aegis/` policy, and
|
|
76
|
+
only blocks what that policy blocks. `aegis init` writes example rules signed with a public
|
|
77
|
+
example key; replace both before relying on it ([Configuration](docs/configuration.md)). It
|
|
78
|
+
works alongside RBAC and your agent's own permission settings; see
|
|
79
|
+
[Why not RBAC](#why-not-rbac-or-the-agents-own-permission-settings).
|
|
80
|
+
|
|
81
|
+
In CI, the [Aegis-DevOps Plan Check](https://github.com/marketplace/actions/aegis-devops-plan-check)
|
|
82
|
+
Action checks a Terraform or OpenTofu plan on every pull request
|
|
83
|
+
(`uses: moneytool/aegis-devops-action@v1` with `plan: plan.json`); `aegis check terraform
|
|
84
|
+
plan.json --exit-style ci` does the same in any pipeline, and Aegis also works as a Python
|
|
85
|
+
library ([Quick start](#quick-start)).
|
|
72
86
|
|
|
73
87
|
## What it does
|
|
74
88
|
|
|
@@ -225,6 +239,45 @@ about who wrote a rule, but it cannot recompute a hash or fetch a source. Up to
|
|
|
225
239
|
rows were scored against all 500 rules, which counted rules the models never saw as resisted
|
|
226
240
|
poison and understated their susceptibility (0.23–0.33); see [`CHANGELOG.md`](CHANGELOG.md).
|
|
227
241
|
|
|
242
|
+
## Why not RBAC, or the agent's own permission settings?
|
|
243
|
+
|
|
244
|
+
Keep both. Aegis sits alongside them; it doesn't replace either.
|
|
245
|
+
|
|
246
|
+
**Agent permission settings** (Claude Code's allow/deny rules, Copilot's tool approvals and
|
|
247
|
+
similar) decide which commands an agent may run without asking you. They match the command
|
|
248
|
+
text. Claude Code's documentation says a Bash deny rule ["isn't a security boundary around the
|
|
249
|
+
program"](https://code.claude.com/docs/en/permissions#bash-rule-limits), and recommends a
|
|
250
|
+
PreToolUse hook when you need to inspect the full command before it runs. Aegis is that hook. It
|
|
251
|
+
works out what the command will do, so every spelling of the same action reaches the same rule:
|
|
252
|
+
|
|
253
|
+
| Command the agent writes | Aegis with the example policy |
|
|
254
|
+
|---|---|
|
|
255
|
+
| `kubectl delete deploy web -n prod` | BLOCK (`no-delete-in-prod-namespace`) |
|
|
256
|
+
| `kubectl -n prod delete deploy web` | BLOCK, same rule |
|
|
257
|
+
| `/usr/bin/kubectl …`, `sudo kubectl …`, `env kubectl …` | BLOCK, same rule |
|
|
258
|
+
| `bash -c 'kubectl delete deploy web -n prod'` | BLOCK, same rule |
|
|
259
|
+
| `cd /tmp && kubectl delete deploy web -n prod` | BLOCK, same rule |
|
|
260
|
+
| `git -C . push --force origin main` | BLOCK (`git-block-force-push-main`) |
|
|
261
|
+
| `K=kubectl; $K delete deploy web -n prod` | Refused: it can't be checked statically, so the hook denies it and asks for the command on its own |
|
|
262
|
+
|
|
263
|
+
Permission settings also record *what* is allowed, not who decided it. An Aegis rule only gets a
|
|
264
|
+
vote if nobody has changed it since it was signed and its author was allowed to write that kind
|
|
265
|
+
of rule.
|
|
266
|
+
|
|
267
|
+
**RBAC and IAM** decide what an identity may do. A coding agent usually runs with the
|
|
268
|
+
developer's own kubeconfig and cloud credentials, so RBAC sees the developer and grants the
|
|
269
|
+
agent the same rights. Aegis decides each action against the policy: no deletes in the `prod`
|
|
270
|
+
namespace, no `kubectl --as` impersonation, no plan that deletes a database. Once agents do have
|
|
271
|
+
their own identities, the same policy compiles into the platform layer, so it holds even for
|
|
272
|
+
calls that never pass through the hook (an SDK script, a leaked key):
|
|
273
|
+
|
|
274
|
+
- `aegis compile aws`: Service Control Policies scoped to agent identities.
|
|
275
|
+
- `aegis compile kubernetes`: ValidatingAdmissionPolicies scoped to agent identities, plus
|
|
276
|
+
`aegis audit-identity kubernetes` to report the RBAC permissions that would let an agent get
|
|
277
|
+
around them (impersonation, editing admission policies, RBAC escalation).
|
|
278
|
+
|
|
279
|
+
Both are previews; see [server-side enforcement](docs/server-side.md).
|
|
280
|
+
|
|
228
281
|
## Why not OPA/Gatekeeper?
|
|
229
282
|
|
|
230
283
|
OPA/Gatekeeper evaluates **structured API objects** against **hand-authored rules**. Aegis
|
|
@@ -255,7 +308,11 @@ context a rule can arrive from a ticket or a chat message as easily as from you.
|
|
|
255
308
|
|
|
256
309
|
The engine (constraint store, interceptor, environment mapping, dry-run handling, rate limits,
|
|
257
310
|
plan-level constraints, and parsers for every tool in "Supported tools") is complete, and
|
|
258
|
-
|
|
311
|
+
v1.0.0 is on PyPI, with the [session budget cap](docs/budget.md). **1.0 is a promise about the
|
|
312
|
+
interface:** the policy file formats, the CLI commands and exit codes, the hook protocol and the
|
|
313
|
+
Action's inputs and outputs stay compatible until 2.0; the server-side compilers and the
|
|
314
|
+
identity audit remain previews ([CHANGELOG](CHANGELOG.md)). It is not a claim that the open gaps
|
|
315
|
+
below are closed. Real LLM baselines have been run: Claude Sonnet 5 through
|
|
259
316
|
the API (cached in `results/llm-external.md`), Haiku through the Claude Code CLI, `gpt-6-astra`
|
|
260
317
|
through the Codex CLI, and a local `mistral:latest`.
|
|
261
318
|
|
|
@@ -278,6 +335,7 @@ of anything you care about.
|
|
|
278
335
|
| [`docs/constraints.md`](docs/constraints.md) | Writing constraints, metadata vocabulary, authority policy, environment mapping |
|
|
279
336
|
| [`docs/configuration.md`](docs/configuration.md) | Configuration/config-dir discovery, signing, source verification, the identity model (`agents.yaml`), rate limits & ledger |
|
|
280
337
|
| [`docs/server-side.md`](docs/server-side.md) | Preview: compiling the policy to AWS Service Control Policies scoped to agent identities |
|
|
338
|
+
| [`docs/budget.md`](docs/budget.md) | The session budget cap: per-session and per-project-per-day limits in estimated USD or tokens, across Claude Code, Codex, Gemini CLI, OpenCode and Copilot CLI |
|
|
281
339
|
| [`docs/benchmark.md`](docs/benchmark.md) | Benchmark methodology, full results table, real LLM baselines, agent-harness baselines, corpus, adversarial suite |
|
|
282
340
|
| [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) | Adding a new parser or tool |
|
|
283
341
|
| [`docs/dev/PLAN.md`](docs/dev/PLAN.md) | Design plan and open gaps |
|
|
@@ -288,7 +346,7 @@ of anything you care about.
|
|
|
288
346
|
## Development
|
|
289
347
|
|
|
290
348
|
```bash
|
|
291
|
-
venv/bin/python -m pytest -q #
|
|
349
|
+
venv/bin/python -m pytest -q # 1,791 passed (CI runs this on 3.11/3.13/3.14, Linux and macOS)
|
|
292
350
|
venv/bin/python -m ruff check src tests scripts examples
|
|
293
351
|
vhs docs/demo.tape # regenerate docs/demo.gif
|
|
294
352
|
```
|
|
@@ -298,6 +356,12 @@ Reporting a bypass: see [`SECURITY.md`](SECURITY.md) — parser evasion is the l
|
|
|
298
356
|
attack surface and the most useful thing to report. Release history is in
|
|
299
357
|
[`CHANGELOG.md`](CHANGELOG.md).
|
|
300
358
|
|
|
359
|
+
## Support
|
|
360
|
+
|
|
361
|
+
If Aegis-DevOps is useful to you, a ⭐ on [GitHub](https://github.com/moneytool/aegis-devops)
|
|
362
|
+
helps other people find it. Bug reports, ideas and bypasses are welcome too: open an issue, or
|
|
363
|
+
see [`SECURITY.md`](SECURITY.md) for anything that gets a blocked command through.
|
|
364
|
+
|
|
301
365
|
## License
|
|
302
366
|
|
|
303
367
|
Apache-2.0 — see [LICENSE](LICENSE).
|
|
@@ -13,30 +13,43 @@ become policy.
|
|
|
13
13
|
|
|
14
14
|

|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
## Try it in 60 seconds
|
|
17
|
+
|
|
18
|
+
**1. Watch it block a pull request (nothing to install).** Open the demo's
|
|
19
|
+
[example PR](https://github.com/moneytool/aegis-devops-demo/pull/1): it deletes a production
|
|
20
|
+
database, and the failing check is Aegis blocking it, with the verdict posted as a comment. Fork
|
|
21
|
+
the [demo repository](https://github.com/moneytool/aegis-devops-demo) to try your own change; no
|
|
22
|
+
cloud account needed.
|
|
23
|
+
|
|
24
|
+
**2. Check a command yourself:**
|
|
17
25
|
|
|
18
26
|
```bash
|
|
19
27
|
pip install aegis-devops && aegis init .aegis
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
aegis check command --pretty -- "kubectl delete namespace prod" # BLOCK (exit 3)
|
|
29
|
+
aegis check command --pretty -- "kubectl get pods -n prod" # ALLOW (exit 0)
|
|
22
30
|
```
|
|
23
31
|
|
|
24
|
-
|
|
32
|
+
**3. Put it in front of your coding agent.** In the same project:
|
|
25
33
|
|
|
26
34
|
```bash
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
claude plugin marketplace add moneytool/aegis-devops
|
|
36
|
+
claude plugin install aegis-devops@aegis-devops
|
|
29
37
|
```
|
|
30
38
|
|
|
31
|
-
|
|
32
|
-
`
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
[
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
Then ask Claude Code to delete the `prod` namespace: the hook blocks the command before it runs.
|
|
40
|
+
Gemini CLI: `gemini extensions install https://github.com/moneytool/aegis-devops`. Codex, GitHub
|
|
41
|
+
Copilot (CLI and VS Code), Cursor and OpenCode: `aegis install codex|copilot|vscode|cursor|opencode`
|
|
42
|
+
(see [Coding agents](docs/agents.md)). Aegis only acts in projects with a `.aegis/` policy, and
|
|
43
|
+
only blocks what that policy blocks. `aegis init` writes example rules signed with a public
|
|
44
|
+
example key; replace both before relying on it ([Configuration](docs/configuration.md)). It
|
|
45
|
+
works alongside RBAC and your agent's own permission settings; see
|
|
46
|
+
[Why not RBAC](#why-not-rbac-or-the-agents-own-permission-settings).
|
|
47
|
+
|
|
48
|
+
In CI, the [Aegis-DevOps Plan Check](https://github.com/marketplace/actions/aegis-devops-plan-check)
|
|
49
|
+
Action checks a Terraform or OpenTofu plan on every pull request
|
|
50
|
+
(`uses: moneytool/aegis-devops-action@v1` with `plan: plan.json`); `aegis check terraform
|
|
51
|
+
plan.json --exit-style ci` does the same in any pipeline, and Aegis also works as a Python
|
|
52
|
+
library ([Quick start](#quick-start)).
|
|
40
53
|
|
|
41
54
|
## What it does
|
|
42
55
|
|
|
@@ -193,6 +206,45 @@ about who wrote a rule, but it cannot recompute a hash or fetch a source. Up to
|
|
|
193
206
|
rows were scored against all 500 rules, which counted rules the models never saw as resisted
|
|
194
207
|
poison and understated their susceptibility (0.23–0.33); see [`CHANGELOG.md`](CHANGELOG.md).
|
|
195
208
|
|
|
209
|
+
## Why not RBAC, or the agent's own permission settings?
|
|
210
|
+
|
|
211
|
+
Keep both. Aegis sits alongside them; it doesn't replace either.
|
|
212
|
+
|
|
213
|
+
**Agent permission settings** (Claude Code's allow/deny rules, Copilot's tool approvals and
|
|
214
|
+
similar) decide which commands an agent may run without asking you. They match the command
|
|
215
|
+
text. Claude Code's documentation says a Bash deny rule ["isn't a security boundary around the
|
|
216
|
+
program"](https://code.claude.com/docs/en/permissions#bash-rule-limits), and recommends a
|
|
217
|
+
PreToolUse hook when you need to inspect the full command before it runs. Aegis is that hook. It
|
|
218
|
+
works out what the command will do, so every spelling of the same action reaches the same rule:
|
|
219
|
+
|
|
220
|
+
| Command the agent writes | Aegis with the example policy |
|
|
221
|
+
|---|---|
|
|
222
|
+
| `kubectl delete deploy web -n prod` | BLOCK (`no-delete-in-prod-namespace`) |
|
|
223
|
+
| `kubectl -n prod delete deploy web` | BLOCK, same rule |
|
|
224
|
+
| `/usr/bin/kubectl …`, `sudo kubectl …`, `env kubectl …` | BLOCK, same rule |
|
|
225
|
+
| `bash -c 'kubectl delete deploy web -n prod'` | BLOCK, same rule |
|
|
226
|
+
| `cd /tmp && kubectl delete deploy web -n prod` | BLOCK, same rule |
|
|
227
|
+
| `git -C . push --force origin main` | BLOCK (`git-block-force-push-main`) |
|
|
228
|
+
| `K=kubectl; $K delete deploy web -n prod` | Refused: it can't be checked statically, so the hook denies it and asks for the command on its own |
|
|
229
|
+
|
|
230
|
+
Permission settings also record *what* is allowed, not who decided it. An Aegis rule only gets a
|
|
231
|
+
vote if nobody has changed it since it was signed and its author was allowed to write that kind
|
|
232
|
+
of rule.
|
|
233
|
+
|
|
234
|
+
**RBAC and IAM** decide what an identity may do. A coding agent usually runs with the
|
|
235
|
+
developer's own kubeconfig and cloud credentials, so RBAC sees the developer and grants the
|
|
236
|
+
agent the same rights. Aegis decides each action against the policy: no deletes in the `prod`
|
|
237
|
+
namespace, no `kubectl --as` impersonation, no plan that deletes a database. Once agents do have
|
|
238
|
+
their own identities, the same policy compiles into the platform layer, so it holds even for
|
|
239
|
+
calls that never pass through the hook (an SDK script, a leaked key):
|
|
240
|
+
|
|
241
|
+
- `aegis compile aws`: Service Control Policies scoped to agent identities.
|
|
242
|
+
- `aegis compile kubernetes`: ValidatingAdmissionPolicies scoped to agent identities, plus
|
|
243
|
+
`aegis audit-identity kubernetes` to report the RBAC permissions that would let an agent get
|
|
244
|
+
around them (impersonation, editing admission policies, RBAC escalation).
|
|
245
|
+
|
|
246
|
+
Both are previews; see [server-side enforcement](docs/server-side.md).
|
|
247
|
+
|
|
196
248
|
## Why not OPA/Gatekeeper?
|
|
197
249
|
|
|
198
250
|
OPA/Gatekeeper evaluates **structured API objects** against **hand-authored rules**. Aegis
|
|
@@ -223,7 +275,11 @@ context a rule can arrive from a ticket or a chat message as easily as from you.
|
|
|
223
275
|
|
|
224
276
|
The engine (constraint store, interceptor, environment mapping, dry-run handling, rate limits,
|
|
225
277
|
plan-level constraints, and parsers for every tool in "Supported tools") is complete, and
|
|
226
|
-
|
|
278
|
+
v1.0.0 is on PyPI, with the [session budget cap](docs/budget.md). **1.0 is a promise about the
|
|
279
|
+
interface:** the policy file formats, the CLI commands and exit codes, the hook protocol and the
|
|
280
|
+
Action's inputs and outputs stay compatible until 2.0; the server-side compilers and the
|
|
281
|
+
identity audit remain previews ([CHANGELOG](CHANGELOG.md)). It is not a claim that the open gaps
|
|
282
|
+
below are closed. Real LLM baselines have been run: Claude Sonnet 5 through
|
|
227
283
|
the API (cached in `results/llm-external.md`), Haiku through the Claude Code CLI, `gpt-6-astra`
|
|
228
284
|
through the Codex CLI, and a local `mistral:latest`.
|
|
229
285
|
|
|
@@ -246,6 +302,7 @@ of anything you care about.
|
|
|
246
302
|
| [`docs/constraints.md`](docs/constraints.md) | Writing constraints, metadata vocabulary, authority policy, environment mapping |
|
|
247
303
|
| [`docs/configuration.md`](docs/configuration.md) | Configuration/config-dir discovery, signing, source verification, the identity model (`agents.yaml`), rate limits & ledger |
|
|
248
304
|
| [`docs/server-side.md`](docs/server-side.md) | Preview: compiling the policy to AWS Service Control Policies scoped to agent identities |
|
|
305
|
+
| [`docs/budget.md`](docs/budget.md) | The session budget cap: per-session and per-project-per-day limits in estimated USD or tokens, across Claude Code, Codex, Gemini CLI, OpenCode and Copilot CLI |
|
|
249
306
|
| [`docs/benchmark.md`](docs/benchmark.md) | Benchmark methodology, full results table, real LLM baselines, agent-harness baselines, corpus, adversarial suite |
|
|
250
307
|
| [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) | Adding a new parser or tool |
|
|
251
308
|
| [`docs/dev/PLAN.md`](docs/dev/PLAN.md) | Design plan and open gaps |
|
|
@@ -256,7 +313,7 @@ of anything you care about.
|
|
|
256
313
|
## Development
|
|
257
314
|
|
|
258
315
|
```bash
|
|
259
|
-
venv/bin/python -m pytest -q #
|
|
316
|
+
venv/bin/python -m pytest -q # 1,791 passed (CI runs this on 3.11/3.13/3.14, Linux and macOS)
|
|
260
317
|
venv/bin/python -m ruff check src tests scripts examples
|
|
261
318
|
vhs docs/demo.tape # regenerate docs/demo.gif
|
|
262
319
|
```
|
|
@@ -266,6 +323,12 @@ Reporting a bypass: see [`SECURITY.md`](SECURITY.md) — parser evasion is the l
|
|
|
266
323
|
attack surface and the most useful thing to report. Release history is in
|
|
267
324
|
[`CHANGELOG.md`](CHANGELOG.md).
|
|
268
325
|
|
|
326
|
+
## Support
|
|
327
|
+
|
|
328
|
+
If Aegis-DevOps is useful to you, a ⭐ on [GitHub](https://github.com/moneytool/aegis-devops)
|
|
329
|
+
helps other people find it. Bug reports, ideas and bypasses are welcome too: open an issue, or
|
|
330
|
+
see [`SECURITY.md`](SECURITY.md) for anything that gets a blocked command through.
|
|
331
|
+
|
|
269
332
|
## License
|
|
270
333
|
|
|
271
334
|
Apache-2.0 — see [LICENSE](LICENSE).
|
|
@@ -7,6 +7,7 @@ name = "aegis-devops"
|
|
|
7
7
|
license = "Apache-2.0"
|
|
8
8
|
dynamic = ["version"]
|
|
9
9
|
description = "Provenance-backed, authority-aware policy verifier for agentic DevOps actions."
|
|
10
|
+
authors = [{ name = "Vamshidher Reddy Jannapu Reddy" }]
|
|
10
11
|
readme = "README.md"
|
|
11
12
|
requires-python = ">=3.11"
|
|
12
13
|
dependencies = [
|
|
@@ -24,7 +25,7 @@ keywords = [
|
|
|
24
25
|
"context-poisoning",
|
|
25
26
|
]
|
|
26
27
|
classifiers = [
|
|
27
|
-
"Development Status ::
|
|
28
|
+
"Development Status :: 4 - Beta",
|
|
28
29
|
"Environment :: Console",
|
|
29
30
|
"Intended Audience :: System Administrators",
|
|
30
31
|
"Intended Audience :: Developers",
|
|
@@ -62,7 +63,7 @@ version = {attr = "aegis_core.__version__"}
|
|
|
62
63
|
where = ["src"]
|
|
63
64
|
|
|
64
65
|
[tool.setuptools.package-data]
|
|
65
|
-
aegis_core = ["_examples/**/*", "integrations/*", "compile/actions/*"]
|
|
66
|
+
aegis_core = ["_examples/**/*", "integrations/*", "compile/actions/*", "budget/*.yaml", "budget/*.json"]
|
|
66
67
|
|
|
67
68
|
[tool.ruff]
|
|
68
69
|
line-length = 100
|
|
@@ -34,6 +34,9 @@ trusted:
|
|
|
34
34
|
- platform: aws
|
|
35
35
|
kind: source-identity
|
|
36
36
|
id: alice@example.com
|
|
37
|
+
# A source identity survives role chaining, so an agent started in alice's session would
|
|
38
|
+
# carry it and be exempt. Trust one only if no agent ever runs under it, and say so:
|
|
39
|
+
no_agents: true
|
|
37
40
|
- platform: github
|
|
38
41
|
kind: oidc-subject
|
|
39
42
|
# bound to one reusable workflow at a protected ref, so an agent job in the same
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# The session budget cap (docs/budget.md). Copy to budget.yaml, set your own limits, and sign
|
|
2
|
+
# it with `aegis sign`; its principal must hold the 'budget' class in authority.yaml. Until
|
|
3
|
+
# it is named budget.yaml it does nothing. Then reinstall your agents' hooks (`aegis install
|
|
4
|
+
# <agent>`) so they see every tool call, and check with: aegis budget status
|
|
5
|
+
version: 1
|
|
6
|
+
principal: admin # must hold the 'budget' class in authority.yaml
|
|
7
|
+
unit: usd # usd (estimated from list prices) | tokens; required
|
|
8
|
+
session:
|
|
9
|
+
limit: 20 # per agent session
|
|
10
|
+
warn_at: 0.8 # warn once at 80%
|
|
11
|
+
project_day:
|
|
12
|
+
limit: 100 # every measured session in this project, per day
|
|
13
|
+
warn_at: 0.8
|
|
14
|
+
tz: UTC # the day boundary
|
|
15
|
+
agents: [claude, codex, gemini, opencode, copilot] # only listed agents are measured
|
|
16
|
+
on_unknown_log: allow # allow (warn) | deny: usage Aegis cannot verify
|
|
17
|
+
on_unknown_price: estimate # estimate (warn) | deny: models with no price
|
|
18
|
+
pricing: {} # signed overrides, USD per million tokens:
|
|
19
|
+
# claude-opus-5-5: {input: 4, output: 20, cache_read: 0.2, cache_write: 8}
|
|
20
|
+
copilot:
|
|
21
|
+
premium_requests: 50 # Copilot CLI reports premium requests, not tokens
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Cross-agent session budget cap (design: docs/dev/DESIGN-v1.0-budget-cap.md).
|
|
2
|
+
|
|
3
|
+
* :mod:`~aegis_core.budget.policy` -- the signed ``budget.yaml``;
|
|
4
|
+
* :mod:`~aegis_core.budget.pricing` -- tokens to estimated dollars;
|
|
5
|
+
* :mod:`~aegis_core.budget.logs` -- reading usage from each agent's logs;
|
|
6
|
+
* :mod:`~aegis_core.budget.accounting` -- session records, project/day
|
|
7
|
+
totals, revisions, locks, the inventory and rebuilds;
|
|
8
|
+
* :mod:`~aegis_core.budget.evaluate` -- allow / warn / deny.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from aegis_core.budget.accounting import BudgetStore, Snapshot, rebuild, refresh
|
|
12
|
+
from aegis_core.budget.evaluate import ALLOW, DENY, WARN, Verdict, evaluate
|
|
13
|
+
from aegis_core.budget.logs import Locator, default_logs
|
|
14
|
+
from aegis_core.budget.policy import BUDGET_CLASS, BUDGET_FILE, BudgetPolicy, load_budget_policy
|
|
15
|
+
from aegis_core.budget.pricing import PriceTable, load_builtin_table
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def price_table(policy: BudgetPolicy) -> PriceTable:
|
|
19
|
+
"""The built-in prices with the policy's signed overrides."""
|
|
20
|
+
return PriceTable(load_builtin_table(), policy.pricing)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"ALLOW", "BUDGET_CLASS", "BUDGET_FILE", "DENY", "WARN", "BudgetPolicy", "BudgetStore",
|
|
25
|
+
"Locator", "PriceTable", "Snapshot", "Verdict", "default_logs", "evaluate",
|
|
26
|
+
"load_budget_policy", "load_builtin_table", "price_table", "rebuild", "refresh",
|
|
27
|
+
]
|