mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-07 19:32:17 +00:00
fix/dev-python/python-upper-bound
18
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
328113e7c3 |
refactor(ai): declare the litellm consumer contract once
Fourteen roles repeated the same two lines to say they use the gateway: a
`shared` flag gated on group_names, and an `enabled` flag conjoining that gate
with LITELLM_CHAT_MODEL_SERVED. Both are now single-sourced.
`shared` becomes literal true. The flag means the provider is a shared instance
rather than one deployed per consumer, and a central gateway is always that;
the dynamic form only said "shared if deployed", which `enabled` already
decides. The 50 shared pins under `litellm:` leave meta/variants.yml with it.
The tree had already noticed: 20 of those 50 lines carried
`# nocheck: variants-static-override`, two of them with copy-pasted text about
container_backup. This narrows
|
||
|
|
7162b7bf4c |
Merge fork/feature/svc-net-tor into feature/ai-agent-employees
834 commits from the Tor onion-service branch against 299 of ours, from merge base |
||
|
|
2c5ad70d24 |
feat(discourse): register the platform gateway as the Discourse AI model
Discourse AI is configured through an LlmModel row rather than settings, so the addon upserts one via rails: provider open_ai, the gateway's chat-completions URL, the model the gateway serves, and this role's virtual key. It then binds that row to ai_default_llm_model and to the bot, because a model that exists but is bound to nothing serves no surface. llm_models.url is POSTed verbatim, so DISCOURSE_LITELLM_CHAT_ENDPOINT carries the full /v1/chat/completions path rather than a base URL. Every other consumer in this requirement takes a base and appends; getting this one wrong produces a 404 at prompt time, long after a green deploy. Three things had to be cleared before any of that could work. Discourse refuses to call a private address unless the host is in allowed_internal_hosts, and it fails as an opaque provider error rather than as a blocked request. The script appends the gateway host to that list and leaves existing entries alone, which matters because the OIDC bootstrap in config.yml.j2 appends the discovery host to the same pipe-separated setting. Both sides check membership before adding, so they compose instead of clobbering each other. The launcher-managed container sits outside the compose graph and does not join the gateway network on its own. handlers/stack_host.yml adds DISCOURSE_LITELLM_NETWORK to its network list and config.yml.j2 passes the matching --network flag, both only while litellm is enabled. The bootstrap aborted before the plugin could install at all. after_code cloned every enabled plugin unconditionally, but a bundled plugin already sits in $home/plugins, git exits non-zero on the clone, and the whole bootstrap stops. discourse-ai is bundled in current images, so it now skips plugins whose source is bundled. mem_limit goes from 2g to 4g. `rails r` boots a second Rails inside the container already running unicorn and sidekiq, and at 2g the kernel kills it mid-run: measured in deploy-036-11 and again in deploy-ai-v2-7, where the task died with "Killed" and the deploy ended at exit 137. Upstream documents 4 GB as Discourse's own minimum, so this corrects an under-provisioned limit rather than working around the task. The variant resource budget still passes. Verified: the OOM with the exact task and exit code across two independent runs, the bundled-plugin abort, and that the budget test holds at 4g. Not verified: the registration has never completed, because every attempt so far died at the OOM first. The eight-fact read-back assertion and addons/discourse-ai.spec.js are both entirely unexercised, the spec because the addon bridge gate had it skipping. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e16eb5728d |
test(lint): drop the minimal variant's exemption from the onion
72fd9c870 required the onion in every variant but exempted variant 1, on the
argument that the minimal round is the one place the stack runs without it. That
argument does not hold: the onion is part of the deployment under test, not a
feature bolted onto the full shape. A round that skips it is not a smaller
deployment, it is a different one.
So the exemption is gone and 95 variant-1 entries pin the onion on. Two
exclusions remain, both read from data rather than a comment: a role with no tor
block has no onion to pin, and a role whose meta/services.yml pins tor.enabled to
a literal false has already declared it has none.
That put the rule in conflict with test_coverage, which requires both polarities
of every dynamic flag: with tor on everywhere, the false side has no variant left
to live in. 94 roles take the exemption that contract already provides for
exactly this - "flags whose group-derived value is a hard invariant that variants
must never override", the same one
|
||
|
|
ab72cff929 |
test(lint): require the onion in every variant, not just SSO ones
|
||
|
|
d88f272f9f |
Merge branch 'feature/swarm-nfs' into feature/svc-net-tor
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
3875eb2cf9 |
feat(variants): pin container_backup per matrix variant
Variant 0 pins the backup consumer flag enabled so the matrix baseline exercises the in-group branch; every other variant pins it disabled (shared: false carries the static-override suppression since the base value stays literally true). The matrix and wordpress variant entries move their services mapping to the list-item head so the static-override line parser resolves the override paths; yaml semantics are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1d9d355bc9 |
feat(tor): add onion on/off variant coverage to domain roles
Each role's meta/variants.yml now pins the tor onion gate both ways so the matrix exercises it: variant 0 pins services.tor.enabled: true, every non-baseline variant pins enabled: false + shared: false (# nocheck: variants-static-override, since tor.shared is a static literal). This gives real test_coverage / test_bond_baseline coverage without the removed per-key code exemptions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
f4774ec145 |
refactor(apps): remap consumers to central engines
About 38 web-app/web-svc roles now consume the central svc-db-* and svc-dns engines via lookup('engine', ...) instead of embedded sidecars: meta/services flags, variant matrices, and env/conf hosts point at the shared services. Lets these apps run unpinned and NFS-shareable in swarm.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
24d4ab8e4a |
refactor(sso)\!: collapse oauth2 + oidc into unified services.sso block (req 21)
Implements docs/requirements/021-sso-flavor-migration.md atomically:
* Schema: every role's meta/services.yml replaces the parallel
`oauth2:` / `oidc:` top-level blocks with a single `sso:` block
carrying `enabled`, `shared`, and a `flavor` discriminator
(`oidc` | `oauth2` | `saml`; default `oidc`). Flavor-specific
sub-keys live under `sso.<flavor>.*` (`sso.oauth2.{origin,acl,
allowed_groups}`, `sso.oidc.plugin`).
* Provider role: roles/web-app-oauth2-proxy/ is deleted in its
entirety; its 5 sidecar templates move under
roles/web-app-keycloak/templates/sso_proxy/, and the per-consumer
rendering task lives at roles/web-app-keycloak/tasks/sso_proxy.yml.
web-app-keycloak now declares `provides: sso`.
* Runtime: new resolver utils/roles/applications/services/sso.py
centralises the SSO predicates (`is_enabled`, `is_proxy_gated`,
`is_oidc_native`) and the oauth2 sub-values
(`oauth2_origin_{host,port}`, `oauth2_acl`, `oauth2_allowed_groups`).
Three lookup plugins consume the resolver: `sso` (single-app
predicate access), `sso_proxy_consumers` (enumerates oauth2-flavored
consumers), `sso_oidc_plugin` (renamed from `oidc_flavor`, Nextcloud
plugin selector). sys-stk-backend, sys-svc-compose, sys-svc-proxy
and plugins/filter/compose_volumes.py all gate on
`lookup('sso', ..., 'is_proxy_gated')` instead of manually combining
`enabled` and `flavor`.
* Identifier renames repo-wide: `services.<entity>.ports.local.oauth2`
→ `ports.local.sso`; `PORT_BANDS.local.oauth2` → `PORT_BANDS.local.sso`;
`OAUTH2_PROXY_*` env/Jinja vars → `SSO_PROXY_*`;
`oauth2_proxy_cookie_secret` → `sso_proxy_cookie_secret`;
`OAUTH2_SERVICE_ENABLED` + `OIDC_SERVICE_ENABLED` collapse into
`SSO_SERVICE_ENABLED`; Playwright gating helpers
(isServiceEnabled/skipUnlessServiceEnabled/requireService/safeIsEnabled/
safeSkipUnlessEnabled) move from `oidc`/`oauth2` to `sso`.
* Dual-block resolution: per req's Background-Table, web-app-bookwyrm
is `flavor: oauth2`; web-app-gitea and web-app-friendica keep
`flavor: oauth2` with their existing `oauth2.acl.blacklist`
(/user/login) and `oauth2.acl.whitelist` (federation + discovery
endpoints) — preserving the operative oauth2-proxy gating.
* Tests: the two mutual-exclusion guards
(tests/integration/iam/oauth2_oidc/test_mutual_exclusive.py and
test_acl_mutual_exclusive.py) are deleted per Decision #10;
test_oauth2_contract.py is renamed and rewritten to
test_sso_contract.py, asserting that `flavor: oauth2` roles carry
`oauth2.origin.{host,port}` plus `ports.local.sso`; test_sso.py
(web-app integration) now requires the unified `sso:` block with an
explicit flavor or a `# nocheck: sso` opt-out; new
tests/lint/repository/no_legacy_sso_paths/ guards the source tree
against re-introducing the legacy strings.
* Docs: req 21 itself has every AC checked off, and reqs 006, 008,
009, 013, 015, 016, 019, 020 plus 10+ role READMEs and
docs/contributing/actions/testing/suppression.md are updated to the
unified SSO naming.
Empirically validated end-to-end against the validation app set
(web-app-keycloak, web-app-nextcloud, web-app-bookwyrm, web-app-gitea,
web-app-friendica, web-app-dashboard) in matrix variants 0 and 1; v2
also passes the 4 target roles' Playwright after a documented
pre-existing KC_HOSTNAME-drift workaround (separate concern, not
caused by this refactor).
BREAKING CHANGE: every consumer of `services.oauth2.*`,
`services.oidc.*`, `OAUTH2_PROXY_*`, `OAUTH2_SERVICE_ENABLED`,
`OIDC_SERVICE_ENABLED`, `oauth2_proxy_cookie_secret`,
`oauth2_proxy_application_id`, `ports.local.oauth2`, the
`web-app-oauth2-proxy` role, or the legacy gating helper service names
(`oidc`/`oauth2`) must migrate to the unified `sso` shape documented
in docs/requirements/021-sso-flavor-migration.md.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
300ea0a054 |
feat(sys-svc-rdbms): build per-consumer postgres image with required libraries for shared:false
Generalises the postgres image build to be driven by a declarative extension→library registry instead of a hardcoded POSTGRES_VECTOR_ENABLED flag. Same Dockerfile.j2 now serves both the central svc-db-postgres image (libraries aggregated across all deployed consumers) and per- consumer images for shared:false postgres consumers whose extensions need libraries not in the postgis/postgis base (e.g. pgvector). postgres.yml.j2 switches between image: and build: based on whether custom libraries are needed. New postgres_libraries lookup filters base-image extensions out and returns recipes for the rest. Dedicated task path extracted into dedicated.yml + dedicated_postgres.yml so the block-with-when size limit stays satisfied and the postgres-type check happens once. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
40cde27eef |
fix(web-app-odoo): collapse generic biber+admin persona tests via PERSONA_*_BLOCKED
The generic `runBiberFlow` / `runAdminFlow` helpers in
roles/test-e2e-playwright/files/personas/{biber,admin}.js single-click
the role's "Sign In" link and expect the next URL to contain
`openid-connect/auth`. Odoo's login page is a two-step OIDC flow
(landing → username/password form with OIDC button below → click OIDC
button → Keycloak), which the helper does not navigate. The
`biber/administrator: app → universal logout` tests fail with
`no in-app logout control reachable on the current authenticated
surface` because the test lands back on the public Odoo landing page.
The role already ships bespoke biber+admin coverage:
- `odoo: admin sso login, verify ui, logout`
- `odoo: biber sso login, verify ui, logout`
Both drive the full OIDC flow through Odoo's own login surface and
both have been passing in CI. The generic persona tests are
redundant for Odoo and add nothing on top.
Set `PERSONA_BIBER_BLOCKED=true` / `PERSONA_ADMINISTRATOR_BLOCKED=true`
in `templates/playwright.env.j2` so the generic helpers cleanly
`test.skip(...)` per the documented escape clause.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
96e6a3daa5 |
feat(web-svc-css): introduce canonical owner of the css service flag
Decouples the CSS service concept from its underlying transport
(currently `web-svc-cdn`) so the flag becomes opt-in via inventory
group membership instead of staying literal-`true` everywhere.
- `roles/web-svc-css/`: new role. Marker / wrapper role that owns
the `css` entry in the service registry, declares `web-svc-cdn` as
the upstream that serves the actual bytes, and 301-redirects its
own canonical domain to the cdn domain so health probes return a
valid response.
- `roles/web-svc-cdn/meta/services.yml`: drop the `css` block — the
canonical owner is now web-svc-css; cdn keeps `javascript`.
- 51 consumer roles (web-app-* and web-svc-{coturn,file,html,
libretranslate,logout,onlyoffice}) migrated their `css:` block from
literal `{ enabled: true, shared: true }` to dynamic
`{ enabled: "{{ 'web-svc-css' in group_names }}", shared: ... }`,
with matching matrix coverage added to each role's
`meta/variants.yml` (true-pinning + false-pinning entries) so the
dynamic-flag variant lint stays green.
- 41 `# nocheck: playwright-service-flag` rationale strings updated
from the now-incorrect "canonical:cdn alias of static-asset
provider" to "css consumer, no Playwright surface (provider:
web-svc-css)".
Bundled refactor: `roles/web-svc-asset/tasks/01_core.yml` now
includes `web-opt-rdr-domains` directly with a single-entry mapping
to redirect its canonical domain to web-svc-file, instead of having
that wiring live in the global `tasks/stages/01_constructor.yml`
constructor. The `add_redirect_if_group` filter
(`plugins/filter/redirect_filters.py`) and its unit test are dropped
as dead code — both call sites are now role-local.
Dashboard's consumption of the new pattern is intentionally not part
of this commit and follows separately.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
f45a6d4699 |
fix(web-app-discourse): pin postgres.shared:true + gate OIDC tests
CI run 25774452286 surfaced two distinct Discourse failures that share
the same root cause: variant 1's `postgres.shared: false` override
forced Discourse's launcher to fall back to its bundled postgres
image, which is vanilla and lacks the `vector` extension. Discourse's
`20230710171141 EnablePgVectorExtension` migration then aborted
`bundle exec rake db:migrate` with `Pups::ExecError` → `FAILED TO
BOOTSTRAP` (retried 4×), leaving the deploy red.
The central `svc-db-postgres` image, by contrast, is built with
pgvector compiled in (`roles/svc-db-postgres/templates/Dockerfile.j2`
clones github.com/pgvector/pgvector and `make install`s it). Pinning
`services.postgres.shared: true` in Discourse's `meta/services.yml`
and dropping the `postgres:` override from `meta/variants.yml` keeps
every variant on the pgvector-equipped central server, so the
migration succeeds unconditionally.
The second failure surfaced once the deploy got further: variant 1
also disables OIDC (`services.oidc.{enabled,shared}: false`), but the
spec's `administrator: dashboard to discourse OIDC login and logout`
and `biber: dashboard to discourse OIDC login and logout` ran
unconditionally, hitting 1.0-minute Playwright timeouts driving an
OIDC sign-in flow that has nothing to authenticate against. Add a
`test.skip(... OIDC_SERVICE_ENABLED ... \!== "true", ...)` guard at the
top of both tests so they skip cleanly when OIDC is disabled by
variant; the third scenario (`guest: public-landing → auth chain →
never authenticated`) does not need a guard because it only checks an
unauthenticated visit, which is meaningful with or without OIDC.
Local FULL_CYCLE PASS 1+2 succeed for both declared variants (v0+v1).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
951f6d36d2 |
chore(lint): unify autoformat/galaxy parallelism into one PARALLEL env var
* scripts/lint/autoformat.sh: rename AUTOFORMAT_PARALLEL to PARALLEL, declare it at file start with default `true`; still env-overridable. Reword the worker comment so the literal `# shellcheck` token no longer appears at start-of-line and trips SC1072/SC1073. * scripts/lint/galaxy.sh: drop the GALAXY_FATAL / GALAXY_NAMESPACE / GALAXY_PARALLEL env vars (over-engineered for a single repo). Failure is always fatal. NAMESPACE is an internal constant. Add the same PARALLEL env var (default `true`, env-overridable); falsy demotes the xargs fan-out to one worker. * docs/contributing/environment/variables.md: collapse the four AUTOFORMAT_*/GALAXY_* rows into one `PARALLEL` row covering both consumers. * docs/contributing/tools/make.md: refer to `PARALLEL=0` everywhere; add the lint-galaxy parallelism note. Plus working-tree drift across roles/, group_vars/, inventories/, and tasks/ that accumulated from the make-test setup phase regenerating generated artefacts during recent test runs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c5a4f5c667 |
fix(discourse): disable LDAP, drop ldap=true variants, document re-enable path
The jonmbake/discourse-ldap-auth plugin cloned in templates/config.yml.j2
no longer registers SiteSetting.ldap_auth_enabled on current Discourse,
so bootstrap aborts with `rails r "SiteSetting.ldap_auth_enabled = true"`
exit 1 (CI run 25567639207 / job 75058359158).
- meta/services.yml: services.ldap.{enabled,shared} pinned to literal
false (with a `# nocheck: dynamic-flag` marker), so the role no
longer attempts the broken LDAP bootstrap path. OIDC via Keycloak's
LDAP federation remains the canonical auth route.
- meta/variants.yml: ldap entries dropped from the all-true / all-false
variants and the dedicated ldap-only variant deleted entirely
(3 variants -> 2 variants). With ldap no longer dynamic in
services.yml, no polarity coverage is required.
- TODO.md: replaced "Finish LDAP implementation" with a concrete
five-step checklist for re-enabling LDAP later (pick a maintained
plugin, swap the URL, flip the services.yml pins back to dynamic,
re-add the variant entries, drop the nocheck marker).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
9e07353682 |
fix(roles): satisfy test_oidc_oauth2_ldap_variants_cover_auth_matrix in 25 roles
Two coupled deltas to ``meta/variants.yml`` across every role whose
``meta/services.yml`` declares ``oidc`` / ``oauth2`` / ``ldap`` via
the dynamic ``"… in group_names"`` shape:
1. **Pair-polarity backfill** in 14 roles whose existing all-true /
all-false reference variants only set ``shared`` (relying on
``services.yml``'s literal ``enabled: true # nocheck:
dynamic-flag``). The auth-coverage rule is stricter: it counts a
pair only when BOTH ``enabled`` AND ``shared`` are explicitly
pinned in the same variant entry. Added the missing ``enabled:
true`` (true-variant) / ``enabled: false`` (false-variant) for
``ldap`` (and ``oidc`` in friendica/gitea/bookwyrm). Touched
roles: web-app-{friendica, funkwhale, fusiondirectory, keycloak,
kix, lam, nextcloud, openproject, opentalk, phpldapadmin,
snipe-it, suitecrm, taiga} and web-svc-xmpp.
2. **LDAP-only third variant** in 25 roles where both an auth
service (``oidc`` / ``oauth2``) AND ``ldap`` are dynamic. The
variant pins ``ldap.enabled: true`` together with ``enabled:
false`` on every dynamic auth service in the same entry, so the
matrix exercises the LDAP-only branch in isolation from OIDC —
the explicit Playwright LDAP-coverage gap tracked by
docs/requirements/018-playwright-ldap-coverage.md. Touched roles:
web-app-{akaunting, baserow, bluesky, bookwyrm, discourse,
espocrm, flowise, friendica, funkwhale, fusiondirectory, gitea,
jenkins, kix, lam, minio, nextcloud, odoo, opencloud, openproject,
opentalk, openwebui, phpldapadmin, snipe-it, suitecrm, taiga}.
Mechanically applied via a one-off ruamel.yaml round-trip script
(comments and key order on existing variants survive); the new
ldap-only entries are a flat ``services:`` block at the end of each
file.
Verification: ``test_oidc_oauth2_ldap_variants_cover_auth_matrix``
passes; ``test_every_dynamic_flag_has_true_and_false_variant``
still passes; full integration suite is now ``172 tests, 0 failures,
1 skip`` — first time the suite is fully green on this branch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
0cc48be9ae |
test(integration): variants coverage + no-self-reference guards for services.yml
Two new integration lints under tests/integration/roles/meta/:
* test_variants_coverage.py — every services.yml flag declared via
the dynamic ``"{{ '<role>' in group_names }}"`` form MUST be
exercised by meta/variants.yml: at least one variant entry pins
it to literal ``true`` AND at least one pins it to ``false``.
Pairs may share variant entries — the test only checks the union
of all variants covers both polarities for every dynamic flag.
* test_services_no_self_reference.py — a role's own primary entity
(matching ``get_entity_name(role)``) MUST NOT use the dynamic form
for ``enabled`` / ``shared``. Both MUST be literal ``true``: the
role's own services.yml is loaded only when the role itself is in
group_names, so a ``'<self>' in group_names`` Jinja is tautological.
The dynamic-flag test now skips the role's own entity to avoid a
contradiction with this new guard.
Self-reference fixes (Jinja → literal ``true: true``) on 19 roles:
svc-ai-ollama, svc-db-{mariadb, openldap, postgres}, web-app-{
dashboard, discourse, keycloak, mailu, matomo, prometheus},
web-svc-{asset, cdn, collabora, coturn, file, libretranslate, logout,
onlyoffice, simpleicons}.
Variants coverage rollout (62 new + 17 merged meta/variants.yml):
* Roles without a pre-existing variants.yml get a new file with two
entries — one pinning every dynamic flag true, one pinning every
dynamic flag false. No ``- {}`` baseline (matrix runs only the
two coverage variants).
* Roles with a pre-existing variants.yml (akaunting/baserow/bluesky/
bookwyrm/flowise/fusiondirectory/jenkins/jira/joomla/keycloak/lam/
minio/phpmyadmin/postmarks/wordpress/web-svc-xmpp) keep their
matrix variants (OIDC vs LDAP, Single-Site vs Multisite, dev creds
+ TOTP-disabled realm, autologin, etc.); the all-true coverage is
deep-merged into variant 0 and the all-false coverage into
variant 1, so each role still ships exactly two matrix rounds.
* svc-ai-ollama keeps its single CI image-shrink variant; after the
self-reference fix it has no remaining dynamic flags so no extra
coverage entry is required.
* svc-db-{mariadb, openldap, postgres} drop variants.yml entirely
for the same reason.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|