codejury 0.14.2__tar.gz → 0.14.3__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.2 → codejury-0.14.3}/PKG-INFO +1 -1
- {codejury-0.14.2 → codejury-0.14.3}/codejury/diff/debate.py +34 -9
- {codejury-0.14.2 → codejury-0.14.3}/codejury.egg-info/PKG-INFO +1 -1
- {codejury-0.14.2 → codejury-0.14.3}/pyproject.toml +1 -1
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_diff_debate.py +23 -0
- {codejury-0.14.2 → codejury-0.14.3}/LICENSE +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/README.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/__init__.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/cli.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/agent/full-review.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/agent/security-review-memory.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/entrypoints.yaml +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/SKILL.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/business-logic.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/code-injection.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/command-injection.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/cross-site-request-forgery.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/cross-site-scripting.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/hardcoded-secrets.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/http-response-splitting.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/improper-authentication.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/information-exposure.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/insecure-cryptography.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/insecure-deserialization.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/insecure-direct-object-reference.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/insecure-transport.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/jwt-validation.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/mass-assignment.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/missing-authorization.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/open-redirect.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/path-traversal.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/race-condition.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/replay-attack.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/server-side-request-forgery.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/server-side-template-injection.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/session-fixation.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/sql-injection.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/data/rules/xml-external-entity.md +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/diff/__init__.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/diff/debate_prompts.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/diff/engine.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/diff/findings_filter.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/diff/prompts.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/diff/rules.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/diff/runner.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/domain/__init__.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/domain/finding.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/json_parse.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/providers/__init__.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/providers/anthropic.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/providers/base.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/providers/factory.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/providers/litellm.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/providers/mock.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/providers/openai.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/providers/openai_format.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/providers/retry.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/repo/__init__.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/repo/model.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/repo/scaffold.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/report.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury/resources.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury.egg-info/SOURCES.txt +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury.egg-info/dependency_links.txt +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury.egg-info/entry_points.txt +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury.egg-info/requires.txt +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/codejury.egg-info/top_level.txt +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/setup.cfg +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_anthropic_provider.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_cli_audit.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_diff_engine.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_json_parse.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_litellm_provider.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_openai_format.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_openai_provider.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_repo_model.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_repo_scaffold.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_report.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/tests/test_retry_provider.py +0 -0
- {codejury-0.14.2 → codejury-0.14.3}/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.3
|
|
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
|
|
@@ -56,6 +56,28 @@ def _dedup(items: list[dict]) -> list[dict]:
|
|
|
56
56
|
return out
|
|
57
57
|
|
|
58
58
|
|
|
59
|
+
_DISMISS_VERDICTS = frozenset({"dismiss", "dismissed", "false_positive", "reject", "rejected"})
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _loc(d: dict) -> str:
|
|
63
|
+
line = d.get("line")
|
|
64
|
+
return f"{d.get('file')}:{line}" if line else str(d.get("file") or "")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _apply_dismissals(findings: list[dict], rebuttals: list[dict]) -> list[dict]:
|
|
68
|
+
"""Drop findings the challenger dismissed. The challenger is recall-safe (it
|
|
69
|
+
dismisses only when the diff shows a safe pattern: a parameterized query,
|
|
70
|
+
basename, an allowlist, shell=False), so honoring its dismissals is sound even
|
|
71
|
+
when the judge is unavailable."""
|
|
72
|
+
dismissed = {
|
|
73
|
+
str(r.get("target")) for r in rebuttals
|
|
74
|
+
if str(r.get("verdict", "")).strip().lower() in _DISMISS_VERDICTS
|
|
75
|
+
}
|
|
76
|
+
if not dismissed:
|
|
77
|
+
return findings
|
|
78
|
+
return [f for f in findings if _loc(f) not in dismissed and str(f.get("file") or "") not in dismissed]
|
|
79
|
+
|
|
80
|
+
|
|
59
81
|
class AdversarialAuditRunner:
|
|
60
82
|
def __init__(
|
|
61
83
|
self,
|
|
@@ -116,16 +138,19 @@ class AdversarialAuditRunner:
|
|
|
116
138
|
rebuttals = _dicts(challenger.get("rebuttals"))
|
|
117
139
|
new_findings = _dicts(challenger.get("new_findings"))
|
|
118
140
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
141
|
+
jp = judge_prompt(diff, finder_findings, rebuttals, new_findings, context=context)
|
|
142
|
+
verdict, judge_ok = self._ask(JUDGE_SYSTEM, jp, self._judge_model)
|
|
143
|
+
if not judge_ok:
|
|
144
|
+
# the judge is the filter that controls false positives, and an
|
|
145
|
+
# unusable reply is often transient (a flaky proxy, a blocked
|
|
146
|
+
# request); re-ask once before giving up on it
|
|
147
|
+
verdict, judge_ok = self._ask(JUDGE_SYSTEM, jp, self._judge_model)
|
|
124
148
|
if not judge_ok:
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
|
|
149
|
+
# judge still unusable: degrade, but apply the recall-safe
|
|
150
|
+
# challenger's dismissals so a transient judge outage does not pass
|
|
151
|
+
# through findings the challenger already showed are safe (this is
|
|
152
|
+
# what otherwise inflates false positives in degraded runs)
|
|
153
|
+
fallback = _dedup(_apply_dismissals(finder_findings, rebuttals) + new_findings)
|
|
129
154
|
judged = AdversarialResult(findings=findings_from_list(fallback), rounds=rounds, degraded=True)
|
|
130
155
|
degraded = True
|
|
131
156
|
break
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codejury
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.3
|
|
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,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "codejury"
|
|
3
|
-
version = "0.14.
|
|
3
|
+
version = "0.14.3"
|
|
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"
|
|
@@ -156,6 +156,29 @@ def test_provider_exception_degrades_rather_than_crashes():
|
|
|
156
156
|
assert out.degraded is True
|
|
157
157
|
|
|
158
158
|
|
|
159
|
+
def test_judge_retry_recovers_from_a_transient_unusable_reply():
|
|
160
|
+
# the judge's first reply is unusable, the retry succeeds: not degraded,
|
|
161
|
+
# and the judge verdict is applied normally
|
|
162
|
+
_, out = _run([_finder([_VULN]), _challenger(), "blocked by waf", _judge([_VULN])], max_rounds=1)
|
|
163
|
+
assert out.degraded is False
|
|
164
|
+
assert [f.category for f in out.findings] == ["sql_injection"]
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_degraded_fallback_drops_challenger_dismissed_findings():
|
|
168
|
+
# judge stays unusable (both the call and its retry); the degraded fallback
|
|
169
|
+
# must still honor the challenger's recall-safe dismissals rather than pass
|
|
170
|
+
# every finder finding through, which is what inflates false positives
|
|
171
|
+
second = {**_VULN, "line": 5, "category": "xss"}
|
|
172
|
+
_, out = _run(
|
|
173
|
+
[_finder([_VULN, second]),
|
|
174
|
+
_challenger(rebuttals=[{"target": "app.py:5", "verdict": "dismiss", "reason": "output is escaped"}]),
|
|
175
|
+
"blocked", "blocked"], # judge call + its one retry both unusable
|
|
176
|
+
max_rounds=1,
|
|
177
|
+
)
|
|
178
|
+
assert out.degraded is True
|
|
179
|
+
assert [f.category for f in out.findings] == ["sql_injection"] # the dismissed xss at app.py:5 is dropped
|
|
180
|
+
|
|
181
|
+
|
|
159
182
|
def test_per_role_models_are_used():
|
|
160
183
|
provider = MockProvider(responses=[_finder([]), _challenger(), _judge([])], default="{}")
|
|
161
184
|
AdversarialAuditRunner(
|
|
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
|
|
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
|