codejury 0.11.0__tar.gz → 0.13.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.
- codejury-0.13.1/PKG-INFO +103 -0
- codejury-0.13.1/README.md +72 -0
- codejury-0.13.1/codejury/__init__.py +14 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/analysis/repo_model.py +23 -5
- codejury-0.13.1/codejury/cli.py +199 -0
- codejury-0.13.1/codejury/data/agent/full-review.md +102 -0
- codejury-0.13.1/codejury/data/agent/security-review-memory.md +30 -0
- codejury-0.13.1/codejury/data/rules/SKILL.md +58 -0
- codejury-0.13.1/codejury/data/rules/business-logic.md +23 -0
- codejury-0.13.1/codejury/data/rules/code-injection.md +23 -0
- codejury-0.13.1/codejury/data/rules/command-injection.md +26 -0
- codejury-0.13.1/codejury/data/rules/cross-site-request-forgery.md +21 -0
- codejury-0.13.1/codejury/data/rules/cross-site-scripting.md +25 -0
- codejury-0.13.1/codejury/data/rules/hardcoded-secrets.md +21 -0
- codejury-0.13.1/codejury/data/rules/http-response-splitting.md +24 -0
- codejury-0.13.1/codejury/data/rules/improper-authentication.md +26 -0
- codejury-0.13.1/codejury/data/rules/information-exposure.md +34 -0
- codejury-0.13.1/codejury/data/rules/insecure-cryptography.md +23 -0
- codejury-0.13.1/codejury/data/rules/insecure-deserialization.md +23 -0
- codejury-0.13.1/codejury/data/rules/insecure-direct-object-reference.md +25 -0
- codejury-0.13.1/codejury/data/rules/insecure-transport.md +22 -0
- codejury-0.13.1/codejury/data/rules/jwt-validation.md +22 -0
- codejury-0.13.1/codejury/data/rules/mass-assignment.md +22 -0
- codejury-0.13.1/codejury/data/rules/missing-authorization.md +28 -0
- codejury-0.13.1/codejury/data/rules/open-redirect.md +24 -0
- codejury-0.13.1/codejury/data/rules/path-traversal.md +34 -0
- codejury-0.13.1/codejury/data/rules/race-condition.md +26 -0
- codejury-0.13.1/codejury/data/rules/replay-attack.md +23 -0
- codejury-0.13.1/codejury/data/rules/server-side-request-forgery.md +23 -0
- codejury-0.13.1/codejury/data/rules/server-side-template-injection.md +21 -0
- codejury-0.13.1/codejury/data/rules/session-fixation.md +23 -0
- codejury-0.13.1/codejury/data/rules/sql-injection.md +26 -0
- codejury-0.13.1/codejury/data/rules/xml-external-entity.md +23 -0
- codejury-0.13.1/codejury/diff/__init__.py +0 -0
- codejury-0.13.1/codejury/diff/debate.py +157 -0
- codejury-0.13.1/codejury/diff/debate_prompts.py +116 -0
- codejury-0.13.1/codejury/diff/engine.py +33 -0
- codejury-0.13.1/codejury/diff/findings_filter.py +61 -0
- codejury-0.13.1/codejury/diff/prompts.py +79 -0
- codejury-0.13.1/codejury/diff/report.py +120 -0
- codejury-0.13.1/codejury/diff/rules.py +87 -0
- codejury-0.13.1/codejury/domain/finding.py +70 -0
- codejury-0.13.1/codejury/fullreview/__init__.py +0 -0
- codejury-0.13.1/codejury/fullreview/scaffold.py +77 -0
- codejury-0.13.1/codejury/infrastructure/json_parse.py +98 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/providers/anthropic.py +1 -0
- codejury-0.13.1/codejury/providers/factory.py +34 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/providers/litellm.py +1 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/providers/openai.py +1 -0
- codejury-0.13.1/codejury/resources.py +13 -0
- codejury-0.13.1/codejury.egg-info/PKG-INFO +103 -0
- codejury-0.13.1/codejury.egg-info/SOURCES.txt +79 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury.egg-info/requires.txt +1 -0
- {codejury-0.11.0 → codejury-0.13.1}/pyproject.toml +3 -2
- codejury-0.13.1/tests/test_cli_audit.py +45 -0
- codejury-0.13.1/tests/test_diff_debate.py +158 -0
- codejury-0.13.1/tests/test_diff_engine.py +116 -0
- codejury-0.13.1/tests/test_diff_report.py +66 -0
- codejury-0.13.1/tests/test_full_review_scaffold.py +74 -0
- {codejury-0.11.0 → codejury-0.13.1}/tests/test_json_parse.py +16 -0
- codejury-0.13.1/tests/test_rules.py +91 -0
- codejury-0.11.0/PKG-INFO +0 -241
- codejury-0.11.0/README.md +0 -211
- codejury-0.11.0/codejury/__init__.py +0 -14
- codejury-0.11.0/codejury/agents/__init__.py +0 -6
- codejury-0.11.0/codejury/agents/base.py +0 -21
- codejury-0.11.0/codejury/agents/debate.py +0 -206
- codejury-0.11.0/codejury/agents/mock.py +0 -37
- codejury-0.11.0/codejury/agents/parsing.py +0 -45
- codejury-0.11.0/codejury/agents/refuter.py +0 -76
- codejury-0.11.0/codejury/agents/skill_runner.py +0 -121
- codejury-0.11.0/codejury/analysis/attack_path.py +0 -110
- codejury-0.11.0/codejury/analysis/provenance.py +0 -253
- codejury-0.11.0/codejury/analysis/taint.py +0 -303
- codejury-0.11.0/codejury/assembly.py +0 -144
- codejury-0.11.0/codejury/baseline.py +0 -58
- codejury-0.11.0/codejury/cli.py +0 -533
- codejury-0.11.0/codejury/data/golden/ag_allowlist_safe.yaml +0 -16
- codejury-0.11.0/codejury/data/golden/ag_arbitrary_tool_vuln.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/ag_destructive_no_confirm_vuln.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/ag_fixed_enum_safe.yaml +0 -19
- codejury-0.11.0/codejury/data/golden/ag_human_approval_safe.yaml +0 -13
- codejury-0.11.0/codejury/data/golden/ag_model_confirmed_vuln.yaml +0 -16
- codejury-0.11.0/codejury/data/golden/api_design_authz_inconsistent_vuln.yaml +0 -23
- codejury-0.11.0/codejury/data/golden/api_design_authz_uniform_safe.yaml +0 -22
- codejury-0.11.0/codejury/data/golden/api_design_cors_allowlist_safe.yaml +0 -23
- codejury-0.11.0/codejury/data/golden/api_design_cors_reflect_origin_vuln.yaml +0 -20
- codejury-0.11.0/codejury/data/golden/api_design_cors_wildcard_credentials_vuln.yaml +0 -23
- codejury-0.11.0/codejury/data/golden/api_design_mass_assignment_allowlist_safe.yaml +0 -22
- codejury-0.11.0/codejury/data/golden/api_design_mass_assignment_vuln.yaml +0 -21
- codejury-0.11.0/codejury/data/golden/api_design_single_missing_auth_not_ours_safe.yaml +0 -18
- codejury-0.11.0/codejury/data/golden/architecture_clean_surface_safe.yaml +0 -19
- codejury-0.11.0/codejury/data/golden/architecture_debug_route_exposed_vuln.yaml +0 -21
- codejury-0.11.0/codejury/data/golden/architecture_internal_route_exposed_vuln.yaml +0 -18
- codejury-0.11.0/codejury/data/golden/architecture_legit_admin_route_safe.yaml +0 -19
- codejury-0.11.0/codejury/data/golden/architecture_minimal_surface_safe.yaml +0 -18
- codejury-0.11.0/codejury/data/golden/architecture_test_echo_route_vuln.yaml +0 -17
- codejury-0.11.0/codejury/data/golden/authn_bcrypt_password.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/authn_jwt_noverify_vuln.yaml +0 -6
- codejury-0.11.0/codejury/data/golden/authn_jwt_verified_safe.yaml +0 -6
- codejury-0.11.0/codejury/data/golden/authn_sha256_checksum_safe.yaml +0 -6
- codejury-0.11.0/codejury/data/golden/authn_sha256_password.yaml +0 -6
- codejury-0.11.0/codejury/data/golden/authn_weak_hash_indirect_vuln.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/authz_idor_vuln.yaml +0 -6
- codejury-0.11.0/codejury/data/golden/authz_owner_safe.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/business_logic_atomic_safe.yaml +0 -15
- codejury-0.11.0/codejury/data/golden/business_logic_price_tamper_vuln.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/business_logic_server_checked_safe.yaml +0 -15
- codejury-0.11.0/codejury/data/golden/business_logic_toctou_vuln.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/cmdi_fixed_argv_safe.yaml +0 -22
- codejury-0.11.0/codejury/data/golden/cmdi_ossystem_vuln.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/cmdi_subprocess_safe.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/crypto_aesgcm_nonce_safe.yaml +0 -13
- codejury-0.11.0/codejury/data/golden/crypto_aesgcm_safe.yaml +0 -6
- codejury-0.11.0/codejury/data/golden/crypto_ecb_vuln.yaml +0 -6
- codejury-0.11.0/codejury/data/golden/crypto_static_iv_vuln.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/data_protection_cleartext_http_vuln.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/data_protection_encrypted_at_rest_safe.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/data_protection_plaintext_pii_vuln.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/data_protection_tokenized_safe.yaml +0 -16
- codejury-0.11.0/codejury/data/golden/dependency_config_debug_off_safe.yaml +0 -12
- codejury-0.11.0/codejury/data/golden/dependency_config_debug_true_vuln.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/dependency_config_tls_verify_off_vuln.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/dependency_config_tls_verify_on_safe.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/deserialize_json_safe.yaml +0 -13
- codejury-0.11.0/codejury/data/golden/deserialize_pickle_vuln.yaml +0 -12
- codejury-0.11.0/codejury/data/golden/error_logging_redacted_safe.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/error_logging_reraise_safe.yaml +0 -15
- codejury-0.11.0/codejury/data/golden/error_logging_secret_leak_vuln.yaml +0 -12
- codejury-0.11.0/codejury/data/golden/error_logging_swallow_vuln.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/ioh_escaped_output_safe.yaml +0 -12
- codejury-0.11.0/codejury/data/golden/ioh_exec_output_vuln.yaml +0 -13
- codejury-0.11.0/codejury/data/golden/ioh_innerhtml_output_vuln.yaml +0 -13
- codejury-0.11.0/codejury/data/golden/ioh_json_response_safe.yaml +0 -15
- codejury-0.11.0/codejury/data/golden/ioh_output_to_sql_vuln.yaml +0 -15
- codejury-0.11.0/codejury/data/golden/ioh_schema_validated_safe.yaml +0 -13
- codejury-0.11.0/codejury/data/golden/literal_eval_safe.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/output_encoding_header_injection_vuln.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/path_basename_safe.yaml +0 -15
- codejury-0.11.0/codejury/data/golden/path_contained_safe.yaml +0 -8
- codejury-0.11.0/codejury/data/golden/path_traversal_vuln.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/pi_delimited_data_safe.yaml +0 -15
- codejury-0.11.0/codejury/data/golden/pi_format_role_vuln.yaml +0 -16
- codejury-0.11.0/codejury/data/golden/pi_indirect_rag_vuln.yaml +0 -16
- codejury-0.11.0/codejury/data/golden/pi_system_concat_vuln.yaml +0 -13
- codejury-0.11.0/codejury/data/golden/pi_user_content_concat_safe.yaml +0 -18
- codejury-0.11.0/codejury/data/golden/pi_user_role_safe.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/sc_pinned_safe.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/sc_safetensors_safe.yaml +0 -12
- codejury-0.11.0/codejury/data/golden/sc_torch_load_vuln.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/sc_trust_remote_code_vuln.yaml +0 -12
- codejury-0.11.0/codejury/data/golden/secrets_env_safe.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/secrets_from_config_safe.yaml +0 -12
- codejury-0.11.0/codejury/data/golden/secrets_hardcoded_token_vuln.yaml +0 -13
- codejury-0.11.0/codejury/data/golden/secrets_hardcoded_vuln.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/session_cookie_flags_safe.yaml +0 -10
- codejury-0.11.0/codejury/data/golden/session_fixation_vuln.yaml +0 -16
- codejury-0.11.0/codejury/data/golden/session_insecure_cookie_vuln.yaml +0 -11
- codejury-0.11.0/codejury/data/golden/session_secure_cookie_safe.yaml +0 -18
- codejury-0.11.0/codejury/data/golden/sql_constant_concat_safe.yaml +0 -14
- codejury-0.11.0/codejury/data/golden/sqli_format_vuln.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/sqli_fstring_query.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/sqli_indirect_var_vuln.yaml +0 -16
- codejury-0.11.0/codejury/data/golden/sqli_parameterized_query.yaml +0 -5
- codejury-0.11.0/codejury/data/golden/ssrf_allowlist_safe.yaml +0 -17
- codejury-0.11.0/codejury/data/golden/ssrf_constant_url_safe.yaml +0 -13
- codejury-0.11.0/codejury/data/golden/ssrf_substring_allowlist_bypass_vuln.yaml +0 -17
- codejury-0.11.0/codejury/data/golden/ssrf_user_url_vuln.yaml +0 -12
- codejury-0.11.0/codejury/data/golden/xfile_idor_no_check_vuln.yaml +0 -20
- codejury-0.11.0/codejury/data/golden/xfile_idor_owner_checked_safe.yaml +0 -21
- codejury-0.11.0/codejury/data/golden/xfile_path_sanitized_safe.yaml +0 -22
- codejury-0.11.0/codejury/data/golden/xfile_path_tainted_vuln.yaml +0 -19
- codejury-0.11.0/codejury/data/golden/xss_innerhtml_constant_safe.yaml +0 -7
- codejury-0.11.0/codejury/data/golden/xss_innerhtml_vuln.yaml +0 -7
- codejury-0.11.0/codejury/data/golden/xss_textcontent_safe.yaml +0 -15
- codejury-0.11.0/codejury/data/poc/cmdi.yaml +0 -14
- codejury-0.11.0/codejury/data/poc/path.yaml +0 -12
- codejury-0.11.0/codejury/data/poc/sqli.yaml +0 -14
- codejury-0.11.0/codejury/data/poc/ssrf.yaml +0 -15
- codejury-0.11.0/codejury/data/skills/api_design/SKILL.md +0 -116
- codejury-0.11.0/codejury/data/skills/api_design/skill.yaml +0 -8
- codejury-0.11.0/codejury/data/skills/architecture/SKILL.md +0 -52
- codejury-0.11.0/codejury/data/skills/architecture/skill.yaml +0 -8
- codejury-0.11.0/codejury/data/skills/authn/SKILL.md +0 -59
- codejury-0.11.0/codejury/data/skills/authn/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/authz/SKILL.md +0 -46
- codejury-0.11.0/codejury/data/skills/authz/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/business_logic/SKILL.md +0 -50
- codejury-0.11.0/codejury/data/skills/business_logic/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/crypto/SKILL.md +0 -55
- codejury-0.11.0/codejury/data/skills/crypto/skill.yaml +0 -12
- codejury-0.11.0/codejury/data/skills/data_protection/SKILL.md +0 -50
- codejury-0.11.0/codejury/data/skills/data_protection/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/dependency_config/SKILL.md +0 -55
- codejury-0.11.0/codejury/data/skills/dependency_config/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/error_logging/SKILL.md +0 -45
- codejury-0.11.0/codejury/data/skills/error_logging/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/excessive_agency/SKILL.md +0 -58
- codejury-0.11.0/codejury/data/skills/excessive_agency/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/input_validation/SKILL.md +0 -128
- codejury-0.11.0/codejury/data/skills/input_validation/skill.yaml +0 -13
- codejury-0.11.0/codejury/data/skills/insecure_output_handling/SKILL.md +0 -62
- codejury-0.11.0/codejury/data/skills/insecure_output_handling/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/model_supply_chain/SKILL.md +0 -57
- codejury-0.11.0/codejury/data/skills/model_supply_chain/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/output_encoding/SKILL.md +0 -45
- codejury-0.11.0/codejury/data/skills/output_encoding/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/skills/prompt_injection/SKILL.md +0 -62
- codejury-0.11.0/codejury/data/skills/prompt_injection/skill.yaml +0 -10
- codejury-0.11.0/codejury/data/skills/secrets/SKILL.md +0 -48
- codejury-0.11.0/codejury/data/skills/secrets/skill.yaml +0 -10
- codejury-0.11.0/codejury/data/skills/session/SKILL.md +0 -47
- codejury-0.11.0/codejury/data/skills/session/skill.yaml +0 -11
- codejury-0.11.0/codejury/data/suppressions.yaml +0 -43
- codejury-0.11.0/codejury/data/taint.yaml +0 -109
- codejury-0.11.0/codejury/data/tasks/audit_diff_debate.yaml +0 -4
- codejury-0.11.0/codejury/data/tasks/quick_scan_single.yaml +0 -4
- codejury-0.11.0/codejury/domain/artifact.py +0 -23
- codejury-0.11.0/codejury/domain/context.py +0 -26
- codejury-0.11.0/codejury/domain/observation.py +0 -170
- codejury-0.11.0/codejury/domain/result.py +0 -33
- codejury-0.11.0/codejury/domain/skill.py +0 -117
- codejury-0.11.0/codejury/evaluation.py +0 -183
- codejury-0.11.0/codejury/infrastructure/cache.py +0 -101
- codejury-0.11.0/codejury/infrastructure/json_parse.py +0 -62
- codejury-0.11.0/codejury/integrations/__init__.py +0 -1
- codejury-0.11.0/codejury/integrations/github.py +0 -103
- codejury-0.11.0/codejury/orchestrators/__init__.py +0 -6
- codejury-0.11.0/codejury/orchestrators/adaptive.py +0 -55
- codejury-0.11.0/codejury/orchestrators/base.py +0 -27
- codejury-0.11.0/codejury/orchestrators/challenge.py +0 -84
- codejury-0.11.0/codejury/orchestrators/debate.py +0 -57
- codejury-0.11.0/codejury/orchestrators/reflexion.py +0 -58
- codejury-0.11.0/codejury/orchestrators/single.py +0 -24
- codejury-0.11.0/codejury/orchestrators/skill_pipeline.py +0 -32
- codejury-0.11.0/codejury/orchestrators/taint_gate.py +0 -75
- codejury-0.11.0/codejury/reporting.py +0 -265
- codejury-0.11.0/codejury/resources.py +0 -17
- codejury-0.11.0/codejury/sandbox.py +0 -363
- codejury-0.11.0/codejury/selection.py +0 -145
- codejury-0.11.0/codejury/sources/__init__.py +0 -6
- codejury-0.11.0/codejury/sources/api_surface.py +0 -101
- codejury-0.11.0/codejury/sources/base.py +0 -17
- codejury-0.11.0/codejury/sources/callers.py +0 -106
- codejury-0.11.0/codejury/sources/chunker.py +0 -36
- codejury-0.11.0/codejury/sources/diff.py +0 -70
- codejury-0.11.0/codejury/sources/function.py +0 -44
- codejury-0.11.0/codejury/sources/mock.py +0 -25
- codejury-0.11.0/codejury/sources/repo.py +0 -79
- codejury-0.11.0/codejury/suppression.py +0 -94
- codejury-0.11.0/codejury/tasks/__init__.py +0 -6
- codejury-0.11.0/codejury/tasks/base.py +0 -82
- codejury-0.11.0/codejury/tasks/registry.py +0 -22
- codejury-0.11.0/codejury.egg-info/PKG-INFO +0 -241
- codejury-0.11.0/codejury.egg-info/SOURCES.txt +0 -253
- codejury-0.11.0/tests/test_adaptive.py +0 -73
- codejury-0.11.0/tests/test_api_surface.py +0 -106
- codejury-0.11.0/tests/test_assembly.py +0 -74
- codejury-0.11.0/tests/test_attack_path.py +0 -141
- codejury-0.11.0/tests/test_baseline.py +0 -63
- codejury-0.11.0/tests/test_cache.py +0 -120
- codejury-0.11.0/tests/test_callers.py +0 -69
- codejury-0.11.0/tests/test_challenge.py +0 -105
- codejury-0.11.0/tests/test_cli_audit.py +0 -116
- codejury-0.11.0/tests/test_context.py +0 -30
- codejury-0.11.0/tests/test_debate_agents.py +0 -87
- codejury-0.11.0/tests/test_debate_orchestrator.py +0 -77
- codejury-0.11.0/tests/test_diff_source.py +0 -63
- codejury-0.11.0/tests/test_evaluation.py +0 -181
- codejury-0.11.0/tests/test_full_review.py +0 -111
- codejury-0.11.0/tests/test_function_source.py +0 -49
- codejury-0.11.0/tests/test_integrations.py +0 -82
- codejury-0.11.0/tests/test_orchestrator.py +0 -39
- codejury-0.11.0/tests/test_parsing.py +0 -32
- codejury-0.11.0/tests/test_provenance.py +0 -105
- codejury-0.11.0/tests/test_reflexion_orchestrator.py +0 -67
- codejury-0.11.0/tests/test_repo_source.py +0 -38
- codejury-0.11.0/tests/test_reporting.py +0 -52
- codejury-0.11.0/tests/test_review_fixes.py +0 -114
- codejury-0.11.0/tests/test_sandbox.py +0 -195
- codejury-0.11.0/tests/test_sarif.py +0 -115
- codejury-0.11.0/tests/test_selection.py +0 -109
- codejury-0.11.0/tests/test_skill.py +0 -140
- codejury-0.11.0/tests/test_skill_runner.py +0 -113
- codejury-0.11.0/tests/test_suppression.py +0 -44
- codejury-0.11.0/tests/test_taint.py +0 -135
- codejury-0.11.0/tests/test_taint_crossfile.py +0 -78
- codejury-0.11.0/tests/test_taint_gate.py +0 -107
- codejury-0.11.0/tests/test_tasks.py +0 -74
- {codejury-0.11.0 → codejury-0.13.1}/LICENSE +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/analysis/__init__.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/data/entrypoints.yaml +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/domain/__init__.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/infrastructure/__init__.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/providers/__init__.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/providers/base.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/providers/mock.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/providers/openai_format.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury/providers/retry.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury.egg-info/dependency_links.txt +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury.egg-info/entry_points.txt +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/codejury.egg-info/top_level.txt +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/setup.cfg +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/tests/test_anthropic_provider.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/tests/test_litellm_provider.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/tests/test_openai_format.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/tests/test_openai_provider.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/tests/test_repo_model.py +0 -0
- {codejury-0.11.0 → codejury-0.13.1}/tests/test_retry_provider.py +0 -0
codejury-0.13.1/PKG-INFO
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codejury
|
|
3
|
+
Version: 0.13.1
|
|
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
|
+
Author: AISecLabs
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/aiseclabs/codejury
|
|
8
|
+
Project-URL: Repository, https://github.com/aiseclabs/codejury
|
|
9
|
+
Keywords: security,appsec,static analysis,llm,owasp,asvs,code review
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Security
|
|
13
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: pyyaml>=6.0
|
|
20
|
+
Requires-Dist: json-repair>=0.30
|
|
21
|
+
Provides-Extra: anthropic
|
|
22
|
+
Requires-Dist: anthropic>=0.40; extra == "anthropic"
|
|
23
|
+
Provides-Extra: openai
|
|
24
|
+
Requires-Dist: openai>=1.0; extra == "openai"
|
|
25
|
+
Provides-Extra: litellm
|
|
26
|
+
Requires-Dist: litellm>=1.0; extra == "litellm"
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
29
|
+
Requires-Dist: jsonschema>=4.0; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# codejury
|
|
33
|
+
|
|
34
|
+
AI code security review, in two paths matched to their nature:
|
|
35
|
+
|
|
36
|
+
- **Diff review** (coded): audit a pull request's diff for newly introduced,
|
|
37
|
+
exploitable risks. A single balanced LLM call, or an adversarial
|
|
38
|
+
Finder/Challenger/Judge pass for higher coverage and fewer false positives.
|
|
39
|
+
- **Whole-repo review** (agent-driven): a methodology an interactive agent
|
|
40
|
+
(Claude Code, Codex) runs to traverse a codebase from its API entrypoints,
|
|
41
|
+
verify issues with a real PoC, and iterate over rounds with a persistent
|
|
42
|
+
memory. Too large for a single LLM call, so codejury ships the methodology and
|
|
43
|
+
scaffolds the workspace rather than running a pipeline.
|
|
44
|
+
|
|
45
|
+
Security knowledge lives in **rich rules** (`codejury/data/rules/*.md`, with
|
|
46
|
+
per-language vulnerable/secure examples), injected into the audit prompt, not
|
|
47
|
+
buried in code.
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install codejury # core
|
|
53
|
+
pip install "codejury[anthropic]" # or [openai] / [litellm] for a backend
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Diff review
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# audit a diff file
|
|
60
|
+
codejury audit --diff-file changes.diff
|
|
61
|
+
|
|
62
|
+
# audit a git range in a repo
|
|
63
|
+
codejury audit --repo /path/to/app --git-range origin/main...HEAD
|
|
64
|
+
|
|
65
|
+
# from stdin
|
|
66
|
+
git diff HEAD~1 | codejury audit
|
|
67
|
+
|
|
68
|
+
# adversarial mode: Finder + Challenger + Judge (higher coverage, lower FP, ~3x cost)
|
|
69
|
+
codejury audit --diff-file changes.diff --mode adversarial
|
|
70
|
+
|
|
71
|
+
# CI gate + SARIF
|
|
72
|
+
codejury audit --diff-file changes.diff --format sarif --fail-on high
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Configure a backend with `--provider`/`--model`/`--api-key`/`--api-base` or the
|
|
76
|
+
`CODEJURY_API_KEY` / `CODEJURY_MODEL` / `CODEJURY_API_BASE` environment variables.
|
|
77
|
+
`codejury dry-run` exercises the engine with a mock provider and no key.
|
|
78
|
+
|
|
79
|
+
## Whole-repo review
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
codejury full-review /path/to/your/repo
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
This scaffolds a review workspace (`api/`, `issues/`, `analysis/`, and a
|
|
86
|
+
`security-review-memory.md`), seeds the API inventory from a deterministic scan,
|
|
87
|
+
and prints the methodology. Run it with an interactive agent: it reads the
|
|
88
|
+
methodology and the rules, traverses the code from its API entrypoints, records
|
|
89
|
+
high-confidence issues with a PoC, and asks you to confirm credentials or false
|
|
90
|
+
positives along the way. Nothing runs against production.
|
|
91
|
+
|
|
92
|
+
## Findings
|
|
93
|
+
|
|
94
|
+
Each finding carries a file and line, a severity and category, a concrete
|
|
95
|
+
exploit scenario, a recommendation, and a confidence. A false-positive filter
|
|
96
|
+
drops test/mock-path and low-confidence noise; the model is also told not to
|
|
97
|
+
report dependency CVEs, style notes, speculation, or config-leak-only risks.
|
|
98
|
+
|
|
99
|
+
## Extending
|
|
100
|
+
|
|
101
|
+
Add a vulnerability class by dropping a new `codejury/data/rules/<class>.md` with
|
|
102
|
+
the standard frontmatter (title, impact, tags, triggers) and vulnerable/secure
|
|
103
|
+
examples. It is data; no code change needed.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# codejury
|
|
2
|
+
|
|
3
|
+
AI code security review, in two paths matched to their nature:
|
|
4
|
+
|
|
5
|
+
- **Diff review** (coded): audit a pull request's diff for newly introduced,
|
|
6
|
+
exploitable risks. A single balanced LLM call, or an adversarial
|
|
7
|
+
Finder/Challenger/Judge pass for higher coverage and fewer false positives.
|
|
8
|
+
- **Whole-repo review** (agent-driven): a methodology an interactive agent
|
|
9
|
+
(Claude Code, Codex) runs to traverse a codebase from its API entrypoints,
|
|
10
|
+
verify issues with a real PoC, and iterate over rounds with a persistent
|
|
11
|
+
memory. Too large for a single LLM call, so codejury ships the methodology and
|
|
12
|
+
scaffolds the workspace rather than running a pipeline.
|
|
13
|
+
|
|
14
|
+
Security knowledge lives in **rich rules** (`codejury/data/rules/*.md`, with
|
|
15
|
+
per-language vulnerable/secure examples), injected into the audit prompt, not
|
|
16
|
+
buried in code.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install codejury # core
|
|
22
|
+
pip install "codejury[anthropic]" # or [openai] / [litellm] for a backend
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Diff review
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# audit a diff file
|
|
29
|
+
codejury audit --diff-file changes.diff
|
|
30
|
+
|
|
31
|
+
# audit a git range in a repo
|
|
32
|
+
codejury audit --repo /path/to/app --git-range origin/main...HEAD
|
|
33
|
+
|
|
34
|
+
# from stdin
|
|
35
|
+
git diff HEAD~1 | codejury audit
|
|
36
|
+
|
|
37
|
+
# adversarial mode: Finder + Challenger + Judge (higher coverage, lower FP, ~3x cost)
|
|
38
|
+
codejury audit --diff-file changes.diff --mode adversarial
|
|
39
|
+
|
|
40
|
+
# CI gate + SARIF
|
|
41
|
+
codejury audit --diff-file changes.diff --format sarif --fail-on high
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Configure a backend with `--provider`/`--model`/`--api-key`/`--api-base` or the
|
|
45
|
+
`CODEJURY_API_KEY` / `CODEJURY_MODEL` / `CODEJURY_API_BASE` environment variables.
|
|
46
|
+
`codejury dry-run` exercises the engine with a mock provider and no key.
|
|
47
|
+
|
|
48
|
+
## Whole-repo review
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
codejury full-review /path/to/your/repo
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This scaffolds a review workspace (`api/`, `issues/`, `analysis/`, and a
|
|
55
|
+
`security-review-memory.md`), seeds the API inventory from a deterministic scan,
|
|
56
|
+
and prints the methodology. Run it with an interactive agent: it reads the
|
|
57
|
+
methodology and the rules, traverses the code from its API entrypoints, records
|
|
58
|
+
high-confidence issues with a PoC, and asks you to confirm credentials or false
|
|
59
|
+
positives along the way. Nothing runs against production.
|
|
60
|
+
|
|
61
|
+
## Findings
|
|
62
|
+
|
|
63
|
+
Each finding carries a file and line, a severity and category, a concrete
|
|
64
|
+
exploit scenario, a recommendation, and a confidence. A false-positive filter
|
|
65
|
+
drops test/mock-path and low-confidence noise; the model is also told not to
|
|
66
|
+
report dependency CVEs, style notes, speculation, or config-leak-only risks.
|
|
67
|
+
|
|
68
|
+
## Extending
|
|
69
|
+
|
|
70
|
+
Add a vulnerability class by dropping a new `codejury/data/rules/<class>.md` with
|
|
71
|
+
the standard frontmatter (title, impact, tags, triggers) and vulnerable/secure
|
|
72
|
+
examples. It is data; no code change needed.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""codejury: an AI code security review tool.
|
|
2
|
+
|
|
3
|
+
Two paths matched to their nature: a coded diff-audit engine (standard single
|
|
4
|
+
call or adversarial Finder/Challenger/Judge), and a whole-repo review run as a
|
|
5
|
+
methodology by an interactive agent. Security knowledge lives in rich markdown
|
|
6
|
+
rules (data/rules) injected into the audit prompt, not in a rendered schema.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
__version__ = version("codejury")
|
|
13
|
+
except PackageNotFoundError: # running from a source tree without an install
|
|
14
|
+
__version__ = "0.0.0"
|
|
@@ -51,12 +51,30 @@ def load_entrypoint_signatures(path: str | Path = ENTRYPOINTS_FILE) -> _Signatur
|
|
|
51
51
|
return _Signatures(decorators=tuple(data.get("decorators", [])), calls=tuple(data.get("calls", [])))
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
_SKIP_DIRS = frozenset({".git", ".venv", "venv", "node_modules", "__pycache__", ".mypy_cache", ".pytest_cache"})
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _read_python_files(root: Path) -> dict[str, str]:
|
|
58
|
+
"""{relative path: content} for .py files under root, skipping noise dirs and
|
|
59
|
+
symlinks that escape the tree."""
|
|
60
|
+
root = root.resolve()
|
|
61
|
+
files: dict[str, str] = {}
|
|
62
|
+
for path in root.rglob("*.py"):
|
|
63
|
+
rel = path.relative_to(root)
|
|
64
|
+
if any(part in _SKIP_DIRS for part in rel.parts):
|
|
65
|
+
continue
|
|
66
|
+
try:
|
|
67
|
+
if not path.resolve().is_relative_to(root):
|
|
68
|
+
continue # symlink escaping the tree
|
|
69
|
+
files[str(rel)] = path.read_text(encoding="utf-8")
|
|
70
|
+
except (OSError, UnicodeDecodeError, ValueError):
|
|
71
|
+
continue
|
|
72
|
+
return files
|
|
57
73
|
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
|
|
75
|
+
def build_repo_model_from_dir(root: str | Path, *, signatures: _Signatures | None = None) -> RepoModel:
|
|
76
|
+
"""Build a RepoModel by reading the .py files under a directory."""
|
|
77
|
+
return build_repo_model(root, _read_python_files(Path(root)), signatures=signatures)
|
|
60
78
|
|
|
61
79
|
|
|
62
80
|
def build_repo_model(root: str | Path, files: dict[str, str], *, signatures: _Signatures | None = None) -> RepoModel:
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""codejury CLI.
|
|
2
|
+
|
|
3
|
+
Two entry points matched to their nature:
|
|
4
|
+
|
|
5
|
+
- ``audit`` runs the coded diff engine over a unified diff: a single balanced
|
|
6
|
+
call (standard) or the adversarial Finder/Challenger/Judge pass.
|
|
7
|
+
- ``full-review`` scaffolds a workspace and prints the methodology for an
|
|
8
|
+
interactive agent to run a whole-repo review (it does not run an LLM pipeline,
|
|
9
|
+
which a single call cannot do for a whole codebase).
|
|
10
|
+
|
|
11
|
+
``dry-run`` exercises the diff engine with a mock provider and no API key.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import subprocess
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
import dataclasses
|
|
21
|
+
|
|
22
|
+
from codejury.diff.debate import AdversarialAuditRunner
|
|
23
|
+
from codejury.diff.engine import AuditRunner
|
|
24
|
+
from codejury.diff.findings_filter import FindingsFilter
|
|
25
|
+
from codejury.diff.report import gate, render
|
|
26
|
+
from codejury.diff.rules import allowed_categories, normalize_category
|
|
27
|
+
from codejury.domain.finding import Finding
|
|
28
|
+
|
|
29
|
+
# A diff larger than this is audited file-by-file so a big PR does not overflow
|
|
30
|
+
# the model's context and silently truncate the reply.
|
|
31
|
+
_MAX_DIFF_CHARS = 60_000
|
|
32
|
+
from codejury.fullreview.scaffold import scaffold
|
|
33
|
+
from codejury.providers.factory import (
|
|
34
|
+
DEFAULT_API_BASE,
|
|
35
|
+
DEFAULT_API_KEY,
|
|
36
|
+
DEFAULT_CHALLENGER_MODEL,
|
|
37
|
+
DEFAULT_FINDER_MODEL,
|
|
38
|
+
DEFAULT_JUDGE_MODEL,
|
|
39
|
+
DEFAULT_MODEL,
|
|
40
|
+
PROVIDERS,
|
|
41
|
+
make_provider,
|
|
42
|
+
)
|
|
43
|
+
from codejury.providers.mock import MockProvider
|
|
44
|
+
|
|
45
|
+
_FORMATS = ("text", "markdown", "json", "sarif")
|
|
46
|
+
_FAIL_ON = ("critical", "high", "medium", "low")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _split_diff_by_file(diff: str) -> list[str]:
|
|
50
|
+
"""Split a unified diff into one diff per file (`diff --git ...` boundaries)."""
|
|
51
|
+
chunks: list[str] = []
|
|
52
|
+
cur: list[str] = []
|
|
53
|
+
for line in diff.splitlines(keepends=True):
|
|
54
|
+
if line.startswith("diff --git ") and cur:
|
|
55
|
+
chunks.append("".join(cur))
|
|
56
|
+
cur = []
|
|
57
|
+
cur.append(line)
|
|
58
|
+
if cur:
|
|
59
|
+
chunks.append("".join(cur))
|
|
60
|
+
return chunks or ([diff] if diff.strip() else [])
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _dedup_findings(findings: list[Finding]) -> list[Finding]:
|
|
64
|
+
seen: set = set()
|
|
65
|
+
out: list[Finding] = []
|
|
66
|
+
for f in findings:
|
|
67
|
+
k = (f.file, f.line, f.category, f.description)
|
|
68
|
+
if k not in seen:
|
|
69
|
+
seen.add(k)
|
|
70
|
+
out.append(f)
|
|
71
|
+
return out
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def audit_diff(
|
|
75
|
+
diff: str,
|
|
76
|
+
*,
|
|
77
|
+
provider,
|
|
78
|
+
model: str,
|
|
79
|
+
mode: str = "standard",
|
|
80
|
+
max_rounds: int = 3,
|
|
81
|
+
filter_findings: bool = True,
|
|
82
|
+
finder_model: str | None = None,
|
|
83
|
+
challenger_model: str | None = None,
|
|
84
|
+
judge_model: str | None = None,
|
|
85
|
+
) -> tuple[list[Finding], list[tuple[Finding, str]]]:
|
|
86
|
+
"""Audit a diff and return (kept findings, dropped (finding, reason)).
|
|
87
|
+
|
|
88
|
+
A diff over the size budget is audited one file at a time so it does not
|
|
89
|
+
overflow the context. Finding categories are normalized to the rule-id set."""
|
|
90
|
+
def _run_one(d: str) -> list[Finding]:
|
|
91
|
+
if mode == "adversarial":
|
|
92
|
+
return AdversarialAuditRunner(
|
|
93
|
+
provider=provider, model=model,
|
|
94
|
+
finder_model=finder_model, challenger_model=challenger_model, judge_model=judge_model,
|
|
95
|
+
).run(d, max_rounds=max_rounds).findings
|
|
96
|
+
return AuditRunner(provider=provider, model=model).run(d)
|
|
97
|
+
|
|
98
|
+
if len(diff) > _MAX_DIFF_CHARS:
|
|
99
|
+
chunks = _split_diff_by_file(diff)
|
|
100
|
+
findings = _dedup_findings([f for c in chunks for f in _run_one(c)])
|
|
101
|
+
else:
|
|
102
|
+
findings = _run_one(diff)
|
|
103
|
+
|
|
104
|
+
allowed = set(allowed_categories())
|
|
105
|
+
findings = [dataclasses.replace(f, category=normalize_category(f.category, allowed)) for f in findings]
|
|
106
|
+
if filter_findings:
|
|
107
|
+
return FindingsFilter().filter(findings)
|
|
108
|
+
return findings, []
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _read_diff(args) -> str:
|
|
112
|
+
if args.diff_file:
|
|
113
|
+
with open(args.diff_file, encoding="utf-8") as f:
|
|
114
|
+
return f.read()
|
|
115
|
+
if args.git_range:
|
|
116
|
+
return subprocess.run(
|
|
117
|
+
["git", "-C", args.repo or ".", "diff", args.git_range],
|
|
118
|
+
capture_output=True, text=True, check=True,
|
|
119
|
+
).stdout
|
|
120
|
+
return sys.stdin.read()
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _dry_run_diff() -> str:
|
|
124
|
+
return "+++ b/app.py\n@@ -0,0 +1 @@\n+cursor.execute('SELECT * FROM u WHERE n=' + name)\n"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def main(argv: list[str] | None = None) -> int:
|
|
128
|
+
parser = argparse.ArgumentParser(prog="codejury")
|
|
129
|
+
sub = parser.add_subparsers(dest="command")
|
|
130
|
+
|
|
131
|
+
sub.add_parser("dry-run", help="run the diff engine with a mock provider, no key")
|
|
132
|
+
|
|
133
|
+
a = sub.add_parser("audit", help="audit a unified diff for security findings")
|
|
134
|
+
a.add_argument("--diff-file", default=None, help="unified diff file (default: read stdin)")
|
|
135
|
+
a.add_argument("--repo", default=None, help="repo path for --git-range")
|
|
136
|
+
a.add_argument("--git-range", default=None, help="git range to diff, e.g. origin/main...HEAD")
|
|
137
|
+
a.add_argument("--mode", choices=("standard", "adversarial"), default="standard")
|
|
138
|
+
a.add_argument("--rounds", type=int, default=3, help="adversarial debate rounds")
|
|
139
|
+
a.add_argument("--provider", choices=PROVIDERS, default="anthropic")
|
|
140
|
+
a.add_argument("--model", default=DEFAULT_MODEL)
|
|
141
|
+
a.add_argument("--finder-model", default=DEFAULT_FINDER_MODEL, help="adversarial: finder role model (default: --model)")
|
|
142
|
+
a.add_argument("--challenger-model", default=DEFAULT_CHALLENGER_MODEL, help="adversarial: challenger role model")
|
|
143
|
+
a.add_argument("--judge-model", default=DEFAULT_JUDGE_MODEL, help="adversarial: judge role model")
|
|
144
|
+
a.add_argument("--api-base", default=DEFAULT_API_BASE)
|
|
145
|
+
a.add_argument("--api-key", default=DEFAULT_API_KEY)
|
|
146
|
+
a.add_argument("--retries", type=int, default=2, help="provider retry attempts on transient failure")
|
|
147
|
+
a.add_argument("--format", choices=_FORMATS, default="text", dest="fmt")
|
|
148
|
+
a.add_argument("--no-filter", action="store_true", help="skip the false-positive filter")
|
|
149
|
+
a.add_argument("--fail-on", choices=_FAIL_ON, default=None, dest="fail_on")
|
|
150
|
+
|
|
151
|
+
fr = sub.add_parser("full-review", help="scaffold a whole-repo review for an interactive agent")
|
|
152
|
+
fr.add_argument("directory", help="target repository to review")
|
|
153
|
+
fr.add_argument("--workspace", default="codejury-review", help="where to create the review workspace")
|
|
154
|
+
|
|
155
|
+
args = parser.parse_args(argv)
|
|
156
|
+
try:
|
|
157
|
+
return _dispatch(args, parser)
|
|
158
|
+
except Exception as exc:
|
|
159
|
+
print(f"{args.command or 'codejury'} failed: {exc}", file=sys.stderr)
|
|
160
|
+
return 1
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _dispatch(args, parser) -> int:
|
|
164
|
+
if args.command == "audit":
|
|
165
|
+
provider = make_provider(args.provider, api_key=args.api_key, api_base=args.api_base, retries=args.retries)
|
|
166
|
+
kept, _ = audit_diff(
|
|
167
|
+
_read_diff(args), provider=provider, model=args.model,
|
|
168
|
+
mode=args.mode, max_rounds=args.rounds, filter_findings=not args.no_filter,
|
|
169
|
+
finder_model=args.finder_model, challenger_model=args.challenger_model, judge_model=args.judge_model,
|
|
170
|
+
)
|
|
171
|
+
print(render(args.fmt, kept))
|
|
172
|
+
return 1 if gate(kept, args.fail_on) else 0
|
|
173
|
+
|
|
174
|
+
if args.command == "full-review":
|
|
175
|
+
res = scaffold(args.directory, args.workspace)
|
|
176
|
+
print(f"Workspace: {res.workspace}", file=sys.stderr)
|
|
177
|
+
print(f"Seeded {res.entrypoints} entrypoints into {res.workspace}/api/_entrypoints.md", file=sys.stderr)
|
|
178
|
+
print(f"Memory: {res.memory_path}", file=sys.stderr)
|
|
179
|
+
print("\nRun this review with an interactive agent (Claude Code / Codex) using the methodology below.\n")
|
|
180
|
+
print(res.methodology)
|
|
181
|
+
return 0
|
|
182
|
+
|
|
183
|
+
if args.command in (None, "dry-run"):
|
|
184
|
+
kept, _ = audit_diff(
|
|
185
|
+
_dry_run_diff(),
|
|
186
|
+
provider=MockProvider(default='{"findings": [{"file": "app.py", "line": 1, "severity": "HIGH", '
|
|
187
|
+
'"category": "sql_injection", "description": "[mock] no backend called", '
|
|
188
|
+
'"confidence": 0.9}]}'),
|
|
189
|
+
model="mock",
|
|
190
|
+
)
|
|
191
|
+
print(render("text", kept))
|
|
192
|
+
return 0
|
|
193
|
+
|
|
194
|
+
parser.print_help()
|
|
195
|
+
return 1
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
199
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Full Security Review — Agent Methodology
|
|
2
|
+
|
|
3
|
+
A whole-repository security audit, run by an interactive coding agent (Claude
|
|
4
|
+
Code, Codex, etc.), not a one-shot LLM call. It traverses the codebase from its
|
|
5
|
+
API entrypoints, reasons across files, verifies issues with a real PoC, and
|
|
6
|
+
iterates over multiple rounds with a persistent memory. One round is roughly
|
|
7
|
+
30 minutes; run as many rounds as needed.
|
|
8
|
+
|
|
9
|
+
Target repository: the directory you were given.
|
|
10
|
+
Workspace: `<workspace>/<project>/` (created for you), holding `api/`,
|
|
11
|
+
`issues/`, `analysis/`, and `security-review-memory.md`.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## On start (do this first)
|
|
16
|
+
|
|
17
|
+
1. Read `security-review-memory.md` in the workspace if it exists:
|
|
18
|
+
- skip every pattern under "Confirmed false positives";
|
|
19
|
+
- do not re-report anything under "Fixed";
|
|
20
|
+
- weight the files under "High-risk areas" more heavily.
|
|
21
|
+
2. Read `api/_entrypoints.md` (seeded for you from a deterministic scan) as the
|
|
22
|
+
starting map of HTTP routes and CLI commands.
|
|
23
|
+
3. Read the relevant rule files under the shipped `rules/` for the target's stack
|
|
24
|
+
(sql-injection, idor, ssrf, authentication-jwt, insecure-deserialization, ...).
|
|
25
|
+
|
|
26
|
+
## Analysis
|
|
27
|
+
|
|
28
|
+
Start from the API entrypoints and read the implementation of each one. For every
|
|
29
|
+
endpoint ask:
|
|
30
|
+
|
|
31
|
+
- What inputs can the attacker control?
|
|
32
|
+
- Is authentication, authorization, signature verification, tenant isolation, or
|
|
33
|
+
a business-state check bypassed or missing?
|
|
34
|
+
- IDOR: can a user reach another user's, tenant's, or service's resource by a
|
|
35
|
+
supplied id?
|
|
36
|
+
- Do privileged operations (payment, signing, approval, state change) allow state
|
|
37
|
+
bypass or replay (no nonce / time window)?
|
|
38
|
+
- Mass assignment: is a user-controlled body bound wholesale into a model?
|
|
39
|
+
- Signature: is a caller-supplied key trusted as the trust anchor?
|
|
40
|
+
|
|
41
|
+
Record the API inventory in `api/` (one file per module: route + auth method +
|
|
42
|
+
review status ✅/⚠️/❌). Record architecture understanding and high-risk paths in
|
|
43
|
+
`analysis/`.
|
|
44
|
+
|
|
45
|
+
## Scope
|
|
46
|
+
|
|
47
|
+
Report only HIGH / CRITICAL, exploitable, high-confidence issues. **Do not report**
|
|
48
|
+
(regardless of severity): dependency CVEs, style or best-practice notes,
|
|
49
|
+
speculative issues you cannot tie to a concrete exploit, and risks that only
|
|
50
|
+
matter if production config is leaked.
|
|
51
|
+
|
|
52
|
+
## Recording an issue
|
|
53
|
+
|
|
54
|
+
Write one `issues/<name>.md` per confirmed issue. Do not write an issue you cannot
|
|
55
|
+
confirm with high confidence. Each must have:
|
|
56
|
+
|
|
57
|
+
```markdown
|
|
58
|
+
# <title>
|
|
59
|
+
|
|
60
|
+
- Risk: HIGH | CRITICAL
|
|
61
|
+
- Type: IDOR | auth bypass | signature flaw | business logic | ...
|
|
62
|
+
- Endpoint: `<METHOD> <path>`
|
|
63
|
+
|
|
64
|
+
## Analysis
|
|
65
|
+
(cite exact file paths and line numbers)
|
|
66
|
+
|
|
67
|
+
## Attack path
|
|
68
|
+
(end-to-end, actionable steps)
|
|
69
|
+
|
|
70
|
+
## PoC
|
|
71
|
+
(a curl command or script that actually triggers it)
|
|
72
|
+
|
|
73
|
+
## Verification
|
|
74
|
+
(result of actually running the PoC in a sandbox / dev environment)
|
|
75
|
+
|
|
76
|
+
## Fix
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## PoC verification (human in the loop)
|
|
80
|
+
|
|
81
|
+
Confirm each issue by running the PoC against a sandbox / dev environment. When
|
|
82
|
+
you need something only the operator has, stop and ask:
|
|
83
|
+
|
|
84
|
+
- an auth cookie or token,
|
|
85
|
+
- an MFA step,
|
|
86
|
+
- specific test data or an account.
|
|
87
|
+
|
|
88
|
+
Never run a PoC against production, and never use real credentials or perform a
|
|
89
|
+
destructive action without the operator's explicit go-ahead.
|
|
90
|
+
|
|
91
|
+
## Iteration
|
|
92
|
+
|
|
93
|
+
Each round, read the workspace history first and do not repeat finished work.
|
|
94
|
+
Process leftover TODOs; otherwise pick an unreviewed (❌) or to-deepen (⚠️)
|
|
95
|
+
endpoint from the API inventory. When every endpoint is ✅ and there are no TODOs,
|
|
96
|
+
report the review complete.
|
|
97
|
+
|
|
98
|
+
## On finish
|
|
99
|
+
|
|
100
|
+
Append a row to the audit history in `security-review-memory.md`, and ask the
|
|
101
|
+
operator which findings were false positives. Record those under "Confirmed false
|
|
102
|
+
positives" so future rounds skip them.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Security Review Memory — <project>
|
|
2
|
+
|
|
3
|
+
> Maintained by the security-review agent. Read at the start of every round,
|
|
4
|
+
> updated at the end. It skips confirmed false positives, avoids re-reporting
|
|
5
|
+
> fixed issues, and focuses on historically risky areas.
|
|
6
|
+
|
|
7
|
+
## Confirmed false positives (skip, do not report)
|
|
8
|
+
|
|
9
|
+
<!-- FP-001 <short description>
|
|
10
|
+
- Date: YYYY-MM-DD
|
|
11
|
+
- Path/pattern: `tests/` or `apps/payment/mock_*.py`
|
|
12
|
+
- Type: sql_injection / auth_bypass / ...
|
|
13
|
+
- Why not a real issue: <reason>
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
## Fixed (do not report again)
|
|
17
|
+
|
|
18
|
+
<!-- FIXED-001 <issue title>
|
|
19
|
+
- Date / commit: YYYY-MM-DD / abc1234
|
|
20
|
+
- Original issue: <summary>
|
|
21
|
+
-->
|
|
22
|
+
|
|
23
|
+
## High-risk areas (weight every round)
|
|
24
|
+
|
|
25
|
+
<!-- - `<path>` — <reason, e.g. past auth bypass> -->
|
|
26
|
+
|
|
27
|
+
## Audit history
|
|
28
|
+
|
|
29
|
+
| Date | Mode | HIGH | MEDIUM | Notes |
|
|
30
|
+
|------|------|------|--------|-------|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-security-review
|
|
3
|
+
description: "Application security rules for reviewing code for exploitable vulnerabilities. Use when reviewing a diff or a codebase for security issues, or when writing code that handles untrusted input, authentication, authorization, file paths, database queries, network requests, deserialization, or cryptography. Read the matching rule before judging whether code is vulnerable."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Code Security Review Rules
|
|
7
|
+
|
|
8
|
+
Application-security rules, one file per weakness class under `rules/`, named by
|
|
9
|
+
the specific weakness (CWE-style). Each rule states impact, the markers to hunt
|
|
10
|
+
(`triggers`), and vulnerable-vs-secure examples. The diff-audit engine injects the
|
|
11
|
+
rules relevant to a change into the prompt; the full-review agent reads them for
|
|
12
|
+
the target's stack. A finding's `category` is one of these ids.
|
|
13
|
+
|
|
14
|
+
## Rules by OWASP category
|
|
15
|
+
|
|
16
|
+
### A01 Broken Access Control
|
|
17
|
+
- `missing-authorization` (CWE-862)
|
|
18
|
+
- `insecure-direct-object-reference` (CWE-639)
|
|
19
|
+
- `cross-site-request-forgery` (CWE-352)
|
|
20
|
+
- `path-traversal` (CWE-22)
|
|
21
|
+
- `open-redirect` (CWE-601)
|
|
22
|
+
|
|
23
|
+
### A02 Cryptographic Failures
|
|
24
|
+
- `insecure-cryptography` (CWE-327)
|
|
25
|
+
- `insecure-transport` (CWE-319)
|
|
26
|
+
- `hardcoded-secrets` (CWE-798)
|
|
27
|
+
- `information-exposure` (CWE-200/532)
|
|
28
|
+
|
|
29
|
+
### A03 Injection
|
|
30
|
+
- `sql-injection` (CWE-89)
|
|
31
|
+
- `command-injection` (CWE-78)
|
|
32
|
+
- `code-injection` (CWE-94)
|
|
33
|
+
- `cross-site-scripting` (CWE-79)
|
|
34
|
+
- `xml-external-entity` (CWE-611)
|
|
35
|
+
- `server-side-template-injection` (CWE-1336)
|
|
36
|
+
- `http-response-splitting` (CWE-113)
|
|
37
|
+
|
|
38
|
+
### A04 Insecure Design / Business Logic
|
|
39
|
+
- `business-logic` (CWE-840)
|
|
40
|
+
- `replay-attack` (CWE-294)
|
|
41
|
+
- `race-condition` (CWE-362)
|
|
42
|
+
- `mass-assignment` (CWE-915)
|
|
43
|
+
|
|
44
|
+
### A07 Identification and Authentication
|
|
45
|
+
- `improper-authentication` (CWE-287)
|
|
46
|
+
- `jwt-validation` (CWE-347)
|
|
47
|
+
- `session-fixation` (CWE-384)
|
|
48
|
+
|
|
49
|
+
### A08 Software and Data Integrity
|
|
50
|
+
- `insecure-deserialization` (CWE-502)
|
|
51
|
+
|
|
52
|
+
### A10 Server-Side Request Forgery
|
|
53
|
+
- `server-side-request-forgery` (CWE-918)
|
|
54
|
+
|
|
55
|
+
Report only real, exploitable, high-confidence issues with a concrete exploit
|
|
56
|
+
path. Do not report dependency CVEs, style, speculation, or config-leak-only
|
|
57
|
+
risks. The set is data: add a class by dropping a new `rules/<id>.md` with the
|
|
58
|
+
same frontmatter (id, title, impact, tags, triggers) and examples.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: business-logic
|
|
3
|
+
title: Business Logic Flaw
|
|
4
|
+
impact: HIGH
|
|
5
|
+
tags: [cwe-840, cwe-841, owasp-a04]
|
|
6
|
+
triggers: ["price", "amount", "quantity", "balance", "status", "approve", "discount", "total =", "request.json[\"price\"", "if status =="]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Business Logic Flaw
|
|
10
|
+
|
|
11
|
+
A stateful workflow trusts client-supplied values or does not enforce its own rules: a client-set price/amount/quantity, a state-machine step reached without its prerequisites, an approval or limit bypassed. Validate amounts and state transitions server-side from trusted data, and enforce the workflow's invariants.
|
|
12
|
+
|
|
13
|
+
### Python
|
|
14
|
+
Vulnerable:
|
|
15
|
+
```python
|
|
16
|
+
total = request.json["price"] * request.json["qty"] # client sets the price
|
|
17
|
+
order.charge(total)
|
|
18
|
+
```
|
|
19
|
+
Secure:
|
|
20
|
+
```python
|
|
21
|
+
price = Product.objects.get(id=pid).price # price from the server
|
|
22
|
+
total = price * validate_qty(request.json["qty"])
|
|
23
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: code-injection
|
|
3
|
+
title: Code Injection
|
|
4
|
+
impact: CRITICAL
|
|
5
|
+
tags: [cwe-94, owasp-a03, injection, rce]
|
|
6
|
+
triggers: ["eval(", "exec(", "compile(", "pickle.loads", "new Function", "setTimeout(\"", "vm.runInContext"]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Code Injection
|
|
10
|
+
|
|
11
|
+
Passing untrusted input to a language evaluation primitive (eval, exec, compile, dynamic import, JS Function) lets an attacker execute arbitrary code. Never evaluate untrusted input; parse it with a data-only parser or dispatch through an allowlist.
|
|
12
|
+
|
|
13
|
+
### Python
|
|
14
|
+
Vulnerable:
|
|
15
|
+
```python
|
|
16
|
+
result = eval(request.args["expr"])
|
|
17
|
+
exec(user_supplied_code)
|
|
18
|
+
```
|
|
19
|
+
Secure:
|
|
20
|
+
```python
|
|
21
|
+
import ast
|
|
22
|
+
result = ast.literal_eval(request.args["expr"]) # data only, no code
|
|
23
|
+
```
|