Skip to content

Commit

Permalink
Merge pull request #17000 from mvdbeek/dev
Browse files Browse the repository at this point in the history
Merge 23.1 into dev
  • Loading branch information
dannon authored Nov 9, 2023
2 parents ff45b63 + 8d80308 commit a1b5485
Show file tree
Hide file tree
Showing 12 changed files with 76 additions and 39 deletions.
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galaxyproject/galaxy-client",
"version": "23.0.0",
"version": "23.1.1",
"description": "Galaxy client application build system",
"keywords": [
"galaxy"
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/User/UserPreferences.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
description="Add or modify the configuration that grants Galaxy to access your cloud-based resources."
to="/user/cloud_auth" />
<UserPreferencesElement
v-if="isConfigLoaded && config.enable_oidc"
v-if="isConfigLoaded && config.enable_oidc && !config.fixed_delegated_auth"
id="manage-third-party-identities"
icon="fa-id-card-o"
title="Manage Third-Party Identities"
Expand Down
2 changes: 1 addition & 1 deletion client/src/entry/analysis/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ export function getRouter(Galaxy) {
{
path: "user/external_ids",
component: ExternalIdentities,
redirect: redirectAnon(),
redirect: redirectIf(Galaxy.config.fixed_delegated_auth, "/") || redirectAnon(),
},
{
path: "user/notifications",
Expand Down
7 changes: 7 additions & 0 deletions lib/galaxy/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,13 @@ def __init__(self, **kwargs) -> None:
self, self.config.oidc_config_file, self.config.oidc_backends_config_file
)

# If there is only a single external authentication provider in use
# TODO: Future work will expand on this and provide an interface for
# multiple auth providers allowing explicit authenticated association.
self.config.fixed_delegated_auth = (
len(list(self.config.oidc)) == 1 and len(list(self.auth_manager.authenticators)) == 0
)

if not self.config.enable_celery_tasks and self.config.history_audit_table_prune_interval > 0:
self.prune_history_audit_task = IntervalTask(
func=lambda: galaxy.model.HistoryAudit.prune(self.model.session),
Expand Down
16 changes: 4 additions & 12 deletions lib/galaxy/authnz/custos_authnz.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,17 +218,7 @@ def callback(self, state_token, authz_code, trans, login_redirect_url):
existing_user = trans.sa_session.query(User).filter_by(email=email).first()
if not user:
if existing_user:
# If there is only a single external authentication
# provider in use, trust the user provided and
# automatically associate.
# TODO: Future work will expand on this and provide an
# interface for when there are multiple auth providers
# allowing explicit authenticated association.
if (
trans.app.config.enable_oidc
and len(trans.app.config.oidc) == 1
and len(trans.app.auth_manager.authenticators) == 0
):
if trans.app.config.fixed_delegated_auth:
user = existing_user
else:
message = f"There already exists a user with email {email}. To associate this external login, you must first be logged in as that existing account."
Expand Down Expand Up @@ -260,7 +250,9 @@ def callback(self, state_token, authz_code, trans, login_redirect_url):
refresh_expiration_time=refresh_expiration_time,
)
label = self.config.label
if existing_user and existing_user != user:
if trans.app.config.fixed_delegated_auth:
redirect_url = login_redirect_url
elif existing_user and existing_user != user:
redirect_url = (
f"{login_redirect_url}user/external_ids"
f"?email_exists={email}"
Expand Down
1 change: 1 addition & 0 deletions lib/galaxy/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,7 @@ def _process_config(self, kwargs: Dict[str, Any]) -> None:
self.builds_file_path = os.path.join(self.tool_data_path, self.builds_file_path)
self.len_file_path = os.path.join(self.tool_data_path, self.len_file_path)
self.oidc: Dict[str, Dict] = {}
self.fixed_delegated_auth: bool = False
self.integrated_tool_panel_config = self._in_managed_config_dir(self.integrated_tool_panel_config)
integrated_tool_panel_tracking_directory = kwargs.get("integrated_tool_panel_tracking_directory")
if integrated_tool_panel_tracking_directory:
Expand Down
65 changes: 47 additions & 18 deletions lib/galaxy/job_execution/setup.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"""Utilities to help job and tool code setup jobs."""
import json
import os
import threading
from typing import (
Any,
cast,
Dict,
List,
NamedTuple,
Optional,
Tuple,
Union,
Expand Down Expand Up @@ -38,6 +40,27 @@
OutputPaths = List[DatasetPath]


class JobOutput(NamedTuple):
output_name: str
dataset: DatasetInstance
dataset_path: DatasetPath


class JobOutputs(threading.local):
def __init__(self) -> None:
super().__init__()
self.output_hdas_and_paths: Optional[OutputHdasAndType] = None
self.output_paths: Optional[OutputPaths] = None

@property
def populated(self) -> bool:
return self.output_hdas_and_paths is not None

def set_job_outputs(self, job_outputs: List[JobOutput]) -> None:
self.output_paths = [t[2] for t in job_outputs]
self.output_hdas_and_paths = {t.output_name: (t.dataset, t.dataset_path) for t in job_outputs}


class JobIO(Dictifiable):
dict_collection_visible_keys = (
"job_id",
Expand Down Expand Up @@ -99,7 +122,6 @@ def __init__(
user_context_instance = user_context
self.user_context = user_context_instance
self.sa_session = sa_session
self.job = job
self.job_id = job.id
self.working_directory = working_directory
self.outputs_directory = outputs_directory
Expand All @@ -121,25 +143,33 @@ def __init__(
self.is_task = is_task
self.tool_source = tool_source
self.tool_source_class = tool_source_class
self._output_paths: Optional[OutputPaths] = None
self._output_hdas_and_paths: Optional[OutputHdasAndType] = None
self.job_outputs = JobOutputs()
self._dataset_path_rewriter: Optional[DatasetPathRewriter] = None

@property
def job(self):
return self.sa_session.get(Job, self.job_id)

@classmethod
def from_json(cls, path, sa_session):
with open(path) as job_io_serialized:
io_dict = json.load(job_io_serialized)
return cls.from_dict(io_dict=io_dict, sa_session=sa_session)

@classmethod
def from_dict(cls, io_dict, sa_session):
io_dict.pop("model_class")
# Drop in 24.0
io_dict.pop("model_class", None)
job_id = io_dict.pop("job_id")
job = sa_session.query(Job).get(job_id)
return cls(sa_session=sa_session, job=job, **io_dict)

@classmethod
def from_dict(cls, io_dict, sa_session):
# Drop in 24.0
io_dict.pop("model_class", None)
return cls(sa_session=sa_session, **io_dict)

def to_dict(self):
io_dict = super().to_dict()
# dict_for will always add `model_class`, we don't need or want it
io_dict.pop("model_class")
io_dict["user_context"] = self.user_context.to_dict()
return io_dict

Expand All @@ -165,15 +195,15 @@ def dataset_path_rewriter(self) -> DatasetPathRewriter:

@property
def output_paths(self) -> OutputPaths:
if self._output_paths is None:
if not self.job_outputs.populated:
self.compute_outputs()
return cast(OutputPaths, self._output_paths)
return cast(OutputPaths, self.job_outputs.output_paths)

@property
def output_hdas_and_paths(self) -> OutputHdasAndType:
if self._output_hdas_and_paths is None:
if not self.job_outputs.populated:
self.compute_outputs()
return cast(OutputHdasAndType, self._output_hdas_and_paths)
return cast(OutputHdasAndType, self.job_outputs.output_hdas_and_paths)

def get_input_dataset_fnames(self, ds: DatasetInstance) -> List[str]:
filenames = [ds.get_file_name()]
Expand Down Expand Up @@ -241,22 +271,21 @@ def compute_outputs(self) -> None:
special = self.sa_session.query(JobExportHistoryArchive).filter_by(job=job).first()
false_path = None

results = []
job_outputs = []
for da in job.output_datasets + job.output_library_datasets:
da_false_path = dataset_path_rewriter.rewrite_dataset_path(da.dataset, "output")
mutable = da.dataset.dataset.external_filename is None
dataset_path = DatasetPath(
da.dataset.dataset.id, da.dataset.get_file_name(), false_path=da_false_path, mutable=mutable
)
results.append((da.name, da.dataset, dataset_path))
job_outputs.append(JobOutput(da.name, da.dataset, dataset_path))

self._output_paths = [t[2] for t in results]
self._output_hdas_and_paths = {t[0]: t[1:] for t in results}
if special:
false_path = dataset_path_rewriter.rewrite_dataset_path(special, "output")
dsp = DatasetPath(special.dataset.id, special.dataset.get_file_name(), false_path)
self._output_paths.append(dsp)
self._output_hdas_and_paths["output_file"] = (special.fda, dsp)
job_outputs.append(JobOutput("output_file", special.fda, dsp))

self.job_outputs.set_job_outputs(job_outputs)

def get_output_file_id(self, file: str) -> Optional[int]:
for dp in self.output_paths:
Expand Down
1 change: 1 addition & 0 deletions lib/galaxy/managers/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ def _config_is_truthy(item, key, **context):
"instance_access_url": _use_config,
"organization_name": _use_config,
"organization_url": _use_config,
"fixed_delegated_auth": _defaults_to(False),
}


Expand Down
5 changes: 3 additions & 2 deletions lib/galaxy/tool_util/xsd/galaxy.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -1719,7 +1719,7 @@ it may be inconvenient to upload the entiry file and this can be used instead.
<xs:documentation xml:lang="en"><![CDATA[
If this attribute is true then try to decompress files if needed. This applies to
test assertions expressed with ``assert_contents`` or ``compare`` set to anything
but ``sim_size``.
but ``sim_size``.
This flag is useful for testing compressed outputs that are non-deterministic
despite having deterministic decompressed contents. By default, only files compressed
with bz2, gzip and zip will be automatically decompressed.
Expand Down Expand Up @@ -7389,7 +7389,7 @@ information according to a catalog.</xs:documentation>
<xs:extension base="xs:string">
<xs:attribute name="type" type="xrefType" use="required">
<xs:annotation>
<xs:documentation xml:lang="en">Type of reference - currently ``bio.tools`` and ``bioconductor`` are
<xs:documentation xml:lang="en">Type of reference - currently ``bio.tools``, ``bioconductor``, and ``biii`` are
the only supported options.</xs:documentation>
</xs:annotation>
</xs:attribute>
Expand All @@ -7403,6 +7403,7 @@ the only supported options.</xs:documentation>
<xs:restriction base="xs:string">
<xs:enumeration value="bio.tools"/>
<xs:enumeration value="bioconductor"/>
<xs:enumeration value="biii"/>
<!--xs:enumeration value="whatelse"/-->
</xs:restriction>
</xs:simpleType>
Expand Down
6 changes: 6 additions & 0 deletions lib/galaxy/web/framework/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ def handle_request(self, request_id, path_info, environ, start_response, body_re
rc = routes.request_config()
rc.mapper = self.mapper
rc.mapper_dict = map_match
server_port = environ["SERVER_PORT"]
if isinstance(server_port, int):
# Workaround bug in the routes package, which would concatenate this
# without casting to str in
# https://github.com/bbangert/routes/blob/c4d5a5fb693ce8dc7cf5dbc591861acfc49d5c23/routes/__init__.py#L73
environ["SERVER_PORT"] = str(server_port)
rc.environ = environ
# Setup the transaction
trans = self.transaction_factory(environ)
Expand Down
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@galaxyproject/galaxy",
"version": "1.0.0",
"version": "23.1.0",
"description": ".. figure:: https://galaxyproject.org/images/galaxy-logos/galaxy_project_logo.jpg :alt: Galaxy Logo",
"main": "index.js",
"devDependencies": {},
Expand All @@ -18,8 +18,7 @@
},
"homepage": "https://github.com/galaxyproject/galaxy#readme",
"dependencies": {
"@galaxyproject/galaxy-client": "^23.0.0",
"cpy-cli": "^4.2.0",
"vuedraggable": "^2.24.3"
"@galaxyproject/galaxy-client": "^23.1.1",
"cpy-cli": "^5.0.0"
}
}
1 change: 1 addition & 0 deletions test/unit/app/authnz/test_custos_authnz.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def setupMocks(self):
self.trans.app.config.enable_oidc = True
self.trans.app.config.oidc = []
self.trans.app.auth_manager.authenticators = []
self.trans.app.config.fixed_delegated_auth = False

@property
def test_id_token(self):
Expand Down

0 comments on commit a1b5485

Please sign in to comment.