feat(v2): complete v2 reimplementation

This commit is contained in:
2026-07-31 13:33:39 +02:00
parent 396219e776
commit bd107d6a30
137 changed files with 20737 additions and 155 deletions
+173
View File
@@ -0,0 +1,173 @@
from __future__ import annotations
import pytest
PASSWORD = "correct horse battery staple"
HOST_KEY = "ssh-ed25519 AQID"
async def _setup_headers(client) -> dict[str, str]:
response = await client.post("/api/v2/setup", json={"username": "admin", "password": PASSWORD})
assert response.status_code == 201
return {"X-CSRF-Token": client.cookies["backup_tool_csrf"]}
async def _create_secret(client, headers: dict[str, str], purpose: str) -> str:
response = await client.post(
"/api/v2/admin/secrets",
json={"purpose": purpose, "value": "PRIVATE-KEY-CANARY"},
headers=headers,
)
assert response.status_code == 201
assert "PRIVATE-KEY-CANARY" not in response.text
return str(response.json()["id"])
def _source(secret_id: str) -> dict[str, object]:
return {
"name": "remote",
"kind": "ssh",
"public_config": {
"hostname": "backup.example.test",
"port": 22,
"username": "backup",
"host_key": HOST_KEY,
"root": "/",
},
"private_key_secret_id": secret_id,
}
@pytest.mark.asyncio
async def test_ssh_source_persists_only_safe_public_config_and_one_key_reference(
app_client,
) -> None:
client, _ = app_client
headers = await _setup_headers(client)
secret_id = await _create_secret(client, headers, "ssh_private_key")
created = await client.post("/api/v2/sources", json=_source(secret_id), headers=headers)
assert created.status_code == 201
body = created.json()
assert body["kind"] == "ssh"
assert body["public_config"] == _source(secret_id)["public_config"]
assert "secret" not in body
assert "PRIVATE-KEY-CANARY" not in created.text
listed = await client.get("/api/v2/sources", headers=headers)
assert listed.status_code == 200
assert listed.json()["items"] == [body]
assert "PRIVATE-KEY-CANARY" not in listed.text
probe = await client.post(f"/api/v2/sources/{body['id']}/probe", headers=headers)
assert probe.status_code == 409
assert probe.json()["code"] == "source_probe_failed"
@pytest.mark.asyncio
async def test_ssh_source_requires_exactly_one_existing_private_key_secret(
app_client,
) -> None:
client, _ = app_client
headers = await _setup_headers(client)
wrong_purpose = await _create_secret(client, headers, "ssh")
request = _source(wrong_purpose)
rejected_purpose = await client.post("/api/v2/sources", json=request, headers=headers)
assert rejected_purpose.status_code == 422
assert rejected_purpose.json()["code"] == "validation_failed"
assert "PRIVATE-KEY-CANARY" not in rejected_purpose.text
missing_secret = await client.post(
"/api/v2/sources",
json=_source("00000000-0000-0000-0000-000000000000"),
headers=headers,
)
assert missing_secret.status_code == 422
assert missing_secret.json()["code"] == "validation_failed"
valid_secret = await _create_secret(client, headers, "ssh_private_key")
extra_secret_reference = {
**_source(valid_secret),
"secret_refs": [valid_secret, wrong_purpose],
}
rejected_extra = await client.post(
"/api/v2/sources", json=extra_secret_reference, headers=headers
)
assert rejected_extra.status_code == 422
@pytest.mark.asyncio
@pytest.mark.parametrize(
"payload",
[
{"name": "unsupported", "kind": "sftp", "public_config": {}},
{"name": "unsupported", "kind": "postgresql", "public_config": {}},
{"name": "unsupported", "kind": "mysql", "public_config": {}},
{"name": "unsupported", "kind": "shell", "public_config": {}},
],
)
async def test_source_api_rejects_all_non_local_ssh_kinds(
app_client, payload: dict[str, object]
) -> None:
client, _ = app_client
headers = await _setup_headers(client)
response = await client.post("/api/v2/sources", json=payload, headers=headers)
assert response.status_code == 422
@pytest.mark.asyncio
@pytest.mark.parametrize(
"public_config",
[
{
"hostname": "backup.example.test",
"port": 22,
"username": "backup",
"root": "/",
},
{
"hostname": "backup.example.test",
"port": 0,
"username": "backup",
"host_key": HOST_KEY,
"root": "/",
},
{
"hostname": "backup.example.test",
"port": 22,
"username": "backup",
"host_key": HOST_KEY,
"root": "/not-the-chroot",
},
{
"hostname": "backup.example.test",
"port": 22,
"username": "backup",
"host_key": HOST_KEY,
"root": "/",
"password": "not-supported",
},
{
"hostname": "backup.example.test",
"port": 22,
"username": "backup",
"host_key": HOST_KEY,
"root": "/",
"remote_command": "not-supported",
},
],
)
async def test_ssh_source_rejects_noncanonical_or_unsupported_config(
app_client, public_config: dict[str, object]
) -> None:
client, _ = app_client
headers = await _setup_headers(client)
secret_id = await _create_secret(client, headers, "ssh_private_key")
payload = _source(secret_id)
payload["public_config"] = public_config
response = await client.post("/api/v2/sources", json=payload, headers=headers)
assert response.status_code == 422