Commit Graph
7 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 5.5 a0da3b326e fix(web-app-yourls): upgrade the database schema on deploy instead of waiting for a browser click
After an image update the YOURLS code was ahead of its schema (db_version 506 vs 507) and every short URL redirected to admin/upgrade.php until someone clicked Upgrade. install.yml now includes upgrade.yml, which runs files/php/upgrade_database.php as www-data inside the container: it boots YOURLS with YOURLS_UPGRADING, runs yourls_upgrade(1/3) when yourls_upgrade_is_needed(), prints 'upgraded <old> -> <new>' or 'current <version>', and turns YOURLS' die() exits into exit 1. A probe short URL must then answer 301/302 without pointing at admin/upgrade.php.

E2E against YOURLS 1.10.6 code with MariaDB: 506 -> 507 upgraded, second run 'current 507', duplicate-key failure exits 1 with the message. PHPUnit: 8 tests, 23 assertions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 21:05:47 +01:00
kevinveenbirkenbachandClaude Opus 5.5 3f331cd8b8 perf(web-app-moodle): converge plugin settings in one CLI run per plugin
04_oidc.yml and 05_ldap_sync.yml looped over 69 auth_oidc and 73
auth_ldap settings and ran one `container exec … php cfg.php --set` per
setting; every exec booted Moodle once, 62 s plus 73 s per deploy on
echoserver.

tasks/utils/plugin_config.yml stages files/php/provision/plugin_config.php
in the container and runs it once per plugin with `{component, settings}`
as JSON on stdin. The script validates the whole payload before writing,
refuses `core` and settings forced in config.php, and for each setting
compares get_config with the wanted value and calls set_config plus
add_to_config_log only on a difference, as cfg.php does; set_config
invalidates the plugin's config cache itself (Moodle v5.3.0
moodlelib.php). It prints `CHANGED <n>`, which drives changed_when.

bind_pw and clientsecret no longer sit on the argv of every exec as
`--set="…"`; they only travel in the stdin payload. Values that the old
host-shell double quotes altered are now written exactly, so the first
run may report them changed.

Evidence: PHPUnit in the test container 42/42 including the 9 new
PluginConfigTest cases; Templar render of both mappings identical to the
old loop items (69/69, 73/73).

On merge: feature/iam-profile-rbac a46d93ff96 replaces several field_map
values with OIDC.ATTRIBUTES.*; carry them into the new mappings.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 21:00:44 +02:00
kevinveenbirkenbachandClaude Opus 5.5 df214dd00a refactor(web-app-moodle): group the provisioning scripts in files/php/provision
provision_ai_gateway.php and provision_mcp.php shared a prefix inside one
directory, which test_prefix_grouped_files rejects. Both move into
files/php/provision/ as ai_gateway.php and mcp.php, the layout
web-app-n8n already uses for its Python provisioning scripts.

The two lookups that feed the scripts to the container follow, and the
unit test moves to its mirrored path as provision/AiGatewayTest.php.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 01:37:03 +02:00
kevinveenbirkenbachandClaude Opus 5.5 3f91dd600e fix(web-app-moodle): point the Moodle 5 AI provider instance at the gateway
Moodle 5 keeps AI provider settings in provider instances, not in the
plugin configuration. The deploy kept writing aiprovider_openai/* through
cfg.php and read the same value back, so its own check stayed green while
no provider existed. The gateway spec then found no settings page and
web-app-moodle#2 failed in run 37646050826.

The deploy now pipes files/php/provision_ai_gateway.php into the
container. It finds the instance by class and name or creates it through
core_ai\manager, points the three text actions at the chat endpoint,
switches image generation off, stores the virtual key and prints what
Moodle stored. The task asserts on that output. An instance an
administrator added is left alone.

The spec finds the instance by MOODLE_AI_PROVIDER_NAME on the providers
page and reads the endpoint from its generate_text action page.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 01:27:03 +02:00
kevinveenbirkenbachandClaude Opus 5 962479ad71 fix(akaunting): realign the seeded administrator password on every pass
The install one-shot seeds the administrator from ADMIN_PASSWORD and runs only while
the first-run marker is absent, so after a credential rotation the account keeps the
secret the deployment no longer holds. The playwright trace of the run shows the
consequence: the native login never leaves /auth/login.

Akaunting ships no first-party command for this. user:seed only invokes a seeder and
sets no password, so the realignment goes through artisan tinker, which composer.json
lists under require rather than require-dev and is therefore present in the served
image. ADMIN_EMAIL and ADMIN_PASSWORD reach it through the environment, never through
an argument.

The password is assigned in clear text deliberately: App\Models\Auth\User defines
setPasswordAttribute, which bcrypts on save, so hashing before assignment would store
a hash of a hash. The fourth test case pins that down by asserting the raw value on
the model after save.

The role had no host/cid resolution at all -- setup/swarm.yml sidesteps it by scaling
to zero and running a one-shot service, which is too coarse for a per-run task -- so
it gains resolve_host_cid and addresses the container directly.

The snippet is not standalone PHP: it carries no opening tag because tinker evaluates
what it is given. The mirrored test therefore stubs App\Models\Auth\User and
Illuminate\Support\Facades\Hash and evaluates the file, covering the missing user, the
missing email, the already-matching password (no save) and the differing one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 15:11:56 +02:00
kevinveenbirkenbach d391b4cbb8 test(unit): cover the postmarks, mediawiki and baserow shims
Bookwyrm has tests for the same trusted-header SSO bridge and settings
patcher; postmarks and baserow ship theirs untested, and the composer
require-dev stripper is a pure transformation nobody exercised.

Each test was checked by breaking its source: the admin gate failing
open, the group matcher loosened to a prefix, require-dev left in place
and the SSO gate forced open all turn the new tests red.
2026-08-22 22:31:37 +02:00
kevinveenbirkenbachandClaude Opus 5 7a9c085c5a test(unit): first php and ruby suites
composer.json, phpunit.xml and the ruby runner were already in place and
had never run a single test, so 24 php and 20 ruby files shipped with
nothing but php -l and ruby -c behind them.

The two joomla scripts are pure file-in/file-out driven by env, which is
testable without Joomla: the tests drive the real script against a
temporary configuration.php. They pin what the code silently does today —
apostrophe escaping in the error level and in the db password, the two
repair regexes for malformed public lines, a missing key that is left
absent rather than added, and the asymmetry that toggle_debug exits 1 on a
missing file while configure_db exits 0.

The mastodon initializer is an env gate that downgrades URL building to
http. The test pins the security-relevant half: with OIDC off, with an
https issuer and with no issuer at all, SWD stays undefined. The http case
proves the branch is taken.

The three nocheck markers had to go with it: the mirrored-unit-test lint
fails a file that carries both a test and an exemption. package_plugin.php
keeps its marker, it is a build step.

vendor/ and .phpunit.result.cache were not ignored; composer install drops
25 packages into the tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 19:17:53 +02:00