codejury 0.14.0__tar.gz → 0.14.2__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.14.0 → codejury-0.14.2}/PKG-INFO +1 -1
- {codejury-0.14.0 → codejury-0.14.2}/codejury/cli.py +10 -83
- {codejury-0.14.0 → codejury-0.14.2}/codejury/diff/debate.py +1 -1
- {codejury-0.14.0 → codejury-0.14.2}/codejury/diff/engine.py +1 -1
- codejury-0.14.2/codejury/diff/runner.py +85 -0
- {codejury-0.14.0/codejury/fullreview → codejury-0.14.2/codejury/repo}/scaffold.py +8 -7
- {codejury-0.14.0 → codejury-0.14.2}/codejury.egg-info/PKG-INFO +1 -1
- {codejury-0.14.0 → codejury-0.14.2}/codejury.egg-info/SOURCES.txt +8 -9
- {codejury-0.14.0 → codejury-0.14.2}/pyproject.toml +1 -1
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_cli_audit.py +8 -7
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_json_parse.py +1 -1
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_repo_model.py +1 -1
- codejury-0.14.0/tests/test_full_review_scaffold.py → codejury-0.14.2/tests/test_repo_scaffold.py +1 -1
- codejury-0.14.0/tests/test_diff_report.py → codejury-0.14.2/tests/test_report.py +1 -1
- codejury-0.14.0/codejury/analysis/__init__.py +0 -8
- codejury-0.14.0/codejury/infrastructure/__init__.py +0 -4
- {codejury-0.14.0 → codejury-0.14.2}/LICENSE +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/README.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/__init__.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/agent/full-review.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/agent/security-review-memory.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/entrypoints.yaml +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/SKILL.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/business-logic.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/code-injection.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/command-injection.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/cross-site-request-forgery.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/cross-site-scripting.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/hardcoded-secrets.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/http-response-splitting.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/improper-authentication.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/information-exposure.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/insecure-cryptography.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/insecure-deserialization.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/insecure-direct-object-reference.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/insecure-transport.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/jwt-validation.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/mass-assignment.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/missing-authorization.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/open-redirect.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/path-traversal.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/race-condition.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/replay-attack.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/server-side-request-forgery.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/server-side-template-injection.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/session-fixation.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/sql-injection.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/data/rules/xml-external-entity.md +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/diff/__init__.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/diff/debate_prompts.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/diff/findings_filter.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/diff/prompts.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/diff/rules.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/domain/__init__.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/domain/finding.py +0 -0
- {codejury-0.14.0/codejury/infrastructure → codejury-0.14.2/codejury}/json_parse.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/providers/__init__.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/providers/anthropic.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/providers/base.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/providers/factory.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/providers/litellm.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/providers/mock.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/providers/openai.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/providers/openai_format.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/providers/retry.py +0 -0
- {codejury-0.14.0/codejury/fullreview → codejury-0.14.2/codejury/repo}/__init__.py +0 -0
- /codejury-0.14.0/codejury/analysis/repo_model.py → /codejury-0.14.2/codejury/repo/model.py +0 -0
- {codejury-0.14.0/codejury/diff → codejury-0.14.2/codejury}/report.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury/resources.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury.egg-info/dependency_links.txt +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury.egg-info/entry_points.txt +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury.egg-info/requires.txt +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/codejury.egg-info/top_level.txt +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/setup.cfg +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_anthropic_provider.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_diff_debate.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_diff_engine.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_litellm_provider.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_openai_format.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_openai_provider.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_retry_provider.py +0 -0
- {codejury-0.14.0 → codejury-0.14.2}/tests/test_rules.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codejury
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.2
|
|
4
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
|
|
5
5
|
Author: AISecLabs
|
|
6
6
|
License-Expression: MIT
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
"""codejury CLI.
|
|
1
|
+
"""codejury CLI: thin argument parsing and dispatch.
|
|
2
2
|
|
|
3
|
-
Two
|
|
3
|
+
Two paths matched to their nature:
|
|
4
4
|
|
|
5
|
-
- ``
|
|
6
|
-
call (standard) or the adversarial Finder/Challenger/Judge pass.
|
|
7
|
-
- ``
|
|
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.
|
|
7
|
+
- ``review repo`` 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
|
-
``dry-run`` exercises the
|
|
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
13
|
"""
|
|
13
14
|
|
|
14
15
|
from __future__ import annotations
|
|
@@ -17,20 +18,9 @@ import argparse
|
|
|
17
18
|
import subprocess
|
|
18
19
|
import sys
|
|
19
20
|
|
|
20
|
-
import dataclasses
|
|
21
|
-
|
|
22
21
|
from codejury import __version__
|
|
23
|
-
from codejury.
|
|
24
|
-
from codejury.diff.
|
|
25
|
-
from codejury.diff.findings_filter import FindingsFilter
|
|
26
|
-
from codejury.diff.report import gate, render
|
|
27
|
-
from codejury.diff.rules import allowed_categories, normalize_category
|
|
28
|
-
from codejury.domain.finding import Finding
|
|
29
|
-
|
|
30
|
-
# A diff larger than this is audited file-by-file so a big PR does not overflow
|
|
31
|
-
# the model's context and silently truncate the reply.
|
|
32
|
-
_MAX_DIFF_CHARS = 60_000
|
|
33
|
-
from codejury.fullreview.scaffold import scaffold
|
|
22
|
+
from codejury.report import gate, render
|
|
23
|
+
from codejury.diff.runner import audit_diff
|
|
34
24
|
from codejury.providers.factory import (
|
|
35
25
|
DEFAULT_API_BASE,
|
|
36
26
|
DEFAULT_API_KEY,
|
|
@@ -42,75 +32,12 @@ from codejury.providers.factory import (
|
|
|
42
32
|
make_provider,
|
|
43
33
|
)
|
|
44
34
|
from codejury.providers.mock import MockProvider
|
|
35
|
+
from codejury.repo.scaffold import scaffold
|
|
45
36
|
|
|
46
37
|
_FORMATS = ("text", "markdown", "json", "sarif")
|
|
47
38
|
_FAIL_ON = ("critical", "high", "medium", "low")
|
|
48
39
|
|
|
49
40
|
|
|
50
|
-
def _split_diff_by_file(diff: str) -> list[str]:
|
|
51
|
-
"""Split a unified diff into one diff per file (`diff --git ...` boundaries)."""
|
|
52
|
-
chunks: list[str] = []
|
|
53
|
-
cur: list[str] = []
|
|
54
|
-
for line in diff.splitlines(keepends=True):
|
|
55
|
-
if line.startswith("diff --git ") and cur:
|
|
56
|
-
chunks.append("".join(cur))
|
|
57
|
-
cur = []
|
|
58
|
-
cur.append(line)
|
|
59
|
-
if cur:
|
|
60
|
-
chunks.append("".join(cur))
|
|
61
|
-
return chunks or ([diff] if diff.strip() else [])
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def _dedup_findings(findings: list[Finding]) -> list[Finding]:
|
|
65
|
-
seen: set = set()
|
|
66
|
-
out: list[Finding] = []
|
|
67
|
-
for f in findings:
|
|
68
|
-
k = (f.file, f.line, f.category, f.description)
|
|
69
|
-
if k not in seen:
|
|
70
|
-
seen.add(k)
|
|
71
|
-
out.append(f)
|
|
72
|
-
return out
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def audit_diff(
|
|
76
|
-
diff: str,
|
|
77
|
-
*,
|
|
78
|
-
provider,
|
|
79
|
-
model: str,
|
|
80
|
-
mode: str = "standard",
|
|
81
|
-
max_rounds: int = 3,
|
|
82
|
-
filter_findings: bool = True,
|
|
83
|
-
finder_model: str | None = None,
|
|
84
|
-
challenger_model: str | None = None,
|
|
85
|
-
judge_model: str | None = None,
|
|
86
|
-
exclude_paths: tuple[str, ...] = (),
|
|
87
|
-
) -> tuple[list[Finding], list[tuple[Finding, str]]]:
|
|
88
|
-
"""Audit a diff and return (kept findings, dropped (finding, reason)).
|
|
89
|
-
|
|
90
|
-
A diff over the size budget is audited one file at a time so it does not
|
|
91
|
-
overflow the context. Finding categories are normalized to the rule-id set.
|
|
92
|
-
``exclude_paths`` are operator-supplied path substrings to drop."""
|
|
93
|
-
def _run_one(d: str) -> list[Finding]:
|
|
94
|
-
if mode == "adversarial":
|
|
95
|
-
return AdversarialAuditRunner(
|
|
96
|
-
provider=provider, model=model,
|
|
97
|
-
finder_model=finder_model, challenger_model=challenger_model, judge_model=judge_model,
|
|
98
|
-
).run(d, max_rounds=max_rounds).findings
|
|
99
|
-
return AuditRunner(provider=provider, model=model).run(d)
|
|
100
|
-
|
|
101
|
-
if len(diff) > _MAX_DIFF_CHARS:
|
|
102
|
-
chunks = _split_diff_by_file(diff)
|
|
103
|
-
findings = _dedup_findings([f for c in chunks for f in _run_one(c)])
|
|
104
|
-
else:
|
|
105
|
-
findings = _run_one(diff)
|
|
106
|
-
|
|
107
|
-
allowed = set(allowed_categories())
|
|
108
|
-
findings = [dataclasses.replace(f, category=normalize_category(f.category, allowed)) for f in findings]
|
|
109
|
-
if filter_findings:
|
|
110
|
-
return FindingsFilter(exclude_paths=exclude_paths).filter(findings)
|
|
111
|
-
return findings, []
|
|
112
|
-
|
|
113
|
-
|
|
114
41
|
def _read_diff(args) -> str:
|
|
115
42
|
if args.diff_file:
|
|
116
43
|
with open(args.diff_file, encoding="utf-8") as f:
|
|
@@ -21,7 +21,7 @@ from codejury.diff.debate_prompts import (
|
|
|
21
21
|
)
|
|
22
22
|
from codejury.diff.rules import rules_for_diff
|
|
23
23
|
from codejury.domain.finding import Finding, findings_from_list
|
|
24
|
-
from codejury.
|
|
24
|
+
from codejury.json_parse import extract_json_object
|
|
25
25
|
from codejury.providers.base import Message, Provider
|
|
26
26
|
|
|
27
27
|
|
|
@@ -10,7 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
from codejury.domain.finding import Finding, findings_from_list
|
|
11
11
|
from codejury.diff.prompts import SYSTEM, standard_audit_prompt
|
|
12
12
|
from codejury.diff.rules import rules_for_diff
|
|
13
|
-
from codejury.
|
|
13
|
+
from codejury.json_parse import extract_json_object
|
|
14
14
|
from codejury.providers.base import Message, Provider
|
|
15
15
|
|
|
16
16
|
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Diff-audit orchestration: run a diff through the engine and clean the result.
|
|
2
|
+
|
|
3
|
+
The library entry point behind `review diff`. Picks the standard or adversarial
|
|
4
|
+
engine, audits a large diff one file at a time so a big PR does not overflow the
|
|
5
|
+
model context, normalizes finding categories onto the rule-id set, and applies
|
|
6
|
+
the false-positive filter. Kept out of the CLI so it can be called as a library.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import dataclasses
|
|
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.rules import allowed_categories, normalize_category
|
|
17
|
+
from codejury.domain.finding import Finding
|
|
18
|
+
|
|
19
|
+
# A diff larger than this is audited file-by-file so a big PR does not overflow
|
|
20
|
+
# the model's context and silently truncate the reply.
|
|
21
|
+
_MAX_DIFF_CHARS = 60_000
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def split_diff_by_file(diff: str) -> list[str]:
|
|
25
|
+
"""Split a unified diff into one diff per file (`diff --git ...` boundaries)."""
|
|
26
|
+
chunks: list[str] = []
|
|
27
|
+
cur: list[str] = []
|
|
28
|
+
for line in diff.splitlines(keepends=True):
|
|
29
|
+
if line.startswith("diff --git ") and cur:
|
|
30
|
+
chunks.append("".join(cur))
|
|
31
|
+
cur = []
|
|
32
|
+
cur.append(line)
|
|
33
|
+
if cur:
|
|
34
|
+
chunks.append("".join(cur))
|
|
35
|
+
return chunks or ([diff] if diff.strip() else [])
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def dedup_findings(findings: list[Finding]) -> list[Finding]:
|
|
39
|
+
seen: set = set()
|
|
40
|
+
out: list[Finding] = []
|
|
41
|
+
for f in findings:
|
|
42
|
+
k = (f.file, f.line, f.category, f.description)
|
|
43
|
+
if k not in seen:
|
|
44
|
+
seen.add(k)
|
|
45
|
+
out.append(f)
|
|
46
|
+
return out
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def audit_diff(
|
|
50
|
+
diff: str,
|
|
51
|
+
*,
|
|
52
|
+
provider,
|
|
53
|
+
model: str,
|
|
54
|
+
mode: str = "standard",
|
|
55
|
+
max_rounds: int = 3,
|
|
56
|
+
filter_findings: bool = True,
|
|
57
|
+
finder_model: str | None = None,
|
|
58
|
+
challenger_model: str | None = None,
|
|
59
|
+
judge_model: str | None = None,
|
|
60
|
+
exclude_paths: tuple[str, ...] = (),
|
|
61
|
+
) -> tuple[list[Finding], list[tuple[Finding, str]]]:
|
|
62
|
+
"""Audit a diff and return (kept findings, dropped (finding, reason)).
|
|
63
|
+
|
|
64
|
+
A diff over the size budget is audited one file at a time so it does not
|
|
65
|
+
overflow the context. Finding categories are normalized to the rule-id set.
|
|
66
|
+
``exclude_paths`` are operator-supplied path substrings to drop."""
|
|
67
|
+
def _run_one(d: str) -> list[Finding]:
|
|
68
|
+
if mode == "adversarial":
|
|
69
|
+
return AdversarialAuditRunner(
|
|
70
|
+
provider=provider, model=model,
|
|
71
|
+
finder_model=finder_model, challenger_model=challenger_model, judge_model=judge_model,
|
|
72
|
+
).run(d, max_rounds=max_rounds).findings
|
|
73
|
+
return AuditRunner(provider=provider, model=model).run(d)
|
|
74
|
+
|
|
75
|
+
if len(diff) > _MAX_DIFF_CHARS:
|
|
76
|
+
chunks = split_diff_by_file(diff)
|
|
77
|
+
findings = dedup_findings([f for c in chunks for f in _run_one(c)])
|
|
78
|
+
else:
|
|
79
|
+
findings = _run_one(diff)
|
|
80
|
+
|
|
81
|
+
allowed = set(allowed_categories())
|
|
82
|
+
findings = [dataclasses.replace(f, category=normalize_category(f.category, allowed)) for f in findings]
|
|
83
|
+
if filter_findings:
|
|
84
|
+
return FindingsFilter(exclude_paths=exclude_paths).filter(findings)
|
|
85
|
+
return findings, []
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Whole-repo review scaffold: set up the agent's workspace, do not run a pipeline.
|
|
2
2
|
|
|
3
|
-
Whole-repo review is too large for a single LLM call, so
|
|
4
|
-
as a pipeline. Instead it scaffolds a workspace for an
|
|
5
|
-
Code, Codex) and hands over the methodology: it creates
|
|
6
|
-
directories, copies the review-memory template, seeds the
|
|
7
|
-
deterministic RepoModel scan, and returns the methodology
|
|
3
|
+
The `review repo` path. Whole-repo review is too large for a single LLM call, so
|
|
4
|
+
codejury does not run it as a pipeline. Instead it scaffolds a workspace for an
|
|
5
|
+
interactive agent (Claude Code, Codex) and hands over the methodology: it creates
|
|
6
|
+
the api/issues/analysis directories, copies the review-memory template, seeds the
|
|
7
|
+
API inventory from a deterministic RepoModel scan, and returns the methodology
|
|
8
|
+
text to print.
|
|
8
9
|
"""
|
|
9
10
|
|
|
10
11
|
from __future__ import annotations
|
|
@@ -12,7 +13,7 @@ from __future__ import annotations
|
|
|
12
13
|
from dataclasses import dataclass, field
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
|
|
15
|
-
from codejury.
|
|
16
|
+
from codejury.repo.model import build_repo_model_from_dir
|
|
16
17
|
from codejury.resources import AGENT_DIR
|
|
17
18
|
|
|
18
19
|
_METHODOLOGY = AGENT_DIR / "full-review.md"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codejury
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.2
|
|
4
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
|
|
5
5
|
Author: AISecLabs
|
|
6
6
|
License-Expression: MIT
|
|
@@ -3,6 +3,8 @@ README.md
|
|
|
3
3
|
pyproject.toml
|
|
4
4
|
codejury/__init__.py
|
|
5
5
|
codejury/cli.py
|
|
6
|
+
codejury/json_parse.py
|
|
7
|
+
codejury/report.py
|
|
6
8
|
codejury/resources.py
|
|
7
9
|
codejury.egg-info/PKG-INFO
|
|
8
10
|
codejury.egg-info/SOURCES.txt
|
|
@@ -10,8 +12,6 @@ codejury.egg-info/dependency_links.txt
|
|
|
10
12
|
codejury.egg-info/entry_points.txt
|
|
11
13
|
codejury.egg-info/requires.txt
|
|
12
14
|
codejury.egg-info/top_level.txt
|
|
13
|
-
codejury/analysis/__init__.py
|
|
14
|
-
codejury/analysis/repo_model.py
|
|
15
15
|
codejury/data/entrypoints.yaml
|
|
16
16
|
codejury/data/agent/full-review.md
|
|
17
17
|
codejury/data/agent/security-review-memory.md
|
|
@@ -47,14 +47,10 @@ codejury/diff/debate_prompts.py
|
|
|
47
47
|
codejury/diff/engine.py
|
|
48
48
|
codejury/diff/findings_filter.py
|
|
49
49
|
codejury/diff/prompts.py
|
|
50
|
-
codejury/diff/report.py
|
|
51
50
|
codejury/diff/rules.py
|
|
51
|
+
codejury/diff/runner.py
|
|
52
52
|
codejury/domain/__init__.py
|
|
53
53
|
codejury/domain/finding.py
|
|
54
|
-
codejury/fullreview/__init__.py
|
|
55
|
-
codejury/fullreview/scaffold.py
|
|
56
|
-
codejury/infrastructure/__init__.py
|
|
57
|
-
codejury/infrastructure/json_parse.py
|
|
58
54
|
codejury/providers/__init__.py
|
|
59
55
|
codejury/providers/anthropic.py
|
|
60
56
|
codejury/providers/base.py
|
|
@@ -64,16 +60,19 @@ codejury/providers/mock.py
|
|
|
64
60
|
codejury/providers/openai.py
|
|
65
61
|
codejury/providers/openai_format.py
|
|
66
62
|
codejury/providers/retry.py
|
|
63
|
+
codejury/repo/__init__.py
|
|
64
|
+
codejury/repo/model.py
|
|
65
|
+
codejury/repo/scaffold.py
|
|
67
66
|
tests/test_anthropic_provider.py
|
|
68
67
|
tests/test_cli_audit.py
|
|
69
68
|
tests/test_diff_debate.py
|
|
70
69
|
tests/test_diff_engine.py
|
|
71
|
-
tests/test_diff_report.py
|
|
72
|
-
tests/test_full_review_scaffold.py
|
|
73
70
|
tests/test_json_parse.py
|
|
74
71
|
tests/test_litellm_provider.py
|
|
75
72
|
tests/test_openai_format.py
|
|
76
73
|
tests/test_openai_provider.py
|
|
77
74
|
tests/test_repo_model.py
|
|
75
|
+
tests/test_repo_scaffold.py
|
|
76
|
+
tests/test_report.py
|
|
78
77
|
tests/test_retry_provider.py
|
|
79
78
|
tests/test_rules.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "codejury"
|
|
3
|
-
version = "0.14.
|
|
3
|
+
version = "0.14.2"
|
|
4
4
|
description = "AI code security review: an adversarial diff-audit engine and an agent-driven whole-repo review methodology, with security knowledge as rich rules"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Diff-audit orchestration (codejury.diff.runner) plus the thin CLI surface.
|
|
2
2
|
|
|
3
3
|
A diff over the size budget is split per file and audited one file at a time so a
|
|
4
4
|
big PR does not overflow the model context and silently truncate the reply; the
|
|
@@ -7,7 +7,8 @@ per-file findings are then de-duplicated.
|
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
9
|
|
|
10
|
-
from codejury.cli import
|
|
10
|
+
from codejury.cli import main
|
|
11
|
+
from codejury.diff.runner import audit_diff, dedup_findings, split_diff_by_file
|
|
11
12
|
from codejury.domain.finding import Finding
|
|
12
13
|
from codejury.providers.mock import MockProvider
|
|
13
14
|
|
|
@@ -16,14 +17,14 @@ _FILE_B = "diff --git a/b.py b/b.py\n@@ -0,0 +1 @@\n+y = 2\n"
|
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def test_split_diff_by_file():
|
|
19
|
-
chunks =
|
|
20
|
+
chunks = split_diff_by_file(_FILE_A + _FILE_B)
|
|
20
21
|
assert chunks == [_FILE_A, _FILE_B]
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
def test_split_diff_empty_and_unbounded():
|
|
24
|
-
assert
|
|
25
|
+
assert split_diff_by_file("") == []
|
|
25
26
|
# a fragment with no `diff --git` boundary is returned as one chunk
|
|
26
|
-
assert
|
|
27
|
+
assert split_diff_by_file("just text\n") == ["just text\n"]
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
def test_dedup_findings_collapses_identical():
|
|
@@ -31,12 +32,12 @@ def test_dedup_findings_collapses_identical():
|
|
|
31
32
|
description="d", confidence=0.9)
|
|
32
33
|
g = Finding(file="a.py", line=2, severity="HIGH", category="sql-injection",
|
|
33
34
|
description="d", confidence=0.9)
|
|
34
|
-
assert
|
|
35
|
+
assert dedup_findings([f, f, g]) == [f, g]
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
def test_large_diff_is_audited_per_file(monkeypatch):
|
|
38
39
|
# force the chunking path on a small diff
|
|
39
|
-
monkeypatch.setattr("codejury.
|
|
40
|
+
monkeypatch.setattr("codejury.diff.runner._MAX_DIFF_CHARS", 1)
|
|
40
41
|
resp = ('{"findings": [{"file": "a.py", "line": 1, "severity": "HIGH", '
|
|
41
42
|
'"category": "sql_injection", "description": "x", "confidence": 0.9}]}')
|
|
42
43
|
provider = MockProvider(default=resp)
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"""Static analysis for provenance (P1).
|
|
2
|
-
|
|
3
|
-
The code-graph / data-flow engine that gives the verifier provenance: whether a
|
|
4
|
-
value reaching a sink is attacker-controlled, sanitized, or a trusted constant.
|
|
5
|
-
It targets the taint precision floor that single-file LLM review cannot reach,
|
|
6
|
-
see ROADMAP P1. Python AST based, currently intra-procedural plus a one-hop
|
|
7
|
-
cross-file caller resolution, not yet a full code graph.
|
|
8
|
-
"""
|
|
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
|
|
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
|