Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2025-02-28 - AST Traversal Memory Optimization
**Learning:** Eagerly materializing AST nodes into lists via `list(ast.iter_child_nodes(node))` during deep recursive AST traversal creates unnecessary memory allocations and GC pressure, particularly in hot paths like taint analysis.
**Action:** When implementing or modifying AST traversal functions, accept `Iterable[ast.AST]` in the signature and pass generators directly instead of eagerly materializing them into lists to prevent unnecessary memory allocations.
2 changes: 2 additions & 0 deletions src/wardline/install/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

_BLOCK_VERSION = "1"


def _compose_body(grant_suffix: str = "", grant_sentence: str = "") -> str:
return (
"This project uses **wardline** as its trust-boundary gate. Before handing "
Expand Down Expand Up @@ -81,6 +82,7 @@ def _pack_guidance(project_root: Path) -> tuple[str, str]:
)
return suffix, sentence


_OWN_NS = "wardline"
_END_MARKER = f"<!-- /{_OWN_NS}:instructions -->"
_WRITER_MARKER = f"<!-- {_OWN_NS}:last-writer:wardline install -->"
Expand Down
4 changes: 1 addition & 3 deletions src/wardline/mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -5103,9 +5103,7 @@ def _grants_merged_arguments(self, arguments: dict[str, Any]) -> dict[str, Any]:
if caller_packs is None or (
isinstance(caller_packs, list) and all(isinstance(p, str) for p in caller_packs)
):
merged["trust_packs"] = list(
dict.fromkeys([*(caller_packs or []), *self._default_trusted_packs])
)
merged["trust_packs"] = list(dict.fromkeys([*(caller_packs or []), *self._default_trusted_packs]))
if self._default_trust_local_packs:
caller_local = merged.get("trust_local_packs")
# Identity checks, not equality: 0 == False, and masking a caller's
Expand Down
18 changes: 8 additions & 10 deletions src/wardline/scanner/taint/variable_level.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from wardline.core.taints import _PROVENANCE_CLASH, RAW_ZONE, TRUST_RANK, TaintState, combine

if TYPE_CHECKING:
from collections.abc import Iterator
from collections.abc import Iterable, Iterator

# Serialisation sinks — calls that cross the representation boundary. Their
# output sheds validation provenance (raw bytes/str), so → UNKNOWN_RAW. This is
Expand Down Expand Up @@ -2519,7 +2519,7 @@ def compute_return_taint(
"""
returns: list[tuple[TaintState, str | None, ast.expr]] = []
_collect_return_paths(
list(func_node.body),
func_node.body,
function_taint,
taint_map,
var_taints,
Expand Down Expand Up @@ -2568,7 +2568,7 @@ def compute_return_callee(
"""
returns: list[tuple[TaintState, str | None, ast.expr]] = []
_collect_return_paths(
list(func_node.body),
func_node.body,
function_taint,
taint_map,
var_taints,
Expand All @@ -2589,14 +2589,14 @@ def compute_return_callee(
# a direct call. Provenance only — never changes a fire/no-fire decision.
for taint, callee, node in returns:
if taint == worst and callee is None and isinstance(node, ast.Name):
indirect = _assignment_callee(list(func_node.body), node.id, worst, function_taint, taint_map, var_taints)
indirect = _assignment_callee(func_node.body, node.id, worst, function_taint, taint_map, var_taints)
if indirect is not None:
return indirect
return None


def _assignment_callee(
nodes: list[ast.AST],
nodes: Iterable[ast.AST],
name: str,
worst: TaintState,
function_taint: TaintState,
Expand Down Expand Up @@ -2629,9 +2629,7 @@ def _assignment_callee(
and _resolve_expr(node.value, function_taint, taint_map, var_taints) == worst
):
result = callee
nested = _assignment_callee(
list(ast.iter_child_nodes(node)), name, worst, function_taint, taint_map, var_taints
)
nested = _assignment_callee(ast.iter_child_nodes(node), name, worst, function_taint, taint_map, var_taints)
if nested is not None:
result = nested
return result
Expand All @@ -2648,7 +2646,7 @@ def _return_callee(node: ast.expr) -> str | None:


def _collect_return_paths(
nodes: list[ast.AST],
nodes: Iterable[ast.AST],
function_taint: TaintState,
taint_map: dict[str, TaintState],
var_taints: dict[str, TaintState],
Expand Down Expand Up @@ -2686,7 +2684,7 @@ def _collect_return_paths(
_CURRENT_VAR_TYPES.reset(token_types)
out.append((taint, _return_callee(node.value), node.value))
_collect_return_paths(
list(ast.iter_child_nodes(node)),
ast.iter_child_nodes(node),
function_taint,
taint_map,
var_taints,
Expand Down
4 changes: 1 addition & 3 deletions tests/unit/install/test_doctor_pack_grants.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ def test_project_mcp_check_accepts_grant_flags(tmp_path: Path, monkeypatch: pyte
assert check.ok, check.message


def test_project_mcp_check_names_divergence_not_missing(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
def test_project_mcp_check_names_divergence_not_missing(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
# A present-but-noncanonical entry is a different failure than an absent one;
# "missing wardline server" for a visibly present entry sent the operator
# chasing the wrong problem.
Expand Down
8 changes: 2 additions & 6 deletions tests/unit/install/test_mcp_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,7 @@ def test_repair_preserves_trust_pack_grant_flags(tmp_path: Path, monkeypatch: py
"--allow-custom-packs",
]
(tmp_path / ".mcp.json").write_text(
json.dumps(
{"mcpServers": {"wardline": {"type": "stdio", "command": "/bin/wardline", "args": list(args)}}}
),
json.dumps({"mcpServers": {"wardline": {"type": "stdio", "command": "/bin/wardline", "args": list(args)}}}),
encoding="utf-8",
)
assert merge_mcp_entry(tmp_path) == "unchanged"
Expand Down Expand Up @@ -581,9 +579,7 @@ def test_repair_preserves_repeated_trust_pack_grants(tmp_path: Path, monkeypatch
assert merge_mcp_entry(tmp_path) == "unchanged"


def test_repair_drops_dangling_trust_pack_but_keeps_bare_grant(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
def test_repair_drops_dangling_trust_pack_but_keeps_bare_grant(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
# A --trust-pack with a missing or flag-shaped value is malformed: it must be
# dropped cleanly, and must never swallow the following --allow-custom-packs.
monkeypatch.setattr("wardline.install.mcp_json._find_wardline_command", lambda: "/bin/wardline")
Expand Down
4 changes: 1 addition & 3 deletions tests/unit/mcp/test_server_trust_grants.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
def _pack_project(tmp_path: Path) -> Path:
proj = tmp_path / "proj"
(proj / "scripts").mkdir(parents=True)
(proj / "scripts" / "grantpack.py").write_text(
'config = {"exclude": ["skipped_by_pack.py"]}\n', encoding="utf-8"
)
(proj / "scripts" / "grantpack.py").write_text('config = {"exclude": ["skipped_by_pack.py"]}\n', encoding="utf-8")
(proj / "weft.toml").write_text(f'[wardline]\npacks = ["{PACK_NAME}"]\n', encoding="utf-8")
(proj / "kept.py").write_text("def kept():\n return 1\n", encoding="utf-8")
(proj / "skipped_by_pack.py").write_text("def skipped():\n return 1\n", encoding="utf-8")
Expand Down