proxy_hide_header is replaced, not merged, by a location that sets its own,
so upstream_strips.conf.j2 only takes effect where a location includes it.
The health locations of web-app-prometheus (/healthz/ready, /_live_probe),
which every standard vhost includes, and the extra locations of
web-app-bluesky (/config, /ipcc) and web-app-opentalk (/v1/, /signaling,
/livekit) proxied without it, so X-Powered-By and the upstream's
Strict-Transport-Security leaked on those paths.
All seven locations now include the strips. A new lint checks every role
template without a server block, i.e. every fragment the front proxy
renders into a vhost, and fails on a proxying location that lacks them.
Templates with their own server block are app-internal nginx configs
behind such a location and stay out of scope.
Closes#1124
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
compose/01_minimal.sh disabled every variable service of the dashboard,
asset included, and ran both matrix rounds; round 1 of web-app-dashboard
pins the asset provider off as well. Without web-svc-asset the dashboard
renders its logo and favicon from the public
https://file.infinito.nexus/assets, so the workspace test depended on
that host: while it does not answer, Playwright's no-console-noise spec
fails on `net::ERR_CONNECTION_REFUSED` for the logo (main run
39684179395, ubuntu and centos).
The test now keeps the asset provider out of the disable set and pins
round 0, so the dashboard serves its branding from the deployment's own
file service. Round 1 stays covered by the regular dashboard matrix.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
scripts/install/filesystem.sh retried `dnf install -y zfs` three times
against the same metadata during the Fedora image build of main run
39684179395 (XMPP#0): every attempt listed pcp-*-7.2.2-1.fc44, every
mirror answered 404, "Failed to download packages" after 3 attempts.
Each retried dnf install now runs with --refresh, so every attempt
resolves against freshly fetched metadata instead of repeating the one
that lists packages no mirror serves anymore.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Under the dnf4 backend (CentOS) ansible.builtin.dnf reports
`Failed to download packages: <reason>` (module_utils/_embed/dnf.py),
under dnf5 (Fedora) the bare `Failed to download packages`. The exact
comparison re-raised the CentOS form instead of retrying. The rescue now
re-raises everything that does not start with that message.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Since 2026-10-21 18:45Z part of the metalinks mirrors.centos.org hands
to CI runners still expects the previous BaseOS repomd.xml (sha512
bed4f4…) while every mirror and the master already serve the current one
(2f4550…). dnf then rejects every mirror ("checksum doesn't match",
"All mirrors were tried", Nextcloud#2, Nextcloud#10, Mattermost#1 in run
39684179395) or resolves BaseOS from a mirror still on the previous push
while AppStream is current ("nothing provides rpm = 4.19.1.1-27.el10
needed by rpm-build-4.19.1.1-27.el10", Baserow#0, Akaunting#0).
roles/update/files/centos_mirror.sh replaces every metalink of the
CentOS Stream repo files with the matching baseurl on
mirror.stream.centos.org and prints what it pinned. The Dockerfile runs
it before its first dnf call, so the dev and swarm-node images never
consult a metalink; roles/update reaches fedora.yml through a new
centos.yml that runs it first, so production hosts resolve against the
same source. The script is idempotent and prints nothing once every
section is pinned.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
7e82ba6d71 moved web-app-bigbluebutton's bbb-pads to v1.5.11, the tag
https://raw.githubusercontent.com/bigbluebutton/docker/develop/repos/tags
names for the bbb-pads source. alangecker/bbb-docker-pads has no such
image (Docker Hub: newest v1.5.8), so every BigBlueButton deploy pulls a
missing tag and test-external fails "These pinned Docker images do not
exist in their registry (HTTP 404): web-app-bigbluebutton/bbb-pads".
bbb-pads goes back to v1.5.8. The version-source updater now knows the
image a `version` pin tags (pulled directly or as the base of a custom
build) and withholds a bump when the registry answers 404 for the new
tag; an indeterminate answer does not block it, the same line
test-external draws. Run against main, the updater now reports no
update for bbb-pads instead of v1.5.11.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The run was stopped on the operator's word to free the GPU, after 25 catalogs.
What it had written stays: 88 msgstr filled across 26 core catalogs, with 90
translated-by marks, the two extra being entries whose mark was set as the run
ended.
Every file passes msgfmt -c. That is the check that matters for a killed run,
because an interrupted write leaves a syntax error rather than a short file,
the way 5790359cd0 found for docs/tr and docs/zh.
Two catalogs carry the open defect rather than translations: core/zh took 0 of
4 entries and core/ar 7 of 15, both on HTTP 422 from the gateway. Those entries
keep a refusal mark, so a later run picks them up again once the 422 is
understood.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fedora deploys failed in `update (dnf)` with "Failed to download
packages": the node's metadata still listed builds the master had
already replaced, and every mirror answered 404 (#1138: less-704-4.fc44
four hours after the push; run 39684179395: OpenBao#0 swarm-mgr-01 and
Nextcloud#9, less-704-4 and ca-certificates-2026.2.90).
Two mechanisms lead there:
- Under dnf5, ansible.builtin.dnf's `update_cache: true` expires no
repository: it queries the repos before loading them (0 available
repos before create_repos_from_system_configuration, 16 after), so
metadata already cached on the node stays in use until
metadata_expire. An explicit `dnf makecache --refresh` now runs
before the upgrade.
- A metalink can still hand out repodata from a mirror on the previous
push. The upgrade now runs in a block whose rescue re-raises every
other failure unchanged and, on exactly "Failed to download
packages", runs `dnf clean metadata` and upgrades once more.
Fixes#1138
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The merge dc19615d62 inverted 1590ec2c6f. It took main's cfg.php task back and
dropped the two env lines that feed config.php, so config.php kept reading
MOODLE_EGRESS_BLOCKED_HOSTS from an environment that no longer carried it, and
moodle_env() throws on an unset name. Both Moodle jobs of run 39658756830 died
in install_database.php with rc 255:
Fatal error: Uncaught RuntimeException: Required env var
MOODLE_EGRESS_BLOCKED_HOSTS is not set in /var/www/html/config.php:11
The rescue bundle proves the absence rather than inferring it: env-lengths.txt
of web-app-moodle-stack lists all 44 variables the container received, and
none of the three the merge dropped is among them.
vars/main.yml gets MOODLE_EGRESS_ALLOWED_PORTS back, as the list main's
expression built, so the conditional LiteLLM port survives under the name the
template and config.php expect. MOODLE_EGRESS_SETTINGS and
MOODLE_EGRESS_NEWLINE go, because their only consumer was the cfg.php loop.
Dropping the egress entries from that loop is mandatory, not tidy, and
1590ec2c6f says why: a value set in config.php lands in
$CFG->config_php_settings, cfg.php then exits 4 with 'unable to change', and
the deploy aborts. Repairing env.j2 alone would have moved the failure one step
later. MOODLE_DEBUG_SETTINGS stays on the cfg.php path, which nothing in
config.php contests.
Values are unchanged. env.j2 joins with commas, moodle_env_lines splits on
/[\s,]+/ and rejoins with PHP_EOL, so both halves produce the byte-identical
string the removed task wrote.
What this restores is reach: the policy now holds for every replica and the
cron container on each request, not for the one replica the deploy touched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Without web-svc-asset in the inventory, services.asset.url falls back to
the public https://file.infinito.nexus/assets. The branding-asset wait
then matched the public logo and favicon and polled the project's public
website before the first compose start. Since that host stopped
answering on 2026-10-21, every deploy that disables the asset service
failed after 60 retries, among them the workspace compose track on main
(run 39684179395: ubuntu and centos, "Status code was -1 ... Errno 101
Network is unreachable" for file.infinito.nexus/assets/img/logo.png).
The slurp, the URL collection and the wait now run in one block guarded
by the dashboard's own services.asset.enabled, so the deploy waits only
for assets the shared file service of this deployment serves.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The package cache creates every Nexus proxy with
strictContentTypeValidation. A raw proxy has no type contract, and Nexus
cannot type a GPG keybox: on a fresh cache it answers the Node.js release
keyring (raw.githubusercontent.com/nodejs/release-keys/.../pubring.kbx)
with 404 "Content type could not be determined". The Node.js installer
from #1108 fetches that keyring, so on main (run 39668792538) Workspace
debian:13 fails in `make install-lint`, and Workspace ubuntu, centos and
manjaro fail in `test-external`, whose URL check reaches the same file
through the cache.
The four raw proxies (raw-githubusercontent, raw-codeload-github,
raw-packagist, raw-alpine) now share the storage block with validation
switched off. Every typed proxy (apt, pypi, npm, helm, rubygems, go, yum)
keeps strict validation. The installer's integrity check does not depend
on Nexus: it verifies the SHASUMS file with gpgv and the tarball with
SHA-256.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>