Commit Graph
4 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 5.5 ab9c23fa76 fix(web-app-suitecrm): run Symfony's session through the Redis handler too
3cefb01d71 moved PHP sessions to Redis by pointing session.save_path at
redis-central. SuiteCRM's own core_services.yaml wraps a
NativeFileSessionHandler around '%session.save_path%', and that handler
forces session.save_handler back to files and treats the Redis URL as a
directory ("is_dir(): Unable to find the wrapper "tcp""). Symfony's session
was empty on every request, so every POST /api/graphql answered 403
"Invalid CSRF token", the SPA logged the user out right after the SAML login
and the biber logout spec failed with "session was lost before the logout
attempt" (SuiteCRM#0 on PR #869, reproduced on main locally).

core_services.yaml is imported after every extension service file, so the
core handler cannot be redefined there. An extension packages file now
points framework.session at our own handler and storage factory, which wrap
PHP's built-in SessionHandler and therefore use phpredis from php.ini, with
its locking, for Symfony and the legacy app alike.

The entrypoint rebuilds the prod cache when an extension config is newer
than it, so an existing installation picks the wiring up instead of keeping
the compiled container.

Verified with a local compose deploy of variant 0: on main the SAML logout
spec failed with the 403 sequence above; after a mode=update redeploy the
cache was rebuilt, all three SAML specs passed, and the prod log shows no
tcp-wrapper warning or CSRF failure after the rebuild.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-12 18:35:22 +02:00
kevinveenbirkenbachandClaude Opus 5.5 52bfc2a476 fix(web-app-suitecrm): hand the log directory to the web user
The entrypoint runs the installer and the cache commands as root. They
create logs/prod, and the entrypoint handed cache and public/legacy back
to the web user but not logs. Apache could not write there, so SuiteCRM
wrote neither its auth.log nor its main log.

The entrypoint now hands logs to the web user after the root-run console
commands, on every boot that holds the boot lock, so volumes of earlier
deploys are repaired too. The deploy fails if a path under logs is not
writable for the web user.

Closes #854

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 00:16:14 +02:00
kevinveenbirkenbachandClaude Opus 5 a501cae538 fix(suitecrm): anchor the IdP cert extraction to the signing key
The greedy sed took the LAST X509Certificate on the line, so a descriptor
carrying an encryption key after the signing key handed SuiteCRM the
encryption cert and every assertion signature check would fail. The
extraction now splits the document into tags and takes the first
certificate after a KeyDescriptor with use="signing" - the active key,
which Keycloak lists first under rotation - falling back to the first
certificate for IdPs that omit the use attribute (SAML metadata treats
absence as both). Proven against five descriptor shapes, including the
one the old pipeline got wrong.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 23:28:17 +02:00
kevinveenbirkenbachandClaude Opus 5 b53d207667 fix(suitecrm): fetch the IdP descriptor with curl, not wget
Every swarm task of the tor variant died 1.4s after start with exit 8, so the
stack never converged and the drill failed at sys-svc-compose's converge wait
(CI run 32119014832, job 95662863105). The task log held exactly one line: the
entrypoint's "Fetching the IdP signing certificate" - nothing after it.

GNU wget cannot parse a socks5h:// proxy. It aborts before sending anything
with "Error parsing proxy URL: Unsupported scheme.", which src/retr.c maps to
PROXERR and src/exits.c to WGET_EXIT_SERVER_ERROR, i.e. 8 - identical in 1.21
through 1.25. Under -qO- the message is suppressed, which is why the container
log ends mid-sentence. Reproduced locally: the same URL without a proxy exits
4, with the socks5h proxy exits 8.

The proxy was injected container-wide as http_proxy/https_proxy, gated on
Keycloak's domain but applied to every destination - and the CI Tor network
has no exit nodes, so that also dead-ended every clearnet call the app makes.
The three sibling roles that solved this (wordpress, nextcloud, joomla) each
gate per destination host instead. Here the only server-side onion call is the
descriptor fetch itself: the SAML bundle is configured statically, so it needs
no backchannel, and the healthcheck already forces --noproxy '*'. The proxy
now reaches exactly the one client that needs it.

curl's timeouts are pinned so a stalled onion cannot hang the boot: 21
attempts of at most 30s bound the fetch at ~10.5min, inside the 20m
start_period and the ~28min converge budget.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 23:28:15 +02:00