codejury 0.16.0__tar.gz → 0.16.1__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 (84) hide show
  1. {codejury-0.16.0 → codejury-0.16.1}/PKG-INFO +1 -1
  2. {codejury-0.16.0 → codejury-0.16.1}/codejury/diff/engine.py +3 -1
  3. {codejury-0.16.0 → codejury-0.16.1}/codejury/diff/prompts.py +3 -1
  4. {codejury-0.16.0/codejury/repo → codejury-0.16.1/codejury}/guides.py +25 -7
  5. {codejury-0.16.0 → codejury-0.16.1}/codejury/repo/scaffold.py +2 -2
  6. {codejury-0.16.0 → codejury-0.16.1}/codejury.egg-info/PKG-INFO +1 -1
  7. {codejury-0.16.0 → codejury-0.16.1}/codejury.egg-info/SOURCES.txt +1 -1
  8. {codejury-0.16.0 → codejury-0.16.1}/pyproject.toml +1 -1
  9. {codejury-0.16.0 → codejury-0.16.1}/tests/test_diff_engine.py +2 -1
  10. {codejury-0.16.0 → codejury-0.16.1}/tests/test_guides.py +13 -2
  11. {codejury-0.16.0 → codejury-0.16.1}/LICENSE +0 -0
  12. {codejury-0.16.0 → codejury-0.16.1}/README.md +0 -0
  13. {codejury-0.16.0 → codejury-0.16.1}/codejury/__init__.py +0 -0
  14. {codejury-0.16.0 → codejury-0.16.1}/codejury/cli.py +0 -0
  15. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/agent/repo-review.md +0 -0
  16. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/agent/security-review-memory.md +0 -0
  17. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/entrypoints.yaml +0 -0
  18. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/frameworks/django.md +0 -0
  19. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/languages/python.md +0 -0
  20. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/SKILL.md +0 -0
  21. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/business-logic.md +0 -0
  22. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/code-injection.md +0 -0
  23. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/command-injection.md +0 -0
  24. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/cross-site-request-forgery.md +0 -0
  25. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/cross-site-scripting.md +0 -0
  26. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/hardcoded-secrets.md +0 -0
  27. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/http-response-splitting.md +0 -0
  28. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/improper-authentication.md +0 -0
  29. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/information-exposure.md +0 -0
  30. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/insecure-cryptography.md +0 -0
  31. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/insecure-deserialization.md +0 -0
  32. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/insecure-direct-object-reference.md +0 -0
  33. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/insecure-transport.md +0 -0
  34. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/jwt-validation.md +0 -0
  35. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/mass-assignment.md +0 -0
  36. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/missing-authorization.md +0 -0
  37. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/open-redirect.md +0 -0
  38. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/path-traversal.md +0 -0
  39. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/race-condition.md +0 -0
  40. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/replay-attack.md +0 -0
  41. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/server-side-request-forgery.md +0 -0
  42. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/server-side-template-injection.md +0 -0
  43. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/session-fixation.md +0 -0
  44. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/sql-injection.md +0 -0
  45. {codejury-0.16.0 → codejury-0.16.1}/codejury/data/rules/xml-external-entity.md +0 -0
  46. {codejury-0.16.0 → codejury-0.16.1}/codejury/diff/__init__.py +0 -0
  47. {codejury-0.16.0 → codejury-0.16.1}/codejury/diff/debate.py +0 -0
  48. {codejury-0.16.0 → codejury-0.16.1}/codejury/diff/debate_prompts.py +0 -0
  49. {codejury-0.16.0 → codejury-0.16.1}/codejury/diff/findings_filter.py +0 -0
  50. {codejury-0.16.0 → codejury-0.16.1}/codejury/diff/rules.py +0 -0
  51. {codejury-0.16.0 → codejury-0.16.1}/codejury/diff/runner.py +0 -0
  52. {codejury-0.16.0 → codejury-0.16.1}/codejury/domain/__init__.py +0 -0
  53. {codejury-0.16.0 → codejury-0.16.1}/codejury/domain/finding.py +0 -0
  54. {codejury-0.16.0 → codejury-0.16.1}/codejury/json_parse.py +0 -0
  55. {codejury-0.16.0 → codejury-0.16.1}/codejury/providers/__init__.py +0 -0
  56. {codejury-0.16.0 → codejury-0.16.1}/codejury/providers/anthropic.py +0 -0
  57. {codejury-0.16.0 → codejury-0.16.1}/codejury/providers/base.py +0 -0
  58. {codejury-0.16.0 → codejury-0.16.1}/codejury/providers/factory.py +0 -0
  59. {codejury-0.16.0 → codejury-0.16.1}/codejury/providers/litellm.py +0 -0
  60. {codejury-0.16.0 → codejury-0.16.1}/codejury/providers/mock.py +0 -0
  61. {codejury-0.16.0 → codejury-0.16.1}/codejury/providers/openai.py +0 -0
  62. {codejury-0.16.0 → codejury-0.16.1}/codejury/providers/openai_format.py +0 -0
  63. {codejury-0.16.0 → codejury-0.16.1}/codejury/providers/retry.py +0 -0
  64. {codejury-0.16.0 → codejury-0.16.1}/codejury/repo/__init__.py +0 -0
  65. {codejury-0.16.0 → codejury-0.16.1}/codejury/repo/model.py +0 -0
  66. {codejury-0.16.0 → codejury-0.16.1}/codejury/report.py +0 -0
  67. {codejury-0.16.0 → codejury-0.16.1}/codejury/resources.py +0 -0
  68. {codejury-0.16.0 → codejury-0.16.1}/codejury.egg-info/dependency_links.txt +0 -0
  69. {codejury-0.16.0 → codejury-0.16.1}/codejury.egg-info/entry_points.txt +0 -0
  70. {codejury-0.16.0 → codejury-0.16.1}/codejury.egg-info/requires.txt +0 -0
  71. {codejury-0.16.0 → codejury-0.16.1}/codejury.egg-info/top_level.txt +0 -0
  72. {codejury-0.16.0 → codejury-0.16.1}/setup.cfg +0 -0
  73. {codejury-0.16.0 → codejury-0.16.1}/tests/test_anthropic_provider.py +0 -0
  74. {codejury-0.16.0 → codejury-0.16.1}/tests/test_cli_audit.py +0 -0
  75. {codejury-0.16.0 → codejury-0.16.1}/tests/test_diff_debate.py +0 -0
  76. {codejury-0.16.0 → codejury-0.16.1}/tests/test_json_parse.py +0 -0
  77. {codejury-0.16.0 → codejury-0.16.1}/tests/test_litellm_provider.py +0 -0
  78. {codejury-0.16.0 → codejury-0.16.1}/tests/test_openai_format.py +0 -0
  79. {codejury-0.16.0 → codejury-0.16.1}/tests/test_openai_provider.py +0 -0
  80. {codejury-0.16.0 → codejury-0.16.1}/tests/test_repo_model.py +0 -0
  81. {codejury-0.16.0 → codejury-0.16.1}/tests/test_repo_scaffold.py +0 -0
  82. {codejury-0.16.0 → codejury-0.16.1}/tests/test_report.py +0 -0
  83. {codejury-0.16.0 → codejury-0.16.1}/tests/test_retry_provider.py +0 -0
  84. {codejury-0.16.0 → codejury-0.16.1}/tests/test_rules.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codejury
3
- Version: 0.16.0
3
+ Version: 0.16.1
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
@@ -12,6 +12,7 @@ from codejury.diff.prompts import SYSTEM, standard_audit_prompt
12
12
  from codejury.diff.rules import rules_for_diff
13
13
  from codejury.json_parse import extract_json_object
14
14
  from codejury.providers.base import Message, Provider
15
+ from codejury.guides import guides_for_diff
15
16
 
16
17
 
17
18
  class AuditError(RuntimeError):
@@ -33,9 +34,10 @@ class AuditRunner:
33
34
  def run(self, diff: str, *, rules: str = "", context: str = "") -> list[Finding]:
34
35
  if not rules:
35
36
  rules = rules_for_diff(diff) # inject the rules relevant to this diff
37
+ stack = guides_for_diff(diff) # inject the target's language/framework conventions
36
38
  result = self._provider.complete(
37
39
  system=SYSTEM,
38
- messages=[Message(role="user", content=standard_audit_prompt(diff, rules=rules, context=context))],
40
+ messages=[Message(role="user", content=standard_audit_prompt(diff, rules=rules, context=context, stack=stack))],
39
41
  model=self._model,
40
42
  max_tokens=self._max_tokens,
41
43
  )
@@ -57,7 +57,8 @@ def category_block() -> str:
57
57
  )
58
58
 
59
59
 
60
- def standard_audit_prompt(diff: str, *, rules: str = "", context: str = "") -> str:
60
+ def standard_audit_prompt(diff: str, *, rules: str = "", context: str = "", stack: str = "") -> str:
61
+ stack_block = f"Conventions of the target's language/framework:\n{stack}\n\n" if stack else ""
61
62
  rules_block = f"Relevant security rules for reference:\n{rules}\n\n" if rules else ""
62
63
  context_block = (
63
64
  f"Surrounding code for tracing where values come from (not under review):\n"
@@ -69,6 +70,7 @@ def standard_audit_prompt(diff: str, *, rules: str = "", context: str = "") -> s
69
70
  "Review the following code change for security vulnerabilities.\n\n"
70
71
  f"{FOCUS}\n{DO_NOT_REPORT}\n"
71
72
  f"{category_block()}"
73
+ f"{stack_block}"
72
74
  f"{rules_block}"
73
75
  f"Code change (unified diff):\n```diff\n{diff}\n```\n\n"
74
76
  f"{context_block}"
@@ -13,6 +13,7 @@ code change, which keeps the unbounded language/framework axis out of code.
13
13
  from __future__ import annotations
14
14
 
15
15
  import fnmatch
16
+ import re
16
17
  from dataclasses import dataclass
17
18
  from pathlib import Path
18
19
 
@@ -20,6 +21,8 @@ import yaml
20
21
 
21
22
  from codejury.resources import FRAMEWORKS_DIR, LANGUAGES_DIR
22
23
 
24
+ _DIFF_PATH = re.compile(r"^(?:\+\+\+ b/|diff --git a/\S+ b/)(\S+)", re.MULTILINE)
25
+
23
26
 
24
27
  @dataclass(frozen=True, kw_only=True)
25
28
  class Guide:
@@ -62,18 +65,33 @@ def load_guides(languages_dir=LANGUAGES_DIR, frameworks_dir=FRAMEWORKS_DIR) -> l
62
65
  return out
63
66
 
64
67
 
65
- def _matches(guide: Guide, files: list[str], manifest: str) -> bool:
68
+ def _matches(guide: Guide, files: list[str], text: str) -> bool:
66
69
  if any(fnmatch.fnmatch(f, pat) for pat in guide.detect_files for f in files):
67
70
  return True
68
- if any(m in manifest for m in guide.detect_manifest):
71
+ if any(m in text for m in guide.detect_manifest):
72
+ return True
73
+ if any(i in text for i in guide.detect_imports):
69
74
  return True
70
75
  return False
71
76
 
72
77
 
73
- def select_guides(files, *, manifest_text: str = "", guides: list[Guide] | None = None) -> list[Guide]:
74
- """The guides whose detect signals fire on the repo (its file paths and the
75
- concatenated text of its dependency manifests), languages first then frameworks."""
78
+ def select_guides(files, *, text: str = "", guides: list[Guide] | None = None) -> list[Guide]:
79
+ """The guides whose detect signals fire on the target, languages first then
80
+ frameworks. `files` are the target's file paths; `text` is content to scan for
81
+ manifest substrings and import markers (a repo's manifests, or a diff body)."""
76
82
  pool = load_guides() if guides is None else guides
77
83
  file_list = list(files)
78
- manifest = manifest_text.lower()
79
- return [g for g in pool if _matches(g, file_list, manifest)]
84
+ blob = text.lower()
85
+ return [g for g in pool if _matches(g, file_list, blob)]
86
+
87
+
88
+ def _changed_paths(diff: str) -> list[str]:
89
+ """The file paths touched by a unified diff (from its `+++ b/` / `diff --git` headers)."""
90
+ return _DIFF_PATH.findall(diff)
91
+
92
+
93
+ def guides_for_diff(diff: str, *, guides: list[Guide] | None = None) -> str:
94
+ """Concatenated bodies of the language/framework guides relevant to a diff, by
95
+ its changed paths and its content. Empty when nothing matches."""
96
+ selected = select_guides(_changed_paths(diff), text=diff, guides=guides)
97
+ return "\n\n---\n\n".join(g.body for g in selected)
@@ -13,7 +13,7 @@ from __future__ import annotations
13
13
  from dataclasses import dataclass, field
14
14
  from pathlib import Path
15
15
 
16
- from codejury.repo.guides import Guide, select_guides
16
+ from codejury.guides import Guide, select_guides
17
17
  from codejury.repo.model import build_repo_model_from_dir
18
18
  from codejury.resources import AGENT_DIR
19
19
 
@@ -105,7 +105,7 @@ def scaffold(target: str | Path, workspace: str | Path) -> ScaffoldResult:
105
105
  (ws / "entrypoints" / "_entrypoints.md").write_text(_entrypoints_md(model), encoding="utf-8")
106
106
 
107
107
  # detect the stack and seed its review guides (languages + frameworks)
108
- guides = select_guides(model.files, manifest_text=_read_manifests(target))
108
+ guides = select_guides(model.files, text=_read_manifests(target))
109
109
  (ws / "_stack.md").write_text(_stack_md(guides), encoding="utf-8")
110
110
 
111
111
  return ScaffoldResult(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codejury
3
- Version: 0.16.0
3
+ Version: 0.16.1
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,7 @@ README.md
3
3
  pyproject.toml
4
4
  codejury/__init__.py
5
5
  codejury/cli.py
6
+ codejury/guides.py
6
7
  codejury/json_parse.py
7
8
  codejury/report.py
8
9
  codejury/resources.py
@@ -63,7 +64,6 @@ codejury/providers/openai.py
63
64
  codejury/providers/openai_format.py
64
65
  codejury/providers/retry.py
65
66
  codejury/repo/__init__.py
66
- codejury/repo/guides.py
67
67
  codejury/repo/model.py
68
68
  codejury/repo/scaffold.py
69
69
  tests/test_anthropic_provider.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codejury"
3
- version = "0.16.0"
3
+ version = "0.16.1"
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"
@@ -85,11 +85,12 @@ def test_engine_raises_on_wrong_shape_json():
85
85
 
86
86
 
87
87
  def test_prompt_carries_diff_focus_and_do_not_report():
88
- p = standard_audit_prompt(_DIFF, rules="RULE-X", context="def caller(): ...")
88
+ p = standard_audit_prompt(_DIFF, rules="RULE-X", context="def caller(): ...", stack="STACK-NOTE")
89
89
  assert "SELECT * FROM u" in p # the diff
90
90
  assert "Do NOT report" in p # the noise-control list
91
91
  assert "IDOR" in p # the focus
92
92
  assert "RULE-X" in p # rules excerpt
93
+ assert "STACK-NOTE" in p # language/framework conventions block
93
94
  assert "def caller()" in p # context block
94
95
 
95
96
 
@@ -1,7 +1,7 @@
1
1
  """Language/framework review guides load and are selected by detection signals
2
2
  (file globs + dependency-manifest substrings), so adding one is a drop-in file."""
3
3
 
4
- from codejury.repo.guides import Guide, load_guides, select_guides
4
+ from codejury.guides import Guide, guides_for_diff, load_guides, select_guides
5
5
 
6
6
 
7
7
  def test_shipped_guides_load():
@@ -19,7 +19,7 @@ def test_select_by_file_glob():
19
19
 
20
20
 
21
21
  def test_select_by_manifest_substring():
22
- matched = {g.id for g in select_guides(["main.py"], manifest_text="Django==4.2\nrequests\n")}
22
+ matched = {g.id for g in select_guides(["main.py"], text="Django==4.2\nrequests\n")}
23
23
  assert "django" in matched and "python" in matched
24
24
 
25
25
 
@@ -32,3 +32,14 @@ def test_select_respects_injected_pool():
32
32
  detect_manifest=(), detect_imports=(), body="b")]
33
33
  assert [g.id for g in select_guides(["a.xyz"], guides=only)] == ["x"]
34
34
  assert select_guides(["a.py"], guides=only) == []
35
+
36
+
37
+ def test_guides_for_diff_by_path_and_content():
38
+ diff = ("diff --git a/app/urls.py b/app/urls.py\n"
39
+ "+from django.urls import path\n+urlpatterns = []\n")
40
+ notes = guides_for_diff(diff)
41
+ assert "Django" in notes and "Python" in notes # urls.py + .py + the django import
42
+
43
+
44
+ def test_guides_for_diff_empty_when_irrelevant():
45
+ assert guides_for_diff("+++ b/README.md\n+hello\n") == ""
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes