codejury 0.10.1__tar.gz → 0.10.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.10.3/PKG-INFO +241 -0
- codejury-0.10.3/README.md +211 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/__init__.py +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/agents/__init__.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/agents/debate.py +3 -3
- {codejury-0.10.1 → codejury-0.10.3}/codejury/agents/mock.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/agents/parsing.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/agents/refuter.py +3 -3
- {codejury-0.10.1 → codejury-0.10.3}/codejury/agents/verifier.py +4 -4
- {codejury-0.10.1 → codejury-0.10.3}/codejury/analysis/__init__.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/analysis/provenance.py +5 -5
- {codejury-0.10.1 → codejury-0.10.3}/codejury/analysis/taint.py +6 -6
- {codejury-0.10.1 → codejury-0.10.3}/codejury/assembly.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/baseline.py +9 -9
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/business_logic.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/dependency_config.yaml +3 -3
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/excessive_agency.yaml +3 -3
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/input_validation.yaml +6 -6
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/insecure_output_handling.yaml +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/prompt_injection.yaml +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/secrets.yaml +5 -5
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ag_fixed_enum_safe.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ag_model_confirmed_vuln.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/authn_sha256_checksum_safe.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/deserialize_json_safe.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/deserialize_pickle_vuln.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ioh_json_response_safe.yaml +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ioh_output_to_sql_vuln.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/pi_user_content_concat_safe.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/session_secure_cookie_safe.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/sql_constant_concat_safe.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ssrf_constant_url_safe.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/xfile_idor_no_check_vuln.yaml +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/xfile_idor_owner_checked_safe.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/xfile_path_sanitized_safe.yaml +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/xfile_path_tainted_vuln.yaml +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/xss_textcontent_safe.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/suppressions.yaml +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/taint.yaml +4 -4
- {codejury-0.10.1 → codejury-0.10.3}/codejury/domain/__init__.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/domain/artifact.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/domain/capability.py +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/domain/context.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/domain/observation.py +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/domain/result.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/evaluation.py +6 -6
- codejury-0.10.3/codejury/infrastructure/__init__.py +4 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/infrastructure/cache.py +4 -4
- codejury-0.10.3/codejury/integrations/__init__.py +1 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/orchestrators/__init__.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/orchestrators/adaptive.py +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/orchestrators/base.py +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/codejury/orchestrators/challenge.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/orchestrators/debate.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/orchestrators/pipeline.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/orchestrators/reflexion.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/orchestrators/single.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/orchestrators/taint_gate.py +3 -3
- {codejury-0.10.1 → codejury-0.10.3}/codejury/providers/__init__.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/providers/anthropic.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/providers/litellm.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/providers/mock.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/providers/openai.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/providers/retry.py +5 -5
- {codejury-0.10.1 → codejury-0.10.3}/codejury/reporting.py +4 -4
- {codejury-0.10.1 → codejury-0.10.3}/codejury/sources/__init__.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/sources/callers.py +6 -6
- {codejury-0.10.1 → codejury-0.10.3}/codejury/sources/chunker.py +3 -3
- {codejury-0.10.1 → codejury-0.10.3}/codejury/sources/diff.py +6 -6
- {codejury-0.10.1 → codejury-0.10.3}/codejury/sources/function.py +5 -5
- {codejury-0.10.1 → codejury-0.10.3}/codejury/sources/mock.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/sources/repo.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/suppression.py +8 -8
- {codejury-0.10.1 → codejury-0.10.3}/codejury/tasks/__init__.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/codejury/tasks/base.py +2 -2
- codejury-0.10.3/codejury.egg-info/PKG-INFO +241 -0
- {codejury-0.10.1 → codejury-0.10.3}/pyproject.toml +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_cache.py +1 -1
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_taint.py +2 -2
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_taint_gate.py +2 -2
- codejury-0.10.1/PKG-INFO +0 -227
- codejury-0.10.1/README.md +0 -197
- codejury-0.10.1/codejury/infrastructure/__init__.py +0 -4
- codejury-0.10.1/codejury/integrations/__init__.py +0 -1
- codejury-0.10.1/codejury.egg-info/PKG-INFO +0 -227
- {codejury-0.10.1 → codejury-0.10.3}/LICENSE +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/agents/base.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/cli.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/authentication.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/authorization.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/crypto.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/data_protection.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/error_logging.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/output_encoding.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/capabilities/session.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ag_allowlist_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ag_arbitrary_tool_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ag_destructive_no_confirm_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ag_human_approval_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/authn_bcrypt_password.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/authn_jwt_noverify_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/authn_jwt_verified_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/authn_sha256_password.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/authn_weak_hash_indirect_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/authz_idor_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/authz_owner_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/business_logic_price_tamper_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/business_logic_server_checked_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/cmdi_fixed_argv_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/cmdi_ossystem_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/cmdi_subprocess_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/crypto_aesgcm_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/crypto_ecb_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/data_protection_plaintext_pii_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/data_protection_tokenized_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/dependency_config_tls_verify_off_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/dependency_config_tls_verify_on_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/error_logging_redacted_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/error_logging_secret_leak_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ioh_escaped_output_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ioh_exec_output_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ioh_innerhtml_output_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ioh_schema_validated_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/literal_eval_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/path_basename_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/path_contained_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/path_traversal_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/pi_delimited_data_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/pi_format_role_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/pi_indirect_rag_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/pi_system_concat_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/pi_user_role_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/secrets_env_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/secrets_hardcoded_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/session_fixation_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/sqli_format_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/sqli_fstring_query.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/sqli_indirect_var_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/sqli_parameterized_query.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ssrf_allowlist_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ssrf_substring_allowlist_bypass_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/ssrf_user_url_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/xss_innerhtml_constant_safe.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/golden/xss_innerhtml_vuln.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/tasks/audit_diff_debate.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/data/tasks/quick_scan_single.yaml +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/infrastructure/json_parse.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/integrations/github.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/providers/base.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/providers/openai_format.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/resources.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/sources/base.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury/tasks/registry.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury.egg-info/SOURCES.txt +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury.egg-info/dependency_links.txt +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury.egg-info/entry_points.txt +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury.egg-info/requires.txt +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/codejury.egg-info/top_level.txt +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/setup.cfg +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_adaptive.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_anthropic_provider.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_assembly.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_audit_pipeline.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_baseline.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_callers.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_capability.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_challenge.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_cli_audit.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_context.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_debate_agents.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_debate_orchestrator.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_diff_source.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_evaluation.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_function_source.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_integrations.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_json_parse.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_litellm_provider.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_openai_provider.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_orchestrator.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_parsing.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_pipeline_orchestrator.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_provenance.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_reflexion_orchestrator.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_repo_source.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_reporting.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_retry_provider.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_review_fixes.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_sarif.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_suppression.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_taint_crossfile.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_tasks.py +0 -0
- {codejury-0.10.1 → codejury-0.10.3}/tests/test_verifier.py +0 -0
codejury-0.10.3/PKG-INFO
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codejury
|
|
3
|
+
Version: 0.10.3
|
|
4
|
+
Summary: General-purpose Application Security AI audit framework: five-layer architecture, capabilities as first-class data
|
|
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
|
+
Provides-Extra: anthropic
|
|
21
|
+
Requires-Dist: anthropic>=0.40; extra == "anthropic"
|
|
22
|
+
Provides-Extra: openai
|
|
23
|
+
Requires-Dist: openai>=1.0; extra == "openai"
|
|
24
|
+
Provides-Extra: litellm
|
|
25
|
+
Requires-Dist: litellm>=1.0; extra == "litellm"
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
28
|
+
Requires-Dist: jsonschema>=4.0; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# codejury
|
|
32
|
+
|
|
33
|
+
An AI security auditor for code whose knowledge lives in versioned YAML, not in
|
|
34
|
+
prompts. It reviews a diff or a whole repository against the OWASP ASVS and the
|
|
35
|
+
OWASP LLM Top 10, and reports a verdict per dimension: both what is **vulnerable**
|
|
36
|
+
and what is **verified safe**.
|
|
37
|
+
|
|
38
|
+
The name is the idea. Code goes before a "jury" of adversarial roles, Finder,
|
|
39
|
+
Challenger, and Judge, that argue and converge on a verdict.
|
|
40
|
+
|
|
41
|
+
## Why it is built this way
|
|
42
|
+
|
|
43
|
+
- **Knowledge is data.** Each OWASP ASVS area, and now the OWASP LLM Top 10, is a
|
|
44
|
+
YAML capability with safe patterns, anti-patterns, CWE ids, and examples. It is
|
|
45
|
+
versioned, reviewable in a PR, and editable by non-engineers, so the framework
|
|
46
|
+
core stays small.
|
|
47
|
+
- **Verdicts, not just alerts.** Every capability yields `SECURE`, `VULNERABLE`,
|
|
48
|
+
`PARTIAL`, or `NOT_PRESENT`, so a report shows what was checked and passed, not
|
|
49
|
+
only what failed.
|
|
50
|
+
- **Composable.** Seven orchestration strategies, three model backends, and diff,
|
|
51
|
+
repo, or function inputs are chosen per run and mix freely.
|
|
52
|
+
- **Deterministic.** Providers run at temperature 0 and verdicts are cached, so
|
|
53
|
+
the same input gives the same result.
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install codejury # core and CLI
|
|
59
|
+
pip install 'codejury[anthropic]' # the provider you will use: anthropic, openai, or litellm
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quickstart
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# No API key needed: prove the pipeline runs end to end with mock layers
|
|
66
|
+
codejury dry-run
|
|
67
|
+
|
|
68
|
+
# A real audit of your staged changes
|
|
69
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
70
|
+
git diff | codejury audit --provider anthropic
|
|
71
|
+
|
|
72
|
+
# CI gate: exit 1 if a high-severity issue is found
|
|
73
|
+
git diff origin/main... | codejury audit --fail-on high -
|
|
74
|
+
|
|
75
|
+
# Inline review comments on a GitHub pull request, needs GITHUB_TOKEN
|
|
76
|
+
git diff origin/main... | codejury audit --github your-org/your-repo#123 -
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Commands
|
|
80
|
+
|
|
81
|
+
| Command | What it does |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `codejury dry-run` | Run the mock pipeline with no key, a smoke test. |
|
|
84
|
+
| `codejury audit [diff]` | Audit a unified diff from a file or stdin (`-`). |
|
|
85
|
+
| `codejury scan <dir>` | Audit a whole directory tree, capability by capability. |
|
|
86
|
+
| `codejury run <task>` | Run a named task preset, see [Tasks](#tasks). |
|
|
87
|
+
| `codejury eval` | Score the golden cases and report precision, recall, and F1, overall and per capability. |
|
|
88
|
+
|
|
89
|
+
Shared flags: `--orchestrator`, `--provider {anthropic,openai,litellm}`,
|
|
90
|
+
`--model`, `--format {text,markdown,json,sarif}`.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Multi-round adversarial debate, rendered as Markdown
|
|
94
|
+
git diff | codejury audit --orchestrator debate --format markdown - > report.md
|
|
95
|
+
|
|
96
|
+
# Deep whole-repo scan, scoped to a few capabilities to bound the cost
|
|
97
|
+
codejury scan ./myrepo --only secrets,input_validation,crypto
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Orchestration strategies
|
|
101
|
+
|
|
102
|
+
`--orchestrator` chooses how the agents run. They mix freely with any provider,
|
|
103
|
+
model, and input.
|
|
104
|
+
|
|
105
|
+
| Strategy | What it does |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `single` | One verifier pass. The default for `audit`. |
|
|
108
|
+
| `pipeline` | One verifier, capability by capability. |
|
|
109
|
+
| `debate` | Finder, Challenger, and Judge argue across rounds. |
|
|
110
|
+
| `reflexion` | An actor and a critic iterate. |
|
|
111
|
+
| `challenge` | Verify, then a recall-safe refuter drops only provably-safe taint flags. |
|
|
112
|
+
| `taint` | Verify, then a static data-flow gate clears an `input_validation` finding only when provenance proves the value reaching the sink is constant, sanitized, or trusted. It uses cross-file caller and callee context and downgrades only on positive proof, so it removes false positives without dropping real findings. |
|
|
113
|
+
| `adaptive` | Run the cheap single verifier first and escalate to a full debate only when it pays off: any `VULNERABLE` verdict, or a low-confidence `PARTIAL`/`UNKNOWN` one. Clean, confident files pay a single model call. |
|
|
114
|
+
|
|
115
|
+
## CI and pull-request workflow
|
|
116
|
+
|
|
117
|
+
- `--fail-on {critical,high,medium,low}` exits 1 when a finding at or above that
|
|
118
|
+
severity is present, so the audit gates a build.
|
|
119
|
+
- `--github owner/repo#number` posts a review with inline comments on a pull
|
|
120
|
+
request, using `GITHUB_TOKEN`.
|
|
121
|
+
- `--baseline <report.json>` reports only findings new since a saved report. Save
|
|
122
|
+
the target branch once, then a PR shows only what it introduced, matched by a
|
|
123
|
+
line-tolerant fingerprint so shifted code is not re-reported. Combine with
|
|
124
|
+
`--fail-on` to gate on new issues only.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
git checkout main && codejury scan . --format json > baseline.json
|
|
128
|
+
git checkout pr-branch && codejury scan . --baseline baseline.json --fail-on high
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- `--format sarif` emits a SARIF 2.1.0 log that validates against the official
|
|
132
|
+
schema, for CI and security dashboards. Each problem with a code location
|
|
133
|
+
becomes a result carrying its capability as the rule id, the CWE, and a precise
|
|
134
|
+
location.
|
|
135
|
+
- Findings in known-noise categories such as availability and DoS, rate limiting,
|
|
136
|
+
and memory safety outside C and C++ are dropped by versioned rules in
|
|
137
|
+
`codejury/data/suppressions.yaml`. Disable with `--no-suppress`.
|
|
138
|
+
|
|
139
|
+
## Determinism and caching
|
|
140
|
+
|
|
141
|
+
Providers query at temperature 0, and `audit` and `scan` cache each verdict on a
|
|
142
|
+
hash of the normalized code, the in-scope capability fingerprints, and the
|
|
143
|
+
orchestration. Re-auditing unchanged code returns the recorded verdicts without
|
|
144
|
+
re-querying the model. Editing a capability YAML changes its fingerprint and
|
|
145
|
+
invalidates affected entries. Pass `--no-cache` to always re-query.
|
|
146
|
+
|
|
147
|
+
## Configuration
|
|
148
|
+
|
|
149
|
+
Provider keys are read from the environment. codejury does **not** auto-load
|
|
150
|
+
`.env`; copy `.env.example` and `source` it.
|
|
151
|
+
|
|
152
|
+
| Variable | Used by |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `ANTHROPIC_API_KEY` | `--provider anthropic` |
|
|
155
|
+
| `OPENAI_API_KEY` | `--provider openai` |
|
|
156
|
+
| `CODEJURY_API_BASE`, `CODEJURY_API_KEY`, `CODEJURY_MODEL` | defaults for `--api-base`, `--api-key`, and `--model`, for any provider |
|
|
157
|
+
|
|
158
|
+
The `CODEJURY_*` variables make a LiteLLM proxy a one-liner:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# with CODEJURY_API_BASE, CODEJURY_API_KEY, CODEJURY_MODEL in a sourced .env
|
|
162
|
+
git diff | codejury audit --provider litellm -
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Tasks
|
|
166
|
+
|
|
167
|
+
A task is a named preset of capabilities, orchestrator, provider, and model. It
|
|
168
|
+
lives in a YAML file. The API key always stays in the environment.
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
# mytasks/proxy_scan.yaml -> codejury run proxy_scan --tasks mytasks
|
|
172
|
+
name: proxy_scan
|
|
173
|
+
orchestrator: debate
|
|
174
|
+
provider: litellm
|
|
175
|
+
model: your-alias
|
|
176
|
+
api_base: https://litellm.example.com # key comes from CODEJURY_API_KEY
|
|
177
|
+
capabilities: [authn, input_validation, secrets] # omit to check all
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Capabilities
|
|
181
|
+
|
|
182
|
+
The library covers all 11 OWASP ASVS areas plus a growing set of OWASP LLM Top 10
|
|
183
|
+
capabilities, one YAML each under `codejury/data/capabilities/`. These ids are
|
|
184
|
+
what `--only` and a task's `capabilities:` accept:
|
|
185
|
+
|
|
186
|
+
`authn`, `authz`, `session`, `input_validation`, `output_encoding`, `crypto`,
|
|
187
|
+
`secrets`, `data_protection`, `error_logging`, `business_logic`,
|
|
188
|
+
`dependency_config`, `prompt_injection`, `insecure_output_handling`,
|
|
189
|
+
`excessive_agency`.
|
|
190
|
+
|
|
191
|
+
To tune for your codebase, edit these files, adding patterns or sharpening
|
|
192
|
+
wording. No code change is needed.
|
|
193
|
+
|
|
194
|
+
## eval
|
|
195
|
+
|
|
196
|
+
`codejury eval` scores the golden cases and reports a confusion matrix with
|
|
197
|
+
precision, recall, and F1, overall and per capability. It takes `--dataset <dir>`
|
|
198
|
+
for the golden directory, `--split <name>` to score only cases tagged with that
|
|
199
|
+
`split:` such as a held-out set, `--orchestrator` to measure any strategy, and
|
|
200
|
+
`--format {text,json}`. The JSON report is a stable, documented schema.
|
|
201
|
+
|
|
202
|
+
## Architecture
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
Layer 5 Task preset: source, capabilities, orchestrator, agents
|
|
206
|
+
Layer 4 Capability YAML domain knowledge: authn, authz, prompt_injection, ...
|
|
207
|
+
Layer 3 Orchestrator strategy: single, pipeline, debate, reflexion, challenge, taint, adaptive
|
|
208
|
+
Source input: diff, repo, function
|
|
209
|
+
Agent role: finder, challenger, judge, verifier, refuter
|
|
210
|
+
Layer 2 Provider model backend: anthropic, openai, litellm, mock
|
|
211
|
+
Layer 1 Infrastructure cross-cutting utilities: json parsing, verdict cache, retry
|
|
212
|
+
Analysis provenance and taint code-graph engine
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Layers talk only through typed data, and each is an abstract base class plus
|
|
216
|
+
implementations, so the axes of task, orchestration, model, and input compose
|
|
217
|
+
independently.
|
|
218
|
+
|
|
219
|
+
## Limitations
|
|
220
|
+
|
|
221
|
+
- **Prompts are a first pass.** Expect false positives and misses on real code.
|
|
222
|
+
Tune by editing the capability YAML and growing the golden set, and measure the
|
|
223
|
+
effect with `codejury eval`.
|
|
224
|
+
- **Local-pattern checks are sharper than data-flow ones.** A capability judged
|
|
225
|
+
from one spot, such as weak crypto or a hardcoded secret, is reliable. Taint
|
|
226
|
+
classes such as path traversal and SSRF over-flag in single-file review because
|
|
227
|
+
the verifier cannot see whether a value is attacker-controlled. `--orchestrator
|
|
228
|
+
taint` adds a static provenance gate that clears findings it can prove safe and
|
|
229
|
+
is recall-safe, but it is shallow on real code where the value flows through
|
|
230
|
+
object or module attributes. Decisive taint precision needs a deeper code
|
|
231
|
+
graph, which is in progress.
|
|
232
|
+
- **`scan` cost scales with files times capabilities.** It is a periodic deep
|
|
233
|
+
audit, not a quick check, so scope it with `--only`. Day to day, audit the diff.
|
|
234
|
+
|
|
235
|
+
## Development
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
python -m venv .venv && source .venv/bin/activate
|
|
239
|
+
pip install -e ".[dev]"
|
|
240
|
+
pytest
|
|
241
|
+
```
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# codejury
|
|
2
|
+
|
|
3
|
+
An AI security auditor for code whose knowledge lives in versioned YAML, not in
|
|
4
|
+
prompts. It reviews a diff or a whole repository against the OWASP ASVS and the
|
|
5
|
+
OWASP LLM Top 10, and reports a verdict per dimension: both what is **vulnerable**
|
|
6
|
+
and what is **verified safe**.
|
|
7
|
+
|
|
8
|
+
The name is the idea. Code goes before a "jury" of adversarial roles, Finder,
|
|
9
|
+
Challenger, and Judge, that argue and converge on a verdict.
|
|
10
|
+
|
|
11
|
+
## Why it is built this way
|
|
12
|
+
|
|
13
|
+
- **Knowledge is data.** Each OWASP ASVS area, and now the OWASP LLM Top 10, is a
|
|
14
|
+
YAML capability with safe patterns, anti-patterns, CWE ids, and examples. It is
|
|
15
|
+
versioned, reviewable in a PR, and editable by non-engineers, so the framework
|
|
16
|
+
core stays small.
|
|
17
|
+
- **Verdicts, not just alerts.** Every capability yields `SECURE`, `VULNERABLE`,
|
|
18
|
+
`PARTIAL`, or `NOT_PRESENT`, so a report shows what was checked and passed, not
|
|
19
|
+
only what failed.
|
|
20
|
+
- **Composable.** Seven orchestration strategies, three model backends, and diff,
|
|
21
|
+
repo, or function inputs are chosen per run and mix freely.
|
|
22
|
+
- **Deterministic.** Providers run at temperature 0 and verdicts are cached, so
|
|
23
|
+
the same input gives the same result.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install codejury # core and CLI
|
|
29
|
+
pip install 'codejury[anthropic]' # the provider you will use: anthropic, openai, or litellm
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quickstart
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# No API key needed: prove the pipeline runs end to end with mock layers
|
|
36
|
+
codejury dry-run
|
|
37
|
+
|
|
38
|
+
# A real audit of your staged changes
|
|
39
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
40
|
+
git diff | codejury audit --provider anthropic
|
|
41
|
+
|
|
42
|
+
# CI gate: exit 1 if a high-severity issue is found
|
|
43
|
+
git diff origin/main... | codejury audit --fail-on high -
|
|
44
|
+
|
|
45
|
+
# Inline review comments on a GitHub pull request, needs GITHUB_TOKEN
|
|
46
|
+
git diff origin/main... | codejury audit --github your-org/your-repo#123 -
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Commands
|
|
50
|
+
|
|
51
|
+
| Command | What it does |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `codejury dry-run` | Run the mock pipeline with no key, a smoke test. |
|
|
54
|
+
| `codejury audit [diff]` | Audit a unified diff from a file or stdin (`-`). |
|
|
55
|
+
| `codejury scan <dir>` | Audit a whole directory tree, capability by capability. |
|
|
56
|
+
| `codejury run <task>` | Run a named task preset, see [Tasks](#tasks). |
|
|
57
|
+
| `codejury eval` | Score the golden cases and report precision, recall, and F1, overall and per capability. |
|
|
58
|
+
|
|
59
|
+
Shared flags: `--orchestrator`, `--provider {anthropic,openai,litellm}`,
|
|
60
|
+
`--model`, `--format {text,markdown,json,sarif}`.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Multi-round adversarial debate, rendered as Markdown
|
|
64
|
+
git diff | codejury audit --orchestrator debate --format markdown - > report.md
|
|
65
|
+
|
|
66
|
+
# Deep whole-repo scan, scoped to a few capabilities to bound the cost
|
|
67
|
+
codejury scan ./myrepo --only secrets,input_validation,crypto
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Orchestration strategies
|
|
71
|
+
|
|
72
|
+
`--orchestrator` chooses how the agents run. They mix freely with any provider,
|
|
73
|
+
model, and input.
|
|
74
|
+
|
|
75
|
+
| Strategy | What it does |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `single` | One verifier pass. The default for `audit`. |
|
|
78
|
+
| `pipeline` | One verifier, capability by capability. |
|
|
79
|
+
| `debate` | Finder, Challenger, and Judge argue across rounds. |
|
|
80
|
+
| `reflexion` | An actor and a critic iterate. |
|
|
81
|
+
| `challenge` | Verify, then a recall-safe refuter drops only provably-safe taint flags. |
|
|
82
|
+
| `taint` | Verify, then a static data-flow gate clears an `input_validation` finding only when provenance proves the value reaching the sink is constant, sanitized, or trusted. It uses cross-file caller and callee context and downgrades only on positive proof, so it removes false positives without dropping real findings. |
|
|
83
|
+
| `adaptive` | Run the cheap single verifier first and escalate to a full debate only when it pays off: any `VULNERABLE` verdict, or a low-confidence `PARTIAL`/`UNKNOWN` one. Clean, confident files pay a single model call. |
|
|
84
|
+
|
|
85
|
+
## CI and pull-request workflow
|
|
86
|
+
|
|
87
|
+
- `--fail-on {critical,high,medium,low}` exits 1 when a finding at or above that
|
|
88
|
+
severity is present, so the audit gates a build.
|
|
89
|
+
- `--github owner/repo#number` posts a review with inline comments on a pull
|
|
90
|
+
request, using `GITHUB_TOKEN`.
|
|
91
|
+
- `--baseline <report.json>` reports only findings new since a saved report. Save
|
|
92
|
+
the target branch once, then a PR shows only what it introduced, matched by a
|
|
93
|
+
line-tolerant fingerprint so shifted code is not re-reported. Combine with
|
|
94
|
+
`--fail-on` to gate on new issues only.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
git checkout main && codejury scan . --format json > baseline.json
|
|
98
|
+
git checkout pr-branch && codejury scan . --baseline baseline.json --fail-on high
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- `--format sarif` emits a SARIF 2.1.0 log that validates against the official
|
|
102
|
+
schema, for CI and security dashboards. Each problem with a code location
|
|
103
|
+
becomes a result carrying its capability as the rule id, the CWE, and a precise
|
|
104
|
+
location.
|
|
105
|
+
- Findings in known-noise categories such as availability and DoS, rate limiting,
|
|
106
|
+
and memory safety outside C and C++ are dropped by versioned rules in
|
|
107
|
+
`codejury/data/suppressions.yaml`. Disable with `--no-suppress`.
|
|
108
|
+
|
|
109
|
+
## Determinism and caching
|
|
110
|
+
|
|
111
|
+
Providers query at temperature 0, and `audit` and `scan` cache each verdict on a
|
|
112
|
+
hash of the normalized code, the in-scope capability fingerprints, and the
|
|
113
|
+
orchestration. Re-auditing unchanged code returns the recorded verdicts without
|
|
114
|
+
re-querying the model. Editing a capability YAML changes its fingerprint and
|
|
115
|
+
invalidates affected entries. Pass `--no-cache` to always re-query.
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
Provider keys are read from the environment. codejury does **not** auto-load
|
|
120
|
+
`.env`; copy `.env.example` and `source` it.
|
|
121
|
+
|
|
122
|
+
| Variable | Used by |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `ANTHROPIC_API_KEY` | `--provider anthropic` |
|
|
125
|
+
| `OPENAI_API_KEY` | `--provider openai` |
|
|
126
|
+
| `CODEJURY_API_BASE`, `CODEJURY_API_KEY`, `CODEJURY_MODEL` | defaults for `--api-base`, `--api-key`, and `--model`, for any provider |
|
|
127
|
+
|
|
128
|
+
The `CODEJURY_*` variables make a LiteLLM proxy a one-liner:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# with CODEJURY_API_BASE, CODEJURY_API_KEY, CODEJURY_MODEL in a sourced .env
|
|
132
|
+
git diff | codejury audit --provider litellm -
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Tasks
|
|
136
|
+
|
|
137
|
+
A task is a named preset of capabilities, orchestrator, provider, and model. It
|
|
138
|
+
lives in a YAML file. The API key always stays in the environment.
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
# mytasks/proxy_scan.yaml -> codejury run proxy_scan --tasks mytasks
|
|
142
|
+
name: proxy_scan
|
|
143
|
+
orchestrator: debate
|
|
144
|
+
provider: litellm
|
|
145
|
+
model: your-alias
|
|
146
|
+
api_base: https://litellm.example.com # key comes from CODEJURY_API_KEY
|
|
147
|
+
capabilities: [authn, input_validation, secrets] # omit to check all
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Capabilities
|
|
151
|
+
|
|
152
|
+
The library covers all 11 OWASP ASVS areas plus a growing set of OWASP LLM Top 10
|
|
153
|
+
capabilities, one YAML each under `codejury/data/capabilities/`. These ids are
|
|
154
|
+
what `--only` and a task's `capabilities:` accept:
|
|
155
|
+
|
|
156
|
+
`authn`, `authz`, `session`, `input_validation`, `output_encoding`, `crypto`,
|
|
157
|
+
`secrets`, `data_protection`, `error_logging`, `business_logic`,
|
|
158
|
+
`dependency_config`, `prompt_injection`, `insecure_output_handling`,
|
|
159
|
+
`excessive_agency`.
|
|
160
|
+
|
|
161
|
+
To tune for your codebase, edit these files, adding patterns or sharpening
|
|
162
|
+
wording. No code change is needed.
|
|
163
|
+
|
|
164
|
+
## eval
|
|
165
|
+
|
|
166
|
+
`codejury eval` scores the golden cases and reports a confusion matrix with
|
|
167
|
+
precision, recall, and F1, overall and per capability. It takes `--dataset <dir>`
|
|
168
|
+
for the golden directory, `--split <name>` to score only cases tagged with that
|
|
169
|
+
`split:` such as a held-out set, `--orchestrator` to measure any strategy, and
|
|
170
|
+
`--format {text,json}`. The JSON report is a stable, documented schema.
|
|
171
|
+
|
|
172
|
+
## Architecture
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
Layer 5 Task preset: source, capabilities, orchestrator, agents
|
|
176
|
+
Layer 4 Capability YAML domain knowledge: authn, authz, prompt_injection, ...
|
|
177
|
+
Layer 3 Orchestrator strategy: single, pipeline, debate, reflexion, challenge, taint, adaptive
|
|
178
|
+
Source input: diff, repo, function
|
|
179
|
+
Agent role: finder, challenger, judge, verifier, refuter
|
|
180
|
+
Layer 2 Provider model backend: anthropic, openai, litellm, mock
|
|
181
|
+
Layer 1 Infrastructure cross-cutting utilities: json parsing, verdict cache, retry
|
|
182
|
+
Analysis provenance and taint code-graph engine
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Layers talk only through typed data, and each is an abstract base class plus
|
|
186
|
+
implementations, so the axes of task, orchestration, model, and input compose
|
|
187
|
+
independently.
|
|
188
|
+
|
|
189
|
+
## Limitations
|
|
190
|
+
|
|
191
|
+
- **Prompts are a first pass.** Expect false positives and misses on real code.
|
|
192
|
+
Tune by editing the capability YAML and growing the golden set, and measure the
|
|
193
|
+
effect with `codejury eval`.
|
|
194
|
+
- **Local-pattern checks are sharper than data-flow ones.** A capability judged
|
|
195
|
+
from one spot, such as weak crypto or a hardcoded secret, is reliable. Taint
|
|
196
|
+
classes such as path traversal and SSRF over-flag in single-file review because
|
|
197
|
+
the verifier cannot see whether a value is attacker-controlled. `--orchestrator
|
|
198
|
+
taint` adds a static provenance gate that clears findings it can prove safe and
|
|
199
|
+
is recall-safe, but it is shallow on real code where the value flows through
|
|
200
|
+
object or module attributes. Decisive taint precision needs a deeper code
|
|
201
|
+
graph, which is in progress.
|
|
202
|
+
- **`scan` cost scales with files times capabilities.** It is a periodic deep
|
|
203
|
+
audit, not a quick check, so scope it with `--only`. Day to day, audit the diff.
|
|
204
|
+
|
|
205
|
+
## Development
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
python -m venv .venv && source .venv/bin/activate
|
|
209
|
+
pip install -e ".[dev]"
|
|
210
|
+
pytest
|
|
211
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"""codejury
|
|
1
|
+
"""codejury: a general-purpose Application Security AI audit framework.
|
|
2
2
|
|
|
3
|
-
Five layers: Task
|
|
3
|
+
Five layers: Task, then Capability plus Orchestrator plus Source plus Agent, then Provider, then Infrastructure.
|
|
4
4
|
Domain knowledge lives in YAML capability files as a first-class citizen,
|
|
5
5
|
aligned with OWASP ASVS.
|
|
6
6
|
"""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""codejury.agents
|
|
1
|
+
"""codejury.agents: the audit roles (finder / challenger / judge / verifier).
|
|
2
2
|
|
|
3
3
|
An agent reads an AnalysisContext and emits observations. It talks to a model
|
|
4
4
|
only through a Provider, never a vendor SDK, so the role logic stays independent
|
|
@@ -35,8 +35,8 @@ _FINDING_SHAPE = (
|
|
|
35
35
|
|
|
36
36
|
_DEEP_LENS = (
|
|
37
37
|
"Look past surface patterns for the deepest flaw:\n"
|
|
38
|
-
"- Trust anchors: what does this code trust to authenticate or authorize
|
|
39
|
-
"signature, role, or caller
|
|
38
|
+
"- Trust anchors: what does this code trust to authenticate or authorize, such as a key, token, header, "
|
|
39
|
+
"signature, role, or caller, and who controls that value? If the attacker supplies what is used to "
|
|
40
40
|
"verify them (e.g. their own public key, an unconfigured key that disables verification), passing the "
|
|
41
41
|
"check proves nothing.\n"
|
|
42
42
|
"- Order of operations: is an external, irreversible, or privileged action performed before the local "
|
|
@@ -101,7 +101,7 @@ class ChallengerAgent(_DebateAgent):
|
|
|
101
101
|
def run(self, ctx: AnalysisContext) -> list[Observation]:
|
|
102
102
|
parts = [
|
|
103
103
|
"Challenge the findings below. For each one you believe is a false positive, write a rebuttal. "
|
|
104
|
-
"Add new_findings for any real issue that was missed
|
|
104
|
+
"Add new_findings for any real issue that was missed, especially a deeper flaw the finder "
|
|
105
105
|
"stopped short of.",
|
|
106
106
|
_DEEP_LENS,
|
|
107
107
|
_code(ctx.artifact),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""MockAgent
|
|
1
|
+
"""MockAgent: a minimal Agent for the dry-run and tests.
|
|
2
2
|
|
|
3
3
|
It really calls the provider (so the dry-run exercises the agent -> provider
|
|
4
4
|
path), then emits one Verdict per in-scope capability, parking the model's reply
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Shared coercion from loosely-typed model JSON into domain values.
|
|
2
2
|
|
|
3
3
|
Agents parse model output that may omit, mistype, or invent fields. These
|
|
4
|
-
helpers coerce defensively
|
|
4
|
+
helpers coerce defensively: they never raise on bad input, they fall back.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import math
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"""RefuterAgent
|
|
1
|
+
"""RefuterAgent: a skeptic that tries to dismiss flagged verdicts as false positives.
|
|
2
2
|
|
|
3
3
|
Used by the challenge orchestrator: the verifier flags issues, then the refuter
|
|
4
4
|
gets the code plus the VULNERABLE verdicts (via ``ctx.history``) and argues which
|
|
5
|
-
are false positives
|
|
5
|
+
are false positives, e.g. a value that is not actually attacker-controlled or a
|
|
6
6
|
sink that is not reachable. It returns a Concession per verdict it refutes.
|
|
7
7
|
|
|
8
8
|
This is the cheap, focused alternative to a full debate: only flagged verdicts
|
|
@@ -53,7 +53,7 @@ class RefuterAgent(Agent):
|
|
|
53
53
|
"is not attacker-controlled: a stored data field, or traced (here or in the call sites) to "
|
|
54
54
|
"a trusted, config, or operator-supplied source. If its origin is not shown or could "
|
|
55
55
|
"plausibly be external input, do NOT refute. For other issue types (hardcoded secrets, "
|
|
56
|
-
"weak crypto, ...), a literal value is often the vulnerability itself
|
|
56
|
+
"weak crypto, ...), a literal value is often the vulnerability itself; do NOT refute "
|
|
57
57
|
"those just because a value is constant.\n\n"
|
|
58
58
|
"Respond with a single JSON object exactly like:\n" + _JSON_SHAPE
|
|
59
59
|
)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"""VerifierAgent
|
|
1
|
+
"""VerifierAgent: check code against a capability's correct/anti patterns.
|
|
2
2
|
|
|
3
3
|
It renders the capability into a prompt, calls the provider once per capability,
|
|
4
4
|
and parses the JSON reply into Verdicts. It asks for one verdict per
|
|
5
5
|
sub_capability including SECURE / NOT_PRESENT, so a report can say what was
|
|
6
|
-
checked and what passed
|
|
6
|
+
checked and what passed, not only what failed.
|
|
7
7
|
|
|
8
8
|
Parsing is defensive: a missing or malformed reply yields no verdicts rather
|
|
9
9
|
than raising, and unknown status values fall back to UNKNOWN.
|
|
@@ -75,7 +75,7 @@ def _render_capability(cap: Capability) -> str:
|
|
|
75
75
|
def _build_prompt(path: str, content: str, cap: Capability, context: str = "") -> str:
|
|
76
76
|
sub_names = ", ".join(cap.sub_capabilities) or "(none)"
|
|
77
77
|
context_block = (
|
|
78
|
-
f"Related code (call sites / usages elsewhere
|
|
78
|
+
f"Related code (call sites / usages elsewhere, for tracing where values come from, "
|
|
79
79
|
f"NOT under review):\n```\n{context}\n```\n\n"
|
|
80
80
|
if context
|
|
81
81
|
else ""
|
|
@@ -90,7 +90,7 @@ def _build_prompt(path: str, content: str, cap: Capability, context: str = "") -
|
|
|
90
90
|
"For input-driven issues (injection, path traversal, SSRF), mark VULNERABLE only when "
|
|
91
91
|
"untrusted/external input could plausibly reach the sink in the code shown. A constant, "
|
|
92
92
|
"a stored data field, a value from trusted config, or a path or argument the operator "
|
|
93
|
-
"supplies (e.g. a CLI argument) is not attacker-controlled
|
|
93
|
+
"supplies (e.g. a CLI argument) is not attacker-controlled; do not flag it.\n\n"
|
|
94
94
|
"Respond with a single JSON object exactly like:\n" + _JSON_SHAPE
|
|
95
95
|
)
|
|
96
96
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Static analysis for provenance (P1).
|
|
2
2
|
|
|
3
|
-
The code-graph / data-flow engine that gives the verifier provenance
|
|
3
|
+
The code-graph / data-flow engine that gives the verifier provenance: whether a
|
|
4
4
|
value reaching a sink is attacker-controlled, sanitized, or a trusted constant.
|
|
5
5
|
This is the real fix for the taint precision floor that single-file LLM review
|
|
6
6
|
cannot reach (see ROADMAP P1). Python / AST based to start.
|
|
@@ -8,7 +8,7 @@ and literals a value derives from.
|
|
|
8
8
|
The analysis is deliberately conservative and flow-insensitive: a name assigned
|
|
9
9
|
more than once contributes the union of all its right-hand sides, so a possible
|
|
10
10
|
source is never dropped (recall over precision). A value built only from literals
|
|
11
|
-
is reported as ``is_constant
|
|
11
|
+
is reported as ``is_constant``, the signal that distinguishes, for example,
|
|
12
12
|
SQL concatenated from constants (safe) from SQL concatenated from a parameter.
|
|
13
13
|
|
|
14
14
|
This module finds where a value comes from; it does not decide what is a source
|
|
@@ -43,7 +43,7 @@ class Origin:
|
|
|
43
43
|
|
|
44
44
|
@property
|
|
45
45
|
def is_constant(self) -> bool:
|
|
46
|
-
"""True when the value is built only from literals
|
|
46
|
+
"""True when the value is built only from literals: no param, call, attr,
|
|
47
47
|
free name, or unmodelled expression contributes."""
|
|
48
48
|
return not (self.params or self.calls or self.attrs or self.globals_ or self.unknown)
|
|
49
49
|
|
|
@@ -65,7 +65,7 @@ def parse_function(source: str, name: str) -> ast.FunctionDef | ast.AsyncFunctio
|
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
def find_calls(scope: ast.AST, callee: str) -> list[ast.Call]:
|
|
68
|
-
"""Every call within ``scope`` whose function is named ``callee
|
|
68
|
+
"""Every call within ``scope`` whose function is named ``callee``, matching a
|
|
69
69
|
bare name (``open``) or the final attribute (``execute`` in ``cur.execute``)."""
|
|
70
70
|
return [node for node in ast.walk(scope) if isinstance(node, ast.Call) and _call_name(node) == callee]
|
|
71
71
|
|
|
@@ -97,7 +97,7 @@ def trace_value(func: ast.FunctionDef | ast.AsyncFunctionDef, expr: ast.AST) ->
|
|
|
97
97
|
on_param=lambda n: Origin(params=frozenset({n})),
|
|
98
98
|
on_global=lambda n: Origin(globals_=frozenset({n})),
|
|
99
99
|
on_constant=lambda: _LITERAL,
|
|
100
|
-
on_cycle=Origin, # assignment cycle
|
|
100
|
+
on_cycle=Origin, # assignment cycle, no new information
|
|
101
101
|
)
|
|
102
102
|
|
|
103
103
|
|
|
@@ -182,7 +182,7 @@ def reduce_value(
|
|
|
182
182
|
if isinstance(expr, (ast.List, ast.Tuple, ast.Set)):
|
|
183
183
|
return combine([recurse(e) for e in expr.elts])
|
|
184
184
|
if isinstance(expr, ast.Name):
|
|
185
|
-
if expr.id in seen: # assignment cycle
|
|
185
|
+
if expr.id in seen: # assignment cycle, stop
|
|
186
186
|
return on_cycle()
|
|
187
187
|
if expr.id in params:
|
|
188
188
|
return on_param(expr.id)
|
|
@@ -6,7 +6,7 @@ sanitizer makes it SANITIZED (taint stops), a propagator carries taint through t
|
|
|
6
6
|
the result, and a trusted origin or a literal is clean.
|
|
7
7
|
|
|
8
8
|
The point is to let a later layer (P1-04) downgrade a taint finding only when the
|
|
9
|
-
value is *provably* not attacker-controlled
|
|
9
|
+
value is *provably* not attacker-controlled (``classification in SAFE``), so
|
|
10
10
|
recall is preserved: anything uncertain is UNKNOWN or PARAM, never quietly safe.
|
|
11
11
|
|
|
12
12
|
Two documented precision leans: a bare module-global name (e.g. ``STATIC_DIR``)
|
|
@@ -42,7 +42,7 @@ from codejury.resources import TAINT_FILE
|
|
|
42
42
|
|
|
43
43
|
class Taint(str, Enum):
|
|
44
44
|
EXTERNAL = "external" # derives from an attacker source, not sanitized
|
|
45
|
-
UNKNOWN = "unknown" # an unknown call / access
|
|
45
|
+
UNKNOWN = "unknown" # an unknown call / access; cannot prove either way
|
|
46
46
|
PARAM = "param" # depends on a parameter; resolve at the call site (cross-file)
|
|
47
47
|
SANITIZED = "sanitized" # had an external component, but a sanitizer neutralized it
|
|
48
48
|
TRUSTED = "trusted" # operator/config/global origin
|
|
@@ -131,14 +131,14 @@ def taint_of(
|
|
|
131
131
|
return Taint.TRUSTED
|
|
132
132
|
if _callee_in(node, vocab.propagators) or _callee_in(node, vocab.safe_sinks):
|
|
133
133
|
return _combine([recurse(a) for a in node.args])
|
|
134
|
-
return Taint.UNKNOWN # unknown call
|
|
134
|
+
return Taint.UNKNOWN # unknown call; a cross-file hop may resolve it later
|
|
135
135
|
if isinstance(node, (ast.Attribute, ast.Subscript)):
|
|
136
136
|
path = access_path(node)
|
|
137
137
|
if path and _access_in(path, vocab.sources):
|
|
138
138
|
return Taint.EXTERNAL
|
|
139
139
|
if path and _access_in(path, vocab.trusted):
|
|
140
140
|
return Taint.TRUSTED
|
|
141
|
-
if access_root(node) in params: # attribute of a parameter
|
|
141
|
+
if access_root(node) in params: # attribute of a parameter; resolve at the call site
|
|
142
142
|
return on_param(access_root(node))
|
|
143
143
|
return Taint.UNKNOWN # unknown object attribute (e.g. self.x): not provably safe
|
|
144
144
|
return Taint.UNKNOWN
|
|
@@ -150,7 +150,7 @@ def taint_of(
|
|
|
150
150
|
combine=_combine,
|
|
151
151
|
leaf=leaf,
|
|
152
152
|
on_param=on_param,
|
|
153
|
-
on_global=lambda n: Taint.TRUSTED, # free module global / builtin
|
|
153
|
+
on_global=lambda n: Taint.TRUSTED, # free module global / builtin; conventionally a constant
|
|
154
154
|
on_constant=lambda: Taint.CONSTANT,
|
|
155
155
|
on_cycle=lambda: Taint.CONSTANT, # assignment cycle: no new information
|
|
156
156
|
)
|
|
@@ -261,7 +261,7 @@ def worst_sink_taint(content: str, files: dict[str, str], vocab: TaintVocab) ->
|
|
|
261
261
|
A "potential sink" is any call that is not a safe sink, sanitizer, or
|
|
262
262
|
propagator (those are not where injection happens). Each such call's argument
|
|
263
263
|
taint is classified with the cross-file resolver. A safe sink that consumes
|
|
264
|
-
tainted data (e.g. ``json.loads(request.data)``) contributes SANITIZED
|
|
264
|
+
tainted data (e.g. ``json.loads(request.data)``) contributes SANITIZED: the
|
|
265
265
|
data was handled safely. The worst contribution is returned.
|
|
266
266
|
|
|
267
267
|
``Taint.UNKNOWN`` when no inspectable sink is found (the artifact may still be
|