Skip to content

SimpleRisk 20261105-001 Release - #183

Merged
simplerisk-core-sync[bot] merged 16 commits into
masterfrom
release-20261105-001
Nov 13, 2026
Merged

simplerisk-core-sync[bot] merged 16 commits into
masterfrom
release-20261105-001

Conversation

@simplerisk-core-sync

Copy link
Copy Markdown
Contributor

GA promotion of the 20261105-001 release candidate.

Opened automatically by code-development's promote_docker_release workflow
when 20261105-001 landed on code-development master.

Merging this publishes the release: the push to master fires
promote-latest.yml, which retags Docker Hub :latest to the
already-built RC digest, mirrors it to GHCR cosign-signed, and moves the
tier=latest SSM tag. No image is rebuilt.

The required image-build checks on this PR are the gate.

jsokol and others added 16 commits October 27, 2026 12:37
…che workers

Every request holds a database connection, and Apache's default of 150 workers
can exceed a small database's max_connections (a db.t3.micro allows about 60);
several containers sharing one database multiply it. The right number depends
on the database and replica count, which the image cannot know, so the
entrypoint accepts APACHE_MAX_REQUEST_WORKERS (1-2000) and writes it to
conf-enabled, raising ServerLimit when it exceeds 256. Unset keeps Apache's
default; invalid values are ignored with a warning.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds file_env to the minimal entrypoint so credentials (DB setup/app
passwords, CSRF secret, mail and admin credentials) can be read from a
file such as /run/secrets/<name> instead of the environment. Setting
both VAR and VAR_FILE, or pointing at an unreadable file, is fatal.

Refs #83

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…, SQL, PHP and sed

Credential values were interpolated into a bash -c string (mysql setup/delete),
a double-quoted PHP string (csrf-secret.php) and unescaped PHP single-quoted
strings (config.php); sed_escape also broke on newlines. _FILE secrets from a
secret manager commonly contain these characters.

- run mysql via an argv array with the password in MYSQL_PWD, SQL on stdin,
  string values single-quoted and identifiers quoted with proper escaping
- write csrf-secret.php and config.php defines as escaped PHP single-quoted strings
- rewrite sed_escape with parameter expansion so newlines survive
- pass the app DB password to apply_mail_setting via MYSQL_PWD, not argv
- add test_escaping.sh and run it in container-validation

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- A digit string longer than 19 digits wrapped around in bash arithmetic and
  could be accepted (18446744073709553616 evaluated to 2000): strip leading
  zeros and bound the length before any arithmetic
- A failed write (for example a read-only root filesystem) still logged
  "Apache will serve at most N requests at once", because a failed redirect on
  a { } group does not report failure: write with a single printf, log an
  error and keep the default instead
- Test: boundaries (1, 256, 257, 2000), the exact file, adversarial and
  overflow input, the unwritable path, and the call placement in the
  entrypoint; loosen the awk extraction pattern
- Docs: prefork-only, memory, session connection and cron caveats

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… connection

apply_mail_setting passed --ssl-mode=DISABLED, so MySQL 8's caching_sha2_password
refused the app user's first login ("Authentication requires secure connection")
and every mail setting was skipped with only a warning. Use the client default
(PREFERRED), and escape values with sql_str_escape. Add a regression check.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…rkers

Add APACHE_MAX_REQUEST_WORKERS to simplerisk-minimal
# Conflicts:
#	.github/workflows/container-validation.yml
feat(minimal): support *_FILE variables for Docker/Kubernetes secrets
The arm64 image's mysql is MariaDB's client (Debian's default-mysql-client; MySQL's apt repo has
no arm64 packages), which rejects --ssl-mode. With DB_SSL_ENABLED=true the privileged setup and
delete calls failed with "unknown variable 'ssl-mode=REQUIRED'", so no customer database could
be created on Graviton against a TLS-only RDS (found on the first Canada deploy).

set_db_ssl_flags now asks the client: Oracle's keeps --ssl-mode=REQUIRED --enable-cleartext-plugin
(unchanged for amd64); MariaDB's gets --ssl --skip-ssl-verify-server-cert, its equivalent (TLS
required, certificate not verified, cleartext plugin built in). If the client cannot be asked the
historical flags are kept.

Verified on an arm64 node against the Canada RDS (MySQL 8.4.8, IAM auth token): the lifted
set_db_ssl_flags + mysql_setup connect over TLS as the master user. test_db_ssl_flags.sh covers
both clients, the opt-in-only rule and the fallback, and fails on the old code; it runs in CI.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
fix(minimal): use TLS flags the installed mysql client understands (arm64 / MariaDB client)
The minimal job built 3 PHP variants x {amd64, arm64} sequentially in one job with arm64
emulated by QEMU: about 27 min per variant, 88 min total. Per-step timings from the 10-27 run show
why: the PHP extension compile (docker-php-ext-configure/install) took 24.3 min on emulated arm64
and 1.6 min on native amd64; the whole variant summed to 27.5 min emulated vs 2.4 min native.

build-minimal is now a matrix of {php83, php84, php85} x {amd64 on ubuntu-latest, arm64 on
ubuntu-24.04-arm}; each leg builds only its own architecture and pushes by digest (no tag).
merge-minimal turns each variant's two digests into the published tags with
'docker buildx imagetools create' and fails unless every tag carries linux/amd64 and
linux/arm64. scan-minimal (one leg per variant) keeps the Grype gate and report labels;
promote needs all three scans and does the same single SSM write as before.

Unchanged: triggers, concurrency, the tag set (<VERSION>-php83/-php84/-php85, bare <VERSION> and
:testing on php85), the full-stack job, and the shape of the published image (amd64 + arm64 +
attestations). New: a workflow_dispatch dry_run input that publishes only
<VERSION>-nativetest-php8x tags, never the bare tag or :testing, and skips the promote. It must be
dispatched from testing (the testing environment admits only that branch).

Verified: actionlint clean; the merge-and-verify commands run against a local registry produce one
index digest for all tags, both platforms, and 2 attestation manifests, matching the shape of
20261020-001-php85. Not run here: a real build on ubuntu-24.04-arm.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ci(testing): build the minimal image natively per architecture (draft)
…ver's certificate

The setup/delete Jobs and the entrypoint's mysql calls encrypt to RDS but never verify the server
(--ssl-mode=REQUIRED / --skip-ssl-verify-server-cert), and the app passes PDO no TLS option unless
SIMPLERISK_DB_SSL_CERT_PATH is set, which the README now says plainly.

- Vendor AWS's RDS global bundle (114 certificates, 174,560 bytes, every region) at
  common/etc/ssl/rds/global-bundle.pem, so the existing 'COPY common/ /' ships it to
  /etc/ssl/rds/global-bundle.pem. rds-global-bundle.sha256 pins it (AWS publishes no checksum);
  test_rds_bundle.sh checks the pin, that every certificate parses, that the us-east-1, eu-central-1
  and ca-central-1 RSA2048 G1 roots are present, that nothing expires within 3 years, and that no
  private key is in the file. rds-bundle-drift.yml compares it with AWS's file every Monday and tells Slack.
- set_db_ssl_flags: with DB_SSL_ENABLED=true and the bundle present, verify chain and host name:
  --ssl-mode=VERIFY_IDENTITY --ssl-ca=<bundle> (Oracle's client) or --ssl-ca=<bundle>
  --ssl-verify-server-cert (MariaDB's, the arm64 image). DB_SSL_VERIFY=false returns to
  encrypt-without-verify without a rebuild; a missing bundle falls back the same way and logs it.
  Without DB_SSL_ENABLED=true nothing changes.
- apply_mail_setting uses app_db_tls_flags: with SIMPLERISK_DB_SSL_CERT_PATH set it verifies against that
  CA like the app does (and does not fall back to plaintext if the file is missing); without it MariaDB's
  client now skips verification as Oracle's default already does, which fixes its failure against servers
  whose certificate it cannot chain ('self-signed certificate in certificate chain').
- README documents DB_SSL_VERIFY, RDS_CA_BUNDLE and what an empty SIMPLERISK_DB_SSL_CERT_PATH means.

Verified: the real functions, lifted from the file, drive the real mysql clients (Oracle 8.4.13 on amd64,
MariaDB 11.8.6 on arm64 under emulation) against a MySQL 8.4 with a private CA: right CA connects over
TLS; an unrelated CA, and a right CA with a name not in the certificate, are refused; the kill switch and a
missing bundle connect unverified. Against a real RDS instance the bundle verifies the server certificate
and the Oracle-client flags log in with an IAM token. 38 + 13 checks, the other minimal tests, ShellCheck
and actionlint pass.

No app or template change here: the app only uses TLS when SIMPLERISK_DB_SSL_CERT_PATH is set.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
feat(minimal): ship the AWS RDS CA bundle and verify the database server's certificate
@simplerisk-core-sync
simplerisk-core-sync Bot merged commit a2ee861 into master Nov 13, 2026
24 checks passed

This branch was successfully deployed

1 active deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant