codejury 0.22.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.
- {codejury-0.22.0 → codejury-0.23.0}/PKG-INFO +1 -1
- {codejury-0.22.0 → codejury-0.23.0}/codejury/cli.py +9 -2
- codejury-0.23.0/codejury/data/commands/codejury-review-repo.md +42 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/methodologies/repo-review.md +44 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/repo/scaffold.py +44 -1
- {codejury-0.22.0 → codejury-0.23.0}/codejury.egg-info/PKG-INFO +1 -1
- {codejury-0.22.0 → codejury-0.23.0}/pyproject.toml +1 -1
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_repo_scaffold.py +30 -0
- codejury-0.22.0/codejury/data/commands/codejury-review-repo.md +0 -29
- {codejury-0.22.0 → codejury-0.23.0}/LICENSE +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/README.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/__init__.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/__main__.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/detection.yaml +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/frameworks/go/echo.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/frameworks/go/gin.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/frameworks/javascript/express.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/frameworks/javascript/nestjs.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/frameworks/python/celery.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/frameworks/python/django.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/frameworks/python/fastapi.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/frameworks/python/flask.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/languages/go.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/languages/javascript.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/languages/python.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/languages/typescript.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/methodologies/memory-template.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/protocols/oauth.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/SKILL.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/business-logic.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/code-injection.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/command-injection.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/cross-site-request-forgery.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/cross-site-scripting.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/hardcoded-secrets.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/http-response-splitting.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/improper-authentication.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/information-exposure.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/insecure-cryptography.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/insecure-deserialization.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/insecure-direct-object-reference.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/insecure-transport.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/jwt-validation.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/mass-assignment.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/missing-authorization.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/open-redirect.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/path-traversal.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/race-condition.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/replay-attack.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/server-side-request-forgery.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/server-side-template-injection.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/session-fixation.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/sql-injection.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/xml-external-entity.md +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/detection.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/domain/__init__.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/domain/finding.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/guides.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/json_parse.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/mddoc.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/providers/__init__.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/providers/anthropic.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/providers/base.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/providers/factory.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/providers/litellm.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/providers/mock.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/providers/openai.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/providers/openai_format.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/providers/retry.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/report.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/resources.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/__init__.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/diff/__init__.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/diff/debate.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/diff/debate_prompts.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/diff/engine.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/diff/findings_filter.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/diff/prompts.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/diff/runner.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/diff/vulnerabilities.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/repo/__init__.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury/review/repo/model.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury.egg-info/SOURCES.txt +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury.egg-info/dependency_links.txt +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury.egg-info/entry_points.txt +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury.egg-info/requires.txt +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/codejury.egg-info/top_level.txt +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/setup.cfg +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_anthropic_provider.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_cli_audit.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_detection.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_diff_debate.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_diff_engine.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_guides.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_json_parse.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_litellm_provider.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_mddoc.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_openai_format.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_openai_provider.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_repo_model.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_report.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_retry_provider.py +0 -0
- {codejury-0.22.0 → codejury-0.23.0}/tests/test_vulnerabilities.py +0 -0
|
@@ -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/`.
|
|
@@ -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
|
|
|
@@ -10,6 +10,7 @@ the methodology text to print.
|
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
+
import shutil
|
|
13
14
|
from dataclasses import dataclass, field
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
|
|
@@ -41,6 +42,8 @@ class ScaffoldResult:
|
|
|
41
42
|
trace_targets: tuple[str, ...] = () # downstream logic-layer files to trace into
|
|
42
43
|
guides: tuple[str, ...] = ()
|
|
43
44
|
created: list[str] = field(default_factory=list)
|
|
45
|
+
had_prior_run: bool = False # the workspace already held a previous review's output
|
|
46
|
+
cleared: list[str] = field(default_factory=list) # paths removed by a fresh run, MEMORY.md included
|
|
44
47
|
|
|
45
48
|
|
|
46
49
|
def _read_manifests(target: Path) -> str:
|
|
@@ -146,10 +149,48 @@ clean one.
|
|
|
146
149
|
"""
|
|
147
150
|
|
|
148
151
|
|
|
149
|
-
def
|
|
152
|
+
def _has_prior_run(ws: Path) -> bool:
|
|
153
|
+
"""True when the workspace already holds a previous review's output, not just
|
|
154
|
+
a bare scaffold. Findings, PoCs, a logged round ledger, or a hand-built
|
|
155
|
+
entrypoint inventory all count. The regenerated seeds alone do not."""
|
|
156
|
+
if not ws.exists():
|
|
157
|
+
return False
|
|
158
|
+
for sub in ("issues", "pocs"):
|
|
159
|
+
d = ws / sub
|
|
160
|
+
if d.is_dir() and any(d.iterdir()):
|
|
161
|
+
return True
|
|
162
|
+
rounds = ws / "analysis" / "_rounds.md"
|
|
163
|
+
if rounds.exists() and rounds.read_text(encoding="utf-8") != _ROUNDS_TEMPLATE:
|
|
164
|
+
return True
|
|
165
|
+
inv = ws / "entrypoints"
|
|
166
|
+
if inv.is_dir() and any(p.name != "_entrypoints.md" for p in inv.iterdir()):
|
|
167
|
+
return True
|
|
168
|
+
return False
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _clear_prior_run(ws: Path) -> list[str]:
|
|
172
|
+
"""Remove a previous review's output so a fresh run starts clean. This wipes
|
|
173
|
+
MEMORY.md too, so the cross-run memory of confirmed false positives and fixed
|
|
174
|
+
issues is reset, the run starts from a blank slate with no stale judgments
|
|
175
|
+
suppressing a finding."""
|
|
176
|
+
removed: list[str] = []
|
|
177
|
+
for child in ws.iterdir():
|
|
178
|
+
if child.is_dir():
|
|
179
|
+
shutil.rmtree(child)
|
|
180
|
+
else:
|
|
181
|
+
child.unlink()
|
|
182
|
+
removed.append(str(child))
|
|
183
|
+
return removed
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def scaffold(target: str | Path, workspace: str | Path, *, fresh: bool = False) -> ScaffoldResult:
|
|
150
187
|
target = Path(target).resolve()
|
|
151
188
|
project = target.name
|
|
152
189
|
ws = Path(workspace) / project
|
|
190
|
+
had_prior_run = _has_prior_run(ws)
|
|
191
|
+
cleared: list[str] = []
|
|
192
|
+
if fresh and ws.exists():
|
|
193
|
+
cleared = _clear_prior_run(ws)
|
|
153
194
|
created: list[str] = []
|
|
154
195
|
for sub in ("entrypoints", "issues", "pocs", "analysis"):
|
|
155
196
|
d = ws / sub
|
|
@@ -201,4 +242,6 @@ def scaffold(target: str | Path, workspace: str | Path) -> ScaffoldResult:
|
|
|
201
242
|
trace_targets=tuple(layers),
|
|
202
243
|
guides=tuple(g.id for g in guides),
|
|
203
244
|
created=created,
|
|
245
|
+
had_prior_run=had_prior_run,
|
|
246
|
+
cleared=cleared,
|
|
204
247
|
)
|
|
@@ -136,6 +136,36 @@ def test_scaffold_does_not_clobber_existing_memory(tmp_path):
|
|
|
136
136
|
assert str(second.memory_path) not in second.created # not recreated
|
|
137
137
|
|
|
138
138
|
|
|
139
|
+
def test_scaffold_flags_a_prior_run(tmp_path):
|
|
140
|
+
target = _target(tmp_path)
|
|
141
|
+
ws_root = tmp_path / "work"
|
|
142
|
+
first = scaffold(target, ws_root)
|
|
143
|
+
assert first.had_prior_run is False # a bare first scaffold is not a prior run
|
|
144
|
+
|
|
145
|
+
(first.workspace / "issues" / "found.md").write_text("# a finding\n")
|
|
146
|
+
second = scaffold(target, ws_root)
|
|
147
|
+
assert second.had_prior_run is True
|
|
148
|
+
assert second.cleared == [] # not cleared without fresh
|
|
149
|
+
assert (second.workspace / "issues" / "found.md").is_file() # left intact
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def test_scaffold_fresh_clears_prior_output_including_memory(tmp_path):
|
|
153
|
+
target = _target(tmp_path)
|
|
154
|
+
ws_root = tmp_path / "work"
|
|
155
|
+
first = scaffold(target, ws_root)
|
|
156
|
+
(first.workspace / "issues" / "found.md").write_text("# a finding\n")
|
|
157
|
+
(first.workspace / "pocs" / "found.py").write_text("print('poc')\n")
|
|
158
|
+
first.memory_path.write_text("# edited memory\nFP-001 ...\n")
|
|
159
|
+
|
|
160
|
+
fresh = scaffold(target, ws_root, fresh=True)
|
|
161
|
+
assert fresh.had_prior_run is True
|
|
162
|
+
assert fresh.cleared # something was removed
|
|
163
|
+
assert not (fresh.workspace / "issues" / "found.md").exists() # stale finding gone
|
|
164
|
+
assert not (fresh.workspace / "pocs" / "found.py").exists()
|
|
165
|
+
assert "# edited memory" not in fresh.memory_path.read_text() # MEMORY.md reset to template
|
|
166
|
+
assert (fresh.workspace / "entrypoints" / "_entrypoints.md").is_file() # reseeded
|
|
167
|
+
|
|
168
|
+
|
|
139
169
|
def test_plain_repo_still_scaffolds(tmp_path):
|
|
140
170
|
d = tmp_path / "plain"
|
|
141
171
|
d.mkdir()
|
|
@@ -1,29 +0,0 @@
|
|
|
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 /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/`.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/cross-site-request-forgery.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/http-response-splitting.md
RENAMED
|
File without changes
|
{codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/improper-authentication.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/insecure-deserialization.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/server-side-request-forgery.md
RENAMED
|
File without changes
|
{codejury-0.22.0 → codejury-0.23.0}/codejury/data/vulnerabilities/server-side-template-injection.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|