grep
This commit is contained in:
@@ -115,6 +115,7 @@ WHITE-BOX TESTING (code provided):
|
|||||||
- Static coverage floor: execute at least one structural AST mapping pass (`sg` and/or Tree-sitter) per repository and keep artifact output
|
- Static coverage floor: execute at least one structural AST mapping pass (`sg` and/or Tree-sitter) per repository and keep artifact output
|
||||||
- Static coverage target per repository: run one `semgrep` pass, one secrets pass (`gitleaks` and/or `trufflehog`), one `trivy fs` pass, and one AST-structural pass (`sg` and/or Tree-sitter); if any are skipped, record why in the shared wiki
|
- Static coverage target per repository: run one `semgrep` pass, one secrets pass (`gitleaks` and/or `trufflehog`), one `trivy fs` pass, and one AST-structural pass (`sg` and/or Tree-sitter); if any are skipped, record why in the shared wiki
|
||||||
- Keep AST artifacts bounded and high-signal: scope to relevant paths/hypotheses, avoid whole-repo generic function dumps
|
- Keep AST artifacts bounded and high-signal: scope to relevant paths/hypotheses, avoid whole-repo generic function dumps
|
||||||
|
- AST target selection rule: build `sg-targets.txt` from `semgrep.json` scope first (`paths.scanned`, fallback to unique `results[].path`), then run `xargs ... sg run` against that file list. Only use path-heuristic fallback if semgrep scope is unavailable, and log fallback reason in the wiki.
|
||||||
- Shared memory: Use notes as shared working memory; discover wiki notes with `list_notes`, then read the selected one via `get_note(note_id=...)` before analysis
|
- Shared memory: Use notes as shared working memory; discover wiki notes with `list_notes`, then read the selected one via `get_note(note_id=...)` before analysis
|
||||||
- Before `agent_finish`/`finish_scan`, update the shared repo wiki with scanner summaries, key routes/sinks, and dynamic follow-up plan
|
- Before `agent_finish`/`finish_scan`, update the shared repo wiki with scanner summaries, key routes/sinks, and dynamic follow-up plan
|
||||||
- Dynamic: Run the application and test live to validate exploitability
|
- Dynamic: Run the application and test live to validate exploitability
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ Increase white-box coverage by combining source-aware triage with dynamic valida
|
|||||||
## Recommended Workflow
|
## Recommended Workflow
|
||||||
|
|
||||||
1. Build a quick source map before deep exploitation, including at least one AST-structural pass (`sg` or `tree-sitter`) scoped to relevant paths.
|
1. Build a quick source map before deep exploitation, including at least one AST-structural pass (`sg` or `tree-sitter`) scoped to relevant paths.
|
||||||
|
- For `sg` baseline, derive `sg-targets.txt` from `semgrep.json` scope first (`paths.scanned`, fallback to unique `results[].path`) and run `xargs ... sg run` on that list.
|
||||||
|
- Only fall back to path heuristics when semgrep scope is unavailable, and record the fallback reason in the repo wiki.
|
||||||
2. Run first-pass static triage to rank high-risk paths.
|
2. Run first-pass static triage to rank high-risk paths.
|
||||||
3. Use triage outputs to prioritize dynamic PoC validation.
|
3. Use triage outputs to prioritize dynamic PoC validation.
|
||||||
4. Keep findings evidence-driven: no report without validation.
|
4. Keep findings evidence-driven: no report without validation.
|
||||||
|
|||||||
@@ -103,9 +103,12 @@ def _ensure_notes_loaded() -> None:
|
|||||||
notes_path = _get_notes_jsonl_path()
|
notes_path = _get_notes_jsonl_path()
|
||||||
if notes_path:
|
if notes_path:
|
||||||
_notes_storage.update(_load_notes_from_jsonl(notes_path))
|
_notes_storage.update(_load_notes_from_jsonl(notes_path))
|
||||||
for note_id, note in _notes_storage.items():
|
try:
|
||||||
if note.get("category") == "wiki":
|
for note_id, note in _notes_storage.items():
|
||||||
_persist_wiki_note(note_id, note)
|
if note.get("category") == "wiki":
|
||||||
|
_persist_wiki_note(note_id, note)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
_loaded_notes_run_dir = run_dir_key
|
_loaded_notes_run_dir = run_dir_key
|
||||||
|
|
||||||
|
|||||||
@@ -170,3 +170,45 @@ def test_append_note_content_appends_delta(tmp_path: Path, monkeypatch) -> None:
|
|||||||
finally:
|
finally:
|
||||||
_reset_notes_state()
|
_reset_notes_state()
|
||||||
set_global_tracer(previous_tracer) # type: ignore[arg-type]
|
set_global_tracer(previous_tracer) # type: ignore[arg-type]
|
||||||
|
|
||||||
|
|
||||||
|
def test_list_and_get_note_handle_wiki_repersist_oserror_gracefully(
|
||||||
|
tmp_path: Path, monkeypatch
|
||||||
|
) -> None:
|
||||||
|
monkeypatch.chdir(tmp_path)
|
||||||
|
_reset_notes_state()
|
||||||
|
|
||||||
|
previous_tracer = get_global_tracer()
|
||||||
|
tracer = Tracer("wiki-repersist-oserror-run")
|
||||||
|
set_global_tracer(tracer)
|
||||||
|
|
||||||
|
try:
|
||||||
|
created = notes_actions.create_note(
|
||||||
|
title="Repo wiki",
|
||||||
|
content="initial wiki content",
|
||||||
|
category="wiki",
|
||||||
|
tags=["repo:demo"],
|
||||||
|
)
|
||||||
|
assert created["success"] is True
|
||||||
|
note_id = created["note_id"]
|
||||||
|
assert isinstance(note_id, str)
|
||||||
|
|
||||||
|
_reset_notes_state()
|
||||||
|
|
||||||
|
def _raise_oserror(*_args, **_kwargs) -> None:
|
||||||
|
raise OSError("disk full")
|
||||||
|
|
||||||
|
monkeypatch.setattr(notes_actions, "_persist_wiki_note", _raise_oserror)
|
||||||
|
|
||||||
|
listed = notes_actions.list_notes(category="wiki")
|
||||||
|
assert listed["success"] is True
|
||||||
|
assert listed["total_count"] == 1
|
||||||
|
assert listed["notes"][0]["note_id"] == note_id
|
||||||
|
|
||||||
|
fetched = notes_actions.get_note(note_id=note_id)
|
||||||
|
assert fetched["success"] is True
|
||||||
|
assert fetched["note"]["note_id"] == note_id
|
||||||
|
assert fetched["note"]["content"] == "initial wiki content"
|
||||||
|
finally:
|
||||||
|
_reset_notes_state()
|
||||||
|
set_global_tracer(previous_tracer) # type: ignore[arg-type]
|
||||||
|
|||||||
Reference in New Issue
Block a user