fix(files): align adaptive tasks with live access
This commit is contained in:
@@ -13,6 +13,7 @@ from govoplan_core.core.modules import (
|
||||
DocumentationTopic,
|
||||
)
|
||||
from govoplan_files.backend.storage.archives import ZIP_UPLOAD_MAX_FILES
|
||||
from govoplan_files.backend.storage.access import user_group_ids
|
||||
from govoplan_files.backend.storage.connector_visibility import (
|
||||
connector_profile_usable_for_import,
|
||||
visible_connector_profiles_for_actor,
|
||||
@@ -90,7 +91,7 @@ def _upload_topic(max_bytes: int) -> DocumentationTopic:
|
||||
"help_contexts": ["files.list"],
|
||||
"prerequisites": [
|
||||
"You may view and upload managed files.",
|
||||
"You can access the destination personal or group space.",
|
||||
"The destination personal or group space grants this account write access; upload permission alone does not grant access to every space.",
|
||||
],
|
||||
"steps": [
|
||||
"Open Files and choose My files or an accessible group space.",
|
||||
@@ -161,6 +162,7 @@ def _zip_topic(max_file_bytes: int, max_zip_bytes: int) -> DocumentationTopic:
|
||||
"prerequisites": [
|
||||
"You may view and upload managed files.",
|
||||
"The archive is not encrypted and fits the current configured limits.",
|
||||
"The destination personal or group space grants this account write access.",
|
||||
],
|
||||
"steps": [
|
||||
"Open Files and choose the managed destination space and folder.",
|
||||
@@ -215,19 +217,36 @@ def _connector_import_topic(context: DocumentationContext) -> DocumentationTopic
|
||||
)
|
||||
|
||||
try:
|
||||
group_ids = _principal_group_ids(principal)
|
||||
member_group_ids = _actor_group_ids(
|
||||
session,
|
||||
principal=principal,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
include_admin_groups=False,
|
||||
)
|
||||
connector_group_ids = (
|
||||
_actor_group_ids(
|
||||
session,
|
||||
principal=principal,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
include_admin_groups=True,
|
||||
)
|
||||
if _has_all_scopes(principal, ("files:file:admin",))
|
||||
else member_group_ids
|
||||
)
|
||||
profiles = visible_connector_profiles_for_actor(
|
||||
session,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
group_ids=group_ids,
|
||||
group_ids=connector_group_ids,
|
||||
settings=context.settings,
|
||||
campaign_visible=_campaign_visibility(
|
||||
context,
|
||||
session=session,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
group_ids=group_ids,
|
||||
group_ids=member_group_ids,
|
||||
),
|
||||
include_effective_policy=True,
|
||||
)
|
||||
@@ -286,6 +305,7 @@ def _connector_import_topic(context: DocumentationContext) -> DocumentationTopic
|
||||
"You may view and upload managed files.",
|
||||
"At least one enabled, credential-ready, policy-allowed connection using a pinning-safe provider is visible to this account.",
|
||||
"The selected remote path and item must pass their operation-time policy checks.",
|
||||
"The managed destination space grants this account write access.",
|
||||
],
|
||||
"steps": [
|
||||
"Open Files and choose a managed destination space.",
|
||||
@@ -382,6 +402,26 @@ def _principal_group_ids(principal: object) -> tuple[str, ...]:
|
||||
return tuple(str(value) for value in values if str(value))
|
||||
|
||||
|
||||
def _actor_group_ids(
|
||||
session: Session,
|
||||
*,
|
||||
principal: object,
|
||||
tenant_id: str,
|
||||
user_id: str,
|
||||
include_admin_groups: bool,
|
||||
) -> tuple[str, ...]:
|
||||
try:
|
||||
values = user_group_ids(
|
||||
session,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
include_admin_groups=include_admin_groups,
|
||||
)
|
||||
except Exception:
|
||||
return _principal_group_ids(principal)
|
||||
return tuple(str(value) for value in values if str(value))
|
||||
|
||||
|
||||
def _campaign_visibility(
|
||||
context: DocumentationContext,
|
||||
*,
|
||||
|
||||
@@ -226,7 +226,7 @@ manifest = ModuleManifest(
|
||||
"help_contexts": ["files.list"],
|
||||
"prerequisites": [
|
||||
"You may view and organize managed files.",
|
||||
"You can access every source and destination space used by the operation.",
|
||||
"You have write or owner access to every source item and destination space used by the operation; the global organize permission alone does not grant resource access.",
|
||||
],
|
||||
"steps": [
|
||||
"Open Files and select the personal or group space to organize.",
|
||||
@@ -317,7 +317,7 @@ manifest = ModuleManifest(
|
||||
"screen": "Files",
|
||||
"help_contexts": ["files.list"],
|
||||
"prerequisites": [
|
||||
"You may view and share the managed file.",
|
||||
"You may view and share the managed file and have write/manage access to that specific asset; the global share permission alone does not grant resource access.",
|
||||
"A supporting workflow or API client is available; the Files page has no general share editor yet.",
|
||||
"The process does not require share revocation, because no revocation route exists yet.",
|
||||
],
|
||||
@@ -368,7 +368,7 @@ manifest = ModuleManifest(
|
||||
"screen": "Files",
|
||||
"help_contexts": ["files.list"],
|
||||
"prerequisites": [
|
||||
"You may view and delete the selected managed content.",
|
||||
"You may view and delete the selected managed content and have write or owner access to every affected asset or folder.",
|
||||
"You have reviewed the complete folder tree when deleting recursively.",
|
||||
],
|
||||
"steps": [
|
||||
|
||||
@@ -160,6 +160,57 @@ class FilesRuntimeDocumentationTests(unittest.TestCase):
|
||||
):
|
||||
self.assertNotIn(secret, payload)
|
||||
|
||||
def test_files_admin_connector_groups_do_not_widen_campaign_membership(self) -> None:
|
||||
usable = ConnectorProfile(
|
||||
id="group-profile",
|
||||
label="Group profile",
|
||||
provider="webdav",
|
||||
scope_type="group",
|
||||
scope_id="admin-visible-group",
|
||||
endpoint_url="https://files.example.invalid",
|
||||
credential_mode="anonymous",
|
||||
)
|
||||
|
||||
def groups_for_actor(_session, *, include_admin_groups, **_kwargs):
|
||||
return ["member-group", "admin-visible-group"] if include_admin_groups else ["member-group"]
|
||||
|
||||
with (
|
||||
patch(
|
||||
"govoplan_files.backend.documentation.user_group_ids",
|
||||
side_effect=groups_for_actor,
|
||||
),
|
||||
patch(
|
||||
"govoplan_files.backend.documentation._campaign_visibility",
|
||||
return_value=None,
|
||||
) as campaign_visibility,
|
||||
patch(
|
||||
"govoplan_files.backend.documentation.visible_connector_profiles_for_actor",
|
||||
return_value=[usable],
|
||||
) as visible,
|
||||
):
|
||||
topics = {
|
||||
topic.id: topic
|
||||
for topic in documentation_topics(
|
||||
self.context(
|
||||
{
|
||||
"files:file:read",
|
||||
"files:file:upload",
|
||||
"files:file:admin",
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
self.assertIn("files.workflow.import-managed-snapshot", topics)
|
||||
self.assertEqual(
|
||||
("member-group", "admin-visible-group"),
|
||||
tuple(visible.call_args.kwargs["group_ids"]),
|
||||
)
|
||||
self.assertEqual(
|
||||
("member-group",),
|
||||
tuple(campaign_visibility.call_args.kwargs["group_ids"]),
|
||||
)
|
||||
|
||||
def test_connector_evaluation_errors_fail_closed_without_error_details(
|
||||
self,
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user