Ownership-only check rejected published/shared workflows that a normal
invocation would accept. Defer to get_stored_accessible_workflow, update
docs, add API tests for published + inaccessible cases.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Client walkthrough (curl) of submit/monitor over WES v1.0.0: state mapping,
gxworkflow:// scheme, engine params, tasks, pagination, errors, limitations.
Cross-link admin <-> dev docs; point at gxy-wes / gxy-wes-bioblend examples.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`TagHandler._create_tag_instance` created the `Tag` in a *separate* session
and committed it, to keep a unique-name `IntegrityError` from aborting the
caller's transaction. When this runs inside an open write transaction - e.g.
applying a tag to an output during workflow job creation - that second
connection's commit deadlocks against the first on SQLite's single-writer
lock, surfacing intermittently as "(sqlite3.OperationalError) database is
locked" and failing the job (and the workflow invocation). It is timing
sensitive, so any small latency in the surrounding code makes it reproducible.
Insert the tag on the session's own connection with
`INSERT ... ON CONFLICT (name) DO NOTHING` (SQLite and PostgreSQL both support
it natively), preserving the duplicate-name isolation without a second
connection. Other backends keep the separate-session fallback - the
single-writer deadlock is SQLite-specific.
When a [project] table is present in pyproject.toml, setuptools
ignores fields in setup.cfg unless they are listed in the dynamic
array. This applies to classifiers and keywords: the build was
silently dropping them from the wheel metadata.
Fix: define classifiers and keywords as static values directly in the
[project] section of each package's pyproject.toml, and remove them from
setup.cfg.
Alternate fix: add both to the dynamic list, keeping the definitions in
setup.cfg. However, I think the first is better since that keeps
pyproject.toml as the single source of truth.
When [project] is defined in pyproject.toml, setuptools does not include
[options.entry_points] from setup.cfg in the built wheel.
Solution: move console script definitions to [project.scripts] in
pyproject.toml for all affected packages.
#22617 routed every non-dict/non-instance value in a multiple data
parameter's value list through `_decode_dataset_id`, which raises
`ParameterValueError("invalid dataset id None")` for anything that isn't
an int/digit/16-char id. An unset optional data input connected to a
`multiple="true"` data parameter arrives as a null list element
(`[None]`), so the job failed at preparation with "invalid dataset id
None" instead of running. Before #22617 this path did
`query(HistoryDatasetAssociation).get(None)` -> `None`, so the null was
tolerated and the tool saw no dataset.
Filter `None`/`"None"`/`""` list elements in `DataToolParameter.from_json`
(matching the existing `to_python` behaviour) so null is tolerated as
"no dataset" while genuinely malformed ids are still rejected. This
restores correct execution of workflows that leave an optional data
input unset (the UI submits explicit null for such inputs).
When an optional parameter_input is omitted from a workflow invocation and
connected to a tool parameter nested inside a conditional/repeat/section, the
unresolved ConnectedValue sentinel leaked into the templated command line, e.g.
`-adapter_sequence '<galaxy.tools.parameters.workflow_utils.ConnectedValue
object at 0x...>'`.
visit_input_values forwards a `payload` dict to its recursive calls for grouped
inputs, but that payload omitted `replace_optional_connections`, so nested
params fell back to the default `False` and the sentinel-replacement branch in
callback_helper never ran for them. Propagate the flag through recursion so
nested optional connections are resolved to the tool parameter's own default,
preserving the not-provided/explicit-null distinction (top-level data params
still receive None as before).
Add a framework workflow regression test that connects an omitted optional
text parameter_input to a text param inside a conditional (boolean_conditional)
and asserts the tool's own default is used with no ConnectedValue leak.
Fix:
```
/home/runner/work/galaxy/galaxy/client/src/entry/analysis/modules/Home.vue
Warning: 1:1 warning Component name "Home" should always be multi-word vue/multi-word-component-names
Error: 48:5 error The "computed" property should be above the "mounted" property on line 35 vue/order-in-components
```
Broken in https://github.com/galaxyproject/galaxy/pull/22720 .
We just needed to update the `isDragging` variable when the `DraggableSeparator` is being dragged. This ensures the `interaction-overlay` is in sync with the dragging operation.
Fixes https://github.com/galaxyproject/galaxy/issues/20349
Updates the pinned FastAPI/Starlette versions on release_25.1 to match
upstream/dev, closing CVE-2026-48710 ("BadHost"). The vulnerability lets
an attacker inject a path into the HTTP Host header and have
``request.url.path`` reflect that path, bypassing path-based access
control in middleware. Starlette 1.0.1+ rejects Host headers with
invalid characters; we pin starlette==1.1.0 to match dev.
Drops Python 3.9 support, matching upstream/dev (commit eb9fde1dcd).
Starlette dropped 3.9 in 0.50.0, so the BadHost fix (starlette >= 1.0.1)
cannot be installed on 3.9. Bumping the floor to 3.10 is the only way
to ship the security fix; the alternative -- marker-splitting the pins
to keep 3.9 on starlette 0.49.x -- would leave 3.9 users exposed to the
CVE we are trying to close.
Actual exposure on release_25.1 (pre-fix)
-----------------------------------------
Galaxy was running a vulnerable starlette but is **not exploitable for
the headline auth-bypass scenario**. Auth runs through FastAPI
dependencies (``get_user``, ``get_trans``, ``AdminUserRequired``), not
through path-string checks in middleware. ``AccessLoggingMiddleware``
already uses ``scope["path"]``; ``add_galaxy_middleware`` /
``GalaxyCORSMiddleware`` / ``RawContextMiddleware`` /
``SentryAsgiMiddleware`` do not branch on ``request.url.path``.
Lower-severity findings that this upgrade also closes:
- ``lib/galaxy/webapps/base/api.py`` ``get_error_response_for_request``
picks an error schema with ``"ga4gh"/"drs"/"trs" in
request.url.path`` -- spoofable Host nudges error payload shape
(info-disclosure / shape confusion only).
- ``lib/galaxy/webapps/galaxy/api/drs.py`` and
``lib/galaxy/webapps/galaxy/services/datasets.py`` derive DRS
``service_info`` / ``self_uri`` from ``request.url`` -- spoofable
Host poisons the advertised DRS identity and client-visible URIs,
not access.
- ``lib/tool_shed/webapp/api2/tools.py`` -- same shape, TRS service
info.
Bumping the pin closes the parser flaw at source and downgrades all of
the above to non-issues, so no separate ``request.url.path ->
scope["path"]`` sweep is needed.
Pin bumps (cherry-picks the relevant ranges from PRs #21526, #22206,
#22754):
- fastapi 0.118.0 -> 0.136.3
- starlette 0.48.0 -> 1.1.0
- starlette-context 0.4.0 -> 0.5.1
- python-multipart 0.0.20 -> 0.0.29
- anyio 4.11.0 -> 4.13.0
Required code changes backported from upstream/dev:
- ``lib/galaxy/webapps/openapi/_compat/v2.py``: import
``GenerateJsonSchema`` and ``get_flat_models_from_fields`` from
``fastapi._compat.v2`` and adopt the new ``get_definitions()``
implementation for FastAPI 0.128.8+ (PRs #21384, dev commits
0800c025ce, c8ccc7f44d, b3bfb45884).
- ``lib/galaxy/webapps/openapi/utils.py``: route ``GenerateJsonSchema``
through ``_compat.v2`` and drop the now-unreachable
``get_compat_model_name_map`` fallback (dev commit b3bfb45884).
- ``lib/galaxy/schema/generics.py``: drop ``CustomJsonSchema`` here
(moved to fast_app.py so it can use the patched ``GenerateJsonSchema``
from ``_compat.v2``).
- ``lib/galaxy/webapps/galaxy/fast_app.py``: relocate
``CustomJsonSchema`` and switch its base to the ``_compat.v2``
``GenerateJsonSchema``; replace the @app.middleware("http") X-Frame
Options handler with a pure ASGI ``XFrameOptionsMiddleware`` class
(dev commit 67eea395ab) since ``BaseHTTPMiddleware`` semantics
changed in starlette 1.0.
- ``lib/galaxy/webapps/base/api.py`` and
``lib/galaxy/webapps/galaxy/api/datasets.py``: drop the ``method``
argument of ``FileResponse`` which starlette 1.0 removed (dev commit
63954cb42e).
Also bumps the minimum FastAPI requirement to ``>=0.133.0`` (first
version compatible with starlette>=1.0.0) and adds an explicit
``starlette>=1.0.1`` floor in ``pyproject.toml`` and the
``packages/web_apps`` / ``packages/tool_shed`` setup.cfg files so
source installs cannot resolve to a vulnerable combo.
Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com>
``Repeat.get_initial_value`` passed the parent ``context`` directly to
each child input's ``get_initial_value``, so siblings within a repeat
instance were invisible to each other's ``dynamic_options`` lookups.
``Section`` and ``Conditional`` already wrap their partial ``rval`` in
a child ``ExpressionContext`` for this reason — bring ``Repeat`` in
line.
Surfaced by ``data_manager_manual`` (``min=1`` on both the outer
``data_tables`` repeat and the inner ``columns`` repeat). The inner
``data_table_column_name`` select declares::
dynamic_options="galaxy_code_get_available_data_table_columns(
__trans__, data_table_name)"
During the initial ``populate_state`` pass ``Repeat.get_initial_value``
built the default ``data_tables`` instance with the outer
``rval_dict`` only visible as a local variable; the recursive
``columns.get_initial_value`` call therefore saw a context that did
not contain ``data_table_name`` and the eval raised::
NameError: name 'data_table_name' is not defined
The error is caught at ``basic.py`` (logged at DEBUG, options returned
as ``[]``) and the default instance is later discarded by
``_populate_state_legacy`` which rebuilds the state with a proper
child context — so the tool ran fine, but every form build polluted
the log.
When a user already has a ``data_manager_json`` bundle in their history
for a given tool data table, ``DynamicOptions.get_user_options`` builds
a synthetic options row from that bundle.
A 2025-02-18 refactor (172ef05f26, "Skip bundles that don't match data
table definition") moved ``field_entry.append(hda)`` from the end of the
row-building loop to the beginning. That shifted every declared column
index by one and put the HDA at position 0. ``get_options`` then reads
``fields[self.columns[<col>]]`` to find the option's name / value and
expects the HDA at ``fields[-1]`` — so it ends up wiring the raw HDA
into the option's ``value`` field. The unserialized HDA then crashed
``/api/tools/{id}/build`` for the data manager's own form with:
TypeError: Object of type HistoryDatasetAssociation is not JSON serializable
Move the HDA append back after the column loop where get_options
expects it.
Regression covered by a new API test in a ``require_admin_user=True``
test class that runs ``data_manager_select`` in bundle mode to produce a
real ``data_manager_json`` bundle, then calls the build endpoint and
asserts the synthetic option is present.
Per review: the tool itself has a data input and a paired collection
input with structured_like output -- it doesn't do mapping-over.
Mapping-over is what the regression test does.
The mako-template removal in 76341658dc deleted the JavaScript
`top.location.href = '/'` redirect that returned the user to Galaxy
after an external data source import in a new tab. The replacement
`show_ok_message` rendered a static page, leaving the new tab
stranded on a "job queued" message instead of navigating back to the
SPA.
Restore the redirect with a 302 to `/?notification=tool-submitted`
from both `ToolRunner.index` and `ASync.index`, and have `Home.vue`
surface a `useToast` notification on landing (then strip the query
param so a reload doesn't re-fire it).
Fixes#22671
Selenium regression for the WorkflowRunFormSimple data-input rerun
hydration crash fixed in the prior commit. Runs
`WORKFLOW_OPTIONAL_TRUE_INPUT_DATA` (a single optional `data_input`)
without selecting a dataset, then reruns without changes and asserts a
new ok output appears.
Pre-fix, the rerun submission raised a "Workflow submission failed:
... 'values' not permitted ..." toast because the rerun-hydrated
wrapper contained `[null]` (left over from the optional input the
user didn't fill on the original run) and `FormData.vue`'s mounted
hook crashed on `"src" in null` before it could normalize the value.
Originally reported on a "1 or 2 haplotypes" workflow where users
left the second-haplotype input empty.
This is done by passing `tool_version: latest` to `POST api/workflows/build_module`, which is then on the backend resolved by removing the version from the tool's GUID, unless we explicitly pass a `tool_uuid` (for UDTs for e.g.).
Fixes https://github.com/galaxyproject/galaxy/issues/22646