feat: implement append_note_content function and update related tests
This commit is contained in:
@@ -738,7 +738,7 @@ def _parse_name_status_z(raw_output: bytes) -> list[DiffEntry]:
|
||||
# Backward-compat fallback if output is tab-delimited unexpectedly.
|
||||
status_fallback, has_tab, first_path = token.partition("\t")
|
||||
if not has_tab:
|
||||
break
|
||||
break
|
||||
fallback_code = status_fallback[:1]
|
||||
fallback_similarity: int | None = None
|
||||
if len(status_fallback) > 1 and status_fallback[1:].isdigit():
|
||||
|
||||
@@ -113,7 +113,7 @@ class LLM:
|
||||
ordered_skills.append(f"scan_modes/{self.config.scan_mode}")
|
||||
if self.config.is_whitebox:
|
||||
ordered_skills.append("coordination/source_aware_whitebox")
|
||||
ordered_skills.append("source_aware_sast")
|
||||
ordered_skills.append("custom/source_aware_sast")
|
||||
|
||||
deduped: list[str] = []
|
||||
seen: set[str] = set()
|
||||
|
||||
@@ -36,10 +36,13 @@ mkdir -p "$ART"
|
||||
|
||||
semgrep scan --config p/default --config p/golang --config p/secrets \
|
||||
--metrics=off --json --output "$ART/semgrep.json" .
|
||||
sg scan --json . > "$ART/ast-grep.json"
|
||||
# Ruleless AST pass (works without sgconfig.yml/rules project setup)
|
||||
sg run --pattern '$F($$$ARGS)' --json=stream . > "$ART/ast-grep.json" 2> "$ART/ast-grep.log" || true
|
||||
gitleaks detect --source . --report-format json --report-path "$ART/gitleaks.json" || true
|
||||
trufflehog filesystem --no-update --json --no-verification . > "$ART/trufflehog.json" || true
|
||||
trivy fs --format json --output "$ART/trivy-fs.json" .
|
||||
# Keep trivy focused on vuln/misconfig (secrets already covered above) and increase timeout for large repos
|
||||
trivy fs --scanners vuln,misconfig --timeout 30m --offline-scan \
|
||||
--format json --output "$ART/trivy-fs.json" . || true
|
||||
```
|
||||
|
||||
If one tool is skipped or fails, record that in the shared wiki note along with the reason.
|
||||
@@ -64,7 +67,8 @@ If diff scope is active, restrict to changed files first, then expand only when
|
||||
Use `sg` for structure-aware code hunting:
|
||||
|
||||
```bash
|
||||
sg scan --json . > /workspace/.strix-source-aware/ast-grep.json
|
||||
# Ruleless one-off structural pass (no sgconfig.yml required)
|
||||
sg run --pattern '$F($$$ARGS)' --json=stream . > /workspace/.strix-source-aware/ast-grep.json 2> /workspace/.strix-source-aware/ast-grep.log || true
|
||||
```
|
||||
|
||||
Target high-value patterns such as:
|
||||
@@ -95,7 +99,8 @@ trufflehog filesystem --json . > /workspace/.strix-source-aware/trufflehog.json
|
||||
Run repository-wide dependency and config checks:
|
||||
|
||||
```bash
|
||||
trivy fs --format json --output /workspace/.strix-source-aware/trivy-fs.json .
|
||||
trivy fs --scanners vuln,misconfig --timeout 30m --offline-scan \
|
||||
--format json --output /workspace/.strix-source-aware/trivy-fs.json . || true
|
||||
```
|
||||
|
||||
## Converting Static Signals Into Exploits
|
||||
|
||||
@@ -123,7 +123,7 @@ def _append_wiki_update_on_finish(
|
||||
return
|
||||
|
||||
try:
|
||||
from strix.tools.notes.notes_actions import update_note
|
||||
from strix.tools.notes.notes_actions import append_note_content
|
||||
|
||||
note = _load_primary_wiki_note(agent_state)
|
||||
if not note:
|
||||
@@ -133,7 +133,6 @@ def _append_wiki_update_on_finish(
|
||||
if not isinstance(note_id, str) or not note_id:
|
||||
return
|
||||
|
||||
existing_content = str(note.get("content") or "")
|
||||
timestamp = datetime.now(UTC).isoformat()
|
||||
summary = " ".join(str(result_summary).split())
|
||||
if len(summary) > 1200:
|
||||
@@ -151,8 +150,7 @@ def _append_wiki_update_on_finish(
|
||||
"Recommendations:\n"
|
||||
f"{recommendation_lines}\n"
|
||||
)
|
||||
updated_content = f"{existing_content.rstrip()}{delta}"
|
||||
update_note(note_id=note_id, content=updated_content)
|
||||
append_note_content(note_id=note_id, delta=delta)
|
||||
except Exception:
|
||||
# Best-effort update; never block agent completion on note persistence.
|
||||
return
|
||||
|
||||
@@ -364,6 +364,26 @@ def get_note(note_id: str) -> dict[str, Any]:
|
||||
return {"success": True, "note": note_with_id}
|
||||
|
||||
|
||||
def append_note_content(note_id: str, delta: str) -> dict[str, Any]:
|
||||
with _notes_lock:
|
||||
try:
|
||||
_ensure_notes_loaded()
|
||||
|
||||
if note_id not in _notes_storage:
|
||||
return {"success": False, "error": f"Note with ID '{note_id}' not found"}
|
||||
|
||||
if not isinstance(delta, str):
|
||||
return {"success": False, "error": "Delta must be a string"}
|
||||
|
||||
note = _notes_storage[note_id]
|
||||
existing_content = str(note.get("content") or "")
|
||||
updated_content = f"{existing_content.rstrip()}{delta}"
|
||||
return update_note(note_id=note_id, content=updated_content)
|
||||
|
||||
except (ValueError, TypeError) as e:
|
||||
return {"success": False, "error": f"Failed to append note content: {e}"}
|
||||
|
||||
|
||||
@register_tool(sandbox_execution=False)
|
||||
def update_note(
|
||||
note_id: str,
|
||||
|
||||
@@ -164,14 +164,14 @@ def test_agent_finish_appends_wiki_update_for_whitebox(monkeypatch) -> None:
|
||||
},
|
||||
}
|
||||
|
||||
def fake_update_note(note_id: str, content: str):
|
||||
def fake_append_note_content(note_id: str, delta: str):
|
||||
captured["note_id"] = note_id
|
||||
captured["content"] = content
|
||||
captured["delta"] = delta
|
||||
return {"success": True, "note_id": note_id}
|
||||
|
||||
monkeypatch.setattr("strix.tools.notes.notes_actions.list_notes", fake_list_notes)
|
||||
monkeypatch.setattr("strix.tools.notes.notes_actions.get_note", fake_get_note)
|
||||
monkeypatch.setattr("strix.tools.notes.notes_actions.update_note", fake_update_note)
|
||||
monkeypatch.setattr("strix.tools.notes.notes_actions.append_note_content", fake_append_note_content)
|
||||
|
||||
state = SimpleNamespace(agent_id=child_id, parent_id=parent_id)
|
||||
result = agents_graph_actions.agent_finish(
|
||||
@@ -185,8 +185,8 @@ def test_agent_finish_appends_wiki_update_for_whitebox(monkeypatch) -> None:
|
||||
assert result["agent_completed"] is True
|
||||
assert captured_get["note_id"] == "wiki-note-1"
|
||||
assert captured["note_id"] == "wiki-note-1"
|
||||
assert "Agent Update: Child" in captured["content"]
|
||||
assert "AST pass completed" in captured["content"]
|
||||
assert "Agent Update: Child" in captured["delta"]
|
||||
assert "AST pass completed" in captured["delta"]
|
||||
|
||||
|
||||
def test_run_agent_in_thread_injects_shared_wiki_context_in_whitebox(monkeypatch) -> None:
|
||||
|
||||
@@ -137,3 +137,36 @@ def test_get_note_returns_full_note(tmp_path: Path, monkeypatch) -> None:
|
||||
finally:
|
||||
_reset_notes_state()
|
||||
set_global_tracer(previous_tracer) # type: ignore[arg-type]
|
||||
|
||||
|
||||
def test_append_note_content_appends_delta(tmp_path: Path, monkeypatch) -> None:
|
||||
monkeypatch.chdir(tmp_path)
|
||||
_reset_notes_state()
|
||||
|
||||
previous_tracer = get_global_tracer()
|
||||
tracer = Tracer("append-note-run")
|
||||
set_global_tracer(tracer)
|
||||
|
||||
try:
|
||||
created = notes_actions.create_note(
|
||||
title="Repo wiki",
|
||||
content="base",
|
||||
category="wiki",
|
||||
tags=["repo:demo"],
|
||||
)
|
||||
assert created["success"] is True
|
||||
note_id = created["note_id"]
|
||||
assert isinstance(note_id, str)
|
||||
|
||||
appended = notes_actions.append_note_content(
|
||||
note_id=note_id,
|
||||
delta="\n\n## Agent Update: worker\nSummary: done",
|
||||
)
|
||||
assert appended["success"] is True
|
||||
|
||||
loaded = notes_actions.get_note(note_id=note_id)
|
||||
assert loaded["success"] is True
|
||||
assert loaded["note"]["content"] == "base\n\n## Agent Update: worker\nSummary: done"
|
||||
finally:
|
||||
_reset_notes_state()
|
||||
set_global_tracer(previous_tracer) # type: ignore[arg-type]
|
||||
|
||||
Reference in New Issue
Block a user