A padlock and an open padlock differ by a few pixels in a job title, which
is where the axis is read most often. A tunnel and a road do not.
Every label derives from here, the plan table's own column header included,
so the two entries carry the change.
Stalwart closes a connection that exceeds its per-IP connection budget
without a greeting. msmtp reports that as "the server sent an empty reply"
with exit 76, and the mail health check treated exit 76 as permanent. One
such drop, in a second in which Alertmanager flushed its notifications,
failed a deploy although the same path accepted a mail one second later.
The health check now retries exit 76 when msmtp names the empty reply,
within the ten attempts it already gives to exit 69, 75 and 124. Every
other protocol error still ends the check at once.
The alarm mail was sent once, so the alarm about a failed unit was lost to
the same drop. It now makes three attempts ten seconds apart for the
transient cases of the health check and still reports the last error.
The limit on the server is left alone. Exempting the node's own senders by
source address would also exempt Tor clients and, in swarm, every external
client. That question is tracked in #793.
Closes#790
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merging the stylelint 17.16.0 and the globals 17.13.0 bump dropped the comma after stylelint and left a trailing one after globals, in package.json and package-lock.json alike. Neither file was JSON any more, so npm could not read the lock and npm ci refused with EUSAGE: 'can only install with an existing package-lock.json'. make lint died in install-lint before a single linter ran, which is the whole lint job on every branch that carries main.
The two entries move into the alphabetical order npm writes them in and the commas follow. No version changes: the lock already resolved stylelint 17.16.0 and globals 17.13.0, only the devDependencies block was malformed. npm ci --dry-run now resolves the tree instead of refusing it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The duplicate check accepted any open PR whose head branch started with
the dedupe prefix and ended in the fingerprint of the fresh proposal. The
listing also returns PRs from forks, and the fingerprint can be derived
from public data, so a fork PR with such a branch name would have made the
bot skip its own update PR without carrying the change.
The shortcut now only applies to PRs whose head branch lives in this
repository, which only accounts with write access can create. A fork PR
is still compared by the content of its head, as before.
Raised by the CodeRabbit review of PR #781.
Refs #780
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The version-source updater only read meta/services.yml. An addon pinned in
meta/addons/<id>.yml stayed where it was: the ONLYOFFICE connector for
Nextcloud sat on v10.1.2, which does not install on Nextcloud 35, until
someone bumped it by hand.
The updater now reads addon files too. An addon declares its source in the
`update:` block it already has, beside monitored, catalog and upstream_id.
A monitored addon of the github-releases catalog needs nothing more: its
upstream_id names the repository whose tags are its versions. The
update-version-sources job opens the PRs, one per role.
Every pinned addon is wired:
- nextcloud onlyoffice carries its own version pin now. Its archive URL
stays a literal that carries the pin, because
test_pinned_addon_archives_available reads it as written
- wordpress mcp-adapter, moodle auth_oidc and jellyfin sso-authentication
follow the tags of their repository, moodle within its v4.5 series
- the three xwiki extensions read their Maven metadata
- pretix-oidc reads the PyPI simple index. The JSON API answers 404 behind
the package cache the test stack routes pypi.org through
- joomla's plugin is built here and jellyfin's ldap-authentication is bound
to the md5 of its archive; both are opted out with that reason
A bump rewrites the pin and the config.archive line together, and an
archive that does not carry the pin fails test_version_keys, so the two
cannot drift apart again. test_version_pins_are_watched covers addon pins
as well: a new one without a source or a reasoned opt-out fails the lint.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Docker updater watches image plus version, the repository updater
repository plus ref. A dozen pins fell outside both - an app_version, a
release, a tag in a registry neither speaks - so nothing ever told anyone
they had gone stale.
Such a pin now names its upstream next to itself in an `update:` block:
git_tags, registry_tags, npm, http_regex or a role-local script, with
`match` selecting a tag flavour and `strip` removing a prefix the pin does
not carry. utils/update/source.py resolves them beside the two existing
updaters, `python -m cli.contributing.update.source` bumps them, the
update-version-sources job opens one PR per role, and
tests/external/update/source warns while a bump is pending.
Two lints hold the rule: every semver pin is watched by one of the three
updaters or opted out with a reason, and a semver only ever sits behind
`version`, `<what>_version` or `ref` - which renames moodle's release to
app_version and simpleicons' local_version to local_tag, the latter being
the tag of a locally built image rather than an upstream version. A
declaration naming a key the entity does not carry, or a type the resolver
does not know, fails the lint instead of resolving nothing in silence.
Picked from feature/store-i18n (94d607fd0a) onto current main. Two things
differ from the original: svc-ai-lmstudio no longer carries an app_version
pin, so its declaration is dropped, and web-app-stalwart's webui_version,
added since, declares the git tags of the webui repository.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
penpotapp/frontend 2.18.1 no longer ships curl. The role probed the
frontend with the curl healthcheck flavor, so docker could not start the
probe at all: "exec: "curl": executable file not found in $PATH". nginx
was up, but the container turned unhealthy after its start period, and in
swarm the replicas were replaced in a loop until the convergence wait gave
up.
The frontend is started through bash by this role, and the image ships
bash, head and grep but neither curl, wget nor nc. The http_status flavor
speaks HTTP over a bash socket and insists on a 2xx or 3xx status line,
which keeps the meaning of curl -f.
Closes#787
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
penpotapp/frontend 2.18.1 no longer ships curl. The role probed the
frontend with the curl healthcheck flavor, so docker could not start the
probe at all: "exec: "curl": executable file not found in $PATH". nginx
was up, but the container turned unhealthy after its start period, and in
swarm the replicas were replaced in a loop until the convergence wait gave
up.
The frontend is started through bash by this role, and the image ships
bash, head and grep but neither curl, wget nor nc. The http_status flavor
speaks HTTP over a bash socket and insists on a 2xx or 3xx status line,
which keeps the meaning of curl -f.
Closes#787
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Connector v10.1.2 declares Nextcloud 33 to 34 as its supported range, so
occ refuses to enable it on Nextcloud 35 and the ONLYOFFICE variant of the
Nextcloud 35 bump fails in the onlyoffice addon spec. v10.2.1 declares 33
to 35 and therefore serves the pinned Nextcloud 34 as well as the pending
bump.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>