codejury 0.19.0__tar.gz → 0.21.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.
Files changed (103) hide show
  1. {codejury-0.19.0 → codejury-0.21.0}/PKG-INFO +78 -29
  2. codejury-0.21.0/README.md +165 -0
  3. codejury-0.21.0/codejury/__main__.py +10 -0
  4. {codejury-0.19.0 → codejury-0.21.0}/codejury/cli.py +41 -13
  5. codejury-0.21.0/codejury/data/commands/codejury-review-repo.md +29 -0
  6. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/detection.yaml +1 -1
  7. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/methodologies/repo-review.md +7 -5
  8. {codejury-0.19.0 → codejury-0.21.0}/codejury/resources.py +1 -0
  9. {codejury-0.19.0/codejury → codejury-0.21.0/codejury/review}/diff/debate.py +2 -2
  10. {codejury-0.19.0/codejury → codejury-0.21.0/codejury/review}/diff/debate_prompts.py +1 -1
  11. {codejury-0.19.0/codejury → codejury-0.21.0/codejury/review}/diff/engine.py +2 -2
  12. {codejury-0.19.0/codejury → codejury-0.21.0/codejury/review}/diff/prompts.py +1 -1
  13. {codejury-0.19.0/codejury → codejury-0.21.0/codejury/review}/diff/runner.py +4 -4
  14. codejury-0.21.0/codejury/review/repo/__init__.py +0 -0
  15. {codejury-0.19.0/codejury → codejury-0.21.0/codejury/review}/repo/scaffold.py +2 -2
  16. {codejury-0.19.0 → codejury-0.21.0}/codejury.egg-info/PKG-INFO +78 -29
  17. {codejury-0.19.0 → codejury-0.21.0}/codejury.egg-info/SOURCES.txt +14 -11
  18. {codejury-0.19.0 → codejury-0.21.0}/pyproject.toml +2 -2
  19. {codejury-0.19.0 → codejury-0.21.0}/tests/test_cli_audit.py +27 -3
  20. {codejury-0.19.0 → codejury-0.21.0}/tests/test_diff_debate.py +2 -2
  21. {codejury-0.19.0 → codejury-0.21.0}/tests/test_diff_engine.py +6 -6
  22. {codejury-0.19.0 → codejury-0.21.0}/tests/test_repo_model.py +4 -1
  23. {codejury-0.19.0 → codejury-0.21.0}/tests/test_repo_scaffold.py +2 -2
  24. {codejury-0.19.0 → codejury-0.21.0}/tests/test_vulnerabilities.py +1 -1
  25. codejury-0.19.0/README.md +0 -116
  26. {codejury-0.19.0 → codejury-0.21.0}/LICENSE +0 -0
  27. {codejury-0.19.0 → codejury-0.21.0}/codejury/__init__.py +0 -0
  28. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/frameworks/go/echo.md +0 -0
  29. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/frameworks/go/gin.md +0 -0
  30. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/frameworks/javascript/express.md +0 -0
  31. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/frameworks/javascript/nestjs.md +0 -0
  32. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/frameworks/python/celery.md +0 -0
  33. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/frameworks/python/django.md +0 -0
  34. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/frameworks/python/fastapi.md +0 -0
  35. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/frameworks/python/flask.md +0 -0
  36. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/languages/go.md +0 -0
  37. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/languages/javascript.md +0 -0
  38. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/languages/python.md +0 -0
  39. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/languages/typescript.md +0 -0
  40. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/methodologies/security-review-memory.md +0 -0
  41. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/protocols/oauth.md +0 -0
  42. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/SKILL.md +0 -0
  43. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/business-logic.md +0 -0
  44. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/code-injection.md +0 -0
  45. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/command-injection.md +0 -0
  46. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/cross-site-request-forgery.md +0 -0
  47. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/cross-site-scripting.md +0 -0
  48. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/hardcoded-secrets.md +0 -0
  49. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/http-response-splitting.md +0 -0
  50. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/improper-authentication.md +0 -0
  51. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/information-exposure.md +0 -0
  52. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/insecure-cryptography.md +0 -0
  53. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/insecure-deserialization.md +0 -0
  54. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/insecure-direct-object-reference.md +0 -0
  55. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/insecure-transport.md +0 -0
  56. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/jwt-validation.md +0 -0
  57. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/mass-assignment.md +0 -0
  58. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/missing-authorization.md +0 -0
  59. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/open-redirect.md +0 -0
  60. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/path-traversal.md +0 -0
  61. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/race-condition.md +0 -0
  62. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/replay-attack.md +0 -0
  63. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/server-side-request-forgery.md +0 -0
  64. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/server-side-template-injection.md +0 -0
  65. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/session-fixation.md +0 -0
  66. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/sql-injection.md +0 -0
  67. {codejury-0.19.0 → codejury-0.21.0}/codejury/data/vulnerabilities/xml-external-entity.md +0 -0
  68. {codejury-0.19.0 → codejury-0.21.0}/codejury/detection.py +0 -0
  69. {codejury-0.19.0 → codejury-0.21.0}/codejury/domain/__init__.py +0 -0
  70. {codejury-0.19.0 → codejury-0.21.0}/codejury/domain/finding.py +0 -0
  71. {codejury-0.19.0 → codejury-0.21.0}/codejury/guides.py +0 -0
  72. {codejury-0.19.0 → codejury-0.21.0}/codejury/json_parse.py +0 -0
  73. {codejury-0.19.0 → codejury-0.21.0}/codejury/mddoc.py +0 -0
  74. {codejury-0.19.0 → codejury-0.21.0}/codejury/providers/__init__.py +0 -0
  75. {codejury-0.19.0 → codejury-0.21.0}/codejury/providers/anthropic.py +0 -0
  76. {codejury-0.19.0 → codejury-0.21.0}/codejury/providers/base.py +0 -0
  77. {codejury-0.19.0 → codejury-0.21.0}/codejury/providers/factory.py +0 -0
  78. {codejury-0.19.0 → codejury-0.21.0}/codejury/providers/litellm.py +0 -0
  79. {codejury-0.19.0 → codejury-0.21.0}/codejury/providers/mock.py +0 -0
  80. {codejury-0.19.0 → codejury-0.21.0}/codejury/providers/openai.py +0 -0
  81. {codejury-0.19.0 → codejury-0.21.0}/codejury/providers/openai_format.py +0 -0
  82. {codejury-0.19.0 → codejury-0.21.0}/codejury/providers/retry.py +0 -0
  83. {codejury-0.19.0 → codejury-0.21.0}/codejury/report.py +0 -0
  84. {codejury-0.19.0/codejury/diff → codejury-0.21.0/codejury/review}/__init__.py +0 -0
  85. {codejury-0.19.0/codejury/repo → codejury-0.21.0/codejury/review/diff}/__init__.py +0 -0
  86. {codejury-0.19.0/codejury → codejury-0.21.0/codejury/review}/diff/findings_filter.py +0 -0
  87. {codejury-0.19.0/codejury → codejury-0.21.0/codejury/review}/diff/vulnerabilities.py +0 -0
  88. {codejury-0.19.0/codejury → codejury-0.21.0/codejury/review}/repo/model.py +0 -0
  89. {codejury-0.19.0 → codejury-0.21.0}/codejury.egg-info/dependency_links.txt +0 -0
  90. {codejury-0.19.0 → codejury-0.21.0}/codejury.egg-info/entry_points.txt +0 -0
  91. {codejury-0.19.0 → codejury-0.21.0}/codejury.egg-info/requires.txt +0 -0
  92. {codejury-0.19.0 → codejury-0.21.0}/codejury.egg-info/top_level.txt +0 -0
  93. {codejury-0.19.0 → codejury-0.21.0}/setup.cfg +0 -0
  94. {codejury-0.19.0 → codejury-0.21.0}/tests/test_anthropic_provider.py +0 -0
  95. {codejury-0.19.0 → codejury-0.21.0}/tests/test_detection.py +0 -0
  96. {codejury-0.19.0 → codejury-0.21.0}/tests/test_guides.py +0 -0
  97. {codejury-0.19.0 → codejury-0.21.0}/tests/test_json_parse.py +0 -0
  98. {codejury-0.19.0 → codejury-0.21.0}/tests/test_litellm_provider.py +0 -0
  99. {codejury-0.19.0 → codejury-0.21.0}/tests/test_mddoc.py +0 -0
  100. {codejury-0.19.0 → codejury-0.21.0}/tests/test_openai_format.py +0 -0
  101. {codejury-0.19.0 → codejury-0.21.0}/tests/test_openai_provider.py +0 -0
  102. {codejury-0.19.0 → codejury-0.21.0}/tests/test_report.py +0 -0
  103. {codejury-0.19.0 → codejury-0.21.0}/tests/test_retry_provider.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codejury
3
- Version: 0.19.0
4
- Summary: AI code security review: an adversarial diff-audit engine and an agent-driven whole-repo review methodology, with security knowledge as rich rules
3
+ Version: 0.21.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,35 +40,44 @@ Dynamic: license-file
40
40
 
41
41
  > AI code security review for diffs and whole repositories.
42
42
 
43
- It runs two paths matched to their nature.
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. It is a methodology an interactive agent such
50
- as Claude Code or Codex runs to map a codebase attack surface, trace inputs to
51
- sinks across files, verify issues with a real PoC, and iterate over rounds with
52
- a persistent memory. A whole repository is too large for one LLM call, so it
53
- ships the methodology and scaffolds the workspace instead of running a
54
- pipeline.
55
-
56
- Security knowledge lives in rich vulnerability classes under `codejury/data/vulnerabilities/*.md`, with a
57
- vulnerable and a secure example per language, injected into the audit prompt
58
- rather than buried in code.
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 # core
64
- pip install "codejury[anthropic]" # add a backend, also openai or litellm
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-repo` 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 repo` 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 review diff --diff-file changes.diff
80
+ codejury review diff --file changes.diff
72
81
 
73
82
  # audit a git range in a repo
74
83
  codejury review diff --repo /path/to/app --git-range origin/main...HEAD
@@ -77,10 +86,10 @@ codejury review diff --repo /path/to/app --git-range origin/main...HEAD
77
86
  git diff HEAD~1 | codejury review diff
78
87
 
79
88
  # adversarial mode, more recall on subtle flaws, about 3x the cost
80
- codejury review diff --diff-file changes.diff --mode adversarial
89
+ codejury review diff --file changes.diff --mode adversarial
81
90
 
82
91
  # CI gate and SARIF
83
- codejury review diff --diff-file changes.diff --format sarif --fail-on high
92
+ codejury review 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
@@ -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
137
  codejury review repo /path/to/your/repo
125
138
  ```
126
139
 
127
- This scaffolds a review workspace with `entrypoints/`, `issues/`, `analysis/`,
128
- and a `security-review-memory.md`, seeds the entrypoint inventory from a
129
- deterministic scan, and prints the methodology. Run it with an interactive agent.
130
- It reads the methodology and the vulnerability classes, maps the attack surface, traces inputs to
131
- sinks across files, records high confidence issues with a PoC, and asks you to
132
- confirm credentials or false positives along the way. Nothing runs against
133
- production.
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-repo /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,14 @@ production config leaks.
142
183
 
143
184
  ## Extending
144
185
 
145
- Add a vulnerability class by dropping a new file `codejury/data/vulnerabilities/<class>.md`
146
- with the standard frontmatter of title, impact, tags, and triggers plus a
147
- vulnerable and a secure example. It is data, no code change needed.
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.
@@ -0,0 +1,165 @@
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-repo` 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 repo` 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 review diff --file changes.diff
50
+
51
+ # audit a git range in a repo
52
+ codejury review diff --repo /path/to/app --git-range origin/main...HEAD
53
+
54
+ # from stdin
55
+ git diff HEAD~1 | codejury review diff
56
+
57
+ # adversarial mode, more recall on subtle flaws, about 3x the cost
58
+ codejury review diff --file changes.diff --mode adversarial
59
+
60
+ # CI gate and SARIF
61
+ codejury review 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 review 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 repo /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-repo /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.
@@ -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())
@@ -4,12 +4,12 @@ Two paths matched to their nature:
4
4
 
5
5
  - ``review diff`` runs the coded diff engine over a unified diff: a single
6
6
  balanced call (standard) or the adversarial Finder/Challenger/Judge pass.
7
- - ``review repo`` scaffolds a workspace and prints the methodology for an
7
+ - ``review repo <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
  ``review diff --dry-run`` exercises the engine with a mock provider and no key.
12
- The audit orchestration itself lives in ``codejury.diff.runner``.
12
+ The audit orchestration itself lives in ``codejury.review.diff.runner``.
13
13
  """
14
14
 
15
15
  from __future__ import annotations
@@ -17,10 +17,11 @@ 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
23
- from codejury.diff.runner import audit_diff
24
+ from codejury.review.diff.runner import audit_diff
24
25
  from codejury.providers.factory import (
25
26
  DEFAULT_API_BASE,
26
27
  DEFAULT_API_KEY,
@@ -32,15 +33,15 @@ from codejury.providers.factory import (
32
33
  make_provider,
33
34
  )
34
35
  from codejury.providers.mock import MockProvider
35
- from codejury.repo.scaffold import scaffold
36
+ from codejury.review.repo.scaffold import scaffold
36
37
 
37
38
  _FORMATS = ("text", "markdown", "json", "sarif")
38
39
  _FAIL_ON = ("critical", "high", "medium", "low")
39
40
 
40
41
 
41
42
  def _read_diff(args) -> str:
42
- if args.diff_file:
43
- with open(args.diff_file, encoding="utf-8") as f:
43
+ if args.file:
44
+ with open(args.file, encoding="utf-8") as f:
44
45
  return f.read()
45
46
  if args.git_range:
46
47
  return subprocess.run(
@@ -65,7 +66,7 @@ _MOCK_REPLY = (
65
66
 
66
67
  def _add_audit_args(p) -> None:
67
68
  """The diff-audit flags for `review diff`."""
68
- p.add_argument("--diff-file", default=None, help="unified diff file (default: read stdin)")
69
+ p.add_argument("--file", default=None, help="unified diff file (default: read stdin)")
69
70
  p.add_argument("--repo", default=None, help="repo path for --git-range")
70
71
  p.add_argument("--git-range", default=None, help="git range to diff, e.g. origin/main...HEAD")
71
72
  p.add_argument("--dry-run", action="store_true",
@@ -99,6 +100,12 @@ def main(argv: list[str] | None = None) -> int:
99
100
  repo.add_argument("directory", help="target repository to review")
100
101
  repo.add_argument("--workspace", default="codejury-review", help="where to create the review workspace")
101
102
 
103
+ inst = sub.add_parser("install-slash-command",
104
+ help="install the /codejury-review-repo slash command for an agent")
105
+ inst.add_argument("--agent", choices=("claude", "codex"), default="claude",
106
+ help="which agent's command directory to install into")
107
+ inst.add_argument("--dir", default=None, help="explicit target directory, overrides --agent")
108
+
102
109
  args = parser.parse_args(argv)
103
110
  try:
104
111
  return _dispatch(args, parser)
@@ -115,7 +122,7 @@ def _dispatch(args, parser) -> int:
115
122
  provider = MockProvider(default=_MOCK_REPLY)
116
123
  model = "mock"
117
124
  # zero-config smoke test: fall back to a built-in demo diff when none is supplied
118
- diff = _read_diff(args) if (args.diff_file or args.git_range) else _dry_run_diff()
125
+ diff = _read_diff(args) if (args.file or args.git_range) else _dry_run_diff()
119
126
  else:
120
127
  provider = make_provider(args.provider, api_key=args.api_key, api_base=args.api_base, retries=args.retries)
121
128
  model = args.model
@@ -131,14 +138,35 @@ def _dispatch(args, parser) -> int:
131
138
 
132
139
  if args.command == "review" and scope == "repo":
133
140
  res = scaffold(args.directory, args.workspace)
134
- print(f"Workspace: {res.workspace}", file=sys.stderr)
141
+ (Path(res.workspace) / "METHODOLOGY.md").write_text(res.methodology, encoding="utf-8")
142
+ print(f"Workspace ready: {res.workspace}", file=sys.stderr)
135
143
  if res.guides:
136
- print(f"Detected stack: {', '.join(res.guides)}. Notes in {res.workspace}/_stack.md", file=sys.stderr)
144
+ print(f"Detected stack: {', '.join(res.guides)}, notes in {res.workspace}/_stack.md", file=sys.stderr)
137
145
  print(f"Flagged {len(res.candidate_files)} candidate entrypoint files into "
138
146
  f"{res.workspace}/entrypoints/_entrypoints.md", file=sys.stderr)
139
- print(f"Memory: {res.memory_path}", file=sys.stderr)
140
- print("\nRun this review with an interactive agent (Claude Code / Codex) using the methodology below.\n")
141
- print(res.methodology)
147
+ print(f"Methodology: {res.workspace}/METHODOLOGY.md", file=sys.stderr)
148
+ print(
149
+ "This command sets up the review, it does not find the issues itself. Next, have an "
150
+ f"interactive agent follow {res.workspace}/METHODOLOGY.md to run the review, or use the "
151
+ "/codejury-review-repo command in Claude Code or Codex. Findings are written to "
152
+ f"{res.workspace}/issues/."
153
+ )
154
+ return 0
155
+
156
+ if args.command == "install-slash-command":
157
+ from codejury.resources import COMMANDS_DIR
158
+ # the command body is portable, only the directory differs per agent
159
+ agent_dirs = {
160
+ "claude": Path.home() / ".claude" / "commands",
161
+ "codex": Path.home() / ".codex" / "prompts",
162
+ }
163
+ target_dir = Path(args.dir) if args.dir else agent_dirs[args.agent]
164
+ target_dir.mkdir(parents=True, exist_ok=True)
165
+ name = "codejury-review-repo.md"
166
+ dst = target_dir / name
167
+ dst.write_text((COMMANDS_DIR / name).read_text(encoding="utf-8"), encoding="utf-8")
168
+ print(f"Installed slash command to {dst}")
169
+ print("Run it in the agent with: /codejury-review-repo <repository>")
142
170
  return 0
143
171
 
144
172
  if args.command == "review": # no scope given
@@ -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 repo $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 real runnable file
151
- `issues/poc_<name>.<ext>`, a script or an `.http` file, not a sketch in prose. If
152
- you cannot write a concrete runnable PoC, the finding is most likely a false
153
- positive, so do not report it. Each issue file must have:
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 `issues/poc_<name>.<ext>` and how to run it)
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)
@@ -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
@@ -11,7 +11,7 @@ from __future__ import annotations
11
11
 
12
12
  from dataclasses import dataclass, field
13
13
 
14
- from codejury.diff.debate_prompts import (
14
+ from codejury.review.diff.debate_prompts import (
15
15
  CHALLENGER_SYSTEM,
16
16
  FINDER_SYSTEM,
17
17
  JUDGE_SYSTEM,
@@ -19,7 +19,7 @@ from codejury.diff.debate_prompts import (
19
19
  finder_prompt,
20
20
  judge_prompt,
21
21
  )
22
- from codejury.diff.vulnerabilities import vulnerabilities_for_diff
22
+ from codejury.review.diff.vulnerabilities import vulnerabilities_for_diff
23
23
  from codejury.domain.finding import Finding, findings_from_list
24
24
  from codejury.json_parse import extract_json_object
25
25
  from codejury.providers.base import Message, Provider
@@ -16,7 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  import json
18
18
 
19
- from codejury.diff.prompts import DO_NOT_REPORT, FOCUS, category_block
19
+ from codejury.review.diff.prompts import DO_NOT_REPORT, FOCUS, category_block
20
20
 
21
21
  _FINDING_FIELDS = (
22
22
  '{"file": "path", "line": 0, "severity": "CRITICAL|HIGH|MEDIUM|LOW", '
@@ -10,8 +10,8 @@ from __future__ import annotations
10
10
  import re
11
11
 
12
12
  from codejury.domain.finding import Finding, findings_from_list
13
- from codejury.diff.prompts import SYSTEM, standard_audit_prompt
14
- from codejury.diff.vulnerabilities import vulnerabilities_for_diff
13
+ from codejury.review.diff.prompts import SYSTEM, standard_audit_prompt
14
+ from codejury.review.diff.vulnerabilities import vulnerabilities_for_diff
15
15
  from codejury.guides import select_guides
16
16
  from codejury.json_parse import extract_json_object
17
17
  from codejury.providers.base import Message, Provider
@@ -46,7 +46,7 @@ _JSON_SHAPE = (
46
46
 
47
47
  def category_block() -> str:
48
48
  """The closed category set the model must choose from, the vulnerability ids."""
49
- from codejury.diff.vulnerabilities import allowed_categories
49
+ from codejury.review.diff.vulnerabilities import allowed_categories
50
50
 
51
51
  cats = allowed_categories()
52
52
  return (
@@ -10,10 +10,10 @@ from __future__ import annotations
10
10
 
11
11
  import dataclasses
12
12
 
13
- from codejury.diff.debate import AdversarialAuditRunner
14
- from codejury.diff.engine import AuditRunner
15
- from codejury.diff.findings_filter import FindingsFilter
16
- from codejury.diff.vulnerabilities import allowed_categories, normalize_category
13
+ from codejury.review.diff.debate import AdversarialAuditRunner
14
+ from codejury.review.diff.engine import AuditRunner
15
+ from codejury.review.diff.findings_filter import FindingsFilter
16
+ from codejury.review.diff.vulnerabilities import allowed_categories, normalize_category
17
17
  from codejury.domain.finding import Finding
18
18
 
19
19
  # A diff larger than this is audited file-by-file so a big PR does not overflow
File without changes
@@ -21,7 +21,7 @@ from codejury.guides import (
21
21
  logic_layer_globs,
22
22
  select_guides,
23
23
  )
24
- from codejury.repo.model import build_repo_model_from_dir, candidate_entrypoint_files, logic_layer_files
24
+ from codejury.review.repo.model import build_repo_model_from_dir, candidate_entrypoint_files, logic_layer_files
25
25
  from codejury.resources import METHODOLOGIES_DIR
26
26
 
27
27
  _METHODOLOGY = METHODOLOGIES_DIR / "repo-review.md"
@@ -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)