Commit Graph
745 Commits
Author SHA1 Message Date
kevinveenbirkenbachandClaude Opus 4.8 6344b33201 fix(web-app-nextcloud): store integration OAuth credentials NC-encrypted via ICrypto
The shared OAuth-credential writer stored the RAW value via IAppConfig::setValueString(..., sensitive: true), but the integration apps (gitlab/openproject/suitecrm/zammad) read back via getValueString(lazy) + ICrypto->decrypt and expect an ICrypto ciphertext. The mismatch made decrypt throw 'Authenticated ciphertext could not be decoded' while rendering the GitLab Personal section, which 500'd the shared connected-accounts page and cascaded into the integration_discourse spec timing out on the missing #discourse_prefs mount. Encrypt each value with ICrypto and store it lazy + non-sensitive, mirroring the apps' own setEncryptedAppValue.

Verified in-container: getAdminClientId() now succeeds, a fresh variant-3 provision no longer returns a 500, and the integration_discourse spec passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 00:34:25 +02:00
kevinveenbirkenbachandClaude Opus 4.8 bb3d68caa0 fix(web-app-nextcloud): probe integration partners with container inspect instead of exec true
The gitlab/openproject/suitecrm/zammad integration tasks gated their partner-running check on 'container exec <partner> true' (rc==0), which returns rc 127 on partner images lacking a true binary, wrongly skipping the integration. Switch to 'container inspect -f {{.State.Running}}' gated on stdout-trimmed == 'true' — the same probe already shipped for the mattermost integration in 8023e4b8b. inspect never enters the container, so the in-container PATH lookup that broke the old probe is irrelevant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:46:57 +02:00
kevinveenbirkenbachandClaude Opus 4.8 8023e4b8b2 fix(web-app-mattermost): repair nextcloud OAuth coupling probe and gate user-access-tokens on nextcloud presence
The nextcloud->mattermost OAuth provisioning failed because the partner-running probe used 'container exec <mm> true' (rc 127 — no true binary in the mattermost image), which gated provisioning off and left the OAuth app unprovisioned (spec failed on oauth_instance_url=null). Replace it with 'container inspect -f {{.State.Running}}' gated on stdout-trimmed == true, provision the OAuth app via a controller-run script using a short-lived admin PAT, and rewrite the spec as a behavioral connect-redirect check.

Mattermost personal access tokens are now enabled only when the consumer web-app-nextcloud is deployed (services.mattermost.user_access_token_enabled renders from 'web-app-nextcloud' in group_names) instead of being hardcoded on.

Verified: probe live in the DiD stack (inspect running -> rc0, missing -> graceful skip); the user-access-token chain renders True/False via a real Templar (nextcloud present -> True, absent -> False); service-flag integration tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 20:41:19 +02:00
kevinveenbirkenbach 74d229912d Update services.yml 2026-06-24 11:12:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 ee4ab0f1e0 style(nextcloud): autoformat reflow of the zammad provision set_facts
Pure whitespace line-wrap from make autoformat; no logic change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 04:34:56 +02:00
infinito-nexus-updater[bot] 9450f686fe update(images): update Docker image versions 2026-06-24 02:17:50 +00:00
kevinveenbirkenbachandClaude Opus 4.8 9f43364c00 fix(apps): swarm-specific deploy fixes (matomo, nextcloud, prometheus, dashboard)
matomo: force-restart the swarm service after patching config.ini.php DB creds (the compose-up handler is a no-op in swarm), extracted into 10_resolve_host_cid. nextcloud: gate the redis PONG wait on the engine being local. prometheus: config 0444 (swarm config objects are root) and gate the host-monitor binds plus privileged cadvisor/node-exporter to compose only. dashboard: probe the public icon URL in swarm.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 19:29:39 +02:00
kevinveenbirkenbachandClaude Opus 4.8 bf32cab5ef fix(nextcloud): store the zammad OAuth client_id as a sensitive app value
The integration_zammad Connect flow reached the partner /oauth/authorize with a malformed client_id, so Zammad's Doorkeeper rejected the unknown client UID and 302-redirected to its homepage (the spec then captured the partner root, not the authorize page). The encrypted-appconfig helper stored the credentials via setValueString(..., lazy: true) WITHOUT sensitive: true, which mangled the client_id on read. Store it sensitive so the provisioned client_id round-trips intact and the OAuth authorize carries the correct UID.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 11:17:59 +02:00
kevinveenbirkenbachandClaude Opus 4.8 196074cdd0 fix(nextcloud): register both oauth-redirect variants for gitlab/mattermost/openproject
Nextcloud runs pretty-URLs (front_controller_active), so each integration app emits its oauth-redirect WITHOUT /index.php at runtime. The partner OAuth apps were registered with only the /index.php variant, so exact-match validation rejected the real callback and the per-user connect silently failed while the deploy and Playwright specs went green. Register both variants (the no-/index.php one first). Build the list on the consumer side (Doorkeeper newline-join for gitlab, native JSON callback_urls array for mattermost, Doorkeeper for openproject) to avoid newline-in-argv.

SuiteCRM is unaffected (OAuth2 password grant, no redirect_uri); the Nextcloud->OpenProject client callback is an OpenProject URL and is left untouched. Also drop the Doorkeeper>=5 hashed-secret fallback in the gitlab provisioner so a missing plaintext secret fails loudly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 02:50:57 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4c1b41418d feat(nextcloud): zammad OAuth provisioning + strengthen peertube addon spec
Provision a Doorkeeper OAuth application on the partner Zammad and write its client_id/client_secret into integration_zammad (Nextcloud-encrypted), so the per-user OAuth connect flow has the credentials the generic SPOT cannot supply. Register both the pretty-URL and /index.php oauth-redirect variants, and drop the hashed-secret fallback so a missing plaintext secret fails loudly instead of persisting an unusable hash.

Strengthen the integration_peertube spec: pin the admin 'instances' value to the exact deployed partner host (new PEERTUBE_BASE_URL) instead of merely 'not Nextcloud', and add a functional OCS search-providers check that fails when the PeerTube provider is not registered. PeerTube has no per-user OAuth (verified upstream: no client_id/oauth_instance_url config, no /oauth/authorize route), so the removed Connect->/oauth/authorize assertion tested a non-existent flow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 02:50:57 +02:00
kevinveenbirkenbachandClaude Opus 4.8 87f2ffc745 fix(test): notification-2FA spec asserts registration, not the enable control
The personal-security enable control for twofactor_nextcloud_notification
only renders once the provider is activatable, which needs a SECOND active
session to receive the approval notification — impossible in a single-session
E2E (the provider state is correctly false there). The addon hook already
proves registration via occ twofactorauth:state; the browser-observable
equivalent is that the provider state element is surfaced, so assert
toBeAttached, not toBeVisible. Verified in-container: nextcloud v1 suite
31 passed, 0 failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 13:36:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 4136641164 fix(nextcloud): gate fileslibreofficeedit on OnlyOffice absence
OnlyOffice declares fileslibreofficeedit (and richdocuments) incompatible and
disables them on install, so the LibreOffice editor's E2E spec failed wherever
OnlyOffice was co-deployed. Enable fileslibreofficeedit only when the OnlyOffice
addon is off (addons.onlyoffice.enabled), and add the required service-coupled
addon integration hook.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 12:36:09 +02:00
kevinveenbirkenbachandClaude Opus 4.8 266697d302 fix(nextcloud): override only dynamic variant flags; repack to 5 variants
mariadb.enabled is a static literal in meta/services.yml, so variants must not
pin it (test_variants_no_static_override). Regenerate variants.yml overriding
only the dynamic flag per service (mariadb keeps shared-only). With mariadb
correctly always-on and flowise+openwebui sharing ollama, the bond<1 partners
repack into 4 bins -> 5 variants (v0 coupled baseline + 4 partner bins), each
under the 73GB/37GB host budget.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 b28436e8f9 test(variants): make the closure bond-aware + add the bond-baseline contract
test_order now only pulls bond>=1 (tightly-coupled, same-host) services into a
role's closure; bond<1 partners deploy on their own host and are excluded, so a
later variant may enable them without variant 0 having to list them.

New test_bond_baseline enforces the placement: a bond>=1 dynamic flag must be
pinned true in variant 0 (the host baseline); a bond<1 flag must be pinned true
in at least one variant. Escape: '# nocheck: bond-baseline'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 6b7c79edb1 test(lint): forbid addon 'enabled' deriving from group_names
An addon's enabled flag must defer to the owning role's service flag
(lookup config services.<x>.enabled), a literal true/false, or api lookups —
never a raw '<role>' in group_names test. group_names belongs in
meta/services.yml (the SPOT); addons read the resolved flag so one source
decides partner presence. New lint scans roles/*/meta/addons/*.yml (87 files)
with a '# nocheck: addon-enabled-group-names' escape.

deck.yml is the one legitimate exception (anti-dependency on web-app-taiga,
which has no nextcloud service flag) and is nochecked accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:19 +02:00
kevinveenbirkenbachandClaude Opus 4.8 71870fd46b fix(nextcloud): disable moodle + suitecrm bridges (no nc-33 plugin)
integration_moodle has no Nextcloud-33-compatible release on the app store
(absent for nc 30/32/33) and integration_suitecrm requires nc <= 24, so both
bridges cannot work on the deployed Nextcloud 33. Set enabled/shared to false
(nocheck: dynamic-flag, like minio) so neither partner is pulled or bridged,
with a TODO to re-enable once a compatible plugin ships. Verified against the
Nextcloud app store nc-33 compatibility list; all other bridges (discourse,
matrix, peertube, mattermost, mastodon, zammad, openai, openproject, gitlab,
github, google, jira, bbb, xwiki) have real nc-33 releases and stay enabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 e8766cb427 feat(nextcloud): set bridged-partner service bonds to reflect loose host coupling
Bridged partner services (openproject, gitlab, mattermost, matrix, zammad,
openwebui, flowise, mastodon, peertube, moodle, suitecrm) get bond: 0.5 and
discourse bond: 0.3 — they are loosely coupled (separate host), unlike the
tightly-coupled bond: 1 infra. Services stay dynamic ({{ '<role>' in
group_names }}).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:18 +02:00
kevinveenbirkenbachandClaude Opus 4.8 fc5ad87dc5 feat(roles): make referenced partner services proper shared providers
Declare the 14 services that consuming roles reference but no role provided
(bigbluebutton, xwiki, openproject, gitlab, mattermost, matrix, zammad,
openwebui, flowise, peertube, moodle, suitecrm, redis, memcached) as shared
providers: set enabled/shared/bond on each entity so the service registry
registers them and the dangling references resolve.

Add test_shared_service_provider.py (lint): fail when a referenced shared
service has no provider and its name matches a role's entity/provider that does
not register it (suppressable via '# nocheck: shared-provider').

Guard the 9 web-app shared services with the run-once 01_core.yml pattern
(main.yml includes 01_core.yml only when run_once_<role> is undefined; the core
flags itself via utils/once/flag.yml) so they deploy once when pulled in by
multiple consumers. svc-db-redis/memcached are template-only (no runtime tasks).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:17 +02:00
kevinveenbirkenbachandClaude Opus 4.8 3fa781004d feat(roles): add bond integration-importance factor to shared services
`bond` is a 0..1 factor for how strongly a service is tied to the overall
integration: bond: 1 = always required, bond: 0 = omittable. Groundwork for
tooling that later scores service importance and decides what can be dropped.
Named `bond` (not `bound`) to avoid clashing with the resource bounds/limits.

Add test_service_bond.py (lint): every enabled + shared service must declare a
valid `bond` (number in 0..1). Seed `bond: 1` as a placeholder on all 638
enabled+shared service entries across 88 roles, to be refined later.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:17 +02:00
kevinveenbirkenbachandClaude Opus 4.8 a71cf55844 style(web-app-nextcloud): autoformat-wrap integration_openai configvalue
mbake line-wrap of the long configvalue jinja expression. Cosmetic only;
the rendered value is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:16 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1a1a02a2d6 fix(web-app-nextcloud): drop dead popup reference in openproject spec
Leftover 'if (popup) await popup.close()' referenced a variable removed
together with the connect-button/popup OAuth flow -> eslint no-undef ->
lint-javascript red -> make test red. make test is green again. No change
to the spec's assertions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:16 +02:00
kevinveenbirkenbachandClaude Opus 4.8 01f0b8686a fix(web-app-nextcloud): assert openproject admin OAuth coupling, not a connect button
OpenProject's integration_openproject renders no 'Connect to OpenProject'
button on connected-accounts (unlike discourse/gitlab/mattermost); the
connection happens via the Files smart-picker / the OpenProject side. The
spec's connect-button + OAuth-authorize popup flow tested non-existent UI.

Assert the real provisioned bidirectional coupling instead, read from the
admin initial-state config: openproject_instance_url (partner host),
openproject_client_id, openproject_client_secret, authorization_method=oauth2.

NOTE: NOT yet verified green live -- the compose-playwright verify run was
OOM-killed (exit 137) before finishing. High confidence by logic only: in the
prior run this spec already passed the instance-URL check (same JSON.parse
path), failing only on the now-removed connect-button assertion, and all
asserted fields are confirmed present in the decoded admin config. Re-run a
scoped verify to confirm before relying on it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:16 +02:00
kevinveenbirkenbachandClaude Opus 4.8 ed4b061408 fix(web-app-nextcloud): store integration OAuth creds Nextcloud-encrypted
integration_gitlab/integration_mattermost read client_id/client_secret via
crypto->decrypt(appConfig->getValueString(lazy:true)). Provisioning set them
with 'config:app:set --sensitive', the wrong scheme -> "Authenticated
ciphertext could not be decoded" -> the connected-accounts admin page 500s,
cascading onto the discourse/matrix/mattermost addon specs.

Add set_encrypted_appconfig.php (crypto->encrypt + appConfig setValueString
lazy -- the exact scheme the apps' setEncryptedAppValue uses) and route both
provisioning hooks through it. Verified live: gitlab client_id is now an
encrypted blob and connected-accounts renders again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:16 +02:00
kevinveenbirkenbachandClaude Opus 4.8 6fea999e93 fix(tests): make make test green (eslint + env order + autoformat)
- discourse-activity-pub, integration_matrix specs: drop unused catch
  binding and useless json init (eslint no-unused-vars/no-useless-assignment)
- openwebui playwright.env.j2: order OLLAMA_SERVICE_ENABLED after
  OIDC_ISSUER_URL (env keys must be ASC, test_alphabetical_sort)
- test_addon_env_flags.py: autoformat

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:16 +02:00
kevinveenbirkenbachandClaude Opus 4.8 d5ef4c1327 fix(web-app-nextcloud): correct addon spec selectors against live DOM
The drawio/files_bpm/external/fileslibreofficeedit/whiteboard addon specs
asserted guessed routes/selectors that do not exist on the live stack.
Verified against the running Nextcloud (make compose-playwright):
- drawio, fileslibreofficeedit: no standalone app route -> assert the app
  is registered+enabled in OC.appswebroots (Files file-action apps)
- files_bpm: modeler surface is #bpmn-app, not #canvas.bpmn-canvas
- external: admin section is #external + #add_external_site
- whiteboard: backend URL is injected in #initial-state-whiteboard-url

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:16 +02:00
kevinveenbirkenbachandClaude Opus 4.8 06aa25c095 feat(ai): integrate OpenWebUI/Ollama as a real integration_openai backend + chat test
- svc-ai-ollama variant-0: preload smollm2:135m (smallest instruct model for CI)
- integration_openai meta: Service URL -> {base}/api for the OpenWebUI backend
- web-app-openwebui: enable_api_keys config flag (services.yml + vars) rendered into
  ENABLE_API_KEYS so sk- API keys authenticate against the OpenAI-compatible API
- integration_openai spec: drop the DOM-gated skip, assert the partner backend host
  (openwebui chat.ai / flowise flow.ai), distinct from Nextcloud
- openwebui: OLLAMA_SERVICE_ENABLED playwright flag + test-ollama-chat.js asserting
  the preloaded model answers a chat completion over OpenWebUI -> Ollama

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:15 +02:00
kevinveenbirkenbachandClaude Opus 4.8 dec65ae175 test(web-app-nextcloud): xwiki spec asserts the admin instances table + partner coupling
Drop the DOM-gated skip; assert the xwiki admin instances table renders (route not
404), no 'no wikis registered' placeholder, and a configured instance-url input
whose host is the XWiki partner, not Nextcloud.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:14 +02:00
kevinveenbirkenbachandClaude Opus 4.8 59ee61ddfa test(web-app-nextcloud): whiteboard spec asserts the admin settings + collab backend URL
Replace the generic Files-app check with the app's own settings/admin/whiteboard
section and assert the collab-backend URL field is present and non-blank, proving
the plugin_configuration reached the running app.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:14 +02:00
kevinveenbirkenbachandClaude Opus 4.8 9a23ef4bd2 test(web-app-nextcloud): spreed spec keeps the deterministic HPB partner coupling
Keep the deterministic config coupling (OCS spreed signaling capability + the Talk
admin TURN server pinned to the web-svc-coturn partner host, STUN server, signaling
host) with a best-effort live 'Test this server' check; drop the comment blocks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:14 +02:00
kevinveenbirkenbachandClaude Opus 4.8 cf19e242c5 test(web-app-nextcloud): richdocuments spec asserts the Collabora WOPI partner coupling
Assert the admin section renders, the wopi_url field carries a real partner URL
whose host is distinct from Nextcloud, and the Collabora connection-failure banner
stays absent, proving the connector reached the partner WOPI server.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:14 +02:00
kevinveenbirkenbachandClaude Opus 4.8 dd1e42f065 test(web-app-nextcloud): recognize spec asserts its admin settings UI mounts
Assert the recognize admin Vue component (#recognize) and its own Face-recognition
section render, not the generic settings shell.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:14 +02:00
kevinveenbirkenbachandClaude Opus 4.8 2d9bc895ed test(web-app-nextcloud): onlyoffice spec asserts a document opens in the partner editor
Replace the config-presence check with a real round trip: upload a valid .docx,
open it, and assert the ONLYOFFICE editor iframe is served by the web-svc-onlyoffice
partner host, shows no JWT/download error, and renders its editor surface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:14 +02:00
kevinveenbirkenbachandClaude Opus 4.8 396968016d test(web-app-nextcloud): metadata spec asserts the metadata provider bundle is loaded
Assert the metadata app is registered in OC.appswebroots and its own frontend
bundle (apps/metadata/...) is injected into the Files page, proving the provider is
loaded and coupled, not just listed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 88f8eb08d8 test(web-app-nextcloud): integration_zammad spec asserts the real Zammad OAuth coupling
Drop the best-effort early-return; assert the admin instance URL is the partner
(not Nextcloud) and the per-user connect drives the partner /oauth/authorize with
the provisioned client_id + response_type=code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 7597888a22 test(web-app-nextcloud): integration_peertube spec asserts the real PeerTube OAuth coupling
Drop the DOM-gated skip; assert the admin panel exposes the provisioned partner
instances list (distinct from Nextcloud) and the per-user connect drives the OAuth
authorize on the partner instance with the provisioned client_id + response_type=code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c83d700afc test(web-app-nextcloud): groupfolders spec asserts the admin app mounts
Assert the groupfolders admin Vue app (#groupfolders-wrapper/#groupfolders-root)
mounts, not the generic settings shell, proving the app is installed and enabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 7608f94e5f test(web-app-nextcloud): fileslibreofficeedit spec asserts its admin settings section renders
Target the app's own settings/admin/fileslibreofficeedit route (not 404) and assert
its LibreOffice editor admin panel and document-editor server URL field render.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 67398cff8d test(web-app-nextcloud): files_linkeditor spec asserts its New-link menu entries register
Open the Files New menu and assert the 'New link (.URL)' and 'New link (.webloc)'
entries the app injects are present, proving its frontend bundle loaded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 9d6ec1ccf9 test(web-app-nextcloud): files_bpm addon spec asserts the BPMN modeler canvas renders
Target the app's own apps/files_bpm/ route (not the generic Files app) and assert
it resolves (not 404) and the #canvas.bpmn-canvas modeler surface renders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 a345d7a482 test(web-app-nextcloud): external addon spec asserts the External-sites admin panel renders
Target the app's own settings/admin/external section and assert its description
text and 'New site' action render, proving the external app's section and template
are served by the enabled app (not the generic additional-settings shell).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:13 +02:00
kevinveenbirkenbachandClaude Opus 4.8 9d787ff03b test(web-app-nextcloud): event_update_notification spec asserts it is an enabled app
The app is backend-only (no user route); assert via the Provisioning OCS registry
that event_update_notification is in the enabled-apps list and not in the disabled
list, so a disabled/absent app fails.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:12 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1f474d070e test(web-app-nextcloud): epubviewer addon spec asserts the reader panel + persisted config
Drop the DOM-gated skips; assert the settings/user/epubviewer section resolves
(not 404), the #reader-personal panel renders, and the #EpubEnable checkbox
reflects the persisted user config.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:12 +02:00
kevinveenbirkenbachandClaude Opus 4.8 b33a8ff85e test(web-app-nextcloud): drawio addon spec asserts the drawio editor surface renders
Drop the DOM-gated skips; assert the apps/drawio/ route resolves (not 404) and the
drawio-specific editor surface mounts, so a disabled/broken app fails.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:12 +02:00
kevinveenbirkenbachandClaude Opus 4.8 5fcfdc7577 test(web-app-nextcloud): bbb addon spec asserts the cloud_bbb app UI renders and is coupled
Navigate to apps/bbb/ and assert the cloud_bbb app shell + its own room-management
surface render, in addition to the admin api.url/api.secret partner coupling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:12 +02:00
kevinveenbirkenbachandClaude Opus 4.8 c9a431e298 fix(web-app-nextcloud): make integration_openproject NC OAuth2 client step best-effort
Push the OpenProject OAuth credentials (authorization_method, openproject_client_id,
openproject_client_secret) into Nextcloud before the NC OAuth2 client step so the
forward connect is always provisioned. The reverse-direction Nextcloud OAuth2 client
relies on occ oauth2:add-client, which Nextcloud 33 does not ship, so it is now
failed_when: false with its dependents in a guarded block — the deploy completes
instead of aborting before the Playwright suite runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:10 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1d6bc786ff refactor(web-app-nextcloud): drop redundant | default('') on always-set register stdouts
The integration_openproject / integration_gitlab provisioning and the user_ldap
config probe read their state with tasks that always run (no when:) and
failed_when: false, so their .stdout is always defined; 'X.stdout | default('') |
trim' is identical to 'X.stdout | trim'. Remove the dead default('').

Genuinely-guarding defaults are kept: the s01 config-id fallback, the skippable
ldap auto-create stdout/stderr, the regex_search None guards, and the outer
default(..., true) fresh-or-persisted secret fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:10 +02:00
kevinveenbirkenbachandClaude Opus 4.8 38796b77a5 fix(web-app-nextcloud): recover integration_openproject OAuth secret on re-deploy
OpenProject only returns a fresh OAuth client secret when the application is first
created; on a re-deploy where the app already exists but Nextcloud never persisted
the secret (e.g. an earlier deploy failed downstream at the storage step), the
secret is unrecoverable and the provisioning assert tripped, aborting the play
before the Playwright suite ran.

ensure_nextcloud_storage.rb now destroys and recreates the OAuth application when
it exists but Nextcloud holds no secret (gated to the first call via the absent NC
client id), so a fresh secret is always emitted. The provision task passes the
persisted-secret read as NC_HAS_OP_SECRET only on that first call so the second
(client-register) call never destroys the freshly created app. Verified
in-container: the recovery path emits a fresh openproject_client_secret.

Also drops the redundant | default('') on the always-set
nextcloud_op_client_secret_current.stdout in this file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:10 +02:00
kevinveenbirkenbachandClaude Opus 4.8 1496174e29 test(web-app-nextcloud): real integration_moodle token round-trip coupling
Drive the real bridge: pin the per-user #moodle-url to the deployed partner
Moodle host (distinct from Nextcloud), persist it, then Connect and assert the
POST /apps/integration_moodle/get-token response is a genuine partner verdict
(200 with user_name minted by the partner webservice, or 401 partner-refused) —
proving the request reached the partner Moodle, not a local stub. bridges:
[moodle] means the deployment gate skips it when the partner is not deployed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:10 +02:00
kevinveenbirkenbachandClaude Opus 4.8 2a8e11462c test(web-app-nextcloud): real integration_mattermost OAuth coupling
Assert the admin oauth_instance_url points at the partner Mattermost host (not
Nextcloud) and the admin panel exposes the provisioned OAuth client, and the
per-user connect drives an OAuth authorize redirect to that partner host with
the provisioned client_id + response_type=code. Backed by the
integration_mattermost_provision hook; bridges: [mattermost] with the partner in
the deploy set means this runs live and fails if provisioning or the connect is
broken.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:10 +02:00
kevinveenbirkenbachandClaude Opus 4.8 2c39e18478 test(web-app-nextcloud): real integration_matrix homeserver coupling
Drop the DOM-gated skip; assert the admin Matrix panel renders, the configured
homeserver is the deployed partner (distinct from Nextcloud), and the per-user
connect drives a real session against the partner homeserver (a browser
/_matrix/client/ call to the partner, or the nextcloud integration_matrix
connect round-trip). bridges: [matrix] with the partner in the deploy set means
this runs live and fails on a broken coupling instead of skipping on the DOM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:03:10 +02:00