82 lines
2.5 KiB
Python
82 lines
2.5 KiB
Python
import json
|
|
import subprocess
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
from uuid import UUID
|
|
|
|
import _bootstrap # noqa: F401
|
|
|
|
from netbox_plugin_store.agent import AgentClient
|
|
from netbox_plugin_store.commands import SubprocessRunner
|
|
|
|
|
|
class FakeSocket:
|
|
def __init__(self, response):
|
|
self.response = response
|
|
self.sent = b""
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *args):
|
|
return None
|
|
|
|
def settimeout(self, timeout):
|
|
self.timeout = timeout
|
|
|
|
def connect(self, path):
|
|
self.path = path
|
|
|
|
def sendall(self, value):
|
|
self.sent += value
|
|
|
|
def shutdown(self, how):
|
|
return None
|
|
|
|
def recv(self, size):
|
|
value, self.response = self.response, b""
|
|
return value
|
|
|
|
|
|
class AgentTests(unittest.TestCase):
|
|
def test_json_line_operation_protocol(self):
|
|
operation_id = "12345678-1234-5678-1234-567812345678"
|
|
response = (
|
|
json.dumps({"protocol_version": 1, "status": 202, "body": {"operation_id": operation_id}}).encode()
|
|
+ b"\n"
|
|
)
|
|
fake = FakeSocket(response)
|
|
with (
|
|
patch("netbox_plugin_store.agent.socket.AF_UNIX", 1, create=True),
|
|
patch("netbox_plugin_store.agent.socket.SOCK_STREAM", 1),
|
|
patch("netbox_plugin_store.agent.socket.socket", return_value=fake),
|
|
):
|
|
result = AgentClient(Path("/run/store.sock")).submit_operation(
|
|
request_id="request-id",
|
|
action="install",
|
|
plugin_slug="example-plugin",
|
|
version="1.0.0",
|
|
approved_payload_sha256="c" * 64,
|
|
requested_by="netbox-user:1",
|
|
)
|
|
self.assertEqual(result, UUID(operation_id))
|
|
request = json.loads(fake.sent.decode().strip())
|
|
self.assertEqual(request["method"], "POST")
|
|
self.assertEqual(request["path"], "/v1/operations")
|
|
self.assertEqual(request["body"]["plugin_slug"], "example-plugin")
|
|
UUID(request["idempotency_key"])
|
|
|
|
|
|
class CommandTests(unittest.TestCase):
|
|
def test_subprocess_boundary_never_uses_shell(self):
|
|
completed = subprocess.CompletedProcess(["python", "-V"], 0, "Python", "")
|
|
with patch("netbox_plugin_store.commands.subprocess.run", return_value=completed) as run:
|
|
result = SubprocessRunner().run(["python", "-V"], timeout=5)
|
|
self.assertEqual(result.stdout, "Python")
|
|
self.assertIs(run.call_args.kwargs["shell"], False)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|