A reusable resolver (galaxy.tool_util.deps.mulled.recommend) that picks the best
quay.io/biocontainers image for a set of conda packages, verified against quay.io
rather than guessed:
- recommend_container() resolves single-package and mulled-v2 (multi-package)
images, distinguishing an exact-version hit from a name-only fallback and
resolving unpinned versions against tags that are actually built.
- biocontainer_tag_built() verifies whether a specific image tag exists.
- Shared lookup helpers move into mulled/util.py and are reused by the existing
container resolver (container_resolvers/mulled.py) to avoid duplication.
Exposed as the mulled-recommend console script:
mulled-recommend samtools=1.17
mulled-recommend bwa,samtools
mulled-recommend --json "samtools=1.3.1,bedtools=2.26.0"
Missing containers and transient network errors degrade gracefully (no exception).
Documented under admin special topics (mulled containers).
The package declared pydantic-ai>=0.1.16, so CI could resolve 1.44.0
where Agent._max_output_retries was still named _max_result_retries,
breaking test_configured_retries_wired_into_agent. Pin to >=1.99.0 to
match what requirements.txt already pins.
galaxy-tool-util-models was listed as an unversioned dependency in
galaxy-schema, galaxy-tool-util, and galaxy-tool-shed-schema. This
caused pip to leave it at a stale version when upgrading an existing
virtualenv, because the already-installed version satisfied the loose
(unconstrained) requirement.
The symptom was ImportError failures at job execution time — e.g.:
ImportError: cannot import name 'AnySafeValidatorModel' from
'galaxy.tool_util_models.parameter_validators'
— where galaxy-util (at the new version) referenced a symbol that
didn't exist in the older galaxy-tool-util-models still present in
the venv.
Fix: add a >=26.0 lower bound in each dependent package so pip is
forced to upgrade galaxy-tool-util-models when installing any of
these packages at 26.0 or later.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
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>
Every webapp process was running its own HistoryAuditMonitor (and the
per-process Postgres LISTEN that comes with it). Move to a single elected
producer via a new is_history_audit_monitor role on DatabaseHeartbeat.
The election prefers any WorkerProcess with app_type=sse_monitor, falling
back to the max-server_name webapp when no dedicated daemon is running,
so the monitor migrates cleanly when the leader dies.
Add a standalone galaxy-sse-monitor process (new lib/galaxy/sse_monitor
package, galaxy-sse-monitor console script) that builds a minimal
GalaxyManagerApplication, registers itself as sse_monitor.<host>.<pid>,
and blocks on SIGTERM. Running this daemon moves SSE event production
out of the webapp so its dispatch can't stall behind a webapp's GIL.
Gate HistoryAuditMonitor.start/stop on the role callback rather than a
postfork hook; make start() restart-safe (clear _exit) and shutdown()
idempotent so role transitions can cycle the monitor.
rocrate 0.15.0 produces crates conforming to 1.2 spec by default, which
causes roc-validator validation errors like:
```
The RO-Crate metadata file descriptor MUST have a `conformsTo` property with the RO-Crate specification version
```
xref https://github.com/crs4/rocrate-validator/issues/107
Also:
- Remove unused `BaseWorkflowPopulator.validate_invocation_crate_directory()` method.
The packaged galaxy-data test suite imports `hvac` (via the vault
tests), so installing the `test` extra needs to pull it in for the
package tests to pass in CI.
The src/ layout conversion in b7f83c8469 updated where the recipe
writes client_build_hash.txt but left the _dist prereq and the hash
target declared at the old galaxy/web_client/ path. Make never sees
the hash file as "made", so `make _dist` re-runs the full
client-production build every time, even when src/galaxy/web_client/
is already populated.
Verified via `make -n _dist`: with the fix, an existing hash file
correctly short-circuits the rebuild and only runs `uv build`.
only directories in `lib/galaxy` & `packages/*/galaxy`
All other files removed or moved to their own module
All references to those files updated, especially galaxy/version.py
rocrate 0.15.0 produces crates conforming to 1.2 spec by default, which
causes roc-validator validation errors like:
```
The RO-Crate metadata file descriptor MUST have a `conformsTo` property with the RO-Crate specification version
```
xref https://github.com/crs4/rocrate-validator/issues/107
Also:
- Remove unused `BaseWorkflowPopulator.validate_invocation_crate_directory()` method.
The 26.0.1.dev0 PyPI packages were already published during the
earlier broken release attempt, so the version string is permanently
burned: PyPI does not allow re-uploading the same version, even for
pre-releases. Bump the dev counter to .dev1 so the release branch
ends at a version that has not been published yet and future dev
builds from this branch can be uploaded.
This commit only changes the four dev0 version strings introduced by
the previous commit:
- lib/galaxy/version.py: VERSION_MINOR = "1.dev0" -> "1.dev1"
- client/package.json: "26.0.1.dev0" -> "26.0.1.dev1"
- packages/*/setup.cfg: version = 26.0.1.dev0 -> 26.0.1.dev1
- packages/*/HISTORY.rst: 26.0.1.dev0 header -> 26.0.1.dev1
The pulsar-galaxy-lib>=0.15.0.dev0 dependency pin in
packages/app/setup.cfg and the historical 22.9.0.dev0 changelog
entries in packages/navigation/HISTORY.rst and packages/tours/HISTORY.rst
are deliberately left untouched — they refer to unrelated versions.
Companion to the previous commit. After v26.0.0 is retagged onto the
restoration commit and the PyPI publish workflow produces the correct
26.0.0 artifacts, this commit returns the release branch to
26.0.1.dev0 so future development on the 26.0 line continues from a
post-release dev version, matching the state established by
f4478f5d09 ("Start work on 26.0.1.dev0").
This is a fresh commit with the same content as f4478f5d09; it is not
a cherry-pick and does not reuse the original hash or author metadata.
After the v26.0.0 tag has been moved and a successful publish is
verified, the branch HEAD is once again at 26.0.1.dev0 just like
before this two-commit sequence — but now the v26.0.0 tag points at a
commit that actually contains version = 26.0.0.
The original v26.0.0 tag was retagged from 52e970855b to HEAD because
of bugs in the GitHub Actions release workflow. Unfortunately HEAD
already contained the post-release version bump from f4478f5d09
("Start work on 26.0.1.dev0"), so PyPI builds from the retagged HEAD
publish wheels labeled 26.0.1.dev0 instead of 26.0.0.
This commit restores the version files to their 26.0.0 state so the
v26.0.0 tag can be moved to point at this commit and the publish
workflow can produce correctly labeled artifacts.
The next commit re-applies the dev0 bump so the release branch ends
back at 26.0.1.dev0 and future development continues normally.
This is purely additive — no history is rewritten and the existing
26.0.1.dev0 commit (f4478f5d09) is left untouched.
Also:
- Drop unused `sphinx` from `package-dev-requirements.txt`
- Sync `client/.node_version` with `nodejs-wheel` version in
`lib/galaxy/dependencies/pinned-requirements.txt`
- Sync `packages/web_client/Makefile` with `packages/package.Makefile`
- Rewrite the Makefile target to buid the client in `packages/web_client/Makefile`