Files
broker/tests/test_creds_source.py
T
coreci 7f7868f7cf docs(milestone): complete coreci-broker
---ci---
phase: 5
milestone: v0.1
status: complete
requirements:
  covered: [REQ-01, REQ-02, REQ-03, REQ-04, REQ-05, REQ-06, REQ-07, REQ-08, REQ-09, REQ-10, REQ-11, REQ-12, REQ-13, REQ-14, REQ-15, REQ-16, REQ-17, REQ-18, REQ-19, REQ-20]
  partial: []
---/ci---
2026-10-10 15:30:14 +00:00

312 lines
13 KiB
Python

import contextlib
import hashlib
import io
import json
import os
import sys
import tempfile
import threading
import unittest
import urllib.parse
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)))
import coreci_broker
API_KEY = "sk-test-key"
KB_NAME = "creds-coreci-coo"
PROXMOX_SECRET = {"url": "https://pve.coreci.dev:8006", "token": "pve-tok"}
PROXMOX_UPDATED = "2026-10-01T12:00:00Z"
def _standard_fixtures():
kbs = [{"id": "kb-1", "name": KB_NAME}]
files = {"kb-1": [{"name": "coreci/proxmox", "id": "f1", "updated_at": PROXMOX_UPDATED}]}
contents = {"f1": json.dumps(PROXMOX_SECRET)}
return kbs, files, contents
class _StubOwuiHandler(BaseHTTPRequestHandler):
kbs = None
files = None
contents = None
failures = None
hits = None
def log_message(self, format, *args):
pass
def _send(self, status, payload):
data = json.dumps(payload).encode("utf-8")
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def do_GET(self):
parsed = urllib.parse.urlsplit(self.path)
path = parsed.path
self.hits.append((path, self.headers.get("Authorization")))
if path in self.failures:
self._send(self.failures[path], {"error": self.failures[path]})
elif path == "/api/v1/knowledge/":
page = max(1, int((urllib.parse.parse_qs(parsed.query).get("page") or ["1"])[0]))
self._send(200, {"items": self.kbs[(page - 1) * 30:page * 30], "total": len(self.kbs)})
elif path.startswith("/api/v1/knowledge/"):
kb_id = path[len("/api/v1/knowledge/"):]
kb = next((entry for entry in self.kbs if entry["id"] == kb_id), None)
if kb is None:
self._send(404, {"error": 404})
else:
self._send(200, dict(kb, files=self.files.get(kb_id, [])))
elif path.startswith("/api/v1/files/") and path.endswith("/data/content"):
file_id = path[len("/api/v1/files/"):-len("/data/content")]
if file_id in self.contents:
self._send(200, {"content": self.contents[file_id]})
else:
self._send(404, {"error": 404})
else:
self._send(404, {"error": 404})
class StubOwuiServer:
def __init__(self, kbs, files, contents):
self.kbs, self.files, self.contents, self.failures = kbs, files, contents, {}
self.hits = []
handler = type("BoundStubHandler", (_StubOwuiHandler,), {
"kbs": kbs, "files": files, "contents": contents,
"failures": self.failures, "hits": self.hits,
})
self.server = ThreadingHTTPServer(("127.0.0.1", 0), handler)
threading.Thread(target=self.server.serve_forever, daemon=True).start()
@property
def base_url(self):
return "http://127.0.0.1:%d" % self.server.server_address[1]
def hits_for(self, path):
return [hit for hit in self.hits if hit[0] == path]
def close(self):
self.server.shutdown()
self.server.server_close()
class FileCredsSourceTests(unittest.TestCase):
def setUp(self):
tmp = tempfile.TemporaryDirectory()
self.addCleanup(tmp.cleanup)
self.creds_path = os.path.join(tmp.name, "creds.json")
self.document = {
"coreci/proxmox": {"url": "https://pve.coreci.dev:8006", "token": "pve-tok"},
"coreci/gitea": {"url": "https://git.coreci.dev", "token": "git-tok"},
}
self._write(self.document)
self.source = coreci_broker.FileCredsSource(self.creds_path)
def _write(self, document):
with open(self.creds_path, "w", encoding="utf-8") as handle:
json.dump(document, handle)
def test_fetches_both_paths_with_response_shape(self):
for path, secret in self.document.items():
result = self.source.get_secret(path)
self.assertEqual(path, result["path"])
self.assertEqual(secret, result["data"])
self.assertIsNone(result["updated_at"])
self.assertRegex(result["version"], r"^[0-9a-f]{8}$")
def test_version_is_short_sha256_of_serialized_data(self):
result = self.source.get_secret("coreci/proxmox")
serialized = json.dumps(result["data"], sort_keys=True, separators=(",", ":"))
expected = hashlib.sha256(serialized.encode("utf-8")).hexdigest()[:8]
self.assertEqual(expected, result["version"])
def test_equal_data_yields_equal_versions(self):
first = self.source.get_secret("coreci/proxmox")
second = self.source.get_secret("coreci/proxmox")
self.assertEqual(first["version"], second["version"])
def test_missing_path_is_not_found(self):
with self.assertRaises(coreci_broker._SecretNotFound):
self.source.get_secret("coreci/ghost")
def test_missing_file_means_all_paths_not_found(self):
os.remove(self.creds_path)
for path in self.document:
with self.assertRaises(coreci_broker._SecretNotFound):
self.source.get_secret(path)
def test_invalid_json_is_source_error(self):
with open(self.creds_path, "w", encoding="utf-8") as handle:
handle.write("{not-json")
with self.assertRaises(coreci_broker._CredsSourceError):
self.source.get_secret("coreci/proxmox")
def test_non_object_document_is_source_error(self):
self._write(["not", "a", "mapping"])
with self.assertRaises(coreci_broker._CredsSourceError):
self.source.get_secret("coreci/proxmox")
def test_fresh_read_sees_out_of_band_edits(self):
first = self.source.get_secret("coreci/proxmox")
self.document["coreci/proxmox"]["token"] = "rotated"
self._write(self.document)
second = self.source.get_secret("coreci/proxmox")
self.assertEqual("pve-tok", first["data"]["token"])
self.assertEqual("rotated", second["data"]["token"])
self.assertNotEqual(first["version"], second["version"])
class OwuiApiCredsSourceTests(unittest.TestCase):
def setUp(self):
kbs, files, contents = _standard_fixtures()
self.stub = StubOwuiServer(kbs, files, contents)
self.addCleanup(self.stub.close)
self.source = coreci_broker.OwuiApiCredsSource(self.stub.base_url, API_KEY)
def test_roundtrip_returns_response_shape(self):
result = self.source.get_secret("coreci/proxmox")
self.assertEqual("coreci/proxmox", result["path"])
self.assertEqual(PROXMOX_SECRET, result["data"])
self.assertEqual(PROXMOX_UPDATED, result["updated_at"])
self.assertRegex(result["version"], r"^[0-9a-f]{8}$")
def test_kb_and_file_map_cached_across_calls(self):
self.source.get_secret("coreci/proxmox")
self.source.get_secret("coreci/proxmox")
self.assertEqual(1, len(self.stub.hits_for("/api/v1/knowledge/")))
self.assertEqual(1, len(self.stub.hits_for("/api/v1/knowledge/kb-1")))
self.assertEqual(2, len(self.stub.hits_for("/api/v1/files/f1/data/content")))
def test_bearer_header_present_on_every_upstream_call(self):
self.source.get_secret("coreci/proxmox")
self.assertTrue(self.stub.hits)
for _, auth in self.stub.hits:
self.assertEqual("Bearer " + API_KEY, auth)
def test_refresh_on_miss_picks_up_newly_added_files(self):
self.source.get_secret("coreci/proxmox")
self.stub.files["kb-1"].append(
{"name": "coreci/gitea", "id": "f2", "updated_at": "2026-10-02T00:00:00Z"})
self.stub.contents["f2"] = json.dumps({"user": "ceo"})
result = self.source.get_secret("coreci/gitea")
self.assertEqual({"user": "ceo"}, result["data"])
self.assertEqual("2026-10-02T00:00:00Z", result["updated_at"])
self.assertEqual(2, len(self.stub.hits_for("/api/v1/knowledge/")))
def test_unknown_path_is_not_found(self):
with self.assertRaises(coreci_broker._SecretNotFound):
self.source.get_secret("coreci/ghost")
def test_missing_kb_is_not_found(self):
self.stub.kbs.clear()
with self.assertRaises(coreci_broker._SecretNotFound):
self.source.get_secret("coreci/proxmox")
def test_kb_list_404_is_not_found(self):
self.stub.failures["/api/v1/knowledge/"] = 404
with self.assertRaises(coreci_broker._SecretNotFound):
self.source.get_secret("coreci/proxmox")
def test_kb_detail_404_is_not_found(self):
self.stub.failures["/api/v1/knowledge/kb-1"] = 404
with self.assertRaises(coreci_broker._SecretNotFound):
self.source.get_secret("coreci/proxmox")
def test_file_content_404_is_not_found(self):
del self.stub.contents["f1"]
with self.assertRaises(coreci_broker._SecretNotFound):
self.source.get_secret("coreci/proxmox")
def test_upstream_500_is_source_error_not_crash(self):
self.stub.failures["/api/v1/files/f1/data/content"] = 500
with self.assertRaises(coreci_broker._CredsSourceError):
self.source.get_secret("coreci/proxmox")
def test_kb_list_500_is_source_error(self):
self.stub.failures["/api/v1/knowledge/"] = 500
with self.assertRaises(coreci_broker._CredsSourceError):
self.source.get_secret("coreci/proxmox")
def test_unavailable_upstream_maps_to_distinct_source_error(self):
source = coreci_broker.OwuiApiCredsSource("http://127.0.0.1:9", API_KEY)
with self.assertRaises(coreci_broker._CredsSourceError) as caught:
source.get_secret("coreci/proxmox")
self.assertIn("unavailable", str(caught.exception))
def test_invalid_content_json_is_source_error(self):
self.stub.contents["f1"] = "not-json"
with self.assertRaises(coreci_broker._CredsSourceError):
self.source.get_secret("coreci/proxmox")
def test_pagination_finds_kb_beyond_first_page(self):
self.stub.kbs[:] = [{"id": "kb-%d" % i, "name": "kb-%d" % i} for i in range(30)]
self.stub.kbs.append({"id": "kb-creds", "name": KB_NAME})
self.stub.files["kb-creds"] = [
{"name": "coreci/proxmox", "id": "f1", "updated_at": PROXMOX_UPDATED}]
result = self.source.get_secret("coreci/proxmox")
self.assertEqual(PROXMOX_SECRET, result["data"])
self.assertEqual(2, len(self.stub.hits_for("/api/v1/knowledge/")))
class CredsSourceFactoryTests(unittest.TestCase):
def setUp(self):
tmp = tempfile.TemporaryDirectory()
self.addCleanup(tmp.cleanup)
self.tmp = tmp.name
def _boot(self, extra):
env = {
"BROKER_ENV_PATH": os.path.join(self.tmp, ".env"),
"BROKER_DB_PATH": os.path.join(self.tmp, "broker.db"),
"BROKER_AUDIT_LOG_PATH": os.path.join(self.tmp, "broker.audit.log"),
}
env.update(extra)
with contextlib.redirect_stdout(io.StringIO()):
broker = coreci_broker.boot(env)
self.addCleanup(broker.audit.close)
self.addCleanup(broker.store.close)
return broker
def test_default_source_is_file_with_default_path(self):
broker = self._boot({})
self.assertIsInstance(broker.creds_source, coreci_broker.FileCredsSource)
self.assertEqual("data/creds.json", broker.creds_source.path)
def test_explicit_file_source_with_custom_path(self):
creds_path = os.path.join(self.tmp, "custom-creds.json")
with open(creds_path, "w", encoding="utf-8") as handle:
json.dump({"coreci/proxmox": PROXMOX_SECRET}, handle)
broker = self._boot({
"BROKER_CREDS_SOURCE": "file",
"BROKER_CREDS_FILE": creds_path,
})
self.assertIsInstance(broker.creds_source, coreci_broker.FileCredsSource)
self.assertEqual(creds_path, broker.creds_source.path)
self.assertEqual(PROXMOX_SECRET, broker.creds_source.get_secret("coreci/proxmox")["data"])
def test_owui_source_selected_by_config(self):
kbs, files, contents = _standard_fixtures()
stub = StubOwuiServer(kbs, files, contents)
self.addCleanup(stub.close)
broker = self._boot({
"BROKER_CREDS_SOURCE": "owui",
"BROKER_OWUI_BASE_URL": stub.base_url,
"BROKER_OWUI_API_KEY": API_KEY,
})
source = broker.creds_source
self.assertIsInstance(source, coreci_broker.OwuiApiCredsSource)
self.assertEqual(stub.base_url, source.base_url)
self.assertEqual(API_KEY, source.api_key)
self.assertEqual(PROXMOX_SECRET, source.get_secret("coreci/proxmox")["data"])
def test_unknown_source_value_raises_at_boot(self):
with self.assertRaises(ValueError):
self._boot({"BROKER_CREDS_SOURCE": "banana"})
if __name__ == "__main__":
unittest.main()