feat: harden shared platform contracts

This commit is contained in:
2026-07-30 14:26:36 +02:00
parent 6970bf7457
commit 9b88ae388b
24 changed files with 2034 additions and 57 deletions

View File

@@ -132,6 +132,24 @@ class ApiSmokeTests(unittest.TestCase):
self.assertEqual(response.status_code, 201, response.text)
return str(response.json()["id"])
def _campaign_version_precondition(
self,
headers: dict[str, str],
campaign_id: str,
version_id: str,
) -> tuple[dict[str, str], int]:
response = self.client.get(
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}",
headers=headers,
)
self.assertEqual(response.status_code, 200, response.text)
etag = response.headers.get("etag")
self.assertIsNotNone(etag)
return (
{**headers, "If-Match": str(etag)},
int(response.json()["edit_revision"]),
)
def test_recipient_import_mapping_profiles_are_db_backed(self) -> None:
headers, _ = self._login()
payload = {
@@ -950,6 +968,33 @@ class ApiSmokeTests(unittest.TestCase):
user_always = {item["id"]: item for item in user_docs_payload["layers"]["always"]["documentation"]}
self.assertEqual(user_always["docs.configured-system-documentation"]["translation_locale"], "de")
sources = self.client.get("/api/v1/docs/sources", headers=headers)
self.assertEqual(sources.status_code, 200, sources.text)
source_payload = sources.json()
self.assertEqual(source_payload["total"], len(source_payload["items"]))
manifest_source = next(
item
for item in source_payload["items"]
if item["id"] == "docs.manifest"
)
self.assertEqual(manifest_source["kind"], "manifest")
self.assertNotIn("inspection", manifest_source)
inspected_source = self.client.get(
manifest_source["inspection_url"],
headers=headers,
)
self.assertEqual(inspected_source.status_code, 200, inspected_source.text)
self.assertEqual(
inspected_source.json()["inspection"]["module_id"],
"docs",
)
unknown_source = self.client.get(
"/api/v1/docs/sources/docs.unknown",
headers=headers,
)
self.assertEqual(unknown_source.status_code, 404, unknown_source.text)
platform_status = self.client.get("/api/v1/platform/status", headers=headers)
self.assertEqual(platform_status.status_code, 200, platform_status.text)
i18n_status = platform_status.json()["i18n"]
@@ -2747,7 +2792,10 @@ class ApiSmokeTests(unittest.TestCase):
archive.writestr("reports/february.txt", "February report")
payload.seek(0)
with patch("govoplan_files.backend.router._read_limited_upload", side_effect=AssertionError("ZIP upload should not be fully buffered")):
with patch(
"govoplan_files.backend.routes.uploads._read_limited_upload",
side_effect=AssertionError("ZIP upload should not be fully buffered"),
):
response = self.client.post(
"/api/v1/files/upload-zip",
headers=headers,
@@ -2890,10 +2938,18 @@ class ApiSmokeTests(unittest.TestCase):
self.assertTrue(full_payload["full"])
self.assertEqual(full_payload["current_version"]["id"], version_id)
mutation_headers, base_revision = self._campaign_version_precondition(
headers,
campaign_id,
version_id,
)
autosaved = self.client.post(
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}/autosave",
headers=headers,
json={"current_step": "fields"},
headers=mutation_headers,
json={
"current_step": "fields",
"base_revision": base_revision,
},
)
self.assertEqual(autosaved.status_code, 200, autosaved.text)
self.assertEqual(autosaved.json()["current_step"], "fields")
@@ -3038,10 +3094,18 @@ class ApiSmokeTests(unittest.TestCase):
self.assertEqual(temporary.json()["user_lock_state"], "temporary")
self.assertTrue(temporary.json()["user_locked_at"])
mutation_headers, base_revision = self._campaign_version_precondition(
headers,
campaign_id,
version_id,
)
blocked_update = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}",
headers=headers,
json={"current_step": "fields"},
headers=mutation_headers,
json={
"current_step": "fields",
"base_revision": base_revision,
},
)
self.assertEqual(blocked_update.status_code, 409, blocked_update.text)
@@ -3052,10 +3116,18 @@ class ApiSmokeTests(unittest.TestCase):
self.assertEqual(unlocked.status_code, 200, unlocked.text)
self.assertIsNone(unlocked.json()["user_lock_state"])
mutation_headers, base_revision = self._campaign_version_precondition(
headers,
campaign_id,
version_id,
)
updated = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}",
headers=headers,
json={"current_step": "fields"},
headers=mutation_headers,
json={
"current_step": "fields",
"base_revision": base_revision,
},
)
self.assertEqual(updated.status_code, 200, updated.text)
self.assertEqual(updated.json()["current_step"], "fields")
@@ -3116,18 +3188,34 @@ class ApiSmokeTests(unittest.TestCase):
self.assertNotEqual(second_version_id, first_version_id)
self.assertEqual(copied.json()["campaign"]["current_version_id"], second_version_id)
mutation_headers, base_revision = self._campaign_version_precondition(
headers,
campaign_id,
first_version_id,
)
historical_update = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{first_version_id}",
headers=headers,
json={"current_step": "fields"},
headers=mutation_headers,
json={
"current_step": "fields",
"base_revision": base_revision,
},
)
self.assertEqual(historical_update.status_code, 409, historical_update.text)
self.assertIn("Historical campaign versions are read-only", historical_update.text)
mutation_headers, base_revision = self._campaign_version_precondition(
headers,
campaign_id,
second_version_id,
)
second_update = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{second_version_id}",
headers=headers,
json={"current_step": "fields"},
headers=mutation_headers,
json={
"current_step": "fields",
"base_revision": base_revision,
},
)
self.assertEqual(second_update.status_code, 200, second_update.text)
@@ -4613,8 +4701,14 @@ class ApiSmokeTests(unittest.TestCase):
)
updated = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{second_version_id}",
headers=headers,
json={"campaign_json": campaign_json},
headers={
**headers,
"If-Match": str(version_response.headers["etag"]),
},
json={
"campaign_json": campaign_json,
"base_revision": version_response.json()["edit_revision"],
},
)
self.assertEqual(updated.status_code, 200, updated.text)
validated = self.client.post(
@@ -5883,10 +5977,18 @@ class ApiSmokeTests(unittest.TestCase):
self.assertEqual(allowed_write.status_code, 200, allowed_write.text)
changed_config = version_detail.json()["raw_json"]
changed_config["entries"]["inline"][0]["to"][0]["email"] = "changed@example.org"
mutation_headers, base_revision = self._campaign_version_precondition(
reader_headers,
campaign_id,
version_id,
)
denied_recipient_edit = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}",
headers=reader_headers,
json={"campaign_json": changed_config},
headers=mutation_headers,
json={
"campaign_json": changed_config,
"base_revision": base_revision,
},
)
self.assertEqual(denied_recipient_edit.status_code, 403, denied_recipient_edit.text)
self.assertEqual(self.client.get(f"/api/v1/campaigns/{campaign_id}", headers=other_headers).status_code, 403)
@@ -6030,18 +6132,29 @@ class ApiSmokeTests(unittest.TestCase):
}
blocked_inline = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}",
headers=headers,
json={"campaign_json": inline_json},
headers={**headers, "If-Match": str(detail.headers["etag"])},
json={
"campaign_json": inline_json,
"base_revision": detail.json()["edit_revision"],
},
)
self.assertEqual(blocked_inline.status_code, 422, blocked_inline.text)
self.assertIn("may only reference", blocked_inline.json()["detail"])
reusable_json = detail.json()["raw_json"]
reusable_json["server"] = {"mail_profile_id": tenant_profile_id}
mutation_headers, base_revision = self._campaign_version_precondition(
headers,
campaign_id,
version_id,
)
allowed_reusable = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}",
headers=headers,
json={"campaign_json": reusable_json},
headers=mutation_headers,
json={
"campaign_json": reusable_json,
"base_revision": base_revision,
},
)
self.assertEqual(allowed_reusable.status_code, 200, allowed_reusable.text)
@@ -6080,8 +6193,11 @@ class ApiSmokeTests(unittest.TestCase):
raw_json["server"] = {"mail_profile_id": profile_id}
denied_update = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}",
headers=headers,
json={"campaign_json": raw_json},
headers={**headers, "If-Match": str(detail.headers["etag"])},
json={
"campaign_json": raw_json,
"base_revision": detail.json()["edit_revision"],
},
)
self.assertEqual(denied_update.status_code, 422, denied_update.text)
@@ -6091,10 +6207,18 @@ class ApiSmokeTests(unittest.TestCase):
json={"policy": {"allowed_profile_ids": [profile_id]}},
)
self.assertEqual(allowed_policy.status_code, 200, allowed_policy.text)
mutation_headers, base_revision = self._campaign_version_precondition(
headers,
campaign_id,
version_id,
)
allowed_update = self.client.put(
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}",
headers=headers,
json={"campaign_json": raw_json},
headers=mutation_headers,
json={
"campaign_json": raw_json,
"base_revision": base_revision,
},
)
self.assertEqual(allowed_update.status_code, 200, allowed_update.text)