Skip to content

Fix evidence gate, atomic state persistence, and lost-update race in EngagementStore - #25

Open
7megaumka7 wants to merge 6 commits into
s0ld13rr:mainfrom
7megaumka7:main
Open

7megaumka7 wants to merge 6 commits into
s0ld13rr:mainfrom
7megaumka7:main

Conversation

@7megaumka7

Copy link
Copy Markdown

Three measured defects fixed in the store layer:

  1. Evidence gate in add_vuln — add_vuln previously accepted any evidence string, so a confirmed finding with empty or thin evidence was written as-is (producing the 34% INFO/LOW noise). resolveVulnWrite now refuses confirmed-with-no-evidence and downgrades thin-evidence to suspected using the existing deriveConfidence.

  2. Atomic state persistence — state.json was written with a direct writeFileSync, so a crash mid-write truncated the file and corrupted the engagement. atomicWriteFileSync now writes temp + fsync + rename.

  3. Lost-update race — two concurrent subagent processes holding stale State copies raced on the write; last-writer-wins rolled back the resolved-vectors ledger 58->300. withFileLock (O_EXCL lockfile, bounded retry, stale-lock reclaim) serializes the file write.

22 tests pass across 4 files; typecheck clean.

7megaumka7 and others added 6 commits November 6, 2026 18:05
…ntStore

Three measured defects fixed in the store layer:
1. add_vuln accepted any evidence string; a confirmed finding with empty or
   thin evidence was written as-is, producing the 34% INFO/LOW noise. Now
   resolveVulnWrite refuses confirmed-with-no-evidence and downgrades
   thin-evidence to suspected using the existing deriveConfidence.
2. state.json was written with a direct writeFileSync, so a crash mid-write
   truncated the file and corrupted the engagement. atomicWriteFileSync now
   writes temp + fsync + rename.
3. two concurrent subagent processes holding stale State copies raced on the
   write, last-writer-wins rolled back the resolved-vectors ledger 58->300.
   withFileLock (O_EXCL lockfile, bounded retry, stale-lock reclaim) serializes
   the file write.

22 tests pass across 4 files; typecheck clean.
…-link

Three orchestration/relationship fixes on top of the store persistence
work (7d6d853):

1. Relationship-ID resolution (store.ts addRelationship). Agents key
   relationships on a vuln's human-facing TITLE instead of its stable
   `.id`, fragmenting the graph into parallel title-keyed vs id-keyed
   nodes and breaking cost-based path-finding. resolveRelationshipIds
   now resolves source_id/target_id from vuln TITLE -> vuln `.id`
   whenever the entity type is "vuln" (idempotent on an existing id).

2. Agent-liveness auto-retry (orchestrator.ts). detectStaleAgents is a
   liveness probe for subagents that are in flight but have produced
   ZERO new state markers for N minutes (busy-but-unproductive). It
   plans exactly ONE auto-retry per node (maxRetries=1) with a reduced
   scope plus an exponential-backoff-with-jitter delay (retryDelayMs,
   bounded [base, max], injectable random for deterministic tests).

3. Auto-chain-link (store.ts addVuln). After a finding is recorded,
   findAutoChainLinks scans its evidence/description/references for a
   reference to ANOTHER finding (by stable id or title) and auto-creates
   the EXPLOITED_VIA relationship edge, so the relationship graph
   reflects the chain without the agent hand-wiring each edge.

1176 core tests pass; typecheck clean.
…layer)

Seventh harness fix: route every subagent's HTTP(S) egress through the
Burp proxy at 127.0.0.1:8080 so proxy history fills and Active Scan++ /
Backslash / Autorize have a complete request corpus.

- proxyEnvForSubagent: computes HTTP_PROXY/HTTPS_PROXY (both cases) +
  NO_PROXY loopback exemption for a subagent env, honoring an explicit
  opt-out (disableProxy flag or per-agent optOutAgents set).
- proxyEnvPrompt: prompt snippet telling the subagent its traffic is
  proxied and must not be unset/bypassed.
- subagentProxy: one-call interface bundling env + prompt for a task node.

Pure compute helpers (never spawn), matching the orchestrator invariant.
1184 core tests pass; typecheck clean.
Commit 1c2e9bb added the pure compute helpers (proxyEnvForSubagent /
subagentProxy / proxyEnvPrompt) + tests, but they were never applied at
launch. This wires them into the two real spawn sites so every subagent's
HTTP(S) egress routes through the Burp proxy at 127.0.0.1:8080:

- orchestrator.ts: add SUBAGENT_PROXY_ENV_METADATA_KEY + proxyEnvFromSession
  (pure, tested) — the round-trip contract between the spawn driver and the
  shell spawn, so the shell reads back the env computed once at spawn instead
  of re-deriving (and re-deciding opt-out) without a task node.
- task.ts (makeOrchestratedSpawner.spawnOne + TaskTool.run): compute
  subagentProxy(node) / proxyEnvForSubagent(assignedAgent), stash the env in
  the subagent session metadata, and append the proxy prompt to the subagent
  instructions.
- shell.ts (ShellTool.shellEnv, the `bash` tool): read the session's stashed
  proxy env and seed it as the shell.env plugin-hook default so HTTP_PROXY /
  HTTPS_PROXY / NO_PROXY land in the child process env (user plugins can still
  override).

Verified: 1186 core tests pass (incl. 2 new proxyEnvFromSession tests); 25
shell tests pass (incl. 2 new end-to-end tests proving a subagent session's
shell sees the proxy env and a root session does not). Typecheck clean in both
packages/core and packages/opencode.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant