codejury 0.21.0__tar.gz → 0.23.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 (104) hide show
  1. {codejury-0.21.0 → codejury-0.23.0}/PKG-INFO +61 -74
  2. {codejury-0.21.0 → codejury-0.23.0}/README.md +60 -73
  3. codejury-0.23.0/codejury/__init__.py +15 -0
  4. {codejury-0.21.0 → codejury-0.23.0}/codejury/cli.py +12 -5
  5. codejury-0.23.0/codejury/data/commands/codejury-review-repo.md +42 -0
  6. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/methodologies/repo-review.md +48 -4
  7. {codejury-0.21.0 → codejury-0.23.0}/codejury/domain/__init__.py +1 -1
  8. {codejury-0.21.0 → codejury-0.23.0}/codejury/domain/finding.py +1 -1
  9. {codejury-0.21.0 → codejury-0.23.0}/codejury/json_parse.py +10 -10
  10. {codejury-0.21.0 → codejury-0.23.0}/codejury/mddoc.py +4 -4
  11. {codejury-0.21.0 → codejury-0.23.0}/codejury/providers/openai_format.py +1 -1
  12. {codejury-0.21.0 → codejury-0.23.0}/codejury/providers/retry.py +1 -1
  13. {codejury-0.21.0 → codejury-0.23.0}/codejury/report.py +1 -1
  14. {codejury-0.21.0 → codejury-0.23.0}/codejury/resources.py +4 -4
  15. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/diff/debate.py +4 -4
  16. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/diff/debate_prompts.py +3 -3
  17. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/diff/engine.py +3 -3
  18. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/diff/findings_filter.py +1 -1
  19. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/diff/runner.py +2 -2
  20. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/diff/vulnerabilities.py +5 -5
  21. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/repo/model.py +5 -5
  22. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/repo/scaffold.py +48 -5
  23. {codejury-0.21.0 → codejury-0.23.0}/codejury.egg-info/PKG-INFO +61 -74
  24. {codejury-0.21.0 → codejury-0.23.0}/codejury.egg-info/SOURCES.txt +1 -1
  25. {codejury-0.21.0 → codejury-0.23.0}/pyproject.toml +2 -2
  26. {codejury-0.21.0 → codejury-0.23.0}/tests/test_cli_audit.py +3 -1
  27. {codejury-0.21.0 → codejury-0.23.0}/tests/test_repo_scaffold.py +30 -0
  28. {codejury-0.21.0 → codejury-0.23.0}/tests/test_vulnerabilities.py +2 -2
  29. codejury-0.21.0/codejury/__init__.py +0 -15
  30. codejury-0.21.0/codejury/data/commands/codejury-review-repo.md +0 -29
  31. {codejury-0.21.0 → codejury-0.23.0}/LICENSE +0 -0
  32. {codejury-0.21.0 → codejury-0.23.0}/codejury/__main__.py +0 -0
  33. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/detection.yaml +0 -0
  34. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/frameworks/go/echo.md +0 -0
  35. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/frameworks/go/gin.md +0 -0
  36. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/frameworks/javascript/express.md +0 -0
  37. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/frameworks/javascript/nestjs.md +0 -0
  38. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/frameworks/python/celery.md +0 -0
  39. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/frameworks/python/django.md +0 -0
  40. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/frameworks/python/fastapi.md +0 -0
  41. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/frameworks/python/flask.md +0 -0
  42. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/languages/go.md +0 -0
  43. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/languages/javascript.md +0 -0
  44. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/languages/python.md +0 -0
  45. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/languages/typescript.md +0 -0
  46. /codejury-0.21.0/codejury/data/methodologies/security-review-memory.md → /codejury-0.23.0/codejury/data/methodologies/memory-template.md +0 -0
  47. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/protocols/oauth.md +0 -0
  48. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/SKILL.md +0 -0
  49. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/business-logic.md +0 -0
  50. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/code-injection.md +0 -0
  51. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/command-injection.md +0 -0
  52. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/cross-site-request-forgery.md +0 -0
  53. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/cross-site-scripting.md +0 -0
  54. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/hardcoded-secrets.md +0 -0
  55. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/http-response-splitting.md +0 -0
  56. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/improper-authentication.md +0 -0
  57. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/information-exposure.md +0 -0
  58. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/insecure-cryptography.md +0 -0
  59. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/insecure-deserialization.md +0 -0
  60. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/insecure-direct-object-reference.md +0 -0
  61. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/insecure-transport.md +0 -0
  62. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/jwt-validation.md +0 -0
  63. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/mass-assignment.md +0 -0
  64. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/missing-authorization.md +0 -0
  65. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/open-redirect.md +0 -0
  66. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/path-traversal.md +0 -0
  67. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/race-condition.md +0 -0
  68. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/replay-attack.md +0 -0
  69. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/server-side-request-forgery.md +0 -0
  70. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/server-side-template-injection.md +0 -0
  71. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/session-fixation.md +0 -0
  72. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/sql-injection.md +0 -0
  73. {codejury-0.21.0 → codejury-0.23.0}/codejury/data/vulnerabilities/xml-external-entity.md +0 -0
  74. {codejury-0.21.0 → codejury-0.23.0}/codejury/detection.py +0 -0
  75. {codejury-0.21.0 → codejury-0.23.0}/codejury/guides.py +0 -0
  76. {codejury-0.21.0 → codejury-0.23.0}/codejury/providers/__init__.py +0 -0
  77. {codejury-0.21.0 → codejury-0.23.0}/codejury/providers/anthropic.py +0 -0
  78. {codejury-0.21.0 → codejury-0.23.0}/codejury/providers/base.py +0 -0
  79. {codejury-0.21.0 → codejury-0.23.0}/codejury/providers/factory.py +0 -0
  80. {codejury-0.21.0 → codejury-0.23.0}/codejury/providers/litellm.py +0 -0
  81. {codejury-0.21.0 → codejury-0.23.0}/codejury/providers/mock.py +0 -0
  82. {codejury-0.21.0 → codejury-0.23.0}/codejury/providers/openai.py +0 -0
  83. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/__init__.py +0 -0
  84. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/diff/__init__.py +0 -0
  85. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/diff/prompts.py +0 -0
  86. {codejury-0.21.0 → codejury-0.23.0}/codejury/review/repo/__init__.py +0 -0
  87. {codejury-0.21.0 → codejury-0.23.0}/codejury.egg-info/dependency_links.txt +0 -0
  88. {codejury-0.21.0 → codejury-0.23.0}/codejury.egg-info/entry_points.txt +0 -0
  89. {codejury-0.21.0 → codejury-0.23.0}/codejury.egg-info/requires.txt +0 -0
  90. {codejury-0.21.0 → codejury-0.23.0}/codejury.egg-info/top_level.txt +0 -0
  91. {codejury-0.21.0 → codejury-0.23.0}/setup.cfg +0 -0
  92. {codejury-0.21.0 → codejury-0.23.0}/tests/test_anthropic_provider.py +0 -0
  93. {codejury-0.21.0 → codejury-0.23.0}/tests/test_detection.py +0 -0
  94. {codejury-0.21.0 → codejury-0.23.0}/tests/test_diff_debate.py +0 -0
  95. {codejury-0.21.0 → codejury-0.23.0}/tests/test_diff_engine.py +0 -0
  96. {codejury-0.21.0 → codejury-0.23.0}/tests/test_guides.py +0 -0
  97. {codejury-0.21.0 → codejury-0.23.0}/tests/test_json_parse.py +0 -0
  98. {codejury-0.21.0 → codejury-0.23.0}/tests/test_litellm_provider.py +0 -0
  99. {codejury-0.21.0 → codejury-0.23.0}/tests/test_mddoc.py +0 -0
  100. {codejury-0.21.0 → codejury-0.23.0}/tests/test_openai_format.py +0 -0
  101. {codejury-0.21.0 → codejury-0.23.0}/tests/test_openai_provider.py +0 -0
  102. {codejury-0.21.0 → codejury-0.23.0}/tests/test_repo_model.py +0 -0
  103. {codejury-0.21.0 → codejury-0.23.0}/tests/test_report.py +0 -0
  104. {codejury-0.21.0 → codejury-0.23.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.21.0
4
- Summary: AI code security review for diffs and whole repositories.
3
+ Version: 0.23.0
4
+ Summary: AI code security review for diffs and repos.
5
5
  Author: AISecLabs
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/aiseclabs/codejury
@@ -38,25 +38,15 @@ Dynamic: license-file
38
38
  ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
39
39
  ```
40
40
 
41
- > AI code security review for diffs and whole repositories.
41
+ An AI code security review tool. It works two ways. `review diff` audits a pull
42
+ request diff for newly introduced exploitable risk in one command. `review repo`
43
+ sets up an interactive agent such as Claude Code or Codex to audit a whole
44
+ repository, mapping the attack surface, tracing inputs to sinks across files, and
45
+ verifying each issue with a real PoC.
42
46
 
43
- codejury runs two paths matched to their nature.
44
-
45
- - **Diff Review** is coded. It audits a pull request diff for newly introduced
46
- exploitable risk, as a single balanced LLM call or an adversarial Finder,
47
- Challenger, and Judge pass that trades roughly 3x the cost for extra recall on
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.
47
+ Security knowledge is data, not code. Drop-in markdown guides hold the
48
+ vulnerability classes, languages, frameworks, and protocols, so the engine names
49
+ no language and adding a stack is a new file.
60
50
 
61
51
  ## Install
62
52
 
@@ -67,19 +57,21 @@ codejury install-slash-command # Claude Code, ~/.claude/commands/
67
57
  codejury install-slash-command --agent codex # Codex, ~/.codex/prompts/
68
58
  ```
69
59
 
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.
60
+ `install-slash-command` copies the `/codejury-review-repo` command into the
61
+ agent's command directory. The command body is the same for every agent, only the
62
+ directory differs, so pass `--dir` for any other agent.
75
63
 
76
64
  ## Diff Review
77
65
 
66
+ The coded engine. It audits a diff in one command, as a single balanced LLM call
67
+ or an adversarial Finder, Challenger, and Judge pass that trades roughly 3x the
68
+ cost for extra recall on subtle flaws that span files.
69
+
78
70
  ```bash
79
- # audit a diff file
71
+ # a diff file
80
72
  codejury review diff --file changes.diff
81
73
 
82
- # audit a git range in a repo
74
+ # a git range in a repo
83
75
  codejury review diff --repo /path/to/app --git-range origin/main...HEAD
84
76
 
85
77
  # from stdin
@@ -97,57 +89,25 @@ the `CODEJURY_API_KEY`, `CODEJURY_MODEL`, and `CODEJURY_API_BASE` environment
97
89
  variables. `codejury review diff --dry-run` exercises the engine with a mock
98
90
  provider and no key, and falls back to a built in demo diff when you pass none.
99
91
 
100
- ### Choosing a Model and Mode
101
-
102
- Detection quality is dominated by the model first, then the mode. On real diff
103
- probes:
104
-
105
- - A strong model at the Claude Sonnet tier in standard mode caught every planted
106
- vulnerability with almost no false positives. A weaker model raised false
107
- positives in both modes, so the model is the lever that matters most.
108
- - Adversarial mode did not lower false positives over standard on those probes
109
- and costs about 3x. Reach for it to gain recall on subtle logic that spans
110
- files, not as a way to cut false positives.
111
-
112
- Default to standard mode with a strong model, set with `--model` or
113
- `CODEJURY_MODEL`. False positives are held down by the do not report list and the
114
- post filter, not by the mode.
115
-
116
- ### Use in CI with GitHub Actions
117
-
118
- Audit every pull request and surface findings in the code scanning tab. Copy
119
- `examples/codejury-pr-review.yml` into `.github/workflows/`, add a
120
- `CODEJURY_API_KEY` repository secret, and it will
121
-
122
- 1. diff the pull request against its base with `--git-range origin/<base>...HEAD`,
123
- 2. write SARIF and upload it with `github/codeql-action/upload-sarif`,
124
- 3. fail the check on a HIGH or CRITICAL finding with `--fail-on high`.
125
-
126
- The job makes one model call per pull request in standard mode. The SARIF is
127
- uploaded even when the gate fails, so findings always show up on the pull
128
- request.
129
-
130
92
  ## Repo Review
131
93
 
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.
94
+ The agent path. A whole repo is too large for one LLM call, so this sets up a
95
+ review for an interactive agent rather than running a pipeline.
135
96
 
136
97
  ```bash
137
98
  codejury review repo /path/to/your/repo
138
99
  ```
139
100
 
140
- This detects the stack, seeds the entrypoint inventory and the downstream trace
101
+ It detects the stack, seeds the entrypoint inventory and the downstream trace
141
102
  targets from a deterministic scan, writes the methodology to
142
- `<workspace>/METHODOLOGY.md`, and prints a short pointer. It creates the
143
- workspace:
103
+ `<workspace>/METHODOLOGY.md`, and prints a short pointer. The workspace:
144
104
 
145
105
  ```
146
106
  entrypoints/ the candidate entrypoint files to start from
147
107
  issues/ one write-up per confirmed or suspected issue
148
108
  pocs/ a runnable PoC per issue, same name as the issue
149
109
  analysis/ _trace_targets.md, the round ledger, and trace notes
150
- security-review-memory.md
110
+ METHODOLOGY.md and MEMORY.md
151
111
  ```
152
112
 
153
113
  Then run it with an interactive agent. In Claude Code or Codex:
@@ -157,22 +117,49 @@ Then run it with an interactive agent. In Claude Code or Codex:
157
117
  ```
158
118
 
159
119
  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.
120
+ to follow the `METHODOLOGY.md` the scaffold wrote. The agent maps the attack
121
+ surface including non HTTP sources, traces each input to its sink through the
122
+ downstream layers, runs an Authorization Model pass for missing-auth and IDOR,
123
+ and follows a control into a library when an entrypoint delegates it. It iterates
124
+ until a Completeness Gate passes, confirms each issue with a real PoC against a
125
+ sandbox or dev environment, and asks you for any credential it needs. Only a
126
+ reproduced PoC is a confirmed finding, and nothing runs against production.
170
127
 
171
128
  The supported stacks today are Python with Django, Celery, Flask, and FastAPI,
172
129
  Go with Gin and Echo, JavaScript and TypeScript with Express and NestJS, and the
173
130
  OAuth and OIDC protocol. The methodology still works on an unguided stack, it just
174
131
  leans more on the agent's own knowledge.
175
132
 
133
+ ## Choosing a Model and Mode
134
+
135
+ Detection quality is dominated by the model first, then the mode. On real diff
136
+ probes:
137
+
138
+ - A strong model at the Claude Sonnet tier in standard mode caught every planted
139
+ vulnerability with almost no false positives. A weaker model raised false
140
+ positives in both modes, so the model is the lever that matters most.
141
+ - Adversarial mode did not lower false positives over standard on those probes
142
+ and costs about 3x. Reach for it to gain recall on subtle logic that spans
143
+ files, not as a way to cut false positives.
144
+
145
+ Default to standard mode with a strong model, set with `--model` or
146
+ `CODEJURY_MODEL`. False positives are held down by the do not report list and the
147
+ post filter, not by the mode.
148
+
149
+ ## Use in CI with GitHub Actions
150
+
151
+ Audit every pull request and surface findings in the code scanning tab. Copy
152
+ `examples/codejury-pr-review.yml` into `.github/workflows/`, add a
153
+ `CODEJURY_API_KEY` repository secret, and it will
154
+
155
+ 1. diff the pull request against its base with `--git-range origin/<base>...HEAD`,
156
+ 2. write SARIF and upload it with `github/codeql-action/upload-sarif`,
157
+ 3. fail the check on a HIGH or CRITICAL finding with `--fail-on high`.
158
+
159
+ The job makes one model call per pull request in standard mode. The SARIF is
160
+ uploaded even when the gate fails, so findings always show up on the pull
161
+ request.
162
+
176
163
  ## Findings
177
164
 
178
165
  Each finding carries a file and line, a severity and category, a concrete exploit
@@ -7,25 +7,15 @@
7
7
  ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
8
8
  ```
9
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.
10
+ An AI code security review tool. It works two ways. `review diff` audits a pull
11
+ request diff for newly introduced exploitable risk in one command. `review repo`
12
+ sets up an interactive agent such as Claude Code or Codex to audit a whole
13
+ repository, mapping the attack surface, tracing inputs to sinks across files, and
14
+ verifying each issue with a real PoC.
15
+
16
+ Security knowledge is data, not code. Drop-in markdown guides hold the
17
+ vulnerability classes, languages, frameworks, and protocols, so the engine names
18
+ no language and adding a stack is a new file.
29
19
 
30
20
  ## Install
31
21
 
@@ -36,19 +26,21 @@ codejury install-slash-command # Claude Code, ~/.claude/commands/
36
26
  codejury install-slash-command --agent codex # Codex, ~/.codex/prompts/
37
27
  ```
38
28
 
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.
29
+ `install-slash-command` copies the `/codejury-review-repo` command into the
30
+ agent's command directory. The command body is the same for every agent, only the
31
+ directory differs, so pass `--dir` for any other agent.
44
32
 
45
33
  ## Diff Review
46
34
 
35
+ The coded engine. It audits a diff in one command, as a single balanced LLM call
36
+ or an adversarial Finder, Challenger, and Judge pass that trades roughly 3x the
37
+ cost for extra recall on subtle flaws that span files.
38
+
47
39
  ```bash
48
- # audit a diff file
40
+ # a diff file
49
41
  codejury review diff --file changes.diff
50
42
 
51
- # audit a git range in a repo
43
+ # a git range in a repo
52
44
  codejury review diff --repo /path/to/app --git-range origin/main...HEAD
53
45
 
54
46
  # from stdin
@@ -66,57 +58,25 @@ the `CODEJURY_API_KEY`, `CODEJURY_MODEL`, and `CODEJURY_API_BASE` environment
66
58
  variables. `codejury review diff --dry-run` exercises the engine with a mock
67
59
  provider and no key, and falls back to a built in demo diff when you pass none.
68
60
 
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
61
  ## Repo Review
100
62
 
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.
63
+ The agent path. A whole repo is too large for one LLM call, so this sets up a
64
+ review for an interactive agent rather than running a pipeline.
104
65
 
105
66
  ```bash
106
67
  codejury review repo /path/to/your/repo
107
68
  ```
108
69
 
109
- This detects the stack, seeds the entrypoint inventory and the downstream trace
70
+ It detects the stack, seeds the entrypoint inventory and the downstream trace
110
71
  targets from a deterministic scan, writes the methodology to
111
- `<workspace>/METHODOLOGY.md`, and prints a short pointer. It creates the
112
- workspace:
72
+ `<workspace>/METHODOLOGY.md`, and prints a short pointer. The workspace:
113
73
 
114
74
  ```
115
75
  entrypoints/ the candidate entrypoint files to start from
116
76
  issues/ one write-up per confirmed or suspected issue
117
77
  pocs/ a runnable PoC per issue, same name as the issue
118
78
  analysis/ _trace_targets.md, the round ledger, and trace notes
119
- security-review-memory.md
79
+ METHODOLOGY.md and MEMORY.md
120
80
  ```
121
81
 
122
82
  Then run it with an interactive agent. In Claude Code or Codex:
@@ -126,22 +86,49 @@ Then run it with an interactive agent. In Claude Code or Codex:
126
86
  ```
127
87
 
128
88
  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.
89
+ to follow the `METHODOLOGY.md` the scaffold wrote. The agent maps the attack
90
+ surface including non HTTP sources, traces each input to its sink through the
91
+ downstream layers, runs an Authorization Model pass for missing-auth and IDOR,
92
+ and follows a control into a library when an entrypoint delegates it. It iterates
93
+ until a Completeness Gate passes, confirms each issue with a real PoC against a
94
+ sandbox or dev environment, and asks you for any credential it needs. Only a
95
+ reproduced PoC is a confirmed finding, and nothing runs against production.
139
96
 
140
97
  The supported stacks today are Python with Django, Celery, Flask, and FastAPI,
141
98
  Go with Gin and Echo, JavaScript and TypeScript with Express and NestJS, and the
142
99
  OAuth and OIDC protocol. The methodology still works on an unguided stack, it just
143
100
  leans more on the agent's own knowledge.
144
101
 
102
+ ## Choosing a Model and Mode
103
+
104
+ Detection quality is dominated by the model first, then the mode. On real diff
105
+ probes:
106
+
107
+ - A strong model at the Claude Sonnet tier in standard mode caught every planted
108
+ vulnerability with almost no false positives. A weaker model raised false
109
+ positives in both modes, so the model is the lever that matters most.
110
+ - Adversarial mode did not lower false positives over standard on those probes
111
+ and costs about 3x. Reach for it to gain recall on subtle logic that spans
112
+ files, not as a way to cut false positives.
113
+
114
+ Default to standard mode with a strong model, set with `--model` or
115
+ `CODEJURY_MODEL`. False positives are held down by the do not report list and the
116
+ post filter, not by the mode.
117
+
118
+ ## Use in CI with GitHub Actions
119
+
120
+ Audit every pull request and surface findings in the code scanning tab. Copy
121
+ `examples/codejury-pr-review.yml` into `.github/workflows/`, add a
122
+ `CODEJURY_API_KEY` repository secret, and it will
123
+
124
+ 1. diff the pull request against its base with `--git-range origin/<base>...HEAD`,
125
+ 2. write SARIF and upload it with `github/codeql-action/upload-sarif`,
126
+ 3. fail the check on a HIGH or CRITICAL finding with `--fail-on high`.
127
+
128
+ The job makes one model call per pull request in standard mode. The SARIF is
129
+ uploaded even when the gate fails, so findings always show up on the pull
130
+ request.
131
+
145
132
  ## Findings
146
133
 
147
134
  Each finding carries a file and line, a severity and category, a concrete exploit
@@ -0,0 +1,15 @@
1
+ """AI code security review tool.
2
+
3
+ Two paths matched to their nature: a coded diff-audit engine, a standard single
4
+ call or an adversarial Finder/Challenger/Judge pass, and a whole-repo review run
5
+ as a methodology by an interactive agent. Security knowledge lives in rich
6
+ markdown vulnerability classes under data/vulnerabilities, injected into the
7
+ audit prompt, not in a rendered schema.
8
+ """
9
+
10
+ from importlib.metadata import PackageNotFoundError, version
11
+
12
+ try:
13
+ __version__ = version("codejury")
14
+ except PackageNotFoundError: # running from a source tree without an install
15
+ __version__ = "0.0.0"
@@ -3,10 +3,10 @@
3
3
  Two paths matched to their nature:
4
4
 
5
5
  - ``review diff`` runs the coded diff engine over a unified diff: a single
6
- balanced call (standard) or the adversarial Finder/Challenger/Judge pass.
6
+ balanced call in standard mode or the adversarial Finder/Challenger/Judge pass.
7
7
  - ``review repo <dir>`` scaffolds a workspace and prints the methodology for an
8
- interactive agent to run a whole-repo review (it does not run an LLM pipeline,
9
- which a single call cannot do for a whole codebase).
8
+ interactive agent to run a whole-repo review. It does not run an LLM pipeline,
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
12
  The audit orchestration itself lives in ``codejury.review.diff.runner``.
@@ -98,7 +98,9 @@ def main(argv: list[str] | None = None) -> int:
98
98
  _add_audit_args(rsub.add_parser("diff", help="audit a unified diff (the coded engine)"))
99
99
  repo = rsub.add_parser("repo", help="scaffold a whole-repo review for an interactive agent")
100
100
  repo.add_argument("directory", help="target repository to review")
101
- repo.add_argument("--workspace", default="codejury-review", help="where to create the review workspace")
101
+ repo.add_argument("--workspace", default="/var/tmp/codejury-review", help="where to create the review workspace")
102
+ repo.add_argument("--fresh", action="store_true",
103
+ help="clear a previous review's output in the workspace first, MEMORY.md included")
102
104
 
103
105
  inst = sub.add_parser("install-slash-command",
104
106
  help="install the /codejury-review-repo slash command for an agent")
@@ -137,8 +139,13 @@ def _dispatch(args, parser) -> int:
137
139
  return 1 if gate(kept, args.fail_on) else 0
138
140
 
139
141
  if args.command == "review" and scope == "repo":
140
- res = scaffold(args.directory, args.workspace)
142
+ res = scaffold(args.directory, args.workspace, fresh=args.fresh)
141
143
  (Path(res.workspace) / "METHODOLOGY.md").write_text(res.methodology, encoding="utf-8")
144
+ if res.cleared:
145
+ print(f"Cleared {len(res.cleared)} prior-run paths in {res.workspace}, MEMORY.md included", file=sys.stderr)
146
+ elif res.had_prior_run:
147
+ print(f"A previous review's output is in {res.workspace}. Re-run with --fresh to clear it "
148
+ "first, MEMORY.md included.", file=sys.stderr)
142
149
  print(f"Workspace ready: {res.workspace}", file=sys.stderr)
143
150
  if res.guides:
144
151
  print(f"Detected stack: {', '.join(res.guides)}, notes in {res.workspace}/_stack.md", file=sys.stderr)
@@ -0,0 +1,42 @@
1
+ ---
2
+ description: Run a codejury whole-repo security review on a repository, interactively
3
+ ---
4
+ Run a codejury whole-repo security review of: $ARGUMENTS
5
+
6
+ 1. Scaffold the workspace:
7
+
8
+ ```
9
+ codejury review repo $ARGUMENTS --workspace /var/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
+ If the output reports that a previous review's output is already in the
17
+ workspace, ask me whether to clear it and start fresh. If I say yes, re-run the
18
+ same command with `--fresh`, which clears the prior issues, PoCs, round ledger,
19
+ and MEMORY.md for a clean slate. If I say no, continue and build on what is
20
+ there.
21
+
22
+ 2. Read `<workspace>/METHODOLOGY.md` and follow it to completion. It is the single
23
+ source of truth for how to run the review, the entrypoint map, the trace
24
+ targets, the Authorization Model pass, the dependency-control checks, the round
25
+ ledger, and the Completeness Gate. Do not improvise a different process.
26
+
27
+ Run every round to the Completeness Gate on your own. Do not pause between
28
+ rounds to ask whether to continue, do not stop early because a round felt
29
+ productive, and do not report the review done until the gate passes. The only
30
+ reasons to stop and ask me are in step 3.
31
+
32
+ 3. Verify each issue with a real PoC, human in the loop. Stop and ask me only for
33
+ what the PoC genuinely needs: a credential, a test account, an MFA step, or
34
+ go-ahead before a destructive action. Never touch production, never use real
35
+ credentials, and never run a destructive action without my go-ahead. Only a
36
+ reproduced PoC is a confirmed finding, so keep reviewing while a PoC is blocked
37
+ on me rather than waiting.
38
+
39
+ 4. Report confirmed findings, the ones with a reproduced PoC, separately from
40
+ suspected ones still blocked on verification, as a table: title, class,
41
+ `file:line`, exploit, verification status. The issue files live in the
42
+ workspace `issues/`.
@@ -1,6 +1,6 @@
1
1
  # Repo Security Review: Agent Methodology
2
2
 
3
- The `review repo` path: a whole-repository security audit, run by an interactive
3
+ The `review repo` path: a whole-repo security audit, run by an interactive
4
4
  coding agent such as Claude Code or Codex, not a one-shot LLM call. It maps the
5
5
  attack surface, traces inputs to sinks across files, verifies issues with a real
6
6
  PoC, and iterates over multiple rounds with a persistent memory. One round is
@@ -8,13 +8,13 @@ roughly 30 minutes. Run as many rounds as needed.
8
8
 
9
9
  Target repository: the directory you were given.
10
10
  Workspace: `<workspace>/<project>/`, created for you, holding `entrypoints/`,
11
- `issues/`, `analysis/`, and `security-review-memory.md`.
11
+ `issues/`, `analysis/`, and `MEMORY.md`.
12
12
 
13
13
  ---
14
14
 
15
15
  ## On Start
16
16
 
17
- 1. Read `security-review-memory.md` in the workspace if it exists:
17
+ 1. Read `MEMORY.md` in the workspace if it exists:
18
18
  - skip every pattern under "Confirmed false positives".
19
19
  - do not re-report anything under "Fixed".
20
20
  - weight the files under "High-risk areas" more heavily.
@@ -136,6 +136,40 @@ third-party. It is not auditing the library for its own bugs, which belongs to
136
136
  that library's own review. It is confirming that the control your endpoint relies
137
137
  on holds here.
138
138
 
139
+ ## Challenge Every Control, Presence Is Not Sufficiency
140
+
141
+ A control being present is not the same as the control holding. The most common
142
+ way a real review misses a real flaw is clearing a path the moment it sees a
143
+ gate, a signature, or a single-use token, without asking whether that control
144
+ actually defeats the specific attack. For every control you find on a path, do
145
+ not clear on presence. Challenge it on these axes:
146
+
147
+ - **Replay**. A signed or authenticated privileged request is replayable unless
148
+ the control BOTH consumes a one-time nonce AND enforces a freshness window such
149
+ as a timestamp or short expiry. That the caller is authenticated, that the
150
+ scheme fails closed, or that a TOTP is single-use is orthogonal to replay, so
151
+ do not let any of them clear it. Capture one valid signed request and ask: can
152
+ the exact same bytes be sent again and accepted? If nothing is consumed and no
153
+ window is checked, it replays.
154
+ - **Concurrency and state**. A check-then-act is bypassable under concurrent
155
+ requests unless a lock is held across the act, even when the single-request
156
+ path looks single-use. A redeem, a balance debit, or a status transition that
157
+ reads then writes without a row lock or atomic guard double-spends under a race.
158
+ - **Sibling coverage**. A gate on one endpoint does not cover its siblings. When
159
+ you find a missing-authorization or IDOR pattern, enumerate every endpoint
160
+ behind the same controller or gate and report the highest-impact instance, not
161
+ the first one you saw. A read variant flagged MEDIUM often has a create or push
162
+ sibling that is HIGH.
163
+ - **Trusted-source assumptions**. A value is not safe just because a caller you
164
+ treat as trusted set it. If that caller is a distinct tenant or service, the
165
+ value is still attacker-influenced. A self-set `callback_url` that flows into a
166
+ server-side fetch is SSRF or a worker-blocking DoS unless there is an allowlist,
167
+ so do not clear it on "the owner set it".
168
+
169
+ When a control passes one axis, it can still fail another, so run all four before
170
+ you mark a path cleared. Record which axis you checked, not just that a control
171
+ exists.
172
+
139
173
  ## Scope
140
174
 
141
175
  Report only HIGH / CRITICAL, exploitable, high-confidence issues. **Do not report**
@@ -205,6 +239,12 @@ from the inventory, trace it through the downstream layers, and log the round in
205
239
  bugs. The hard classes such as authorization, replay, and broken business state
206
240
  usually appear only after several rounds, so keep going.
207
241
 
242
+ Run the rounds to the Completeness Gate on your own. Do not pause between rounds
243
+ to ask whether to continue, and do not stop early because a round was productive.
244
+ The one place to stop and ask the operator is PoC verification, when a PoC needs a
245
+ credential, test data, or go-ahead for a destructive action. While a PoC is
246
+ blocked on the operator, keep reviewing other sources rather than waiting.
247
+
208
248
  ## Completeness Gate
209
249
 
210
250
  Do not report the review complete until all of the following hold. A short run
@@ -217,6 +257,10 @@ reporting it as clean is the failure this gate exists to prevent.
217
257
  at the view.
218
258
  - The Authorization Model pass ran: the access gate is mapped, sibling endpoints
219
259
  compared, and IDOR and unauthenticated privileged paths checked.
260
+ - Every control on a cleared path was challenged for sufficiency, not presence:
261
+ replay needs a nonce and a freshness window, check-then-act needs a lock,
262
+ sibling endpoints behind a shared gate were all enumerated, and a trusted-source
263
+ value flowing to a sink was still treated as attacker-influenced.
220
264
  - `analysis/_rounds.md` shows two consecutive rounds that added no new source, no
221
265
  new traced path, and no new issue.
222
266
 
@@ -226,6 +270,6 @@ If any item fails, run another round. State which items pass when you report.
226
270
 
227
271
  Report the confirmed findings, the ones with a reproduced PoC, separately from
228
272
  the suspected ones still blocked on verification, so the two are never conflated.
229
- Append a row to the audit history in `security-review-memory.md`, and ask the
273
+ Append a row to the audit history in `MEMORY.md`, and ask the
230
274
  operator which findings were false positives. Record those under "Confirmed false
231
275
  positives" so future rounds skip them.
@@ -1,5 +1,5 @@
1
1
  """The framework's typed data model.
2
2
 
3
3
  Layers communicate only through these structures. This package depends on no
4
- concrete implementation (Provider / Source / ...).
4
+ concrete implementation such as a Provider or a Source.
5
5
  """
@@ -45,7 +45,7 @@ def _to_line(value: object) -> int | None:
45
45
 
46
46
  def finding_from_dict(data: dict[str, Any]) -> Finding | None:
47
47
  """Map one loosely-typed model finding onto a Finding, or None if it has no
48
- location (invariant: every finding carries a file)."""
48
+ location, since every finding carries a file, that is the invariant."""
49
49
  if not isinstance(data, dict):
50
50
  return None
51
51
  file = str(data.get("file", "")).strip()
@@ -1,12 +1,12 @@
1
1
  """Best-effort extraction of a JSON object from model output.
2
2
 
3
3
  Models often wrap JSON in prose or code fences, and sometimes emit slightly
4
- malformed JSON (an unescaped quote, a trailing comma, a reply truncated at the
5
- token limit). This recovers the object: a direct parse, then a fenced ```json
6
- block, then the first balanced-brace span (string-aware, so braces inside string
7
- values do not throw off the count), then a json-repair fallback for malformed or
8
- truncated output. The repair step keeps a single bad character from silently
9
- dropping an entire findings list.
4
+ malformed JSON, for example an unescaped quote, a trailing comma, or a reply
5
+ truncated at the token limit. This recovers the object: a direct parse, then a
6
+ fenced ```json block, then the first balanced-brace span, which is string-aware
7
+ so braces inside string values do not throw off the count, then a json-repair
8
+ fallback for malformed or truncated output. The repair step keeps a single bad
9
+ character from silently dropping an entire findings list.
10
10
  """
11
11
 
12
12
  from __future__ import annotations
@@ -17,7 +17,7 @@ import re
17
17
  _FENCE = re.compile(r"```(?:json)?\s*(\{.*?\})\s*```", re.DOTALL)
18
18
 
19
19
  # Defensive ceiling: model output is bounded by max_tokens, but never scan an
20
- # unbounded string (the balanced-brace pass is superlinear on pathological input).
20
+ # unbounded string, the balanced-brace pass is superlinear on pathological input.
21
21
  _MAX_SCAN = 1_000_000
22
22
 
23
23
 
@@ -49,7 +49,7 @@ def extract_json_object(text: str) -> dict | None:
49
49
 
50
50
  def _first_balanced_object(text: str) -> dict | None:
51
51
  """The first complete top-level {...} span, counting braces only outside of
52
- string literals so braces inside a value (code in a description, "{x}") do not
52
+ string literals so braces inside a value, for example code in a description like "{x}", do not
53
53
  corrupt the depth count."""
54
54
  depth = 0
55
55
  start = -1
@@ -85,8 +85,8 @@ def _first_balanced_object(text: str) -> dict | None:
85
85
 
86
86
 
87
87
  def _repair(text: str) -> dict | None:
88
- """Last resort: repair malformed or truncated JSON (unescaped quotes, trailing
89
- commas, an unterminated reply). Optional dependency, a no-op if absent."""
88
+ """Last resort: repair malformed or truncated JSON such as unescaped quotes, trailing
89
+ commas, or an unterminated reply. Optional dependency, a no-op if absent."""
90
90
  try:
91
91
  from json_repair import repair_json
92
92
  except ImportError: