test_wp13_plugin_platform_api.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. """Flask/RBAC/openapi contract for the closed WP13 plugin gateway."""
  2. from __future__ import annotations
  3. from app.core.plugins.governance import fixture_signature_digest
  4. MANIFEST = {
  5. "schema_version": 1, "plugin_uid": "fixture-api-quality", "name": "fixture-api-quality", "version": "1.0.0", "api_version": "1",
  6. "type": "quality", "capabilities": ["evaluate"],
  7. "permissions": {"network": False, "file": False, "secret": False, "child_process": False},
  8. "resource": {"timeout_ms": 100, "max_output_bytes": 4096, "max_concurrency": 1, "max_retries": 1},
  9. "compatibility": {"platform_api": "1"},
  10. "distribution": {"kind": "builtin_fixture", "fixture_id": "ENGINEERING_EVIDENCE_ONLY", "artifact_digest": "a" * 64},
  11. }
  12. RECORD = {
  13. "artifact_digest": "a" * 64,
  14. "signature": {"trust_store_key_id": "local-fixture-key-v1", "signature_digest": fixture_signature_digest("a" * 64)},
  15. "sbom_digest": "b" * 64, "license_digest": "c" * 64, "vulnerability_digest": "d" * 64, "provenance_digest": "e" * 64,
  16. }
  17. class _Gateway:
  18. calls: list[dict] = []
  19. def register(self, **kwargs):
  20. type(self).calls.append(kwargs)
  21. return {"state": "draft", "plugin_uid": kwargs["manifest"]["plugin_uid"], "version": "1.0.0"}
  22. def _client(monkeypatch):
  23. from app import create_app
  24. from app.api.system import plugin_platform_routes
  25. _Gateway.calls = []
  26. monkeypatch.setattr(plugin_platform_routes, "DatabasePluginPlatformService", _Gateway)
  27. monkeypatch.setattr(
  28. "app.core.system.auth.load_identity_from_token",
  29. lambda token, secret: {"id": "01900000-0000-7000-8000-000000000013", "roles": [token]} if token in {"viewer", "admin"} else None,
  30. )
  31. app = create_app()
  32. app.config.update(TESTING=True)
  33. return app.test_client()
  34. def test_wp13_registry_route_is_closed_rbac_no_store_and_server_principal(monkeypatch):
  35. client = _client(monkeypatch)
  36. assert client.post("/api/system/plugins/registry", json={"manifest": MANIFEST, "registry_record": RECORD}, headers={"Authorization": "Bearer viewer"}).status_code == 403
  37. rejected = client.post("/api/system/plugins/registry", json={"manifest": MANIFEST | {"url": "https://invalid"}, "registry_record": RECORD}, headers={"Authorization": "Bearer admin"})
  38. assert rejected.status_code == 400 and rejected.headers["Cache-Control"] == "no-store"
  39. accepted = client.post("/api/system/plugins/registry", json={"manifest": MANIFEST, "registry_record": RECORD}, headers={"Authorization": "Bearer admin"})
  40. assert accepted.status_code == 201 and accepted.headers["Cache-Control"] == "no-store"
  41. assert _Gateway.calls[0]["actor_ref"] == "01900000-0000-7000-8000-000000000013"