codejury 0.19.0__tar.gz → 0.20.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.
- {codejury-0.19.0 → codejury-0.20.0}/PKG-INFO +83 -33
- codejury-0.20.0/README.md +166 -0
- codejury-0.20.0/codejury/__main__.py +10 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/cli.py +43 -23
- codejury-0.20.0/codejury/data/commands/codejury-review.md +29 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/detection.yaml +1 -1
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/methodologies/repo-review.md +7 -5
- {codejury-0.19.0 → codejury-0.20.0}/codejury/repo/scaffold.py +1 -1
- {codejury-0.19.0 → codejury-0.20.0}/codejury/resources.py +1 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury.egg-info/PKG-INFO +83 -33
- {codejury-0.19.0 → codejury-0.20.0}/codejury.egg-info/SOURCES.txt +2 -0
- {codejury-0.19.0 → codejury-0.20.0}/pyproject.toml +2 -2
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_cli_audit.py +26 -2
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_repo_model.py +3 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_repo_scaffold.py +1 -1
- codejury-0.19.0/README.md +0 -116
- {codejury-0.19.0 → codejury-0.20.0}/LICENSE +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/__init__.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/frameworks/go/echo.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/frameworks/go/gin.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/frameworks/javascript/express.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/frameworks/javascript/nestjs.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/frameworks/python/celery.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/frameworks/python/django.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/frameworks/python/fastapi.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/frameworks/python/flask.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/languages/go.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/languages/javascript.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/languages/python.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/languages/typescript.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/methodologies/security-review-memory.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/protocols/oauth.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/SKILL.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/business-logic.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/code-injection.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/command-injection.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/cross-site-request-forgery.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/cross-site-scripting.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/hardcoded-secrets.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/http-response-splitting.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/improper-authentication.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/information-exposure.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/insecure-cryptography.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/insecure-deserialization.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/insecure-direct-object-reference.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/insecure-transport.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/jwt-validation.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/mass-assignment.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/missing-authorization.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/open-redirect.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/path-traversal.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/race-condition.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/replay-attack.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/server-side-request-forgery.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/server-side-template-injection.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/session-fixation.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/sql-injection.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/data/vulnerabilities/xml-external-entity.md +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/detection.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/diff/__init__.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/diff/debate.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/diff/debate_prompts.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/diff/engine.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/diff/findings_filter.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/diff/prompts.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/diff/runner.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/diff/vulnerabilities.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/domain/__init__.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/domain/finding.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/guides.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/json_parse.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/mddoc.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/providers/__init__.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/providers/anthropic.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/providers/base.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/providers/factory.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/providers/litellm.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/providers/mock.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/providers/openai.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/providers/openai_format.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/providers/retry.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/repo/__init__.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/repo/model.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury/report.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury.egg-info/dependency_links.txt +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury.egg-info/entry_points.txt +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury.egg-info/requires.txt +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/codejury.egg-info/top_level.txt +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/setup.cfg +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_anthropic_provider.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_detection.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_diff_debate.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_diff_engine.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_guides.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_json_parse.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_litellm_provider.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_mddoc.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_openai_format.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_openai_provider.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_report.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_retry_provider.py +0 -0
- {codejury-0.19.0 → codejury-0.20.0}/tests/test_vulnerabilities.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codejury
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: AI code security review
|
|
3
|
+
Version: 0.20.0
|
|
4
|
+
Summary: AI code security review for diffs and whole repositories.
|
|
5
5
|
Author: AISecLabs
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/aiseclabs/codejury
|
|
@@ -40,52 +40,61 @@ Dynamic: license-file
|
|
|
40
40
|
|
|
41
41
|
> AI code security review for diffs and whole repositories.
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
codejury runs two paths matched to their nature.
|
|
44
44
|
|
|
45
45
|
- **Diff Review** is coded. It audits a pull request diff for newly introduced
|
|
46
46
|
exploitable risk, as a single balanced LLM call or an adversarial Finder,
|
|
47
47
|
Challenger, and Judge pass that trades roughly 3x the cost for extra recall on
|
|
48
|
-
subtle flaws that span files.
|
|
49
|
-
- **Repo Review** is agent driven.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
subtle flaws that span files. One command in, findings out.
|
|
49
|
+
- **Repo Review** is agent driven. A whole repository is too large for one LLM
|
|
50
|
+
call, so codejury scaffolds a workspace and hands an interactive agent such as
|
|
51
|
+
Claude Code or Codex a methodology to run. The agent maps the attack surface,
|
|
52
|
+
traces inputs to sinks across files, verifies issues with a real PoC, and
|
|
53
|
+
iterates over rounds with a persistent memory.
|
|
54
|
+
|
|
55
|
+
Security knowledge is data, not code. Vulnerability classes live in
|
|
56
|
+
`codejury/data/vulnerabilities/*.md` with a vulnerable and a secure example per
|
|
57
|
+
language, and the stack guides live under `data/languages`, `data/frameworks`,
|
|
58
|
+
and `data/protocols`. The engine stays language neutral and names no framework,
|
|
59
|
+
so adding a stack is a drop-in markdown file.
|
|
59
60
|
|
|
60
61
|
## Install
|
|
61
62
|
|
|
62
63
|
```bash
|
|
63
|
-
pip install codejury
|
|
64
|
-
pip install "codejury[anthropic]"
|
|
64
|
+
pip install codejury # core
|
|
65
|
+
pip install "codejury[anthropic]" # add a backend, also openai or litellm
|
|
66
|
+
codejury install-slash-command # Claude Code, ~/.claude/commands/
|
|
67
|
+
codejury install-slash-command --agent codex # Codex, ~/.codex/prompts/
|
|
65
68
|
```
|
|
66
69
|
|
|
70
|
+
`install-slash-command` copies the `/codejury-review` command into the agent's
|
|
71
|
+
command directory. The command body is the same for every agent, only the
|
|
72
|
+
directory differs, so pass `--dir` for any other agent. The repo review itself is
|
|
73
|
+
agent neutral, so even without the command you can run `codejury review` and
|
|
74
|
+
tell any agent to follow the methodology it writes.
|
|
75
|
+
|
|
67
76
|
## Diff Review
|
|
68
77
|
|
|
69
78
|
```bash
|
|
70
79
|
# audit a diff file
|
|
71
|
-
codejury
|
|
80
|
+
codejury diff --diff-file changes.diff
|
|
72
81
|
|
|
73
82
|
# audit a git range in a repo
|
|
74
|
-
codejury
|
|
83
|
+
codejury diff --repo /path/to/app --git-range origin/main...HEAD
|
|
75
84
|
|
|
76
85
|
# from stdin
|
|
77
|
-
git diff HEAD~1 | codejury
|
|
86
|
+
git diff HEAD~1 | codejury diff
|
|
78
87
|
|
|
79
88
|
# adversarial mode, more recall on subtle flaws, about 3x the cost
|
|
80
|
-
codejury
|
|
89
|
+
codejury diff --diff-file changes.diff --mode adversarial
|
|
81
90
|
|
|
82
91
|
# CI gate and SARIF
|
|
83
|
-
codejury
|
|
92
|
+
codejury diff --diff-file changes.diff --format sarif --fail-on high
|
|
84
93
|
```
|
|
85
94
|
|
|
86
95
|
Configure a backend with `--provider`, `--model`, `--api-key`, `--api-base`, or
|
|
87
96
|
the `CODEJURY_API_KEY`, `CODEJURY_MODEL`, and `CODEJURY_API_BASE` environment
|
|
88
|
-
variables. `codejury
|
|
97
|
+
variables. `codejury diff --dry-run` exercises the engine with a mock
|
|
89
98
|
provider and no key, and falls back to a built in demo diff when you pass none.
|
|
90
99
|
|
|
91
100
|
### Choosing a Model and Mode
|
|
@@ -120,17 +129,49 @@ request.
|
|
|
120
129
|
|
|
121
130
|
## Repo Review
|
|
122
131
|
|
|
132
|
+
Repo Review does not scan and print findings. It sets up a review for an agent to
|
|
133
|
+
run, because a whole repository needs many rounds of reading, cross-file tracing,
|
|
134
|
+
and PoC work that an agent does, not a single call.
|
|
135
|
+
|
|
123
136
|
```bash
|
|
124
|
-
codejury review
|
|
137
|
+
codejury review /path/to/your/repo
|
|
125
138
|
```
|
|
126
139
|
|
|
127
|
-
This
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
140
|
+
This detects the stack, seeds the entrypoint inventory and the downstream trace
|
|
141
|
+
targets from a deterministic scan, writes the methodology to
|
|
142
|
+
`<workspace>/METHODOLOGY.md`, and prints a short pointer. It creates the
|
|
143
|
+
workspace:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
entrypoints/ the candidate entrypoint files to start from
|
|
147
|
+
issues/ one write-up per confirmed or suspected issue
|
|
148
|
+
pocs/ a runnable PoC per issue, same name as the issue
|
|
149
|
+
analysis/ _trace_targets.md, the round ledger, and trace notes
|
|
150
|
+
security-review-memory.md
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Then run it with an interactive agent. In Claude Code or Codex:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
/codejury-review /path/to/your/repo
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Any agent works, the slash command is just a shortcut. Without it, tell the agent
|
|
160
|
+
to follow the `METHODOLOGY.md` the scaffold wrote.
|
|
161
|
+
|
|
162
|
+
The agent follows `METHODOLOGY.md`: it maps the attack surface including non HTTP
|
|
163
|
+
sources, traces each input to its sink through the downstream layers, runs an
|
|
164
|
+
Authorization Model pass for missing-auth and IDOR, and follows a control into a
|
|
165
|
+
library when an entrypoint delegates it. It keeps going until a Completeness Gate
|
|
166
|
+
passes, two consecutive rounds that add nothing new. It confirms each issue with
|
|
167
|
+
a real PoC against a sandbox or dev environment and asks you for any credential or
|
|
168
|
+
test data it needs. Only a reproduced PoC is a confirmed finding, and nothing
|
|
169
|
+
runs against production.
|
|
170
|
+
|
|
171
|
+
The supported stacks today are Python with Django, Celery, Flask, and FastAPI,
|
|
172
|
+
Go with Gin and Echo, JavaScript and TypeScript with Express and NestJS, and the
|
|
173
|
+
OAuth and OIDC protocol. The methodology still works on an unguided stack, it just
|
|
174
|
+
leans more on the agent's own knowledge.
|
|
134
175
|
|
|
135
176
|
## Findings
|
|
136
177
|
|
|
@@ -142,6 +183,15 @@ production config leaks.
|
|
|
142
183
|
|
|
143
184
|
## Extending
|
|
144
185
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
186
|
+
Knowledge is data, so extending codejury is a drop-in markdown file with no code
|
|
187
|
+
change.
|
|
188
|
+
|
|
189
|
+
- A vulnerability class: `codejury/data/vulnerabilities/<class>.md` with
|
|
190
|
+
frontmatter of title, impact, tags, and triggers, plus a vulnerable and a
|
|
191
|
+
secure example.
|
|
192
|
+
- A language or framework: `codejury/data/languages/<lang>.md` or
|
|
193
|
+
`codejury/data/frameworks/<lang>/<framework>.md`, declaring its detect signals,
|
|
194
|
+
entrypoint markers, and downstream logic layers.
|
|
195
|
+
- A protocol such as OAuth: `codejury/data/protocols/<name>.md`, detected by
|
|
196
|
+
language neutral content tokens.
|
|
197
|
+
```
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
```
|
|
2
|
+
██████╗ ██████╗ ██████╗ ███████╗ ██╗██╗ ██╗██████╗ ██╗ ██╗
|
|
3
|
+
██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██║██║ ██║██╔══██╗╚██╗ ██╔╝
|
|
4
|
+
██║ ██║ ██║██║ ██║█████╗ ██║██║ ██║██████╔╝ ╚████╔╝
|
|
5
|
+
██║ ██║ ██║██║ ██║██╔══╝ ██ ██║██║ ██║██╔══██╗ ╚██╔╝
|
|
6
|
+
╚██████╗╚██████╔╝██████╔╝███████╗╚█████╔╝╚██████╔╝██║ ██║ ██║
|
|
7
|
+
╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
> AI code security review for diffs and whole repositories.
|
|
11
|
+
|
|
12
|
+
codejury runs two paths matched to their nature.
|
|
13
|
+
|
|
14
|
+
- **Diff Review** is coded. It audits a pull request diff for newly introduced
|
|
15
|
+
exploitable risk, as a single balanced LLM call or an adversarial Finder,
|
|
16
|
+
Challenger, and Judge pass that trades roughly 3x the cost for extra recall on
|
|
17
|
+
subtle flaws that span files. One command in, findings out.
|
|
18
|
+
- **Repo Review** is agent driven. A whole repository is too large for one LLM
|
|
19
|
+
call, so codejury scaffolds a workspace and hands an interactive agent such as
|
|
20
|
+
Claude Code or Codex a methodology to run. The agent maps the attack surface,
|
|
21
|
+
traces inputs to sinks across files, verifies issues with a real PoC, and
|
|
22
|
+
iterates over rounds with a persistent memory.
|
|
23
|
+
|
|
24
|
+
Security knowledge is data, not code. Vulnerability classes live in
|
|
25
|
+
`codejury/data/vulnerabilities/*.md` with a vulnerable and a secure example per
|
|
26
|
+
language, and the stack guides live under `data/languages`, `data/frameworks`,
|
|
27
|
+
and `data/protocols`. The engine stays language neutral and names no framework,
|
|
28
|
+
so adding a stack is a drop-in markdown file.
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install codejury # core
|
|
34
|
+
pip install "codejury[anthropic]" # add a backend, also openai or litellm
|
|
35
|
+
codejury install-slash-command # Claude Code, ~/.claude/commands/
|
|
36
|
+
codejury install-slash-command --agent codex # Codex, ~/.codex/prompts/
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`install-slash-command` copies the `/codejury-review` command into the agent's
|
|
40
|
+
command directory. The command body is the same for every agent, only the
|
|
41
|
+
directory differs, so pass `--dir` for any other agent. The repo review itself is
|
|
42
|
+
agent neutral, so even without the command you can run `codejury review` and
|
|
43
|
+
tell any agent to follow the methodology it writes.
|
|
44
|
+
|
|
45
|
+
## Diff Review
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# audit a diff file
|
|
49
|
+
codejury diff --diff-file changes.diff
|
|
50
|
+
|
|
51
|
+
# audit a git range in a repo
|
|
52
|
+
codejury diff --repo /path/to/app --git-range origin/main...HEAD
|
|
53
|
+
|
|
54
|
+
# from stdin
|
|
55
|
+
git diff HEAD~1 | codejury diff
|
|
56
|
+
|
|
57
|
+
# adversarial mode, more recall on subtle flaws, about 3x the cost
|
|
58
|
+
codejury diff --diff-file changes.diff --mode adversarial
|
|
59
|
+
|
|
60
|
+
# CI gate and SARIF
|
|
61
|
+
codejury diff --diff-file changes.diff --format sarif --fail-on high
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Configure a backend with `--provider`, `--model`, `--api-key`, `--api-base`, or
|
|
65
|
+
the `CODEJURY_API_KEY`, `CODEJURY_MODEL`, and `CODEJURY_API_BASE` environment
|
|
66
|
+
variables. `codejury diff --dry-run` exercises the engine with a mock
|
|
67
|
+
provider and no key, and falls back to a built in demo diff when you pass none.
|
|
68
|
+
|
|
69
|
+
### Choosing a Model and Mode
|
|
70
|
+
|
|
71
|
+
Detection quality is dominated by the model first, then the mode. On real diff
|
|
72
|
+
probes:
|
|
73
|
+
|
|
74
|
+
- A strong model at the Claude Sonnet tier in standard mode caught every planted
|
|
75
|
+
vulnerability with almost no false positives. A weaker model raised false
|
|
76
|
+
positives in both modes, so the model is the lever that matters most.
|
|
77
|
+
- Adversarial mode did not lower false positives over standard on those probes
|
|
78
|
+
and costs about 3x. Reach for it to gain recall on subtle logic that spans
|
|
79
|
+
files, not as a way to cut false positives.
|
|
80
|
+
|
|
81
|
+
Default to standard mode with a strong model, set with `--model` or
|
|
82
|
+
`CODEJURY_MODEL`. False positives are held down by the do not report list and the
|
|
83
|
+
post filter, not by the mode.
|
|
84
|
+
|
|
85
|
+
### Use in CI with GitHub Actions
|
|
86
|
+
|
|
87
|
+
Audit every pull request and surface findings in the code scanning tab. Copy
|
|
88
|
+
`examples/codejury-pr-review.yml` into `.github/workflows/`, add a
|
|
89
|
+
`CODEJURY_API_KEY` repository secret, and it will
|
|
90
|
+
|
|
91
|
+
1. diff the pull request against its base with `--git-range origin/<base>...HEAD`,
|
|
92
|
+
2. write SARIF and upload it with `github/codeql-action/upload-sarif`,
|
|
93
|
+
3. fail the check on a HIGH or CRITICAL finding with `--fail-on high`.
|
|
94
|
+
|
|
95
|
+
The job makes one model call per pull request in standard mode. The SARIF is
|
|
96
|
+
uploaded even when the gate fails, so findings always show up on the pull
|
|
97
|
+
request.
|
|
98
|
+
|
|
99
|
+
## Repo Review
|
|
100
|
+
|
|
101
|
+
Repo Review does not scan and print findings. It sets up a review for an agent to
|
|
102
|
+
run, because a whole repository needs many rounds of reading, cross-file tracing,
|
|
103
|
+
and PoC work that an agent does, not a single call.
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
codejury review /path/to/your/repo
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
This detects the stack, seeds the entrypoint inventory and the downstream trace
|
|
110
|
+
targets from a deterministic scan, writes the methodology to
|
|
111
|
+
`<workspace>/METHODOLOGY.md`, and prints a short pointer. It creates the
|
|
112
|
+
workspace:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
entrypoints/ the candidate entrypoint files to start from
|
|
116
|
+
issues/ one write-up per confirmed or suspected issue
|
|
117
|
+
pocs/ a runnable PoC per issue, same name as the issue
|
|
118
|
+
analysis/ _trace_targets.md, the round ledger, and trace notes
|
|
119
|
+
security-review-memory.md
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Then run it with an interactive agent. In Claude Code or Codex:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
/codejury-review /path/to/your/repo
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Any agent works, the slash command is just a shortcut. Without it, tell the agent
|
|
129
|
+
to follow the `METHODOLOGY.md` the scaffold wrote.
|
|
130
|
+
|
|
131
|
+
The agent follows `METHODOLOGY.md`: it maps the attack surface including non HTTP
|
|
132
|
+
sources, traces each input to its sink through the downstream layers, runs an
|
|
133
|
+
Authorization Model pass for missing-auth and IDOR, and follows a control into a
|
|
134
|
+
library when an entrypoint delegates it. It keeps going until a Completeness Gate
|
|
135
|
+
passes, two consecutive rounds that add nothing new. It confirms each issue with
|
|
136
|
+
a real PoC against a sandbox or dev environment and asks you for any credential or
|
|
137
|
+
test data it needs. Only a reproduced PoC is a confirmed finding, and nothing
|
|
138
|
+
runs against production.
|
|
139
|
+
|
|
140
|
+
The supported stacks today are Python with Django, Celery, Flask, and FastAPI,
|
|
141
|
+
Go with Gin and Echo, JavaScript and TypeScript with Express and NestJS, and the
|
|
142
|
+
OAuth and OIDC protocol. The methodology still works on an unguided stack, it just
|
|
143
|
+
leans more on the agent's own knowledge.
|
|
144
|
+
|
|
145
|
+
## Findings
|
|
146
|
+
|
|
147
|
+
Each finding carries a file and line, a severity and category, a concrete exploit
|
|
148
|
+
scenario, a recommendation, and a confidence. A false positive filter drops test
|
|
149
|
+
paths, mock paths, and low confidence noise. The model is also told not to report
|
|
150
|
+
dependency CVEs, style notes, speculation, or risks that only matter when
|
|
151
|
+
production config leaks.
|
|
152
|
+
|
|
153
|
+
## Extending
|
|
154
|
+
|
|
155
|
+
Knowledge is data, so extending codejury is a drop-in markdown file with no code
|
|
156
|
+
change.
|
|
157
|
+
|
|
158
|
+
- A vulnerability class: `codejury/data/vulnerabilities/<class>.md` with
|
|
159
|
+
frontmatter of title, impact, tags, and triggers, plus a vulnerable and a
|
|
160
|
+
secure example.
|
|
161
|
+
- A language or framework: `codejury/data/languages/<lang>.md` or
|
|
162
|
+
`codejury/data/frameworks/<lang>/<framework>.md`, declaring its detect signals,
|
|
163
|
+
entrypoint markers, and downstream logic layers.
|
|
164
|
+
- A protocol such as OAuth: `codejury/data/protocols/<name>.md`, detected by
|
|
165
|
+
language neutral content tokens.
|
|
166
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Entry point for `python -m codejury`, mirroring the `codejury` console script.
|
|
2
|
+
|
|
3
|
+
Lets the tool run without the console script on PATH, for example from a fresh
|
|
4
|
+
shell that has not activated the project venv: `python -m codejury ...`.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from codejury.cli import main
|
|
8
|
+
|
|
9
|
+
if __name__ == "__main__":
|
|
10
|
+
raise SystemExit(main())
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Two paths matched to their nature:
|
|
4
4
|
|
|
5
|
-
- ``
|
|
6
|
-
|
|
7
|
-
- ``review
|
|
5
|
+
- ``diff`` runs the coded diff engine over a unified diff: a single balanced call
|
|
6
|
+
(standard) or the adversarial Finder/Challenger/Judge pass.
|
|
7
|
+
- ``review <dir>`` scaffolds a workspace and prints the methodology for an
|
|
8
8
|
interactive agent to run a whole-repo review (it does not run an LLM pipeline,
|
|
9
9
|
which a single call cannot do for a whole codebase).
|
|
10
10
|
|
|
11
|
-
``
|
|
11
|
+
``diff --dry-run`` exercises the engine with a mock provider and no key.
|
|
12
12
|
The audit orchestration itself lives in ``codejury.diff.runner``.
|
|
13
13
|
"""
|
|
14
14
|
|
|
@@ -17,6 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
import argparse
|
|
18
18
|
import subprocess
|
|
19
19
|
import sys
|
|
20
|
+
from pathlib import Path
|
|
20
21
|
|
|
21
22
|
from codejury import __version__
|
|
22
23
|
from codejury.report import gate, render
|
|
@@ -92,12 +93,17 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
92
93
|
parser.add_argument("--version", action="version", version=f"codejury {__version__}")
|
|
93
94
|
sub = parser.add_subparsers(dest="command")
|
|
94
95
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
_add_audit_args(sub.add_parser("diff", help="audit a unified diff (the coded engine)"))
|
|
97
|
+
|
|
98
|
+
review = sub.add_parser("review", help="scaffold a whole-repo review for an interactive agent")
|
|
99
|
+
review.add_argument("directory", help="target repository to review")
|
|
100
|
+
review.add_argument("--workspace", default="codejury-review", help="where to create the review workspace")
|
|
101
|
+
|
|
102
|
+
inst = sub.add_parser("install-slash-command",
|
|
103
|
+
help="install the /codejury-review slash command for an agent")
|
|
104
|
+
inst.add_argument("--agent", choices=("claude", "codex"), default="claude",
|
|
105
|
+
help="which agent's command directory to install into")
|
|
106
|
+
inst.add_argument("--dir", default=None, help="explicit target directory, overrides --agent")
|
|
101
107
|
|
|
102
108
|
args = parser.parse_args(argv)
|
|
103
109
|
try:
|
|
@@ -109,8 +115,7 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
109
115
|
|
|
110
116
|
|
|
111
117
|
def _dispatch(args, parser) -> int:
|
|
112
|
-
|
|
113
|
-
if args.command == "review" and scope == "diff":
|
|
118
|
+
if args.command == "diff":
|
|
114
119
|
if args.dry_run:
|
|
115
120
|
provider = MockProvider(default=_MOCK_REPLY)
|
|
116
121
|
model = "mock"
|
|
@@ -129,23 +134,38 @@ def _dispatch(args, parser) -> int:
|
|
|
129
134
|
print(render(args.fmt, kept))
|
|
130
135
|
return 1 if gate(kept, args.fail_on) else 0
|
|
131
136
|
|
|
132
|
-
if args.command == "review"
|
|
137
|
+
if args.command == "review":
|
|
133
138
|
res = scaffold(args.directory, args.workspace)
|
|
134
|
-
|
|
139
|
+
(Path(res.workspace) / "METHODOLOGY.md").write_text(res.methodology, encoding="utf-8")
|
|
140
|
+
print(f"Workspace ready: {res.workspace}", file=sys.stderr)
|
|
135
141
|
if res.guides:
|
|
136
|
-
print(f"Detected stack: {', '.join(res.guides)}
|
|
142
|
+
print(f"Detected stack: {', '.join(res.guides)}, notes in {res.workspace}/_stack.md", file=sys.stderr)
|
|
137
143
|
print(f"Flagged {len(res.candidate_files)} candidate entrypoint files into "
|
|
138
144
|
f"{res.workspace}/entrypoints/_entrypoints.md", file=sys.stderr)
|
|
139
|
-
print(f"
|
|
140
|
-
print(
|
|
141
|
-
|
|
145
|
+
print(f"Methodology: {res.workspace}/METHODOLOGY.md", file=sys.stderr)
|
|
146
|
+
print(
|
|
147
|
+
"This command sets up the review, it does not find the issues itself. Next, have an "
|
|
148
|
+
f"interactive agent follow {res.workspace}/METHODOLOGY.md to run the review, or use the "
|
|
149
|
+
"/codejury-review command in Claude Code or Codex. Findings are written to "
|
|
150
|
+
f"{res.workspace}/issues/."
|
|
151
|
+
)
|
|
142
152
|
return 0
|
|
143
153
|
|
|
144
|
-
if args.command == "
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
if args.command == "install-slash-command":
|
|
155
|
+
from codejury.resources import COMMANDS_DIR
|
|
156
|
+
# the command body is portable, only the directory differs per agent
|
|
157
|
+
agent_dirs = {
|
|
158
|
+
"claude": Path.home() / ".claude" / "commands",
|
|
159
|
+
"codex": Path.home() / ".codex" / "prompts",
|
|
160
|
+
}
|
|
161
|
+
target_dir = Path(args.dir) if args.dir else agent_dirs[args.agent]
|
|
162
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
163
|
+
name = "codejury-review.md"
|
|
164
|
+
dst = target_dir / name
|
|
165
|
+
dst.write_text((COMMANDS_DIR / name).read_text(encoding="utf-8"), encoding="utf-8")
|
|
166
|
+
print(f"Installed slash command to {dst}")
|
|
167
|
+
print("Run it in the agent with: /codejury-review <repository>")
|
|
168
|
+
return 0
|
|
149
169
|
|
|
150
170
|
parser.print_help()
|
|
151
171
|
return 1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run a codejury whole-repo security review on a repository, interactively
|
|
3
|
+
---
|
|
4
|
+
Run a codejury whole-repository security review of: $ARGUMENTS
|
|
5
|
+
|
|
6
|
+
1. Scaffold the workspace:
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
codejury review $ARGUMENTS --workspace /tmp/codejury-review
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
If `codejury` is not on PATH it is a pip-installed console script, so activate
|
|
13
|
+
the project venv first, for example `. .venv/bin/activate`, or run it through
|
|
14
|
+
that venv's Python, for example `python -m codejury`.
|
|
15
|
+
|
|
16
|
+
2. Read `<workspace>/METHODOLOGY.md` and follow it to completion. It is the single
|
|
17
|
+
source of truth for how to run the review, the entrypoint map, the trace
|
|
18
|
+
targets, the Authorization Model pass, the dependency-control checks, the round
|
|
19
|
+
ledger, and the Completeness Gate. Do not improvise a different process.
|
|
20
|
+
|
|
21
|
+
3. Verify each issue with a real PoC, human in the loop. Ask me for any
|
|
22
|
+
credential, test account, or MFA step you need. Never touch production, never
|
|
23
|
+
use real credentials, and never run a destructive action without my go-ahead.
|
|
24
|
+
Only a reproduced PoC is a confirmed finding.
|
|
25
|
+
|
|
26
|
+
4. Report confirmed findings, the ones with a reproduced PoC, separately from
|
|
27
|
+
suspected ones still blocked on verification, as a table: title, class,
|
|
28
|
+
`file:line`, exploit, verification status. The issue files live in the
|
|
29
|
+
workspace `issues/`.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# data edit. This is distinct from a guide's stack detection, which decides which
|
|
5
5
|
# language, framework, or protocol applies.
|
|
6
6
|
|
|
7
|
-
skip_dirs: [".git", ".venv", "venv", "node_modules", "__pycache__", ".mypy_cache", ".pytest_cache"]
|
|
7
|
+
skip_dirs: [".git", ".venv", "venv", "node_modules", "__pycache__", ".mypy_cache", ".pytest_cache", "build", "dist", "target", "out", ".tox", ".eggs", ".next", ".nuxt"]
|
|
8
8
|
|
|
9
9
|
source_extensions: [".py", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".go", ".rb", ".java", ".kt", ".php", ".cs", ".scala", ".rs"]
|
|
10
10
|
|
|
@@ -147,10 +147,12 @@ exploitable exposure, so it is in scope. See "Controls That Live in a Library".
|
|
|
147
147
|
|
|
148
148
|
## Recording an Issue
|
|
149
149
|
|
|
150
|
-
Write one `issues/<name>.md` per issue, and save its PoC as a
|
|
151
|
-
`
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
Write one `issues/<name>.md` per issue, the write-up only, and save its PoC as a
|
|
151
|
+
real runnable file `pocs/<name>.<ext>` with the **same `<name>`** so the two pair
|
|
152
|
+
one to one, a script or an `.http` file, not a sketch in prose and not a `.md`.
|
|
153
|
+
Keep `issues/` write-ups and `pocs/` scripts in their own directories, do not mix
|
|
154
|
+
them. If you cannot write a concrete runnable PoC, the finding is most likely a
|
|
155
|
+
false positive, so do not report it. Each issue file must have:
|
|
154
156
|
|
|
155
157
|
```markdown
|
|
156
158
|
# <title>
|
|
@@ -167,7 +169,7 @@ positive, so do not report it. Each issue file must have:
|
|
|
167
169
|
(end-to-end, actionable steps)
|
|
168
170
|
|
|
169
171
|
## PoC
|
|
170
|
-
(the path to `
|
|
172
|
+
(the path to `pocs/<name>.<ext>` and how to run it)
|
|
171
173
|
|
|
172
174
|
## Verification
|
|
173
175
|
(the actual output of running the PoC, or the exact blocker)
|
|
@@ -151,7 +151,7 @@ def scaffold(target: str | Path, workspace: str | Path) -> ScaffoldResult:
|
|
|
151
151
|
project = target.name
|
|
152
152
|
ws = Path(workspace) / project
|
|
153
153
|
created: list[str] = []
|
|
154
|
-
for sub in ("entrypoints", "issues", "analysis"):
|
|
154
|
+
for sub in ("entrypoints", "issues", "pocs", "analysis"):
|
|
155
155
|
d = ws / sub
|
|
156
156
|
if not d.exists():
|
|
157
157
|
d.mkdir(parents=True, exist_ok=True)
|
|
@@ -14,3 +14,4 @@ FRAMEWORKS_DIR = _DATA / "frameworks" # per-framework review guides (how the ta
|
|
|
14
14
|
PROTOCOLS_DIR = _DATA / "protocols" # protocol guides such as oauth (what to check)
|
|
15
15
|
METHODOLOGIES_DIR = _DATA / "methodologies" # repo-review methodology and memory template
|
|
16
16
|
DETECTION_FILE = _DATA / "detection.yaml" # file and path classification across ecosystems
|
|
17
|
+
COMMANDS_DIR = _DATA / "commands" # Claude Code slash commands shipped for install
|