test_security.py python
79 lines 2.9 KB
Raw
sha256:2313b6a6353294a0ca08ff579624198da250b99163a86215aed31a905912e360 Land Scooling Lab T0/T2 training contract and seven-tier tests Human minor ⚠ breaking 42 days ago
1 """Security tier tests for Scooling Lab request and dependency boundaries."""
2
3 from __future__ import annotations
4
5 import unittest
6
7 from scooling_lab_helpers import PROJECT_ROOT, valid_payload
8
9 from scooling_lab.bom import audit_repository_paths
10 from scooling_lab.contracts import TrainingJobRequest
11 from scooling_lab.errors import ApiError
12 from scooling_lab.license_policy import BomEntry, LicensePolicyError, validate_entry
13
14
15 class ScoolingLabSecurityTests(unittest.TestCase):
16 """Security tests for injection rejection and AGPL boundary enforcement."""
17
18 def test_security_rejects_path_traversal_command_and_url_injection(self) -> None:
19 """Untrusted paths, commands, URLs, callbacks, and worker fields fail closed."""
20
21 attacks: list[dict[str, object]] = []
22 path_payload = valid_payload("path")
23 path_payload["datasetId"] = "../private"
24 attacks.append(path_payload)
25
26 command_payload = valid_payload("command")
27 command_payload["trainingParameters"] = {"epochs": 1, "command": "rm -rf /"}
28 attacks.append(command_payload)
29
30 callback_payload = valid_payload("callback")
31 callback_payload["callbackUrl"] = "https://attacker.invalid/callback"
32 attacks.append(callback_payload)
33
34 worker_payload = valid_payload("worker")
35 worker_payload["workerUrl"] = "http://127.0.0.1:9999"
36 attacks.append(worker_payload)
37
38 for payload in attacks:
39 with self.subTest(payload=payload):
40 with self.assertRaises(ApiError):
41 TrainingJobRequest.from_mapping(payload)
42
43 def test_security_secret_scan_and_bom_audit_are_wired(self) -> None:
44 """CI contains gitleaks and the repository path audit passes locally."""
45
46 workflow = (PROJECT_ROOT / ".github/workflows/ci.yml").read_text(
47 encoding="utf-8"
48 )
49 self.assertIn("gitleaks detect", workflow)
50 self.assertIn("python -m scooling_lab.bom", workflow)
51 audit_repository_paths(PROJECT_ROOT)
52
53 def test_security_agpl_package_and_blocked_paths_are_rejected(self) -> None:
54 """AGPL license ids and Studio/CLI paths cannot enter the BOM."""
55
56 with self.assertRaises(LicensePolicyError):
57 validate_entry(
58 BomEntry(
59 name="studio",
60 version="1.0.0",
61 license="AGPL-3.0-only",
62 source_path="studio/backend/run.py",
63 evidence="fixture",
64 )
65 )
66 with self.assertRaises(LicensePolicyError):
67 validate_entry(
68 BomEntry(
69 name="unsloth-cli",
70 version="1.0.0",
71 license="Apache-2.0",
72 source_path="vendor/unsloth_cli/app.py",
73 evidence="fixture",
74 )
75 )
76
77
78 if __name__ == "__main__":
79 unittest.main()
File History 1 commit
sha256:2313b6a6353294a0ca08ff579624198da250b99163a86215aed31a905912e360 Land Scooling Lab T0/T2 training contract and seven-tier tests Human minor 42 days ago