fix(security): Harden skill activation and loading flows
Harden batch activation, dev refresh gating, Microsoft sync path handling, and Jetski skill loading against command injection, symlink traversal, and client-side star tampering. Add regression coverage for the security-sensitive paths and update the internal triage addendum for the Jetski loader fix.
This commit is contained in:
@@ -41,6 +41,60 @@ class SyncMicrosoftSkillsSecurityTests(unittest.TestCase):
|
||||
child.unlink()
|
||||
outside.rmdir()
|
||||
|
||||
def test_find_github_skills_ignores_symlinked_directories(self):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
root = Path(temp_dir)
|
||||
github_skills = root / ".github" / "skills"
|
||||
github_skills.mkdir(parents=True)
|
||||
|
||||
safe_skill = github_skills / "safe-skill"
|
||||
safe_skill.mkdir()
|
||||
(safe_skill / "SKILL.md").write_text("---\nname: safe-skill\n---\n", encoding="utf-8")
|
||||
|
||||
outside = Path(tempfile.mkdtemp())
|
||||
try:
|
||||
escaped = outside / "escaped-skill"
|
||||
escaped.mkdir()
|
||||
(escaped / "SKILL.md").write_text("---\nname: escaped\n---\n", encoding="utf-8")
|
||||
(github_skills / "escape").symlink_to(escaped, target_is_directory=True)
|
||||
|
||||
entries = sms.find_github_skills(root, set())
|
||||
relative_paths = {str(entry["relative_path"]) for entry in entries}
|
||||
|
||||
self.assertEqual(relative_paths, {".github/skills/safe-skill"})
|
||||
finally:
|
||||
for child in escaped.iterdir():
|
||||
child.unlink()
|
||||
escaped.rmdir()
|
||||
outside.rmdir()
|
||||
|
||||
def test_find_github_skills_ignores_symlinked_skill_markdown(self):
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
root = Path(temp_dir)
|
||||
github_skills = root / ".github" / "skills"
|
||||
github_skills.mkdir(parents=True)
|
||||
|
||||
safe_skill = github_skills / "safe-skill"
|
||||
safe_skill.mkdir()
|
||||
(safe_skill / "SKILL.md").write_text("---\nname: safe-skill\n---\n", encoding="utf-8")
|
||||
|
||||
linked_skill = github_skills / "linked-skill"
|
||||
linked_skill.mkdir()
|
||||
|
||||
outside = Path(tempfile.mkdtemp())
|
||||
try:
|
||||
target = outside / "SKILL.md"
|
||||
target.write_text("---\nname: escaped\n---\n", encoding="utf-8")
|
||||
(linked_skill / "SKILL.md").symlink_to(target)
|
||||
|
||||
entries = sms.find_github_skills(root, set())
|
||||
relative_paths = {str(entry["relative_path"]) for entry in entries}
|
||||
|
||||
self.assertEqual(relative_paths, {".github/skills/safe-skill"})
|
||||
finally:
|
||||
target.unlink()
|
||||
outside.rmdir()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user