diff --git a/.kiro/specs/pre-push-safety-net/brief.md b/.kiro/specs/pre-push-safety-net/brief.md index 67611a8..4bd08c5 100644 --- a/.kiro/specs/pre-push-safety-net/brief.md +++ b/.kiro/specs/pre-push-safety-net/brief.md @@ -1,6 +1,6 @@ # Brief: pre-push-safety-net -Status: requirements, design and tasks approved; groups 1–5 implemented and verified (16/27 subtasks). The first PMPro/Node experiment is measured NO-GO: six cold timeouts, no completed target checks. Groups 6–8 pending; normal capabilities remain disabled and warm hook latency unproven. Language: English. +Status: requirements, design and tasks approved; groups 1–6 implemented and verified (20/27 subtasks). Compatible preparation/graph/query reuse is demonstrated, including packaged JavaScript evidence equivalence. Groups 7–8 pending. Rollout remains NO-GO: changed-code feasibility and independent capability qualification are not established; normal capabilities remain disabled. Language: English. ## Problem @@ -10,12 +10,18 @@ maintainer explicitly rejects noisy advisory output as well as noisy blocking ou ## Current State -The scan driver and Joern arbiters exist, with demonstrated PHP/Python cases. Immutable push-tip -resolution, isolated source materialization and lexical change context are implemented and verified. -Ranker integration, persistent graph caching and an end-to-end deadline remain pending. -The driver builds a whole-root graph before cutting the region budget. The latest PMPro ranking -experiment alone spends about 130 seconds building and 296 seconds extracting evidence. A manually -selected two-file slice finding a CVE does not demonstrate automatic incremental analysis. +The existing ranker, Joern arbiters, immutable replay, change comparison, actionability policy +and absolute deadline are integrated. Vendor code is physically excluded from frontend graphs +and targets. Explicit local caching reuses complete discovery, validated isolated graph copies +and compatible query evidence while reapplying current admission. Changed source/declarations +invalidate affected graph units; no incremental Joern mutation is implemented. + +Group 5's PMPro/Node cold experiment remains NO-GO. Group 6 adds a packaged JavaScript +correctness control with equal cached/uncached evidence and admission; an identical-revision +hit is fast, while the changed-code deadline remains a separate unmet gate. Automatic +context projection and independent capability eligibility remain explicit limits. See +implementation-group-6.md and the committed reuse control evidence. Historical whole-PMPro +ranking costs and manually selected CVE slices do not establish automatic push latency. ## Desired Outcome diff --git a/.kiro/specs/pre-push-safety-net/design.md b/.kiro/specs/pre-push-safety-net/design.md index 2d1d04e..b7c9823 100644 --- a/.kiro/specs/pre-push-safety-net/design.md +++ b/.kiro/specs/pre-push-safety-net/design.md @@ -147,6 +147,7 @@ New files (proposed, not created by this documentation change): | `src/openultrasast/push/contracts.py` | Immutable ref/comparison identities and comparison-owned completion/status records | | `src/openultrasast/push/snapshot.py` | Parse ref updates, resolve bases, materialize blobs, produce change context | | `src/openultrasast/push/cache.py` | Artifact keys, validity, atomic publication and eviction | +| `src/openultrasast/push/reuse.py` | Complete discovery reuse and backend graph/query reuse through the existing driver | | `src/openultrasast/push/policy.py` | Delta identity, actionability admission and push disposition | | `src/openultrasast/push/runner.py` | Shared deadline, ranker/engine orchestration, per-ref result aggregation | | `src/openultrasast/push/report.py` | Compact terminal result and reproducible push manifest | @@ -157,8 +158,9 @@ Contract configuration (task 1.4) uses `[push]`: optional `comparison_base`, pos `deadline_seconds` (30), positive `cancellation_allowance_seconds` (2), positive integer `cache_max_bytes` (2 GiB), `mode` (`advisory` by default, or `blocking`) and independent `incomplete_coverage_policy` (`allow` by default, or `block`). Unknown keys, malformed -sections and coerced/nonfinite numeric values are rejected. These settings are inert until -runner integration; they do not enable a hook or admit experimental capabilities. The cache +sections and coerced/nonfinite numeric values are rejected. Experimental replay consumes the deadline, mode, coverage policy and optional cache budget. +An explicit `--cache-dir` enables local reuse; omission retains a cold control. These settings +do not install a hook or admit experimental capabilities. The cache limit is a local storage budget, not a latency claim. Completion records are owned by an exact comparison so reused head graphs cannot merge evidence from different bases. Live leases have no JSON constructor; only the backend can validate and issue them in task 6.1. @@ -251,7 +253,7 @@ cleanup consume the same execution deadline and cancellation allowance as the ba Runtime origin is `unspecified` when no declaration establishes browser/server scope; JavaScript presence alone does not admit an Express capability. TypeScript and C/C++ retain explicit capability limits. These records prepare later artifact manifests; -they do not implement persistent graph storage. +task 6 now binds them to backend-owned persistent graph manifests and isolated leases. Graph key: digest of every included blob/path and applicable declarations, frontend/engine version, overlay semantics/options, language, and exclusions. Query key additionally includes graph key, diff --git a/.kiro/specs/pre-push-safety-net/implementation-group-6.md b/.kiro/specs/pre-push-safety-net/implementation-group-6.md index c8c0a3a..b5ca26c 100644 --- a/.kiro/specs/pre-push-safety-net/implementation-group-6.md +++ b/.kiro/specs/pre-push-safety-net/implementation-group-6.md @@ -103,3 +103,96 @@ the cache never confers eligibility. JSON decoding is non-executable and bounded - CLAIM: Task 6.3 semantic keys and completed comparison evidence reuse. - EVIDENCE: production policy integration and cache key tests, 1260 passing suite tests and final static checks. - GAPS: Graph/query/preparation reuse must still be connected to replay under 6.4; no rollout claim. + +## Task 6.4 brief + +Requirements 1.1, 2.2, 4.1, 4.2, 4.3, 4.4 and 7.3; design: Push Runner and +Cache and Engine Boundary. Explicit `--cache-dir` integrates the three cache layers; +omitting it preserves a cold replay control. Complete immutable snapshots are still read +and verified by the adapter before persisted discovery can be used. Equal base/head revisions +share one live materialization. Discovery keys include exact file identities and shipped code/facts; +dependency/declaration changes invalidate them. Graph units remain the existing physical frontend +partitions. Source changes rebuild the affected unit; all declaration and exclusion context is +bound. There is no incremental graph mutation or changed-file scope selector. + +The runner uses backend-issued copies and per-question cached raw answers, then runs the existing +ranker, arbiter, comparison and current admission. Partial answers are not promoted to complete +lookups. Complete answers already returned by the engine remain available when persistence cannot +finish. Query keys include actual parameters and graph bytes; graph keys do not include unrelated +ranking/security-fact versions. Layout/exclusion facts and frontend adaptation bytes do affect them. +Integration review repaired the task 6.1 identity to include installed frontend/adaptation bytes, +rather than relying only on Joern's release label. This is an owning-contract repair, not a new +frontend or a detector change. + +The first source-mounted/package integration trial is retained separately from the final +frozen image run. It showed equal cached/uncached evidence and admission (including one +new JavaScript injection candidate), a 1.23-second identical-revision hit, and a 30.48-second +dependency-edit timeout. Those numbers are preliminary control evidence, not the final image +or rollout measurements. Final review also binds installed runtime identity into admission +semantics, while avoiding a second backend instance or an unbudgeted availability probe. + +The cache entry lease ends after its validated bytes are copied into the backend's independent +working lease. The working copy remains valid if storage later evicts the original entry; +queries never operate on the stored original. Partial fresh answers cannot borrow a cached +answer's census. Pure discovery remains in the existing bounded child process; persisted +JSON is decoded as data, never executable objects. + +## Status Report +- STATUS: READY_FOR_REVIEW +- TASK: 6.4 +- RED_PHASE_OUTPUT: `/tmp/group6-4-red.log`: graph/query reuse and replay discovery/cache-location tests failed before integration (temporary switch OFF). Enabled implementation passed; switch removed. Additional regressions cover mixed cached/fresh census failure and installed runtime provenance. +- TESTS_RUN: 89 final focused tests passed; full suite 1268 passed, 9 skipped in 108.74s. Ruff, formatting, mypy (114 source files), compileall, detection/map/pair gates and Docker build/packaged CLI smoke passed. +- EVIDENCE: final packaged JavaScript control exited 0 with exact cached/uncached scope, question outcomes, findings and admission equality. One new injection is retained as diagnostic evidence and denied normal admission by the empty registry. Source/dependency edits invalidate graph reuse and retain timed-out coverage artifacts. +- CONCERNS: identical-revision hits are development correctness controls, not representative warm p95 or capability qualification. Main-context review fallback remains explicit. + +## Review Verdict +- VERDICT: APPROVED +- TASK: 6.4 +- MECHANICAL_RESULTS: canonical tests and regression gates passed; final image reached the usable CLI and completed real replay controls. No introduced placeholders, secrets or boundary violations found. +- FINDINGS: installation-byte identity now also binds comparison/admission provenance. The predecessor no-unbudgeted-probe regression caught an unnecessary backend instance in provenance; the repair uses a pure runtime-identity function and the final regression passes. Mixed fresh/cached answers require the fresh query's own valid census before being retained as complete. Snapshot reads, discovery, ranker/driver selection, vendor boundary and independent push/coverage status remain intact. +- SUMMARY: Task 6.4 integrates valid local reuse and truthful misses under the existing transaction deadline without changing detection or admission rules. + +## Verification Result +- STATUS: VERIFIED +- CLAIM_TYPE: TASK +- CLAIM: Group 6 implementation (6.1–6.4), with compatible replay evidence and admission equivalence. +- EVIDENCE: final tests/static checks, native packaged Joern controls, and committed measurement record below. +- GAPS: Rollout remains NO-GO. Groups 7–8, representative changed-code completion/p95 and independent capability qualification remain pending. Automatic projection limitations are unchanged. + +## Final packaged evidence + +Image: `sha256:6622b846996989a321d81bfa6c25e792e3f217984d7ede66f830cff1206a634c`. +Nonroot, network disabled, 3 GiB memory; controls ran serially without concurrent +tests/builds. Filesystem cache was not flushed. Each case is one development control, +not a representative p95 population. + +| Run | Full CLI seconds | Graph hits | Query-answer hits | +|---|---:|---:|---:| +| populate | 154.848 | 0 | 0 | +| warm-identical | 2.002 | 2 | 37 | +| uncached | 130.432 | 0 | 0 | +| dependency-edit | 30.458 | 0 | 0 | +| one-function-edit | 30.479 | 0 | 0 | +| uncached, same revisions, 30s budget | 30.606 | 0 | 0 | + +Cached and uncached laboratory runs have **equal scope, question outcomes, findings and +admission**, including the known introduced JavaScript injection. The 30-second identical +cached run retains that same evidence: one completed supported head injection check plus +four base comparison checks. The same revisions without caching complete zero checks in +the 30-second control. All six CLI artifacts were retained, including timed-out edits. +Warm source/dependency edits correctly invalidate the affected graph and produce incomplete +coverage; they do not replay the old answer. The empty normal capability registry denies the +new diagnostic candidate for `capability_unavailable`; this is not a clean repository verdict. + +The manifest, full artifacts and stdout/stderr are retained in +`benchmarks/measurements/2026-09-13-reuse-control.json` and the associated final/initial +compressed bundles. Each bundle maps original filenames to exact UTF-8 content; decompression +was compared with the original files and SHA-256 hashes recorded. The committed reusable +harness is `benchmarks/push/reuse_control.py`; the extra same-revision 30-second uncached +command is recorded in the final bundle. + +**Group 6 implementation: verified. Rollout: NO-GO.** Changed-code feasibility remains +unmet in these controls, and independent precision/recall/capability populations have not +qualified. The spec now explicitly requires stage-level investigation of remaining timeouts +under task 8.2, retaining its original thresholds and population rules. Group 7 is next; +no hook has been installed and no normal capability enabled. diff --git a/.kiro/specs/pre-push-safety-net/spec.json b/.kiro/specs/pre-push-safety-net/spec.json index cd3c6ea..931f8ce 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-13T13:22:55.634332+00:00", + "updated_at": "2026-09-13T15:06:56.856952+00:00", "language": "en", "phase": "implementation", "approvals": { @@ -19,7 +19,7 @@ } }, "ready_for_implementation": true, - "implementation_approval_note": "Groups1\u20135 implemented and verified (16/27). Group5 used manual Kiro fallback review, repaired observed predecessor deadline bugs, and executed a newly frozen PMPro/Node experiment. Measured feasibility NO-GO; real capabilities remain disabled. Groups6\u20138 pending.", + "implementation_approval_note": "Groups 1\u20136 implemented and verified (20/27); group 6 authorized as a whole. Main-context Kiro review fallback after fresh dispatch thread limit. Valid reuse is demonstrated; real capability registry remains empty and rollout gates remain unmet. Groups 7\u20138 pending.", "depends_on": [ "contributor-scan" ], @@ -98,19 +98,24 @@ "4.2", "4.3", "5.1", - "5.2" + "5.2", + "6.1", + "6.2", + "6.3", + "6.4" ], - "remaining_tasks": 11, - "verification_record": "implementation-group-5.md", + "remaining_tasks": 7, + "verification_record": "implementation-group-6.md", "verification_records": [ "implementation-group-1.md", "implementation-group-2.md", "implementation-group-3.md", "implementation-group-4.md", - "implementation-group-5.md" + "implementation-group-5.md", + "implementation-group-6.md" ], - "next_group": 6, + "next_group": 7, "blocked_tasks": [], - "feasibility": "NO-GO: six cold replay timeouts; no completed supported target checks; warm performance and eligibility unproven" + "feasibility": "NO-GO for rollout: compatible identical-revision reuse verified; representative changed-code p95/completion and independent alert eligibility remain unmet." } } diff --git a/.kiro/specs/pre-push-safety-net/tasks.md b/.kiro/specs/pre-push-safety-net/tasks.md index a624617..9b77162 100644 --- a/.kiro/specs/pre-push-safety-net/tasks.md +++ b/.kiro/specs/pre-push-safety-net/tasks.md @@ -1,11 +1,12 @@ # Implementation Plan: pre-push-safety-net -Status: task plan approved by the maintainer on 2026-09-12. Groups 1–5 (tasks 1.1–5.2) -are implemented, reviewed and verified (16/27 subtasks). Tasks 4.3 and group 5 used the -documented Kiro manual review fallback after agent dispatch reached its thread limit. -The first experiment is measured NO-GO: all six cold PMPro/Node cases timed out without -completed target checks. Groups 6–8 remain pending; no production capability or warm -hook latency is admitted. +Status: task plan approved by the maintainer on 2026-09-12. Groups 1–6 (tasks 1.1–6.4) +are implemented, reviewed and verified (20/27 subtasks). Tasks 4.3 and groups 5–6 used the +explicit Kiro manual review fallback after fresh agent dispatch reached its thread limit. +Group 5's six cold PMPro/Node timeouts remain historical NO-GO evidence. Group 6 verifies +compatible reuse with equal evidence/admission in a packaged authored JavaScript control; +its identical-revision run completed in 2.00s. This is not representative warm p95 or +independent capability qualification. Groups 7–8 remain pending; rollout remains NO-GO. ## Execution contract @@ -160,7 +161,7 @@ hook latency is admitted. - _Depends: 1.2, 1.3, 5.1_ - _Requirements: 6.2, 6.3, 6.4, 6.5, 8.1, 8.2, 8.3, 8.4_ -- [ ] 6. Reuse valid graphs and results without stale conclusions +- [x] 6. Reuse valid graphs and results without stale conclusions - [x] 6.1 Validate graph artifact identity and leases - Have the backend own source/declaration/exclusion digests, frontend/engine/overlay options, graph census and complete/partial identity. - Permit validated graph leases in the generic driver while preserving the fresh-build path; isolate potentially mutating loads and retain bounded cleanup. @@ -180,7 +181,7 @@ hook latency is admitted. - Done when source, context, fact, query, mode, policy and optional model changes invalidate the appropriate layer, while an identical compatible request returns the same evidence and provenance. - _Boundary: Push cache, policy integration_ - _Requirements: 3.4, 4.3, 4.4, 6.4, 7.2, 7.3_ -- [ ] 6.4 Integrate cache reuse into the shared push deadline +- [x] 6.4 Integrate cache reuse into the shared push deadline - Reuse complete preparation/discovery by immutable tree and discovery/fact/configuration identity, retaining readable snapshot and declaration/boundary records; measure its costs and hits separately from graph/query reuse. - Reuse identical snapshots/unchanged declared units across refs without merging different comparisons; changed units rebuild and stale graph relationships remain hints only. - Account for lookup, lock wait, lease, build/query and result persistence in the same deadline; preserve completed outcomes on cancellation. @@ -219,6 +220,7 @@ hook latency is admitted. - _Requirements: 1.1, 1.2, 1.3, 1.4, 2.2, 2.3, 4.2, 4.4, 5.2, 5.5, 7.1, 7.4, 8.2_ - [ ] 8.2 Measure realistic cache and deadline feasibility - Measure identical-tip reuse, a warm one-function edit, dependency/configuration edits, cold starts, repository growth and multi-ref workloads on declared hardware. + - If reuse correctness passes but changed-code checks time out, identify preparation, frontend/overlay/census and query costs separately and route the remaining optimization to its owning boundary before rollout GO. Preserve the declared gates and do not substitute identical-tip latency. - Publish p50/p95, timeouts, cancellation allowance, completed/deferred population and stage costs; the denominator is fixed before ranker selection. - Done when the versioned scorecard evaluates the accepted latency/coverage gates without hiding timeouts or calling repeated-identical-tip hits representative warm edits; a failed gate remains NO-GO for rollout. - _Boundary: Evaluation harness, runtime integration_ @@ -244,3 +246,5 @@ hook latency is admitted. - Task5.2 measured PMPro timing out after both snapshots were materialized but before change context/graph analysis. Group6 must account for compatible snapshot/discovery reuse as well as graph reuse; identical-tip hits cannot substitute for the later representative changed-code latency gate. No new detector, scope heuristic or incremental CPG mutation is implied. - Cancellation must cover semantic planning and reporting, not only engine subprocesses: `_collect` and `_scope_work` now consume the shared deadline, and replay instantiates the budget-aware backend once. Preserve the 400-question failure-census and real Node artifact-retention regressions. + +- Group 6: complete discovery/graph/query reuse is explicit via `--cache-dir`; source/declaration edits invalidate affected units. Installed frontend/adaptation bytes now bind graph and admission provenance. A valid cached census cannot qualify a fresh answer that omitted its own census. Identical-revision timing is not the changed-code rollout gate. diff --git a/.kiro/steering/roadmap.md b/.kiro/steering/roadmap.md index f4d4c10..4fe9bd5 100644 --- a/.kiro/steering/roadmap.md +++ b/.kiro/steering/roadmap.md @@ -46,7 +46,7 @@ engine are out of scope. - [ ] pre-push-safety-net — Immutable pushed tips, existing-ranker integration, compatible artifact reuse, total deadline, change attribution, actionability admission and compact hook behavior. Dependencies: contributor-scan. Requirements/design approved 2026-09-12; tasks generated - (8 groups, 27 executable subtasks), independently reviewed and approved; groups 1–5 are implemented and verified (16/27 tasks), including the resolved frontend-retention prerequisite. + (8 groups, 27 executable subtasks), independently reviewed and approved; groups 1–6 are implemented and verified (20/27 tasks), including the resolved frontend-retention prerequisite. ### Next concrete step @@ -59,14 +59,19 @@ its deadline in preparation/discovery after materializing both trees; Node reach driver but did not complete checks. The exact 11-case population remains unresolved. No normal capability is enabled and these six cold samples establish no warm p95 claim. -Group 6 is next for valid graph/result identity, leases and reuse. Account for snapshot -and discovery costs before treating graph persistence as the sole optimization; record -compatible preparation reuse alongside graph reuse. Representative changed-code warm -latency and coverage must still be measured later, without substituting identical-tip hits. -Do not change ranking weights, add a second source-slicer or assume incremental Joern -mutation from this negative performance evidence. +Group 6 now provides complete preparation/discovery, graph and query reuse through explicit +`--cache-dir`, bounded publication and isolated graph leases. A packaged authored JavaScript +control preserved the same evidence/admission as an uncached run; its identical-revision +replay took 2.00s. Source/declaration changes invalidate affected units. This correctness +control does not establish representative changed-code p95, independent alert precision or +eligibility. Rollout remains NO-GO and normal capabilities remain disabled. -Tasks 4.3 and group 5 used the documented Kiro manual review fallback after the agent +Group 7 is next for the real multi-ref push interface and opt-in hook integration. Group 8 +must still pass the joint gates on declared populations. Keep the existing thresholds and +profile preparation, graph construction and queries separately when investigating misses; +do not substitute identical-tip hits for warm changed-code performance. + +Tasks 4.3 and groups 5–6 used the documented Kiro manual review fallback after the agent thread limit; this is not independent review. See `pre-push-safety-net/implementation-group-5.md` and `benchmarks/measurements/2026-09-13-first-replay-experiment.json` for provenance, initial instrument failures, their repairs and the newly frozen final trial. The NodeGoat diff --git a/.kiro/steering/safety-net.md b/.kiro/steering/safety-net.md index b329613..3b3ada5 100644 --- a/.kiro/steering/safety-net.md +++ b/.kiro/steering/safety-net.md @@ -79,16 +79,21 @@ updates as a shortcut to an unmeasured latency promise. The product direction above is user-requested. The amended requirements, design and initial evaluation profile in `pre-push-safety-net` were approved for task generation on 2026-09-12 ("ok, next kiro phase"). The maintainer then approved the task plan and starting group 1 -("approve.") and then group 2 ("ok, next kiro phase, approved"). Groups 1–5 are now -implemented, reviewed and verified (16/27), including the frontend-retention prerequisite -and the deadline regression exposed by full Node replay. Tasks 4.3 and group 5 used the +("approve.") and then group 2 ("ok, next kiro phase, approved"). Groups 1–6 are now +implemented, reviewed and verified (20/27), including the frontend-retention prerequisite +and the deadline regression exposed by full Node replay. Tasks 4.3 and groups 5–6 used the explicit Kiro manual review fallback after the agent thread limit. The first newly frozen PMPro/Node experiment is measured **NO-GO**: all six cold cases timed out without completed supported target checks, while retaining all 11 declared cases. The repaired CLI saved all artifacts and returned in 30.55–30.64 seconds. PMPro exhausted the deadline in preparation/discovery before graph analysis, so compatible preparation -reuse matters alongside graph persistence. Group 6 is next; warm changed-code performance +reuse matters alongside graph persistence. Group 6 now provides compatible local reuse; warm changed-code performance and useful coverage remain mandatory later gates. No ranking/fact adaptation or holdout inspection occurred in the final transfer run. Real capability eligibility and automatic dominance context projection remain unproven; the default capability registry is empty. + +Group 6 verified equal cached/uncached evidence and current admission in a packaged authored +JavaScript control. Source/declaration edits invalidate affected units. Identical-revision +latency does not qualify representative changed-code performance. Requirements and rollout +thresholds remain unchanged; groups 7–8 and independent capability admission remain pending. diff --git a/benchmarks/measurements/2026-09-08-module-audit.json b/benchmarks/measurements/2026-09-08-module-audit.json index a60b336..b67dad7 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": 103, + "load_bearing": 104, "standalone_capability": 9 }, - "modules": 112, - "note": "Refreshed for task 6.2: bounded local artifact storage, integrated by task 6.4.", + "modules": 113, + "note": "Refreshed for group 6: replay reaches compatible graph, query, discovery and comparison reuse.", "orphaned": [], "rows": [ { @@ -118,6 +118,7 @@ "config", "cpg.artifact", "model.contracts", + "push.cache", "push.contracts", "push.policy" ], @@ -139,6 +140,7 @@ "model.taint", "push.cache", "push.policy", + "push.reuse", "push.runner" ], "module": "cpg", @@ -148,7 +150,10 @@ "classification": "load_bearing", "importers": [ "cpg.backend", - "push.cache" + "push.cache", + "push.policy", + "push.reuse", + "push.runner" ], "module": "cpg.artifact", "reason": "pre-push-safety-net Req 4.3/7.3: backend graph identity and live lease contract; validation integration pending" @@ -167,6 +172,7 @@ "model.taint", "push.cache", "push.policy", + "push.reuse", "push.runner" ], "module": "cpg.backend", @@ -374,6 +380,7 @@ "push.contracts", "push.policy", "push.report", + "push.reuse", "push.runner", "push.snapshot" ], @@ -421,6 +428,7 @@ "push.contracts", "push.policy", "push.report", + "push.reuse", "push.runner", "push.snapshot" ], @@ -484,7 +492,8 @@ "importers": [ "model.partitions", "model.scan", - "preprocess" + "preprocess", + "push.runner" ], "module": "model.layout", "reason": "reachable from gate, map_gate, pair_gate or the CLI" @@ -513,6 +522,7 @@ "model.layout", "model.scan", "push.policy", + "push.reuse", "push.runner" ], "module": "model.regions", @@ -690,6 +700,7 @@ "cli", "push.policy", "push.report", + "push.reuse", "push.runner", "push.snapshot" ], @@ -698,7 +709,11 @@ }, { "classification": "load_bearing", - "importers": [], + "importers": [ + "push.policy", + "push.reuse", + "push.runner" + ], "module": "push.cache", "reason": "pre-push-safety-net task 6.2: bounded artifact publication and leased eviction; runner integration in 6.4" }, @@ -707,6 +722,7 @@ "importers": [ "push.policy", "push.report", + "push.reuse", "push.runner", "push.snapshot" ], @@ -730,6 +746,14 @@ "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": [ + "push.runner" + ], + "module": "push.reuse", + "reason": "reachable from gate, map_gate, pair_gate or the CLI" + }, { "classification": "load_bearing", "importers": [ diff --git a/benchmarks/measurements/2026-09-13-reuse-control.json b/benchmarks/measurements/2026-09-13-reuse-control.json new file mode 100644 index 0000000..e2e9ccc --- /dev/null +++ b/benchmarks/measurements/2026-09-13-reuse-control.json @@ -0,0 +1,1627 @@ +{ + "purpose": "Group 6 authored JavaScript reuse correctness and invalidation control; not independent capability qualification", + "image": "sha256:6622b846996989a321d81bfa6c25e792e3f217984d7ede66f830cff1206a634c", + "environment": { + "network": "none", + "memory_limit_bytes": 3221225472, + "user": "image nonroot ousast", + "filesystem_cache": "uncontrolled", + "workloads": "serial; no concurrent tests/builds during final timed controls" + }, + "harness": "benchmarks/push/reuse_control.py mounted read-only; additional same-revision 30-second uncached CLI command retained in bundle", + "harness_sha256": "900393eb6cc614162136f5a70b6be13fa34cff2e3a80824e69d8a4ccf8c77cf2", + "final_summary": { + "cold_populated_evidence_equal": true, + "cold_warm_evidence_equal": true, + "admission_equal": true, + "runs": [ + { + "name": "populate", + "elapsed_seconds": 154.84820935002062, + "exit_code": 0, + "timings": { + "deadline_seconds": 600.0, + "cancellation_allowance_seconds": 2.0, + "resolution_seconds": 0.01658846205100417, + "provenance_seconds": 0.3594230430899188, + "snapshot_seconds": 0.016923974035307765, + "snapshot_reuses": 0, + "discovery_seconds": 0.15945994993671775, + "discovery_hits": 0, + "preparation_seconds": 0.20162996603175998, + "head_seconds": 78.34064441197552, + "base_seconds": 75.3250151189277, + "admission_seconds": 0.006018119980581105, + "cleanup_seconds": 0.0003920870367437601, + "graph_hits": 0, + "query_hits": 0, + "total_seconds": 154.2775415830547 + }, + "result": { + "analyses": [ + { + "comparison": { + "head_oid": "458817181ffff46da686825cdea0e27189fb447d", + "base_oid": "54b3130ca5354201a00bbd841640f6cb8651aaf8", + "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": "javascript", + "path": "api.js", + "function": "handler", + "family": "access_control" + }, + "priority": 0.0, + "evidence": [ + "static_rank=1.0", + "taint_evidence_not_applicable", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": null, + "score": null + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "config_secrets" + }, + "priority": -1.0, + "evidence": [ + "static_rank=1.0", + "taint_evidence_not_applicable", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": null, + "score": null + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "injection" + }, + "priority": -2.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":3,\"method\":\"handler\"}],\"source_local\":true,\"source_near\":true}", + "tier=4", + "score=5.5", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}" + ], + "tier": 4, + "score": 5.5 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "output_encoding" + }, + "priority": -3.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "path" + }, + "priority": -4.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "prototype" + }, + "priority": -5.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"prototype\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"prototype\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "untrusted_destination" + }, + "priority": -6.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "config_secrets" + }, + "priority": -7.0, + "evidence": [ + "static_rank=0.15", + "taint_evidence_not_applicable", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": null, + "score": null + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "injection" + }, + "priority": -8.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "output_encoding" + }, + "priority": -9.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "path" + }, + "priority": -10.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "prototype" + }, + "priority": -11.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "untrusted_destination" + }, + "priority": -12.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + } + ], + "deferred": [], + "unresolved_boundaries": [ + "context_projection_unavailable:contributor-scan:7ad5ff7dd4882f08a395c2c0f55de6f6a3ddb9f9db1536b207572a65485776ac", + "context_projection_unavailable:contributor-scan:010672f395d61fff5ca6acb6e5fb3e3aae4dcf9c30887240b985e705b656717a", + "dynamic_external_or_depth_context_unresolved:contributor-scan:e3453476e53cbccfd684460af10a161bb890fc026f3d10e18b30405d62a3d6cd", + "dynamic_external_or_depth_context_unresolved:contributor-scan:7a8bdefd0721637c5f48e97e26439ce8b329b293d8f6e65367e9e0c362f27b1d", + "dynamic_external_or_depth_context_unresolved:contributor-scan:1f94e3ba635eccd3f41986a6d98fc72c3f80358fe857e753b320e35cf6b73d64", + "dynamic_external_or_depth_context_unresolved:contributor-scan:3e5e7ffa9d58f7410260699db0971f16db0f439393765944fe1fb80eadda97e8", + "context_projection_unavailable:contributor-scan:1354f0d585180f0836d0688fa02f6e277e23082a8586e943e6d14a6b6c674937", + "context_scope_empty:contributor-scan:a707b5a8dd0057e55f54f4a8920d895cebf04fa14b9a7464a40ac60b9ba5002f", + "context_scope_empty:contributor-scan:915e4a4f1f95ecd70094688f73feb49a8be41d7a7a151d8e35f2d42035cecdf0", + "context_scope_empty:contributor-scan:f73e64bc02e13221cf6c8e8ae697e1ba2857957157a9b2fd216e556bd8d57a1a", + "context_scope_empty:contributor-scan:66f58a5dc208fab2d2634273b2f4b4048e593b4933ccfb1093baf39c04027ab5", + "context_scope_empty:contributor-scan:1c1ec68dedd385fa5c98bd93ae642d8384a6fa384470cd8290623842d921bfa2" + ] + } + ], + "completed_questions": [ + { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "injection" + } + ], + "coverage_status": "incomplete" + } + ], + "finding_status": "none", + "coverage_status": "incomplete", + "push_disposition": "allow", + "actionable_defect_ids": [] + }, + "artifact": "/results/populate.json" + }, + { + "name": "warm-identical", + "elapsed_seconds": 2.002456544083543, + "exit_code": 0, + "timings": { + "deadline_seconds": 30.0, + "cancellation_allowance_seconds": 2.0, + "resolution_seconds": 0.01683276705443859, + "provenance_seconds": 0.3089857939630747, + "snapshot_seconds": 0.0196256039198488, + "snapshot_reuses": 0, + "discovery_seconds": 0.010183473001234233, + "discovery_hits": 2, + "preparation_seconds": 0.05007663299329579, + "head_seconds": 0.5239870100049302, + "base_seconds": 0.5983346940483898, + "admission_seconds": 0.0056962770177051425, + "cleanup_seconds": 0.00035001395735889673, + "graph_hits": 2, + "query_hits": 37, + "total_seconds": 1.5298795499838889 + }, + "result": { + "analyses": [ + { + "comparison": { + "head_oid": "458817181ffff46da686825cdea0e27189fb447d", + "base_oid": "54b3130ca5354201a00bbd841640f6cb8651aaf8", + "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": "javascript", + "path": "api.js", + "function": "handler", + "family": "access_control" + }, + "priority": 0.0, + "evidence": [ + "static_rank=1.0", + "taint_evidence_not_applicable", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": null, + "score": null + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "config_secrets" + }, + "priority": -1.0, + "evidence": [ + "static_rank=1.0", + "taint_evidence_not_applicable", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": null, + "score": null + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "injection" + }, + "priority": -2.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":3,\"method\":\"handler\"}],\"source_local\":true,\"source_near\":true}", + "tier=4", + "score=5.5", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}" + ], + "tier": 4, + "score": 5.5 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "output_encoding" + }, + "priority": -3.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "path" + }, + "priority": -4.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "prototype" + }, + "priority": -5.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"prototype\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"prototype\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "untrusted_destination" + }, + "priority": -6.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "config_secrets" + }, + "priority": -7.0, + "evidence": [ + "static_rank=0.15", + "taint_evidence_not_applicable", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": null, + "score": null + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "injection" + }, + "priority": -8.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "output_encoding" + }, + "priority": -9.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "path" + }, + "priority": -10.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "prototype" + }, + "priority": -11.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "untrusted_destination" + }, + "priority": -12.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + } + ], + "deferred": [], + "unresolved_boundaries": [ + "context_projection_unavailable:contributor-scan:7ad5ff7dd4882f08a395c2c0f55de6f6a3ddb9f9db1536b207572a65485776ac", + "context_projection_unavailable:contributor-scan:010672f395d61fff5ca6acb6e5fb3e3aae4dcf9c30887240b985e705b656717a", + "dynamic_external_or_depth_context_unresolved:contributor-scan:e3453476e53cbccfd684460af10a161bb890fc026f3d10e18b30405d62a3d6cd", + "dynamic_external_or_depth_context_unresolved:contributor-scan:7a8bdefd0721637c5f48e97e26439ce8b329b293d8f6e65367e9e0c362f27b1d", + "dynamic_external_or_depth_context_unresolved:contributor-scan:1f94e3ba635eccd3f41986a6d98fc72c3f80358fe857e753b320e35cf6b73d64", + "dynamic_external_or_depth_context_unresolved:contributor-scan:3e5e7ffa9d58f7410260699db0971f16db0f439393765944fe1fb80eadda97e8", + "context_projection_unavailable:contributor-scan:1354f0d585180f0836d0688fa02f6e277e23082a8586e943e6d14a6b6c674937", + "context_scope_empty:contributor-scan:a707b5a8dd0057e55f54f4a8920d895cebf04fa14b9a7464a40ac60b9ba5002f", + "context_scope_empty:contributor-scan:915e4a4f1f95ecd70094688f73feb49a8be41d7a7a151d8e35f2d42035cecdf0", + "context_scope_empty:contributor-scan:f73e64bc02e13221cf6c8e8ae697e1ba2857957157a9b2fd216e556bd8d57a1a", + "context_scope_empty:contributor-scan:66f58a5dc208fab2d2634273b2f4b4048e593b4933ccfb1093baf39c04027ab5", + "context_scope_empty:contributor-scan:1c1ec68dedd385fa5c98bd93ae642d8384a6fa384470cd8290623842d921bfa2" + ] + } + ], + "completed_questions": [ + { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "injection" + } + ], + "coverage_status": "incomplete" + } + ], + "finding_status": "none", + "coverage_status": "incomplete", + "push_disposition": "allow", + "actionable_defect_ids": [] + }, + "artifact": "/results/warm-identical.json" + }, + { + "name": "uncached", + "elapsed_seconds": 130.4318098879885, + "exit_code": 0, + "timings": { + "deadline_seconds": 600.0, + "cancellation_allowance_seconds": 2.0, + "resolution_seconds": 0.01867874909657985, + "provenance_seconds": 0.28871102491393685, + "snapshot_seconds": 0.018826198996976018, + "snapshot_reuses": 0, + "discovery_seconds": 0.11859792796894908, + "discovery_hits": 0, + "preparation_seconds": 0.15741463494487107, + "head_seconds": 64.25150758202653, + "base_seconds": 65.24028130201623, + "admission_seconds": 0.005215354030951858, + "cleanup_seconds": 0.00034814607352018356, + "graph_hits": 0, + "query_hits": 0, + "total_seconds": 129.98746631806716 + }, + "result": { + "analyses": [ + { + "comparison": { + "head_oid": "458817181ffff46da686825cdea0e27189fb447d", + "base_oid": "54b3130ca5354201a00bbd841640f6cb8651aaf8", + "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": "javascript", + "path": "api.js", + "function": "handler", + "family": "access_control" + }, + "priority": 0.0, + "evidence": [ + "static_rank=1.0", + "taint_evidence_not_applicable", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": null, + "score": null + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "config_secrets" + }, + "priority": -1.0, + "evidence": [ + "static_rank=1.0", + "taint_evidence_not_applicable", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": null, + "score": null + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "injection" + }, + "priority": -2.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":3,\"method\":\"handler\"}],\"source_local\":true,\"source_near\":true}", + "tier=4", + "score=5.5", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"injection\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}" + ], + "tier": 4, + "score": 5.5 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "output_encoding" + }, + "priority": -3.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"output_encoding\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "path" + }, + "priority": -4.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"path\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "prototype" + }, + "priority": -5.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"prototype\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"prototype\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "untrusted_destination" + }, + "priority": -6.0, + "evidence": [ + "static_rank=1.0", + "normalized_evidence={\"access_declared_public\":true,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "affected_relationship={\"evidence\":[\"base_span:api.js:2-2\",\"head_span:api.js:2-2\",\"unchanged_line:1;lexical_only\",\"unchanged_line:3;lexical_only\",\"unchanged_line:4;lexical_only\"],\"kind\":\"entry\",\"source\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"},\"target\":{\"family\":\"untrusted_destination\",\"function\":\"handler\",\"language\":\"javascript\",\"path\":\"api.js\",\"unit\":\"repository\"}}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "config_secrets" + }, + "priority": -7.0, + "evidence": [ + "static_rank=0.15", + "taint_evidence_not_applicable", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": null, + "score": null + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "injection" + }, + "priority": -8.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "output_encoding" + }, + "priority": -9.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "path" + }, + "priority": -10.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "prototype" + }, + "priority": -11.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "untrusted_destination" + }, + "priority": -12.0, + "evidence": [ + "static_rank=0.15", + "normalized_evidence={\"access_declared_public\":false,\"bound_names\":[\"execute\",\"query\"],\"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\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"458817181ffff46da686825cdea0e27189fb447d\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ], + "tier": 0, + "score": 0.0 + } + ], + "deferred": [], + "unresolved_boundaries": [ + "context_projection_unavailable:contributor-scan:7ad5ff7dd4882f08a395c2c0f55de6f6a3ddb9f9db1536b207572a65485776ac", + "context_projection_unavailable:contributor-scan:010672f395d61fff5ca6acb6e5fb3e3aae4dcf9c30887240b985e705b656717a", + "dynamic_external_or_depth_context_unresolved:contributor-scan:e3453476e53cbccfd684460af10a161bb890fc026f3d10e18b30405d62a3d6cd", + "dynamic_external_or_depth_context_unresolved:contributor-scan:7a8bdefd0721637c5f48e97e26439ce8b329b293d8f6e65367e9e0c362f27b1d", + "dynamic_external_or_depth_context_unresolved:contributor-scan:1f94e3ba635eccd3f41986a6d98fc72c3f80358fe857e753b320e35cf6b73d64", + "dynamic_external_or_depth_context_unresolved:contributor-scan:3e5e7ffa9d58f7410260699db0971f16db0f439393765944fe1fb80eadda97e8", + "context_projection_unavailable:contributor-scan:1354f0d585180f0836d0688fa02f6e277e23082a8586e943e6d14a6b6c674937", + "context_scope_empty:contributor-scan:a707b5a8dd0057e55f54f4a8920d895cebf04fa14b9a7464a40ac60b9ba5002f", + "context_scope_empty:contributor-scan:915e4a4f1f95ecd70094688f73feb49a8be41d7a7a151d8e35f2d42035cecdf0", + "context_scope_empty:contributor-scan:f73e64bc02e13221cf6c8e8ae697e1ba2857957157a9b2fd216e556bd8d57a1a", + "context_scope_empty:contributor-scan:66f58a5dc208fab2d2634273b2f4b4048e593b4933ccfb1093baf39c04027ab5", + "context_scope_empty:contributor-scan:1c1ec68dedd385fa5c98bd93ae642d8384a6fa384470cd8290623842d921bfa2" + ] + } + ], + "completed_questions": [ + { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "injection" + } + ], + "coverage_status": "incomplete" + } + ], + "finding_status": "none", + "coverage_status": "incomplete", + "push_disposition": "allow", + "actionable_defect_ids": [] + }, + "artifact": "/results/uncached.json" + }, + { + "name": "dependency-edit", + "elapsed_seconds": 30.458495798055083, + "exit_code": 0, + "timings": { + "deadline_seconds": 30.0, + "cancellation_allowance_seconds": 2.0, + "resolution_seconds": 0.015588726033456624, + "provenance_seconds": 0.2984913958935067, + "snapshot_seconds": 0.021403303020633757, + "snapshot_reuses": 0, + "discovery_seconds": 0.10751347593031824, + "discovery_hits": 1, + "preparation_seconds": 0.14761024806648493, + "head_seconds": 29.52236297901254, + "base_seconds": 5.339505150914192e-05, + "admission_seconds": 0.0002843959955498576, + "graph_hits": 0, + "query_hits": 0, + "total_seconds": 30.008655319106765 + }, + "result": { + "analyses": [ + { + "comparison": { + "head_oid": "1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8", + "base_oid": "54b3130ca5354201a00bbd841640f6cb8651aaf8", + "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": "javascript", + "path": "api.js", + "function": "handler", + "family": "access_control" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "config_secrets" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "injection" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "output_encoding" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "path" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "prototype" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "untrusted_destination" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "config_secrets" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "injection" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "output_encoding" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "path" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "prototype" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "untrusted_destination" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\",\"7061636b6167652e6a736f6e\"],\"declaration_paths\":[\"7061636b6167652e6a736f6e\"],\"deleted_paths\":[],\"head_revision\":\"1dfa34ea3bbf2d7850d4dd7ab533a911885b2ae8\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + } + ], + "unresolved_boundaries": [ + "configuration_dependency_projection_unavailable:contributor-scan", + "change_context_deadline_exhausted", + "deadline_exhausted" + ] + } + ], + "completed_questions": [], + "coverage_status": "incomplete" + } + ], + "finding_status": "none", + "coverage_status": "incomplete", + "push_disposition": "allow", + "actionable_defect_ids": [] + }, + "artifact": "/results/dependency-edit.json" + }, + { + "name": "one-function-edit", + "elapsed_seconds": 30.47911988804117, + "exit_code": 0, + "timings": { + "deadline_seconds": 30.0, + "cancellation_allowance_seconds": 2.0, + "resolution_seconds": 0.0180521160364151, + "provenance_seconds": 0.3072873749770224, + "snapshot_seconds": 0.01567274401895702, + "snapshot_reuses": 0, + "discovery_seconds": 0.09289419103879482, + "discovery_hits": 1, + "preparation_seconds": 0.12448294495698065, + "head_seconds": 29.538544582901523, + "base_seconds": 8.924305438995361e-05, + "admission_seconds": 0.0003181110369041562, + "graph_hits": 0, + "query_hits": 0, + "total_seconds": 30.013175226049498 + }, + "result": { + "analyses": [ + { + "comparison": { + "head_oid": "55267520b163df2b09174a99caa3932e716cd68e", + "base_oid": "54b3130ca5354201a00bbd841640f6cb8651aaf8", + "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": "javascript", + "path": "api.js", + "function": "handler", + "family": "access_control" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "config_secrets" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "injection" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "output_encoding" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "path" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "prototype" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "handler", + "family": "untrusted_destination" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=1.0", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "config_secrets" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "injection" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "output_encoding" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "path" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "prototype" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + }, + { + "identity": { + "unit": "repository", + "language": "javascript", + "path": "api.js", + "function": "", + "family": "untrusted_destination" + }, + "reason": "deadline_exhausted", + "evidence": [ + "static_rank=0.15", + "analysis_not_started=deadline_exhausted", + "change_sites={\"base_revision\":\"54b3130ca5354201a00bbd841640f6cb8651aaf8\",\"changed_paths\":[\"6170692e6a73\"],\"declaration_paths\":[],\"deleted_paths\":[],\"head_revision\":\"55267520b163df2b09174a99caa3932e716cd68e\",\"path_encoding\":\"filesystem-bytes-hex\"}", + "change_context_incomplete" + ] + } + ], + "unresolved_boundaries": [ + "change_context_deadline_exhausted", + "deadline_exhausted" + ] + } + ], + "completed_questions": [], + "coverage_status": "incomplete" + } + ], + "finding_status": "none", + "coverage_status": "incomplete", + "push_disposition": "allow", + "actionable_defect_ids": [] + }, + "artifact": "/results/one-function-edit.json" + } + ], + "source_bytes": 109, + "rollout": "not qualified; authored development control only" + }, + "same_revision_uncached_hook": { + "command": [ + "python", + "-m", + "openultrasast.cli", + "pre-push", + "/results/repo", + "--base", + "54b3130ca5354201a00bbd841640f6cb8651aaf8", + "--head", + "458817181ffff46da686825cdea0e27189fb447d", + "--artifact", + "/results/uncached-hook.json", + "--deadline", + "30", + "--max-regions", + "20" + ], + "exit_code": 0, + "elapsed_seconds": 30.606204619980417 + }, + "completed_question_controls": { + "warm_identical_30_seconds": 5, + "uncached_same_revisions_30_seconds": 0, + "head_supported_injection": 1, + "base_comparison_checks": 4 + }, + "normal_alerts": 0, + "registry": "empty; new diagnostic injection denied admission for capability_unavailable", + "provenance": { + "engine": "joern-4.0.625", + "facts": "32edb6e1a78f1afb08ac4248cd436be16663e0d90dc1b3aaf948f2ce49a5a8f0", + "queries": "7bf090e053331f03d04c9290c8a593d00efd4d390f4b77b8382c2befc47996cc", + "policy": "b0ad9ee436fb4a71e3ff3d40f7be604c780562859cfcee491f4d201ec45cba04", + "repository": "/results/repo", + "model": "disabled", + "requested_base": "54b3130ca5354201a00bbd841640f6cb8651aaf8", + "requested_head": "458817181ffff46da686825cdea0e27189fb447d", + "engine_runtime": "2b415139532d8d3a0c6e46ecdac26cd3d792efc2bae441f0b7e39bb28ec5d16e", + "graph_layout": "060428173f47cf33bdf5e532d4069feb598ba0e8c7ea30a60888c8e4cfb37a42", + "core": "36ac9a045b8b8ad943eea1f511924caae54750a9d5d45da776ebefc460f08eab", + "semantics": "4558faecc3f33aaab98a65672550c3acb4e142689a827c696fd29a9bdd1bf78c", + "ranking_mode": "evidence", + "capabilities": "empty_registry_pending_task_8.3", + "cache": "validated_local_reuse" + }, + "validation": { + "pytest": "1268 passed, 9 skipped in 108.74s", + "ruff": "PASS", + "format": "PASS (250 files)", + "mypy": "PASS (114 source files)", + "compileall": "PASS", + "detection_gate": "PASS 44/47, FP 0/44", + "map_gate": "PASS", + "pair_gate": "PASS local 3/3; labeled 28/28; fix leaks 0", + "docker_build": "PASS", + "packaged_cli_smoke": "PASS", + "manual_review_fallback": true + }, + "bundles": [ + { + "path": "2026-09-13-reuse-final-control.json.gz", + "sha256": "c8a4306450166a74f590e8f23018df5a6c333d05f8f3a5924b729c4e5206a111", + "format": "gzip JSON object mapping original filenames to exact UTF-8 content" + }, + { + "path": "2026-09-13-reuse-initial-control.json.gz", + "sha256": "20fd916aed04c9ca829e1ecbc149720335587e7245ec2289e8c5c9be8743995c", + "format": "gzip JSON object mapping original filenames to exact UTF-8 content" + } + ], + "decision": "Group 6 reuse correctness PASS; rollout NO-GO. Source/dependency edits exhaust the 30-second deadline, representative p95/completion and independent precision/recall populations remain unqualified." +} diff --git a/benchmarks/measurements/2026-09-13-reuse-final-control.json.gz b/benchmarks/measurements/2026-09-13-reuse-final-control.json.gz new file mode 100644 index 0000000..c15347e Binary files /dev/null and b/benchmarks/measurements/2026-09-13-reuse-final-control.json.gz differ diff --git a/benchmarks/measurements/2026-09-13-reuse-initial-control.json.gz b/benchmarks/measurements/2026-09-13-reuse-initial-control.json.gz new file mode 100644 index 0000000..fe608e8 Binary files /dev/null and b/benchmarks/measurements/2026-09-13-reuse-initial-control.json.gz differ diff --git a/benchmarks/push/README.md b/benchmarks/push/README.md index e21c3f4..34e28e9 100644 --- a/benchmarks/push/README.md +++ b/benchmarks/push/README.md @@ -137,3 +137,24 @@ flushed. Six one-shot runs are diagnostic samples, not representative warm p95 e Normal capabilities remain disabled, so zero alerts do not establish precision or useful recall. A separately named longer lab run may obtain witnesses, but cannot replace the 30-second measurements or satisfy the hook's latency gate. + +### Group 6 reuse correctness control + +`reuse_control.py` creates an isolated, authored JavaScript history and invokes the packaged +replay command for a cache-populating run, a 30-second identical-revision run, an uncached +control, and dependency/one-function edits. It retains every artifact and checks equal evidence +and current admission for compatible completed questions. This is development control data, +not the untouched eligibility population or the representative warm p95 gate. + +```sh +docker run --rm --network none --memory 3g \ + -v /path/to/empty/results:/results \ + -v "$PWD/benchmarks/push/reuse_control.py:/control.py:ro" \ + --entrypoint python openultrasast:dev /control.py --out /results +``` + +The output directory must be empty and writable by the image's nonroot user. Cold runs use a +600-second laboratory budget; the identical-revision and changed-code controls retain the +30-second deadline and 2-second cancellation allowance. Default normal capabilities remain +empty. A passing reuse control cannot authorize rollout or turn unresolved coverage into clean +analysis; groups 7–8 still own the real interface and joint evaluation. diff --git a/benchmarks/push/reuse_control.py b/benchmarks/push/reuse_control.py new file mode 100644 index 0000000..ea063a4 --- /dev/null +++ b/benchmarks/push/reuse_control.py @@ -0,0 +1,133 @@ +"""Packaged JavaScript reuse correctness control, not capability qualification. + +Run with --out pointing to an empty directory outside any analyzed repository. +Authored development code is never an independent precision/recall population. +""" + +import argparse +import json +import subprocess +import time +from pathlib import Path + +parser = argparse.ArgumentParser(description=__doc__) +parser.add_argument("--out", type=Path, required=True) +args = parser.parse_args() +out = args.out.resolve() +out.mkdir(parents=True, exist_ok=True) +if any(out.iterdir()): + parser.error("output directory must be empty") +repo = out / "repo" +repo.mkdir() + + +def git(*args): + return subprocess.run(["git", "-C", str(repo), *args], check=True, capture_output=True, text=True).stdout.strip() + + +git("init") +git("config", "user.name", "Replay control") +git("config", "user.email", "control@example.invalid") +git("config", "core.hooksPath", "/dev/null") +source = repo / "api.js" +source.write_text('function handler(req, res) {\n const value = "fixed";\n eval(value);\n}\napp.post("/run", handler);\n') +assert len(source.read_bytes()) > 0 +git("add", "api.js") +git("commit", "-m", "fixed") +base = git("rev-parse", "HEAD") +source.write_text(source.read_text().replace('"fixed"', "req.body.value")) +git("add", "api.js") +git("commit", "-m", "introduce") +head = git("rev-parse", "HEAD") +runs = [] + + +def run(name, deadline, cache=True, tip=head): + artifact = out / (name + ".json") + cmd = [ + "python", + "-m", + "openultrasast.cli", + "pre-push", + str(repo), + "--base", + base, + "--head", + tip, + "--artifact", + str(artifact), + "--deadline", + str(deadline), + "--max-regions", + "20", + ] + if cache: + cmd += ["--cache-dir", str(out / "cache")] + start = time.monotonic() + process = subprocess.run(cmd, capture_output=True, text=True, timeout=deadline + 10) + elapsed = time.monotonic() - start + (out / (name + ".stdout")).write_text(process.stdout) + (out / (name + ".stderr")).write_text(process.stderr) + assert artifact.is_file(), (process.returncode, process.stdout, process.stderr) + data = json.loads(artifact.read_text()) + run = { + "name": name, + "elapsed_seconds": elapsed, + "exit_code": process.returncode, + "timings": data["timings"], + "result": data["result"], + "artifact": str(artifact), + } + runs.append(run) + (out / "runs.json").write_text(json.dumps(runs, indent=2)) + print(json.dumps(run), flush=True) + return data + + +populated = run("populate", 600) +warm = run("warm-identical", 30) +cold = run("uncached", 600, False) +(repo / "package.json").write_text('{"dependencies":{"express":"5.0.0"}}\n') +git("add", "package.json") +git("commit", "-m", "dependency change") +changed = git("rev-parse", "HEAD") +run("dependency-edit", 30, tip=changed) +git("rm", "package.json") +source.write_text(source.read_text().replace("req.body.value", 'req.body.value + "!"')) +git("add", "api.js") +git("commit", "-m", "one function edit") +edited = git("rev-parse", "HEAD") +run("one-function-edit", 30, tip=edited) + + +def evidence(data): + return [ + { + "side": s["side"], + "scope": s["scan"]["scope"], + "questions": s["scan"]["question_outcomes"], + "findings": s["scan"]["findings"], + "degradations": s["scan"]["degradations"], + } + for s in data["scans"] + ] + + +summary = { + "cold_populated_evidence_equal": evidence(cold) == evidence(populated), + "cold_warm_evidence_equal": evidence(cold) == evidence(warm), + "admission_equal": cold["admission"] == warm["admission"], + "runs": runs, + "source_bytes": len(source.read_bytes()), + "rollout": "not qualified; authored development control only", +} +(out / "summary.json").write_text(json.dumps(summary, indent=2)) +print(json.dumps(summary), flush=True) +assert summary["cold_populated_evidence_equal"] and summary["cold_warm_evidence_equal"] and summary["admission_equal"] +assert warm["timings"]["graph_hits"] == 2 and warm["timings"]["query_hits"] > 0 +assert any(item["candidate"]["delta"]["novelty"] == "new" for item in warm["admission"]["dispositions"]) +assert not any(data["admission"]["defects"] for data in (populated, warm, cold)) +assert runs[1]["elapsed_seconds"] <= 32 +assert all( + r["timings"]["graph_hits"] <= 1 and r["elapsed_seconds"] <= 32 for r in runs if r["name"] in ("dependency-edit", "one-function-edit") +) diff --git a/ops/README.md b/ops/README.md index aa13e28..c242f29 100644 --- a/ops/README.md +++ b/ops/README.md @@ -266,3 +266,19 @@ it does not demand a positive after an interrupted query. Run with the network-d 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. + +Experimental replay can reuse compatible local preparation, graphs and query evidence: + +```sh +ousast pre-push /path/to/repo --base BASE --head HEAD \ + --artifact /path/outside/repo/result.json \ + --cache-dir /path/outside/repo/private-cache +``` + +Omit `--cache-dir` for a cold control. The cache directory must be owned by the current +user, private (0700), and outside the analyzed repository. Its default payload/manifest +budget is 2 GiB (`PushConfig.cache_max_bytes` for API callers). Cache permission to reuse +is separate from alert eligibility: current admission is always applied. No hook is installed +by replay. Artifact timings record discovery, graph and query hits; identical-tip hits do +not establish representative changed-code latency. Corrupt, partial or incompatible entries +are misses, with remaining work constrained by the same push deadline. diff --git a/src/openultrasast/cli.py b/src/openultrasast/cli.py index ea25539..de143fc 100644 --- a/src/openultrasast/cli.py +++ b/src/openultrasast/cli.py @@ -115,6 +115,9 @@ def main(argv: list[str] | None = None) -> int: 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( + "--cache-dir", type=Path, help="reuse compatible local artifacts in a private directory outside the repository" + ) 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) @@ -212,7 +215,13 @@ def main(argv: list[str] | None = None) -> int: 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 + args.path, + base=args.base, + head=args.head, + artifact=args.artifact, + config=settings, + max_regions=args.max_regions, + cache_dir=args.cache_dir, ) except ValueError as error: parser.error(str(error)) diff --git a/src/openultrasast/cpg/backend.py b/src/openultrasast/cpg/backend.py index c62e19e..7d78881 100644 --- a/src/openultrasast/cpg/backend.py +++ b/src/openultrasast/cpg/backend.py @@ -266,6 +266,41 @@ class NullBackend: return None +def engine_runtime_identity( + *, include_tests: bool = True, language: str | None = None, execution_budget: ExecutionBudget | None = None +) -> str: + """Installed frontend/adaptation bytes, also used by comparison eligibility provenance.""" + from .artifact import digest_value, graph_bytes + + budget = execution_budget + deadline = budget.deadline_monotonic if budget else float("inf") + launcher = shutil.which("joern") + version = joern_version() + installation = [] + if launcher is not None and version is not None: + home = Path(launcher).resolve().parent + engine = ".".join(map(str, version)) + frontends = {_FRONTENDS.get(language, "joern-parse")} if language else set(_FRONTENDS.values()) + candidates = {home / f"lib/io.joern.joern-cli-{engine}.jar", Path(launcher).resolve()} + for frontend in frontends: + candidates.add(home / f"frontends/{frontend}/lib/io.joern.{frontend}-{engine}.jar") + frontend_launcher = shutil.which(frontend) + if frontend_launcher is not None: + candidates.add(Path(frontend_launcher).resolve()) + if "jssrc2cpg" in frontends: + candidates.update({home / "ousast-frontend-retention-v1/manifest.json", home / "frontends/jssrc2cpg/bin/astgen/astgen-linux"}) + for candidate in sorted(candidates): + installation.append((candidate.name, graph_bytes(candidate, deadline) if candidate.is_file() else "absent")) + return digest_value( + { + "version": version, + "files": installation, + "include_tests": include_tests, + "java_options": os.environ.get("JAVA_TOOL_OPTIONS", ""), + } + ) + + @dataclass class JoernBackend: """``joern-parse`` then ``joern --script``, both out of process and both timeout-bounded.""" @@ -324,7 +359,8 @@ class JoernBackend: ) -> GraphIdentity: from .artifact import digest_value, read_bytes, source_inventory - deadline = execution_budget.deadline_monotonic if execution_budget else float("inf") + budget = execution_budget or self.execution_budget + deadline = budget.deadline_monotonic if budget else float("inf") version = joern_version() if version is None: raise ValueError("engine_identity_unknown") @@ -342,7 +378,16 @@ class JoernBackend: engine, (DATAFLOW_OVERLAY,), (("implementation", code),), - (("include_tests", str(self.include_tests)), ("java_options", os.environ.get("JAVA_TOOL_OPTIONS", "default") or "default")), + ( + ("include_tests", str(self.include_tests)), + ( + "installation", + engine_runtime_identity( + include_tests=self.include_tests, language=language, execution_budget=execution_budget or self.execution_budget + ), + ), + ("java_options", os.environ.get("JAVA_TOOL_OPTIONS", "default") or "default"), + ), ) def describe_graph( diff --git a/src/openultrasast/push/reuse.py b/src/openultrasast/push/reuse.py new file mode 100644 index 0000000..dccdac2 --- /dev/null +++ b/src/openultrasast/push/reuse.py @@ -0,0 +1,202 @@ +"""Compatible replay reuse; the existing ranker and detector remain decision owners.""" + +from __future__ import annotations + +import math +import os +import time +from collections.abc import Callable, Mapping, Sequence +from dataclasses import asdict, replace +from pathlib import Path +from typing import Any + +from openultrasast.cpg.artifact import GraphArtifact, digest_value +from openultrasast.cpg.backend import CpgResult, JoernBackend +from openultrasast.model.contracts import ExecutionBudget +from openultrasast.model.regions import ScanRegion +from openultrasast.push.cache import ArtifactCache, SemanticKeys +from openultrasast.push.contracts import SnapshotManifest + + +class ReusingBackend: + def __init__(self, backend: JoernBackend, cache: ArtifactCache, semantics: SemanticKeys, *, declarations: str, exclusions: str) -> None: + self.backend = backend + self.cache = cache + self.semantics = semantics + self.declarations = declarations + self.exclusions = exclusions + self.last_failure = "" + self.graph_hits = 0 + self.query_hits = 0 + + def build(self, root: Path, *, language: str, exclude: Sequence[str], execution_budget: ExecutionBudget) -> CpgResult | None: + identity = None + artifact = None + result = None + try: + identity = self.backend.graph_identity( + root, + language=language, + declarations_digest=self.declarations, + exclusions_digest=digest_value([self.exclusions, sorted(exclude)]), + execution_budget=execution_budget, + ) + key = digest_value({"layer": "graph-v1", "identity": identity.to_payload()}) + with self.cache.lookup(key, execution_budget) as entry: + if entry is not None: + artifact = GraphArtifact.from_payload(entry.metadata) + result = self.backend.load_graph(entry.path, artifact, identity, execution_budget=execution_budget) + if result is not None: + self.graph_hits += 1 + except (OSError, ValueError, TimeoutError): + artifact = None + if result is None: + artifact = None + result = self.backend.build(root, language=language, exclude=exclude, execution_budget=execution_budget) + self.last_failure = self.backend.last_failure + if result is None: + return None + if identity is not None and time.monotonic() < execution_budget.deadline_monotonic: + artifact = self.backend.describe_graph(result, root, identity, execution_budget=execution_budget) + if artifact is not None: + self.cache.publish(key, result.cpg_path, artifact.to_payload(), execution_budget) + if artifact is None: + return result + return self._answers(result, artifact, execution_budget) + + def _answers(self, result: CpgResult, artifact: GraphArtifact, budget: ExecutionBudget) -> CpgResult: + def normalize(value: Any) -> Any: + if isinstance(value, str): + return value.replace(artifact.source_root + "/", "") + if isinstance(value, list): + return [normalize(item) for item in value] + if isinstance(value, dict): + return {key: normalize(item) for key, item in value.items()} + return value + + def batch(kind: str, requests: Mapping[str, Mapping[str, object]]) -> dict[str, list[object]] | None: + answers: dict[str, list[object]] = {} + missing = {} + keys = {} + for rid, request in requests.items(): + if time.monotonic() >= budget.deadline_monotonic: + break + key = self.semantics.query( + graph=digest_value({"identity": artifact.identity.to_payload(), "bytes": artifact.graph_digest}), + kind=kind, + request=request, + context={"paths": artifact.source_paths, "declarations": artifact.identity.declarations_digest}, + ) + keys[rid] = key + cached = self.cache.get_json(key, kind="query", budget=budget) + if isinstance(cached, dict) and isinstance(cached.get("rows"), list) and self._census(cached.get("census"), artifact): + answers[rid] = cached["rows"] + answers["__census__"] = cached["census"] + self.query_hits += 1 + else: + missing[rid] = request + if missing and time.monotonic() < budget.deadline_monotonic: + raw: Any = result.run_batch(kind, missing) if result.run_batch else None + if raw is None and result.run_batch is None: + raw = {rid: result.run(kind, params) for rid, params in missing.items()} + if isinstance(raw, dict): + normalized = normalize(raw) + census = normalized.get("__census__") + valid = self._census(census, artifact) + if not valid: + return answers or None + answers["__census__"] = census + for rid in missing: + rows = normalized.get(rid) + if isinstance(rows, list): + answers[rid] = rows + self.cache.put_json(keys[rid], {"rows": rows, "census": census}, kind="query", budget=budget, complete=valid) + return answers or None + + def run(kind: str, params: Mapping[str, object]) -> object | None: + if kind == "census": + value: object = normalize(result.run(kind, params)) + return value + rows = batch(kind, {"one": params}) + return rows.get("one") if rows is not None else None + + return replace(result, run=run, run_batch=batch) + + @staticmethod + def _census(value: object, artifact: GraphArtifact) -> bool: + if not isinstance(value, list) or len(value) != 1 or not isinstance(value[0], dict): + return False + row = value[0] + names = row.get("file_names") + try: + return ( + isinstance(names, list) + and all(isinstance(name, str) for name in names) + and set(artifact.source_paths) <= set(names) + and int(str(row.get("methods", 0))) > 0 + and int(str(row.get("files", 0))) >= len(artifact.source_paths) + and int(str(row.get("shards", 1))) == 1 + ) + except (ValueError, TypeError): + return False + + +def discovery( + root: Path, + manifest: SnapshotManifest, + *, + cache: ArtifactCache | None, + identity: str, + budget: ExecutionBudget, + discover: Callable[[Path], tuple[tuple[ScanRegion, ...], tuple[bytes, ...]]], +) -> tuple[tuple[ScanRegion, ...], tuple[bytes, ...], bool]: + """Persist pure discovery only after the adapter proves the complete snapshot readable.""" + key = digest_value( + { + "layer": "discovery-v1", + "files": [item.to_payload() for item in manifest.files], + "object_format": manifest.object_format, + "identity": identity, + } + ) + raw = cache.get_json(key, kind="discovery", budget=budget) if cache and manifest.complete else None + if isinstance(raw, dict): + try: + regions = [] + for item in raw["regions"]: + values = dict(item) + values["families"] = tuple(values["families"]) + region = ScanRegion(**values) + if ( + not all(isinstance(v, str) for v in (region.path, region.language, region.source, *region.families)) + or region.function is not None + and not isinstance(region.function, str) + or type(region.shipped) is not bool + or type(region.rank) not in (int, float) + or not math.isfinite(region.rank) + ): + raise ValueError("invalid_discovery_region") + if os.fsencode(region.path) not in {item.path_bytes for item in manifest.files}: + raise ValueError("discovery_path_outside_snapshot") + regions.append(region) + declarations = tuple(bytes.fromhex(item) for item in raw["declarations"]) + if not set(declarations) <= {item.path_bytes for item in manifest.files}: + raise ValueError("invalid_declarations") + return tuple(regions), declarations, True + except (KeyError, ValueError, TypeError): + pass + found, declarations = discover(root) + if cache and manifest.complete: + cache.put_json( + key, + {"regions": [asdict(region) for region in found], "declarations": [item.hex() for item in declarations]}, + kind="discovery", + budget=budget, + complete=True, + ) + return found, declarations, False + + +def declaration_identity(manifest: SnapshotManifest, paths: tuple[bytes, ...]) -> str: + declared = set(paths) + return digest_value([item.to_payload() for item in manifest.files if item.path_bytes in declared]) diff --git a/src/openultrasast/push/runner.py b/src/openultrasast/push/runner.py index 4f94b61..67e1987 100644 --- a/src/openultrasast/push/runner.py +++ b/src/openultrasast/push/runner.py @@ -9,18 +9,22 @@ import pickle import selectors import time from collections.abc import Callable +from contextlib import nullcontext 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 JoernBackend, joern_version +from openultrasast.cpg.artifact import digest_value +from openultrasast.cpg.backend import JoernBackend, engine_runtime_identity, joern_version from openultrasast.mapping import analyze_entry_points from openultrasast.model.contracts import ExecutionBudget +from openultrasast.model.layout import layout_facts 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.cache import ArtifactCache, SemanticKeys from openultrasast.push.contracts import ComparisonAnalysis, SnapshotManifest from openultrasast.push.policy import ( AdmissionCandidate, @@ -32,6 +36,7 @@ from openultrasast.push.policy import ( semantics_digest, ) from openultrasast.push.report import PushReport, ReportDelivery, ScanRecord, _completed_scan, deliver_report, render_report +from openultrasast.push.reuse import ReusingBackend, declaration_identity, discovery from openultrasast.push.snapshot import SnapshotAdapter _T = TypeVar("_T") @@ -124,14 +129,25 @@ def _provenance(repository: Path, scan_budget: ScanBudget) -> dict[str, str]: version = joern_version() engine = "joern-" + (".".join(map(str, version)) if version else "unavailable_or_unidentified") + runtime = engine_runtime_identity() + integration = digest(list((root / "cpg").glob("*.py"))) return { "repository": str(repository.absolute()), + "engine_runtime": runtime, "engine": engine, "facts": digest(list((root / "ruleset").rglob("*.toml"))), + "graph_layout": digest_value( + { + "facts": [asdict(row) for row in layout_facts()], + "implementation": digest([root / "model/layout.py", root / "model/partitions.py"]), + } + ), "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)), + "semantics": semantics_digest( + engine_identity=engine, options={**asdict(scan_budget), "engine_runtime": runtime, "engine_integration": integration} + ), "ranking_mode": "evidence", "model": "disabled", "capabilities": "empty_registry_pending_task_8.3", @@ -139,6 +155,13 @@ def _provenance(repository: Path, scan_budget: ScanBudget) -> dict[str, str]: } +def _discovery_identity() -> str: + root = Path(__file__).resolve().parents[1] + # Discovery invokes the shipped mapper, preprocessing, layout and family specs. + # Hash code bytes, never a mutable import name or a repository-provided version. + return digest_value([(p.relative_to(root).as_posix(), hashlib.sha256(p.read_bytes()).hexdigest()) for p in sorted(root.rglob("*.py"))]) + + def replay( repository: Path, *, @@ -148,16 +171,22 @@ def replay( config: PushConfig | None = None, backend: Any = None, max_regions: int = 500, + cache_dir: Path | None = None, ) -> 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") + if cache_dir is not None and cache_dir.resolve().is_relative_to(repository.resolve()): + raise ValueError("cache directory must be outside the analyzed repository") 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) if backend is None: backend = JoernBackend() + cache = None + cache_semantics = None + reused: list[ReusingBackend] = [] records: list[ScanRecord] = [] manifests: list[SnapshotManifest] = [] reasons: list[str] = [] @@ -179,16 +208,66 @@ def replay( stage, stage_started = "provenance", time.monotonic() provenance.update(_prepare(lambda: _provenance(repository, scan_budget), budget)) timings[stage + "_seconds"] = time.monotonic() - stage_started + if cache_dir is not None: + cache = ArtifactCache(cache_dir, max_bytes=config.cache_max_bytes) + cache_semantics = SemanticKeys( + provenance["facts"], + provenance["queries"], + digest_value({"query_parameters": "complete-joern-request-v1"}), + digest_value({"ranking_mode": "evidence", "options": asdict(scan_budget)}), + provenance["policy"], + provenance["model"], + provenance["capabilities"], + config.mode, + ) + provenance["cache"] = "validated_local_reuse" + discovery_identity = digest_value({"code": _prepare(lambda: _discovery_identity(), budget), "facts": provenance["facts"]}) 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: + old_context = ( + nullcontext(tip) if comparison.base_oid == comparison.head_oid else adapter.materialize(comparison.base_oid, budget=budget) + ) + with old_context 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) + timings["snapshot_seconds"] = time.monotonic() - stage_started + timings["snapshot_reuses"] = int(comparison.base_oid == comparison.head_oid) + discovery_started = time.monotonic() + head_regions, head_declarations, head_hit = _prepare( + lambda: discovery(tip.root, tip.manifest, cache=cache, identity=discovery_identity, budget=budget, discover=_discover), + budget, + ) + base_regions, base_declarations, base_hit = _prepare( + lambda: discovery(old.root, old.manifest, cache=cache, identity=discovery_identity, budget=budget, discover=_discover), + budget, + ) + timings["discovery_seconds"] = time.monotonic() - discovery_started + timings["discovery_hits"] = int(head_hit) + int(base_hit) + head_backend = base_backend = backend + if ( + cache is not None + and cache_semantics is not None + and isinstance(backend, JoernBackend) + and all(m.complete for m in manifests) + ): + head_backend = ReusingBackend( + backend, + cache, + cache_semantics, + declarations=declaration_identity(tip.manifest, head_declarations), + exclusions=provenance["graph_layout"], + ) + base_backend = ReusingBackend( + backend, + cache, + cache_semantics, + declarations=declaration_identity(old.manifest, base_declarations), + exclusions=provenance["graph_layout"], + ) + reused.extend((head_backend, base_backend)) 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) @@ -197,7 +276,7 @@ def replay( head_scan = scan_repository( tip.root, head_regions, - backend=backend, + backend=head_backend, budget=scan_budget, execution_budget=budget, ranking_mode="evidence", @@ -214,11 +293,13 @@ def replay( head_regions=head_regions, base_regions=base_regions, context=context, - backend=backend, + backend=base_backend, execution_budget=budget, scan_budget=scan_budget, head_semantics=provenance["semantics"], base_semantics=provenance["semantics"], + cache=cache, + cache_semantics=cache_semantics, ) if delta.base_scan is not None: records.append(ScanRecord(comparison, "base", delta.base_scan)) @@ -251,6 +332,8 @@ def replay( timings[stage + "_seconds"] = time.monotonic() - stage_started if time.monotonic() >= budget.deadline_monotonic: reasons.append("deadline_exhausted") + timings["graph_hits"] = sum(item.graph_hits for item in reused) + timings["query_hits"] = sum(item.query_hits for item in reused) head_records = [r.scan for r in records if r.side == "head"] for record in records: if record.scan.scope is not None: diff --git a/tests/test_graph_reuse.py b/tests/test_graph_reuse.py index 544e0ef..6b7010d 100644 --- a/tests/test_graph_reuse.py +++ b/tests/test_graph_reuse.py @@ -88,3 +88,21 @@ def test_generic_driver_accepts_backend_validated_lease(tmp_path, monkeypatch): assert result.run("census", {})["file_names"] == ["a.js"] _dispose(result) assert graph.read_bytes() == b"graph original" + + +def test_installed_frontend_adaptation_changes_graph_identity(tmp_path, monkeypatch): + import openultrasast.cpg.backend as module + + backend, root, _, identity, _ = prepared(tmp_path, monkeypatch) + home = tmp_path / "engine" + home.mkdir() + launcher = home / "joern" + launcher.write_text("launcher") + jar = home / "frontends/jssrc2cpg/lib/io.joern.jssrc2cpg-4.0.625.jar" + jar.parent.mkdir(parents=True) + jar.write_bytes(b"frontend-one") + monkeypatch.setattr(module.shutil, "which", lambda name: str(launcher) if name == "joern" else None) + first = backend.graph_identity(root, language="javascript", declarations_digest="d", exclusions_digest="e") + jar.write_bytes(b"frontend-two") + second = backend.graph_identity(root, language="javascript", declarations_digest="d", exclusions_digest="e") + assert first != second diff --git a/tests/test_push_reuse.py b/tests/test_push_reuse.py new file mode 100644 index 0000000..f611eb8 --- /dev/null +++ b/tests/test_push_reuse.py @@ -0,0 +1,89 @@ +"""Live integration of validated graph and query reuse under one deadline.""" + +import json +import time + +from openultrasast.cpg.backend import CpgResult, JoernBackend +from openultrasast.model.contracts import ExecutionBudget +from openultrasast.push.cache import ArtifactCache, SemanticKeys +from openultrasast.push.reuse import ReusingBackend + + +def test_backend_reuses_graph_and_answers_then_invalidates_source_and_dependencies(tmp_path, monkeypatch): + import openultrasast.cpg.backend as module + + monkeypatch.setattr(module, "joern_version", lambda: (4, 0, 625)) + builds = [] + queries = [] + + class Engine(JoernBackend): + def build(self, root, *, language, exclude, execution_budget): + builds.append(root) + path = tmp_path / f"graph-{len(builds)}.json" + paths = [str(p) for p in root.glob("*.js")] + path.write_text(json.dumps(paths)) + return CpgResult(path, lambda kind, params: self.query(path, kind, params), lambda kind, req: self.query_batch(path, kind, req)) + + def query(self, path, kind, params): + names = json.loads(path.read_text()) + return {"files": len(names), "methods": 2, "calls": 1, "file_names": names, "overlays": "dataflowOss"} + + def query_batch(self, path, kind, requests): + queries.append((kind, requests)) + return {**{rid: [] for rid in requests}, "__census__": [self.query(path, "census", {})]} + + root = tmp_path / "source" + root.mkdir() + (root / "a.js").write_text("function f() {}") + cache = ArtifactCache(tmp_path / "cache", max_bytes=100000) + semantics = SemanticKeys("facts", "queries", "config", "ranking", "admission", "disabled", "empty", "advisory") + deadline = ExecutionBudget(time.monotonic() + 10, 0.2) + backend = ReusingBackend(Engine(), cache, semantics, declarations="dependencies", exclusions="exclusions") + + def run(): + result = backend.build(root, language="javascript", exclude=(), execution_budget=deadline) + assert result is not None + answer = result.run_batch("taint", {"q": {"file": "a.js", "callDepth": 3}}) + if result.cleanup: + result.cleanup() + return answer + + expected = run() + assert run() == expected + assert len(builds) == 1 and len(queries) == 1 + (root / "a.js").write_text("function g() {}") + run() + assert len(builds) == 2 and len(queries) == 2 + backend.declarations = "changed-dependency" + run() + assert len(builds) == 3 and len(queries) == 3 + backend.semantics = SemanticKeys("changed-facts", "queries", "config", "ranking", "admission", "disabled", "empty", "advisory") + run() + assert len(builds) == 3 and len(queries) == 4 + + +def test_fresh_missing_census_cannot_borrow_a_cached_query_census(tmp_path): + from openultrasast.cpg.artifact import GraphArtifact, GraphCensus, GraphIdentity + + identity = GraphIdentity( + "source", "declarations", "exclude", "repository", "javascript", "engine", "frontend", "version", ("dataflowOss",), () + ) + artifact = GraphArtifact(identity, "graph-bytes", 10, GraphCensus(1, 1, 1), "complete", (), "/old", ("a.js",)) + cache = ArtifactCache(tmp_path / "cache", max_bytes=100000) + semantics = SemanticKeys("facts", "queries", "config", "ranking", "admission", "disabled", "empty", "advisory") + wrapper = ReusingBackend(JoernBackend(), cache, semantics, declarations="d", exclusions="e") + census = [{"files": 1, "methods": 1, "file_names": ["a.js"]}] + calls = [] + + def batch(kind, requests): + calls.append(requests) + result = {rid: [] for rid in requests} + if len(calls) == 1: + result["__census__"] = census + return result + + graph = CpgResult(tmp_path / "graph", lambda *_: None, batch) + result = wrapper._answers(graph, artifact, ExecutionBudget(time.monotonic() + 5, 0.2)) + assert "q" in result.run_batch("taint", {"q": {"file": "a.js"}}) + answer = result.run_batch("taint", {"q": {"file": "a.js"}, "fresh": {"file": "a.js", "callDepth": 3}}) + assert "q" in answer and "fresh" not in answer diff --git a/tests/test_push_runner.py b/tests/test_push_runner.py index f9ad498..0a5591a 100644 --- a/tests/test_push_runner.py +++ b/tests/test_push_runner.py @@ -218,3 +218,84 @@ def test_default_replay_does_not_launch_unbudgeted_availability_probe(tmp_path, monkeypatch.setattr(runner, "JoernBackend", Backend, raising=False) result = replay(root, base=base, head=head, artifact=tmp_path / "probe.json") assert builds and result.result.coverage_status == "incomplete" + + +def test_replay_persists_discovery_without_skipping_readable_snapshots(tmp_path, monkeypatch): + from openultrasast.push import runner + + root, base, head, _ = history(tmp_path) + cache = tmp_path / "cache" + cold = tmp_path / "cold.json" + warm = tmp_path / "warm.json" + replay(root, base=base, head=head, artifact=cold, backend=NullBackend(), cache_dir=cache) + + def should_reuse(*args): + raise AssertionError("discovery should be cached") + + monkeypatch.setattr(runner, "_discover", should_reuse) + replay(root, base=base, head=head, artifact=warm, backend=NullBackend(), cache_dir=cache) + a, b = json.loads(cold.read_text()), json.loads(warm.read_text()) + assert a["result"] == b["result"] + assert a["snapshots"] == b["snapshots"] + assert b["timings"]["discovery_hits"] == 2 + assert b["snapshots"][0]["bytes_read"] > 0 + + +def test_cache_cannot_write_inside_repository(tmp_path): + root, base, head, git = history(tmp_path) + before = git("status", "--porcelain") + with pytest.raises(ValueError, match="cache.*outside"): + replay(root, base=base, head=head, artifact=tmp_path / "out.json", cache_dir=root / "cache") + assert git("status", "--porcelain") == before + + +def test_cached_discovery_invalidates_source_and_dependency_edits(tmp_path): + root, base, head, git = history(tmp_path) + cache = tmp_path / "cache" + replay(root, base=base, head=head, artifact=tmp_path / "initial.json", backend=NullBackend(), cache_dir=cache) + (root / "api.js").write_text("function replacement(req) { eval(req.body.other); }") + git("add", "api.js") + git("commit", "-m", "change source") + edited = git("rev-parse", "HEAD") + replay(root, base=base, head=edited, artifact=tmp_path / "edited.json", backend=NullBackend(), cache_dir=cache) + data = json.loads((tmp_path / "edited.json").read_text()) + assert data["timings"]["discovery_hits"] == 1 + (root / "package.json").write_text('{"dependencies":{"express":"5"}}') + git("add", "package.json") + git("commit", "-m", "change dependencies") + dependency = git("rev-parse", "HEAD") + replay(root, base=base, head=dependency, artifact=tmp_path / "dependency.json", backend=NullBackend(), cache_dir=cache) + data = json.loads((tmp_path / "dependency.json").read_text()) + assert data["timings"]["discovery_hits"] == 1 + assert data["change_context"]["head_revision"] == dependency + + +def test_identical_revision_materializes_once_and_reuses_discovery(tmp_path, monkeypatch): + from openultrasast.push.snapshot import SnapshotAdapter + + root, base, _, _ = history(tmp_path) + original = SnapshotAdapter.materialize + calls = [] + + def counted(self, oid, **kwargs): + calls.append(oid) + return original(self, oid, **kwargs) + + monkeypatch.setattr(SnapshotAdapter, "materialize", counted) + replay(root, base=base, head=base, artifact=tmp_path / "same.json", backend=NullBackend(), cache_dir=tmp_path / "cache") + data = json.loads((tmp_path / "same.json").read_text()) + assert calls == [base] + assert data["timings"]["discovery_hits"] == 1 + assert len(data["snapshots"]) == 2 + + +def test_admission_provenance_invalidates_when_installed_runtime_changes(tmp_path, monkeypatch): + from openultrasast.model.scan import ScanBudget + from openultrasast.push import runner + + monkeypatch.setattr(runner, "engine_runtime_identity", lambda: "first-installation") + first = runner._provenance(tmp_path, ScanBudget()) + monkeypatch.setattr(runner, "engine_runtime_identity", lambda: "second-installation") + second = runner._provenance(tmp_path, ScanBudget()) + assert first["semantics"] != second["semantics"] + assert first["facts"] == second["facts"] and first["graph_layout"] == second["graph_layout"]