test_injection.py python
74 lines 2.5 KB
Raw
sha256:4671b7f787ddbe63ced31c895b688c77ab495653b65a730b423329f26b3c1439 feat: K1-P1 complete — agent provenance, build-verification… Sonnet 4.6 patch 55 days ago
1 """Security tests — injection surfaces in adapter inputs."""
2
3 from __future__ import annotations
4
5 import pytest
6
7 from adapters.errors import ConfigError, ReadError, WriteError
8 from tests.support import adapter_for, make_runner, ok
9
10
11 def test_commit_feature_rejects_path_traversal(git_only_config, repo_root) -> None:
12 adapter = adapter_for(git_only_config, repo_root, make_runner({}))
13 result = adapter.commit_feature(
14 branch="feat/x",
15 message="ok",
16 paths=["../../etc/passwd"],
17 )
18 assert isinstance(result, ReadError)
19
20
21 def test_commit_feature_rejects_dash_prefixed_path(muse_only_config, repo_root) -> None:
22 adapter = adapter_for(muse_only_config, repo_root, make_runner({}))
23 result = adapter.commit_feature(
24 branch="feat/x",
25 message="ok",
26 paths=["-rf"],
27 )
28 assert isinstance(result, ReadError)
29
30
31 def test_commit_feature_refuses_protected_main_across_regimes(
32 git_only_config,
33 muse_only_config,
34 muse_git_mirror_config,
35 repo_root,
36 ) -> None:
37 for config in (git_only_config, muse_only_config, muse_git_mirror_config):
38 adapter = adapter_for(config, repo_root, make_runner({}))
39 result = adapter.commit_feature(branch="main", message="x", paths=[])
40 assert isinstance(result, WriteError)
41
42
43 def test_shell_metacharacters_are_quoted(git_only_config, repo_root) -> None:
44 runner = make_runner(
45 {
46 "git checkout": ok(""),
47 "git add": ok(""),
48 "git commit": ok(""),
49 "git rev-parse": ok("deadbeef"),
50 }
51 )
52 adapter = adapter_for(git_only_config, repo_root, runner)
53 branch = "feat/$(rm -rf /)"
54 adapter.commit_feature(branch=branch, message="safe", paths=["docs/a.md"])
55 checkout_cmds = [c[0] for c in runner.calls if "git checkout" in c[0]]
56 assert checkout_cmds == [f"git checkout 'feat/$(rm -rf /)'"]
57
58
59 def test_template_substitution_does_not_execute_shell(git_only_config) -> None:
60 from adapters.templating import build_token_map, substitute_tokens
61
62 token_map = build_token_map(git_only_config)
63 payload = "{{repo.name}}; $(rm -rf /); `whoami`"
64 result = substitute_tokens(payload, token_map)
65 assert "$(rm -rf /)" in result
66 assert result.startswith("test-git")
67
68
69 def test_template_rejects_unknown_token_keys() -> None:
70 from adapters.templating import substitute_tokens
71
72 with pytest.raises(ConfigError, match="unknown or unmapped"):
73 substitute_tokens("{{not.in.registry}}", {"repo.name": "x"})
74
File History 1 commit
sha256:4671b7f787ddbe63ced31c895b688c77ab495653b65a730b423329f26b3c1439 feat: K1-P1 complete — agent provenance, build-verification… Sonnet 4.6 patch 55 days ago