The image bump 9ed531a77e (#1254) put Stalwart v1.0.1 on main. v1.0.1
shows the password form right after the username, without the "Allow"
consent step that v1.0.0 asked for. test-login-native.js waited for that
button unconditionally, so "administrator: stalwart recovery admin
native login and logout" timed out after 60 s in every attempt
(locator.waitFor on getByRole('button', { name: /^allow$/i })).
The spec now waits for either the Allow button or the password field and
clicks Allow only when it is shown; the same check runs before the
dashboard assertion after sign-in. Both waits still fail when neither
element appears.
The change is identical to the one on feature/updater-lockdown-probe,
so the two lines do not conflict when they meet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-up on the in-container probes of gitea, shopware and fider.
- fider: the tenant POST over /dev/tcp waited on `head` without a bound,
so a peer that accepts and stays silent blocked the task for good. It
now runs under `timeout` (TIMEOUT_FACTOR-scaled 30 s, the old uri
socket timeout) and reads the status line with the `read` builtin, so
the bound kills the whole probe. Only outcomes Fider never committed
are retried: a refused connect and a 5xx (Fider rolls the request
transaction back on a handler error). A timeout or a closed socket
after the request was sent fails the task instead of resending the
POST; the next run's tenant count decides again.
- fider: both bootstrap tasks get `no_log` behind MASK_CREDENTIALS_IN_LOGS,
as the body carries the administrator's name and email.
- shopware: each wget probe runs under `timeout`, as busybox wget waits
900 s per read by default.
- shopware, gitea: the first readiness wait derives its retries from
lookup('timeout', 300) again, the budget of the wait_for it replaced,
so TIMEOUT_FACTOR scales it.
Refs #1089
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`make autoformat` rewrites roles/web-app-seaweedfs/vars/main.yml and
tests/unit/python/roles/web-app-stalwart/test_store_guard.py on every
checkout of main, so every quality gate on every branch leaves them as
unstaged changes, and the gate lints a tree the commit does not carry.
The YAML change folds one line of the `>-` scalar
SEAWEEDFS_S3_ADMIN_CURL; the parsed value is identical. The Python
change is ruff's line wrapping only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Mailu assert accepted any non-empty forward on the rua user, so a
forward to a user without a mailbox let the deploy publish an rua address
whose alias delivers nowhere. A forward now satisfies the assert only when
its target carries a mailbox account.
production_facts.py let a later duplicate tag overwrite an earlier one, so
a record with two rua tags passed although receivers discard it (DKIM
tag-list rules, adopted by RFC 7489). dmarc_tags now raises on a duplicate
tag and check_dmarc reports the record as invalid. The rua comparison also
took the raw URI text, so a percent-encoded address or one followed by
mailto header fields never matched; the address is now cut at '?' and
percent-decoded after the size suffix is removed (RFC 6068).
Refs #1125
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
a7685e3b21 derived the worktree lab subnet as 10.244.<slot>.0/24, which
lies inside NETWORK_TOR_VIRTUAL_CIDR (10.240.0.0/12). On a swarm with
svc-net-tor the nft output chain redirects every TCP connection to that
range into Tor's TransPort, so the nodes could not reach each other: in
the slot-114 worktree `curl http://10.244.114.10:5000/v2/` timed out on
the manager itself and svc-prx-openresty died pushing to the stack
registry with Client.Timeout.
The prefix is now 10.160.<slot>, outside every range the platform
reserves in group_vars/all/08_networks.yml.
The lint now reads the reserved ranges from that file instead of a
hardcoded list: NETWORK_TOR_VIRTUAL_CIDR, NETWORK_MESH_POOL,
NETWORK_DOCKER_ADDRESS_POOLS, NETWORK_NESTED_DOCKER_ADDRESS_POOLS and
NETWORK_NESTED_DOCKER_BIP, plus the primary lab subnet and the worktree
INFINITO_SUBNET range. Against the 10.244 prefix it fails every slot on
the Tor range.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dashboard sent script-src 'unsafe-inline' from two sources. Its own
meta/csp.yml granted it to script-src-attr, and build_csp_header adds it
to script-src-elem and script-src-attr for every app with
services.logout.enabled. Both reach script-src through the family union,
and the token in script-src-elem also closes the hash gate, so the
hashes that sys-front-inj-javascript, -dashboard, -logout and -matomo
register for their inline snippets were discarded.
build_csp_header now skips the logout grant on a directive whose
meta/csp.yml sets unsafe-inline: false. Only web-app-dashboard sets it:
on script-src and script-src-elem. Its injected snippets now run by hash
and the logout one-liner is hashed like the others. A render of
build_csp_header for every role, variant, logout on/off and tor on/off
(1712 headers) differs from origin/main only in the 8 web-app-dashboard
headers; the 86 other roles that declare a logout service render
byte-identical policies.
script-src-attr keeps 'unsafe-inline': port-ui 2.2.2 still renders
inline event handlers (menu onclick entries, openDynamicPopup,
closeAllModals, the card image onerror). It goes once the port-ui
release without inline handlers is pinned and header.yml.j2 moves from
onclick to action.
The dashboard Playwright spec asserts that script-src and script-src-elem
carry no 'unsafe-inline' on the landing page, next to its existing check
for CSP violations.
Refs #1122
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>