Block authoring apply on RBAC and privacy guards
This commit is contained in:
@@ -3242,11 +3242,7 @@ def _authoring_guard_checks(
|
||||
status="WARNING" if context.review_findings else "OK",
|
||||
message=f"{len(context.review_findings)} review findings in context",
|
||||
),
|
||||
AuthoringGuardCheck(
|
||||
name="privacy",
|
||||
status="WARNING" if context.privacy_markers else "OK",
|
||||
message=f"{len(context.privacy_markers)} privacy markers in context",
|
||||
),
|
||||
_authoring_privacy_check(context),
|
||||
AuthoringGuardCheck(
|
||||
name="ai-token-budget",
|
||||
status=token_status,
|
||||
@@ -3264,6 +3260,7 @@ def _authoring_task_session_check(
|
||||
project_id: str,
|
||||
task_id: str | None,
|
||||
session_id: str | None,
|
||||
user_id: str | None = None,
|
||||
) -> AuthoringGuardCheck:
|
||||
if not task_id:
|
||||
return AuthoringGuardCheck(
|
||||
@@ -3315,6 +3312,12 @@ def _authoring_task_session_check(
|
||||
status="BLOCKED",
|
||||
message=f"Session {session_id} is already finished",
|
||||
)
|
||||
if user_id and session.user_id != user_id:
|
||||
return AuthoringGuardCheck(
|
||||
name="task-session",
|
||||
status="BLOCKED",
|
||||
message=f"Session {session_id} belongs to user {session.user_id}",
|
||||
)
|
||||
return AuthoringGuardCheck(
|
||||
name="task-session",
|
||||
status="OK",
|
||||
@@ -3322,6 +3325,47 @@ def _authoring_task_session_check(
|
||||
)
|
||||
|
||||
|
||||
def _authoring_rbac_check(user_id: str | None) -> AuthoringGuardCheck:
|
||||
if not user_id:
|
||||
return AuthoringGuardCheck(
|
||||
name="rbac",
|
||||
status="BLOCKED",
|
||||
message="User id is required for workspace apply",
|
||||
)
|
||||
if not _rbac.is_allowed(user_id, Permission.APPLY_AUTHORING_CHANGE):
|
||||
return AuthoringGuardCheck(
|
||||
name="rbac",
|
||||
status="BLOCKED",
|
||||
message=f"User {user_id} is not allowed to apply authoring changes",
|
||||
)
|
||||
return AuthoringGuardCheck(
|
||||
name="rbac",
|
||||
status="OK",
|
||||
message=f"User {user_id} can apply authoring changes",
|
||||
)
|
||||
|
||||
|
||||
def _authoring_privacy_check(context: AuthoringContextResponse) -> AuthoringGuardCheck:
|
||||
blocked_markers = [
|
||||
marker
|
||||
for marker in context.privacy_markers
|
||||
if marker.classification in {PrivacyClassification.PERSONAL_DATA, PrivacyClassification.SECRET}
|
||||
]
|
||||
if blocked_markers:
|
||||
return AuthoringGuardCheck(
|
||||
name="privacy",
|
||||
status="BLOCKED",
|
||||
message=f"{len(blocked_markers)} sensitive privacy markers require explicit local-only handling before apply",
|
||||
)
|
||||
if context.privacy_markers:
|
||||
return AuthoringGuardCheck(
|
||||
name="privacy",
|
||||
status="WARNING",
|
||||
message=f"{len(context.privacy_markers)} privacy markers in context",
|
||||
)
|
||||
return AuthoringGuardCheck(name="privacy", status="OK", message="No privacy markers in context")
|
||||
|
||||
|
||||
def _authoring_target_node(snapshot: SirSnapshot, request: AuthoringSemanticDiffPreviewRequest):
|
||||
if request.target_lineage_id:
|
||||
found = next((node for node in snapshot.nodes if node.lineage_id == request.target_lineage_id), None)
|
||||
@@ -3455,7 +3499,8 @@ def _authoring_semantic_diff_preview(
|
||||
user_id=request.user_id,
|
||||
),
|
||||
)
|
||||
checks.append(_authoring_task_session_check(project_id, request.task_id, request.session_id))
|
||||
checks.append(_authoring_task_session_check(project_id, request.task_id, request.session_id, request.user_id))
|
||||
checks.append(_authoring_rbac_check(request.user_id))
|
||||
version_preview = _authoring_version_preview(target, request.proposed_text, request.task_id, request.session_id)
|
||||
return AuthoringSemanticDiffPreviewResponse(
|
||||
project_id=project_id,
|
||||
@@ -5282,7 +5327,8 @@ def _authoring_metadata_object_preview(
|
||||
AuthoringGuardCheck(name="preview", status="REQUIRED", message="Metadata draft must be reviewed before apply"),
|
||||
AuthoringGuardCheck(name="workspace-history", status="READY", message="Draft can be saved to SFERA workspace history"),
|
||||
AuthoringGuardCheck(name="production-1c", status="BLOCKED", message="Production 1C metadata write is disabled"),
|
||||
_authoring_task_session_check(project_id, request.task_id, request.session_id),
|
||||
_authoring_task_session_check(project_id, request.task_id, request.session_id, request.user_id),
|
||||
_authoring_rbac_check(request.user_id),
|
||||
]
|
||||
return AuthoringMetadataObjectPreviewResponse(
|
||||
project_id=project_id,
|
||||
@@ -5818,9 +5864,13 @@ async def authoring_apply_rollback(
|
||||
raise HTTPException(status_code=409, detail="Expected rollback version id does not match current preview")
|
||||
if not preview.apply_available:
|
||||
raise HTTPException(status_code=409, detail="Rollback apply is not available")
|
||||
task_session_check = _authoring_task_session_check(project_id, request.task_id, request.session_id)
|
||||
if task_session_check.status == "BLOCKED":
|
||||
raise HTTPException(status_code=409, detail={"blocked_checks": [task_session_check.model_dump(mode="json")]})
|
||||
apply_checks = [
|
||||
_authoring_task_session_check(project_id, request.task_id, request.session_id),
|
||||
_authoring_rbac_check(request.approved_by),
|
||||
]
|
||||
blocking_checks = [check for check in apply_checks if check.status == "BLOCKED"]
|
||||
if blocking_checks:
|
||||
raise HTTPException(status_code=409, detail={"blocked_checks": [check.model_dump(mode="json") for check in blocking_checks]})
|
||||
version, path = _persist_authoring_rollback(project_id, change_payload, preview, request)
|
||||
return AuthoringApplyRollbackResponse(
|
||||
project_id=project_id,
|
||||
|
||||
Reference in New Issue
Block a user