agentsecure 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.
- {agentsecure-0.1.2/agentsecure.egg-info → agentsecure-0.1.4}/PKG-INFO +66 -5
- {agentsecure-0.1.2 → agentsecure-0.1.4}/README.md +64 -2
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/__init__.py +1 -2
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/cli/main.py +76 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/cli/policy.py +8 -1
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/cli/project.py +9 -0
- agentsecure-0.1.4/agentsecure/cli/proxy.py +283 -0
- agentsecure-0.1.4/agentsecure/cli/receipts.py +207 -0
- agentsecure-0.1.4/agentsecure/config/__init__.py +1 -0
- agentsecure-0.1.4/agentsecure/config/default_agentsecure.json +49 -0
- agentsecure-0.1.4/agentsecure/core/agentsecure_md.py +188 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/config.py +113 -4
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/container.py +1 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/key_service.py +2 -19
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/models.py +18 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/product.py +23 -35
- agentsecure-0.1.4/agentsecure/core/provider_proxy.py +23 -0
- agentsecure-0.1.4/agentsecure/gateway/proxy.py +587 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4/agentsecure.egg-info}/PKG-INFO +66 -5
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure.egg-info/SOURCES.txt +11 -1
- {agentsecure-0.1.2 → agentsecure-0.1.4}/setup.cfg +7 -4
- agentsecure-0.1.4/tests/test_agentsecure_md.py +66 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_cli.py +30 -0
- agentsecure-0.1.4/tests/test_cli_proxy.py +116 -0
- agentsecure-0.1.4/tests/test_config_validation.py +81 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_product.py +8 -0
- agentsecure-0.1.4/tests/test_provider_proxy.py +277 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_secret_scan.py +11 -0
- agentsecure-0.1.4/tests/test_version.py +24 -0
- agentsecure-0.1.2/agentsecure/gateway/proxy.py +0 -272
- agentsecure-0.1.2/agentsecure.egg-info/requires.txt +0 -3
- {agentsecure-0.1.2 → agentsecure-0.1.4}/LICENSE +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/NOTICE +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/__main__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/api/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/api/server.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/api/services.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/cli/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/cli/common.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/cli/demo.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/cli/secrets.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/cli/settings.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/client/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/client/wrappers.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/cloud.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/capabilities.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/command_metadata.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/config_profiles.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/policy_mutation.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/policy_ports.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/policy_response.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/policy_validation.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/core/time.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/crypto/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/crypto/cipher.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/crypto/key_provider.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/daemon/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/daemon/commands.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/daemon/policies.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/daemon/sessions.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/daemon/supervisor.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/discovery/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/discovery/dotenv_scanner.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/discovery/env_scanner.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/discovery/patterns.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/discovery/scanner.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/discovery/suggestions.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/gateway/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/guard/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/guard/command.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/guard/network.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/guard/sanitizer.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/guard/wrappers.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/implementations/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/implementations/audit.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/implementations/encrypted_secret_store.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/implementations/grant_store.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/implementations/local_secret_store.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/implementations/policy.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/implementations/secret_store_factory.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/implementations/secrets.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/interfaces/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/interfaces/audit.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/interfaces/grants.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/interfaces/key_store.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/interfaces/policy.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/interfaces/secrets.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/workspace/__init__.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/workspace/apply.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/workspace/diff.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/workspace/materializer.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/workspace/rewriter.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure/workspace/strategies.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure.egg-info/dependency_links.txt +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure.egg-info/entry_points.txt +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/agentsecure.egg-info/top_level.txt +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/pyproject.toml +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/setup.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_audit.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_cli_demo.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_cli_policy.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_diff.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_discovery.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_encrypted_secret_store.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_env_policy.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_env_policy_contract.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_gateway_credentials.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_guard.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_guard_network.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_key_service.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_policy.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_policy_mutation.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_secrets.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_workspace.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_workspace_apply.py +0 -0
- {agentsecure-0.1.2 → agentsecure-0.1.4}/tests/test_wrappers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentsecure
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Local-first security runtime for AI coding agents
|
|
5
5
|
Home-page: https://github.com/ShellFrameAI/agentsecure-community
|
|
6
6
|
Author: ShellFrame AI
|
|
@@ -18,11 +18,10 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
18
18
|
Classifier: Topic :: Security
|
|
19
19
|
Classifier: Environment :: Console
|
|
20
20
|
Classifier: Operating System :: OS Independent
|
|
21
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
|
24
24
|
License-File: NOTICE
|
|
25
|
-
Requires-Dist: dataclasses; python_version < "3.7"
|
|
26
25
|
Dynamic: license-file
|
|
27
26
|
|
|
28
27
|
# AgentSecure Community
|
|
@@ -77,12 +76,18 @@ Why:
|
|
|
77
76
|
|
|
78
77
|
## Quickstart In A Project
|
|
79
78
|
|
|
80
|
-
Create a local config:
|
|
79
|
+
Create a local config and repo guidance file:
|
|
81
80
|
|
|
82
81
|
```bash
|
|
83
82
|
agentsecure init
|
|
84
83
|
```
|
|
85
84
|
|
|
85
|
+
This creates `agentsecure.json`, local private state under `.agentsecure/`, and `AGENTSECURE.md`. Review the Markdown file before running agents:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
agentsecure policy validate
|
|
89
|
+
```
|
|
90
|
+
|
|
86
91
|
Create a fake `.env` for testing:
|
|
87
92
|
|
|
88
93
|
```bash
|
|
@@ -108,6 +113,52 @@ By default, `--protect-all` virtualizes discovered secrets. The command output s
|
|
|
108
113
|
|
|
109
114
|
Denied values are removed only when policy sets `mode: "deny"` for that environment variable. The built-in `agentsecure demo` includes that policy for `DATABASE_URL_PROD` so you can see both behaviors: virtualize and deny.
|
|
110
115
|
|
|
116
|
+
## Provider Proxy Preview
|
|
117
|
+
|
|
118
|
+
Virtual secrets keep real values out of the agent context. Provider proxy mode goes one step further for tools and SDKs that honor `OPENAI_BASE_URL`: the agent gets a virtual key and a local base URL, while AgentSecure injects the real key only when forwarding to the configured provider.
|
|
119
|
+
|
|
120
|
+
Configure OpenAI from `agentsecure.json.provider_catalog.openai`:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
agentsecure proxy setup openai
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Then run the agent:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
agentsecure run --protect-all -- codex
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The agent-visible environment includes:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
OPENAI_API_KEY=virt_openai_...
|
|
136
|
+
OPENAI_BASE_URL=http://127.0.0.1:8765/providers/openai/v1
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
AgentSecure forwards provider calls to the configured upstream:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"provider_proxy": {
|
|
144
|
+
"providers": {
|
|
145
|
+
"openai": {
|
|
146
|
+
"upstream": "https://api.openai.com",
|
|
147
|
+
"local_path": "/providers/openai"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Run the proxy proof:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
agentsecure receipts --proxy
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Provider proxy mode is local-only. It is not a system-wide proxy, not TLS MITM, and not browser-wide interception. Tools must use the provider base URL environment variable.
|
|
161
|
+
|
|
111
162
|
## What It Demonstrates
|
|
112
163
|
|
|
113
164
|
- Discover likely secrets in `.env` files and environment variables.
|
|
@@ -121,7 +172,7 @@ Command-guard mode is a usability guard, not a hard sandbox. A determined proces
|
|
|
121
172
|
|
|
122
173
|
## Example Policy
|
|
123
174
|
|
|
124
|
-
See [examples/agentsecure.community.json](examples/agentsecure.community.json) and [examples/.env.example](examples/.env.example).
|
|
175
|
+
See [examples/agentsecure.community.json](examples/agentsecure.community.json), [examples/AGENTSECURE.md](examples/AGENTSECURE.md), and [examples/.env.example](examples/.env.example).
|
|
125
176
|
|
|
126
177
|
Minimal policy shape:
|
|
127
178
|
|
|
@@ -150,6 +201,7 @@ Minimal policy shape:
|
|
|
150
201
|
|
|
151
202
|
```bash
|
|
152
203
|
agentsecure init
|
|
204
|
+
agentsecure policy validate
|
|
153
205
|
agentsecure status
|
|
154
206
|
agentsecure doctor
|
|
155
207
|
agentsecure discover
|
|
@@ -157,6 +209,9 @@ agentsecure suggest
|
|
|
157
209
|
agentsecure env
|
|
158
210
|
agentsecure keys list
|
|
159
211
|
agentsecure network list
|
|
212
|
+
agentsecure proxy setup openai
|
|
213
|
+
agentsecure proxy doctor
|
|
214
|
+
agentsecure receipts --proxy
|
|
160
215
|
```
|
|
161
216
|
|
|
162
217
|
Run an agent or command through local command guard:
|
|
@@ -221,6 +276,12 @@ python3 scripts/secret_scan.py .
|
|
|
221
276
|
|
|
222
277
|
CI runs tests across supported Python versions and runs the local secret scan.
|
|
223
278
|
|
|
279
|
+
## AGENTSECURE.md
|
|
280
|
+
|
|
281
|
+
`AGENTSECURE.md` is a small repo-level policy guidance file for humans and AI coding agents. In the community release, AgentSecure creates it and validates that it does not contain raw secrets or unsupported raw-secret passthrough modes.
|
|
282
|
+
|
|
283
|
+
Supported community secret modes in the Markdown guidance are `virtualize` and `deny`. Do not use `allow` or `allow_real` for secrets. The Markdown file is guidance plus local validation; it is not a full sandbox by itself.
|
|
284
|
+
|
|
224
285
|
## Public Release Boundary
|
|
225
286
|
|
|
226
287
|
This community release does not include hosted backend integration, enterprise policy sync, billing/licensing, production secrets, internal endpoints, or sensitive commercial heuristics. See [OPEN_SOURCE_PLAN.md](OPEN_SOURCE_PLAN.md) and [OPEN_SOURCE_READINESS_REPORT.md](OPEN_SOURCE_READINESS_REPORT.md) for the public/private boundary.
|
|
@@ -50,12 +50,18 @@ Why:
|
|
|
50
50
|
|
|
51
51
|
## Quickstart In A Project
|
|
52
52
|
|
|
53
|
-
Create a local config:
|
|
53
|
+
Create a local config and repo guidance file:
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
56
|
agentsecure init
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
This creates `agentsecure.json`, local private state under `.agentsecure/`, and `AGENTSECURE.md`. Review the Markdown file before running agents:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
agentsecure policy validate
|
|
63
|
+
```
|
|
64
|
+
|
|
59
65
|
Create a fake `.env` for testing:
|
|
60
66
|
|
|
61
67
|
```bash
|
|
@@ -81,6 +87,52 @@ By default, `--protect-all` virtualizes discovered secrets. The command output s
|
|
|
81
87
|
|
|
82
88
|
Denied values are removed only when policy sets `mode: "deny"` for that environment variable. The built-in `agentsecure demo` includes that policy for `DATABASE_URL_PROD` so you can see both behaviors: virtualize and deny.
|
|
83
89
|
|
|
90
|
+
## Provider Proxy Preview
|
|
91
|
+
|
|
92
|
+
Virtual secrets keep real values out of the agent context. Provider proxy mode goes one step further for tools and SDKs that honor `OPENAI_BASE_URL`: the agent gets a virtual key and a local base URL, while AgentSecure injects the real key only when forwarding to the configured provider.
|
|
93
|
+
|
|
94
|
+
Configure OpenAI from `agentsecure.json.provider_catalog.openai`:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
agentsecure proxy setup openai
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Then run the agent:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
agentsecure run --protect-all -- codex
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The agent-visible environment includes:
|
|
107
|
+
|
|
108
|
+
```text
|
|
109
|
+
OPENAI_API_KEY=virt_openai_...
|
|
110
|
+
OPENAI_BASE_URL=http://127.0.0.1:8765/providers/openai/v1
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
AgentSecure forwards provider calls to the configured upstream:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"provider_proxy": {
|
|
118
|
+
"providers": {
|
|
119
|
+
"openai": {
|
|
120
|
+
"upstream": "https://api.openai.com",
|
|
121
|
+
"local_path": "/providers/openai"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Run the proxy proof:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
agentsecure receipts --proxy
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Provider proxy mode is local-only. It is not a system-wide proxy, not TLS MITM, and not browser-wide interception. Tools must use the provider base URL environment variable.
|
|
135
|
+
|
|
84
136
|
## What It Demonstrates
|
|
85
137
|
|
|
86
138
|
- Discover likely secrets in `.env` files and environment variables.
|
|
@@ -94,7 +146,7 @@ Command-guard mode is a usability guard, not a hard sandbox. A determined proces
|
|
|
94
146
|
|
|
95
147
|
## Example Policy
|
|
96
148
|
|
|
97
|
-
See [examples/agentsecure.community.json](examples/agentsecure.community.json) and [examples/.env.example](examples/.env.example).
|
|
149
|
+
See [examples/agentsecure.community.json](examples/agentsecure.community.json), [examples/AGENTSECURE.md](examples/AGENTSECURE.md), and [examples/.env.example](examples/.env.example).
|
|
98
150
|
|
|
99
151
|
Minimal policy shape:
|
|
100
152
|
|
|
@@ -123,6 +175,7 @@ Minimal policy shape:
|
|
|
123
175
|
|
|
124
176
|
```bash
|
|
125
177
|
agentsecure init
|
|
178
|
+
agentsecure policy validate
|
|
126
179
|
agentsecure status
|
|
127
180
|
agentsecure doctor
|
|
128
181
|
agentsecure discover
|
|
@@ -130,6 +183,9 @@ agentsecure suggest
|
|
|
130
183
|
agentsecure env
|
|
131
184
|
agentsecure keys list
|
|
132
185
|
agentsecure network list
|
|
186
|
+
agentsecure proxy setup openai
|
|
187
|
+
agentsecure proxy doctor
|
|
188
|
+
agentsecure receipts --proxy
|
|
133
189
|
```
|
|
134
190
|
|
|
135
191
|
Run an agent or command through local command guard:
|
|
@@ -194,6 +250,12 @@ python3 scripts/secret_scan.py .
|
|
|
194
250
|
|
|
195
251
|
CI runs tests across supported Python versions and runs the local secret scan.
|
|
196
252
|
|
|
253
|
+
## AGENTSECURE.md
|
|
254
|
+
|
|
255
|
+
`AGENTSECURE.md` is a small repo-level policy guidance file for humans and AI coding agents. In the community release, AgentSecure creates it and validates that it does not contain raw secrets or unsupported raw-secret passthrough modes.
|
|
256
|
+
|
|
257
|
+
Supported community secret modes in the Markdown guidance are `virtualize` and `deny`. Do not use `allow` or `allow_real` for secrets. The Markdown file is guidance plus local validation; it is not a full sandbox by itself.
|
|
258
|
+
|
|
197
259
|
## Public Release Boundary
|
|
198
260
|
|
|
199
261
|
This community release does not include hosted backend integration, enterprise policy sync, billing/licensing, production secrets, internal endpoints, or sensitive commercial heuristics. See [OPEN_SOURCE_PLAN.md](OPEN_SOURCE_PLAN.md) and [OPEN_SOURCE_READINESS_REPORT.md](OPEN_SOURCE_READINESS_REPORT.md) for the public/private boundary.
|
|
@@ -14,6 +14,7 @@ import time
|
|
|
14
14
|
from typing import Any, Dict, List, Optional
|
|
15
15
|
from urllib.request import Request, urlopen
|
|
16
16
|
|
|
17
|
+
from agentsecure import __version__
|
|
17
18
|
from agentsecure.cloud import CloudError, CloudRuntimeService
|
|
18
19
|
from agentsecure.api.server import LocalApiServer
|
|
19
20
|
from agentsecure.api.services import ApiServices
|
|
@@ -32,6 +33,8 @@ from agentsecure.cli.project import (
|
|
|
32
33
|
show_status,
|
|
33
34
|
uninstall_agentsecure,
|
|
34
35
|
)
|
|
36
|
+
from agentsecure.cli.proxy import add_proxy_subparser, handle_proxy
|
|
37
|
+
from agentsecure.cli.receipts import handle_receipts
|
|
35
38
|
from agentsecure.cli.secrets import (
|
|
36
39
|
discover_secrets,
|
|
37
40
|
handle_keys,
|
|
@@ -47,6 +50,7 @@ from agentsecure.cli.settings import (
|
|
|
47
50
|
handle_setup,
|
|
48
51
|
)
|
|
49
52
|
from agentsecure.client.wrappers import AgentWrapperInstaller, SUPPORTED_AGENTS
|
|
53
|
+
from agentsecure.core.agentsecure_md import AGENTSECURE_MD, agentsecure_md_status
|
|
50
54
|
from agentsecure.core.command_metadata import safe_command_metadata
|
|
51
55
|
from agentsecure.core.config import ConfigError, JsonConfigLoader, JsonConfigWriter
|
|
52
56
|
from agentsecure.core.config_profiles import (
|
|
@@ -57,6 +61,7 @@ from agentsecure.core.capabilities import broker_url_for_env
|
|
|
57
61
|
from agentsecure.core.container import Container
|
|
58
62
|
from agentsecure.core.key_service import KeyManagementError, KeyManagementService
|
|
59
63
|
from agentsecure.core.models import AgentSecureConfig, DiscoveredSecret, ProcessRequest, SecretReplacement
|
|
64
|
+
from agentsecure.core.provider_proxy import configured_provider_base_url, provider_base_local_path
|
|
60
65
|
from agentsecure.core.product import ProductService
|
|
61
66
|
from agentsecure.core.time import DurationError
|
|
62
67
|
from agentsecure.daemon.commands import CommandExecutor, CommandPoller
|
|
@@ -116,6 +121,10 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|
|
116
121
|
return handle_files(args)
|
|
117
122
|
if args.command == "network":
|
|
118
123
|
return handle_network(args)
|
|
124
|
+
if args.command == "proxy":
|
|
125
|
+
return handle_proxy(args)
|
|
126
|
+
if args.command == "receipts":
|
|
127
|
+
return handle_receipts(args)
|
|
119
128
|
if args.command == "policy":
|
|
120
129
|
return handle_policy(args)
|
|
121
130
|
if args.command == "setup":
|
|
@@ -138,6 +147,7 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|
|
138
147
|
|
|
139
148
|
def build_parser() -> argparse.ArgumentParser:
|
|
140
149
|
parser = argparse.ArgumentParser(prog="agentsecure")
|
|
150
|
+
parser.add_argument("--version", action="version", version="agentsecure %s" % __version__)
|
|
141
151
|
parser.add_argument(
|
|
142
152
|
"--config",
|
|
143
153
|
default="agentsecure.json",
|
|
@@ -225,6 +235,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
225
235
|
network_remove_parser = network_subparsers.add_parser("remove", help="Remove domains from credential allowlist")
|
|
226
236
|
network_remove_parser.add_argument("domains", nargs="+")
|
|
227
237
|
|
|
238
|
+
add_proxy_subparser(subparsers)
|
|
239
|
+
receipts_parser = subparsers.add_parser("receipts", help="Run replayable AgentSecure proof receipts")
|
|
240
|
+
receipts_parser.add_argument("--proxy", action="store_true", help="Run provider proxy receipts")
|
|
228
241
|
add_policy_subparser(subparsers)
|
|
229
242
|
|
|
230
243
|
setup_parser = subparsers.add_parser("setup", help="Install local protected agent command wrappers")
|
|
@@ -254,6 +267,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
254
267
|
|
|
255
268
|
|
|
256
269
|
def run_agent(args: argparse.Namespace) -> int:
|
|
270
|
+
policy_doc = agentsecure_md_status(AGENTSECURE_MD)
|
|
271
|
+
if policy_doc.get("exists"):
|
|
272
|
+
state = "valid" if policy_doc.get("ok") else "needs review"
|
|
273
|
+
print("AgentSecure policy guidance: %s (%s)" % (AGENTSECURE_MD, state), flush=True)
|
|
257
274
|
cloud = CloudRuntimeService() if _cloud_features_enabled() else None
|
|
258
275
|
if cloud:
|
|
259
276
|
_apply_cloud_runtime_defaults(args, cloud)
|
|
@@ -266,6 +283,7 @@ def run_agent(args: argparse.Namespace) -> int:
|
|
|
266
283
|
if isinstance(replacements, int):
|
|
267
284
|
return replacements
|
|
268
285
|
container = Container.from_config_path(args.config)
|
|
286
|
+
replacements.extend(_configured_secret_replacements(container, replacements))
|
|
269
287
|
run_cwd = os.getcwd()
|
|
270
288
|
workspace_session = None
|
|
271
289
|
materializer = WorkspaceMaterializer(_workspace_base_for_runtime(run_cwd, args.runtime))
|
|
@@ -346,6 +364,7 @@ def run_agent(args: argparse.Namespace) -> int:
|
|
|
346
364
|
env = os.environ.copy()
|
|
347
365
|
for env_name in container.config.env_policy.rules:
|
|
348
366
|
env.pop(env_name, None)
|
|
367
|
+
_strip_backing_secret_environment(env, container)
|
|
349
368
|
env.update(container.virtual_env_provider.build_environment())
|
|
350
369
|
if args.runtime == "command-guard":
|
|
351
370
|
CommandGuardWrapperInstaller(args.config).install(env)
|
|
@@ -354,6 +373,7 @@ def run_agent(args: argparse.Namespace) -> int:
|
|
|
354
373
|
env["AGENTSECURE_SESSION_ID"] = session_id
|
|
355
374
|
proxy_url = _proxy_url(gateway_host, gateway_port, session_id)
|
|
356
375
|
_apply_proxy_environment(env, proxy_url)
|
|
376
|
+
_apply_provider_proxy_environment(env, container, gateway_host, gateway_port)
|
|
357
377
|
command_metadata = safe_command_metadata(argv)
|
|
358
378
|
container.audit_logger.record(
|
|
359
379
|
"agent_started",
|
|
@@ -625,6 +645,7 @@ def _start_local_gateway_thread(container: Container, host: str, port: int):
|
|
|
625
645
|
container.token_resolver,
|
|
626
646
|
container.audit_logger,
|
|
627
647
|
container.bindings,
|
|
648
|
+
container.config.provider_proxy,
|
|
628
649
|
)
|
|
629
650
|
|
|
630
651
|
def run_gateway_thread() -> None:
|
|
@@ -809,6 +830,59 @@ def _apply_proxy_environment(env, proxy_url: str) -> None:
|
|
|
809
830
|
env["no_proxy"] = no_proxy
|
|
810
831
|
|
|
811
832
|
|
|
833
|
+
def _apply_provider_proxy_environment(env, container: Container, gateway_host: str, gateway_port: int) -> None:
|
|
834
|
+
if not container.config.provider_proxy.enabled:
|
|
835
|
+
return
|
|
836
|
+
raw = dict(container.config.raw)
|
|
837
|
+
gateway = dict(raw.get("gateway", {}))
|
|
838
|
+
gateway["host"] = gateway_host
|
|
839
|
+
gateway["port"] = gateway_port
|
|
840
|
+
raw["gateway"] = gateway
|
|
841
|
+
for provider in container.config.provider_proxy.providers.values():
|
|
842
|
+
provider_data = {
|
|
843
|
+
"local_path": provider_base_local_path(provider.local_path, provider.allow_paths),
|
|
844
|
+
}
|
|
845
|
+
env[provider.base_url_env] = configured_provider_base_url(raw, provider_data)
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
def _strip_backing_secret_environment(env, container: Container) -> None:
|
|
849
|
+
for binding in container.config.secrets:
|
|
850
|
+
if binding.real_secret_env:
|
|
851
|
+
env.pop(binding.real_secret_env, None)
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
def _configured_secret_replacements(container: Container, existing: List[SecretReplacement]) -> List[SecretReplacement]:
|
|
855
|
+
existing_names = set(replacement.name for replacement in existing)
|
|
856
|
+
replacements = []
|
|
857
|
+
for binding in container.config.secrets:
|
|
858
|
+
if binding.env_name in existing_names:
|
|
859
|
+
continue
|
|
860
|
+
real_value = container.token_resolver.resolve(binding.virtual_token) or ""
|
|
861
|
+
if not real_value:
|
|
862
|
+
continue
|
|
863
|
+
rule = container.config.env_policy.rule_for(binding.env_name)
|
|
864
|
+
if rule.mode == "deny":
|
|
865
|
+
replacements.append(
|
|
866
|
+
SecretReplacement(
|
|
867
|
+
source="configured",
|
|
868
|
+
name=binding.env_name,
|
|
869
|
+
real_value=real_value,
|
|
870
|
+
virtual_value="",
|
|
871
|
+
action="remove",
|
|
872
|
+
)
|
|
873
|
+
)
|
|
874
|
+
elif rule.mode != "broker":
|
|
875
|
+
replacements.append(
|
|
876
|
+
SecretReplacement(
|
|
877
|
+
source="configured",
|
|
878
|
+
name=binding.env_name,
|
|
879
|
+
real_value=real_value,
|
|
880
|
+
virtual_value=binding.virtual_token,
|
|
881
|
+
)
|
|
882
|
+
)
|
|
883
|
+
return replacements
|
|
884
|
+
|
|
885
|
+
|
|
812
886
|
def _merge_no_proxy(existing: str) -> str:
|
|
813
887
|
defaults = [
|
|
814
888
|
"localhost",
|
|
@@ -825,6 +899,8 @@ def _merge_no_proxy(existing: str) -> str:
|
|
|
825
899
|
if not value:
|
|
826
900
|
continue
|
|
827
901
|
key = value.lower()
|
|
902
|
+
if key == "*":
|
|
903
|
+
continue
|
|
828
904
|
if key not in seen:
|
|
829
905
|
values.append(value)
|
|
830
906
|
seen.add(key)
|
|
@@ -2,6 +2,7 @@ import argparse
|
|
|
2
2
|
import json
|
|
3
3
|
import sys
|
|
4
4
|
|
|
5
|
+
from agentsecure.core.agentsecure_md import AGENTSECURE_MD, validate_agentsecure_md
|
|
5
6
|
from agentsecure.core.config import ConfigError
|
|
6
7
|
from agentsecure.core.policy_mutation import LocalPolicyMutationService
|
|
7
8
|
|
|
@@ -14,11 +15,17 @@ def add_policy_subparser(subparsers) -> None:
|
|
|
14
15
|
policy_preview_parser.add_argument("--json-file", help="Read mutation JSON from this file instead of stdin")
|
|
15
16
|
policy_apply_parser = policy_subparsers.add_parser("apply-local", help="Apply local policy changes from JSON")
|
|
16
17
|
policy_apply_parser.add_argument("--json-file", help="Read mutation JSON from this file instead of stdin")
|
|
18
|
+
validate_parser = policy_subparsers.add_parser("validate", help="Validate AGENTSECURE.md policy guidance")
|
|
19
|
+
validate_parser.add_argument("--file", default=AGENTSECURE_MD, help="AGENTSECURE.md path")
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
def handle_policy(args: argparse.Namespace) -> int:
|
|
20
|
-
service = LocalPolicyMutationService(args.config)
|
|
21
23
|
try:
|
|
24
|
+
if args.policy_command == "validate":
|
|
25
|
+
payload = validate_agentsecure_md(args.file)
|
|
26
|
+
print(json.dumps(payload, indent=2, sort_keys=True))
|
|
27
|
+
return 0 if payload["ok"] else 1
|
|
28
|
+
service = LocalPolicyMutationService(args.config)
|
|
22
29
|
if args.policy_command == "review":
|
|
23
30
|
payload = service.review()
|
|
24
31
|
elif args.policy_command == "preview":
|
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import shutil
|
|
5
5
|
|
|
6
6
|
from agentsecure.cli.common import scanner
|
|
7
|
+
from agentsecure.core.agentsecure_md import AGENTSECURE_MD
|
|
7
8
|
from agentsecure.core.product import ProductService
|
|
8
9
|
from agentsecure.workspace.materializer import make_tree_writable
|
|
9
10
|
|
|
@@ -32,6 +33,14 @@ def show_status(args: argparse.Namespace) -> int:
|
|
|
32
33
|
return 0
|
|
33
34
|
print("AgentSecure status")
|
|
34
35
|
print("Config: %s (%s)" % (result["config_path"], "found" if result["config_exists"] else "missing"))
|
|
36
|
+
agentsecure_md = result.get("agentsecure_md", {})
|
|
37
|
+
print(
|
|
38
|
+
"AGENTSECURE.md: %s (%s)"
|
|
39
|
+
% (
|
|
40
|
+
agentsecure_md.get("path", AGENTSECURE_MD),
|
|
41
|
+
"valid" if agentsecure_md.get("exists") and agentsecure_md.get("ok") else "missing" if not agentsecure_md.get("exists") else "needs review",
|
|
42
|
+
)
|
|
43
|
+
)
|
|
35
44
|
print("Configured secrets: %s" % result["configured_secrets"])
|
|
36
45
|
print("Discovered secrets: %s" % result["discovered_secrets"])
|
|
37
46
|
grants = result["grants"]
|