Files
StarPilot/tools/vendor/tests/test_manifest.py
T
firestar5683 694b460f80 Developer Tools
Provide laptop and device build entry points, cache compatibility checks and developer tooling. Keep distribution assets and model packaging available before runtime consumers.

Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>

Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 20:02:39 -05:00

362 lines
14 KiB
Python

"""Source-manifest validation with standard-library and temporary Git fixtures."""
import copy
import json
import os
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
from openpilot.common.vendor_manifest import DEPENDENCIES, parse_manifest, validate_revision, validate_worktree
def make_manifest():
return {
"schema_version": 1,
"upstream": {"url": "https://github.com/commaai/openpilot.git", "commit": "1" * 40},
"dependencies": [
{"path": name, "url": f"https://github.com/commaai/{name}.git", "commit": "2" * 40, "tree": "3" * 40, "exclude": []}
for name in sorted(DEPENDENCIES)
],
}
def extension_manifest():
manifest = make_manifest()
entry = next(item for item in manifest['dependencies'] if item['path'] == 'jetlink_repo')
manifest['dependencies'].remove(entry)
manifest['vendored_extensions'] = [entry]
return manifest
class TestManifestSchema(unittest.TestCase):
def assert_invalid(self, manifest):
with self.assertRaises(ValueError):
parse_manifest(json.dumps(manifest))
def test_valid_manifest(self):
manifest = make_manifest()
manifest["dependencies"][-1]["exclude"] = ["AGENTS.md", "docs/generated"]
self.assertEqual(parse_manifest(json.dumps(manifest)), manifest)
def test_extension_and_legacy_manifest_forms(self):
for manifest in (make_manifest(), extension_manifest()):
self.assertEqual(parse_manifest(json.dumps(manifest)), manifest)
legacy = extension_manifest()
del legacy['vendored_extensions']
self.assertEqual(parse_manifest(json.dumps(legacy)), legacy)
def test_extensions_are_known_unique_and_fully_validated(self):
for field, value in (('path', 'unknown_repo'), ('path', 'panda'), ('commit', 'short'),
('tree', 'short'), ('url', 'http://example.com'), ('exclude', ['../escape'])):
with self.subTest(field=field, value=value):
manifest = extension_manifest()
manifest['vendored_extensions'][0][field] = value
self.assert_invalid(manifest)
for entries in (None, {}, 'jetlink_repo'):
manifest = extension_manifest()
manifest['vendored_extensions'] = entries
self.assert_invalid(manifest)
manifest = extension_manifest()
manifest['vendored_extensions'] *= 2
self.assert_invalid(manifest)
manifest = extension_manifest()
manifest['dependencies'].append(copy.deepcopy(manifest['vendored_extensions'][0]))
self.assert_invalid(manifest)
def test_malformed_json_and_non_objects(self):
for raw in ("", "{", b"\xff", "null", "true", "[]", '"manifest"', "1"):
with self.subTest(raw=raw), self.assertRaises(ValueError):
parse_manifest(raw)
def test_schema_is_integer_version_one(self):
for version in (None, True, False, 1.0, 0, 2, "1", [], {}):
with self.subTest(version=version):
manifest = make_manifest()
manifest["schema_version"] = version
self.assert_invalid(manifest)
def test_invalid_source_urls(self):
for url in (None, [], "", "https://", "https:///repo", "http://example.com/repo", "file:///repo", "git@example.com:repo"):
for field in ("upstream", "dependency"):
with self.subTest(url=url, field=field):
manifest = make_manifest()
entry = manifest["upstream"] if field == "upstream" else manifest["dependencies"][0]
entry["url"] = url
self.assert_invalid(manifest)
def test_invalid_revision_and_tree_identifiers(self):
for sha in (None, [], "", "a" * 39, "a" * 41, "G" * 40, "A" * 40, "master"):
for field in ("upstream", "dependency", "tree"):
with self.subTest(sha=sha, field=field):
manifest = make_manifest()
entry = manifest["upstream"] if field == "upstream" else manifest["dependencies"][0]
entry["tree" if field == "tree" else "commit"] = sha
self.assert_invalid(manifest)
def test_dependencies_are_complete_unique_and_known(self):
manifest = make_manifest()
variants = [None, {}, [], manifest["dependencies"][:-1], manifest["dependencies"] + [manifest["dependencies"][0]]]
for entries in variants:
with self.subTest(entries=entries):
candidate = copy.deepcopy(manifest)
candidate["dependencies"] = entries
self.assert_invalid(candidate)
for path in (None, [], {}, "../panda", "/panda", "panda/child", "unknown"):
with self.subTest(path=path):
candidate = make_manifest()
candidate["dependencies"][0]["path"] = path
self.assert_invalid(candidate)
for entry in (None, [], "dependency"):
with self.subTest(entry=entry):
candidate = make_manifest()
candidate["dependencies"][0] = entry
self.assert_invalid(candidate)
def test_exclusions_are_safe_relative_paths(self):
for exclusion in ("", ".", "..", "../escape", "/absolute", "dir/../../escape", "./file", "dir//file", ".git", "dir/.git", "bad\0path"):
with self.subTest(exclusion=exclusion):
manifest = make_manifest()
manifest["dependencies"][0]["exclude"] = [exclusion]
self.assert_invalid(manifest)
for excluded in (None, "AGENTS.md", [None], [[]], [{}], ["file", "file"]):
with self.subTest(excluded=excluded):
manifest = make_manifest()
manifest["dependencies"][0]["exclude"] = excluded
self.assert_invalid(manifest)
class TestManifestSourceTrees(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory()
self.addCleanup(self.temporary.cleanup)
self.root = Path(self.temporary.name)
self.repo = self.root / "source"
self.repo.mkdir()
env_patch = patch.dict(os.environ, {
"GIT_CONFIG_NOSYSTEM": "1", "GIT_CONFIG_GLOBAL": os.devnull,
"GIT_AUTHOR_NAME": "Source manifest test", "GIT_COMMITTER_NAME": "Source manifest test",
"GIT_AUTHOR_EMAIL": "source@example.invalid", "GIT_COMMITTER_EMAIL": "source@example.invalid",
})
env_patch.start()
self.addCleanup(env_patch.stop)
self.git("init", "-b", "test-manifest")
self.manifest = make_manifest()
self.manifest_path = self.repo / "upstream-sync.json"
self.write_manifest()
for name in DEPENDENCIES:
folder = self.repo / name
folder.mkdir()
(folder / "README.md").write_text("Ordinary dependency source\n")
self.commit()
def git(self, *args, input_text=None):
return subprocess.run(
["git", "-C", str(self.repo), *args], input=input_text, check=True,
text=True, capture_output=True,
).stdout.strip()
def write_manifest(self):
self.manifest_path.write_text(json.dumps(self.manifest))
def commit(self):
self.git("add", "--all")
self.git("commit", "-m", "Source layout fixture")
def assert_invalid_revision_and_worktree(self):
with self.assertRaises(ValueError):
validate_revision(self.repo, "HEAD")
with self.assertRaises(ValueError):
validate_worktree(self.repo)
def use_extension(self):
self.manifest = extension_manifest()
self.write_manifest()
self.commit()
def test_extension_tree_and_missing_provenance(self):
self.use_extension()
self.assertEqual(validate_revision(self.repo, 'HEAD'), self.manifest)
self.assertEqual(validate_worktree(self.repo), self.manifest)
del self.manifest['vendored_extensions']
self.write_manifest()
self.commit()
self.assert_invalid_revision_and_worktree()
shutil.rmtree(self.repo / 'jetlink_repo')
self.commit()
self.assertEqual(validate_revision(self.repo, 'HEAD'), self.manifest)
self.assertEqual(validate_worktree(self.repo), self.manifest)
def test_extension_missing_folder_and_symlink_rejected(self):
self.use_extension()
folder = self.repo / 'jetlink_repo'
external = self.root / 'external-jetlink'
folder.rename(external)
self.commit()
self.assert_invalid_revision_and_worktree()
folder.symlink_to(external, target_is_directory=True)
self.commit()
self.assert_invalid_revision_and_worktree()
def test_extension_excluded_metadata_and_nested_git_rejected(self):
self.use_extension()
folder = self.repo / 'jetlink_repo'
(folder / '.git').mkdir()
with self.assertRaises(ValueError):
validate_worktree(self.repo)
(folder / '.git').rmdir()
(folder / 'AGENTS.md').write_text('Excluded metadata')
self.commit()
self.assert_invalid_revision_and_worktree()
def test_valid_tree_permits_local_source_edits(self):
self.assertEqual(validate_revision(self.repo, "HEAD"), self.manifest)
(self.repo / "panda" / "README.md").write_text("Intentional local customization\n")
self.assertEqual(validate_worktree(self.repo), self.manifest)
def test_missing_tracked_manifest(self):
self.manifest_path.unlink()
self.commit()
with self.assertRaises(ValueError):
validate_revision(self.repo, "HEAD")
def test_manifest_worktree_symlink(self):
target = self.root / "external-manifest.json"
self.manifest_path.rename(target)
self.manifest_path.symlink_to(target)
with self.assertRaises(ValueError):
validate_worktree(self.repo)
def test_tracked_manifest_symlink(self):
target = self.repo / "source-manifest.json"
self.manifest_path.rename(target)
self.manifest_path.symlink_to(target.name)
self.commit()
self.assert_invalid_revision_and_worktree()
def test_missing_dependency_folder(self):
shutil.rmtree(self.repo / "panda")
with self.assertRaises(ValueError):
validate_worktree(self.repo)
self.commit()
self.assert_invalid_revision_and_worktree()
def test_dependency_root_symlink(self):
folder = self.repo / "panda"
target = self.root / "panda-outside"
folder.rename(target)
folder.symlink_to(target, target_is_directory=True)
with self.assertRaises(ValueError):
validate_worktree(self.repo)
self.commit()
self.assert_invalid_revision_and_worktree()
def test_gitlink_anywhere_is_rejected(self):
commit = self.git("rev-parse", "HEAD")
self.git("update-index", "--add", "--cacheinfo", f"160000,{commit},panda/embedded")
self.git("commit", "-m", "Nested gitlink fixture")
self.assert_invalid_revision_and_worktree()
def test_tracked_metadata_is_rejected(self):
for name in (".gitmodules", "AGENTS.md", "nested/agents.md"):
with self.subTest(name=name):
path = self.repo / "panda" / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("Excluded metadata fixture\n")
self.commit()
self.assert_invalid_revision_and_worktree()
path.unlink()
self.commit()
def test_nested_git_metadata_is_rejected(self):
for relative in (".git", "nested/.git"):
for kind in ("file", "directory", "broken_symlink"):
with self.subTest(relative=relative, kind=kind):
path = self.repo / "panda" / relative
path.parent.mkdir(parents=True, exist_ok=True)
if kind == "file":
path.write_text("gitdir: /does-not-exist\n")
elif kind == "directory":
path.mkdir()
else:
path.symlink_to("does-not-exist")
try:
with self.assertRaises(ValueError):
validate_worktree(self.repo)
finally:
if path.is_dir() and not path.is_symlink():
path.rmdir()
else:
path.unlink()
def test_missing_tracked_source(self):
(self.repo / "panda" / "README.md").unlink()
with self.assertRaises(ValueError):
validate_worktree(self.repo)
def test_regular_file_replaced_by_directory(self):
file = self.repo / "panda" / "README.md"
file.unlink()
file.mkdir()
with self.assertRaises(ValueError):
validate_worktree(self.repo)
def test_regular_file_replaced_by_symlink(self):
file = self.repo / "panda" / "README.md"
file.unlink()
file.symlink_to("../msgq_repo/README.md")
with self.assertRaises(ValueError):
validate_worktree(self.repo)
def test_intermediate_directory_symlink_is_rejected(self):
folder = self.repo / "panda" / "nested"
folder.mkdir()
(folder / "source.py").write_text("SOURCE = 1\n")
self.commit()
target = self.root / "external-source"
folder.rename(target)
folder.symlink_to(target, target_is_directory=True)
with self.assertRaises(ValueError):
validate_worktree(self.repo)
def test_tracked_leaf_symlink_is_preserved(self):
link = self.repo / "panda" / "linked-readme"
link.symlink_to("README.md")
self.commit()
self.assertEqual(validate_revision(self.repo, "HEAD"), self.manifest)
self.assertEqual(validate_worktree(self.repo), self.manifest)
link.unlink()
link.write_text("Unexpected regular file\n")
with self.assertRaises(ValueError):
validate_worktree(self.repo)
def test_unresolved_index_is_rejected(self):
blob = self.git("rev-parse", "HEAD:panda/README.md")
self.git("update-index", "--force-remove", "panda/README.md")
self.git("update-index", "--index-info", input_text=f"100644 {blob} 2\tpanda/README.md\n100644 {blob} 3\tpanda/README.md\n")
with self.assertRaises(ValueError):
validate_worktree(self.repo)
def test_excluded_file_and_directory_are_not_tracked(self):
entry = next(entry for entry in self.manifest["dependencies"] if entry["path"] == "panda")
entry["exclude"] = ["private.txt", "generated"]
self.write_manifest()
self.commit()
self.assertEqual(validate_revision(self.repo, "HEAD"), self.manifest)
for name in ("private.txt", "generated/source.py"):
with self.subTest(name=name):
file = self.repo / "panda" / name
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text("Excluded content\n")
self.commit()
self.assert_invalid_revision_and_worktree()
file.unlink()
self.commit()
if __name__ == "__main__":
unittest.main()