becwright 0.1.0__tar.gz → 0.2.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.
- {becwright-0.1.0/src/becwright.egg-info → becwright-0.2.0}/PKG-INFO +54 -14
- {becwright-0.1.0 → becwright-0.2.0}/README.md +48 -13
- {becwright-0.1.0 → becwright-0.2.0}/pyproject.toml +6 -2
- becwright-0.2.0/src/becwright/__init__.py +1 -0
- becwright-0.2.0/src/becwright/__main__.py +6 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/bundle.py +9 -5
- becwright-0.2.0/src/becwright/checks/_ignore.py +11 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/checks/dangerous_eval.py +3 -1
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/checks/debug_remnants.py +3 -1
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/checks/forbid.py +3 -1
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/checks/hardcoded_secrets.py +3 -1
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/checks/no_token_in_logs.py +3 -1
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/checks/wildcard_imports.py +3 -1
- becwright-0.2.0/src/becwright/cli.py +340 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/git.py +12 -3
- becwright-0.2.0/src/becwright/mcp_server.py +45 -0
- becwright-0.2.0/src/becwright/report.py +38 -0
- {becwright-0.1.0 → becwright-0.2.0/src/becwright.egg-info}/PKG-INFO +54 -14
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright.egg-info/SOURCES.txt +10 -1
- becwright-0.2.0/src/becwright.egg-info/requires.txt +12 -0
- {becwright-0.1.0 → becwright-0.2.0}/tests/test_bundle.py +24 -4
- {becwright-0.1.0 → becwright-0.2.0}/tests/test_cli_and_git.py +33 -0
- becwright-0.2.0/tests/test_ignore.py +29 -0
- becwright-0.2.0/tests/test_init.py +108 -0
- becwright-0.2.0/tests/test_list.py +22 -0
- becwright-0.2.0/tests/test_mcp.py +55 -0
- becwright-0.2.0/tests/test_report_and_json.py +86 -0
- becwright-0.1.0/src/becwright/__init__.py +0 -1
- becwright-0.1.0/src/becwright/cli.py +0 -179
- becwright-0.1.0/src/becwright.egg-info/requires.txt +0 -5
- {becwright-0.1.0 → becwright-0.2.0}/LICENSE +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/setup.cfg +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/checks/__init__.py +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/checks/redundant_comments.py +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/engine.py +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright/rules.py +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright.egg-info/dependency_links.txt +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright.egg-info/entry_points.txt +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/src/becwright.egg-info/top_level.txt +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/tests/test_checks.py +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/tests/test_engine.py +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/tests/test_engine_integration.py +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/tests/test_forbid.py +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/tests/test_more_checks.py +0 -0
- {becwright-0.1.0 → becwright-0.2.0}/tests/test_redundant_comments.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: becwright
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Deterministically enforces constraints (BECs) on your code, blocking commits that violate them.
|
|
5
5
|
Author: Alonso David De Leon Rodarte
|
|
6
6
|
License: MIT
|
|
@@ -18,6 +18,11 @@ Requires-Dist: pyyaml>=6
|
|
|
18
18
|
Provides-Extra: dev
|
|
19
19
|
Requires-Dist: pytest>=8; extra == "dev"
|
|
20
20
|
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
21
|
+
Requires-Dist: mcp>=1.2; extra == "dev"
|
|
22
|
+
Provides-Extra: build
|
|
23
|
+
Requires-Dist: pyinstaller>=6; extra == "build"
|
|
24
|
+
Provides-Extra: mcp
|
|
25
|
+
Requires-Dist: mcp>=1.2; extra == "mcp"
|
|
21
26
|
Dynamic: license-file
|
|
22
27
|
|
|
23
28
|
> **English** · [Español](README.es.md)
|
|
@@ -72,26 +77,53 @@ becwright is installed once as a tool; each repo only contributes its own
|
|
|
72
77
|
`.bec/rules.yaml`.
|
|
73
78
|
|
|
74
79
|
```bash
|
|
75
|
-
# 1. Install the engine
|
|
76
|
-
|
|
80
|
+
# 1. Install the engine. Pick your ecosystem — no Python needed via npm/pnpm,
|
|
81
|
+
# which ship a self-contained binary:
|
|
82
|
+
npm install --save-dev becwright # or global: npm install -g becwright
|
|
83
|
+
pnpm add -D becwright
|
|
84
|
+
pipx install becwright # or: pip install becwright
|
|
77
85
|
|
|
78
|
-
# 2. In
|
|
79
|
-
becwright
|
|
86
|
+
# 2. In your repo, scaffold rules + install the hook
|
|
87
|
+
becwright init # detects your language, writes .bec/rules.yaml, installs the hook
|
|
80
88
|
|
|
81
|
-
# 3.
|
|
82
|
-
# 4. Done: each commit runs the checks; if a blocking rule fails, it stops.
|
|
89
|
+
# 3. Done: each commit runs the checks; if a blocking rule fails, it stops.
|
|
83
90
|
```
|
|
84
91
|
|
|
92
|
+
Installed as a devDependency, the pre-commit hook resolves the local binary from
|
|
93
|
+
`node_modules/.bin`, so it works without a global install. The npm packages cover
|
|
94
|
+
`linux-x64`, `linux-arm64`, `darwin-x64`, `darwin-arm64` and `win32-x64`; on any
|
|
95
|
+
other platform use `pipx install becwright`.
|
|
96
|
+
|
|
85
97
|
Available commands:
|
|
86
98
|
|
|
87
99
|
| Command | What it does |
|
|
88
100
|
|---|---|
|
|
101
|
+
| `becwright init` | Scaffold a starter `.bec/rules.yaml` and install the hook |
|
|
102
|
+
| `becwright list` | List the built-in checks |
|
|
89
103
|
| `becwright check` | Runs the rules over the staged files |
|
|
90
104
|
| `becwright install` | Installs the native `pre-commit` hook |
|
|
91
105
|
| `becwright uninstall` | Removes the hook |
|
|
92
106
|
| `becwright export <id>` | Exports a BEC to a `.bec.yaml` file |
|
|
93
107
|
| `becwright import <file\|URL>` | Imports a BEC from another repo |
|
|
94
108
|
|
|
109
|
+
### Use with AI agents (Claude Code)
|
|
110
|
+
|
|
111
|
+
becwright is the deterministic net for what an AI agent lets slip. There is a
|
|
112
|
+
Claude Code plugin so an agent can install and drive it for you:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
/plugin marketplace add DataDave-Dev/becwright
|
|
116
|
+
/plugin install becwright@becwright
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
It adds a `becwright` skill and a `/becwright` command. See
|
|
120
|
+
[`integrations/claude-code/`](integrations/claude-code/).
|
|
121
|
+
|
|
122
|
+
For structured results, `becwright check --json` prints a machine-readable
|
|
123
|
+
summary, and `becwright mcp` (install the `mcp` extra: `pipx install
|
|
124
|
+
"becwright[mcp]"`) runs an MCP server exposing `check` and `list_checks` to any
|
|
125
|
+
agent. See [`documentation/mcp.md`](documentation/mcp.md).
|
|
126
|
+
|
|
95
127
|
A rule in `.bec/rules.yaml`:
|
|
96
128
|
|
|
97
129
|
```yaml
|
|
@@ -103,7 +135,7 @@ rules:
|
|
|
103
135
|
If a token shows up in the logs, anyone with access to them can steal a
|
|
104
136
|
user's session.
|
|
105
137
|
paths: ["src/**/*.py"]
|
|
106
|
-
check: "
|
|
138
|
+
check: "becwright run no_token_in_logs"
|
|
107
139
|
severity: blocking # blocking = stops the commit | warning = only warns
|
|
108
140
|
```
|
|
109
141
|
|
|
@@ -134,7 +166,7 @@ rules:
|
|
|
134
166
|
A secret in the repo stays in git history forever and is visible to
|
|
135
167
|
anyone with access to the code.
|
|
136
168
|
paths: ["src/**/*.py"]
|
|
137
|
-
check: "
|
|
169
|
+
check: "becwright run hardcoded_secrets"
|
|
138
170
|
severity: blocking
|
|
139
171
|
|
|
140
172
|
- id: no-debug-remnants
|
|
@@ -143,7 +175,7 @@ rules:
|
|
|
143
175
|
why_it_matters: >
|
|
144
176
|
A forgotten breakpoint hangs the process in production or CI.
|
|
145
177
|
paths: ["src/**/*.py"]
|
|
146
|
-
check: "
|
|
178
|
+
check: "becwright run debug_remnants"
|
|
147
179
|
severity: blocking
|
|
148
180
|
|
|
149
181
|
- id: no-dangerous-eval
|
|
@@ -152,7 +184,7 @@ rules:
|
|
|
152
184
|
why_it_matters: >
|
|
153
185
|
eval/exec on untrusted input is remote code execution.
|
|
154
186
|
paths: ["src/**/*.py"]
|
|
155
|
-
check: "
|
|
187
|
+
check: "becwright run dangerous_eval"
|
|
156
188
|
severity: blocking
|
|
157
189
|
|
|
158
190
|
- id: no-wildcard-imports
|
|
@@ -162,7 +194,7 @@ rules:
|
|
|
162
194
|
Wildcard imports hide where each name comes from and break static
|
|
163
195
|
analysis.
|
|
164
196
|
paths: ["src/**/*.py"]
|
|
165
|
-
check: "
|
|
197
|
+
check: "becwright run wildcard_imports"
|
|
166
198
|
severity: warning
|
|
167
199
|
```
|
|
168
200
|
|
|
@@ -183,7 +215,7 @@ rules:
|
|
|
183
215
|
why_it_matters: >
|
|
184
216
|
A forgotten 'debugger' halts execution and should not reach production.
|
|
185
217
|
paths: ["**/*.js", "**/*.ts"]
|
|
186
|
-
check: "
|
|
218
|
+
check: "becwright run forbid --pattern '\\bdebugger\\b'"
|
|
187
219
|
severity: blocking
|
|
188
220
|
```
|
|
189
221
|
|
|
@@ -214,10 +246,18 @@ Use `--yes` to skip the confirmation in automated environments.
|
|
|
214
246
|
There is a **catalog of ready-to-use BECs** in [`becs/`](becs/) that you can
|
|
215
247
|
import directly from their raw URL.
|
|
216
248
|
|
|
217
|
-
Built-in checks (`
|
|
249
|
+
Built-in checks (`becwright run *`) travel with the package, so
|
|
218
250
|
the bundle only stores their name. A **custom** check (`.bec/checks/foo.py`)
|
|
219
251
|
travels with its code embedded and lands in `.bec/checks/` of the target repo.
|
|
220
252
|
|
|
253
|
+
## Documentation
|
|
254
|
+
|
|
255
|
+
Technical documentation lives in [`documentation/`](documentation/):
|
|
256
|
+
[architecture & flow](documentation/architecture.md),
|
|
257
|
+
[usage & rules schema](documentation/usage.md),
|
|
258
|
+
[writing checks](documentation/writing-checks.md), and
|
|
259
|
+
[portability](documentation/portability.md).
|
|
260
|
+
|
|
221
261
|
## Current status
|
|
222
262
|
|
|
223
263
|
The **installable MVP** is built and verified end-to-end: packaged engine
|
|
@@ -50,26 +50,53 @@ becwright is installed once as a tool; each repo only contributes its own
|
|
|
50
50
|
`.bec/rules.yaml`.
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
|
-
# 1. Install the engine
|
|
54
|
-
|
|
53
|
+
# 1. Install the engine. Pick your ecosystem — no Python needed via npm/pnpm,
|
|
54
|
+
# which ship a self-contained binary:
|
|
55
|
+
npm install --save-dev becwright # or global: npm install -g becwright
|
|
56
|
+
pnpm add -D becwright
|
|
57
|
+
pipx install becwright # or: pip install becwright
|
|
55
58
|
|
|
56
|
-
# 2. In
|
|
57
|
-
becwright
|
|
59
|
+
# 2. In your repo, scaffold rules + install the hook
|
|
60
|
+
becwright init # detects your language, writes .bec/rules.yaml, installs the hook
|
|
58
61
|
|
|
59
|
-
# 3.
|
|
60
|
-
# 4. Done: each commit runs the checks; if a blocking rule fails, it stops.
|
|
62
|
+
# 3. Done: each commit runs the checks; if a blocking rule fails, it stops.
|
|
61
63
|
```
|
|
62
64
|
|
|
65
|
+
Installed as a devDependency, the pre-commit hook resolves the local binary from
|
|
66
|
+
`node_modules/.bin`, so it works without a global install. The npm packages cover
|
|
67
|
+
`linux-x64`, `linux-arm64`, `darwin-x64`, `darwin-arm64` and `win32-x64`; on any
|
|
68
|
+
other platform use `pipx install becwright`.
|
|
69
|
+
|
|
63
70
|
Available commands:
|
|
64
71
|
|
|
65
72
|
| Command | What it does |
|
|
66
73
|
|---|---|
|
|
74
|
+
| `becwright init` | Scaffold a starter `.bec/rules.yaml` and install the hook |
|
|
75
|
+
| `becwright list` | List the built-in checks |
|
|
67
76
|
| `becwright check` | Runs the rules over the staged files |
|
|
68
77
|
| `becwright install` | Installs the native `pre-commit` hook |
|
|
69
78
|
| `becwright uninstall` | Removes the hook |
|
|
70
79
|
| `becwright export <id>` | Exports a BEC to a `.bec.yaml` file |
|
|
71
80
|
| `becwright import <file\|URL>` | Imports a BEC from another repo |
|
|
72
81
|
|
|
82
|
+
### Use with AI agents (Claude Code)
|
|
83
|
+
|
|
84
|
+
becwright is the deterministic net for what an AI agent lets slip. There is a
|
|
85
|
+
Claude Code plugin so an agent can install and drive it for you:
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
/plugin marketplace add DataDave-Dev/becwright
|
|
89
|
+
/plugin install becwright@becwright
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
It adds a `becwright` skill and a `/becwright` command. See
|
|
93
|
+
[`integrations/claude-code/`](integrations/claude-code/).
|
|
94
|
+
|
|
95
|
+
For structured results, `becwright check --json` prints a machine-readable
|
|
96
|
+
summary, and `becwright mcp` (install the `mcp` extra: `pipx install
|
|
97
|
+
"becwright[mcp]"`) runs an MCP server exposing `check` and `list_checks` to any
|
|
98
|
+
agent. See [`documentation/mcp.md`](documentation/mcp.md).
|
|
99
|
+
|
|
73
100
|
A rule in `.bec/rules.yaml`:
|
|
74
101
|
|
|
75
102
|
```yaml
|
|
@@ -81,7 +108,7 @@ rules:
|
|
|
81
108
|
If a token shows up in the logs, anyone with access to them can steal a
|
|
82
109
|
user's session.
|
|
83
110
|
paths: ["src/**/*.py"]
|
|
84
|
-
check: "
|
|
111
|
+
check: "becwright run no_token_in_logs"
|
|
85
112
|
severity: blocking # blocking = stops the commit | warning = only warns
|
|
86
113
|
```
|
|
87
114
|
|
|
@@ -112,7 +139,7 @@ rules:
|
|
|
112
139
|
A secret in the repo stays in git history forever and is visible to
|
|
113
140
|
anyone with access to the code.
|
|
114
141
|
paths: ["src/**/*.py"]
|
|
115
|
-
check: "
|
|
142
|
+
check: "becwright run hardcoded_secrets"
|
|
116
143
|
severity: blocking
|
|
117
144
|
|
|
118
145
|
- id: no-debug-remnants
|
|
@@ -121,7 +148,7 @@ rules:
|
|
|
121
148
|
why_it_matters: >
|
|
122
149
|
A forgotten breakpoint hangs the process in production or CI.
|
|
123
150
|
paths: ["src/**/*.py"]
|
|
124
|
-
check: "
|
|
151
|
+
check: "becwright run debug_remnants"
|
|
125
152
|
severity: blocking
|
|
126
153
|
|
|
127
154
|
- id: no-dangerous-eval
|
|
@@ -130,7 +157,7 @@ rules:
|
|
|
130
157
|
why_it_matters: >
|
|
131
158
|
eval/exec on untrusted input is remote code execution.
|
|
132
159
|
paths: ["src/**/*.py"]
|
|
133
|
-
check: "
|
|
160
|
+
check: "becwright run dangerous_eval"
|
|
134
161
|
severity: blocking
|
|
135
162
|
|
|
136
163
|
- id: no-wildcard-imports
|
|
@@ -140,7 +167,7 @@ rules:
|
|
|
140
167
|
Wildcard imports hide where each name comes from and break static
|
|
141
168
|
analysis.
|
|
142
169
|
paths: ["src/**/*.py"]
|
|
143
|
-
check: "
|
|
170
|
+
check: "becwright run wildcard_imports"
|
|
144
171
|
severity: warning
|
|
145
172
|
```
|
|
146
173
|
|
|
@@ -161,7 +188,7 @@ rules:
|
|
|
161
188
|
why_it_matters: >
|
|
162
189
|
A forgotten 'debugger' halts execution and should not reach production.
|
|
163
190
|
paths: ["**/*.js", "**/*.ts"]
|
|
164
|
-
check: "
|
|
191
|
+
check: "becwright run forbid --pattern '\\bdebugger\\b'"
|
|
165
192
|
severity: blocking
|
|
166
193
|
```
|
|
167
194
|
|
|
@@ -192,10 +219,18 @@ Use `--yes` to skip the confirmation in automated environments.
|
|
|
192
219
|
There is a **catalog of ready-to-use BECs** in [`becs/`](becs/) that you can
|
|
193
220
|
import directly from their raw URL.
|
|
194
221
|
|
|
195
|
-
Built-in checks (`
|
|
222
|
+
Built-in checks (`becwright run *`) travel with the package, so
|
|
196
223
|
the bundle only stores their name. A **custom** check (`.bec/checks/foo.py`)
|
|
197
224
|
travels with its code embedded and lands in `.bec/checks/` of the target repo.
|
|
198
225
|
|
|
226
|
+
## Documentation
|
|
227
|
+
|
|
228
|
+
Technical documentation lives in [`documentation/`](documentation/):
|
|
229
|
+
[architecture & flow](documentation/architecture.md),
|
|
230
|
+
[usage & rules schema](documentation/usage.md),
|
|
231
|
+
[writing checks](documentation/writing-checks.md), and
|
|
232
|
+
[portability](documentation/portability.md).
|
|
233
|
+
|
|
199
234
|
## Current status
|
|
200
235
|
|
|
201
236
|
The **installable MVP** is built and verified end-to-end: packaged engine
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "becwright"
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.2.0"
|
|
10
10
|
description = "Deterministically enforces constraints (BECs) on your code, blocking commits that violate them."
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.12"
|
|
@@ -28,7 +28,11 @@ classifiers = [
|
|
|
28
28
|
becwright = "becwright.cli:main"
|
|
29
29
|
|
|
30
30
|
[project.optional-dependencies]
|
|
31
|
-
dev = ["pytest>=8", "pytest-cov>=5"]
|
|
31
|
+
dev = ["pytest>=8", "pytest-cov>=5", "mcp>=1.2"]
|
|
32
|
+
# Used to freeze the standalone binary distributed via npm (see packaging/).
|
|
33
|
+
build = ["pyinstaller>=6"]
|
|
34
|
+
# MCP server for AI agents: `becwright mcp` (see src/becwright/mcp_server.py).
|
|
35
|
+
mcp = ["mcp>=1.2"]
|
|
32
36
|
|
|
33
37
|
[tool.setuptools.packages.find]
|
|
34
38
|
where = ["src"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.0"
|
|
@@ -11,7 +11,11 @@ from .rules import Rule
|
|
|
11
11
|
|
|
12
12
|
BUNDLE_VERSION = 1
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
# Accept the current `becwright run <module>` form and the legacy
|
|
15
|
+
# `python3 -m becwright.checks.<module>` form so older bundles still import.
|
|
16
|
+
_BUILTIN = re.compile(
|
|
17
|
+
r"^(?:becwright\s+run\s+(\w+)|python3?\s+-m\s+becwright\.checks\.(\w+))(?:\s+(.*))?$"
|
|
18
|
+
)
|
|
15
19
|
_PY_PATH = re.compile(r"[\w./-]+\.py")
|
|
16
20
|
_ITEM_INDENT = re.compile(r"^([ \t]+)-\s", re.MULTILINE)
|
|
17
21
|
_EMPTY_RULES = re.compile(r"^rules:[ \t]*(?:\[[ \t]*\]|\{[ \t]*\})[ \t]*$", re.MULTILINE)
|
|
@@ -41,9 +45,9 @@ def classify_check(command: str, root: Path) -> dict:
|
|
|
41
45
|
command = command.strip()
|
|
42
46
|
builtin = _BUILTIN.match(command)
|
|
43
47
|
if builtin:
|
|
44
|
-
out = {"kind": "builtin", "module": builtin.group(1)}
|
|
45
|
-
if builtin.group(
|
|
46
|
-
out["args"] = builtin.group(
|
|
48
|
+
out = {"kind": "builtin", "module": builtin.group(1) or builtin.group(2)}
|
|
49
|
+
if builtin.group(3):
|
|
50
|
+
out["args"] = builtin.group(3).strip()
|
|
47
51
|
return out
|
|
48
52
|
for token in _PY_PATH.findall(command):
|
|
49
53
|
candidate = root / token
|
|
@@ -108,7 +112,7 @@ def materialize(bundle: dict, root: Path) -> dict:
|
|
|
108
112
|
check = bundle["check"]
|
|
109
113
|
kind = check.get("kind")
|
|
110
114
|
if kind == "builtin":
|
|
111
|
-
command = f"
|
|
115
|
+
command = f"becwright run {check['module']}"
|
|
112
116
|
if check.get("args"):
|
|
113
117
|
command += f" {check['args']}"
|
|
114
118
|
elif kind == "script":
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
# A line carrying this marker (inside a comment, in any language) is exempt from
|
|
6
|
+
# any check: `# becwright: ignore`, `// becwright: ignore`, etc.
|
|
7
|
+
_MARKER = re.compile(r"becwright:\s*ignore\b", re.IGNORECASE)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def is_ignored(line: str) -> bool:
|
|
11
|
+
return bool(_MARKER.search(line))
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import re
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
+
from ._ignore import is_ignored
|
|
7
|
+
|
|
6
8
|
PATTERN = re.compile(r"\b(?:eval|exec)\s*\(")
|
|
7
9
|
|
|
8
10
|
|
|
@@ -15,7 +17,7 @@ def find_violations(paths: list[str]) -> list[tuple[str, int, str]]:
|
|
|
15
17
|
try:
|
|
16
18
|
with open(path, encoding="utf-8") as f:
|
|
17
19
|
for lineno, line in enumerate(f, start=1):
|
|
18
|
-
if PATTERN.search(line):
|
|
20
|
+
if PATTERN.search(line) and not is_ignored(line):
|
|
19
21
|
violations.append((path, lineno, line.strip()))
|
|
20
22
|
except (FileNotFoundError, IsADirectoryError, UnicodeDecodeError):
|
|
21
23
|
continue
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import re
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
+
from ._ignore import is_ignored
|
|
7
|
+
|
|
6
8
|
PATTERN = re.compile(
|
|
7
9
|
r"\bbreakpoint\s*\(|\b(?:i?pdb)\.set_trace\s*\(|\bimport\s+i?pdb\b"
|
|
8
10
|
)
|
|
@@ -17,7 +19,7 @@ def find_violations(paths: list[str]) -> list[tuple[str, int, str]]:
|
|
|
17
19
|
try:
|
|
18
20
|
with open(path, encoding="utf-8") as f:
|
|
19
21
|
for lineno, line in enumerate(f, start=1):
|
|
20
|
-
if PATTERN.search(line):
|
|
22
|
+
if PATTERN.search(line) and not is_ignored(line):
|
|
21
23
|
violations.append((path, lineno, line.strip()))
|
|
22
24
|
except (FileNotFoundError, IsADirectoryError, UnicodeDecodeError):
|
|
23
25
|
continue
|
|
@@ -4,6 +4,8 @@ import argparse
|
|
|
4
4
|
import re
|
|
5
5
|
import sys
|
|
6
6
|
|
|
7
|
+
from ._ignore import is_ignored
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
def find_violations(paths: list[str], pattern: str, flags: int = 0) -> list[tuple[str, int, str]]:
|
|
9
11
|
rx = re.compile(pattern, flags)
|
|
@@ -15,7 +17,7 @@ def find_violations(paths: list[str], pattern: str, flags: int = 0) -> list[tupl
|
|
|
15
17
|
try:
|
|
16
18
|
with open(path, encoding="utf-8") as f:
|
|
17
19
|
for lineno, line in enumerate(f, start=1):
|
|
18
|
-
if rx.search(line):
|
|
20
|
+
if rx.search(line) and not is_ignored(line):
|
|
19
21
|
violations.append((path, lineno, line.strip()))
|
|
20
22
|
except (FileNotFoundError, IsADirectoryError, UnicodeDecodeError):
|
|
21
23
|
continue
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import re
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
+
from ._ignore import is_ignored
|
|
7
|
+
|
|
6
8
|
_AWS_KEY = r"AKIA[0-9A-Z]{16}"
|
|
7
9
|
_PRIVATE_KEY = r"-----BEGIN [A-Z ]*PRIVATE KEY-----"
|
|
8
10
|
_ASSIGNMENT = (
|
|
@@ -27,7 +29,7 @@ def find_violations(paths: list[str]) -> list[tuple[str, int, str]]:
|
|
|
27
29
|
try:
|
|
28
30
|
with open(path, encoding="utf-8") as f:
|
|
29
31
|
for lineno, line in enumerate(f, start=1):
|
|
30
|
-
if PATTERN.search(line) and not _PLACEHOLDER.search(line):
|
|
32
|
+
if PATTERN.search(line) and not _PLACEHOLDER.search(line) and not is_ignored(line):
|
|
31
33
|
violations.append((path, lineno, line.strip()))
|
|
32
34
|
except (FileNotFoundError, IsADirectoryError, UnicodeDecodeError):
|
|
33
35
|
continue
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import re
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
+
from ._ignore import is_ignored
|
|
7
|
+
|
|
6
8
|
SENSITIVE = r"(token|password|passwd|secret|api[_-]?key|credential|session[_-]?id)"
|
|
7
9
|
LOG_CALL = r"(log\.|logger\.|logging\.|print\s*\()"
|
|
8
10
|
# A log call that mentions something sensitive on the same line.
|
|
@@ -18,7 +20,7 @@ def find_violations(paths: list[str]) -> list[tuple[str, int, str]]:
|
|
|
18
20
|
try:
|
|
19
21
|
with open(path, encoding="utf-8") as f:
|
|
20
22
|
for lineno, line in enumerate(f, start=1):
|
|
21
|
-
if PATTERN.search(line):
|
|
23
|
+
if PATTERN.search(line) and not is_ignored(line):
|
|
22
24
|
violations.append((path, lineno, line.strip()))
|
|
23
25
|
except (FileNotFoundError, IsADirectoryError, UnicodeDecodeError):
|
|
24
26
|
continue
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
import re
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
+
from ._ignore import is_ignored
|
|
7
|
+
|
|
6
8
|
PATTERN = re.compile(r"^\s*from\s+[\w.]+\s+import\s+\*")
|
|
7
9
|
|
|
8
10
|
|
|
@@ -15,7 +17,7 @@ def find_violations(paths: list[str]) -> list[tuple[str, int, str]]:
|
|
|
15
17
|
try:
|
|
16
18
|
with open(path, encoding="utf-8") as f:
|
|
17
19
|
for lineno, line in enumerate(f, start=1):
|
|
18
|
-
if PATTERN.search(line):
|
|
20
|
+
if PATTERN.search(line) and not is_ignored(line):
|
|
19
21
|
violations.append((path, lineno, line.strip()))
|
|
20
22
|
except (FileNotFoundError, IsADirectoryError, UnicodeDecodeError):
|
|
21
23
|
continue
|