trusted_delivery_controls.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. """No-store HTTP boundary for trusted-delivery control and release gate summaries."""
  2. from flask import g, jsonify, request
  3. from sqlalchemy.exc import DBAPIError, IntegrityError
  4. from app import db
  5. from app.api.system import bp
  6. from app.core.system.permissions import (
  7. SECURITY_GOVERNANCE_MANAGE,
  8. SECURITY_GOVERNANCE_OPERATE,
  9. SECURITY_GOVERNANCE_READ,
  10. require_permissions,
  11. )
  12. from app.core.system.trusted_delivery_controls import TrustedDeliveryControlError
  13. from app.core.system.trusted_delivery_controls_repository import (
  14. SqlAlchemyTrustedDeliveryControlsRepository,
  15. )
  16. from app.core.system.trusted_delivery_controls_service import (
  17. TrustedDeliveryControlsService,
  18. )
  19. from app.models.result import failed, success
  20. MAX_TRUSTED_DELIVERY_CONTROL_REQUEST_BYTES = 16 * 1024
  21. def _service():
  22. return TrustedDeliveryControlsService(SqlAlchemyTrustedDeliveryControlsRepository(db.session))
  23. def _body(allowed):
  24. if request.content_length is not None and request.content_length > MAX_TRUSTED_DELIVERY_CONTROL_REQUEST_BYTES:
  25. raise TrustedDeliveryControlError("trusted delivery control request is too large")
  26. if len(request.get_data(cache=True)) > MAX_TRUSTED_DELIVERY_CONTROL_REQUEST_BYTES:
  27. raise TrustedDeliveryControlError("trusted delivery control request is too large")
  28. body = request.get_json(silent=True)
  29. if not isinstance(body, dict) or set(body) - allowed:
  30. raise TrustedDeliveryControlError("closed request schema")
  31. return body
  32. def _execute(operation, *, created=False):
  33. try:
  34. value = operation()
  35. # Do not acknowledge a durable control mutation before its commit has
  36. # succeeded. Failure takes the common rollback/redacted-error path.
  37. db.session.commit()
  38. response = jsonify(success(value, code=201 if created else 200))
  39. response.headers["Cache-Control"] = "no-store"
  40. return (response, 201) if created else response
  41. except PermissionError:
  42. db.session.rollback()
  43. response = jsonify(failed("trusted delivery control request denied", code=403))
  44. except (LookupError, RuntimeError, TrustedDeliveryControlError, ValueError, TypeError, IntegrityError, DBAPIError):
  45. db.session.rollback()
  46. response = jsonify(failed("trusted delivery control request rejected", code=400))
  47. response.headers["Cache-Control"] = "no-store"
  48. return response, response.get_json()["code"]
  49. @bp.get("/trusted-delivery/controls/profiles/<profile_id>/active")
  50. @require_permissions(SECURITY_GOVERNANCE_READ)
  51. def trusted_delivery_active_control_profile(profile_id):
  52. return _execute(lambda: _service().active_profile_summary(profile_id))
  53. @bp.post("/trusted-delivery/controls/release-gates/evaluate")
  54. @require_permissions(SECURITY_GOVERNANCE_OPERATE)
  55. def trusted_delivery_release_gate():
  56. return _execute(lambda: _service().evaluate_release_gate(_body({"artifact_digest", "sbom_digest", "license_policy_digest", "vulnerability_scan_digest", "approval_id", "approval_version", "scan_decision", "evidence_expires_at", "approval_ref", "approval_digest", "idempotency_key"}), actor_uid=g.current_user["id"]), created=True)
  57. @bp.post("/trusted-delivery/controls/profiles/activate")
  58. @require_permissions(SECURITY_GOVERNANCE_MANAGE)
  59. def trusted_delivery_activate_control_profile():
  60. return _execute(lambda: _service().activate_profile(_body({"profile_id", "version", "approval_ref", "approval_digest", "idempotency_key"}), actor_uid=g.current_user["id"]), created=True)
  61. @bp.post("/trusted-delivery/controls/profiles/rollback")
  62. @require_permissions(SECURITY_GOVERNANCE_MANAGE)
  63. def trusted_delivery_rollback_control_profile():
  64. return _execute(lambda: _service().activate_profile(_body({"profile_id", "version", "approval_ref", "approval_digest", "idempotency_key"}), actor_uid=g.current_user["id"], operation="rollback"))
  65. @bp.post("/trusted-delivery/controls/capability-approvals")
  66. @require_permissions(SECURITY_GOVERNANCE_MANAGE)
  67. def trusted_delivery_capability_approval():
  68. return _execute(lambda: _service().approve_capability(_body({"provider", "capability", "version", "config_digest", "approval_ref", "approval_digest", "idempotency_key"}), actor_uid=g.current_user["id"]), created=True)
  69. @bp.get("/trusted-delivery/controls/evidence")
  70. @require_permissions(SECURITY_GOVERNANCE_READ)
  71. def trusted_delivery_control_evidence():
  72. return _execute(lambda: _service().evidence_summary())
  73. @bp.post("/trusted-delivery/controls/destruction-approvals")
  74. @require_permissions(SECURITY_GOVERNANCE_MANAGE)
  75. def trusted_delivery_destruction_approval():
  76. return _execute(lambda: _service().approve_destruction(_body({"asset_uid", "approval_refs", "evidence_digest", "idempotency_key"}), actor_uid=g.current_user["id"]), created=True)