Fix tool output sharing when inputs come from public sources (#21802)

When a user's history is configured with private default permissions,
running a tool on a dataset imported from a public library would fail
with "Job attempted to create sharable output datasets in a storage
location with sharing disabled". This happened because output permissions
were derived solely from input datasets — public inputs produced outputs
with no DATASET_ACCESS restrictions, which conflicted with the private
object store.

The fix ensures that the history's default DATASET_ACCESS restrictions
are applied to tool outputs when the derived permissions from inputs lack
them. This respects the user's privacy intent (expressed via history
defaults) regardless of input origin.
This commit is contained in:
mvdbeek
2026-02-17 17:04:23 +01:00
parent 4e7b0cda56
commit 0673d1f91b
2 changed files with 11 additions and 8 deletions
+9 -1
View File
@@ -512,11 +512,19 @@ class DefaultToolAction(ToolAction):
if not completed_job:
# Determine output dataset permission/roles list
default_history_permissions = app.security_agent.history_get_default_permissions(history)
if all_permissions:
output_permissions = app.security_agent.guess_derived_permissions(all_permissions)
# Ensure history default access restrictions are applied even when
# inputs are less restrictive (e.g. public library datasets). The
# history defaults reflect the user's intent for output privacy.
# See https://github.com/galaxyproject/galaxy/issues/21802
access_action = app.security_agent.get_action("access")
if access_action in default_history_permissions and access_action not in output_permissions:
output_permissions[access_action] = default_history_permissions[access_action]
else:
# No valid inputs, we will use history defaults
output_permissions = app.security_agent.history_get_default_permissions(history)
output_permissions = default_history_permissions
# Add the dbkey to the incoming parameters
incoming["dbkey"] = input_dbkey
@@ -95,13 +95,11 @@ class TestToolOutputFromLibraryImportWithPrivateObjectStore(BaseObjectStoreInteg
), f"Library import should retain default store, got {copied_storage['object_store_id']}"
# Make the imported dataset public — simulating a dataset from a public
# data library where datasets are accessible to all users. This is the
# crux of the bug: the input's access permissions (public) propagate to
# tool outputs, which then conflict with the private object store.
# data library where datasets are accessible to all users.
response = self.dataset_populator.make_dataset_public_raw(history_id, copied_hda["id"])
api_asserts.assert_status_code_is_ok(response)
# Run a tool on the library-imported dataset — this is the scenario from the bug
# Run a tool on the library-imported dataset
run_response = self.dataset_populator.run_tool(
"cat1",
inputs={"input1": {"src": "hda", "id": copied_hda["id"]}},
@@ -110,9 +108,6 @@ class TestToolOutputFromLibraryImportWithPrivateObjectStore(BaseObjectStoreInteg
self.dataset_populator.wait_for_history(history_id)
job = run_response["jobs"][0]
job_details = self.dataset_populator.get_job_details(job["id"], full=True).json()
# This is the core assertion — the job should succeed, not fail with
# "Job attempted to create sharable output datasets in a storage location
# with sharing disabled"
assert job_details["state"] == "ok", (
f"Tool run on library-imported dataset failed with state '{job_details['state']}'. "
f"Expected outputs to respect history's private store preference regardless of input origin."