pywrit 0.2.4__tar.gz → 0.2.6__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.
- {pywrit-0.2.4 → pywrit-0.2.6}/PKG-INFO +83 -8
- pywrit-0.2.4/src/pywrit.egg-info/PKG-INFO → pywrit-0.2.6/README.md +72 -19
- {pywrit-0.2.4 → pywrit-0.2.6}/pyproject.toml +11 -2
- {pywrit-0.2.4 → pywrit-0.2.6}/src/pywrit/__init__.py +1 -1
- {pywrit-0.2.4 → pywrit-0.2.6}/src/pywrit/cli.py +568 -1
- pywrit-0.2.4/README.md → pywrit-0.2.6/src/pywrit.egg-info/PKG-INFO +94 -5
- {pywrit-0.2.4 → pywrit-0.2.6}/src/pywrit.egg-info/SOURCES.txt +3 -1
- pywrit-0.2.6/src/pywrit.egg-info/requires.txt +12 -0
- pywrit-0.2.6/tests/test_scan_json.py +151 -0
- pywrit-0.2.6/tests/test_scan_tsjs.py +243 -0
- pywrit-0.2.4/src/pywrit.egg-info/requires.txt +0 -1
- {pywrit-0.2.4 → pywrit-0.2.6}/LICENSE +0 -0
- {pywrit-0.2.4 → pywrit-0.2.6}/setup.cfg +0 -0
- {pywrit-0.2.4 → pywrit-0.2.6}/src/pywrit/client.py +0 -0
- {pywrit-0.2.4 → pywrit-0.2.6}/src/pywrit/errors.py +0 -0
- {pywrit-0.2.4 → pywrit-0.2.6}/src/pywrit.egg-info/dependency_links.txt +0 -0
- {pywrit-0.2.4 → pywrit-0.2.6}/src/pywrit.egg-info/entry_points.txt +0 -0
- {pywrit-0.2.4 → pywrit-0.2.6}/src/pywrit.egg-info/top_level.txt +0 -0
- {pywrit-0.2.4 → pywrit-0.2.6}/tests/test_client.py +0 -0
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pywrit
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Python client + CLI for Writ — the gate before the write
|
|
5
|
-
License: MIT
|
|
5
|
+
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/AvenueDAdmin/pywrit
|
|
7
7
|
Project-URL: Documentation, https://withwrit.com/docs
|
|
8
|
-
Keywords: ai-agents,policy,audit-log,guardrails
|
|
9
8
|
Requires-Python: >=3.9
|
|
10
9
|
Description-Content-Type: text/markdown
|
|
11
10
|
License-File: LICENSE
|
|
12
11
|
Requires-Dist: httpx>=0.27
|
|
12
|
+
Provides-Extra: polyglot
|
|
13
|
+
Requires-Dist: tree-sitter>=0.23; extra == "polyglot"
|
|
14
|
+
Requires-Dist: tree-sitter-typescript>=0.23; extra == "polyglot"
|
|
15
|
+
Requires-Dist: tree-sitter-javascript>=0.23; extra == "polyglot"
|
|
16
|
+
Provides-Extra: keywords
|
|
17
|
+
Requires-Dist: ai-agents; extra == "keywords"
|
|
18
|
+
Requires-Dist: policy; extra == "keywords"
|
|
19
|
+
Requires-Dist: audit-log; extra == "keywords"
|
|
20
|
+
Requires-Dist: guardrails; extra == "keywords"
|
|
13
21
|
Dynamic: license-file
|
|
14
22
|
|
|
15
23
|
# pywrit
|
|
@@ -32,6 +40,18 @@ pip install pywrit
|
|
|
32
40
|
|
|
33
41
|
Requires Python 3.9+. Installs the `writ` command and the `pywrit` Python client.
|
|
34
42
|
|
|
43
|
+
**JavaScript/TypeScript devs:** run the scanner with no Python setup via npm:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx writ-scan .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The `writ-scan` package wraps the same scanner (including TS/JS support). On
|
|
50
|
+
first run it installs `pywrit[polyglot]` from PyPI using your Python 3.9+
|
|
51
|
+
(one-time); afterwards it starts instantly. See [`npm/`](npm/) for details,
|
|
52
|
+
environment overrides (`WRIT_PYTHON`, `WRIT_SCAN_NO_INSTALL`), and the
|
|
53
|
+
install test.
|
|
54
|
+
|
|
35
55
|
## 60-second quickstart: scan → apply → gate
|
|
36
56
|
|
|
37
57
|
**1. Scan.** See which functions write, and how many of them are gated.
|
|
@@ -114,13 +134,42 @@ Python (`.py`) files, parsed with the stdlib `ast` (no extra dependencies):
|
|
|
114
134
|
calls such as `stripe.Refund.create(...)`, deferred task queues, or shared clients
|
|
115
135
|
several layers down. The risk report lists these gaps every time.
|
|
116
136
|
|
|
117
|
-
### TypeScript / JavaScript
|
|
137
|
+
### TypeScript / JavaScript (scan-only)
|
|
138
|
+
|
|
139
|
+
`writ scan` also finds write sites in TypeScript and JavaScript. It needs the
|
|
140
|
+
optional extra (tree-sitter based):
|
|
141
|
+
|
|
142
|
+
pip install 'pywrit[polyglot]'
|
|
143
|
+
writ scan .
|
|
144
|
+
|
|
145
|
+
Without the extra, the scanner prints a one-line hint and keeps going —
|
|
146
|
+
Python scanning never needs it.
|
|
147
|
+
|
|
148
|
+
TS/JS is **scan-only**: findings are listed with verbs for your policy file,
|
|
149
|
+
but `writ scan --apply` never rewrites TS/JS files — gate those by hand.
|
|
150
|
+
Covered patterns: `fetch`/`axios` writes, `fs` writes, SQL through knex-style
|
|
151
|
+
clients, Prisma writes, and JS SDK calls such as `stripe.refunds.create(...)`.
|
|
152
|
+
(Still not covered: the *Python* SDK equivalents like `stripe.Refund.create(...)`
|
|
153
|
+
— see "Not covered" above.)
|
|
154
|
+
|
|
155
|
+

|
|
156
|
+
|
|
157
|
+
## GitHub Action
|
|
158
|
+
|
|
159
|
+
Scan every pull request for ungated write sites. Findings land as check
|
|
160
|
+
annotations on the exact file and line, plus a Markdown risk report in the
|
|
161
|
+
job summary. The check fails when an ungated finding meets your
|
|
162
|
+
`fail-on-risk` threshold (default: `high`).
|
|
118
163
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
164
|
+
```yaml
|
|
165
|
+
- uses: actions/checkout@v4
|
|
166
|
+
- uses: AvenueDAdmin/pywrit@v1
|
|
167
|
+
with:
|
|
168
|
+
fail-on-risk: high # high | medium | low | never
|
|
169
|
+
```
|
|
122
170
|
|
|
123
|
-
|
|
171
|
+
No API key needed. Full reference: [docs/github-action.md](docs/github-action.md) ·
|
|
172
|
+
example workflow: [examples/github-action/writ-scan.yml](examples/github-action/writ-scan.yml)
|
|
124
173
|
|
|
125
174
|
## Python client
|
|
126
175
|
|
|
@@ -185,6 +234,32 @@ writ grant --sponsor acme --agent agent-7 --verb payments.refund \
|
|
|
185
234
|
Sponsor-token commands (`revoke`, `reinstate`, `revoked`, `grant`) read
|
|
186
235
|
`--sponsor-token` or `WRIT_SPONSOR_TOKEN`. Run `writ --help` for the full command list.
|
|
187
236
|
|
|
237
|
+
## README badge
|
|
238
|
+
|
|
239
|
+
Show that your agent's writes are gated by Writ. Two flavors:
|
|
240
|
+
|
|
241
|
+
**Static** (works today, no API key) — same design, no live count:
|
|
242
|
+
|
|
243
|
+
```md
|
|
244
|
+
[](https://withwrit.com)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Dynamic** (live 30-day gated-write count from your audit log) — mint a badge
|
|
248
|
+
token, then embed the snippet the API returns:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
curl -s https://api.withwrit.com/v1/badge/tokens \
|
|
252
|
+
-H "Authorization: Bearer writ_..." \
|
|
253
|
+
-H "Content-Type: application/json" \
|
|
254
|
+
-d '{}'
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The dynamic endpoint ships with the gate — until it's live, `POST /v1/badge/tokens`
|
|
258
|
+
returns 404 and the static badge above is the one to use.
|
|
259
|
+
|
|
260
|
+
See [`badge/`](badge/) for embed docs and the verification model (what the
|
|
261
|
+
badge proves — and what it doesn't).
|
|
262
|
+
|
|
188
263
|
## Docs
|
|
189
264
|
|
|
190
265
|
Full docs: [docs.withwrit.com](https://docs.withwrit.com) ·
|
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: pywrit
|
|
3
|
-
Version: 0.2.4
|
|
4
|
-
Summary: Python client + CLI for Writ — the gate before the write
|
|
5
|
-
License: MIT
|
|
6
|
-
Project-URL: Homepage, https://github.com/AvenueDAdmin/pywrit
|
|
7
|
-
Project-URL: Documentation, https://withwrit.com/docs
|
|
8
|
-
Keywords: ai-agents,policy,audit-log,guardrails
|
|
9
|
-
Requires-Python: >=3.9
|
|
10
|
-
Description-Content-Type: text/markdown
|
|
11
|
-
License-File: LICENSE
|
|
12
|
-
Requires-Dist: httpx>=0.27
|
|
13
|
-
Dynamic: license-file
|
|
14
|
-
|
|
15
1
|
# pywrit
|
|
16
2
|
|
|
17
3
|
**Find the dangerous writes in your Python agent's code, then gate it.** `pywrit` is the Python
|
|
@@ -32,6 +18,18 @@ pip install pywrit
|
|
|
32
18
|
|
|
33
19
|
Requires Python 3.9+. Installs the `writ` command and the `pywrit` Python client.
|
|
34
20
|
|
|
21
|
+
**JavaScript/TypeScript devs:** run the scanner with no Python setup via npm:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx writ-scan .
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The `writ-scan` package wraps the same scanner (including TS/JS support). On
|
|
28
|
+
first run it installs `pywrit[polyglot]` from PyPI using your Python 3.9+
|
|
29
|
+
(one-time); afterwards it starts instantly. See [`npm/`](npm/) for details,
|
|
30
|
+
environment overrides (`WRIT_PYTHON`, `WRIT_SCAN_NO_INSTALL`), and the
|
|
31
|
+
install test.
|
|
32
|
+
|
|
35
33
|
## 60-second quickstart: scan → apply → gate
|
|
36
34
|
|
|
37
35
|
**1. Scan.** See which functions write, and how many of them are gated.
|
|
@@ -114,13 +112,42 @@ Python (`.py`) files, parsed with the stdlib `ast` (no extra dependencies):
|
|
|
114
112
|
calls such as `stripe.Refund.create(...)`, deferred task queues, or shared clients
|
|
115
113
|
several layers down. The risk report lists these gaps every time.
|
|
116
114
|
|
|
117
|
-
### TypeScript / JavaScript
|
|
115
|
+
### TypeScript / JavaScript (scan-only)
|
|
116
|
+
|
|
117
|
+
`writ scan` also finds write sites in TypeScript and JavaScript. It needs the
|
|
118
|
+
optional extra (tree-sitter based):
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
> development; the command it uses is not available yet.
|
|
120
|
+
pip install 'pywrit[polyglot]'
|
|
121
|
+
writ scan .
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
Without the extra, the scanner prints a one-line hint and keeps going —
|
|
124
|
+
Python scanning never needs it.
|
|
125
|
+
|
|
126
|
+
TS/JS is **scan-only**: findings are listed with verbs for your policy file,
|
|
127
|
+
but `writ scan --apply` never rewrites TS/JS files — gate those by hand.
|
|
128
|
+
Covered patterns: `fetch`/`axios` writes, `fs` writes, SQL through knex-style
|
|
129
|
+
clients, Prisma writes, and JS SDK calls such as `stripe.refunds.create(...)`.
|
|
130
|
+
(Still not covered: the *Python* SDK equivalents like `stripe.Refund.create(...)`
|
|
131
|
+
— see "Not covered" above.)
|
|
132
|
+
|
|
133
|
+

|
|
134
|
+
|
|
135
|
+
## GitHub Action
|
|
136
|
+
|
|
137
|
+
Scan every pull request for ungated write sites. Findings land as check
|
|
138
|
+
annotations on the exact file and line, plus a Markdown risk report in the
|
|
139
|
+
job summary. The check fails when an ungated finding meets your
|
|
140
|
+
`fail-on-risk` threshold (default: `high`).
|
|
141
|
+
|
|
142
|
+
```yaml
|
|
143
|
+
- uses: actions/checkout@v4
|
|
144
|
+
- uses: AvenueDAdmin/pywrit@v1
|
|
145
|
+
with:
|
|
146
|
+
fail-on-risk: high # high | medium | low | never
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
No API key needed. Full reference: [docs/github-action.md](docs/github-action.md) ·
|
|
150
|
+
example workflow: [examples/github-action/writ-scan.yml](examples/github-action/writ-scan.yml)
|
|
124
151
|
|
|
125
152
|
## Python client
|
|
126
153
|
|
|
@@ -185,6 +212,32 @@ writ grant --sponsor acme --agent agent-7 --verb payments.refund \
|
|
|
185
212
|
Sponsor-token commands (`revoke`, `reinstate`, `revoked`, `grant`) read
|
|
186
213
|
`--sponsor-token` or `WRIT_SPONSOR_TOKEN`. Run `writ --help` for the full command list.
|
|
187
214
|
|
|
215
|
+
## README badge
|
|
216
|
+
|
|
217
|
+
Show that your agent's writes are gated by Writ. Two flavors:
|
|
218
|
+
|
|
219
|
+
**Static** (works today, no API key) — same design, no live count:
|
|
220
|
+
|
|
221
|
+
```md
|
|
222
|
+
[](https://withwrit.com)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Dynamic** (live 30-day gated-write count from your audit log) — mint a badge
|
|
226
|
+
token, then embed the snippet the API returns:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
curl -s https://api.withwrit.com/v1/badge/tokens \
|
|
230
|
+
-H "Authorization: Bearer writ_..." \
|
|
231
|
+
-H "Content-Type: application/json" \
|
|
232
|
+
-d '{}'
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
The dynamic endpoint ships with the gate — until it's live, `POST /v1/badge/tokens`
|
|
236
|
+
returns 404 and the static badge above is the one to use.
|
|
237
|
+
|
|
238
|
+
See [`badge/`](badge/) for embed docs and the verification model (what the
|
|
239
|
+
badge proves — and what it doesn't).
|
|
240
|
+
|
|
188
241
|
## Docs
|
|
189
242
|
|
|
190
243
|
Full docs: [docs.withwrit.com](https://docs.withwrit.com) ·
|
|
@@ -4,12 +4,21 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pywrit"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.6"
|
|
8
8
|
description = "Python client + CLI for Writ — the gate before the write"
|
|
9
9
|
readme = "README.md"
|
|
10
|
-
license =
|
|
10
|
+
license = "MIT"
|
|
11
11
|
requires-python = ">=3.9"
|
|
12
12
|
dependencies = ["httpx>=0.27"]
|
|
13
|
+
|
|
14
|
+
[project.optional-dependencies]
|
|
15
|
+
# `pip install 'pywrit[polyglot]'`: lets `writ scan` parse TypeScript and
|
|
16
|
+
# JavaScript (scan only). Python scanning never needs it.
|
|
17
|
+
polyglot = [
|
|
18
|
+
"tree-sitter>=0.23",
|
|
19
|
+
"tree-sitter-typescript>=0.23",
|
|
20
|
+
"tree-sitter-javascript>=0.23",
|
|
21
|
+
]
|
|
13
22
|
keywords = ["ai-agents", "policy", "audit-log", "guardrails"]
|
|
14
23
|
|
|
15
24
|
[project.urls]
|