codejury 1.0.0__tar.gz → 1.0.1__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.
- {codejury-1.0.0 → codejury-1.0.1}/PKG-INFO +19 -10
- {codejury-1.0.0 → codejury-1.0.1}/README.md +18 -9
- {codejury-1.0.0 → codejury-1.0.1}/codejury/cli.py +21 -11
- {codejury-1.0.0 → codejury-1.0.1}/codejury/guides.py +2 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/languages/python.md +0 -2
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/protocols/oauth.md +1 -1
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/cross-site-request-forgery.md +14 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/server-side-request-forgery.md +2 -2
- {codejury-1.0.0 → codejury-1.0.1}/codejury/playbook/false-positive-traps.md +4 -4
- {codejury-1.0.0 → codejury-1.0.1}/codejury/playbook/methodology.md +7 -5
- {codejury-1.0.0 → codejury-1.0.1}/codejury/playbook/slash-command.md +14 -8
- {codejury-1.0.0 → codejury-1.0.1}/codejury/playbook/unit-review.md +14 -7
- {codejury-1.0.0 → codejury-1.0.1}/codejury/providers/anthropic.py +39 -9
- {codejury-1.0.0 → codejury-1.0.1}/codejury/providers/litellm.py +1 -1
- {codejury-1.0.0 → codejury-1.0.1}/codejury/providers/openai.py +1 -1
- codejury-1.0.0/codejury/review/diff/engine.py → codejury-1.0.1/codejury/review/diff/audit.py +3 -2
- codejury-1.0.0/codejury/review/diff/runner.py → codejury-1.0.1/codejury/review/diff/engine.py +1 -1
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/agent.py +3 -5
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/engine.py +140 -36
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/gate.py +5 -5
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/model.py +0 -1
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/paths.py +1 -1
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/reviewer.py +19 -20
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/scaffold.py +27 -10
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/severity.py +1 -0
- codejury-1.0.1/codejury/review/repo/shapes.py +23 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/verifier.py +30 -4
- {codejury-1.0.0 → codejury-1.0.1}/codejury.egg-info/PKG-INFO +19 -10
- {codejury-1.0.0 → codejury-1.0.1}/codejury.egg-info/SOURCES.txt +8 -4
- {codejury-1.0.0 → codejury-1.0.1}/pyproject.toml +1 -1
- codejury-1.0.1/tests/test_anthropic_provider.py +108 -0
- codejury-1.0.0/tests/test_openai_format.py → codejury-1.0.1/tests/test_chat_format.py +1 -1
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_cli.py +16 -7
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_diff_adversarial.py +9 -6
- codejury-1.0.0/tests/test_diff_engine.py → codejury-1.0.1/tests/test_diff_audit.py +6 -6
- codejury-1.0.1/tests/test_evals.py +392 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_guides.py +1 -1
- codejury-1.0.1/tests/test_json_parse.py +79 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_litellm_provider.py +32 -1
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_openai_provider.py +40 -1
- codejury-1.0.1/tests/test_provider_factory.py +31 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_repo_engine.py +95 -35
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_repo_gate.py +6 -5
- codejury-1.0.1/tests/test_repo_paths.py +42 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_repo_scaffold.py +20 -11
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_repo_verifier.py +15 -14
- codejury-1.0.0/tests/test_anthropic_provider.py +0 -54
- codejury-1.0.0/tests/test_json_parse.py +0 -41
- {codejury-1.0.0 → codejury-1.0.1}/LICENSE +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/__init__.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/__main__.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/detection.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/detection.yaml +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/finding.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/json_parse.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/frameworks/go/echo.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/frameworks/go/gin.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/frameworks/javascript/express.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/frameworks/javascript/nestjs.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/frameworks/python/celery.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/frameworks/python/django.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/frameworks/python/fastapi.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/frameworks/python/flask.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/languages/go.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/languages/javascript.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/guides/languages/typescript.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/index.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/business-logic.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/code-injection.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/command-injection.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/cross-site-scripting.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/hardcoded-secrets.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/http-response-splitting.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/improper-authentication.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/information-exposure.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/insecure-cryptography.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/insecure-deserialization.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/insecure-direct-object-reference.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/insecure-session-management.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/insecure-transport.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/jwt-validation.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/mass-assignment.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/missing-authorization.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/open-redirect.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/path-traversal.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/race-condition.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/replay-attack.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/server-side-template-injection.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/sql-injection.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/xml-external-entity.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/markdown_docs.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/playbook/severity-rubric.md +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/providers/__init__.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/providers/base.py +0 -0
- /codejury-1.0.0/codejury/providers/openai_format.py → /codejury-1.0.1/codejury/providers/chat_format.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/providers/factory.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/providers/mock.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/providers/retry.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/report.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/resources.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/__init__.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/diff/__init__.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/diff/adversarial.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/diff/filter.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/diff/prompts.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/diff/vulnerabilities.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/__init__.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/pass_loop.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/review/repo/union.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury/severity.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury.egg-info/dependency_links.txt +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury.egg-info/entry_points.txt +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury.egg-info/requires.txt +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/codejury.egg-info/top_level.txt +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/setup.cfg +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_detection.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_markdown_docs.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_repo_agent.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_repo_model.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_repo_pass_loop.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_repo_severity.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_repo_union.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_report.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_retry_provider.py +0 -0
- {codejury-1.0.0 → codejury-1.0.1}/tests/test_vulnerabilities.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codejury
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: AI-assisted security review for code diffs and whole repositories.
|
|
5
5
|
Author: AISecLabs
|
|
6
6
|
License-Expression: MIT
|
|
@@ -35,7 +35,7 @@ Requires-Dist: pytest>=8.0; extra == "dev"
|
|
|
35
35
|
Requires-Dist: jsonschema>=4.0; extra == "dev"
|
|
36
36
|
Dynamic: license-file
|
|
37
37
|
|
|
38
|
-
```
|
|
38
|
+
```text
|
|
39
39
|
██████╗ ██████╗ ██████╗ ███████╗ ██╗██╗ ██╗██████╗ ██╗ ██╗
|
|
40
40
|
██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██║██║ ██║██╔══██╗╚██╗ ██╔╝
|
|
41
41
|
██║ ██║ ██║██║ ██║█████╗ ██║██║ ██║██████╔╝ ╚████╔╝
|
|
@@ -44,6 +44,10 @@ Dynamic: license-file
|
|
|
44
44
|
╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
[](https://pypi.org/project/codejury/)
|
|
48
|
+
[](https://pypi.org/project/codejury/)
|
|
49
|
+
[](https://github.com/aiseclabs/codejury/blob/master/LICENSE)
|
|
50
|
+
|
|
47
51
|
AI-assisted security review for code diffs and whole repositories.
|
|
48
52
|
|
|
49
53
|
The tool has two review paths:
|
|
@@ -75,7 +79,7 @@ codejury install-slash-command --agent codex # Codex
|
|
|
75
79
|
`install-slash-command` copies `/codejury-review-repo` into the selected agent's command
|
|
76
80
|
directory. Pass `--dir` to install it somewhere else.
|
|
77
81
|
|
|
78
|
-
## Configure
|
|
82
|
+
## Configure a Model Backend
|
|
79
83
|
|
|
80
84
|
Set a provider key through flags or environment variables:
|
|
81
85
|
|
|
@@ -156,12 +160,16 @@ codejury review repo /path/to/repo
|
|
|
156
160
|
The workspace contains:
|
|
157
161
|
|
|
158
162
|
```text
|
|
159
|
-
inventory/ attack surface, authorization model,
|
|
163
|
+
inventory/ attack surface, authorization model, seeded entrypoints, severity rubric
|
|
160
164
|
units/ one review unit per candidate entrypoint
|
|
161
|
-
|
|
165
|
+
candidates/ agent proposals, one write-up per candidate finding
|
|
166
|
+
findings/ confirmed findings, written by finalize
|
|
162
167
|
pocs/ runnable PoCs, when available
|
|
168
|
+
findings.json ranked machine-readable findings
|
|
163
169
|
METHODOLOGY.md full review process
|
|
164
170
|
_stack.md detected stack notes
|
|
171
|
+
_refuted.md refuted candidates and why
|
|
172
|
+
_pocs.md PoC reconciliation, planned versus delivered
|
|
165
173
|
```
|
|
166
174
|
|
|
167
175
|
Then run the interactive slash command in Claude Code or Codex:
|
|
@@ -181,9 +189,10 @@ codejury review repo /path/to/repo --finalize
|
|
|
181
189
|
codejury review repo /path/to/repo --gate
|
|
182
190
|
```
|
|
183
191
|
|
|
184
|
-
`--finalize` deduplicates
|
|
185
|
-
`
|
|
186
|
-
|
|
192
|
+
`--finalize` deduplicates candidate files, verifies survivors, writes the confirmed
|
|
193
|
+
`findings/`, records refuted candidates in `_refuted.md` and PoC reconciliation in
|
|
194
|
+
`_pocs.md`, and writes ranked `findings.json`. `--gate` fails until the workspace has an
|
|
195
|
+
enumerated surface, reviewed units, and calibrated candidates.
|
|
187
196
|
|
|
188
197
|
For a headless run, use:
|
|
189
198
|
|
|
@@ -221,7 +230,7 @@ The tool is intentionally scoped to real exploitable application security issues
|
|
|
221
230
|
not report dependency CVEs, style notes, generic best practices, speculation, or risks that
|
|
222
231
|
only matter if production configuration leaks.
|
|
223
232
|
|
|
224
|
-
## Model
|
|
233
|
+
## Model and Mode Guidance
|
|
225
234
|
|
|
226
235
|
Detection quality is dominated by model quality first, then mode.
|
|
227
236
|
|
|
@@ -241,7 +250,7 @@ cp examples/codejury-pr-review.yml .github/workflows/codejury-pr-review.yml
|
|
|
241
250
|
Add `CODEJURY_API_KEY` as a repository secret. The workflow reviews the pull request diff,
|
|
242
251
|
uploads SARIF to code scanning, and fails on HIGH or CRITICAL findings.
|
|
243
252
|
|
|
244
|
-
## Extend
|
|
253
|
+
## Extend the Knowledge
|
|
245
254
|
|
|
246
255
|
Add security knowledge as markdown:
|
|
247
256
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
```
|
|
1
|
+
```text
|
|
2
2
|
██████╗ ██████╗ ██████╗ ███████╗ ██╗██╗ ██╗██████╗ ██╗ ██╗
|
|
3
3
|
██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██║██║ ██║██╔══██╗╚██╗ ██╔╝
|
|
4
4
|
██║ ██║ ██║██║ ██║█████╗ ██║██║ ██║██████╔╝ ╚████╔╝
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
+
[](https://pypi.org/project/codejury/)
|
|
11
|
+
[](https://pypi.org/project/codejury/)
|
|
12
|
+
[](https://github.com/aiseclabs/codejury/blob/master/LICENSE)
|
|
13
|
+
|
|
10
14
|
AI-assisted security review for code diffs and whole repositories.
|
|
11
15
|
|
|
12
16
|
The tool has two review paths:
|
|
@@ -38,7 +42,7 @@ codejury install-slash-command --agent codex # Codex
|
|
|
38
42
|
`install-slash-command` copies `/codejury-review-repo` into the selected agent's command
|
|
39
43
|
directory. Pass `--dir` to install it somewhere else.
|
|
40
44
|
|
|
41
|
-
## Configure
|
|
45
|
+
## Configure a Model Backend
|
|
42
46
|
|
|
43
47
|
Set a provider key through flags or environment variables:
|
|
44
48
|
|
|
@@ -119,12 +123,16 @@ codejury review repo /path/to/repo
|
|
|
119
123
|
The workspace contains:
|
|
120
124
|
|
|
121
125
|
```text
|
|
122
|
-
inventory/ attack surface, authorization model,
|
|
126
|
+
inventory/ attack surface, authorization model, seeded entrypoints, severity rubric
|
|
123
127
|
units/ one review unit per candidate entrypoint
|
|
124
|
-
|
|
128
|
+
candidates/ agent proposals, one write-up per candidate finding
|
|
129
|
+
findings/ confirmed findings, written by finalize
|
|
125
130
|
pocs/ runnable PoCs, when available
|
|
131
|
+
findings.json ranked machine-readable findings
|
|
126
132
|
METHODOLOGY.md full review process
|
|
127
133
|
_stack.md detected stack notes
|
|
134
|
+
_refuted.md refuted candidates and why
|
|
135
|
+
_pocs.md PoC reconciliation, planned versus delivered
|
|
128
136
|
```
|
|
129
137
|
|
|
130
138
|
Then run the interactive slash command in Claude Code or Codex:
|
|
@@ -144,9 +152,10 @@ codejury review repo /path/to/repo --finalize
|
|
|
144
152
|
codejury review repo /path/to/repo --gate
|
|
145
153
|
```
|
|
146
154
|
|
|
147
|
-
`--finalize` deduplicates
|
|
148
|
-
`
|
|
149
|
-
|
|
155
|
+
`--finalize` deduplicates candidate files, verifies survivors, writes the confirmed
|
|
156
|
+
`findings/`, records refuted candidates in `_refuted.md` and PoC reconciliation in
|
|
157
|
+
`_pocs.md`, and writes ranked `findings.json`. `--gate` fails until the workspace has an
|
|
158
|
+
enumerated surface, reviewed units, and calibrated candidates.
|
|
150
159
|
|
|
151
160
|
For a headless run, use:
|
|
152
161
|
|
|
@@ -184,7 +193,7 @@ The tool is intentionally scoped to real exploitable application security issues
|
|
|
184
193
|
not report dependency CVEs, style notes, generic best practices, speculation, or risks that
|
|
185
194
|
only matter if production configuration leaks.
|
|
186
195
|
|
|
187
|
-
## Model
|
|
196
|
+
## Model and Mode Guidance
|
|
188
197
|
|
|
189
198
|
Detection quality is dominated by model quality first, then mode.
|
|
190
199
|
|
|
@@ -204,7 +213,7 @@ cp examples/codejury-pr-review.yml .github/workflows/codejury-pr-review.yml
|
|
|
204
213
|
Add `CODEJURY_API_KEY` as a repository secret. The workflow reviews the pull request diff,
|
|
205
214
|
uploads SARIF to code scanning, and fails on HIGH or CRITICAL findings.
|
|
206
215
|
|
|
207
|
-
## Extend
|
|
216
|
+
## Extend the Knowledge
|
|
208
217
|
|
|
209
218
|
Add security knowledge as markdown:
|
|
210
219
|
|
|
@@ -9,19 +9,20 @@ Two paths matched to their nature:
|
|
|
9
9
|
which a single call cannot do for a whole codebase.
|
|
10
10
|
|
|
11
11
|
``review diff --dry-run`` exercises the engine with a mock provider and no key.
|
|
12
|
-
The audit orchestration itself lives in ``codejury.review.diff.
|
|
12
|
+
The audit orchestration itself lives in ``codejury.review.diff.engine``.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import argparse
|
|
18
|
+
import os
|
|
18
19
|
import subprocess
|
|
19
20
|
import sys
|
|
20
21
|
from pathlib import Path
|
|
21
22
|
|
|
22
23
|
from codejury import __version__
|
|
23
24
|
from codejury.report import gate, render
|
|
24
|
-
from codejury.review.diff.
|
|
25
|
+
from codejury.review.diff.engine import audit_diff
|
|
25
26
|
from codejury.providers.factory import (
|
|
26
27
|
DEFAULT_API_BASE,
|
|
27
28
|
DEFAULT_API_KEY,
|
|
@@ -39,6 +40,12 @@ _FORMATS = ("text", "markdown", "json", "sarif")
|
|
|
39
40
|
_FAIL_ON = ("critical", "high", "medium", "low")
|
|
40
41
|
|
|
41
42
|
|
|
43
|
+
def _default_workspace() -> str:
|
|
44
|
+
"""A user-private default, since the workspace holds the auth model, exploit paths, and PoCs."""
|
|
45
|
+
base = os.environ.get("XDG_STATE_HOME") or str(Path.home() / ".local" / "state")
|
|
46
|
+
return str(Path(base) / "codejury" / "reviews")
|
|
47
|
+
|
|
48
|
+
|
|
42
49
|
def _read_diff(args) -> str:
|
|
43
50
|
if args.file:
|
|
44
51
|
with open(args.file, encoding="utf-8") as f:
|
|
@@ -102,7 +109,9 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
102
109
|
_add_audit_args(rsub.add_parser("diff", help="audit a unified diff (the coded engine)"))
|
|
103
110
|
repo = rsub.add_parser("repo", help="scaffold a whole-repo review for an interactive agent")
|
|
104
111
|
repo.add_argument("directory", help="target repository to review")
|
|
105
|
-
repo.add_argument("--workspace", default=
|
|
112
|
+
repo.add_argument("--workspace", default=_default_workspace(),
|
|
113
|
+
help="where to create the review workspace, defaults to a user-private "
|
|
114
|
+
"directory under XDG_STATE_HOME or ~/.local/state")
|
|
106
115
|
repo.add_argument("--fresh", action="store_true",
|
|
107
116
|
help="clear a previous review's output in the workspace first")
|
|
108
117
|
repo.add_argument("--gate", action="store_true",
|
|
@@ -112,7 +121,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
112
121
|
help="run the coded multi-pass engine over the repo, not just scaffold, "
|
|
113
122
|
"covers every unit each pass, cycles lenses, unions until convergence")
|
|
114
123
|
repo.add_argument("--finalize", action="store_true",
|
|
115
|
-
help="post-process an existing workspace's
|
|
124
|
+
help="post-process an existing workspace's candidates in code: dedup, "
|
|
116
125
|
"adversarially verify, and write the ranked report, resumable")
|
|
117
126
|
repo.add_argument("--dry-run", action="store_true",
|
|
118
127
|
help="run only: drive the engine with a mock provider and no key, to smoke-test the pipeline")
|
|
@@ -211,9 +220,10 @@ def _dispatch(args, parser) -> int:
|
|
|
211
220
|
)
|
|
212
221
|
kept = len(fr.verify.confirmed) if fr.verify else fr.deduped
|
|
213
222
|
refuted = len(fr.verify.refuted) if fr.verify else 0
|
|
214
|
-
print(f"Finalize done: parsed {fr.parsed}
|
|
223
|
+
print(f"Finalize done: parsed {fr.parsed} candidates -> {fr.deduped} after dedup -> "
|
|
215
224
|
f"{kept} confirmed, {refuted} refuted, see {fr.workspace}/_refuted.md.")
|
|
216
|
-
print(f"
|
|
225
|
+
print(f"Confirmed findings in {fr.workspace}/findings/ and {fr.workspace}/findings.json, "
|
|
226
|
+
f"PoC reconciliation in {fr.workspace}/_pocs.md")
|
|
217
227
|
if fr.verify and fr.verify.errors:
|
|
218
228
|
print(f"WARNING: {fr.verify.errors} verification calls failed. Re-run to resume.", file=sys.stderr)
|
|
219
229
|
return 1 # fail loud: an incomplete verification is not a clean finalize, invariant 3
|
|
@@ -259,7 +269,7 @@ def _dispatch(args, parser) -> int:
|
|
|
259
269
|
print(f"WARNING: {failures} model calls failed, e.g. provider errors or rate limits. "
|
|
260
270
|
"Results may be understated. Lower --concurrency or raise --retries and re-run.",
|
|
261
271
|
file=sys.stderr)
|
|
262
|
-
print(f"Findings written to {res.scaffold.workspace}/
|
|
272
|
+
print(f"Findings written to {res.scaffold.workspace}/findings/ and {res.scaffold.workspace}/findings.json")
|
|
263
273
|
return 1 if failures else 0 # fail loud: a partial run must not exit clean, invariant 3
|
|
264
274
|
|
|
265
275
|
if args.command == "review" and scope == "repo":
|
|
@@ -275,13 +285,13 @@ def _dispatch(args, parser) -> int:
|
|
|
275
285
|
print(f"Detected stack: {', '.join(res.guides)}, notes in {res.workspace}/_stack.md", file=sys.stderr)
|
|
276
286
|
print(f"Seeded {len(res.candidate_files)} candidate entrypoint files and "
|
|
277
287
|
f"{len(res.trace_targets)} logic-layer trace targets into "
|
|
278
|
-
f"{res.workspace}/inventory/
|
|
288
|
+
f"{res.workspace}/inventory/_entrypoints.md", file=sys.stderr)
|
|
279
289
|
print(f"Methodology: {res.workspace}/METHODOLOGY.md", file=sys.stderr)
|
|
280
290
|
print(
|
|
281
|
-
"This command sets up the review, it does not find
|
|
291
|
+
"This command sets up the review, it does not find anything itself. Next, have an "
|
|
282
292
|
f"interactive agent follow {res.workspace}/METHODOLOGY.md to run the review, or use the "
|
|
283
|
-
"/codejury-review-repo command in Claude Code or Codex.
|
|
284
|
-
f"{res.workspace}/
|
|
293
|
+
"/codejury-review-repo command in Claude Code or Codex. The agent proposes findings in "
|
|
294
|
+
f"{res.workspace}/candidates/, finalize confirms them into {res.workspace}/findings/."
|
|
285
295
|
)
|
|
286
296
|
return 0
|
|
287
297
|
|
|
@@ -87,6 +87,8 @@ def logic_layer_globs(guides: list[Guide]) -> tuple[str, ...]:
|
|
|
87
87
|
def load_guides(languages_dir=LANGUAGES_DIR, frameworks_dir=FRAMEWORKS_DIR, protocols_dir=PROTOCOLS_DIR) -> list[Guide]:
|
|
88
88
|
# a guide's kind comes from its frontmatter, never from the directory it sits in, so the two cannot drift
|
|
89
89
|
out: list[Guide] = []
|
|
90
|
+
# languages first, then frameworks, then protocols, select_guides keeps this order so a
|
|
91
|
+
# language guide outranks a framework guide when both fire on the same target
|
|
90
92
|
for directory in (languages_dir, frameworks_dir, protocols_dir):
|
|
91
93
|
out += [_guide(path, meta, body) for path, meta, body in iter_md_docs(directory)]
|
|
92
94
|
return out
|
|
@@ -4,8 +4,6 @@ title: Python
|
|
|
4
4
|
kind: language
|
|
5
5
|
detect:
|
|
6
6
|
files: ["*.py"]
|
|
7
|
-
manifest: []
|
|
8
|
-
imports: []
|
|
9
7
|
entrypoint_files: ["*__main__.py", "*main.py", "*cli.py", "*/cli/*.py", "*/commands/*.py"]
|
|
10
8
|
entrypoint_markers: ["argparse", "ArgumentParser", "click.command", "click.group", "@click.command", "@click.group"]
|
|
11
9
|
logic_layers: ["*/services/*.py", "*services.py", "*/managers/*.py", "*managers.py", "*/dao/*.py", "*dao.py", "*/repositories/*.py", "*/repository/*.py"]
|
|
@@ -3,7 +3,7 @@ id: oauth
|
|
|
3
3
|
title: OAuth and OIDC
|
|
4
4
|
kind: protocol
|
|
5
5
|
detect:
|
|
6
|
-
content: ["grant_type", "authorization_code", "redirect_uri", "code_challenge", "response_type", "client_secret", "openid-configuration"]
|
|
6
|
+
content: ["grant_type", "authorization_code", "redirect_uri", "code_challenge", "response_type", "client_secret", "openid-configuration", "exchange_code"]
|
|
7
7
|
---
|
|
8
8
|
# OAuth and OIDC Review Notes
|
|
9
9
|
|
{codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/cross-site-request-forgery.md
RENAMED
|
@@ -21,6 +21,20 @@ def change_email():
|
|
|
21
21
|
```
|
|
22
22
|
Secure: keep CSRF protection on. Validate the token, or set the session cookie `SameSite="Lax"` and check the Origin header.
|
|
23
23
|
|
|
24
|
+
### OAuth Login CSRF
|
|
25
|
+
|
|
26
|
+
An OAuth callback that redeems the `code` and starts a session is a state-changing request. When it does not check a `state` value bound to the user's session, an attacker can hand the victim a code from the attacker's account and log the victim into it, login CSRF.
|
|
27
|
+
|
|
28
|
+
Vulnerable:
|
|
29
|
+
```python
|
|
30
|
+
@app.route("/oauth/callback")
|
|
31
|
+
def callback():
|
|
32
|
+
token = exchange_code(request.args["code"]) # no state check, any code is accepted
|
|
33
|
+
login(token)
|
|
34
|
+
return redirect("/")
|
|
35
|
+
```
|
|
36
|
+
Secure: issue a random `state` at authorize time, keep it in the session, and reject the callback unless the returned `state` matches.
|
|
37
|
+
|
|
24
38
|
### Not a Finding
|
|
25
39
|
|
|
26
40
|
An endpoint authenticated by a bearer token read from JavaScript and sent in the `Authorization` header, not by an ambient cookie, is not CSRF. CSRF needs a credential the browser attaches automatically.
|
{codejury-1.0.0 → codejury-1.0.1}/codejury/knowledge/vulnerabilities/server-side-request-forgery.md
RENAMED
|
@@ -22,8 +22,8 @@ if urlparse(url).hostname not in ALLOWED_HOSTS:
|
|
|
22
22
|
return requests.get(url).text
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Stronger hardening adds defense in depth: enforce `https`, reject credentials in the URL, resolve the host and block private, loopback, and link-local ranges, and re-check after each redirect. Prefer an exact destination allowlist.
|
|
26
26
|
|
|
27
27
|
### Not a Finding
|
|
28
28
|
|
|
29
|
-
A URL fetched only after
|
|
29
|
+
A URL fetched only after the parsed hostname is checked against a fixed allowlist by exact equality or membership before the fetch is the expected control and is not reportable without a concrete bypass. Report it only when the check is bypassable, such as a substring, suffix, or `startswith` match, an attacker-controlled allowlist, or a redirect followed with no re-check. Missing internal-IP blocking or redirect re-checks on top of an exact allowlist is hardening advice, not by itself an exploitable finding. A constant or trusted-config URL is not SSRF.
|
|
@@ -17,7 +17,7 @@ recurring misjudgement, add it here.
|
|
|
17
17
|
- `transaction.atomic()` plus a real row lock serializes concurrent redeems even
|
|
18
18
|
on READ COMMITTED. The race only exists if no lock is taken on the contended row.
|
|
19
19
|
|
|
20
|
-
## Input That Looks Attacker-Controlled
|
|
20
|
+
## Input That Looks Attacker-Controlled but Is Not
|
|
21
21
|
|
|
22
22
|
- An id, ticket, or key read from the session, a signed cookie, or a server-set
|
|
23
23
|
field is not attacker-controlled even though it arrives in the request object.
|
|
@@ -25,7 +25,7 @@ recurring misjudgement, add it here.
|
|
|
25
25
|
- A value the framework derives from an authenticated identity, not from the
|
|
26
26
|
request body, is trusted input.
|
|
27
27
|
|
|
28
|
-
## Controls That Live
|
|
28
|
+
## Controls That Live off the Handler Body
|
|
29
29
|
|
|
30
30
|
- The auth, ownership, or signature check may be in a decorator, a middleware, a
|
|
31
31
|
permission class, a base class, or a wrapper, not in the handler you are reading.
|
|
@@ -36,14 +36,14 @@ recurring misjudgement, add it here.
|
|
|
36
36
|
|
|
37
37
|
- "The caller is authenticated", "the scheme fails closed", or "the token is
|
|
38
38
|
single-use" do not by themselves make a request non-replayable. Conversely, if a
|
|
39
|
-
nonce
|
|
39
|
+
nonce is consumed and a freshness window is enforced, the replay concern is moot.
|
|
40
40
|
Controlling fact: is the exact signed request accepted twice, or is a nonce
|
|
41
41
|
consumed and a timestamp window checked?
|
|
42
42
|
|
|
43
43
|
## Trust Boundaries
|
|
44
44
|
|
|
45
45
|
- A cross-service or cross-tenant read is only a finding if the two sides are
|
|
46
|
-
actually distinct trust domains. Decide
|
|
46
|
+
actually distinct trust domains. Decide once whether a given principal, an internal
|
|
47
47
|
service role, a sibling tenant, a worker, is inside or outside the boundary, then
|
|
48
48
|
apply that one answer to every finding touching it. Do not confirm one finding by
|
|
49
49
|
treating the principal as hostile and refute another by treating the same principal
|
|
@@ -31,7 +31,8 @@ The one irreducible human dependency, the credentials and go-ahead to run a PoC
|
|
|
31
31
|
safely, is deferred to a separate phase and never asked for mid-run.
|
|
32
32
|
|
|
33
33
|
Workspace: `<workspace>/<project>/`, created for you, holding `inventory/`,
|
|
34
|
-
`units/`, `
|
|
34
|
+
`units/`, `candidates/`, `pocs/`, and `findings/`. You write proposals into
|
|
35
|
+
`candidates/` and PoCs into `pocs/`. Finalize confirms them into `findings/`.
|
|
35
36
|
|
|
36
37
|
---
|
|
37
38
|
|
|
@@ -132,7 +133,7 @@ mandate below:
|
|
|
132
133
|
owner vs tenant vs service, or only prove the caller is some valid user?
|
|
133
134
|
Compare the unit's siblings and versions for a dropped or weakened check.
|
|
134
135
|
- **Replay**: does a signed or authenticated privileged request both consume a
|
|
135
|
-
one-time nonce
|
|
136
|
+
one-time nonce and enforce a freshness window? A signature alone is not enough.
|
|
136
137
|
- **Concurrency**: is a check-then-act serialized by a lock held across the act?
|
|
137
138
|
Read the real mechanism. A `select_for_update` whose result is discarded still
|
|
138
139
|
holds the row lock on a production RDBMS inside a transaction, so judge against
|
|
@@ -169,8 +170,9 @@ cleared it, so a wrong clear is visible.
|
|
|
169
170
|
on a privileged path that looks bounded lands at MEDIUM or higher and is reported,
|
|
170
171
|
not refuted. When unsure between two levels, report at the higher and say why.
|
|
171
172
|
|
|
172
|
-
Write each
|
|
173
|
-
`pocs/<name>.<ext
|
|
173
|
+
Write each candidate finding to `candidates/<name>.md` with a runnable PoC at
|
|
174
|
+
`pocs/<name>.<ext>` under the same `<name>`, so finalize can match the PoC to the
|
|
175
|
+
confirmed finding it writes into `findings/`:
|
|
174
176
|
|
|
175
177
|
```markdown
|
|
176
178
|
# <title>
|
|
@@ -216,6 +218,6 @@ evidence.
|
|
|
216
218
|
|
|
217
219
|
The persistent workspace carries the settled work across runs, so a re-run extends
|
|
218
220
|
coverage instead of restarting. A unit already marked `- Status: reviewed` is not
|
|
219
|
-
re-reviewed, the
|
|
221
|
+
re-reviewed, the proposals in `candidates/` are not re-derived, and a finding already
|
|
220
222
|
verified is not re-litigated. A re-run, including after a usage limit, picks up the
|
|
221
223
|
units still open and stops when the gate passes.
|
|
@@ -12,16 +12,20 @@ review in passing here is the shallow whole-repo pass this method exists to repl
|
|
|
12
12
|
1. SCAFFOLD. Build the workspace, the deterministic worklist you do not invent:
|
|
13
13
|
|
|
14
14
|
```
|
|
15
|
-
codejury review repo $ARGUMENTS
|
|
15
|
+
codejury review repo $ARGUMENTS
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
The workspace defaults to a user-private directory under `XDG_STATE_HOME` or
|
|
19
|
+
`~/.local/state`, the same path for all three steps below, so they share one workspace.
|
|
20
|
+
Pass `--workspace <path>` to override it.
|
|
21
|
+
|
|
18
22
|
If `codejury` is not on PATH it is a pip-installed console script, so activate the
|
|
19
23
|
project venv first, for example `. .venv/bin/activate`, or run `python -m codejury`.
|
|
20
24
|
If it reports a previous review's output in the workspace, ask me whether to clear
|
|
21
25
|
it, and if I say yes, re-run with `--fresh`.
|
|
22
26
|
|
|
23
27
|
RESUMING. If a previous run was interrupted, for example by a usage limit, just run
|
|
24
|
-
this command again
|
|
28
|
+
this command again without clearing the workspace, answer no when it asks to clear. It
|
|
25
29
|
resumes and does not redo finished work: a unit already marked `- Status: reviewed`
|
|
26
30
|
is skipped in the fan-out, and `--finalize` does not re-verify a finding it already
|
|
27
31
|
settled. So an interruption loses no completed work, keep resuming in new sessions
|
|
@@ -55,19 +59,20 @@ review in passing here is the shallow whole-repo pass this method exists to repl
|
|
|
55
59
|
libraries they call, hunts the high-impact classes, verifies each control on the
|
|
56
60
|
code it actually reads, refutes its own candidates, grades every real finding by
|
|
57
61
|
the rubric, CRITICAL through LOW, never refuted for low impact, writes each to
|
|
58
|
-
`
|
|
62
|
+
`candidates/<name>.md` with its PoC at `pocs/<name>.<ext>` under the same `<name>`,
|
|
63
|
+
and flips its unit to `- Status: reviewed`.
|
|
59
64
|
|
|
60
65
|
Do not review units in this main context, only orchestrate. After the first pass,
|
|
61
66
|
run more passes giving the units a different lead lens each time, authorization,
|
|
62
67
|
then replay, then concurrency, then data exposure, then business logic, adding only
|
|
63
|
-
findings not already in `
|
|
68
|
+
findings not already in `candidates/`. The union grows along a different axis each pass.
|
|
64
69
|
Stop when two consecutive passes add no new issue.
|
|
65
70
|
|
|
66
71
|
4. FINALIZE. In code, do not dedup or verify in prose. Once the fan-out has covered the
|
|
67
72
|
surface, run:
|
|
68
73
|
|
|
69
74
|
```
|
|
70
|
-
codejury review repo $ARGUMENTS --
|
|
75
|
+
codejury review repo $ARGUMENTS --finalize
|
|
71
76
|
```
|
|
72
77
|
|
|
73
78
|
In Claude Code, add `--reviewer claude-cli` to verify through your Claude Code access
|
|
@@ -82,7 +87,7 @@ review in passing here is the shallow whole-repo pass this method exists to repl
|
|
|
82
87
|
5. GATE. Let codejury, not your judgment, decide whether the review may stop:
|
|
83
88
|
|
|
84
89
|
```
|
|
85
|
-
codejury review repo $ARGUMENTS --
|
|
90
|
+
codejury review repo $ARGUMENTS --gate
|
|
86
91
|
```
|
|
87
92
|
|
|
88
93
|
If it exits non-zero it lists what is unmet: the surface not enumerated, a unit not
|
|
@@ -100,5 +105,6 @@ follow-up run I start later, do not pause to ask me mid-run.
|
|
|
100
105
|
End with one report and then stop: confirmed findings as a table of title, class,
|
|
101
106
|
`file:line`, severity, and status, the blocked findings each with its `Needs:`, the
|
|
102
107
|
consolidated verification-needs list, and the coverage, units reviewed over units in
|
|
103
|
-
the inventory. The
|
|
104
|
-
continue, just finish and
|
|
108
|
+
the inventory. The proposals live in the workspace `candidates/`, the confirmed
|
|
109
|
+
findings finalize writes in `findings/`. Do not ask me to continue, just finish and
|
|
110
|
+
report.
|
|
@@ -27,8 +27,15 @@ For every control on the path, decide on the code you actually read, never on th
|
|
|
27
27
|
presence of a named control:
|
|
28
28
|
|
|
29
29
|
- **Authorization granularity**: does the check scope to the right principal, owner
|
|
30
|
-
vs tenant vs service, or only prove the caller is some valid user? Compare
|
|
31
|
-
|
|
30
|
+
vs tenant vs service, or only prove the caller is some valid user? Compare siblings
|
|
31
|
+
for a control present on most and dropped on one. Siblings are not only sibling
|
|
32
|
+
endpoints and endpoint versions, but repeated branches in one handler, a query run
|
|
33
|
+
once per object type in a fan out, or one method in a set of similar methods. Where
|
|
34
|
+
most scope to the owner and one does not, that one is the likely IDOR.
|
|
35
|
+
- **Disclosure on a list endpoint**: a list or ReadAll that returns a secret field, a
|
|
36
|
+
hash, token, password, or key, hands it to every caller allowed to list, including one
|
|
37
|
+
meant to see only a less privileged subset. Returning the hash of a write or admin
|
|
38
|
+
share to a viewer with read access is an escalation, not a clean list.
|
|
32
39
|
- **Replay**: does a signed or authenticated privileged request both consume a
|
|
33
40
|
one-time nonce and enforce a freshness window? A signature alone is not enough.
|
|
34
41
|
- **Concurrency**: is a check-then-act serialized by a lock held across the act? A
|
|
@@ -47,7 +54,7 @@ report clean. The only things you do not report are dependency or component CVEs
|
|
|
47
54
|
of this tool's scope, and a candidate the facts refute, the controlling fact holds when
|
|
48
55
|
you read the code. Everything else that is real is reported, graded by the rubric.
|
|
49
56
|
|
|
50
|
-
A weaker signal is a
|
|
57
|
+
A weaker signal is a lower severity, not a dropped finding. A best-practice or
|
|
51
58
|
hardening gap, a config default, a debug or env-gated path, or a finding whose impact
|
|
52
59
|
looks bounded is graded LOW or MEDIUM and surfaced, never suppressed. Noise is managed
|
|
53
60
|
by severity, the reader sorts by it, it is not managed by you hiding findings. An
|
|
@@ -68,8 +75,8 @@ non-finding with a plausible word: "it is idempotent", "it yields the same token
|
|
|
68
75
|
"it only returns status" lower the severity per the rubric, they do not make the
|
|
69
76
|
finding disappear.
|
|
70
77
|
|
|
71
|
-
Write each confirmed or blocked finding to `
|
|
78
|
+
Write each confirmed or blocked finding to `candidates/<name>.md`: Risk, Type, Source as
|
|
72
79
|
`METHOD /path`, Status, Analysis citing `file:line`, Attack Path, and Fix. Save a
|
|
73
|
-
runnable PoC to `pocs/<name>.<ext
|
|
74
|
-
fact that cleared it, so a wrong clear
|
|
75
|
-
`reviewed`.
|
|
80
|
+
runnable PoC to `pocs/<name>.<ext>` under the same `<name>`, so finalize can match it.
|
|
81
|
+
Record any cleared control with the controlling fact that cleared it, so a wrong clear
|
|
82
|
+
is visible. Then set this unit's Status to `reviewed`.
|
|
@@ -18,11 +18,18 @@ from codejury.providers.base import CompletionResult, Message, Provider
|
|
|
18
18
|
|
|
19
19
|
class AnthropicProvider(Provider):
|
|
20
20
|
def __init__(
|
|
21
|
-
self,
|
|
21
|
+
self,
|
|
22
|
+
*,
|
|
23
|
+
api_key: str | None = None,
|
|
24
|
+
base_url: str | None = None,
|
|
25
|
+
client: Any | None = None,
|
|
26
|
+
temperature: float | None = 0.0,
|
|
22
27
|
) -> None:
|
|
23
28
|
self._api_key = api_key
|
|
24
29
|
self._base_url = base_url
|
|
25
30
|
self._client = client
|
|
31
|
+
# determinism: temperature 0 so the same input yields the same verdicts, invariant 2
|
|
32
|
+
self._temperature = temperature
|
|
26
33
|
|
|
27
34
|
def _get_client(self) -> Any:
|
|
28
35
|
if self._client is None:
|
|
@@ -53,16 +60,39 @@ class AnthropicProvider(Provider):
|
|
|
53
60
|
if cache and system:
|
|
54
61
|
system_param = [{"type": "text", "text": system, "cache_control": {"type": "ephemeral"}}]
|
|
55
62
|
|
|
56
|
-
|
|
57
|
-
model
|
|
58
|
-
max_tokens
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
63
|
+
request: dict[str, Any] = {
|
|
64
|
+
"model": model,
|
|
65
|
+
"max_tokens": max_tokens,
|
|
66
|
+
"timeout": 600,
|
|
67
|
+
"system": system_param,
|
|
68
|
+
"messages": [{"role": m.role, "content": m.content} for m in messages],
|
|
69
|
+
}
|
|
70
|
+
response = self._create(request)
|
|
64
71
|
return CompletionResult(text=_extract_text(response))
|
|
65
72
|
|
|
73
|
+
def _create(self, request: dict[str, Any]) -> Any:
|
|
74
|
+
client = self._get_client()
|
|
75
|
+
if self._temperature is None:
|
|
76
|
+
return client.messages.create(**request)
|
|
77
|
+
try:
|
|
78
|
+
return client.messages.create(temperature=self._temperature, **request)
|
|
79
|
+
except Exception as exc:
|
|
80
|
+
if not _is_temperature_rejected(exc):
|
|
81
|
+
raise
|
|
82
|
+
# drop it for this provider so later calls skip the rejected param, no wasted retry
|
|
83
|
+
self._temperature = None
|
|
84
|
+
return client.messages.create(**request)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _is_temperature_rejected(exc: Exception) -> bool:
|
|
88
|
+
"""True when the API refused the call only because this model does not accept the
|
|
89
|
+
temperature param, the one error recovered from by dropping it. Matched on the message,
|
|
90
|
+
not a model name list, so a new reasoning model needs no code change."""
|
|
91
|
+
status = getattr(exc, "status_code", None)
|
|
92
|
+
if status != 400 and "BadRequest" not in type(exc).__name__:
|
|
93
|
+
return False
|
|
94
|
+
return "temperature" in str(exc).lower()
|
|
95
|
+
|
|
66
96
|
|
|
67
97
|
def _extract_text(response: Any) -> str:
|
|
68
98
|
content = getattr(response, "content", None)
|
|
@@ -13,7 +13,7 @@ from __future__ import annotations
|
|
|
13
13
|
from typing import Any, Callable
|
|
14
14
|
|
|
15
15
|
from codejury.providers.base import CompletionResult, Message, Provider
|
|
16
|
-
from codejury.providers.
|
|
16
|
+
from codejury.providers.chat_format import choice_text
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class LiteLLMProvider(Provider):
|
|
@@ -12,7 +12,7 @@ from __future__ import annotations
|
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
14
|
from codejury.providers.base import CompletionResult, Message, Provider
|
|
15
|
-
from codejury.providers.
|
|
15
|
+
from codejury.providers.chat_format import choice_text
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class OpenAIProvider(Provider):
|
codejury-1.0.0/codejury/review/diff/engine.py → codejury-1.0.1/codejury/review/diff/audit.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
"""Standard diff
|
|
1
|
+
"""Standard diff audit: one model call over a diff, parsed into Findings. The single-call
|
|
2
|
+
unit the orchestrator in engine.py drives.
|
|
2
3
|
|
|
3
|
-
The cheap, balanced default. The adversarial Finder/Challenger/Judge
|
|
4
|
+
The cheap, balanced default. The adversarial Finder/Challenger/Judge runner
|
|
4
5
|
builds on the same Finding domain for the cases that need higher
|
|
5
6
|
coverage and lower false positives.
|
|
6
7
|
"""
|
codejury-1.0.0/codejury/review/diff/runner.py → codejury-1.0.1/codejury/review/diff/engine.py
RENAMED
|
@@ -11,7 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
import dataclasses
|
|
12
12
|
|
|
13
13
|
from codejury.review.diff.adversarial import AdversarialAuditRunner
|
|
14
|
-
from codejury.review.diff.
|
|
14
|
+
from codejury.review.diff.audit import AuditRunner
|
|
15
15
|
from codejury.review.diff.filter import FindingsFilter
|
|
16
16
|
from codejury.review.diff.vulnerabilities import allowed_categories, normalize_category
|
|
17
17
|
from codejury.finding import Finding
|