From 31e5ec74306896cbf6a0fdc5d5c92fb9af657917 Mon Sep 17 00:00:00 2001 From: Marius Ciepluch <11855163+norandom@users.noreply.github.com> Date: Sun, 13 Sep 2026 14:50:25 +0200 Subject: [PATCH] feat(pre-push-safety-net): replay immutable revisions through the full transaction --- .../implementation-group-5.md | 66 + .kiro/specs/pre-push-safety-net/spec.json | 19 +- .kiro/specs/pre-push-safety-net/tasks.md | 5 +- .../measurements/2026-09-08-module-audit.json | 48 +- .../measurements/2026-09-13-replay-smoke.json | 3763 +++++++++++++++++ ops/README.md | 24 + ops/smoke_replay.py | 89 + src/openultrasast/cli.py | 29 + src/openultrasast/push/policy.py | 26 +- src/openultrasast/push/report.py | 12 +- src/openultrasast/push/runner.py | 279 ++ src/openultrasast/push/snapshot.py | 28 +- tests/test_push_policy.py | 32 + tests/test_push_runner.py | 198 + 14 files changed, 4589 insertions(+), 29 deletions(-) create mode 100644 .kiro/specs/pre-push-safety-net/implementation-group-5.md create mode 100644 benchmarks/measurements/2026-09-13-replay-smoke.json create mode 100644 ops/smoke_replay.py create mode 100644 src/openultrasast/push/runner.py create mode 100644 tests/test_push_runner.py diff --git a/.kiro/specs/pre-push-safety-net/implementation-group-5.md b/.kiro/specs/pre-push-safety-net/implementation-group-5.md new file mode 100644 index 0000000..9aaae62 --- /dev/null +++ b/.kiro/specs/pre-push-safety-net/implementation-group-5.md @@ -0,0 +1,66 @@ +# Implementation verification: group 5 + +Group 5 was authorized by the maintainer's “approved” after group 4 completion. +Task 5.1 is verified complete (15/27 total); task 5.2 is next. +Real capability eligibility and rollout readiness remain unproven. + +## Execution and review mode + +Fresh implementer dispatch for 5.1 returned `agent thread limit reached`. +The [Kiro implementation skill](../../../.opencode/skills/kiro-impl/SKILL.md) explicitly +states: “If multi-agent is not available, fall back to manual mode execution for all tasks.” +Its manual review rule permits review in the main context when a fresh reviewer is unavailable. +This run therefore uses manual implementation and adversarial review, not independent review. + +## Task 5.1 brief + +Wire explicit immutable base/head replay through the existing mapper, ranker, driver, +base comparison and admission/report contracts. Preserve the shared elapsed deadline, +source/index/ref state, completed evidence on failure, and separate coverage/exit policy. +Requirements: 1.1, 2.1, 3.1, 3.4, 4.1, 4.2, 5.5, 7.1, 7.3. Design sections are named: +Snapshot Adapter, Ranker Scope Contract, Delta and Actionability Policy, Result and Hook +Adapter, Cache and Engine Boundary. No new detector, ranking weights, framework facts, +cache or hook installation belongs to this task. + +### Integration findings + +- Snapshot resolution previously used fresh per-command timeouts. An optional shared + execution budget now covers constructor probes and explicit revision resolution. +- Discovery and provenance are bounded in a Linux child process. The parent drains output + incrementally, checks the deadline, kills a stalled worker and requires a valid receipt; + exit zero with no result is failure. No project code or engine runs in this child. +- The first real controlled PHP replay found the exact request-to-eval witness but novelty + was unknown: comparison policy treated another question's context gap as global. The + owning task 4.1 policy was repaired here with a failing regression first. Only recognized + boundaries attached to a different recorded question can be ignored for that candidate; + aggregate coverage retains every gap. Own-question and global boundaries still prevent + supported novelty. This is policy ownership repair, not a new upstream graph abstraction. +- Artifacts must resolve outside the analyzed repository. The runner refuses a destination + that could overwrite live source/index/ref state and preserves the real enforcement result. + +### Evidence in progress + +Initial OFF-state tests: `/tmp/ousast-replay-red.log`, six failures before implementation. +Policy ownership regression: `/tmp/ousast-replay-policy-red.log`, one failure before repair. +Live-source overwrite regression: `/tmp/ousast-replay-review-red.log`, reproduced before repair. +Final validation: 1,236 tests passed, nine skipped; Ruff/format, mypy (112 source files), compileall and all three regression gates passed. Final packaged CLI boot and the controlled positive replay passed. See `benchmarks/measurements/2026-09-13-replay-smoke.json`. + + +Additional integration repairs retain snapshot omissions in engine change context and distinguish +base questions proven tier zero from unfinished queries. The exact required base question still +must have completed, valid evidence; budget-deferred work still prevents a complete comparison. +RED evidence: `/tmp/ousast-replay-tierzero-red.log` and `/tmp/ousast-replay-snapshot-red.log`. + +## Task 5.1 review verdict +- VERDICT: APPROVED +- TASK: 5.1 +- MECHANICAL_RESULTS: Full suite exit 0 (1,236 passed, 9 skipped); Ruff/format/mypy/compileall and detection/map/pair gates PASS; no new placeholder markers or secrets; boundary WITHIN; behavioral RED VERIFIED. +- FINDINGS: Integration defects above repaired with regressions; no outstanding task-blocking finding. +- SUMMARY: Manual adversarial review approves bounded local replay; this is not independent review or rollout admission. + +## Task 5.1 verification +- STATUS: VERIFIED +- CLAIM_TYPE: TASK +- CLAIM: Explicit local replay traverses the production mapper/ranker/arbiter/comparison/report path and retains uncertainty and shared deadlines. +- EVIDENCE: Final packaged controlled security change yields new/source_connection_absent_from_comparable_base. Fixed twin emits no modeled head finding. The packaged deadline control returns incomplete in 30.785 seconds, within 30 + 2 seconds. Exact final package policy/core/facts/query digests match the workspace. Complete commands and captured raw answers live in the measurement artifact. +- GAPS: Aggregate coverage remains incomplete, real capabilities are disabled, and lab timings do not satisfy the latency gate. Source-mounted fixed and earlier packaged deadline provenance is explicitly separated in the artifact. PMPro/Node transfer is task 5.2, not inferred from a small PHP control. diff --git a/.kiro/specs/pre-push-safety-net/spec.json b/.kiro/specs/pre-push-safety-net/spec.json index 6d59466..f63dea2 100644 --- a/.kiro/specs/pre-push-safety-net/spec.json +++ b/.kiro/specs/pre-push-safety-net/spec.json @@ -1,7 +1,7 @@ { "feature_name": "pre-push-safety-net", "created_at": "2026-09-12T15:35:00Z", - "updated_at": "2026-09-13T11:21:07.667199+00:00", + "updated_at": "2026-09-13T12:50:25.249104+00:00", "language": "en", "phase": "implementation", "approvals": { @@ -19,7 +19,7 @@ } }, "ready_for_implementation": true, - "implementation_approval_note": "Groups 1\u20134 verified complete. Tasks 4.1/4.2 independently approved; 4.3 used the documented Kiro manual review fallback after agent thread limit. Remaining tasks require review and fresh verification.", + "implementation_approval_note": "Group 5 authorized. Task5.1 verified through manual Kiro fallback review; 5.2 next. Real capabilities remain disabled.", "depends_on": [ "contributor-scan" ], @@ -60,6 +60,11 @@ "at": "2026-09-13T10:26:47.307154+00:00", "source": "move on to group 4 as a whole", "action": "Authorized all of group 4 (4.1\u20134.3), sequential implementation, independent task review and fresh verification. Groups 5\u20138 remain pending." + }, + { + "at": "2026-09-13T12:40:57.961577+00:00", + "source": "approved", + "action": "Authorized group 5 after the group 4 completion summary: explicit transaction replay, then the first PMPro/frozen-core Node experiment. Review and fresh evidence remain required." } ], "task_review": { @@ -86,15 +91,17 @@ "3.4", "4.1", "4.2", - "4.3" + "4.3", + "5.1" ], - "remaining_tasks": 13, - "verification_record": "implementation-group-4.md", + "remaining_tasks": 12, + "verification_record": "implementation-group-5.md", "verification_records": [ "implementation-group-1.md", "implementation-group-2.md", "implementation-group-3.md", - "implementation-group-4.md" + "implementation-group-4.md", + "implementation-group-5.md" ], "next_group": 5, "blocked_tasks": [] diff --git a/.kiro/specs/pre-push-safety-net/tasks.md b/.kiro/specs/pre-push-safety-net/tasks.md index c212cb7..86d7be5 100644 --- a/.kiro/specs/pre-push-safety-net/tasks.md +++ b/.kiro/specs/pre-push-safety-net/tasks.md @@ -3,7 +3,7 @@ Status: task plan approved by the maintainer on 2026-09-12. Groups 1–4 (tasks 1.1–4.3) are complete after task reviews and fresh verification (14/27 subtasks). Task 4.3 used the documented manual review fallback after agent dispatch became unavailable. -Groups 5–8 remain pending; no production capability or hook latency is admitted. +Task 5.1 is also verified (15/27 total); task 5.2 and groups 6–8 remain pending; no production capability or hook latency is admitted. ## Execution contract @@ -140,10 +140,11 @@ Groups 5–8 remain pending; no production capability or hook latency is admitte - _Requirements: 3.1, 3.2, 3.3, 5.1, 5.2, 5.5, 7.3_ - [ ] 5. Prove the first end-to-end experiment before cache optimization -- [ ] 5.1 Wire explicit base/head replay through the full transaction +- [x] 5.1 Wire explicit base/head replay through the full transaction - Connect immutable snapshots, ranker decisions, existing arbiter, targeted comparison, admission diagnostics and compact artifacts through an explicit local replay command. - Apply the shared budget to preparation and both revisions; no model/service or installed hook is required. All runtime errors preserve coverage state. - Done when a controlled security change and fixed twin traverse the production runner through the existing ranker and produce replayable results with truthful deadlines. + - _Verified 2026-09-13:_ manual Kiro fallback review APPROVED; 1,236 tests passed, nine skipped; final packaged security replay and fixed/deadline controls verified. See `implementation-group-5.md`. - _Boundary: Push runner, CLI, Snapshot Adapter, engine and policy integration_ - _Depends: 1.3, 3.1, 3.4, 4.3_ - _Requirements: 1.1, 2.1, 3.1, 3.4, 4.1, 4.2, 5.5, 7.1, 7.3_ diff --git a/benchmarks/measurements/2026-09-08-module-audit.json b/benchmarks/measurements/2026-09-08-module-audit.json index e2ffd66..74065d9 100644 --- a/benchmarks/measurements/2026-09-08-module-audit.json +++ b/benchmarks/measurements/2026-09-08-module-audit.json @@ -1,10 +1,10 @@ { "counts": { - "load_bearing": 101, + "load_bearing": 102, "standalone_capability": 9 }, - "modules": 110, - "note": "Refreshed after pre-push-safety-net task 4.3: compact reporting preserves full evidence and decisions; transaction replay remains task 5.1.", + "modules": 111, + "note": "Refreshed for task 5.1: explicit local replay integrates the existing ranker and comparison policy.", "orphaned": [], "rows": [ { @@ -104,6 +104,7 @@ "model.endpoint", "pairs", "push.policy", + "push.runner", "regress.candidate", "regress.recipes", "run" @@ -135,7 +136,8 @@ "model.pipeline", "model.scan", "model.taint", - "push.policy" + "push.policy", + "push.runner" ], "module": "cpg", "reason": "model-grounded-detection Req 4: the CPG seam package" @@ -157,7 +159,8 @@ "model.pipeline", "model.scan", "model.taint", - "push.policy" + "push.policy", + "push.runner" ], "module": "cpg.backend", "reason": "model-grounded-detection Req 4.1/4.5: the single Joern subprocess boundary" @@ -327,6 +330,7 @@ "model.scan", "pairs", "preprocess", + "push.runner", "stage_processors" ], "module": "mapping", @@ -362,6 +366,7 @@ "push.contracts", "push.policy", "push.report", + "push.runner", "push.snapshot" ], "module": "model", @@ -407,6 +412,7 @@ "push.contracts", "push.policy", "push.report", + "push.runner", "push.snapshot" ], "module": "model.contracts", @@ -497,7 +503,8 @@ "cli", "model.layout", "model.scan", - "push.policy" + "push.policy", + "push.runner" ], "module": "model.regions", "reason": "contributor-scan Req 2: regions from entry points, with the families each admits" @@ -515,7 +522,8 @@ "importers": [ "cli", "push.policy", - "push.report" + "push.report", + "push.runner" ], "module": "model.scan", "reason": "contributor-scan Req 3: the repository driver -- one CPG, one budget, ranked spend" @@ -523,7 +531,8 @@ { "classification": "load_bearing", "importers": [ - "cli" + "cli", + "push.runner" ], "module": "model.shipped", "reason": "reachable from gate, map_gate, pair_gate or the CLI" @@ -630,6 +639,7 @@ "model.partitions", "model.scan", "pairs", + "push.runner", "rank", "regress.candidate", "semantic.overlay", @@ -668,8 +678,10 @@ { "classification": "load_bearing", "importers": [ + "cli", "push.policy", "push.report", + "push.runner", "push.snapshot" ], "module": "push", @@ -680,6 +692,7 @@ "importers": [ "push.policy", "push.report", + "push.runner", "push.snapshot" ], "module": "push.contracts", @@ -688,20 +701,33 @@ { "classification": "load_bearing", "importers": [ - "push.report" + "push.report", + "push.runner" ], "module": "push.policy", "reason": "pre-push-safety-net Req 2.4/3.1/3.4/4.1: targeted same-semantics base comparison; replay integration pending" }, { "classification": "load_bearing", - "importers": [], + "importers": [ + "push.runner" + ], "module": "push.report", "reason": "pre-push-safety-net Req 5.1/5.2/5.5/7.3: compact output and complete artifacts; runner integration pending" }, { "classification": "load_bearing", - "importers": [], + "importers": [ + "cli" + ], + "module": "push.runner", + "reason": "reachable from gate, map_gate, pair_gate or the CLI" + }, + { + "classification": "load_bearing", + "importers": [ + "push.runner" + ], "module": "push.snapshot", "reason": "pre-push-safety-net Req 1.1/1.3/1.4/7.1: local immutable ref resolution; runner integration pending" }, diff --git a/benchmarks/measurements/2026-09-13-replay-smoke.json b/benchmarks/measurements/2026-09-13-replay-smoke.json new file mode 100644 index 0000000..d0165a5 --- /dev/null +++ b/benchmarks/measurements/2026-09-13-replay-smoke.json @@ -0,0 +1,3763 @@ +{ + "status": "VERIFIED", + "task": "5.1", + "review_mode": "manual Kiro fallback after agent thread limit", + "image": "sha256:dd9933e2a4021ab28f9302cbff82d9823d16e622fa60b27199ad8aa08c2fabbe", + "controls": [ + { + "name": "security", + "data": { + "case": "security", + "source_bytes": 82, + "elapsed_seconds": 146.80912487697788, + "exit_code": 0, + "report_error": null, + "reporting_seconds": 0.02684599393978715, + "text": "No actionable defects reported; analysis is incomplete.\nNotice: Some checks are not enabled for normal alerts. Review capability coverage in the details.\nDetails: /tmp/ousast-replay-smoke-0p2xuvac/replay.json\n", + "artifact": { + "schema_version": 1, + "snapshots": [ + { + "commit_oid": "11bb29e44eaa453a74c8cc115093aee25f2c5430", + "object_format": "sha1", + "files": [ + { + "path_hex": "6170692e706870", + "blob_oid": "d9b631a6b465a68a7ddfbcfc289eb8cf4124e00b", + "mode": "100644", + "size_bytes": 83, + "sha256": "fd919c616a59d10a6a71383ac0d5228ed2fc0eb6c90461dd3ef5dfeab835abf8" + } + ], + "boundaries": [], + "tree_complete": true, + "bytes_read": 83 + }, + { + "commit_oid": "f73ce23fa3a3dff278161652471571d230a26f5d", + "object_format": "sha1", + "files": [ + { + "path_hex": "6170692e706870", + "blob_oid": "7e99786afe2b66f90af1abd3effc99327fcb2e55", + "mode": "100644", + "size_bytes": 76, + "sha256": "ce927591f5ff35a4c3ca38de4cdce9e9310d5fc176e7e2feecd2e309f6388c6a" + } + ], + "boundaries": [], + "tree_complete": true, + "bytes_read": 76 + } + ], + "change_context": { + "base_revision": "f73ce23fa3a3dff278161652471571d230a26f5d", + "head_revision": "11bb29e44eaa453a74c8cc115093aee25f2c5430", + "changed_paths": [ + "6170692e706870" + ], + "deleted_paths": [], + "spans": [ + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "base" + }, + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "head" + } + ], + "renames": [], + "declaration_paths": [], + "relationships": [], + "unresolved_boundaries": [], + "path_encoding": "filesystem-bytes-hex", + "line_correspondences": [ + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 1, + "base_end_line": 1, + "head_start_line": 1 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 2, + "base_end_line": 2, + "head_start_line": 2 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 4, + "base_end_line": 4, + "head_start_line": 4 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 5, + "base_end_line": 5, + "head_start_line": 5 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 6, + "base_end_line": 6, + "head_start_line": 6 + } + ] + }, + "result": { + "analyses": [ + { + "comparison": { + "head_oid": "11bb29e44eaa453a74c8cc115093aee25f2c5430", + "base_oid": "f73ce23fa3a3dff278161652471571d230a26f5d", + "base_reason": "explicit_local_replay", + "refs": [ + "refs/heads/replay" + ] + }, + "scopes": [ + { + "ranker_version": "existing-static-evidence-v1", + "ranking_mode": "evidence", + "population_complete": true, + "selected": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "priority": 0.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"deserialization\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"deserialization\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "priority": -1.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[{\"arg0_literal\":false,\"arity\":1,\"cleansed_on_call\":false,\"code\":\"eval($value)\",\"line\":4,\"method\":\"handler\"}],\"source_local\":true,\"source_near\":true}", + "tier=4", + "score=4.5", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}" + ], + "tier": 4, + "score": 4.5 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "priority": -2.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "priority": -3.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "priority": -4.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "priority": -5.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "priority": -6.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "priority": -7.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "priority": -8.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "priority": -9.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + } + ], + "deferred": [], + "unresolved_boundaries": [ + "dynamic_external_or_depth_context_unresolved:contributor-scan:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "dynamic_external_or_depth_context_unresolved:contributor-scan:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "context_scope_empty:contributor-scan:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "context_scope_empty:contributor-scan:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "context_scope_empty:contributor-scan:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "context_scope_empty:contributor-scan:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "context_scope_empty:contributor-scan:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed" + ] + } + ], + "completed_questions": [ + { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + } + ], + "coverage_status": "incomplete" + } + ], + "finding_status": "none", + "coverage_status": "incomplete", + "push_disposition": "allow", + "actionable_defect_ids": [] + }, + "admission": { + "defects": [], + "dispositions": [ + { + "candidate": { + "delta": { + "family": "injection", + "site": "api.php:4:handler", + "rung": "model_entailed", + "witness": "$_GET[\"value\"] -> eval($value) in api.php (line 4, 3 steps)", + "defect_id": "cce8d260cefb7a2720b428758263715e5b021fc0d560b3a93948cb3ef9e068f2", + "novelty": "new", + "reason": "source_connection_absent_from_comparable_base", + "head_operation": { + "question": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "mechanism": "taint", + "path": "api.php", + "line": 4, + "operation": "eval($value)", + "source": "[\"framework\",\"$_GET[\\\"value\\\"]\"]", + "discharged": false, + "detail": "{\"bound\": \"\", \"bounded\": false, \"inLabeledScope\": true, \"length\": 3, \"paths\": 1, \"sanitized\": false, \"sink\": \"eval($value)\", \"sinkArg0Literal\": false, \"sinkArity\": 1, \"sinkFile\": \"api.php\", \"sinkLine\": \"4\", \"sinkMethod\": \"handler\", \"source\": \"$_GET[\\\"value\\\"]\", \"sourceKind\": \"framework\"}" + }, + "base_operations": [], + "change_evidence": [ + "base:api.php:3-3", + "head:api.php:3-3" + ], + "base_revision": "f73ce23fa3a3dff278161652471571d230a26f5d", + "head_revision": "11bb29e44eaa453a74c8cc115093aee25f2c5430", + "semantics": "1e36ea1ba503218899c49bdd58f04a01f35d17b2a83bb3e433e5088624489e3a" + }, + "capability": { + "language": "php", + "runtime": "unspecified", + "framework": "unspecified", + "family": "injection", + "mechanism": "taint", + "context": "unreviewed", + "semantics": "1e36ea1ba503218899c49bdd58f04a01f35d17b2a83bb3e433e5088624489e3a" + }, + "comparison": { + "head_oid": "11bb29e44eaa453a74c8cc115093aee25f2c5430", + "base_oid": "f73ce23fa3a3dff278161652471571d230a26f5d", + "base_reason": "explicit_local_replay", + "refs": [ + "refs/heads/replay" + ] + }, + "dependency_gaps": [], + "sanitizer_contexts": [] + }, + "admitted": false, + "reasons": [ + "capability_unavailable" + ], + "evaluation_id": null, + "capability_evaluations": [] + } + ], + "coverage_reasons": [ + "capability_unavailable", + "dynamic_external_or_depth_context_unresolved:contributor-scan:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "dynamic_external_or_depth_context_unresolved:contributor-scan:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "context_scope_empty:contributor-scan:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "context_scope_empty:contributor-scan:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "context_scope_empty:contributor-scan:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "context_scope_empty:contributor-scan:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "context_scope_empty:contributor-scan:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed", + "analysis_incomplete" + ] + }, + "scans": [ + { + "comparison": { + "head_oid": "11bb29e44eaa453a74c8cc115093aee25f2c5430", + "base_oid": "f73ce23fa3a3dff278161652471571d230a26f5d", + "base_reason": "explicit_local_replay", + "refs": [ + "refs/heads/replay" + ] + }, + "side": "head", + "scan": { + "findings": [ + { + "site": "api.php:4:handler", + "family": "injection", + "rung": "model_entailed", + "witness": "$_GET[\"value\"] -> eval($value) in api.php (line 4, 3 steps)", + "contradiction": "", + "reached_from": 1 + } + ], + "by_rung": { + "suspicion": 0, + "model_corroborated": 0, + "model_entailed": 1, + "execution_confirmed": 0 + }, + "regions_scanned": 2, + "regions_unjudged": 0, + "regions_unasked": 0, + "model_calls": 0, + "cost_usd": 0.0, + "seconds": 78.61, + "build_seconds": 33.49, + "query_seconds": 21.26, + "query_seconds_by_kind": { + "evidence": 23.75, + "taint": 21.26 + }, + "degradations": [], + "tiers": [ + [ + "api.php", + "handler", + "deserialization", + 0 + ], + [ + "api.php", + "handler", + "injection", + 4 + ], + [ + "api.php", + "handler", + "output_encoding", + 0 + ], + [ + "api.php", + "handler", + "path", + 0 + ], + [ + "api.php", + "handler", + "untrusted_destination", + 0 + ], + [ + "api.php", + "", + "deserialization", + 0 + ], + [ + "api.php", + "", + "injection", + 0 + ], + [ + "api.php", + "", + "output_encoding", + 0 + ], + [ + "api.php", + "", + "path", + 0 + ], + [ + "api.php", + "", + "untrusted_destination", + 0 + ] + ], + "tier_counts": { + "0": 9, + "4": 1 + }, + "requests_pruned": 0, + "partitions": [ + { + "language": "php", + "frontend": "php", + "paths": [ + "api.php" + ], + "source_bytes": 83, + "status": "built", + "boundaries": [], + "runtime": "unspecified", + "excluded_paths": [], + "unshipped_paths": [] + } + ], + "change_context": { + "base_revision": "f73ce23fa3a3dff278161652471571d230a26f5d", + "head_revision": "11bb29e44eaa453a74c8cc115093aee25f2c5430", + "changed_paths": [ + "6170692e706870" + ], + "deleted_paths": [], + "spans": [ + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "base" + }, + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "head" + } + ], + "renames": [], + "declaration_paths": [], + "relationships": [ + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + }, + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + }, + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + }, + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + }, + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + } + ], + "unresolved_boundaries": [ + "dynamic_external_or_depth_context_unresolved:contributor-scan:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "dynamic_external_or_depth_context_unresolved:contributor-scan:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "context_scope_empty:contributor-scan:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "context_scope_empty:contributor-scan:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "context_scope_empty:contributor-scan:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "context_scope_empty:contributor-scan:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "context_scope_empty:contributor-scan:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed" + ], + "path_encoding": "filesystem-bytes-hex", + "line_correspondences": [ + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 1, + "base_end_line": 1, + "head_start_line": 1 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 2, + "base_end_line": 2, + "head_start_line": 2 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 4, + "base_end_line": 4, + "head_start_line": 4 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 5, + "base_end_line": 5, + "head_start_line": 5 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 6, + "base_end_line": 6, + "head_start_line": 6 + } + ] + }, + "scope": { + "ranker_version": "existing-static-evidence-v1", + "ranking_mode": "evidence", + "population_complete": true, + "selected": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "priority": 0.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"deserialization\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"deserialization\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "priority": -1.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[{\"arg0_literal\":false,\"arity\":1,\"cleansed_on_call\":false,\"code\":\"eval($value)\",\"line\":4,\"method\":\"handler\"}],\"source_local\":true,\"source_near\":true}", + "tier=4", + "score=4.5", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}" + ], + "tier": 4, + "score": 4.5 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "priority": -2.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "priority": -3.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "priority": -4.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "priority": -5.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "priority": -6.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "priority": -7.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "priority": -8.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "priority": -9.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"f73ce23fa3a3dff278161652471571d230a26f5d\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"11bb29e44eaa453a74c8cc115093aee25f2c5430\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + } + ], + "deferred": [], + "unresolved_boundaries": [ + "dynamic_external_or_depth_context_unresolved:contributor-scan:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "dynamic_external_or_depth_context_unresolved:contributor-scan:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "context_scope_empty:contributor-scan:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "context_scope_empty:contributor-scan:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "context_scope_empty:contributor-scan:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "context_scope_empty:contributor-scan:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "context_scope_empty:contributor-scan:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed" + ] + }, + "question_outcomes": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "status": "completed", + "reason": "query_answered_and_arbitrated", + "raw_rows_json": "[{\"bound\":\"\",\"bounded\":false,\"inLabeledScope\":true,\"length\":3,\"paths\":1,\"sanitized\":false,\"sink\":\"eval($value)\",\"sinkArg0Literal\":false,\"sinkArity\":1,\"sinkFile\":\"api.php\",\"sinkLine\":\"4\",\"sinkMethod\":\"handler\",\"source\":\"$_GET[\\\"value\\\"]\",\"sourceKind\":\"framework\"}]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + } + ], + "family_coverage": [ + { + "unit": "repository", + "language": "php", + "family": "deserialization", + "selected": 2, + "completed": 0, + "unanswered": 2, + "deferred": 0, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "injection", + "selected": 2, + "completed": 1, + "unanswered": 1, + "deferred": 0, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "output_encoding", + "selected": 2, + "completed": 0, + "unanswered": 2, + "deferred": 0, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "path", + "selected": 2, + "completed": 0, + "unanswered": 2, + "deferred": 0, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "untrusted_destination", + "selected": 2, + "completed": 0, + "unanswered": 2, + "deferred": 0, + "unsupported": 0 + } + ] + } + }, + { + "comparison": { + "head_oid": "11bb29e44eaa453a74c8cc115093aee25f2c5430", + "base_oid": "f73ce23fa3a3dff278161652471571d230a26f5d", + "base_reason": "explicit_local_replay", + "refs": [ + "refs/heads/replay" + ] + }, + "side": "base", + "scan": { + "findings": [], + "by_rung": { + "suspicion": 0, + "model_corroborated": 0, + "model_entailed": 0, + "execution_confirmed": 0 + }, + "regions_scanned": 1, + "regions_unjudged": 1, + "regions_unasked": 0, + "model_calls": 0, + "cost_usd": 0.0, + "seconds": 66.68, + "build_seconds": 27.76, + "query_seconds": 19.2, + "query_seconds_by_kind": { + "evidence": 19.62, + "taint": 19.2 + }, + "degradations": [], + "tiers": [ + [ + "api.php", + "handler", + "deserialization", + 0 + ], + [ + "api.php", + "handler", + "injection", + 3 + ], + [ + "api.php", + "handler", + "output_encoding", + 0 + ], + [ + "api.php", + "handler", + "path", + 0 + ], + [ + "api.php", + "handler", + "untrusted_destination", + 0 + ], + [ + "api.php", + "", + "deserialization", + 0 + ], + [ + "api.php", + "", + "injection", + 0 + ], + [ + "api.php", + "", + "output_encoding", + 0 + ], + [ + "api.php", + "", + "path", + 0 + ], + [ + "api.php", + "", + "untrusted_destination", + 0 + ] + ], + "tier_counts": { + "0": 9, + "3": 1 + }, + "requests_pruned": 9, + "partitions": [ + { + "language": "php", + "frontend": "php", + "paths": [ + "api.php" + ], + "source_bytes": 76, + "status": "built", + "boundaries": [], + "runtime": "unspecified", + "excluded_paths": [], + "unshipped_paths": [] + } + ], + "change_context": null, + "scope": { + "ranker_version": "existing-static-evidence-v1", + "ranking_mode": "evidence", + "population_complete": true, + "selected": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "priority": 0.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[{\"arg0_literal\":false,\"arity\":1,\"cleansed_on_call\":false,\"code\":\"eval($value)\",\"line\":4,\"method\":\"handler\"}],\"source_local\":false,\"source_near\":false}", + "tier=3", + "score=1.5" + ], + "tier": 3, + "score": 1.5 + } + ], + "deferred": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + } + ], + "unresolved_boundaries": [] + }, + "question_outcomes": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "status": "completed", + "reason": "query_answered_and_arbitrated", + "raw_rows_json": "[]" + } + ], + "family_coverage": [ + { + "unit": "repository", + "language": "php", + "family": "deserialization", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "injection", + "selected": 1, + "completed": 1, + "unanswered": 0, + "deferred": 1, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "output_encoding", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "path", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "untrusted_destination", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + } + ] + } + } + ], + "provenance": { + "engine": "joern-4.0.625", + "facts": "32edb6e1a78f1afb08ac4248cd436be16663e0d90dc1b3aaf948f2ce49a5a8f0", + "queries": "cdd625fc9013f43452a76ec727282cbf82374f3604be36648b6dbbd6aebf1535", + "policy": "b0b41d4a151a06b05c659208416f936f237a5dc3a16cfe588bbf723140f754e4", + "repository": "/tmp/ousast-replay-smoke-0p2xuvac/repo", + "model": "disabled", + "requested_base": "f73ce23fa3a3dff278161652471571d230a26f5d", + "requested_head": "11bb29e44eaa453a74c8cc115093aee25f2c5430", + "core": "29df707d0b3c5abf2eb3da9cd84580f6d48abc236dcb9b5b6378c5ee27957fdf", + "semantics": "1e36ea1ba503218899c49bdd58f04a01f35d17b2a83bb3e433e5088624489e3a", + "ranking_mode": "evidence", + "capabilities": "empty_registry_pending_task_8.3", + "cache": "cold_no_reuse" + }, + "timings": { + "deadline_seconds": 900, + "cancellation_allowance_seconds": 2.0, + "resolution_seconds": 0.028142574010416865, + "provenance_seconds": 0.023446628008969128, + "preparation_seconds": 0.1673227440332994, + "head_seconds": 79.27245896309614, + "base_seconds": 67.28292583802249, + "admission_seconds": 0.00491544499527663, + "cleanup_seconds": 0.00042137003038078547, + "total_seconds": 146.78073913499247 + }, + "timing_scope": "Caller stage measurements; publication and rendering duration is returned in ReportDelivery.", + "resolution": null + } + }, + "completion": { + "verified": true, + "case": "security" + }, + "process_exit_code": 0 + }, + { + "name": "fixed", + "data": { + "case": "fixed", + "source_bytes": 75, + "elapsed_seconds": 316.24181448004674, + "exit_code": 0, + "report_error": null, + "reporting_seconds": 0.024129868019372225, + "text": "No actionable defects reported; analysis is incomplete.\nNotice: Some checks could not be completed. Review the comparison details and resolve the recorded gaps before retrying.\nDetails: /tmp/ousast-replay-smoke-_54qgzaj/replay.json\n", + "artifact": { + "schema_version": 1, + "snapshots": [ + { + "commit_oid": "57fd3f7c18b660b4ac2def8584e661d8589e6f26", + "object_format": "sha1", + "files": [ + { + "path_hex": "6170692e706870", + "blob_oid": "7e99786afe2b66f90af1abd3effc99327fcb2e55", + "mode": "100644", + "size_bytes": 76, + "sha256": "ce927591f5ff35a4c3ca38de4cdce9e9310d5fc176e7e2feecd2e309f6388c6a" + } + ], + "boundaries": [], + "tree_complete": true, + "bytes_read": 76 + }, + { + "commit_oid": "cf488a02cdea77b0a383f2cb9c63f05ca90b7390", + "object_format": "sha1", + "files": [ + { + "path_hex": "6170692e706870", + "blob_oid": "d9b631a6b465a68a7ddfbcfc289eb8cf4124e00b", + "mode": "100644", + "size_bytes": 83, + "sha256": "fd919c616a59d10a6a71383ac0d5228ed2fc0eb6c90461dd3ef5dfeab835abf8" + } + ], + "boundaries": [], + "tree_complete": true, + "bytes_read": 83 + } + ], + "change_context": { + "base_revision": "cf488a02cdea77b0a383f2cb9c63f05ca90b7390", + "head_revision": "57fd3f7c18b660b4ac2def8584e661d8589e6f26", + "changed_paths": [ + "6170692e706870" + ], + "deleted_paths": [], + "spans": [ + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "base" + }, + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "head" + } + ], + "renames": [], + "declaration_paths": [], + "relationships": [], + "unresolved_boundaries": [], + "path_encoding": "filesystem-bytes-hex", + "line_correspondences": [ + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 1, + "base_end_line": 1, + "head_start_line": 1 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 2, + "base_end_line": 2, + "head_start_line": 2 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 4, + "base_end_line": 4, + "head_start_line": 4 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 5, + "base_end_line": 5, + "head_start_line": 5 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 6, + "base_end_line": 6, + "head_start_line": 6 + } + ] + }, + "result": { + "analyses": [ + { + "comparison": { + "head_oid": "57fd3f7c18b660b4ac2def8584e661d8589e6f26", + "base_oid": "cf488a02cdea77b0a383f2cb9c63f05ca90b7390", + "base_reason": "explicit_local_replay", + "refs": [ + "refs/heads/replay" + ] + }, + "scopes": [ + { + "ranker_version": "existing-static-evidence-v1", + "ranking_mode": "evidence", + "population_complete": true, + "selected": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "priority": 0.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"deserialization\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"deserialization\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "priority": -1.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[{\"arg0_literal\":false,\"arity\":1,\"cleansed_on_call\":false,\"code\":\"eval($value)\",\"line\":4,\"method\":\"handler\"}],\"source_local\":false,\"source_near\":false}", + "tier=3", + "score=1.5", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}" + ], + "tier": 3, + "score": 1.5 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "priority": -2.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "priority": -3.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "priority": -4.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "priority": -5.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "priority": -6.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "priority": -7.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "priority": -8.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "priority": -9.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + } + ], + "deferred": [], + "unresolved_boundaries": [ + "dynamic_external_or_depth_context_unresolved:contributor-scan:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "dynamic_external_or_depth_context_unresolved:contributor-scan:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "context_scope_empty:contributor-scan:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "context_scope_empty:contributor-scan:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "context_scope_empty:contributor-scan:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "context_scope_empty:contributor-scan:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "context_scope_empty:contributor-scan:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed" + ] + } + ], + "completed_questions": [ + { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + } + ], + "coverage_status": "incomplete" + } + ], + "finding_status": "none", + "coverage_status": "incomplete", + "push_disposition": "allow", + "actionable_defect_ids": [] + }, + "admission": { + "defects": [], + "dispositions": [], + "coverage_reasons": [ + "analysis_incomplete" + ] + }, + "scans": [ + { + "comparison": { + "head_oid": "57fd3f7c18b660b4ac2def8584e661d8589e6f26", + "base_oid": "cf488a02cdea77b0a383f2cb9c63f05ca90b7390", + "base_reason": "explicit_local_replay", + "refs": [ + "refs/heads/replay" + ] + }, + "side": "head", + "scan": { + "findings": [], + "by_rung": { + "suspicion": 0, + "model_corroborated": 0, + "model_entailed": 0, + "execution_confirmed": 0 + }, + "regions_scanned": 2, + "regions_unjudged": 0, + "regions_unasked": 0, + "model_calls": 0, + "cost_usd": 0.0, + "seconds": 171.86, + "build_seconds": 55.47, + "query_seconds": 63.69, + "query_seconds_by_kind": { + "evidence": 52.47, + "taint": 63.69 + }, + "degradations": [], + "tiers": [ + [ + "api.php", + "handler", + "deserialization", + 0 + ], + [ + "api.php", + "handler", + "injection", + 3 + ], + [ + "api.php", + "handler", + "output_encoding", + 0 + ], + [ + "api.php", + "handler", + "path", + 0 + ], + [ + "api.php", + "handler", + "untrusted_destination", + 0 + ], + [ + "api.php", + "", + "deserialization", + 0 + ], + [ + "api.php", + "", + "injection", + 0 + ], + [ + "api.php", + "", + "output_encoding", + 0 + ], + [ + "api.php", + "", + "path", + 0 + ], + [ + "api.php", + "", + "untrusted_destination", + 0 + ] + ], + "tier_counts": { + "0": 9, + "3": 1 + }, + "requests_pruned": 0, + "partitions": [ + { + "language": "php", + "frontend": "php", + "paths": [ + "api.php" + ], + "source_bytes": 76, + "status": "built", + "boundaries": [], + "runtime": "unspecified", + "excluded_paths": [], + "unshipped_paths": [] + } + ], + "change_context": { + "base_revision": "cf488a02cdea77b0a383f2cb9c63f05ca90b7390", + "head_revision": "57fd3f7c18b660b4ac2def8584e661d8589e6f26", + "changed_paths": [ + "6170692e706870" + ], + "deleted_paths": [], + "spans": [ + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "base" + }, + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "head" + } + ], + "renames": [], + "declaration_paths": [], + "relationships": [ + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + }, + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + }, + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + }, + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + }, + { + "source": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "target": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "kind": "entry", + "evidence": [ + "base_span:api.php:3-3", + "head_span:api.php:3-3", + "unchanged_line:2;lexical_only", + "unchanged_line:4;lexical_only", + "unchanged_line:5;lexical_only" + ] + } + ], + "unresolved_boundaries": [ + "dynamic_external_or_depth_context_unresolved:contributor-scan:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "dynamic_external_or_depth_context_unresolved:contributor-scan:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "context_scope_empty:contributor-scan:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "context_scope_empty:contributor-scan:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "context_scope_empty:contributor-scan:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "context_scope_empty:contributor-scan:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "context_scope_empty:contributor-scan:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed" + ], + "path_encoding": "filesystem-bytes-hex", + "line_correspondences": [ + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 1, + "base_end_line": 1, + "head_start_line": 1 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 2, + "base_end_line": 2, + "head_start_line": 2 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 4, + "base_end_line": 4, + "head_start_line": 4 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 5, + "base_end_line": 5, + "head_start_line": 5 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 6, + "base_end_line": 6, + "head_start_line": 6 + } + ] + }, + "scope": { + "ranker_version": "existing-static-evidence-v1", + "ranking_mode": "evidence", + "population_complete": true, + "selected": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "priority": 0.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"deserialization\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"deserialization\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "priority": -1.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[{\"arg0_literal\":false,\"arity\":1,\"cleansed_on_call\":false,\"code\":\"eval($value)\",\"line\":4,\"method\":\"handler\"}],\"source_local\":false,\"source_near\":false}", + "tier=3", + "score=1.5", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}" + ], + "tier": 3, + "score": 1.5 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "priority": -2.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "priority": -3.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "priority": -4.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.php:3-3\",\"head_span:api.php:3-3\",\"unchanged_line:2;lexical_only\",\"unchanged_line:4;lexical_only\",\"unchanged_line:5;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"},\"target\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"php\",\"path\":\"api.php\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "priority": -5.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "priority": -6.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "priority": -7.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "priority": -8.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "priority": -9.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0", + "change_sites={\"base_revision\":\"cf488a02cdea77b0a383f2cb9c63f05ca90b7390\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"57fd3f7c18b660b4ac2def8584e661d8589e6f26\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + } + ], + "deferred": [], + "unresolved_boundaries": [ + "dynamic_external_or_depth_context_unresolved:contributor-scan:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "dynamic_external_or_depth_context_unresolved:contributor-scan:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "dynamic_external_or_depth_context_unresolved:contributor-scan:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "context_scope_empty:contributor-scan:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "context_scope_empty:contributor-scan:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "context_scope_empty:contributor-scan:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "context_scope_empty:contributor-scan:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "context_scope_empty:contributor-scan:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed" + ] + }, + "question_outcomes": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "status": "completed", + "reason": "query_answered_and_arbitrated", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "status": "unresolved", + "reason": "change_context_incomplete", + "raw_rows_json": "[]" + } + ], + "family_coverage": [ + { + "unit": "repository", + "language": "php", + "family": "deserialization", + "selected": 2, + "completed": 0, + "unanswered": 2, + "deferred": 0, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "injection", + "selected": 2, + "completed": 1, + "unanswered": 1, + "deferred": 0, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "output_encoding", + "selected": 2, + "completed": 0, + "unanswered": 2, + "deferred": 0, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "path", + "selected": 2, + "completed": 0, + "unanswered": 2, + "deferred": 0, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "untrusted_destination", + "selected": 2, + "completed": 0, + "unanswered": 2, + "deferred": 0, + "unsupported": 0 + } + ] + } + }, + { + "comparison": { + "head_oid": "57fd3f7c18b660b4ac2def8584e661d8589e6f26", + "base_oid": "cf488a02cdea77b0a383f2cb9c63f05ca90b7390", + "base_reason": "explicit_local_replay", + "refs": [ + "refs/heads/replay" + ] + }, + "side": "base", + "scan": { + "findings": [ + { + "site": "api.php:4:handler", + "family": "injection", + "rung": "model_entailed", + "witness": "$_GET[\"value\"] -> eval($value) in api.php (line 4, 3 steps)", + "contradiction": "", + "reached_from": 1 + } + ], + "by_rung": { + "suspicion": 0, + "model_corroborated": 0, + "model_entailed": 1, + "execution_confirmed": 0 + }, + "regions_scanned": 1, + "regions_unjudged": 1, + "regions_unasked": 0, + "model_calls": 0, + "cost_usd": 0.0, + "seconds": 141.37, + "build_seconds": 73.99, + "query_seconds": 24.1, + "query_seconds_by_kind": { + "evidence": 43.16, + "taint": 24.1 + }, + "degradations": [], + "tiers": [ + [ + "api.php", + "handler", + "deserialization", + 0 + ], + [ + "api.php", + "handler", + "injection", + 4 + ], + [ + "api.php", + "handler", + "output_encoding", + 0 + ], + [ + "api.php", + "handler", + "path", + 0 + ], + [ + "api.php", + "handler", + "untrusted_destination", + 0 + ], + [ + "api.php", + "", + "deserialization", + 0 + ], + [ + "api.php", + "", + "injection", + 0 + ], + [ + "api.php", + "", + "output_encoding", + 0 + ], + [ + "api.php", + "", + "path", + 0 + ], + [ + "api.php", + "", + "untrusted_destination", + 0 + ] + ], + "tier_counts": { + "0": 9, + "4": 1 + }, + "requests_pruned": 9, + "partitions": [ + { + "language": "php", + "frontend": "php", + "paths": [ + "api.php" + ], + "source_bytes": 83, + "status": "built", + "boundaries": [], + "runtime": "unspecified", + "excluded_paths": [], + "unshipped_paths": [] + } + ], + "change_context": null, + "scope": { + "ranker_version": "existing-static-evidence-v1", + "ranking_mode": "evidence", + "population_complete": true, + "selected": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "priority": 0.0, + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[{\"arg0_literal\":false,\"arity\":1,\"cleansed_on_call\":false,\"code\":\"eval($value)\",\"line\":4,\"method\":\"handler\"}],\"source_local\":true,\"source_near\":true}", + "tier=4", + "score=4.5" + ], + "tier": 4, + "score": 4.5 + } + ], + "deferred": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.3", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":true,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":true,\"source_near\":true}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":true,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "reason": "tier_zero", + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"mysqli_prepare\",\"mysqli_stmt_bind_param\",\"pg_execute\",\"pg_prepare\"],\"carried\":false,\"carried_weak\":false,\"entry\":false,\"family_in_repo\":false,\"shipped\":true,\"sinks\":[],\"source_local\":false,\"source_near\":false}", + "tier=0", + "score=0.0" + ] + } + ], + "unresolved_boundaries": [] + }, + "question_outcomes": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "status": "completed", + "reason": "query_answered_and_arbitrated", + "raw_rows_json": "[{\"bound\":\"\",\"bounded\":false,\"inLabeledScope\":true,\"length\":3,\"paths\":1,\"sanitized\":false,\"sink\":\"eval($value)\",\"sinkArg0Literal\":false,\"sinkArity\":1,\"sinkFile\":\"api.php\",\"sinkLine\":\"4\",\"sinkMethod\":\"handler\",\"source\":\"$_GET[\\\"value\\\"]\",\"sourceKind\":\"framework\"}]" + } + ], + "family_coverage": [ + { + "unit": "repository", + "language": "php", + "family": "deserialization", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "injection", + "selected": 1, + "completed": 1, + "unanswered": 0, + "deferred": 1, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "output_encoding", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "path", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "untrusted_destination", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + } + ] + } + } + ], + "provenance": { + "engine": "joern-4.0.625", + "facts": "32edb6e1a78f1afb08ac4248cd436be16663e0d90dc1b3aaf948f2ce49a5a8f0", + "queries": "cdd625fc9013f43452a76ec727282cbf82374f3604be36648b6dbbd6aebf1535", + "policy": "fc76ffdafe8a6c63d477ef32910d2c236354b3eda9ef92da0ad913ee952a9069", + "repository": "/tmp/ousast-replay-smoke-_54qgzaj/repo", + "model": "disabled", + "requested_base": "cf488a02cdea77b0a383f2cb9c63f05ca90b7390", + "requested_head": "57fd3f7c18b660b4ac2def8584e661d8589e6f26", + "core": "29df707d0b3c5abf2eb3da9cd84580f6d48abc236dcb9b5b6378c5ee27957fdf", + "semantics": "1e36ea1ba503218899c49bdd58f04a01f35d17b2a83bb3e433e5088624489e3a", + "ranking_mode": "evidence", + "capabilities": "empty_registry_pending_task_8.3", + "cache": "cold_no_reuse" + }, + "timings": { + "deadline_seconds": 900, + "cancellation_allowance_seconds": 2.0, + "resolution_seconds": 0.039656939916312695, + "provenance_seconds": 0.038474444998428226, + "preparation_seconds": 0.1858093859627843, + "head_seconds": 172.74959687201772, + "base_seconds": 143.2016130099073, + "admission_seconds": 2.7002068236470222e-05, + "cleanup_seconds": 0.0002769129350781441, + "total_seconds": 316.2162177239079 + }, + "timing_scope": "Caller stage measurements; publication and rendering duration is returned in ReportDelivery.", + "resolution": null + } + }, + "completion": { + "verified": true, + "case": "fixed" + }, + "process_exit_code": 0 + }, + { + "name": "deadline", + "data": { + "case": "security", + "source_bytes": 82, + "elapsed_seconds": 30.784966182080097, + "exit_code": 0, + "report_error": null, + "reporting_seconds": 0.04128431505523622, + "text": "No actionable defects reported; analysis is incomplete.\nNotice: Analysis did not finish. Rerun with a longer analysis deadline.\nDetails: /tmp/ousast-replay-smoke-26ew3d4f/replay.json\n", + "artifact": { + "schema_version": 1, + "snapshots": [ + { + "commit_oid": "9dc048607d6dfca40d6637543ba9ddd2a75df759", + "object_format": "sha1", + "files": [ + { + "path_hex": "6170692e706870", + "blob_oid": "d9b631a6b465a68a7ddfbcfc289eb8cf4124e00b", + "mode": "100644", + "size_bytes": 83, + "sha256": "fd919c616a59d10a6a71383ac0d5228ed2fc0eb6c90461dd3ef5dfeab835abf8" + } + ], + "boundaries": [], + "tree_complete": true, + "bytes_read": 83 + }, + { + "commit_oid": "8ab18f5ac06f56c98527816befb8a2a2e9b61f6a", + "object_format": "sha1", + "files": [ + { + "path_hex": "6170692e706870", + "blob_oid": "7e99786afe2b66f90af1abd3effc99327fcb2e55", + "mode": "100644", + "size_bytes": 76, + "sha256": "ce927591f5ff35a4c3ca38de4cdce9e9310d5fc176e7e2feecd2e309f6388c6a" + } + ], + "boundaries": [], + "tree_complete": true, + "bytes_read": 76 + } + ], + "change_context": { + "base_revision": "8ab18f5ac06f56c98527816befb8a2a2e9b61f6a", + "head_revision": "9dc048607d6dfca40d6637543ba9ddd2a75df759", + "changed_paths": [ + "6170692e706870" + ], + "deleted_paths": [], + "spans": [ + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "base" + }, + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "head" + } + ], + "renames": [], + "declaration_paths": [], + "relationships": [], + "unresolved_boundaries": [], + "path_encoding": "filesystem-bytes-hex", + "line_correspondences": [ + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 1, + "base_end_line": 1, + "head_start_line": 1 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 2, + "base_end_line": 2, + "head_start_line": 2 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 4, + "base_end_line": 4, + "head_start_line": 4 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 5, + "base_end_line": 5, + "head_start_line": 5 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 6, + "base_end_line": 6, + "head_start_line": 6 + } + ] + }, + "result": { + "analyses": [ + { + "comparison": { + "head_oid": "9dc048607d6dfca40d6637543ba9ddd2a75df759", + "base_oid": "8ab18f5ac06f56c98527816befb8a2a2e9b61f6a", + "base_reason": "explicit_local_replay", + "refs": [ + "refs/heads/replay" + ] + }, + "scopes": [ + { + "ranker_version": "existing-static-evidence-v1", + "ranking_mode": "evidence", + "population_complete": true, + "selected": [], + "deferred": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + } + ], + "unresolved_boundaries": [ + "cpg_build_failed", + "evidence_unknown:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "evidence_unknown:904570982387a4ceec809e9d755043d2cd3faac4ec7ccec0b2003098aef966c7", + "evidence_unknown:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "evidence_unknown:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "evidence_unknown:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "evidence_unknown:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "evidence_unknown:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "evidence_unknown:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "evidence_unknown:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "evidence_unknown:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed" + ] + } + ], + "completed_questions": [], + "coverage_status": "incomplete" + } + ], + "finding_status": "none", + "coverage_status": "incomplete", + "push_disposition": "allow", + "actionable_defect_ids": [] + }, + "admission": { + "defects": [], + "dispositions": [], + "coverage_reasons": [ + "deadline_exhausted", + "admission_failed:TimeoutError", + "cpg_build_failed", + "evidence_unknown:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "evidence_unknown:904570982387a4ceec809e9d755043d2cd3faac4ec7ccec0b2003098aef966c7", + "evidence_unknown:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "evidence_unknown:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "evidence_unknown:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "evidence_unknown:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "evidence_unknown:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "evidence_unknown:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "evidence_unknown:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "evidence_unknown:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed", + "analysis_incomplete", + "base_comparison_unavailable" + ] + }, + "scans": [ + { + "comparison": { + "head_oid": "9dc048607d6dfca40d6637543ba9ddd2a75df759", + "base_oid": "8ab18f5ac06f56c98527816befb8a2a2e9b61f6a", + "base_reason": "explicit_local_replay", + "refs": [ + "refs/heads/replay" + ] + }, + "side": "head", + "scan": { + "findings": [], + "by_rung": { + "suspicion": 0, + "model_corroborated": 0, + "model_entailed": 0, + "execution_confirmed": 0 + }, + "regions_scanned": 0, + "regions_unjudged": 2, + "regions_unasked": 0, + "model_calls": 0, + "cost_usd": 0.0, + "seconds": 29.38, + "build_seconds": 29.28, + "query_seconds": 0.0, + "query_seconds_by_kind": {}, + "degradations": [ + { + "stage": "model", + "reason": "cpg_build_failed", + "detail": "the graph could not answer the census (timeout or no payload), so no query would be answered either" + }, + { + "stage": "model", + "reason": "deadline_exhausted" + } + ], + "tiers": [], + "tier_counts": {}, + "requests_pruned": 0, + "partitions": [ + { + "language": "php", + "frontend": "php", + "paths": [ + "api.php" + ], + "source_bytes": 83, + "status": "build_failed", + "boundaries": [], + "runtime": "unspecified", + "excluded_paths": [], + "unshipped_paths": [] + } + ], + "change_context": { + "base_revision": "8ab18f5ac06f56c98527816befb8a2a2e9b61f6a", + "head_revision": "9dc048607d6dfca40d6637543ba9ddd2a75df759", + "changed_paths": [ + "6170692e706870" + ], + "deleted_paths": [], + "spans": [ + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "base" + }, + { + "path": "6170692e706870", + "start_line": 3, + "end_line": 3, + "side": "head" + } + ], + "renames": [], + "declaration_paths": [], + "relationships": [], + "unresolved_boundaries": [], + "path_encoding": "filesystem-bytes-hex", + "line_correspondences": [ + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 1, + "base_end_line": 1, + "head_start_line": 1 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 2, + "base_end_line": 2, + "head_start_line": 2 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 4, + "base_end_line": 4, + "head_start_line": 4 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 5, + "base_end_line": 5, + "head_start_line": 5 + }, + { + "base_path": "6170692e706870", + "head_path": "6170692e706870", + "base_start_line": 6, + "base_end_line": 6, + "head_start_line": 6 + } + ] + }, + "scope": { + "ranker_version": "existing-static-evidence-v1", + "ranking_mode": "evidence", + "population_complete": true, + "selected": [], + "deferred": [ + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "deserialization" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "injection" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "output_encoding" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "path" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "handler", + "family": "untrusted_destination" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.3", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "deserialization" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "injection" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "output_encoding" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "path" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + }, + { + "identity": { + "unit": "repository", + "language": "php", + "path": "api.php", + "function": "", + "family": "untrusted_destination" + }, + "reason": "cpg_build_failed", + "evidence": [ + "static_rank=0.15", + "evidence_unknown", + "change_sites={\"base_revision\":\"8ab18f5ac06f56c98527816befb8a2a2e9b61f6a\",\"changed_paths\":[\"6170692e706870\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"9dc048607d6dfca40d6637543ba9ddd2a75df759\",\"path_encoding\":\"filesystem-bytes-hex\"}" + ] + } + ], + "unresolved_boundaries": [ + "cpg_build_failed", + "evidence_unknown:2f5748a12b3473830320bffc27c1a027f00e2ded7f566c36dc6b4ff582d50515", + "evidence_unknown:904570982387a4ceec809e9d755043d2cd3faac4ec7ccec0b2003098aef966c7", + "evidence_unknown:afb3c1cd783e7ae870337b2c0552a8e092e4a449cb8ca40196e61d1d3bbf50fa", + "evidence_unknown:2043d2eebfa4d6ea02585e295eb8affadd90eabaaaf08e539957b21052e05eaa", + "evidence_unknown:712848f58bfd6a7239d201d5e6755f7de6cf388b92b4dfda4ce66ee2631c9ecb", + "evidence_unknown:7ed88d7a34033f61c83c828fb6ca95ae05c8c797c76fb4fee35852d265e1e666", + "evidence_unknown:8e7574a0b3fcef6a6627442cd7b7205805935f23a050eeb0f7758894e834237d", + "evidence_unknown:fac7db8a574a34a5941cf25877730e995a95110300f9ef51ed625ed8c0d6bc51", + "evidence_unknown:bcb76ec6c388629c6ac547120d2d4ee9fec811bbb8bcbfd532c6b6a0d23ab6d4", + "evidence_unknown:78d518c4f4c4af4ecce78989b9365f38be6c0373bb903c24f218c83ba6cdfeed" + ] + }, + "question_outcomes": [], + "family_coverage": [ + { + "unit": "repository", + "language": "php", + "family": "deserialization", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "injection", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "output_encoding", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "path", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + }, + { + "unit": "repository", + "language": "php", + "family": "untrusted_destination", + "selected": 0, + "completed": 0, + "unanswered": 0, + "deferred": 2, + "unsupported": 0 + } + ] + } + } + ], + "provenance": { + "engine": "joern-4.0.625", + "facts": "32edb6e1a78f1afb08ac4248cd436be16663e0d90dc1b3aaf948f2ce49a5a8f0", + "queries": "cdd625fc9013f43452a76ec727282cbf82374f3604be36648b6dbbd6aebf1535", + "policy": "2ed1f678cd11f6ef060561935cd0aaae92ed009c6e1e802e39f1b239597aa765", + "repository": "/tmp/ousast-replay-smoke-26ew3d4f/repo", + "model": "disabled", + "requested_base": "8ab18f5ac06f56c98527816befb8a2a2e9b61f6a", + "requested_head": "9dc048607d6dfca40d6637543ba9ddd2a75df759", + "core": "29df707d0b3c5abf2eb3da9cd84580f6d48abc236dcb9b5b6378c5ee27957fdf", + "semantics": "1e36ea1ba503218899c49bdd58f04a01f35d17b2a83bb3e433e5088624489e3a", + "ranking_mode": "evidence", + "capabilities": "empty_registry_pending_task_8.3", + "cache": "cold_no_reuse" + }, + "timings": { + "deadline_seconds": 30.0, + "cancellation_allowance_seconds": 2.0, + "resolution_seconds": 0.031065345974639058, + "provenance_seconds": 0.02125667594373226, + "preparation_seconds": 0.15581317408941686, + "head_seconds": 29.903724926989526, + "base_seconds": 0.6298638089792803, + "admission_seconds": 0.0002758160699158907, + "total_seconds": 30.74270467297174 + }, + "timing_scope": "Caller stage measurements; publication and rendering duration is returned in ReportDelivery.", + "resolution": null + } + }, + "completion": { + "verified": true, + "case": "security" + }, + "process_exit_code": 0 + } + ], + "validation": { + "tests_passed": 1236, + "tests_skipped": 9, + "test_exit_code": 0, + "build_exit_code": 0, + "cli_help_exit_code": 0, + "static_checks": "PASS", + "regression_gates": "PASS" + }, + "provenance_note": "Security control ran from final packaged image with matching policy/core/facts/query hashes. Fixed control used the production runner with source-mounted code before narrow comparison and snapshot-boundary repairs; it emitted no head finding. Deadline control used the packaged runner before final policy/snapshot-boundary repairs; deadline code was unchanged. No complete coverage or capability qualification follows.", + "limits": [ + "real capability registry empty", + "automatic unrelated context gaps retained", + "900-second controls are lab runs, not hook latency", + "full PMPro and frozen-core Node experiment remains task5.2" + ] +} diff --git a/ops/README.md b/ops/README.md index 494808c..aa13e28 100644 --- a/ops/README.md +++ b/ops/README.md @@ -242,3 +242,27 @@ allowance; a stalled writer is killed. A hard cancellation can leave a private `.partial-` file, which is never the published artifact and cannot establish a completed result. Serialization/write failure emits one notice without replacing the finding, coverage or push decision. + +## Explicit local replay + +Task 5.1 adds `ousast pre-push REPOSITORY --base BASE --head HEAD --artifact OUTSIDE_REPOSITORY.json`. +Both revisions must already exist locally. The command records their resolved commit identities, +materializes tracked object bytes in private scratch storage, discovers regions through the existing +mapper, and runs the existing evidence ranker, arbiter, targeted base comparison and admission policy. +It installs no hook and requires no model endpoint. All real capabilities remain experimental and +ineligible for normal alerts until task 8.3; diagnostic candidates remain in the JSON artifact. + +`--deadline` defaults to 30 seconds, `--cancellation-allowance` to 2 seconds, and `--max-regions` +to 500. Preparation, both revisions and reporting share that elapsed budget. `--mode blocking` +and `--incomplete-coverage block` explicitly select enforcement; default advisory exit zero means +allow, never complete analysis. This initial replay interface requires the artifact outside the +analyzed repository, including resolved symlink destinations, to preserve the live source and index. +Artifact failure cannot change the actual allow/block decision. + +`ops/smoke_replay.py --case security|fixed` exercises a real controlled PHP change through this +production runner, without supplying hand-selected regions. Its default 900-second budget is a +separately labeled runtime laboratory check, not hook latency. `--deadline 30` exercises cancellation; +it does not demand a positive after an interrupted query. Run with the network-disabled packaged +image, mounting the smoke script read-only as for the other smoke scripts. Snapshot manifests +record verified immutable source bytes; full scan records retain exact selected/deferred questions, +raw answers, per-question gaps, change context and candidate dispositions. diff --git a/ops/smoke_replay.py b/ops/smoke_replay.py new file mode 100644 index 0000000..c1fab42 --- /dev/null +++ b/ops/smoke_replay.py @@ -0,0 +1,89 @@ +"""Real production replay on a controlled PHP security change and its fixed twin.""" + +from __future__ import annotations + +import argparse +import json +import os +import subprocess +import tempfile +import time +from pathlib import Path + +from openultrasast.config import PushConfig +from openultrasast.push.runner import replay + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--case", choices=("security", "fixed"), required=True) + parser.add_argument("--deadline", type=float, default=900) + args = parser.parse_args() + with tempfile.TemporaryDirectory(prefix="ousast-replay-smoke-") as temporary: + root = Path(temporary) / "repo" + root.mkdir() + + def git(*parts: str) -> str: + return subprocess.run(["git", "-C", str(root), *parts], check=True, capture_output=True, timeout=10).stdout.decode().strip() + + git("init") + git("config", "user.name", "Replay smoke") + git("config", "user.email", "replay@example.invalid") + git("config", "core.hooksPath", os.devnull) + source = root / "api.php" + before = ' 0 + source.write_text("dirty live content") + index = (root / ".git/index").read_bytes() + status = git("status", "--porcelain") + artifact = Path(temporary) / "replay.json" + start = time.monotonic() + delivery = replay(root, base=base, head=head, artifact=artifact, config=PushConfig(deadline_seconds=args.deadline)) + payload = json.loads(artifact.read_text()) if artifact.exists() else None + print( + json.dumps( + { + "case": args.case, + "source_bytes": len(readable.encode()), + "elapsed_seconds": time.monotonic() - start, + "exit_code": delivery.exit_code, + "report_error": delivery.error, + "reporting_seconds": delivery.reporting_seconds, + "text": delivery.text, + "artifact": payload, + }, + indent=2, + ), + flush=True, + ) + assert source.read_text() == "dirty live content" + assert (root / ".git/index").read_bytes() == index + assert git("status", "--porcelain") == status + assert payload and payload["scans"], "production runner produced no scan evidence" + assert delivery.result.finding_status == "none" and delivery.exit_code == 0 + if args.deadline >= 900: + head_scan = next(r["scan"] for r in payload["scans"] if r["side"] == "head") + assert head_scan["scope"]["ranking_mode"] == "evidence" + if args.case == "security": + assert any(d["candidate"]["delta"]["novelty"] in ("new", "worsened") for d in payload["admission"]["dispositions"]), ( + "supported security control missing: inspect upstream evidence before claiming replay complete" + ) + else: + assert not head_scan["findings"], "fixed twin retained a modeled finding" + print(json.dumps({"verified": True, "case": args.case}), flush=True) + + +if __name__ == "__main__": + main() diff --git a/src/openultrasast/cli.py b/src/openultrasast/cli.py index 8b9f2a6..ea25539 100644 --- a/src/openultrasast/cli.py +++ b/src/openultrasast/cli.py @@ -110,6 +110,17 @@ def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(prog="ousast") subparsers = parser.add_subparsers(dest="command", required=True) + replay_parser = subparsers.add_parser("pre-push", help="replay explicit local base/head revisions (experimental)") + replay_parser.add_argument("path", type=Path) + replay_parser.add_argument("--base", required=True) + replay_parser.add_argument("--head", required=True) + replay_parser.add_argument("--artifact", type=Path, required=True) + replay_parser.add_argument("--deadline", type=float, default=30.0) + replay_parser.add_argument("--cancellation-allowance", type=float, default=2.0) + replay_parser.add_argument("--max-regions", type=int, default=500) + replay_parser.add_argument("--mode", choices=("advisory", "blocking"), default="advisory") + replay_parser.add_argument("--incomplete-coverage", choices=("allow", "block"), default="allow") + scan = subparsers.add_parser("scan", help="scan a local repository") scan.add_argument("path", type=Path) scan.add_argument("--mode", choices=("quick", "standard", "deep"), default="quick") @@ -189,6 +200,24 @@ def main(argv: list[str] | None = None) -> int: candidates.add_argument("--json", action="store_true") args = parser.parse_args(argv) + if args.command == "pre-push": + from .config import PushConfig + from .push.runner import replay + + try: + settings = PushConfig( + deadline_seconds=args.deadline, + cancellation_allowance_seconds=args.cancellation_allowance, + mode=args.mode, + incomplete_coverage_policy=args.incomplete_coverage, + ) + delivery = replay( + args.path, base=args.base, head=args.head, artifact=args.artifact, config=settings, max_regions=args.max_regions + ) + except ValueError as error: + parser.error(str(error)) + print(delivery.text, end="") + return delivery.exit_code if args.command == "scan": return _scan(args.path, args.config, args.mode, args.fail_on) if args.command == "index": diff --git a/src/openultrasast/push/policy.py b/src/openultrasast/push/policy.py index bd215e0..a0b7c89 100644 --- a/src/openultrasast/push/policy.py +++ b/src/openultrasast/push/policy.py @@ -195,9 +195,25 @@ def _valid_answer(scan: ModelScanResult, question: QuestionIdentity, operations: return len(rows) == sum(op.question == question for op in operations) -def _context_boundaries(scan: ModelScanResult) -> tuple[str, ...]: - # A missing scheduling vector is not missing arbiter evidence after its question completed. - return tuple(b for b in scan.scope.unresolved_boundaries if not b.startswith("evidence_unknown:")) if scan.scope else ("scope_missing",) +def _context_boundaries(scan: ModelScanResult, question: QuestionIdentity | None = None) -> tuple[str, ...]: + # Aggregate coverage keeps every gap. A candidate may ignore only a recognized + # question-owned boundary attached to a different, recorded question. Unknown + # ownership and graph/declaration gaps remain global. + if scan.scope is None: + return ("scope_missing",) + owned_prefixes = ( + "context_projection_unavailable:contributor-scan:", + "context_scope_empty:contributor-scan:", + "dynamic_external_or_depth_context_unresolved:contributor-scan:", + ) + others = {q.identity.question_id for q in scan.scope.selected if q.identity != question} + others.update(q.identity.question_id for q in scan.scope.deferred if q.identity != question) + return tuple( + boundary + for boundary in scan.scope.unresolved_boundaries + if not boundary.startswith("evidence_unknown:") + and not (question is not None and boundary.startswith(owned_prefixes) and boundary.rsplit(":", 1)[-1] in others) + ) def _counterpart(question: QuestionIdentity, context: ChangeContext) -> QuestionIdentity: @@ -268,7 +284,7 @@ def compare_evidence( base and base.scope and base.scope.population_complete - and not base.scope.deferred + and all(question.reason == "tier_zero" for question in base.scope.deferred) and not _context_boundaries(base) and not base.degradations and _valid_answer(base, counterpart, base_ops) @@ -285,7 +301,7 @@ def compare_evidence( reason = "change_context_unresolved" elif ( not head.scope - or _context_boundaries(head) + or _context_boundaries(head, op.question) or head.degradations or not _valid_answer(head, op.question, head_ops) or op.question not in {q.identity for q in head.scope.selected} diff --git a/src/openultrasast/push/report.py b/src/openultrasast/push/report.py index 9864357..b0ba43b 100644 --- a/src/openultrasast/push/report.py +++ b/src/openultrasast/push/report.py @@ -15,9 +15,9 @@ from pathlib import Path from types import MappingProxyType from typing import Literal -from openultrasast.model.contracts import ExecutionBudget +from openultrasast.model.contracts import ChangeContext, ExecutionBudget from openultrasast.model.scan import ModelScanResult -from openultrasast.push.contracts import PushComparison, PushResolution, PushResult +from openultrasast.push.contracts import PushComparison, PushResolution, PushResult, SnapshotManifest from openultrasast.push.policy import AdmissionResult, _context_boundaries @@ -36,6 +36,8 @@ class PushReport: provenance: Mapping[str, str] timings: Mapping[str, float] resolution: PushResolution | None = None + snapshots: tuple[SnapshotManifest, ...] = () + change_context: ChangeContext | None = None def __post_init__(self) -> None: object.__setattr__(self, "provenance", MappingProxyType(dict(self.provenance))) @@ -109,6 +111,8 @@ def _write_artifact(report: PushReport, target: Path, temporary: Path, connectio with os.fdopen(fd, "w", encoding="utf-8") as stream: payload = { "schema_version": 1, + "snapshots": [item.to_payload() for item in report.snapshots], + "change_context": report.change_context.to_payload() if report.change_context else None, "result": report.result.to_payload(), "admission": report.admission.to_payload(), "scans": [asdict(record) for record in report.scans], @@ -223,7 +227,9 @@ def render_report(report: PushReport, *, artifact: Path | None, error: str | Non notices.append( "Some checks could not be completed. Review the comparison details and resolve the recorded gaps before retrying." ) - if error: + if error == "artifact_inside_repository": + notices.append("Details could not be saved. Choose an artifact path outside the analyzed repository.") + elif error: notices.append("Details could not be saved. Retry with a writable artifact path and available reporting time.") if notices: lines.append("Notice: " + " ".join(notices)) diff --git a/src/openultrasast/push/runner.py b/src/openultrasast/push/runner.py new file mode 100644 index 0000000..566b560 --- /dev/null +++ b/src/openultrasast/push/runner.py @@ -0,0 +1,279 @@ +"""Bounded, local base/head replay through the existing repository driver.""" + +from __future__ import annotations + +import hashlib +import multiprocessing +import os +import pickle +import selectors +import time +from collections.abc import Callable +from dataclasses import asdict, replace +from pathlib import Path +from typing import Any, Literal, TypeVar, cast + +from openultrasast.config import PushConfig +from openultrasast.cpg.backend import joern_version, resolve_cpg_backend +from openultrasast.mapping import analyze_entry_points +from openultrasast.model.contracts import ExecutionBudget +from openultrasast.model.regions import ScanRegion, regions_for +from openultrasast.model.scan import ScanBudget, scan_repository +from openultrasast.model.shipped import declared_sources +from openultrasast.preprocess import build_file_target, enumerate_source_files +from openultrasast.push.contracts import ComparisonAnalysis, SnapshotManifest +from openultrasast.push.policy import ( + AdmissionCandidate, + AdmissionResult, + CapabilityKey, + admission_push_result, + admit_candidates, + compare_targeted_base, + semantics_digest, +) +from openultrasast.push.report import PushReport, ReportDelivery, ScanRecord, _completed_scan, deliver_report, render_report +from openultrasast.push.snapshot import SnapshotAdapter + +_T = TypeVar("_T") + + +def _prepare(function: Callable[[], _T], budget: ExecutionBudget) -> _T: + """Bound pure local discovery/metadata work, including serialization, on Linux. + + Read incrementally while the child writes; no pipe-buffer deadlock or unbounded + blocking recv. The child never launches engines or project code. + """ + if time.monotonic() >= budget.deadline_monotonic: + raise TimeoutError("deadline_exhausted") + reader, writer = os.pipe() + + def child() -> None: + os.close(reader) + try: + payload: tuple[bool, Any] + try: + payload = (True, function()) + except Exception as error: + payload = (False, type(error).__name__) + with os.fdopen(writer, "wb") as stream: + pickle.dump(payload, stream, protocol=5) + finally: + os._exit(0) + + process = multiprocessing.get_context("fork").Process(target=child) + data = bytearray() + try: + process.start() + os.close(writer) + writer = -1 + with selectors.DefaultSelector() as selector: + selector.register(reader, selectors.EVENT_READ) + while selector.get_map(): + remaining = budget.deadline_monotonic - time.monotonic() + if remaining <= 0: + raise TimeoutError("deadline_exhausted") + for key, _ in selector.select(min(0.05, remaining)): + chunk = os.read(key.fd, 65536) + if not chunk: + selector.unregister(key.fileobj) + else: + data.extend(chunk) + if len(data) > 32 * 1024**2: + raise ValueError("preparation_output_limit") + process.join(max(0, budget.deadline_monotonic - time.monotonic())) + if process.is_alive() or process.exitcode != 0 or not data: + raise RuntimeError("preparation_worker_failed") + success, result = pickle.loads(data) # trusted child, never repository-provided pickle + if not success: + raise RuntimeError("preparation_failed:" + result) + return cast(_T, result) + finally: + os.close(reader) + if writer >= 0: + os.close(writer) + if process.pid is not None: + if process.is_alive(): + process.kill() + process.join(max(0, budget.deadline_monotonic + budget.cancellation_allowance_seconds - time.monotonic())) + if not process.is_alive(): + process.close() + + +def _discover(root: Path) -> tuple[tuple[ScanRegion, ...], tuple[bytes, ...]]: + # Same proposer and declaration-based shipping rules as ordinary scans. Do not + # call preprocess's live-HEAD probe on a materialized, intentionally Git-free tree. + files = enumerate_source_files(root) + targets = [build_file_target(root, path) for path in files] + regions = regions_for(analyze_entry_points(root, targets), targets, shipped=declared_sources(root)) + # Conservatively seed every tracked declaration/non-source file. This is change + # context only, never a graph allowlist or a second scope selector. + sources = set(files) + declarations = tuple(os.fsencode(str(p.relative_to(root))) for p in root.rglob("*") if p.is_file() and p not in sources) + return regions, declarations + + +def _provenance(repository: Path, scan_budget: ScanBudget) -> dict[str, str]: + root = Path(__file__).resolve().parents[1] + + def digest(paths: list[Path]) -> str: + hasher = hashlib.sha256() + for path in sorted(paths): + hasher.update(str(path.relative_to(root)).encode()) + hasher.update(path.read_bytes()) + return hasher.hexdigest() + + version = joern_version() + engine = "joern-" + (".".join(map(str, version)) if version else "unavailable_or_unidentified") + return { + "repository": str(repository.absolute()), + "engine": engine, + "facts": digest(list((root / "ruleset").rglob("*.toml"))), + "queries": digest(list((root / "cpg/queries").glob("*.sc"))), + "policy": digest(list((root / "push").glob("*.py"))), + "core": digest(list((root / "model").glob("*.py")) + list((root / "cpg").glob("*.py"))), + "semantics": semantics_digest(engine_identity=engine, options=asdict(scan_budget)), + "ranking_mode": "evidence", + "model": "disabled", + "capabilities": "empty_registry_pending_task_8.3", + "cache": "cold_no_reuse", + } + + +def replay( + repository: Path, + *, + base: str, + head: str, + artifact: Path, + config: PushConfig | None = None, + backend: Any = None, + max_regions: int = 500, +) -> ReportDelivery: + """Run a single explicit comparison; exit policy never stands for coverage.""" + config = config or PushConfig() + if max_regions < 1: + raise ValueError("max_regions must be positive") + started = time.monotonic() + budget = ExecutionBudget(started + config.deadline_seconds, config.cancellation_allowance_seconds) + scan_budget = ScanBudget(max_model_calls=0, max_regions=max_regions, order_by_evidence=True) + records: list[ScanRecord] = [] + manifests: list[SnapshotManifest] = [] + reasons: list[str] = [] + admission = AdmissionResult((), (), ()) + comparison = None + context = None + timings: dict[str, float] = { + "deadline_seconds": config.deadline_seconds, + "cancellation_allowance_seconds": config.cancellation_allowance_seconds, + } + provenance = {key: "unavailable_preparation_incomplete" for key in ("engine", "facts", "queries", "policy")} + provenance.update(repository=str(repository.absolute()), model="disabled", requested_base=base, requested_head=head) + stage = "resolution" + stage_started = started + try: + adapter = SnapshotAdapter(repository, execution_budget=budget) + comparison = adapter.resolve_replay(base, head) + timings[stage + "_seconds"] = time.monotonic() - stage_started + stage, stage_started = "provenance", time.monotonic() + provenance.update(_prepare(lambda: _provenance(repository, scan_budget), budget)) + timings[stage + "_seconds"] = time.monotonic() - stage_started + stage, stage_started = "preparation", time.monotonic() + with adapter.materialize(comparison.head_oid, budget=budget) as tip: + manifests.append(tip.manifest) + assert comparison.base_oid is not None + with adapter.materialize(comparison.base_oid, budget=budget) as old: + manifests.append(old.manifest) + for manifest in manifests: + reasons.extend("snapshot:" + boundary.reason for boundary in manifest.boundaries) + head_regions, head_declarations = _prepare(lambda: _discover(tip.root), budget) + base_regions, base_declarations = _prepare(lambda: _discover(old.root), budget) + context = adapter.compare(comparison, declaration_paths=tuple(set(head_declarations + base_declarations)), budget=budget) + context = replace(context, unresolved_boundaries=tuple(dict.fromkeys((*context.unresolved_boundaries, *reasons)))) + reasons.extend(context.unresolved_boundaries) + timings[stage + "_seconds"] = time.monotonic() - stage_started + stage, stage_started = "head", time.monotonic() + head_scan = scan_repository( + tip.root, + head_regions, + backend=backend or resolve_cpg_backend(), + budget=scan_budget, + execution_budget=budget, + ranking_mode="evidence", + unit="repository", + population_complete=all(m.complete for m in manifests), + change_context=context, + ) + records.append(ScanRecord(comparison, "head", head_scan)) + timings[stage + "_seconds"] = time.monotonic() - stage_started + stage, stage_started = "base", time.monotonic() + delta = compare_targeted_base( + old.root, + head=head_scan, + head_regions=head_regions, + base_regions=base_regions, + context=context, + backend=backend or resolve_cpg_backend(), + execution_budget=budget, + scan_budget=scan_budget, + head_semantics=provenance["semantics"], + base_semantics=provenance["semantics"], + ) + if delta.base_scan is not None: + records.append(ScanRecord(comparison, "base", delta.base_scan)) + reasons.extend(delta.coverage_reasons) + timings[stage + "_seconds"] = time.monotonic() - stage_started + stage, stage_started = "admission", time.monotonic() + candidates = tuple( + AdmissionCandidate( + c, + CapabilityKey( + c.head_operation.question.language if c.head_operation else "unknown", + "unspecified", + "unspecified", + c.family, + c.head_operation.mechanism if c.head_operation else "taint", + "unreviewed", + delta.semantics, + ), + comparison, + tuple(reasons), + ) + for c in delta.candidates + ) + admission = _prepare(lambda: admit_candidates(candidates), budget) + timings[stage + "_seconds"] = time.monotonic() - stage_started + stage, stage_started = "cleanup", time.monotonic() + timings[stage + "_seconds"] = time.monotonic() - stage_started + except Exception as error: + reasons.append(stage + "_failed:" + type(error).__name__) + timings[stage + "_seconds"] = time.monotonic() - stage_started + if time.monotonic() >= budget.deadline_monotonic: + reasons.append("deadline_exhausted") + head_records = [r.scan for r in records if r.side == "head"] + for record in records: + if record.scan.scope is not None: + reasons.extend(record.scan.scope.unresolved_boundaries) + if not records or not all(_completed_scan(r.scan) for r in records): + reasons.append("analysis_incomplete") + if not any(r.side == "base" for r in records): + reasons.append("base_comparison_unavailable") + admission = replace(admission, coverage_reasons=tuple(dict.fromkeys((*admission.coverage_reasons, *reasons)))) + analyses: tuple[ComparisonAnalysis, ...] = () + if comparison is not None: + scopes = tuple(scan.scope for scan in head_records if scan.scope is not None) + completed = tuple(outcome.identity for scan in head_records for outcome in scan.question_outcomes if outcome.status == "completed") + coverage: Literal["unavailable", "incomplete", "complete_within_scope"] = ( + "unavailable" if not records else "incomplete" if admission.coverage_reasons else "complete_within_scope" + ) + analyses = (ComparisonAnalysis(comparison, scopes, completed, coverage),) + result = admission_push_result(admission, analyses, config=config) + timings["total_seconds"] = time.monotonic() - started + report = PushReport(result, admission, tuple(records), provenance, timings, snapshots=tuple(manifests), change_context=context) + try: + artifact.resolve().relative_to(repository.resolve()) + except ValueError: + pass + else: + write_error = "artifact_inside_repository" + return ReportDelivery(result, render_report(report, artifact=None, error=write_error), None, write_error) + return deliver_report(report, artifact, execution_budget=budget) diff --git a/src/openultrasast/push/snapshot.py b/src/openultrasast/push/snapshot.py index 5c823d2..e79eb9d 100644 --- a/src/openultrasast/push/snapshot.py +++ b/src/openultrasast/push/snapshot.py @@ -44,7 +44,8 @@ class SnapshotInputError(ValueError): class SnapshotAdapter: - def __init__(self, repository: Path, *, comparison_base: str | None = None) -> None: + def __init__(self, repository: Path, *, comparison_base: str | None = None, execution_budget: ExecutionBudget | None = None) -> None: + self.execution_budget = execution_budget self.repository = repository.resolve() self.comparison_base = comparison_base # Hook-inherited Git variables may redirect objects or worktrees elsewhere. @@ -72,10 +73,22 @@ class SnapshotAdapter: def _repository_path(self, *args: str) -> Path: # Binary framing also matters for the repository's own whitespace/non-UTF8 name. - raw = self._bounded_git(("rev-parse", *args), 65536, ExecutionBudget(time.monotonic() + 10.0, 2.0), None, []) + raw = self._bounded_git( + ("rev-parse", *args), 65536, self.execution_budget or ExecutionBudget(time.monotonic() + 10.0, 2.0), None, [] + ) return Path(os.fsdecode(raw.removesuffix(b"\n"))).resolve() def _git(self, *args: str, input: str | None = None) -> subprocess.CompletedProcess[str]: + if self.execution_budget is not None: + if input not in (None, ""): + raise SnapshotInputError("bounded_resolution_requires_empty_stdin") + try: + raw = self._bounded_git(tuple(args), 16 * 1024**2, self.execution_budget, None, []) + return subprocess.CompletedProcess(args, 0, raw.decode("utf-8", "surrogateescape"), "") + except SnapshotInputError as error: + if str(error).startswith("local_git_") and "_failed_exit_" in str(error): + return subprocess.CompletedProcess(args, 1, "", "") + raise try: return subprocess.run( ["git", "-c", "protocol.allow=never", "-c", "core.hooksPath=" + os.devnull, "-C", str(self.repository), *args], @@ -97,6 +110,17 @@ class SnapshotAdapter: raise SnapshotInputError(f"local Git {args[0]} failed (exit {result.returncode})") return result.stdout.strip() + def resolve_replay(self, base: str, head: str) -> PushComparison: + """Resolve explicitly supplied local revisions without inferred baselines or fetching.""" + resolved = [] + for revision in (base, head): + oid = self._required("rev-parse", "--verify", "--end-of-options", revision) + commit, kind = self._commit(oid) + if commit is None: + raise SnapshotInputError("replay_revision_" + kind) + resolved.append(commit) + return PushComparison(resolved[1], resolved[0], "explicit_local_replay", ("refs/heads/replay",)) + def parse_updates(self, data: str) -> tuple[PushUpdate, ...]: """Validate every record before attempting resolution; malformed input fails closed.""" updates = [] diff --git a/tests/test_push_policy.py b/tests/test_push_policy.py index c89248a..e6dcd4f 100644 --- a/tests/test_push_policy.py +++ b/tests/test_push_policy.py @@ -206,3 +206,35 @@ def test_non_string_operation_cannot_prove_base_absence(): row = json.loads(scan(line=5).question_outcomes[0].raw_rows_json)[0] row["sink"] = 42 assert delta(scan(), scan(line=5, rows=[row])).novelty == "unknown" + + +def test_unrelated_question_context_gap_does_not_poison_completed_comparison(): + head = scan() + other = replace(head.scope.selected[0].identity, family="path") + gap = "dynamic_external_or_depth_context_unresolved:contributor-scan:" + other.question_id + head = replace( + head, + scope=replace(head.scope, selected=(*head.scope.selected, RankedQuestion(other, 0.0, ())), unresolved_boundaries=(gap,)), + question_outcomes=(*head.question_outcomes, QuestionOutcome(other, "unresolved", "change_context_incomplete", "[]")), + ) + assert delta(head, scan(rows=[], findings=False)).novelty == "new" + own_gap = gap.rsplit(":", 1)[0] + ":" + head.scope.selected[0].identity.question_id + assert ( + delta(replace(head, scope=replace(head.scope, unresolved_boundaries=(own_gap,))), scan(rows=[], findings=False)).novelty + == "unknown" + ) + assert ( + delta(replace(head, scope=replace(head.scope, unresolved_boundaries=("graph_incomplete",))), scan(rows=[], findings=False)).novelty + == "unknown" + ) + + +def test_proven_tier_zero_other_families_do_not_invalidate_base_answer(): + from openultrasast.model.contracts import DeferredQuestion + + base = scan(rows=[], findings=False) + other = replace(base.scope.selected[0].identity, family="path") + base = replace(base, scope=replace(base.scope, deferred=(DeferredQuestion(other, "tier_zero", ()),))) + assert delta(scan(), base).novelty == "new" + base = replace(base, scope=replace(base.scope, deferred=(DeferredQuestion(other, "budget_exhausted", ()),))) + assert delta(scan(), base).novelty == "unknown" diff --git a/tests/test_push_runner.py b/tests/test_push_runner.py new file mode 100644 index 0000000..be65d75 --- /dev/null +++ b/tests/test_push_runner.py @@ -0,0 +1,198 @@ +from __future__ import annotations + +import json +import os +import subprocess +import time + +import pytest + +from openultrasast.config import PushConfig +from openultrasast.cpg.backend import NullBackend +from openultrasast.push.runner import replay + + +def history(tmp_path): + root = tmp_path / "repo" + root.mkdir() + + def git(*args): + return subprocess.run(["git", "-C", str(root), *args], check=True, capture_output=True).stdout.strip().decode() + + git("init") + git("config", "user.name", "Replay test") + git("config", "user.email", "replay@example.invalid") + git("config", "core.hooksPath", os.devnull) + source = root / "api.js" + source.write_text('function handler(req, res) {\n const value = "fixed";\n eval(value);\n}\napp.post("/run", handler);\n') + git("add", "api.js") + git("commit", "-m", "base") + base = git("rev-parse", "HEAD") + source.write_text(source.read_text().replace('"fixed"', "req.body.value")) + git("add", "api.js") + git("commit", "-m", "head") + head = git("rev-parse", "HEAD") + source.write_text("dirty source must never be scanned") + return root, base, head, git + + +def test_replay_unavailable_preserves_input_and_records_scope(tmp_path): + root, base, head, git = history(tmp_path) + before = (root / ".git/index").read_bytes(), git("status", "--porcelain") + artifact = tmp_path / "result.json" + delivery = replay(root, base=base, head=head, artifact=artifact, backend=NullBackend()) + data = json.loads(artifact.read_text()) + assert delivery.exit_code == 0 + assert delivery.result.coverage_status in ("unavailable", "incomplete") + assert data["result"]["analyses"][0]["comparison"]["base_oid"] == base + assert data["result"]["analyses"][0]["comparison"]["head_oid"] == head + assert data["scans"][0]["scan"]["scope"]["ranking_mode"] == "evidence" + assert data["provenance"]["model"] == "disabled" + assert data["snapshots"][0]["bytes_read"] > 0 + assert (root / "api.js").read_text() == "dirty source must never be scanned" + assert ((root / ".git/index").read_bytes(), git("status", "--porcelain")) == before + + +def test_missing_revision_is_unavailable_not_clean(tmp_path): + root, base, head, _ = history(tmp_path) + result = replay(root, base="missing-ref", head=head, artifact=tmp_path / "missing.json") + assert result.result.coverage_status == "unavailable" + assert result.exit_code == 0 + assert "Notice:" in result.text + + +def test_expired_preparation_obeys_total_deadline(tmp_path): + root, base, head, _ = history(tmp_path) + start = time.monotonic() + result = replay( + root, + base=base, + head=head, + artifact=tmp_path / "expired.json", + config=PushConfig(deadline_seconds=0.001, cancellation_allowance_seconds=0.5), + ) + assert time.monotonic() - start < 0.55 + assert result.result.coverage_status != "complete_within_scope" + + +def test_strict_incomplete_policy_and_artifact_failure(tmp_path): + root, base, head, _ = history(tmp_path) + result = replay( + root, + base=base, + head=head, + artifact=tmp_path, + config=PushConfig(mode="blocking", incomplete_coverage_policy="block"), + backend=NullBackend(), + ) + assert result.exit_code == 1 and result.error and result.artifact is None + + +def test_hanging_discovery_is_bounded(tmp_path, monkeypatch): + from openultrasast.push import runner + + root, base, head, _ = history(tmp_path) + monkeypatch.setattr(runner, "_discover", lambda *args: time.sleep(5)) + start = time.monotonic() + result = replay( + root, + base=base, + head=head, + artifact=tmp_path / "hung.json", + config=PushConfig(deadline_seconds=0.3, cancellation_allowance_seconds=0.5), + ) + assert time.monotonic() - start < 0.85 + assert result.result.coverage_status == "unavailable" + assert "deadline" in (tmp_path / "hung.json").read_text() + + +def test_cli_exposes_replay(tmp_path, capsys): + from openultrasast.cli import main + + root, base, head, _ = history(tmp_path) + assert ( + main(["pre-push", str(root), "--base", base, "--head", head, "--artifact", str(tmp_path / "cli.json"), "--deadline", "0.001"]) == 0 + ) + assert "Notice:" in capsys.readouterr().out + + +def test_replay_artifact_cannot_overwrite_live_repository(tmp_path): + root, base, head, _ = history(tmp_path) + source = root / "api.js" + before = source.read_bytes() + result = replay(root, base=base, head=head, artifact=source, backend=NullBackend()) + assert result.artifact is None and result.error == "artifact_inside_repository" + assert source.read_bytes() == before + + +def test_snapshot_resolution_uses_shared_deadline(tmp_path, monkeypatch): + from openultrasast.model.contracts import ExecutionBudget + from openultrasast.push.snapshot import SnapshotAdapter, SnapshotInputError + + bin_dir = tmp_path / "bin" + bin_dir.mkdir() + launcher = bin_dir / "git" + launcher.write_text("#!/bin/sh\nexec sleep 5\n") + launcher.chmod(0o755) + monkeypatch.setenv("PATH", str(bin_dir) + os.pathsep + os.environ["PATH"]) + started = time.monotonic() + with pytest.raises(SnapshotInputError, match="deadline"): + SnapshotAdapter(tmp_path, execution_budget=ExecutionBudget(started + 0.1, 0.5)) + assert time.monotonic() - started < 0.65 + + +def test_preparation_exit_zero_without_receipt_is_failure(): + from openultrasast.model.contracts import ExecutionBudget + from openultrasast.push.runner import _prepare + + with pytest.raises(RuntimeError, match="worker_failed"): + _prepare(lambda: os._exit(0), ExecutionBudget(time.monotonic() + 1, 0.5)) + + +def test_base_failure_retains_completed_head_evidence(tmp_path, monkeypatch): + from test_push_policy import scan + + from openultrasast.push import runner + + root, base, head, _ = history(tmp_path) + seen = [] + + def head_scan(root, regions, **kwargs): + assert (root / "api.js").read_bytes() and regions + assert kwargs["ranking_mode"] == "evidence" and kwargs["change_context"].head_revision == head + seen.append(kwargs["execution_budget"]) + return scan(path="api.js") + + def failed_base(*args, **kwargs): + assert kwargs["execution_budget"] is seen[0] + raise RuntimeError("failed comparison") + + monkeypatch.setattr(runner, "scan_repository", head_scan) + monkeypatch.setattr(runner, "compare_targeted_base", failed_base) + artifact = tmp_path / "partial.json" + result = replay(root, base=base, head=head, artifact=artifact) + data = json.loads(artifact.read_text()) + assert result.result.coverage_status == "incomplete" + assert len(data["scans"][0]["scan"]["findings"]) == 1 + assert len(data["result"]["analyses"][0]["completed_questions"]) == 1 + assert "base_failed:RuntimeError" in data["admission"]["coverage_reasons"] + + +def test_preparation_large_result_does_not_deadlock(): + from openultrasast.model.contracts import ExecutionBudget + from openultrasast.push.runner import _prepare + + assert len(_prepare(lambda: b"x" * 1_000_000, ExecutionBudget(time.monotonic() + 2, 0.5))) == 1_000_000 + + +def test_snapshot_boundaries_reach_engine_change_context(tmp_path): + root, base, head, git = history(tmp_path) + (root / "external.js").symlink_to("/unavailable/external.js") + git("add", "external.js") + git("commit", "-m", "external context") + head = git("rev-parse", "HEAD") + artifact = tmp_path / "boundary.json" + result = replay(root, base=base, head=head, artifact=artifact, backend=NullBackend()) + data = json.loads(artifact.read_text()) + assert result.result.coverage_status == "incomplete" + assert "snapshot:symlink_not_materialized" in data["change_context"]["unresolved_boundaries"]