Block authoring apply on RBAC and privacy guards
This commit is contained in:
@@ -13,6 +13,8 @@ from one_c_normalizer import ConfigurationRoot, MetadataGroup, MetadataObject, M
|
||||
def create_authoring_session(client: TestClient, project_id: str, task_id: str, session_id: str, user_id: str = "dev.ivan") -> None:
|
||||
user = client.post("/collaboration/users", json={"user_id": user_id, "display_name": user_id})
|
||||
assert user.status_code == 200
|
||||
grant = client.post(f"/security/users/{user_id}/roles/developer")
|
||||
assert grant.status_code == 200
|
||||
task = client.post(
|
||||
"/collaboration/tasks",
|
||||
json={"task_id": task_id, "project_id": project_id, "title": f"Authoring {task_id}", "assignee_user_id": user_id},
|
||||
@@ -1999,6 +2001,7 @@ def test_authoring_context_and_completion_preview(tmp_path: Path):
|
||||
),
|
||||
"task_id": "task.authoring",
|
||||
"session_id": "session.authoring",
|
||||
"user_id": "dev.ivan",
|
||||
},
|
||||
)
|
||||
|
||||
@@ -2011,6 +2014,7 @@ def test_authoring_context_and_completion_preview(tmp_path: Path):
|
||||
assert diff_payload["version_preview"]["task_id"] == "task.authoring"
|
||||
assert diff_payload["version_preview"]["apply_available"] is False
|
||||
assert any(row["name"] == "task-session" and row["status"] == "OK" for row in diff_payload["checks"])
|
||||
assert any(row["name"] == "rbac" and row["status"] == "OK" for row in diff_payload["checks"])
|
||||
assert any(row["name"] == "apply" and row["status"] == "BLOCKED" for row in diff_payload["checks"])
|
||||
|
||||
apply_response = client.post(
|
||||
@@ -2025,6 +2029,7 @@ def test_authoring_context_and_completion_preview(tmp_path: Path):
|
||||
),
|
||||
"task_id": "task.authoring",
|
||||
"session_id": "session.authoring",
|
||||
"user_id": "dev.ivan",
|
||||
"expected_next_version_id": diff_payload["version_preview"]["next_version_id"],
|
||||
"approved_by": "dev.ivan",
|
||||
"approval_note": "preview checked",
|
||||
@@ -2150,6 +2155,129 @@ def test_authoring_apply_requires_active_task_session(tmp_path: Path):
|
||||
assert blocked[0]["name"] == "task-session"
|
||||
|
||||
|
||||
def test_authoring_apply_requires_rbac_permission(tmp_path: Path):
|
||||
project_id = f"authoring-rbac-{uuid4()}"
|
||||
module = tmp_path / "rbac_module.bsl"
|
||||
source_text = "Процедура Проверить()\nКонецПроцедуры\n"
|
||||
module.write_text(source_text, encoding="utf-8")
|
||||
client = TestClient(app)
|
||||
|
||||
indexed = client.post("/projects/index", json={"path": str(tmp_path), "project_id": project_id})
|
||||
assert indexed.status_code == 200
|
||||
user = client.post("/collaboration/users", json={"user_id": "viewer.ivan", "display_name": "Viewer"})
|
||||
assert user.status_code == 200
|
||||
grant = client.post("/security/users/viewer.ivan/roles/viewer")
|
||||
assert grant.status_code == 200
|
||||
task = client.post(
|
||||
"/collaboration/tasks",
|
||||
json={"task_id": "task.rbac", "project_id": project_id, "title": "RBAC authoring", "assignee_user_id": "viewer.ivan"},
|
||||
)
|
||||
assert task.status_code == 200
|
||||
session = client.post(
|
||||
"/collaboration/sessions",
|
||||
json={"session": {"session_id": "session.rbac", "task_id": "task.rbac", "user_id": "viewer.ivan"}},
|
||||
)
|
||||
assert session.status_code == 200
|
||||
|
||||
preview = client.post(
|
||||
f"/projects/{project_id}/authoring/semantic-diff-preview",
|
||||
json={
|
||||
"routine_name": "Проверить",
|
||||
"source_path": str(module),
|
||||
"original_text": source_text,
|
||||
"proposed_text": source_text.replace("КонецПроцедуры", " Возврат;\nКонецПроцедуры"),
|
||||
"task_id": "task.rbac",
|
||||
"session_id": "session.rbac",
|
||||
"user_id": "viewer.ivan",
|
||||
},
|
||||
)
|
||||
assert preview.status_code == 200
|
||||
preview_payload = preview.json()
|
||||
assert any(check["name"] == "rbac" and check["status"] == "BLOCKED" for check in preview_payload["checks"])
|
||||
|
||||
apply_response = client.post(
|
||||
f"/projects/{project_id}/authoring/apply-change-set",
|
||||
json={
|
||||
"routine_name": "Проверить",
|
||||
"source_path": str(module),
|
||||
"original_text": source_text,
|
||||
"proposed_text": source_text.replace("КонецПроцедуры", " Возврат;\nКонецПроцедуры"),
|
||||
"task_id": "task.rbac",
|
||||
"session_id": "session.rbac",
|
||||
"user_id": "viewer.ivan",
|
||||
"expected_next_version_id": preview_payload["version_preview"]["next_version_id"],
|
||||
"approved_by": "viewer.ivan",
|
||||
},
|
||||
)
|
||||
assert apply_response.status_code == 409
|
||||
assert any(check["name"] == "rbac" for check in apply_response.json()["detail"]["blocked_checks"])
|
||||
|
||||
|
||||
def test_authoring_apply_blocks_sensitive_privacy_context(tmp_path: Path):
|
||||
project_id = f"authoring-privacy-{uuid4()}"
|
||||
(tmp_path / "metadata.xml").write_text(
|
||||
"""
|
||||
<Configuration>
|
||||
<Document name="ЗаказПокупателя" qualifiedName="Документ.ЗаказПокупателя">
|
||||
<Attribute name="Телефон" qualifiedName="Документ.ЗаказПокупателя.Телефон" />
|
||||
</Document>
|
||||
</Configuration>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
module = tmp_path / "Documents" / "ЗаказПокупателя" / "Ext" / "ObjectModule.bsl"
|
||||
module.parent.mkdir(parents=True)
|
||||
source_text = "Процедура Проверить()\n Сообщить(Телефон);\nКонецПроцедуры\n"
|
||||
module.write_text(source_text, encoding="utf-8")
|
||||
client = TestClient(app)
|
||||
|
||||
indexed = client.post("/projects/index", json={"path": str(tmp_path), "project_id": project_id})
|
||||
assert indexed.status_code == 200
|
||||
create_authoring_session(client, project_id, "task.privacy", "session.privacy")
|
||||
schema = client.get(f"/projects/{project_id}/objects/schema/Документ.ЗаказПокупателя")
|
||||
phone_lineage = schema.json()["attributes"][0]["lineage_id"]
|
||||
marker = client.post(
|
||||
f"/projects/{project_id}/privacy/markers",
|
||||
json={"target_id": phone_lineage, "classification": "PERSONAL_DATA", "reason": "phone number"},
|
||||
)
|
||||
assert marker.status_code == 200
|
||||
|
||||
preview = client.post(
|
||||
f"/projects/{project_id}/authoring/semantic-diff-preview",
|
||||
json={
|
||||
"object_name": "Документ.ЗаказПокупателя",
|
||||
"routine_name": "Проверить",
|
||||
"source_path": str(module),
|
||||
"original_text": source_text,
|
||||
"proposed_text": source_text.replace("Сообщить(Телефон);", "Сообщить(Телефон);\n Возврат;"),
|
||||
"task_id": "task.privacy",
|
||||
"session_id": "session.privacy",
|
||||
"user_id": "dev.ivan",
|
||||
},
|
||||
)
|
||||
assert preview.status_code == 200
|
||||
preview_payload = preview.json()
|
||||
assert any(check["name"] == "privacy" and check["status"] == "BLOCKED" for check in preview_payload["checks"])
|
||||
|
||||
apply_response = client.post(
|
||||
f"/projects/{project_id}/authoring/apply-change-set",
|
||||
json={
|
||||
"object_name": "Документ.ЗаказПокупателя",
|
||||
"routine_name": "Проверить",
|
||||
"source_path": str(module),
|
||||
"original_text": source_text,
|
||||
"proposed_text": source_text.replace("Сообщить(Телефон);", "Сообщить(Телефон);\n Возврат;"),
|
||||
"task_id": "task.privacy",
|
||||
"session_id": "session.privacy",
|
||||
"user_id": "dev.ivan",
|
||||
"expected_next_version_id": preview_payload["version_preview"]["next_version_id"],
|
||||
"approved_by": "dev.ivan",
|
||||
},
|
||||
)
|
||||
assert apply_response.status_code == 409
|
||||
assert any(check["name"] == "privacy" for check in apply_response.json()["detail"]["blocked_checks"])
|
||||
|
||||
|
||||
def test_authoring_metadata_object_preview_and_apply(tmp_path: Path):
|
||||
project_id = f"metadata-authoring-api-{uuid4()}"
|
||||
(tmp_path / "metadata.xml").write_text(
|
||||
@@ -2187,6 +2315,7 @@ def test_authoring_metadata_object_preview_and_apply(tmp_path: Path):
|
||||
"commands": [{"name": "Заполнить", "handler": "ЗаполнитьКоманда"}],
|
||||
"task_id": "task.metadata",
|
||||
"session_id": "session.metadata",
|
||||
"user_id": "dev.ivan",
|
||||
}
|
||||
|
||||
preview = client.post(f"/projects/{project_id}/authoring/metadata-object-preview", json=draft)
|
||||
@@ -2196,6 +2325,7 @@ def test_authoring_metadata_object_preview_and_apply(tmp_path: Path):
|
||||
assert preview_payload["changed"] is True
|
||||
assert preview_payload["version_preview"]["apply_available"] is True
|
||||
assert any(check["name"] == "task-session" and check["status"] == "OK" for check in preview_payload["checks"])
|
||||
assert any(check["name"] == "rbac" and check["status"] == "OK" for check in preview_payload["checks"])
|
||||
assert any("Реквизит.Контрагент" in row["text"] for row in preview_payload["semantic_diff"])
|
||||
assert any("ТабличнаяЧасть.Товары" in row["text"] for row in preview_payload["semantic_diff"])
|
||||
assert any("Команда.Заполнить" in row["text"] for row in preview_payload["semantic_diff"])
|
||||
|
||||
Reference in New Issue
Block a user