feat: add NetBox plugin store
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from support import make_config, plan
|
||||
|
||||
from netbox_store_agent.errors import PolicyError
|
||||
from netbox_store_agent.journal import ManagedPlugin
|
||||
from netbox_store_agent.managed_files import ManagedFiles
|
||||
|
||||
|
||||
class ManagedFilesTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.temporary = tempfile.TemporaryDirectory()
|
||||
self.root = Path(self.temporary.name)
|
||||
self.config = make_config(self.root, dry_run=False)
|
||||
self.files = ManagedFiles(self.config)
|
||||
release = plan()
|
||||
self.plugin = ManagedPlugin(
|
||||
"demo-plugin",
|
||||
"demo-plugin",
|
||||
"demo_plugin",
|
||||
"1.2.3",
|
||||
True,
|
||||
(release.requirement(),),
|
||||
)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
self.temporary.cleanup()
|
||||
|
||||
def test_include_exports_constant_without_referencing_plugins(self) -> None:
|
||||
text = self.files.render_include([self.plugin]).decode()
|
||||
self.assertIn('STORE_PLUGINS = [\n "demo_plugin"\n]', text)
|
||||
self.assertNotIn("PLUGINS = list", text)
|
||||
|
||||
def test_atomic_write_backup_and_restore(self) -> None:
|
||||
self.config.paths.include_path.write_text("old include", encoding="utf-8")
|
||||
self.config.paths.requirements_path.write_text("old requirements", encoding="utf-8")
|
||||
snapshot = self.files.write(
|
||||
"20f4274f-d4e5-42bf-9164-967b1a774481", [self.plugin]
|
||||
)
|
||||
self.assertIn("STORE_PLUGINS", self.config.paths.include_path.read_text())
|
||||
self.assertIn("--hash=sha256:", self.config.paths.requirements_path.read_text())
|
||||
self.files.restore(snapshot)
|
||||
self.assertEqual(self.config.paths.include_path.read_text(), "old include")
|
||||
self.assertEqual(self.config.paths.requirements_path.read_text(), "old requirements")
|
||||
|
||||
def test_conflicting_locked_distribution_rejected(self) -> None:
|
||||
other_requirement = {**self.plugin.requirements[0], "version": "2.0.0"}
|
||||
other = ManagedPlugin(
|
||||
"other", "demo-plugin", "other_plugin", "2.0.0", False, (other_requirement,)
|
||||
)
|
||||
with self.assertRaises(PolicyError):
|
||||
self.files.render_requirements([self.plugin, other])
|
||||
|
||||
def test_requirement_host_must_be_allowlisted(self) -> None:
|
||||
requirement = {**self.plugin.requirements[0], "download_url": "http://evil.test/x.whl"}
|
||||
plugin = ManagedPlugin(
|
||||
"demo-plugin", "demo-plugin", "demo_plugin", "1.2.3", False, (requirement,)
|
||||
)
|
||||
with self.assertRaises(Exception):
|
||||
self.files.render_requirements([plugin])
|
||||
|
||||
def test_path_escape_rejected(self) -> None:
|
||||
escaped = self.root / "outside.py"
|
||||
changed = self.config.__class__(
|
||||
self.config.agent,
|
||||
self.config.store,
|
||||
self.config.paths.__class__(
|
||||
self.config.paths.allowed_root,
|
||||
escaped,
|
||||
self.config.paths.requirements_path,
|
||||
self.config.paths.temp_dir,
|
||||
),
|
||||
self.config.commands,
|
||||
self.config.policy,
|
||||
)
|
||||
with self.assertRaises(PolicyError):
|
||||
ManagedFiles(changed).write(
|
||||
"20f4274f-d4e5-42bf-9164-967b1a774481", [self.plugin]
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user