mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-10-27 02:01:57 -06:00
Add assembly endpoints and approval flows
This commit is contained in:
@@ -109,3 +109,245 @@ def test_device_approvals_listing(prepared_app, engine_settings):
|
||||
record = next(a for a in approvals if a["id"] == "approval-http")
|
||||
assert record.get("hostname_conflict", {}).get("fingerprint_match") is True
|
||||
|
||||
|
||||
def test_device_approval_requires_resolution(prepared_app, engine_settings):
|
||||
client = prepared_app.test_client()
|
||||
_login(client)
|
||||
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
conn = sqlite3.connect(engine_settings.database.path)
|
||||
cur = conn.cursor()
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO devices (
|
||||
guid,
|
||||
hostname,
|
||||
created_at,
|
||||
last_seen,
|
||||
ssl_key_fingerprint,
|
||||
status
|
||||
) VALUES (?, ?, ?, ?, ?, 'active')
|
||||
""",
|
||||
(
|
||||
"33333333-3333-3333-3333-333333333333",
|
||||
"conflict-host",
|
||||
int(now.timestamp()),
|
||||
int(now.timestamp()),
|
||||
"existingfp",
|
||||
),
|
||||
)
|
||||
|
||||
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-conflict",
|
||||
"REF-CONFLICT",
|
||||
None,
|
||||
"conflict-host",
|
||||
"newfinger",
|
||||
"code-conflict",
|
||||
"pending",
|
||||
base64.b64encode(b"client").decode(),
|
||||
base64.b64encode(b"server").decode(),
|
||||
now_iso,
|
||||
now_iso,
|
||||
None,
|
||||
b"pub",
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
resp = client.post("/api/admin/device-approvals/approval-conflict/approve", json={})
|
||||
assert resp.status_code == 409
|
||||
assert resp.get_json().get("error") == "conflict_resolution_required"
|
||||
|
||||
resp = client.post(
|
||||
"/api/admin/device-approvals/approval-conflict/approve",
|
||||
json={"conflict_resolution": "overwrite"},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
body = resp.get_json()
|
||||
assert body == {"status": "approved", "conflict_resolution": "overwrite"}
|
||||
|
||||
conn = sqlite3.connect(engine_settings.database.path)
|
||||
cur = conn.cursor()
|
||||
cur.execute(
|
||||
"SELECT status, guid, approved_by_user_id FROM device_approvals WHERE id = ?",
|
||||
("approval-conflict",),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
conn.close()
|
||||
assert row[0] == "approved"
|
||||
assert row[1] == "33333333-3333-3333-3333-333333333333"
|
||||
assert row[2]
|
||||
|
||||
resp = client.post(
|
||||
"/api/admin/device-approvals/approval-conflict/approve",
|
||||
json={"conflict_resolution": "overwrite"},
|
||||
)
|
||||
assert resp.status_code == 409
|
||||
assert resp.get_json().get("error") == "approval_not_pending"
|
||||
|
||||
|
||||
def test_device_approval_auto_merge(prepared_app, engine_settings):
|
||||
client = prepared_app.test_client()
|
||||
_login(client)
|
||||
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
conn = sqlite3.connect(engine_settings.database.path)
|
||||
cur = conn.cursor()
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO devices (
|
||||
guid,
|
||||
hostname,
|
||||
created_at,
|
||||
last_seen,
|
||||
ssl_key_fingerprint,
|
||||
status
|
||||
) VALUES (?, ?, ?, ?, ?, 'active')
|
||||
""",
|
||||
(
|
||||
"44444444-4444-4444-4444-444444444444",
|
||||
"merge-host",
|
||||
int(now.timestamp()),
|
||||
int(now.timestamp()),
|
||||
"deadbeef",
|
||||
),
|
||||
)
|
||||
|
||||
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-merge",
|
||||
"REF-MERGE",
|
||||
None,
|
||||
"merge-host",
|
||||
"deadbeef",
|
||||
"code-merge",
|
||||
"pending",
|
||||
base64.b64encode(b"client").decode(),
|
||||
base64.b64encode(b"server").decode(),
|
||||
now_iso,
|
||||
now_iso,
|
||||
None,
|
||||
b"pub",
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
resp = client.post("/api/admin/device-approvals/approval-merge/approve", json={})
|
||||
assert resp.status_code == 200
|
||||
body = resp.get_json()
|
||||
assert body.get("status") == "approved"
|
||||
assert body.get("conflict_resolution") == "auto_merge_fingerprint"
|
||||
|
||||
conn = sqlite3.connect(engine_settings.database.path)
|
||||
cur = conn.cursor()
|
||||
cur.execute(
|
||||
"SELECT guid, status FROM device_approvals WHERE id = ?",
|
||||
("approval-merge",),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
conn.close()
|
||||
assert row[1] == "approved"
|
||||
assert row[0] == "44444444-4444-4444-4444-444444444444"
|
||||
|
||||
|
||||
def test_device_approval_deny(prepared_app, engine_settings):
|
||||
client = prepared_app.test_client()
|
||||
_login(client)
|
||||
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
conn = sqlite3.connect(engine_settings.database.path)
|
||||
cur = conn.cursor()
|
||||
|
||||
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-deny",
|
||||
"REF-DENY",
|
||||
None,
|
||||
"deny-host",
|
||||
"cafebabe",
|
||||
"code-deny",
|
||||
"pending",
|
||||
base64.b64encode(b"client").decode(),
|
||||
base64.b64encode(b"server").decode(),
|
||||
now_iso,
|
||||
now_iso,
|
||||
None,
|
||||
b"pub",
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
resp = client.post("/api/admin/device-approvals/approval-deny/deny", json={})
|
||||
assert resp.status_code == 200
|
||||
assert resp.get_json() == {"status": "denied"}
|
||||
|
||||
conn = sqlite3.connect(engine_settings.database.path)
|
||||
cur = conn.cursor()
|
||||
cur.execute(
|
||||
"SELECT status FROM device_approvals WHERE id = ?",
|
||||
("approval-deny",),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
conn.close()
|
||||
assert row[0] == "denied"
|
||||
|
||||
86
Data/Engine/tests/test_http_assemblies.py
Normal file
86
Data/Engine/tests/test_http_assemblies.py
Normal file
@@ -0,0 +1,86 @@
|
||||
import pytest
|
||||
|
||||
pytest.importorskip("flask")
|
||||
|
||||
from .test_http_auth import _login, prepared_app
|
||||
|
||||
|
||||
def test_assembly_crud_flow(prepared_app, engine_settings):
|
||||
client = prepared_app.test_client()
|
||||
_login(client)
|
||||
|
||||
resp = client.post(
|
||||
"/api/assembly/create",
|
||||
json={"island": "scripts", "kind": "folder", "path": "Utilities"},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
|
||||
resp = client.post(
|
||||
"/api/assembly/create",
|
||||
json={
|
||||
"island": "scripts",
|
||||
"kind": "file",
|
||||
"path": "Utilities/sample",
|
||||
"content": {"name": "Sample", "script": "Write-Output 'Hello'", "type": "powershell"},
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
body = resp.get_json()
|
||||
rel_path = body.get("rel_path")
|
||||
assert rel_path and rel_path.endswith(".json")
|
||||
|
||||
resp = client.get("/api/assembly/list?island=scripts")
|
||||
assert resp.status_code == 200
|
||||
listing = resp.get_json()
|
||||
assert any(item["rel_path"] == rel_path for item in listing.get("items", []))
|
||||
|
||||
resp = client.get(f"/api/assembly/load?island=scripts&path={rel_path}")
|
||||
assert resp.status_code == 200
|
||||
loaded = resp.get_json()
|
||||
assert loaded.get("assembly", {}).get("name") == "Sample"
|
||||
|
||||
resp = client.post(
|
||||
"/api/assembly/rename",
|
||||
json={
|
||||
"island": "scripts",
|
||||
"kind": "file",
|
||||
"path": rel_path,
|
||||
"new_name": "renamed",
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
renamed_rel = resp.get_json().get("rel_path")
|
||||
assert renamed_rel and renamed_rel.endswith(".json")
|
||||
|
||||
resp = client.post(
|
||||
"/api/assembly/move",
|
||||
json={
|
||||
"island": "scripts",
|
||||
"path": renamed_rel,
|
||||
"new_path": "Utilities/Nested/renamed.json",
|
||||
"kind": "file",
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
|
||||
resp = client.post(
|
||||
"/api/assembly/delete",
|
||||
json={
|
||||
"island": "scripts",
|
||||
"path": "Utilities/Nested/renamed.json",
|
||||
"kind": "file",
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
|
||||
resp = client.get("/api/assembly/list?island=scripts")
|
||||
remaining = resp.get_json().get("items", [])
|
||||
assert all(item["rel_path"] != "Utilities/Nested/renamed.json" for item in remaining)
|
||||
|
||||
|
||||
def test_server_time_endpoint(prepared_app):
|
||||
client = prepared_app.test_client()
|
||||
resp = client.get("/api/server/time")
|
||||
assert resp.status_code == 200
|
||||
body = resp.get_json()
|
||||
assert set(["epoch", "iso", "utc_iso", "timezone", "offset_seconds", "display"]).issubset(body)
|
||||
Reference in New Issue
Block a user