mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-10-26 22:01:59 -06:00
Implement admin enrollment APIs
This commit is contained in:
122
Data/Engine/tests/test_enrollment_admin_service.py
Normal file
122
Data/Engine/tests/test_enrollment_admin_service.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import base64
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import pytest
|
||||
|
||||
from Data.Engine.repositories.sqlite import connection as sqlite_connection
|
||||
from Data.Engine.repositories.sqlite import migrations as sqlite_migrations
|
||||
from Data.Engine.repositories.sqlite.enrollment_repository import SQLiteEnrollmentRepository
|
||||
from Data.Engine.repositories.sqlite.user_repository import SQLiteUserRepository
|
||||
from Data.Engine.services.enrollment.admin_service import EnrollmentAdminService
|
||||
|
||||
|
||||
def _build_service(tmp_path):
|
||||
db_path = tmp_path / "admin.db"
|
||||
conn = sqlite3.connect(db_path)
|
||||
sqlite_migrations.apply_all(conn)
|
||||
conn.close()
|
||||
|
||||
factory = sqlite_connection.connection_factory(db_path)
|
||||
enrollment_repo = SQLiteEnrollmentRepository(factory)
|
||||
user_repo = SQLiteUserRepository(factory)
|
||||
|
||||
fixed_now = datetime(2024, 1, 1, tzinfo=timezone.utc)
|
||||
service = EnrollmentAdminService(
|
||||
repository=enrollment_repo,
|
||||
user_repository=user_repo,
|
||||
clock=lambda: fixed_now,
|
||||
)
|
||||
return service, factory, fixed_now
|
||||
|
||||
|
||||
def test_create_and_list_install_codes(tmp_path):
|
||||
service, factory, fixed_now = _build_service(tmp_path)
|
||||
|
||||
record = service.create_install_code(ttl_hours=3, max_uses=5, created_by="admin")
|
||||
assert record.code
|
||||
assert record.max_uses == 5
|
||||
assert record.status(now=fixed_now) == "active"
|
||||
|
||||
records = service.list_install_codes()
|
||||
assert any(r.record_id == record.record_id for r in records)
|
||||
|
||||
# Invalid TTL should raise
|
||||
with pytest.raises(ValueError):
|
||||
service.create_install_code(ttl_hours=2, max_uses=1, created_by=None)
|
||||
|
||||
# Deleting should succeed and remove the record
|
||||
assert service.delete_install_code(record.record_id) is True
|
||||
remaining = service.list_install_codes()
|
||||
assert all(r.record_id != record.record_id for r in remaining)
|
||||
|
||||
|
||||
def test_list_device_approvals_includes_conflict(tmp_path):
|
||||
service, factory, fixed_now = _build_service(tmp_path)
|
||||
|
||||
conn = factory()
|
||||
cur = conn.cursor()
|
||||
|
||||
cur.execute(
|
||||
"INSERT INTO sites (name, description, created_at) VALUES (?, ?, ?)",
|
||||
("HQ", "Primary site", int(fixed_now.timestamp())),
|
||||
)
|
||||
site_id = cur.lastrowid
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO devices (guid, hostname, created_at, last_seen, ssl_key_fingerprint, status)
|
||||
VALUES (?, ?, ?, ?, ?, 'active')
|
||||
""",
|
||||
("11111111-1111-1111-1111-111111111111", "agent-one", int(fixed_now.timestamp()), int(fixed_now.timestamp()), "abc123",),
|
||||
)
|
||||
cur.execute(
|
||||
"INSERT INTO device_sites (device_hostname, site_id, assigned_at) VALUES (?, ?, ?)",
|
||||
("agent-one", site_id, int(fixed_now.timestamp())),
|
||||
)
|
||||
|
||||
now_iso = fixed_now.isoformat()
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO device_approvals (
|
||||
id,
|
||||
approval_reference,
|
||||
guid,
|
||||
hostname_claimed,
|
||||
ssl_key_fingerprint_claimed,
|
||||
enrollment_code_id,
|
||||
status,
|
||||
client_nonce,
|
||||
server_nonce,
|
||||
created_at,
|
||||
updated_at,
|
||||
approved_by_user_id,
|
||||
agent_pubkey_der
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
"approval-1",
|
||||
"REF123",
|
||||
None,
|
||||
"agent-one",
|
||||
"abc123",
|
||||
"code-1",
|
||||
"pending",
|
||||
base64.b64encode(b"client").decode(),
|
||||
base64.b64encode(b"server").decode(),
|
||||
now_iso,
|
||||
now_iso,
|
||||
None,
|
||||
b"pubkey",
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
approvals = service.list_device_approvals()
|
||||
assert len(approvals) == 1
|
||||
record = approvals[0]
|
||||
assert record.hostname_conflict is not None
|
||||
assert record.hostname_conflict.fingerprint_match is True
|
||||
assert record.conflict_requires_prompt is False
|
||||
|
||||
111
Data/Engine/tests/test_http_admin.py
Normal file
111
Data/Engine/tests/test_http_admin.py
Normal file
@@ -0,0 +1,111 @@
|
||||
import base64
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from .test_http_auth import _login, prepared_app
|
||||
|
||||
|
||||
def test_enrollment_codes_require_authentication(prepared_app):
|
||||
client = prepared_app.test_client()
|
||||
resp = client.get("/api/admin/enrollment-codes")
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
def test_enrollment_code_workflow(prepared_app):
|
||||
client = prepared_app.test_client()
|
||||
_login(client)
|
||||
|
||||
payload = {"ttl_hours": 3, "max_uses": 4}
|
||||
resp = client.post("/api/admin/enrollment-codes", json=payload)
|
||||
assert resp.status_code == 201
|
||||
created = resp.get_json()
|
||||
assert created["max_uses"] == 4
|
||||
assert created["status"] == "active"
|
||||
|
||||
resp = client.get("/api/admin/enrollment-codes")
|
||||
assert resp.status_code == 200
|
||||
codes = resp.get_json().get("codes", [])
|
||||
assert any(code["id"] == created["id"] for code in codes)
|
||||
|
||||
resp = client.delete(f"/api/admin/enrollment-codes/{created['id']}")
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
def test_device_approvals_listing(prepared_app, engine_settings):
|
||||
client = prepared_app.test_client()
|
||||
_login(client)
|
||||
|
||||
conn = sqlite3.connect(engine_settings.database.path)
|
||||
cur = conn.cursor()
|
||||
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
cur.execute(
|
||||
"INSERT INTO sites (name, description, created_at) VALUES (?, ?, ?)",
|
||||
("HQ", "Primary", int(now.timestamp())),
|
||||
)
|
||||
site_id = cur.lastrowid
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO devices (guid, hostname, created_at, last_seen, ssl_key_fingerprint, status)
|
||||
VALUES (?, ?, ?, ?, ?, 'active')
|
||||
""",
|
||||
(
|
||||
"22222222-2222-2222-2222-222222222222",
|
||||
"approval-host",
|
||||
int(now.timestamp()),
|
||||
int(now.timestamp()),
|
||||
"deadbeef",
|
||||
),
|
||||
)
|
||||
cur.execute(
|
||||
"INSERT INTO device_sites (device_hostname, site_id, assigned_at) VALUES (?, ?, ?)",
|
||||
("approval-host", site_id, int(now.timestamp())),
|
||||
)
|
||||
|
||||
now_iso = now.isoformat()
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO device_approvals (
|
||||
id,
|
||||
approval_reference,
|
||||
guid,
|
||||
hostname_claimed,
|
||||
ssl_key_fingerprint_claimed,
|
||||
enrollment_code_id,
|
||||
status,
|
||||
client_nonce,
|
||||
server_nonce,
|
||||
created_at,
|
||||
updated_at,
|
||||
approved_by_user_id,
|
||||
agent_pubkey_der
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
"approval-http",
|
||||
"REFHTTP",
|
||||
None,
|
||||
"approval-host",
|
||||
"deadbeef",
|
||||
"code-http",
|
||||
"pending",
|
||||
base64.b64encode(b"client").decode(),
|
||||
base64.b64encode(b"server").decode(),
|
||||
now_iso,
|
||||
now_iso,
|
||||
None,
|
||||
b"pub",
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
resp = client.get("/api/admin/device-approvals")
|
||||
assert resp.status_code == 200
|
||||
body = resp.get_json()
|
||||
approvals = body.get("approvals", [])
|
||||
assert any(a["id"] == "approval-http" for a in approvals)
|
||||
record = next(a for a in approvals if a["id"] == "approval-http")
|
||||
assert record.get("hostname_conflict", {}).get("fingerprint_match") is True
|
||||
|
||||
Reference in New Issue
Block a user