codejury 0.14.3__tar.gz → 0.14.5__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.3 → codejury-0.14.5}/PKG-INFO +1 -1
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/agent/full-review.md +46 -12
- {codejury-0.14.3 → codejury-0.14.5}/codejury/repo/model.py +4 -1
- {codejury-0.14.3 → codejury-0.14.5}/codejury.egg-info/PKG-INFO +1 -1
- {codejury-0.14.3 → codejury-0.14.5}/pyproject.toml +1 -1
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_repo_model.py +21 -0
- {codejury-0.14.3 → codejury-0.14.5}/LICENSE +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/README.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/__init__.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/cli.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/agent/security-review-memory.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/entrypoints.yaml +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/SKILL.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/business-logic.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/code-injection.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/command-injection.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/cross-site-request-forgery.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/cross-site-scripting.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/hardcoded-secrets.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/http-response-splitting.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/improper-authentication.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/information-exposure.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/insecure-cryptography.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/insecure-deserialization.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/insecure-direct-object-reference.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/insecure-transport.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/jwt-validation.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/mass-assignment.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/missing-authorization.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/open-redirect.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/path-traversal.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/race-condition.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/replay-attack.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/server-side-request-forgery.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/server-side-template-injection.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/session-fixation.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/sql-injection.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/data/rules/xml-external-entity.md +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/diff/__init__.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/diff/debate.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/diff/debate_prompts.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/diff/engine.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/diff/findings_filter.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/diff/prompts.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/diff/rules.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/diff/runner.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/domain/__init__.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/domain/finding.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/json_parse.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/providers/__init__.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/providers/anthropic.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/providers/base.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/providers/factory.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/providers/litellm.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/providers/mock.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/providers/openai.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/providers/openai_format.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/providers/retry.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/repo/__init__.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/repo/scaffold.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/report.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury/resources.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury.egg-info/SOURCES.txt +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury.egg-info/dependency_links.txt +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury.egg-info/entry_points.txt +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury.egg-info/requires.txt +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/codejury.egg-info/top_level.txt +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/setup.cfg +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_anthropic_provider.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_cli_audit.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_diff_debate.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_diff_engine.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_json_parse.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_litellm_provider.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_openai_format.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_openai_provider.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_repo_scaffold.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_report.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/tests/test_retry_provider.py +0 -0
- {codejury-0.14.3 → codejury-0.14.5}/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.5
|
|
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,8 +1,8 @@
|
|
|
1
1
|
# Full Security Review — Agent Methodology
|
|
2
2
|
|
|
3
3
|
A whole-repository security audit, run by an interactive coding agent (Claude
|
|
4
|
-
Code, Codex, etc.), not a one-shot LLM call. It
|
|
5
|
-
|
|
4
|
+
Code, Codex, etc.), not a one-shot LLM call. It maps the attack surface, traces
|
|
5
|
+
inputs to sinks across files, verifies issues with a real PoC, and
|
|
6
6
|
iterates over multiple rounds with a persistent memory. One round is roughly
|
|
7
7
|
30 minutes; run as many rounds as needed.
|
|
8
8
|
|
|
@@ -18,15 +18,34 @@ Workspace: `<workspace>/<project>/` (created for you), holding `api/`,
|
|
|
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.
|
|
21
|
-
2. Read `api/_entrypoints.md` (seeded for you from a deterministic scan) as
|
|
22
|
-
starting map of HTTP routes and CLI commands
|
|
21
|
+
2. Read `api/_entrypoints.md` (seeded for you from a deterministic AST scan) as a
|
|
22
|
+
*starting* map of the attack surface. It lists HTTP routes and CLI commands
|
|
23
|
+
only, so it is a subset, not the whole surface (see "Map the attack surface").
|
|
23
24
|
3. Read the relevant rule files under the shipped `rules/` for the target's stack
|
|
24
25
|
(sql-injection, idor, ssrf, authentication-jwt, insecure-deserialization, ...).
|
|
25
26
|
|
|
26
|
-
##
|
|
27
|
+
## Map the attack surface
|
|
28
|
+
|
|
29
|
+
The seeded inventory lists HTTP routes and CLI commands only. Before analysing,
|
|
30
|
+
complete the surface: untrusted input enters at more than HTTP. Enumerate every
|
|
31
|
+
source the attacker can influence and add it to `api/`:
|
|
32
|
+
|
|
33
|
+
- HTTP routes, GraphQL resolvers, gRPC / RPC handlers, WebSocket handlers;
|
|
34
|
+
- CLI commands, scheduled jobs / cron, queue and topic consumers, webhooks and
|
|
35
|
+
third-party callbacks;
|
|
36
|
+
- deserialization points (pickle, yaml.load, marshal), file and document parsers
|
|
37
|
+
(XML / XXE, YAML, CSV, zip, image / office), template rendering of user input;
|
|
38
|
+
- file uploads, archive extraction, and any filesystem path built from user input;
|
|
39
|
+
- headers, cookies, environment, and config read as trusted, and inbound
|
|
40
|
+
inter-service calls.
|
|
41
|
+
|
|
42
|
+
`pickle.loads(cookie)` and `yaml.load(upload)` are entrypoints just as much as a
|
|
43
|
+
route is. Record the inventory in `api/` (one file per module: source + auth
|
|
44
|
+
method + review status ✅/⚠️/❌).
|
|
27
45
|
|
|
28
|
-
|
|
29
|
-
|
|
46
|
+
## Analyse each source
|
|
47
|
+
|
|
48
|
+
Read the implementation reachable from each source. For every one ask:
|
|
30
49
|
|
|
31
50
|
- What inputs can the attacker control?
|
|
32
51
|
- Is authentication, authorization, signature verification, tenant isolation, or
|
|
@@ -38,9 +57,24 @@ endpoint ask:
|
|
|
38
57
|
- Mass assignment: is a user-controlled body bound wholesale into a model?
|
|
39
58
|
- Signature: is a caller-supplied key trusted as the trust anchor?
|
|
40
59
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
## Trace attack paths (the core work)
|
|
61
|
+
|
|
62
|
+
A whole-repo review earns its keep by reasoning *across files*: a flaw is usually
|
|
63
|
+
a source in one file reaching a dangerous sink in another, past a control defined
|
|
64
|
+
in a third (a route that trusts a helper which skips signature checks; an id that
|
|
65
|
+
reaches a query with no ownership check). For each promising source, trace the
|
|
66
|
+
path and record it in `analysis/`:
|
|
67
|
+
|
|
68
|
+
- **Source**: the entrypoint and the attacker-controlled value.
|
|
69
|
+
- **Sink**: the dangerous operation it reaches (query, shell, file path, fetch,
|
|
70
|
+
deserialize, template, redirect), with `file:line`.
|
|
71
|
+
- **Controls on the path**: every auth / authz / validation / sanitization /
|
|
72
|
+
signature / tenant check between source and sink, and crucially which are
|
|
73
|
+
missing or bypassable.
|
|
74
|
+
|
|
75
|
+
The vulnerability is a path with a reachable sink and no adequate control. Record
|
|
76
|
+
the system's trust boundaries and auth/authz model in `analysis/` once, so every
|
|
77
|
+
trace can refer to it instead of restating it.
|
|
44
78
|
|
|
45
79
|
## Scope
|
|
46
80
|
|
|
@@ -59,7 +93,7 @@ confirm with high confidence. Each must have:
|
|
|
59
93
|
|
|
60
94
|
- Risk: HIGH | CRITICAL
|
|
61
95
|
- Type: IDOR | auth bypass | signature flaw | business logic | ...
|
|
62
|
-
-
|
|
96
|
+
- Source: `<METHOD> <path>` or the non-HTTP entrypoint (queue, deserializer, ...)
|
|
63
97
|
|
|
64
98
|
## Analysis
|
|
65
99
|
(cite exact file paths and line numbers)
|
|
@@ -92,7 +126,7 @@ destructive action without the operator's explicit go-ahead.
|
|
|
92
126
|
|
|
93
127
|
Each round, read the workspace history first and do not repeat finished work.
|
|
94
128
|
Process leftover TODOs; otherwise pick an unreviewed (❌) or to-deepen (⚠️)
|
|
95
|
-
|
|
129
|
+
source from the inventory. When every source is ✅ and there are no TODOs,
|
|
96
130
|
report the review complete.
|
|
97
131
|
|
|
98
132
|
## On finish
|
|
@@ -86,7 +86,10 @@ def build_repo_model(root: str | Path, files: dict[str, str], *, signatures: _Si
|
|
|
86
86
|
tree = ast.parse(content)
|
|
87
87
|
except SyntaxError:
|
|
88
88
|
continue
|
|
89
|
-
|
|
89
|
+
# an entrypoint must name a reviewable handler function; drop entries
|
|
90
|
+
# with no resolvable function (a Django include() mount, or a view the
|
|
91
|
+
# AST scan cannot resolve) so the seeded inventory stays clean
|
|
92
|
+
entrypoints.extend(e for e in _entrypoints_in(path, tree, sigs) if e.function)
|
|
90
93
|
return RepoModel(root=str(root), files=tuple(sorted(files)), entrypoints=tuple(entrypoints))
|
|
91
94
|
|
|
92
95
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codejury
|
|
3
|
-
Version: 0.14.
|
|
3
|
+
Version: 0.14.5
|
|
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.5"
|
|
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"
|
|
@@ -59,6 +59,19 @@ urlpatterns = [
|
|
|
59
59
|
]
|
|
60
60
|
'''
|
|
61
61
|
|
|
62
|
+
# include() mounts and class-based views resolve to no handler function: noise
|
|
63
|
+
DJANGO_NOISE = '''
|
|
64
|
+
from django.urls import path, include
|
|
65
|
+
from .views import DashboardView
|
|
66
|
+
|
|
67
|
+
urlpatterns = [
|
|
68
|
+
path("", include("app.urls")),
|
|
69
|
+
path("accounts/", include("allauth.urls")),
|
|
70
|
+
path("profile/", views.profile),
|
|
71
|
+
path("dash/", DashboardView.as_view()),
|
|
72
|
+
]
|
|
73
|
+
'''
|
|
74
|
+
|
|
62
75
|
PLAIN = '''
|
|
63
76
|
def helper(x):
|
|
64
77
|
return x + 1
|
|
@@ -102,6 +115,14 @@ def test_django_path_calls_capture_view_and_route():
|
|
|
102
115
|
}
|
|
103
116
|
|
|
104
117
|
|
|
118
|
+
def test_django_include_and_cbv_with_no_resolvable_function_are_dropped():
|
|
119
|
+
# include() mounts and an unresolved .as_view() carry no handler function;
|
|
120
|
+
# only the plain function-based view survives, no empty `- -` noise entries
|
|
121
|
+
model = _model({"urls.py": DJANGO_NOISE})
|
|
122
|
+
assert _routes(model) == {("http", "django", "profile", "profile/", "")}
|
|
123
|
+
assert all(e.function for e in model.entrypoints)
|
|
124
|
+
|
|
125
|
+
|
|
105
126
|
def test_plain_module_has_no_entrypoints():
|
|
106
127
|
model = _model({"util.py": PLAIN})
|
|
107
128
|
assert model.entrypoints == ()
|
|
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
|