Commit Graph
8 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 5 cb8707af06 feat(addons): let an addon declare the architectures it runs on
jenkins-1.1.0.tar.gz carries plugin-linux-amd64, plugin-darwin-amd64 and
plugin-windows-amd64.exe, and nothing for linux/arm64 (read from the tarball
itself). Mattermost installs and enables the plugin anyway, then logs

  jenkins: failed to apply option: backend executable not found for
  environment: linux/arm64

and drops it from the active set, so addons/mattermost-plugin-jenkins.spec.js
asserted against a plugin the server had already refused. v1.1.0 is the last
release since 2020-06-19, so there is nothing to wait for upstream.

Turning the addon off outright would lose it on amd64 too. The architecture is
knowable at deploy time - ansible.cfg gathers facts and tasks/utils/addon.yml
already resolves MATTERMOST_HOST_NODE and delegates to it, so even a mixed
swarm cluster names the node whose kernel decides - but not where the addon
declares itself: test_addon_enabled_renders_to_bool renders every `enabled`
against group_vars plus role names only, and an expression that cannot resolve
there does not fail, it coerces to False and switches the addon off in every
run. Run 34893363518 lost web-app-nextcloud that way.

So the declaration stays static and the gate moves to the task:

  meta/addons/*.yml   architectures: [amd64]      what the addon can run on
  tasks/utils/addon.yml                           skips provision, enable and
                                                  the integration hook when the
                                                  hosting node is something else
  playwright.env.j2   MATTERMOST_ARCHITECTURE     so the spec skips with it

HOST_ARCHITECTURE_BY_KERNEL maps ansible_architecture to the tokens the deploy
matrix rotates. It is deliberately not SYS_SVC_CONTAINER_DPKG_ARCH_BY_ANSIBLE_ARCH:
that table speaks dpkg (armhf, ppc64el), and an OCI/matrix token is a different
namespace that happens to agree on two entries.

The schema check rejects anything outside ARCHITECTURES rather than narrowing
silently, mirroring get_role_architectures: an unknown token matches no host
and would drop the addon from every deploy while every run stayed green.

Rendered through Templar, the gate yields a real bool in all six combinations
of {no architectures, [amd64]} x {x86_64, aarch64, armv7l}, and the six other
Mattermost addons - which declare none - stay True throughout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-12 16:07:11 +02:00
kevinveenbirkenbach 0f77cfbc31 Merge branch 'main' into feature/store-i18n 2026-10-06 02:29:13 +02:00
kevinveenbirkenbachandClaude Opus 5.5 89b95d751c fix(update): stop bumping pins of eol roles
The update bot opened a version PR for web-app-jira (#821) although the role is end of life: none of the updaters looked at the lifecycle. utils.update.base.is_maintained now answers that question once, and the collectors for image versions, declared version sources, pip pins, repository refs and the addon check skip a role whose lifecycle is eol.

The lint that requires every semver pin to be watched shares that scope, otherwise it would report the pins of the eol roles as unwatched. Every other stage, deprecated included, stays in the update scope.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-06 01:09:10 +02:00
kevinveenbirkenbach 4b1972b165 Merge branch 'main' into feature/store-i18n 2026-10-05 22:25:40 +02:00
kevinveenbirkenbachandClaude Opus 5.5 739c78bad1 feat(update): bump addon pins through their declared source
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>
2026-10-05 02:50:48 +02:00
kevinveenbirkenbachandClaude Opus 5 d937f23863 feat(web-app-discourse): render mermaid fences as diagrams
Discourse ships no mermaid plugin: the repository that name suggests does not exist, the one third-party plugin carrying it is archived, and the maintained artefact is discourse/discourse-mermaid-theme-component. A theme component installs through RemoteTheme.import_theme rather than a clone into the plugins directory, which the addon contract had no word for, so mechanism gains the value theme and the launcher config only clones addons whose mechanism is plugin.

The component is imported idempotently by remote_url, enabled, and attached as a child of the default theme; the task reads all four properties back and fails when one is missing, because a component that is installed but unattached leaves a fence rendering as plain source.

Unlike the neighbouring addons this one is pinned off in variant 1 instead of carrying the addons-variant-pinning waiver: their reason is that a plugin compiled into the image costs nothing to disable, which does not hold for an install step that runs after the deploy.

The Playwright spec publishes a topic through the session API and asserts the rendered result. It polls the text content of the post's SVGs rather than inspecting <text> nodes: current mermaid places labels in foreignObject HTML, and SVG nodes expose no innerText, so both narrower reads come back empty on a diagram that rendered correctly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-03 21:12:11 +02:00
kevinveenbirkenbachandClaude Opus 5 f713ba8350 refactor(credentials): address them at secrets.credentials, like every other meta file
meta/schema.yml became meta/secrets.yml, but its content still landed at
applications.<app>.credentials — the one meta file whose payload did not sit
under a root named after the file. Every other topic obeys that rule:
meta/volumes.yml goes to volumes, meta/rbac.yml to rbac. Credentials now go to
secrets.credentials.

The path exists exactly once, in utils/manager/credential_key.py, and
OVERRIDE_SECTION is derived from its two segments rather than spelled beside
them, so the dotted form used by --set and the nested form used by the
inventory cannot drift. Six consumers read it: the loader, the generator, the
CLI override parser, the two emit helpers, and the four lookup validators.

--set now accepts exactly one key shape,
applications.<app>.secrets.credentials.<key>. The three short forms are
rejected instead of guessed at: the same short key names different credentials
on different apps. That also retired primary_app_id, which only existed to
disambiguate them.

Three defects surfaced while wiring this up. _apply_one_role_schema still wrote
to the old root, so an app's own credentials would have moved while its
providers' stayed behind. web-app-pgadmin reads through
lookup('applications', ...).credentials.<key>, an access path no regex over
lookup('config', ...) could see, and would have deployed with an empty postgres
password. And _META_NON_GENERIC_TOPICS still listed 'schema' — a bare topic
name, invisible to any path search — so the generic file-root loop assigned the
raw schema under secrets and the follow-up write landed inside the cached
document, truncating keycloak's four credentials to one for every later
reader.

tests/integration/ansible/lookups/config/test_credentials_roundtrip.py pins both
directions of the seam and the cache invariant that last defect broke.

Existing inventories still carry the pre-rename root; migrating them is
deliberately out of scope here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 16:51:56 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e317f08ac9 feat(addons): unified meta/addons contract (req 026)
Per-file meta/addons/<id>.yml loader, schema + bridge-parity lints, shared update SPOT, unit/external tests, and layout.md/plugins README docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 11:30:45 +02:00