Compare commits

...

1616 Commits

Author SHA1 Message Date
445c94788e Refactor: consolidate pkgmgr updates and remove legacy roles
Details:
- Added pkgmgr update task directly in pkgmgr role (pkgmgr pull --all)
- Removed deprecated update-pkgmgr role and references
- Removed deprecated update-pip role and references
- Simplified update-compose by dropping update-pkgmgr include

https://chatgpt.com/share/68bbeff1-27a0-800f-bef3-03ab597595fd
2025-09-06 10:46:39 +02:00
aac9704e8b Refactor: remove legacy update-docker role and references
Details:
- Removed update-docker role (README, meta, vars, tasks, script)
- Cleaned references from group_vars, update-compose, and docs
- Adjusted web-app-matrix role (removed @todo pointing to update-docker)
- Updated administrator guide (update-docker no longer mentioned)

Ref: https://chatgpt.com/share/68bbeff1-27a0-800f-bef3-03ab597595fd
2025-09-06 10:32:33 +02:00
a57a5f8828 Refactor: remove Python-based Listmonk upgrade logic and implement upgrade as Ansible task
Details:
- Removed upgrade_listmonk() function and related calls from update-docker script
- Added dedicated Ansible task in web-app-listmonk role to run non-interactive DB/schema upgrade
- Conditional execution via MODE_UPDATE

Ref: https://chatgpt.com/share/68bbeff1-27a0-800f-bef3-03ab597595fd
2025-09-06 10:25:41 +02:00
90843726de keycloak: update realm mail settings to use smtp_server.json.j2 (SPOT); merge via kc_merge_path; fix display name and SSL handling
See: https://chatgpt.com/share/68bb0b25-96bc-800f-8ff7-9ca8d7c7af11
2025-09-05 18:09:33 +02:00
d25da76117 Solved wrong variable bug 2025-09-05 17:30:08 +02:00
d48a1b3c0a Solved missing variable bugs. Role is not fully implemented need to pause development on it for the moment 2025-09-05 17:07:15 +02:00
2839d2e1a4 In between commit Magento implementation 2025-09-05 17:01:13 +02:00
00c99e58e9 Cleaned up bridgy fed 2025-09-04 17:09:35 +02:00
904040589e Added correct variables and health check 2025-09-04 15:13:10 +02:00
9f3d300bca Removed unneccessary handlers 2025-09-04 14:04:53 +02:00
9e253a2d09 Bluesky: Patch hardcoded IPCC_URL and proxy /ipcc
- Added Ansible replace task to override IPCC_URL in geolocation.tsx to same-origin '/ipcc'
- Extended Nginx extra_locations.conf to proxy /ipcc requests to https://bsky.app/ipcc
- Ensures frontend avoids CORS errors when fetching IP geolocation

See: https://chatgpt.com/share/68b97be3-0278-800f-9ee0-94389ca3ac0c
2025-09-04 13:45:57 +02:00
49120b0dcf Added more CSP headers 2025-09-04 13:36:35 +02:00
b6f91ab9d3 changed database_user to database_username 2025-09-04 12:45:22 +02:00
77e8e7ed7e Magento 2.4.8 refactor:
- Switch to split containers (markoshust/magento-php:8.2-fpm + magento-nginx:latest)
- Disable central DB; use app-local MariaDB and pin to 11.4
- Composer bootstrap of Magento in php container (Adobe repo keys), idempotent via creates
- Make setup:install idempotent; run as container user 'app'
- Wire OpenSearch (security disabled) and depends_on ordering
- Add credentials schema (adobe_public_key/adobe_private_key)
- Update vars for php/nginx/search containers + MAGENTO_USER
- Remove legacy docs (Administration.md, Upgrade.md)
Context: changes derived from our ChatGPT session about getting Magento 2.4.8 running with MariaDB 11.4.
Conversation: https://chatgpt.com/share/68b8dc30-361c-800f-aa69-88df514cb160
2025-09-04 12:45:03 +02:00
32bc17e0c3 Optimized whitespacing 2025-09-04 12:41:11 +02:00
e294637cb6 Changed db config path attribut 2025-09-04 12:34:13 +02:00
577767bed6 sys-svc-rdbms: Refactor database service templates and add version support for Magento
- Unified Jinja2 variable spacing in tasks and templates
- Introduced database_image and database_version variables in vars/database.yml
- Updated mariadb.yml.j2 and postgres.yml.j2 to use {{ database_image }}:{{ database_version }}
- Ensured env file paths and includes are consistent
- Prepared support for versioned database images (needed for Magento deployment)

Ref: https://chatgpt.com/share/68b96a9d-c100-800f-856f-cd23d1eda2ed
2025-09-04 12:32:34 +02:00
e77f8da510 Added debug options to mastodon 2025-09-04 11:50:14 +02:00
4738b263ec Added docker_volume_path filter_plugin 2025-09-04 11:49:40 +02:00
0a588023a7 feat(bluesky): fix CORS by serving /config same-origin and pinning BAPP_CONFIG_URL
- Add `server.config_upstream_url` default in `roles/web-app-bluesky/config/main.yml`
  to define upstream for /config (defaults to https://ip.bsky.app/config).
- Introduce front-proxy injection `extra_locations.conf.j2` that:
  - proxies `/config` to the upstream,
  - sets SNI and correct Host header,
  - normalizes CORS headers for same-origin consumption.
- Wire the proxy injection only for the Web domain in
  `roles/web-app-bluesky/tasks/main.yml` via `proxy_extra_configuration`.
- Force fresh social-app checkout and patch
  `src/state/geolocation.tsx` to `const BAPP_CONFIG_URL = '/config'`
  in `roles/web-app-bluesky/tasks/02_social_app.yml`; notify `docker compose build` and `up`.
- Tidy and re-group PDS env in `roles/web-app-bluesky/templates/env.j2` (no functional change).
- Add vars in `roles/web-app-bluesky/vars/main.yml`:
  - `BLUESKY_FRONT_PROXY_CONTENT` (renders the extra locations),
  - `BLUESKY_CONFIG_UPSTREAM_URL` (reads `server.config_upstream_url`).

Security/Scope:
- Only affects the Bluesky web frontend (same-origin `/config`); PDS/API and AppView remain unchanged.

Refs:
- Conversation: https://chatgpt.com/share/68b8dd3a-2100-800f-959e-1495f6320aab
2025-09-04 02:29:10 +02:00
d2fa90774b Added fediverse bridge draft 2025-09-04 02:26:27 +02:00
0e72dcbe36 feat(magento): switch to ghcr.io/alexcheng1982/docker-magento2:2.4.6-p3; update Compose/Env/Tasks/Docs
• Docs: updated to MAGENTO_VOLUME; removed Installation/User_Administration guides
• Compose: volume path → /var/www/html; switched variables to MAGENTO_*/MYSQL_*/OPENSEARCH_*
• Env: new variable set + APACHE_SERVERNAME
• Task: setup:install via docker compose exec (multiline form)
• Schema: removed obsolete credentials definition
Link: https://chatgpt.com/share/68b8dc30-361c-800f-aa69-88df514cb160
2025-09-04 02:25:49 +02:00
4f8ce598a9 Mastodon: allow internal chess host & refactor var names; OpenLDAP: safer get_app_conf
- Add ALLOWED_PRIVATE_ADDRESSES to .env (from svc-db-postgres) to handle 422 Mastodon::PrivateNetworkAddressError
- Switch docker-compose to MASTODON_* variables and align vars/main.yml
- Always run 01_setup.yml during deployment (removed conditional flag)
- OpenLDAP: remove implicit True default on network.local to avoid unintended truthy behavior

Context: chess.infinito.nexus resolved to 192.168.200.30 (private IP) from Mastodon; targeted allowlist unblocks federation lookups.

Ref: https://chat.openai.com/share/REPLACE_WITH_THIS_CONVERSATION_LINK
2025-09-03 21:44:47 +02:00
3769e66d8d Updated CSP for bluesky 2025-09-03 20:55:21 +02:00
33a5fadf67 web-app-chess: fix Corepack/Yarn EACCES and switch to ARG-driven Dockerfile
• Add roles/web-app-chess/files/Dockerfile using build ARGs (CHESS_VERSION, CHESS_REPO_URL, CHESS_REPO_REF, CHESS_ENTRYPOINT_REL, CHESS_ENTRYPOINT_INT, CHESS_APP_DATA_DIR, CONTAINER_PORT). Enable Corepack/Yarn as root in the runtime stage to avoid EACCES on /usr/local/bin symlinks, then drop privileges to 'node'.

• Delete Jinja-based templates/Dockerfile.j2; docker-compose now passes former Jinja vars via build.args. • Update templates/docker-compose.yml.j2 to forward all required build args. • Update config/main.yml: add CSP flag 'script-src-elem: unsafe-inline'.

Ref: https://chatgpt.com/share/68b88d3d-3bd8-800f-9723-e8df0cdc37e2
2025-09-03 20:47:50 +02:00
699a6b6f1e feat(web-app-magento): add Magento role + network/ports
- add role files (docs, vars, config, tasks, schema, templates)

- networks: add web-app-magento 192.168.103.208/28

- ports: add localhost http 8052

Conversation: https://chatgpt.com/share/68b8820f-f864-800f-8819-da509b99cee2
2025-09-03 20:00:01 +02:00
61c29eee60 web-app-chess: build/runtime hardening & feature enablement
Build: use Yarn 4 via Corepack; immutable install with inline builds.

Runtime: enable Corepack as user 'node', use project-local cache (/app/.yarn/cache), add curl; fix ownership.

Entrypoint: generate keys in correct dir; run 'yarn install --immutable --inline-builds' before migrations; wait for Postgres.

Config: enable matomo/css/desktop; notify 'docker compose build' on entrypoint changes.

Docs: rename README title to 'Chess'.

Ref: ChatGPT conversation (2025-09-03) — https://chatgpt.com/share/68b88126-7a6c-800f-acae-ae61ed577f46
2025-09-03 19:56:13 +02:00
d5204fb5c2 Removed unnecessary env loading 2025-09-03 17:41:53 +02:00
751615b1a4 Changed 09_ports.yml to 10_ports.yml 2025-09-03 17:41:14 +02:00
e2993d2912 Added more CSP urls for bluesky 2025-09-03 17:31:29 +02:00
24b6647bfb Corrected variable 2025-09-03 17:30:31 +02:00
d2dc2eab5f web-app-bluesky: refactor role, add Cloudflare DNS integration, split tasks
Changes: add AppView port; add CSP whitelist; new tasks (01_pds, 02_social_app, 03_dns); switch templates to BLUESKY_* vars; update docker-compose and env; TCP healthcheck; remove admin_password from schema.

Conversation context: https://chatgpt.com/share/68b85276-e0ec-800f-90ec-480a1d528593
2025-09-03 16:37:35 +02:00
a1130e33d7 web-app-chess: refactor runtime & entrypoint
- Move entrypoint to files/ and deploy via copy
- Parameterize APP_KEY_FILE, data dir, and entrypoint paths
- Require explicit PORT/PG envs (remove fallbacks)
- Drop stray header from config/main.yml
- Dockerfile: use templated data dir & entrypoint; keep node user
- Compose: set custom image, adjust volume mapping
- env: derive APP_SCHEME from WEB_PROTOCOL; NODE_ENV from ENVIRONMENT
- tasks: add 01_core and simplify main to include it

Ref: https://chatgpt.com/share/68b851c5-4dd8-800f-8e9e-22b985597b8f
2025-09-03 16:34:04 +02:00
df122905eb mailu: include base defaults for oletools (env_file/LD_PRELOAD)
Add base include to oletools service so it inherits env_file (LD_PRELOAD=/usr/lib/libhardened_malloc.so) and other defaults. Fixes crash: PermissionError: '/proc/cpuinfo' during hardened_malloc compatibility probe when LD_PRELOAD was absent. Aligns oletools with other Mailu services.

Refs: ChatGPT discussion – https://chatgpt.com/share/68b837ba-c9cc-800f-b5d9-62b60d6fafd9
2025-09-03 14:42:50 +02:00
d093a22d61 Added correct CSP for JIRA 2025-09-03 11:35:24 +02:00
5e550ce3a3 sys-ctl-rpr-docker-soft: switch to STRICT label mode and adapt tests
- script.py now resolves docker-compose project and working_dir strictly from container labels
- removed container-name fallback logic
- adjusted sys-ctl-hlth-docker-container to include sys-ctl-rpr-docker-soft
- cleaned up sys-svc-docker dependencies
- updated unit tests to mock docker inspect and os.path.isfile for STRICT mode

Conversation: https://chatgpt.com/share/68b80927-b800-800f-a909-0fe8d110fd0e
2025-09-03 11:24:14 +02:00
0ada12e3ca Enabled rpr service by failed health checkl isntead of tiumer 2025-09-03 10:46:46 +02:00
1a5ce4a7fa web-app-bookwyrm, web-app-confluence:
- Fix BookWyrm email SSL/TLS handling (use ternary without 'not' for clarity)
- Add truststore_enabled flag in Confluence config and vars
- Wire JVM_SUPPORT_RECOMMENDED_ARGS to disable UPM signature check if truststore is disabled
- Add placeholder style.css.j2 for Confluence

See conversation: https://chatgpt.com/share/68b80024-7100-800f-a2fe-ba8b9f5cec05
2025-09-03 10:45:41 +02:00
a9abb3ce5d Added unsafe-eval csp to jira 2025-09-03 09:43:07 +02:00
71ceb339fc Fix Confluence & BookWyrm setup:
- Add docker compose build trigger in docker-compose tasks
- Cleanup svc-prx-openresty vars
- Enable unsafe-inline CSP flags for BookWyrm, Confluence, Jira to allow Atlassian inline scripts
- Generalize CONFLUENCE_HOME usage in vars, env and docker-compose
- Ensure confluence-init.properties written with correct home
- Add JVM_SUPPORT_RECOMMENDED_ARGS to pass atlassian.home
- Update README to reference {{ CONFLUENCE_HOME }}

See: https://chatgpt.com/share/68b7582a-aeb8-800f-a14f-e98c5b4e6c70
2025-09-02 22:49:02 +02:00
61bba3d2ef feat(bookwyrm): production-ready runtime + Redis wiring
- Dockerfile: build & install gunicorn wheels
- compose: run initdb before start; use `python -m gunicorn`
- env: add POSTGRES_* and BookWyrm Redis aliases (BROKER/ACTIVITY/CACHE) + CACHE_URL
- vars: add cache URL, DB indices, and URL aliases for Redis

Ref: https://chatgpt.com/share/68b7492b-3200-800f-80c4-295bc3233d68
2025-09-02 21:45:11 +02:00
0bde4295c7 Implemented correct confluence version 2025-09-02 17:01:58 +02:00
8059f272d5 Refactor Confluence and Jira env templates to use official Atlassian ATL_* database variables instead of unused custom placeholders. Ensures containers connect directly to PostgreSQL without relying on CONFLUENCE_DATABASE_* or JIRA_DATABASE_* vars. See conversation: https://chatgpt.com/share/68b6ddfd-3c44-800f-a57e-244dbd7ceeb5 2025-09-02 14:07:38 +02:00
7c814e6e83 BookWyrm: update Dockerfile and env handling
- Remove ARG BOOKWYRM_VERSION default, use Jinja variable directly
- Add proper SMTP environment variables mapping (EMAIL_HOST, EMAIL_PORT, TLS/SSL flags, user, password, default_from)
- Ensure env.j2 uses BookWyrm-expected names only
Ref: ChatGPT conversation 2025-09-02 https://chatgpt.com/share/68b6dc73-3784-800f-9a7e-340be498a412
2025-09-02 14:01:04 +02:00
d760c042c2 Atlassian JVM sizing: cast memory vars to int before floor-division
Apply |int to TOTAL_MB and dependent values to prevent 'unsupported operand type(s) for //' during templating in Confluence and Jira roles.

Context: discussion on 2025-09-02 — https://chatgpt.com/share/68b6d386-4490-800f-9bad-aa7be1571ebe
2025-09-02 13:22:59 +02:00
6cac8085a8 feat(web-app-chess): add castling.club role with ports, networks, and build setup
- Added network subnet (192.168.103.192/28) and port 8050 for web-app-chess
- Replaced stub README with usability-focused description of castling.club
- Implemented config, vars, meta, and tasks for web-app-chess
- Added Dockerfile, docker-compose.yml, env, and docker-entrypoint.sh templates
- Integrated entrypoint asset placement
- Updated meta to reflect usability and software features

Ref: https://chatgpt.com/share/68b6c65a-3de8-800f-86b2-a110920cd50e
2025-09-02 13:21:15 +02:00
3a83f3d14e Refactor BookWyrm role: switch to source-built Dockerfile, update README/meta for usability, add env improvements (ALLOWED_HOSTS, Redis vars, Celery broker), and pin version v0.7.5. See https://chatgpt.com/share/68b6d273-abc4-800f-ad3f-e1a5b9f8dad0 2025-09-02 13:18:32 +02:00
61d852c508 Added ports and networks for bookwyrm, jira, confluence 2025-09-02 12:08:20 +02:00
188b098503 Confluence/Jira roles: add READMEs, switch to custom images, proxy/JVM envs, and integer-safe heap sizing
Confluence: README added; demo disables OIDC/LDAP; Dockerfile overlay; docker-compose now uses CONFLUENCE_CUSTOM_IMAGE and DB depends include; env.j2 adds ATL_* and JVM_*; vars use integer math (//) for Xmx/Xms and expose CUSTOM_IMAGE.

Jira: initial role skeleton with README, config/meta/tasks; Dockerfile overlay; docker-compose using JIRA_CUSTOM_IMAGE and DB depends include; env.j2 with proxy + JVM envs; vars with integer-safe memory sizing.

Context: https://chatgpt.com/share/68b6b592-2250-800f-b68e-b37ae98dbe70
2025-09-02 12:07:34 +02:00
bc56940e55 Implement initial BookWyrm role
- Removed obsolete TODO.md
- Added config/main.yml with service, feature, CSP, and registration settings
- Added schema/main.yml defining vaulted SECRET_KEY (alphanumeric)
- Added tasks/main.yml to load stateful stack
- Added Dockerfile.j2 ensuring data/media dirs
- Added docker-compose.yml.j2 with application, worker, redis, volumes
- Added env.j2 with registration, secrets, DB, Redis, OIDC support
- Extended vars/main.yml with BookWyrm variables and OIDC, Docker, Redis settings
- Updated meta/main.yml with logo and run_after dependencies

Ref: https://chatgpt.com/share/68b6c060-3a0c-800f-89f8-e114a16a4a80
2025-09-02 12:03:11 +02:00
5dfc2efb5a Used port variable 2025-09-02 11:59:50 +02:00
7f9dc65b37 Add README.md files for web-app-bookwyrm, web-app-postmarks, and web-app-socialhome roles
Introduce integration test to ensure all web-app-* roles contain a README.md (required for Web App Desktop visibility)

See: https://chatgpt.com/share/68b6be49-7b78-800f-a3ff-bf922b4b083f
2025-09-02 11:52:34 +02:00
163a925096 fix(docker-compose): proper lock path + robust pull for buildable services
- Store pull lock under ${PATH_DOCKER_COMPOSE_PULL_LOCK_DIR}/<hash>.lock so global cleanup removes it reliably
- If any service defines `build:`, run `docker compose build --pull` before pulling
- Use `docker compose pull --ignore-buildable` when supported; otherwise tolerate pull failures for locally built images

This prevents failures when images are meant to be built locally (e.g., custom images) and ensures lock handling is consistent.

Ref: https://chatgpt.com/share/68b6b592-2250-800f-b68e-b37ae98dbe70
2025-09-02 11:15:28 +02:00
a8c88634b5 cleanup: remove unused handlers and add integration test for unused handlers
Removed obsolete handlers from roles (VirtualBox, backup-to-USB, OpenLDAP)
and introduced an integration test under tests/integration/test_handlers_invoked.py
that ensures all handlers defined in roles/*/handlers are actually notified
somewhere in the code base. This keeps the repository clean by preventing
unused or forgotten handlers from accumulating.

Ref: https://chatgpt.com/share/68b6b28e-4388-800f-87d2-34dfb34b8d36
2025-09-02 11:02:30 +02:00
ce3fe1cd51 Nextcloud: integrate Talk & Whiteboard; adjust ports & healthchecks
- Enable Spreed (Talk); signaling via /standalone-signaling/
- STUN/TURN: move STUN to 3480 (3479 occupied by BBB), keep TURN 5350 reserved
- docker-compose: expose internal WS ports; explicit TURN port mapping
- Healthchecks: add nc-based TCP checks (roles/docker-container/templates/healthcheck/nc.yml.j2)
- Nginx: location proxy to talk:8081
- Schema: add talk_* secrets (turn/signaling/internal)
- Plugins: configure spreed/whiteboard via vars/*; remove old task files
- Ports matrix (group_vars/all/09_ports.yml) updated/commented

Conversation: https://chatgpt.com/share/68b61a6a-e1dc-800f-b793-4aa600bc0166
2025-09-02 00:13:23 +02:00
7ca8b7c71d feat(nextcloud): integrate Talk & Whiteboard; refactor to NEXTCLOUD_* vars; full-stack setup
config(ports): add Nextcloud websocket port (4003); canonical domains (nextcloud/talk/whiteboard)

refactor: unify get_app_conf usage & Jinja spacing; migrate paths/handlers to new NEXTCLOUD_* vars

feat(plugins): split plugin routines; configure Whiteboard via occ (URL + JWT)

fix(oidc): use NEXTCLOUD_URL for logout; correct LDAP attribute mappings; add OIDC flavor switch

feat: Whiteboard container & reverse-proxy location; Talk STUN/WS ports; Redis URL for Whiteboard

chore: drop obsolete TODO; minor cleanups in oauth2-proxy, matrix, peertube, pgadmin, phpldapadmin, pixelfed, phpmyadmin

security(schema): Bluesky jwt_secret now base64_prefixed_32; add Nextcloud whiteboard_jwt_secret

db: normalize postgres image tag templating; central DB host checks spacing fixes

ops: add full-stack bootstrap (certs, proxy, volumes); internal nginx config reload handler update

refs: https://chatgpt.com/share/68b5f5b7-8d64-800f-b001-1241f818dc0e
2025-09-01 21:37:02 +02:00
110381e80c Refactored peertube role and implemented config volume 2025-09-01 18:19:50 +02:00
b02d88adc0 Refactored server roles for better readability 2025-09-01 18:08:35 +02:00
b7065837df MediaWiki: switch feature.css to false and add custom Vector 2022 override stylesheet
See: https://chatgpt.com/share/68b5b925-f418-800f-8f84-de744dd2d093
2025-09-01 17:18:12 +02:00
c98a2378c4 Added is defined condition 2025-09-01 17:05:30 +02:00
4ae3cee36c web-svc-logout: merge logout domains into CSP connect-src and refactor task flow
• Add tasks/01_core.yml to set applications[application_id].server.csp.whitelist['connect-src'] = LOGOUT_CONNECT_SRC_NEW.

• Switch tasks/main.yml to include 01_core.yml (run-once guard preserved).

• Update templates/env.j2 to emit LOGOUT_DOMAINS as a comma-separated list.

• Rework vars/main.yml: compute LOGOUT_DOMAINS, derive LOGOUT_ORIGINS with WEB_PROTOCOL, read connect-src via the get_app_conf filter, and merge/dedupe (unique).

Rationale: ensure CSP allows cross-domain logout requests for all configured services.

Conversation: https://chatgpt.com/share/68b5b07d-b208-800f-b6b2-f26934607c8a
2025-09-01 16:41:33 +02:00
b834f0c95c Implemented config image for pretix 2025-09-01 16:20:04 +02:00
9f734dff17 web-app-pretix: fix healthcheck and allowed hosts
- Add Host header to curl healthcheck when container_hostname is defined
- Use PRETIX_PRETIX_ALLOWED_HOSTS to fix Django 400 Bad Request during healthcheck
- Centralize PRETIX_HOSTNAME from container_hostname var
- Add Redis broker/result backend config for Celery

See: https://chatgpt.com/share/68b59c42-c0fc-800f-9bfb-f1137c59b3de
2025-09-01 15:15:04 +02:00
6fa4d00547 Refactor CDN and run_once handling
- Move run_once include from main.yml to 01_core.yml in desk-gnome-caffeine and desk-ssh
- Introduce sys-svc-cdn/01_core.yml to handle shared/vendor dirs once and role dirs per run
- Replace cdn.* with cdn_paths_all.* across inj roles
- Split cdn_dirs into cdn_dirs_role and CDN_DIRS_GLOBAL
- Ensure cdn_urls uses cdn_paths_all

Details: https://chatgpt.com/share/68b58d64-1e28-800f-8907-36926a9e9a9b
2025-09-01 14:11:36 +02:00
7254667186 Nextcloud: make app:update more robust by retrying once with retries/until (fixes transient migration errors)
See: https://chatgpt.com/share/68b57e29-4420-800f-b326-b34d09fa64b5
2025-09-01 13:06:44 +02:00
aaedaab3da refactor(web-app-mediawiki): unify debug & oidc handling via _ensure_require, introduce host-side prep, switch to bind mounts
- Removed obsolete Installation.md, TODO.md, 02_debug.yml, 05_oidc.yml and legacy debug enable/disable tasks
- Added 01_prep.yml to render debug.php/oidc.php on host side before container start
- Introduced _ensure_require.yml for generic require_once management in LocalSettings.php
- Renamed 01_install.yml -> 02_install.yml to align with new numbering
- Updated docker-compose.yml.j2 to bind-mount mw-local into /opt/mw-local
- Adjusted vars/main.yml to define MEDIAWIKI_LOCAL_MOUNT_DIR and MEDIAWIKI_LOCAL_PATH
- Templates debug.php.j2 and oidc.php.j2 now gated by MODE_DEBUG and MEDIAWIKI_OIDC_ENABLED
- main.yml now orchestrates prep, install, debug, extensions, oidc require, admin consistently

Ref: https://chatgpt.com/share/68b57db2-efcc-800f-a733-aca952298437
2025-09-01 13:04:57 +02:00
7791bd8c04 Implement filter checks: ensure all defined filters are used and remove dead code
Integration tests added/updated:
- tests/integration/test_filters_usage.py: AST-based detection of filter definitions (FilterModule.filters), robust Jinja detection ({{ ... }}, {% ... %}, {% filter ... %}), plus Python call tracking; fails if a filter is used only under tests/.
- tests/integration/test_filters_are_defined.py: inverse check — every filter used in .yml/.yaml/.j2/.jinja2/.tmpl must be defined locally. Scans only inside Jinja blocks and ignores pipes inside strings (e.g., lookup('pipe', "... | grep ... | awk ...")) to avoid false positives like trusted_hosts, woff/woff2, etc.

Bug fixes & robustness:
- Build regexes without %-string formatting to avoid ValueError from literal '%' in Jinja tags.
- Strip quoted strings in usage analysis so sed/grep/awk pipes are not miscounted as filters.
- Prevent self-matches in the defining file.

Cleanup / removal of dead code:
- Removed unused filter plugins and related unit tests:
  * filter_plugins/alias_domains_map.py
  * filter_plugins/get_application_id.py
  * filter_plugins/load_configuration.py
  * filter_plugins/safe.py
  * filter_plugins/safe_join.py
  * roles/svc-db-openldap/filter_plugins/build_ldap_nested_group_entries.py
  * roles/sys-ctl-bkp-docker-2-loc/filter_plugins/dict_to_cli_args.py
  * corresponding tests under tests/unit/*
- roles/svc-db-postgres/filter_plugins/split_postgres_connections.py: dropped no-longer-needed list_postgres_roles API; adjusted tests.

Misc:
- sys-stk-front-proxy/defaults/main.yml: clarified valid vhost_flavour values (comma-separated).

Ref: https://chatgpt.com/share/68b56bac-c4f8-800f-aeef-6708dbb44199
2025-09-01 11:47:51 +02:00
34b3f3b0ad Optimized healthcheck link for web-app-yourls 2025-09-01 10:54:08 +02:00
94fe58b5da safe_join: raise ValueError on None parameters and update tests
Changed safe_join to raise ValueError if base or tail is None instead of returning 'None/path'.
Adjusted unit tests accordingly to expect exceptions for None inputs and kept empty-string handling valid.

Ref: https://chatgpt.com/share/68b55850-e854-800f-9702-09ea956b8dc4
2025-09-01 10:25:08 +02:00
9feb766e6f replaced style-src-elem by style-src 2025-09-01 10:14:03 +02:00
231fd567b3 feat(frontend): rename inj roles to sys-front-*, add sys-svc-cdn, cache-busting lookup
Introduce sys-svc-cdn (cdn_paths/cdn_urls/cdn_dirs) and ensure CDN directories + latest symlink.

Rename sys-srv-web-inj-* → sys-front-inj-*; update includes/templates; serve shared/per-app CSS & JS via CDN.

Add lookup_plugins/local_mtime_qs.py for mtime-based cache busting; split CSS into default.css/bootstrap.css + optional per-app style.css.

CSP: use style-src-elem; drop unsafe-inline for styles. Services: fix SYS_SERVICE_ALL_ENABLED bool and controlled flush.

BREAKING CHANGE: role names changed; replace includes and references accordingly.

Conversation: https://chatgpt.com/share/68b55494-9ec4-800f-b559-44707029141d
2025-09-01 10:10:23 +02:00
3f8e7c1733 Refactor CSP filter:
- Move default 'unsafe-inline' for style-src and style-src-elem into get_csp_flags
- Ensure hashes are only added if 'unsafe-inline' not in final tokens
- Improve comments and structure
- Extend unit tests to cover default flags, overrides, and final-token logic
See: https://chatgpt.com/share/68b54520-5cfc-800f-9bac-45093740df78
2025-09-01 09:03:22 +02:00
3bfab9ef8e feat(filter_plugins/url_join): add query parameter support
- Support query elements starting with '?' or '&'
  * First query element normalized to '?', subsequent to '&'
  * Each query element must be exactly one 'key=value' pair
  * Query elements may only appear after path elements
  * Once query starts, no more path elements are allowed
- Extend test suite with success and failure cases for query handling

See: https://chatgpt.com/share/68b537ea-d198-800f-927a-940c4de832f2
2025-09-01 08:16:22 +02:00
f1870c07be refactor(filter_plugins/url_join): enforce mandatory scheme and raise specific AnsibleFilterError messages
Improved url_join filter:
- Requires first element to contain a valid '<scheme>://'
- Raises specific errors for None, empty list, wrong type, missing scheme,
  extra schemes in later parts, or string conversion failures
- Provides clearer error messages with index context in parts

See: https://chatgpt.com/share/68b537ea-d198-800f-927a-940c4de832f2
2025-09-01 08:06:48 +02:00
d0cec9a7d4 CSP filters: add explicit style-src-elem handling and improve unit tests
See ChatGPT conversation: https://chatgpt.com/share/68b4a82c-e0c8-800f-9273-9165ce1aa8d6
2025-08-31 21:53:39 +02:00
1dbd714a56 yourls: move container_port/healthcheck to vars; listen on 8080
• Removed hardcoded container_port/container_healthcheck from docker-compose.yml.j2
• Added container_port=8080 and container_healthcheck to vars/main.yml
• Rationale: current image listens on 8080; centralizes settings in vars

Ref: https://chatgpt.com/share/68b4a69d-e4b0-800f-a4f8-6c8e4fc55ee4
2025-08-31 21:48:24 +02:00
3a17b2979e Refactor CSP filters to use get_url for domain resolution and update tests to check CSP directives order-independently. See: https://chatgpt.com/share/68b49e5c-6774-800f-9d8e-a3f980799c08 2025-08-31 21:11:57 +02:00
bb0530c2ac Optimized yourls variables and healthcheck 2025-08-31 20:38:02 +02:00
aa2eb53776 fix(csp): always include internal CDN in script-src/connect-src and update tests accordingly
See ChatGPT conversation: https://chatgpt.com/share/68b492b8-847c-800f-82a9-fb890d4add7f
2025-08-31 20:22:05 +02:00
5f66c1a622 feat(postgres): add split_postgres_connections filter and average pool fact
Compute POSTGRES_ALLOWED_AVG_CONNECTIONS once and propagate to app roles (gitlab, mastodon, listmonk, matrix, pretix, mobilizon, openproject, discourse). Fix docker-compose postgres command (-c flags split). Add unit tests. Minor env/locale tweaks and includes.

Conversation: https://chatgpt.com/share/68b48e72-cc28-800f-9c21-270cbc17d82a
2025-08-31 20:04:14 +02:00
b3dfb8bf22 Fix: Resolved Discourse plugin bug and unified variable/path handling
- Discourse: fixed 'DISCOURSE_CONTAINERS_DIR' and 'DISCOURSE_APPLICATION_YML_DEST'
- Nextcloud: improved plugin enable/configure tasks formatting
- WordPress: unified OIDC, msmtp, and upload.ini variables and tasks
- General: aligned spacing and switched to path_join for consistency
2025-08-29 20:53:36 +02:00
db642c1c39 refactor(schedule): unify service timeouts, rename 08_timer.yml → 08_schedule.yml, fix docker repair/update timeouts, raise WP upload limit
See https://chatgpt.com/share/68b1deb9-2534-800f-b28f-7f19925b1fa7
2025-08-29 19:09:28 +02:00
2fccebbd1f Enforce uppercase README.md and TODO.md filenames
- Renamed all Readme.md → README.md
- Renamed all Todo.md → TODO.md
- Added integration test (tests/integration/test_filename_conventions.py) to automatically check naming convention.

Background:
Consistency in file naming (uppercase README.md and TODO.md) avoids issues with case-sensitive filesystems and ensures desktop cards (e.g. Pretix) are properly included.
Ref: https://chatgpt.com/share/68b1d135-c688-800f-9441-46a3cbfee175
2025-08-29 18:11:53 +02:00
c23fbd8ec4 Add new role web-app-confluence
Introduced a new Ansible role for deploying Atlassian Confluence within the Infinito.Nexus ecosystem.
The role follows the same structure as web-app-pretix and includes:

- : Core variables, database config, OIDC integration.
- : Docker service definitions, features (Matomo, CSS, OIDC, logout, central DB).
- : Loads docker, db and proxy stack.
- : Placeholder for schema definitions.
- :
  -  (base for OIDC plugins/extensions),
  -  (service orchestration),
  -  (environment configuration).
- : Metadata, license, company, logo (Font Awesome book-open icon).

Canonical domain is set to `confluence.{{ PRIMARY_DOMAIN }}`.
This role ensures Confluence integrates seamlessly with Keycloak OIDC and the Infinito.Nexus service stack.

Conversation: https://chatgpt.com/share/68b1d006-bbd4-800f-9d2e-9c8a8af2c00f
2025-08-29 18:07:01 +02:00
2999d9af77 web-app-pretix: fully implemented role
Summary:
- Replace draft with complete README (features, resources, credits).
- Remove obsolete Todo.md.
- Switch to custom image tag (PRETIX_IMAGE_CUSTOM) and install 'pretix-oidc' in Dockerfile.
- Drop unused 'config' volume; keep persistent 'data' only.
- Rename docker-compose service from 'application' to 'pretix' and use container_port.
- Use standard depends_on include for DB/Redis (dmbs_excl).
- Align vars to docker.services.pretix.* (image/version/name); add PRETIX_IMAGE_CUSTOM.

Breaking:
- Service key changed to 'pretix' under docker.services.
- 'config' volume removed from compose.

Status:
- Pretix role is now fully implemented and production-ready.

Reference:
- Conversation: https://chatgpt.com/share/68b1cb34-b7dc-800f-8b39-c183124972f2
2025-08-29 17:46:31 +02:00
2809ffb9f0 Added correct fa class and description for pretix 2025-08-29 17:02:50 +02:00
cb12114ce8 Added correct run_after for pretix 2025-08-29 16:47:21 +02:00
ba99e558f7 Improve SAN certbundle task logic and messages
- Fixed typo: 'seperat' → 'separate'
- Added more robust changed_when conditions (stdout + stderr, handle already-issued, rate-limit, service-down cases)
- Added explicit warnings for Let's Encrypt rate limits (exact set and generic)
- Improved readability of SAN encapsulation task with descriptive name

See conversation: https://chatgpt.com/share/68b1bc75-c3a0-800f-8861-fcf4f5f4a48c
2025-08-29 16:45:03 +02:00
2aed0f97d2 Enhance timeout_start_sec_for_domains filter to accept dict, list, or str
- Updated filter to handle dict (domain map), list (flattened domains), or single str inputs.
- Prevents duplicate 'www.' prefixes by checking prefix before adding.
- Adjusted unit tests:
  * Replaced old non-dict test with invalid type tests (int, None).
  * Added explicit tests for list and string input types.

See conversation: https://chatgpt.com/share/68b1ae9a-1ac0-800f-b49d-2915386a1a23
2025-08-29 15:57:00 +02:00
f36c7831b1 Implement dynamic TimeoutStartSec filter for domains and update roles
- Added new filter plugin 'timeout_start_sec_for_domains' to calculate TimeoutStartSec based on number of domains.
- Updated sys-ctl-hlth-csp and sys-ctl-hlth-webserver tasks to use the filter.
- Removed obsolete systemctl.service.j2 in sys-ctl-hlth-csp.
- Adjusted variable naming (CURRENT_PLAY_DOMAINS_ALL etc.) in multiple roles.
- Updated srv-letsencrypt and sys-svc-certs to use uppercase vars.
- Switched pretix role to sys-stk-full-stateful and removed leftover javascript.js.
- Added unittests for the new filter under tests/unit/filter_plugins.

See conversation: https://chatgpt.com/share/68b1ae9a-1ac0-800f-b49d-2915386a1a23
2025-08-29 15:44:31 +02:00
009bee531b Refactor role naming for TLS and proxy stack
- Renamed role `srv-tls-core` → `sys-svc-certs`
- Renamed role `srv-https-stack` → `sys-stk-front-pure`
- Renamed role `sys-stk-front` → `sys-stk-front-proxy`
- Updated all includes, READMEs, meta, and dependent roles accordingly

This improves clarity and consistency of naming conventions for certificate management and proxy orchestration.

See: https://chatgpt.com/share/68b19f2c-22b0-800f-ba9b-3f2c8fd427b0
2025-08-29 14:38:20 +02:00
4c7bb6d9db Solved path bugs and optimized them 2025-08-29 14:13:59 +02:00
092869b29a pretix: enable OIDC support
- add pretix-oidc plugin installation (Dockerfile, version 2.3.1 default)
- configure OIDC env vars (issuer, endpoints, client ID/secret, scopes, unique attribute)
- enable redis + database, add config/data volumes
- switch canonical domain to ticket.<PRIMARY_DOMAIN> with pretix.<PRIMARY_DOMAIN> alias
- mirror GitLab-style OIDC var structure for consistency

Implements pretix authentication via Keycloak/SSO.
See: https://chatgpt.com/share/68b19721-341c-800f-b372-527164474018
2025-08-29 14:04:03 +02:00
f4ea6c6c0f refactor(web-app-gitlab): restructure configuration and add OIDC support
- Added oidc feature flag in config
- Removed obsolete credentials schema (initial_root_password)
- Updated docker-compose.yml.j2 to use explicit GITLAB_* vars (image, version, container, volumes)
- Moved initial_root_password into vars/main.yml
- Introduced GITLAB_OMNIBUS_BASE and GITLAB_OMNIBUS_OIDC config lists
- Switched env.j2 to use GITLAB_OMNIBUS_ALL join

See conversation: https://chatgpt.com/share/68b1962c-3ee0-800f-a858-d4590ff6132a
2025-08-29 14:02:46 +02:00
3ed84717a7 Solved wireguard name bugs 2025-08-29 13:03:06 +02:00
1cfc2b7e23 Optimized mastodon url 2025-08-29 12:27:59 +02:00
01b9648650 Made OIDC secret UPPER 2025-08-29 12:27:29 +02:00
65d3b3040d Activated system_service_suppress_flush for journalctl servic4 2025-08-29 12:26:53 +02:00
28f7ac5aba Removed attendize because it isn't maintained anymore. Pretix is the successor. 2025-08-29 11:17:10 +02:00
19926b0c57 Optimized web-app-desktop variables 2025-08-29 11:04:52 +02:00
3a79d9d630 Optimized pkgmgr variables and removed 'Ensure main.py is executable' because it should be preset by repositories itself 2025-08-29 10:53:36 +02:00
983287a84a Finished mediawiki oidc implementation 2025-08-29 04:24:50 +02:00
dd9a9b6d84 feat(mediawiki): Refactor OIDC + debug; install Composer deps in-container; modularize role
Discussion: https://chatgpt.com/share/68b10c0a-c308-800f-93ac-2ffb386cf58b

- Split tasks into 01_install, 02_debug, 03_admin, 04_extensions, 05_oidc.
- Ensure unzip+git+composer on demand in the container; run Composer as www-data with COMPOSER_HOME=/tmp/composer.
- Idempotently unpack/install PluggableAuth & OpenIDConnect; run composer install only if vendor/ is missing.
- Add sanity check for Jumbojett\OpenIDConnectClient.
- Copy oidc.php only when changed and append a single require_once to LocalSettings.php.
- Use REL1_44-compatible numeric array for $wgPluggableAuth_Config; set $wgPluggableAuth_ButtonLabelMessage.
- Debug: add debug.php that logs to STDERR (visible via docker logs); toggle cleanly with MODE_DEBUG.
- Enable OIDC feature in config; add paths/OIDC/extension vars in vars/main.yml.

fix(services): include SYS_SERVICE_GROUP_CLEANUP in StartPre lock (ssd-hdd, docker-hard).

fix(desktop/joomla): simplify MODE_DEBUG templating.

chore: minor cleanups and renames.
2025-08-29 04:10:46 +02:00
23a2e081bf Optimized services 2025-08-29 01:11:06 +02:00
4cbd848026 Set SYS_TIMER_ALL_ENABLED ny default to DEBUG_MODE 2025-08-29 01:06:09 +02:00
d67f660152 Enabled CSS and Desktop for Mediawiki 2025-08-29 00:46:29 +02:00
5c6349321b Removed MyBB role, because it's deprecated and Discourse takes over 2025-08-29 00:12:35 +02:00
af1ee64246 web-app-mediawiki: installer-driven bootstrap, DB readiness, idempotent admin; drop LocalSettings bind-mount
Tasks:
- Enable docker_compose_flush_handlers=true so services come up immediately.
- Add DB readiness guard via maintenance/sql.php (SELECT 1).
- Run maintenance/install.php on empty schema with robust changed_when/failed_when (merge stdout+stderr); keep secrets hidden.
- Run maintenance/update.php for migrations with neutral changed_when unless work is done.
- Make admin creation idempotent: tolerate 'already exists' and 'Account exists', keep async+no_log.

Config changes:
- Remove LocalSettings.php template and its host bind-mount from compose.
- Drop MediaWiki settings path variables and META namespace variable (unused after switch).

Result: First boot is fully automated (schema + admin), subsequent runs are cleanly idempotent.

Ref: ChatGPT conversation (Aug 28, 2025, Europe/Berlin) — https://chatgpt.com/share/68b0d2e1-9bc0-800f-81a5-db03ce0b81e3.
2025-08-29 00:07:00 +02:00
d96bfc64a6 added possibility to deactivate docker service loading for performance 2025-08-28 22:47:05 +02:00
6ea8301364 Refactor: migrate cmp/* and srv/* roles into sys-stk/* and sys-svc/* namespaces
- Removed obsolete 'cmp' category, introduced 'stk' category (fa-bars-staggered icon).
- Renamed roles:
  * cmp-db-docker → sys-stk-back-stateful
  * cmp-docker-oauth2 → sys-stk-back-stateless
  * srv-domain-provision → sys-stk-front
  * cmp-db-docker-proxy → sys-stk-full-stateful
  * cmp-docker-proxy → sys-stk-full-stateless
  * cmp-rdbms → sys-svc-rdbms
- Updated all include_role references, vars, templates and README.md files.
- Adjusted run_once comments and variable paths accordingly.
- Updated all web-app roles to use new sys-stk/* and sys-svc/* roles.

Conversation: https://chatgpt.com/share/68b0ba66-09f8-800f-86fc-76c47009d431
2025-08-28 22:23:09 +02:00
92f5bf6481 refactor(web-app-mybb): remove obsolete Installation.md, introduce schema for secret_pin, and rework task/vars handling
- Removed outdated Installation.md (manual plugin instructions no longer needed)
- Added schema/main.yml with validation for secret_pin
- Added config.php.j2 template to manage DB + admin config
- Refactored tasks/main.yml to deploy config.php instead of legacy docker-compose
- Removed setup-domain.yml (TLS/domain handling moved to core roles)
- Updated docker-compose.yml.j2 to mount config.php and use new vars
- Cleaned up vars/main.yml: standardized MYBB_* variable names, added MYBB_SECRET_PIN, config paths, and container port

See ChatGPT conversation: https://chatgpt.com/share/68b0ae26-93ec-800f-8785-0da7c9303090
2025-08-28 21:29:58 +02:00
58c17bf043 web-app-mediawiki: template-driven LocalSettings.php + admin automation; compose & config tweaks
Config & features:
- roles/web-app-mediawiki/config/main.yml:
  - Add sitename ('Wiki on {{ PRIMARY_DOMAIN | upper }}') and meta_namespace ('Meta')
  - Enable central_database feature and database service
  - Move volumes under docker.volumes (correct indentation)

Tasks & automation:
- roles/web-app-mediawiki/tasks/main.yml:
  - Avoid immediate compose handler flush (docker_compose_flush_handlers: false), then explicit meta: flush_handlers
  - Deploy templated LocalSettings.php to host path
  - Create admin via maintenance/createAndPromote.php (docker exec, idempotent changed_when/failed_when)

Templates:
- roles/web-app-mediawiki/templates/LocalSettings.php.j2:
  - Set $wgSitename, $wgMetaNamespace, $wgServer from MEDIAWIKI_*
  - DB settings (mysql, host:port, name, user, password)
  - Mail settings (EmergencyContact/PasswordSender)
  - Default skin: vector
  - Load basic extensions (ParserFunctions, Cite)
- roles/web-app-mediawiki/templates/docker-compose.yml.j2:
  - Switch to MEDIAWIKI_* vars, mount LocalSettings.php (ro)
  - Use container_port, include curl healthcheck
  - Fix volumes name to MEDIAWIKI_VOLUME

Vars:
- roles/web-app-mediawiki/vars/main.yml:
  - Restructure with MEDIAWIKI_* (sitename, meta_namespace, URL, image/version/container/volume)
  - Define SETTINGS host/dock paths, container_port, default user (www-data)
  - Admin bootstrap vars (name/password/email)

Misc:
- Add empty schema/main.yml placeholder for future validation

Refs: ChatGPT conversation (2025-08-28, Europe/Berlin). Link: https://chatgpt.com/share/68b0ace6-f8f4-800f-b7a7-a51a6c5260f1
2025-08-28 21:28:47 +02:00
6c2d5c52c8 Attached 'not (system_service_suppress_flush | bool)' directly to handler 2025-08-28 21:16:04 +02:00
b919f39e35 Made stop unrequired for joomla container 2025-08-28 21:15:07 +02:00
9f2cfe65af Remove non-functional Joomla LDAP integration
- Disabled LDAP feature flag (set to false by default, with comment)
- Removed ldapautocreate plugin (PHP + XML)
- Deleted LDAP helper tasks (01_ldap_files.yml, 05_ldap.yml, 07_diagnose.yml)
- Deleted LDAP CLI helper scripts (cli.php, diagnose.php, plugins.php, auth-trace.php)
- Removed LDAP configuration variables from vars/main.yml
- Removed LDAP environment variables from env.j2
- Removed LDAP-specific mounts from docker-compose.yml.j2
- Dropped php-ldap installation from Dockerfile
- Renamed task files for consistent numbering (02->01_install, 03->02_debug, 04->03_patch, 06->04_assert)

Reason: LDAP integration was removed because it was not functional.

Conversation: https://chatgpt.com/share/68b09373-7aa8-800f-8f2c-11e27123bad1
2025-08-28 19:36:12 +02:00
fe399c3967 Added all LDAP changes before removing, because it doesn't work. Will trty to replace it by OIDC 2025-08-28 19:22:37 +02:00
ef801aa498 Joomla: Add LDAP autocreate plugin support
- Introduced autocreate_users feature flag in config/main.yml
- Added ldapautocreate.php and ldapautocreate.xml plugin files
- Implemented tasks/01_ldap_files.yml for plugin deployment
- Added tasks/05_ldap.yml to configure LDAP plugin and register ldapautocreate
- Renamed tasks for better structure (01→02, 02→03, etc.)
- Updated cli-ldap.php.j2 for clean parameter handling
- Mounted ldapautocreate plugin via docker-compose.yml.j2
- Extended vars/main.yml with LDAP autocreate configuration

Ref: https://chatgpt.com/share/68b0802f-bfd4-800f-b10a-57cf0c091f7e
2025-08-28 18:13:53 +02:00
18f3b1042f feat(web-app-joomla): reliable first-run install, safe debug toggler, DB patching, LDAP scaffolding
Why
- Fix flaky first-run installs and make config edits idempotent.
- Prepare LDAP support and allow optional inline CSP for UI.
- Improve observability and guard against broken configuration.php.

What
- config/main.yml: enable features.ldap; add CSP flags (allow inline style/script elem); minor spacing.
- tasks/: split into 01_install (wait for core, absolute CLI path), 02_debug (toggle $debug/$error_reporting safely), 03_patch (patch DB creds in configuration.php), 04_ldap (configure plugin via helper), 05_assert (optional php -l).
- templates/Dockerfile.j2: conditionally install/compile php-ldap (fallback to docker-php-ext-install with libsasl2-dev).
- templates/cli-ldap.php.j2: idempotently enable & configure Authentication - LDAP from env.
- templates/docker-compose.yml.j2: build custom image when LDAP is enabled; mount cli-ldap.php; pull_policy: never.
- templates/env.j2: add site/admin vars, MariaDB connector/env, full LDAP env.
- vars/main.yml: default to MariaDB (mysqli), add JOOMLA_* vars incl. JOOMLA_CONFIG_FILE.

Notes
- LDAP path implemented but NOT yet tested end-to-end.
- Ref: https://chatgpt.com/share/68b068a8-2aa4-800f-8cd1-56383561a9a8.
2025-08-28 16:33:45 +02:00
dece6228a4 Refactor docker-compose build logic and pull policy
- Added conditional '--pull' flag on retry in docker-compose build handler, tied to MODE_UPDATE
- Added 'pull_policy: never' to multiple docker-compose service templates to prevent unwanted image pulls
- Fixed minor formatting issues (e.g. Nextcloud volume spacing, WordPress desktop alignment)

Reference: https://chatgpt.com/share/68b0207a-4d9c-800f-b76f-9515885e5183
2025-08-28 11:25:35 +02:00
cb66fb2978 Refactor LDAP variable schema to use top-level constant LDAP and nested ALL-CAPS keys.
- Converted group_vars/all/13_ldap.yml from lower-case to ALL-CAPS nested keys.
- Updated all roles, tasks, templates, and filter_plugins to reference LDAP.* instead of ldap.*.
- Fixed Keycloak JSON templates to properly quote Jinja variables.
- Adjusted svc-db-openldap filter plugins and unit tests to handle new LDAP structure.
- Updated integration test to only check uniqueness of TOP-LEVEL ALL-CAPS constants, ignoring nested keys.

See: https://chatgpt.com/share/68b01017-efe0-800f-a508-7d7e2f1c8c8d
2025-08-28 10:15:48 +02:00
b9da6908ec keycloak(role): add realm support to generic updater
- Allow kc_object_kind='realm'
- Map endpoint to 'realms' and default lookup_field to 'id'
- Use realm-specific kcadm GET/UPDATE (no -r flag)
- Preserve immutables: id, realm
- Guard query-based ID resolution to non-realm objects

Context: fixing failure in 'Update REALM mail settings' task.
See: https://chatgpt.com/share/68affdb8-3d28-800f-8480-aa6a74000bf8
2025-08-28 08:57:29 +02:00
8baec17562 web-app-taiga: extract admin bootstrap into dedicated task; add robust upsert path
Add roles/web-app-taiga/tasks/01_administrator.yml to handle admin creation via 'createsuperuser' and, on failure, an upsert fallback using 'manage.py shell'. Ensures email, is_staff, is_superuser, is_active are set and password is updated when needed; emits CHANGED marker for idempotence.

Update roles/web-app-taiga/tasks/main.yml to include the new 01_administrator.yml task file, removing the inline admin logic for better separation of concerns.

Uses taiga-manage helper service and composes docker-compose.yml with docker-compose-inits.yml to inherit env/networks/volumes consistently.

Chat reference: https://chatgpt.com/share/68af7637-225c-800f-b670-2b948f5dea54
2025-08-27 23:58:37 +02:00
1401779a9d web-app-taiga: add manage/init flow and idempotent admin bootstrap; fix OIDC config and env quoting
config/main.yml: convert oidc from empty mapping to block; indent flavor under oidc; enable javascript feature.

tasks/main.yml: use path_join for taiga settings; create docker-compose-inits via TAIGA_DOCKER_COMPOSE_INIT_PATH; flush handlers; add idempotent createsuperuser via taiga-manage with async/poll and masked logs.

templates/docker-compose-inits.yml.j2: include compose/container base to inherit env and project settings.

templates/env.j2: quote WEB_PROTOCOL and WEBSOCKET_PROTOCOL.

templates/javascript.js.j2: add SSO warning include.

users/main.yml: add administrator email stub.

vars/main.yml: add js_application_name; restructure OIDC flavor flags; add compose PATH vars; expose TAIGA_SUPERUSER_* vars.

Chat reference: https://chatgpt.com/share/68af7637-225c-800f-b670-2b948f5dea54
2025-08-27 23:19:42 +02:00
707a3fc1d0 Optimized defaults for modes 2025-08-27 22:58:05 +02:00
d595d46e2e Solved unquoted bug 2025-08-27 22:30:03 +02:00
73d5651eea web-app-taiga: refactor OIDC gating + defaults
- Introduced dedicated variables in vars/main.yml:
  * TAIGA_FLAVOR_TAIGAIO
  * TAIGA_TAIGAIO_ENABLED
- Replaced inline Jinja2 get_app_conf checks with TAIGA_TAIGAIO_ENABLED for
  consistency in tasks, docker-compose template and env file.
- Adjusted env.j2 to use TAIGA_TAIGAIO_ENABLED instead of direct flavor checks.
- Enabled css by default (true instead of false).
- Cleaned up spacing/indentation in config and env.

This improves readability, reduces duplicated logic, and makes it easier to
maintain both OIDC flavors (robrotheram, taigaio).

Conversation: https://chatgpt.com/share/68af65b3-27c0-800f-964f-ff4f2d96ff5d
2025-08-27 22:08:35 +02:00
12a267827d Refactor websocket and Taiga variables
- Introduce WEBSOCKET_PROTOCOL derived from WEB_PROTOCOL (wss if https, else ws).
- Replace hardcoded websocket URLs in EspoCRM, Nextcloud and Taiga with {{ WEBSOCKET_PROTOCOL }}.
- Fix mautrix-imessage to use ws:// for internal synapse:8008.
- Standardize Pixelfed OIDC env spacing.
- Refactor Taiga variables to TAIGA_* naming convention and clean up EMAIL_BACKEND definition.

See: https://chatgpt.com/share/68af62fa-4dcc-800f-9aaf-cff746daab1e
2025-08-27 21:57:04 +02:00
c6cd6430bb Refactor Joomla role to new docker.* schema
- Move image definition from images.joomla to docker.services.joomla
- Add container name, container_port variable, and healthcheck
- Introduce JOOMLA_IMAGE, JOOMLA_VERSION, JOOMLA_CONTAINER, JOOMLA_VOLUME in vars
- Use volume mapping via docker.volumes.data

See: https://chatgpt.com/share/68af55a9-6514-800f-b6f7-1dc86356936e
2025-08-27 21:00:08 +02:00
67b2ebf001 Encapsulated code to pass performance tests 2025-08-27 20:58:00 +02:00
ebb6660473 Renamed Gitea variables 2025-08-27 20:49:35 +02:00
f62d09d8f1 Handle Let's Encrypt maintenance errors gracefully
- Extend certbundle task to ignore 'The service is down for maintenance or had an internal error'
  as a fatal failure.
- Add debug/warning output when this error occurs, so playbook does not stop but logs the issue.
- Ensure changed_when does not mark run as changed if only maintenance error was hit.

Ref: https://chatgpt.com/share/68af4e15-24cc-800f-b1dd-6a5f2380e35a
2025-08-27 20:28:25 +02:00
de159db918 web-app-wordpress: move msmtp configuration from Docker image to docker-compose mount
- Removed COPY of msmtp configuration from Dockerfile to avoid baking secrets/config into the image
- Added volume mount for host-side msmtp config ({{ WORDPRESS_HOST_MSMTP_CONF }}) in docker-compose.yml
- Keeps PHP upload.ini handling inside the image, but externalizes sensitive mail configuration
- Increases flexibility and avoids rebuilds when msmtp config changes

Ref: https://chatgpt.com/share/68af3c51-0544-800f-b76f-b2660c43addb
2025-08-27 19:12:03 +02:00
e2c2cf4bcf Updated sys-svc-msmtp execution condition 2025-08-27 18:12:49 +02:00
6e1e1ad5c5 Renamed pixelfed parameter 2025-08-27 18:11:31 +02:00
06baa4b03a Added correct validation handling 2025-08-27 18:10:49 +02:00
73e7fbdc8a refactor(web-app-wordpress): unify variable naming to uppercase WORDPRESS_* style
- Replaced all lowercase wordpress_* variables with uppercase WORDPRESS_* equivalents
- Ensured consistency across tasks, templates, and vars
- Improves readability and aligns with naming conventions

Conversation: https://chatgpt.com/share/68af29b5-8e7c-800f-bd12-48cc5956311c
2025-08-27 17:52:38 +02:00
bae2bc21ec Optimized system services included suppress option and solved bugs 2025-08-27 17:34:59 +02:00
a8f4dea9d2 Solved matrix name bug 2025-08-27 16:39:07 +02:00
5aaf2d28dc Refactor path handling, service conditions and dependencies
- Fixed incorrect filter usage in docker-compose handler (proper use of | path_join).
- Improved LetsEncrypt template by joining paths with filenames instead of appending manually.
- Enhanced sys-svc-msmtp task with an additional condition to only run if no-reply mailu_token exists.
- Updated Keycloak meta to depend on Mailu (ensuring token generation before setup).
- Refactored Keycloak import path variables to use path_join consistently.
- Adjusted Mailu meta dependency to run after Matomo instead of Keycloak.

See: https://chatgpt.com/share/68af13e6-edc0-800f-b76a-a5f427837173
2025-08-27 16:19:57 +02:00
5287bb4d74 Refactor Akaunting role and CSP handling
- Improved CSP filter to properly include web-svc-cdn and use protocol-aware domains
- Added Todo.md with redis and OIDC notes
- Enhanced Akaunting role config with CSP flags and redis option
- Updated schema to include app_key validation
- Reworked tasks to handle first-run marker logic cleanly
- Fixed docker-compose template (marker, healthcheck, setup flag)
- Expanded env.j2 with cache, email, proxy, and redis options
- Added javascript.js.j2 template for SSO warning
- Introduced structured vars for Akaunting role
- Removed deprecated update-repository-with-files.yml task

See conversation: https://chatgpt.com/share/68af00df-2c74-800f-90b6-6ac5b29acdcb
2025-08-27 14:58:44 +02:00
5446a1497e Optimized attendize role. Role can be removed as soon as pretix as alternative tool is implemented 2025-08-27 12:27:55 +02:00
19889a8cfc fix(credentials, akaunting):
- update cli/create/credentials.py to handle vault literals correctly:
  * strip 'vault |' headers and keep only ANSIBLE_VAULT body
  * skip reprocessing keys added in same run (no duplicate confirmation prompts)
  * detect both 'vault' and 'ANSIBLE_VAULT' as already encrypted

Refs: https://chatgpt.com/share/68aed780-ad4c-800f-877d-aa4c40a47755
2025-08-27 12:02:36 +02:00
d9980c0d8f feat(baserow): add one-time SSO warning JavaScript
- Introduced a generic sso_warning.js.j2 template under
  templates/roles/web-app/templates/javascripts/
- Included this template in web-app-baserow/templates/javascript.js.j2
- Added new variable js_application_name in
  roles/web-app-baserow/vars/main.yml to make the warning
  application-specific
- Implemented cookie-based logic so the warning is only shown once
  per user (default: 365 days)

Reference: https://chatgpt.com/share/68aecdae-82d0-800f-b05e-f2cb680664f1
2025-08-27 11:19:59 +02:00
35206aaafd Solved undeclared docker compose variable bug 2025-08-26 22:35:41 +02:00
942e8c9c12 Updated baserow CSP adn variables for new Infinito.Nexus structure 2025-08-26 22:20:31 +02:00
97f4045c68 Keycloak: align client attributes with realm dictionary
- Extended kc_force_attrs in tasks/main.yml to source 'publicClient',
  'serviceAccountsEnabled' and 'frontchannelLogout' directly from
  KEYCLOAK_DICTIONARY_REALM for consistency with import definitions.
- Updated default.json.j2 import template to set 'publicClient' to true.
- Public client mode is required so the frontend API of role 'web-app-desktop'
  can handle login/logout flows without client secret.

Ref: https://chatgpt.com/share/68ae0060-4fac-800f-9f02-22592a4087d3
2025-08-26 21:22:27 +02:00
c182ecf516 Refactor and cleanup OIDC, desktop, and web-app roles
- Improved OIDC variable definitions (12_oidc.yml)
- Added account/security/profile URLs
- Restructured web-app-desktop tasks and JS handling
- Introduced oidc.js and iframe.js with runtime loader
- Fixed nginx.conf, LDAP, and healthcheck templates spacing
- Improved Lua injection for CSP and snippets
- Fixed typos (WordPress, receive, etc.)
- Added silent-check-sso nginx location

Conversation: https://chatgpt.com/share/68ae0060-4fac-800f-9f02-22592a4087d3
2025-08-26 20:44:05 +02:00
ce033c370a Removed waiting for other services, otherwise it ends up breaking, waiting for hard restart service 2025-08-26 19:23:47 +02:00
a0477ad54c Switched OnFailure with StartPost 2025-08-26 19:10:41 +02:00
35c3681f55 sys-daemon & sys-service: align timeout handling
- Updated sys-daemon defaults:
  * Increased SYSTEMD_DEFAULT_TIMEOUT_START to 24h
  * Improved inline comments for clarity
- Changed sys-service vars:
  * Removed hardcoded 60s TimeoutStartSec
  * Now empty by default → inherits manager defaults from sys-daemon

See: https://chatgpt.com/share/68ade432-67f8-800f-b6c2-b8f87764479b
2025-08-26 18:48:45 +02:00
af97e71976 Fix: correct Docker Go template syntax in sys-ctl-rpr-docker-soft script
Replaced over-escaped '{{{{.Names}}}}' with proper '{{.Names}}'
in docker ps commands. This resolves 'failed to parse template:
unexpected "{" in command' errors during unhealthy/exited
container detection.

Reference: https://chatgpt.com/share/68addfd9-fa78-800f-abda-49161699e673
2025-08-26 18:25:25 +02:00
19a51fd718 Solved linebreak bug 2025-08-26 17:13:29 +02:00
b916173422 Renamed web-app-port-ui to web-app-desktop 2025-08-26 11:35:22 +02:00
9756a0f75f Extend repair scripts with env-file support and unit tests
- Added detect_env_file() to both sys-ctl-rpr-docker-soft and sys-ctl-rpr-docker-hard
  * prefer .env, fallback to .env/env
  * append --env-file parameter automatically
- Refactored soft script to use compose_cmd() for consistent command building
- Adjusted error recovery path in soft script to also respect env-file
- Extended unit tests for soft script to cover env-file priority and restart commands
- Added new unit tests for hard script verifying env-file priority, cwd handling,
  and --only filter logic

Ref: https://chatgpt.com/share/68ad7b30-7510-800f-8172-56f03a2f40f5
2025-08-26 11:15:59 +02:00
e417bc19bd Refactor sys-ctl-rpr-docker-soft role to use standalone Python script with argparse and unittests
- Replace Jinja2 template (script.py.j2) with raw Python script (files/script.py)
- Add argparse options: --manipulation, --manipulation-string, --timeout
- Implement timeout handling in wait_while_manipulation_running
- Update systemd ExecStart/ExecStartPre handling in tasks/01_core.yml
- Remove obsolete systemctl.service.j2 and script.py.j2 templates
- Add unittest suite under tests/unit/roles/sys-ctl-rpr-docker-soft/files/test_script.py
- Mock docker and systemctl calls in tests for safe execution

Reference: ChatGPT conversation (see https://chatgpt.com/share/68ad770b-ea84-800f-b378-559cb61fc43a)
2025-08-26 10:58:17 +02:00
7ad14673e1 sys-service: add ExecStartPost support and adjust health/repair roles
- extended generic systemctl template to support ExecStartPost
- health-docker-volumes: run main script with whitelist, trigger both compose alarm and cleanup on failure
- repair-docker-hard: added ExecStartPre lock, ExecStart, and ExecStartPost to trigger compose alarm always, plus cleanup on failure
- removed obsolete role-specific systemctl.service.j2 templates
- improved consistency across vars and defaults

See: https://chatgpt.com/share/68ad6cb8-c164-800f-96b6-a45c6c7779b3
2025-08-26 10:15:35 +02:00
eb781dbf8b fix(keycloak/ldap): make userObjectClasses JSON-safe and exclude posixAccount
- Render userObjectClasses via `tojson` (and trim) to avoid invalid control
  characters and ensure valid realm import parsing.
- Introduce KEYCLOAK_LDAP_USER_OBJECT_CLASSES in vars; exclude `posixAccount`
  for Keycloak’s LDAP config while keeping it for Ansible-managed UNIX users.
- Update UserStorageProvider template to use the new variable.

Rationale:
Keycloak must not require `posixAccount` on every LDAP user. We keep
`posixAccount` structural for Ansible provisioning, but filter it out for
Keycloak to prevent sync/import errors on entries without POSIX attributes.

Touched:
- roles/web-app-keycloak/templates/import/components/org.keycloak.storage.UserStorageProvider.json.j2
- roles/web-app-keycloak/vars/main.yml

Refs: conversation https://chatgpt.com/share/68aa1ef0-3658-800f-bdf4-5b57131d03b4
2025-08-23 22:05:26 +02:00
6016da6f1f Optimized bbb variables 2025-08-23 19:21:07 +02:00
8b2f0ac47b refactor(web-app-espocrm): improve config patching and container vars
- Replace `ESPOCRM_NAME` with `ESPOCRM_CONTAINER` for clarity and consistency.
- Drop unused `ESPOCRM_CONFIG_FILE_PUBLIC`, rely only on `config-internal.php`.
- Make DB credential patching idempotent using `grep` + `sed` checks.
- Replace direct sed edits for maintenance/cron/cache with EspoCRM ConfigWriter.
- Add fallback execution as root if www-data user cannot write config.
- Clear EspoCRM cache only when config changes and in update mode.
- Remove obsolete OIDC scopes inline task (now handled via env/vars).
- Fix docker-compose template to use `ESPOCRM_CONTAINER`.

This refactor makes the EspoCRM role more robust, idempotent, and aligned
with EspoCRM’s official ConfigWriter mechanism.

See conversation: https://chatgpt.com/share/68a87820-12f8-800f-90d6-01ba97a1b279
2025-08-22 16:01:48 +02:00
9d6d64e11d Renamed espocrm data volume 2025-08-22 14:49:25 +02:00
f1a2967a37 Implemented sys-svc-cln-anon-volumes as service so that it can be triggert after sys-ctl-rpr-docker-hard 2025-08-22 14:48:50 +02:00
95a2172fff Corrected link 2025-08-22 09:23:40 +02:00
dc3f4e05a8 sys-ctl-rpr-docker-hard: Refactor restart script with argparse & update systemd ExecStart
- Removed unused soft restart function and switched to argparse-based CLI.
- Added --only argument to selectively restart subdirectories.
- Updated systemctl service template to pass PATH_DOCKER_COMPOSE_INSTANCES as argument.
- Ensures service unit correctly invokes the Python script with target path.

See conversation: https://chatgpt.com/share/68a771d9-5fd8-800f-a410-08132699cc3a
2025-08-21 21:22:29 +02:00
e33944cda2 Solved service ignore parameter bugs 2025-08-21 21:04:21 +02:00
efa68cc1e0 sys-ctl: make service file generation deterministic and simplify ignore logic
- Added '| sort' to all service group lists and backup routine lists to ensure
  deterministic ordering and stable checksums across Ansible runs.
- Adjusted systemctl templates to use a single service variable
  ('SYS_SERVICE_BACKUP_RMT_2_LOC') instead of rejecting dynamic list entries,
  making the ignore logic simpler and more predictable.
- Fixed minor whitespace inconsistencies in Jinja templates to avoid
  unnecessary changes.

This change was made to prevent spurious 'changed' states in Ansible caused by
non-deterministic list order and to reduce complexity in service definitions.

See discussion: https://chatgpt.com/share/68a74c20-6300-800f-a44e-da43ae2f3dea
2025-08-21 18:43:17 +02:00
79e702a3ab web-svc-collabora: localize vars, adjust CSP, fix systemd perms; refactor role composition
- sys-service:
  - Set explicit ownership and permissions for generated unit files:
    owner=root, group=root, mode=0644. Prevents drift and makes idempotence
    predictable when handlers reload/refresh systemd.

- web-svc-collabora:
  - Move cmp-docker-proxy include into tasks/01_core.yml and run it
    before Nginx config generation. Use public: true only to initialize the
    proxy/compose context and docker_compose_flush_handlers: true to ensure
    timely handler execution.
  - Define role-local variables domain and http_port in vars/main.yml
    and use {{ domain }} for the Nginx server file path. These values MUST
    be defined locally because they cannot be reliably imported via
    public: true — other roles may override them later in the play, leading
    to leakage and nondeterministic behavior. Localizing avoids precedence
    conflicts without resorting to host-wide set_fact.
  - CSP adjusted: add server.security.flags.style-src.unsafe-inline: true
    to accommodate Collabora’s inline styles (requested as “csr” in notes).
  - Minor variable alignment/cleanup and TODO note for future refactor.

- Housekeeping:
  - Rename task title to reflect {{ domain }} usage.

Refs:
- Discussion and rationale in this chat https://chatgpt.com/share/68a731aa-d394-800f-9eb4-2499f45ed54b (2025-08-21, Europe/Berlin).
2025-08-21 16:48:37 +02:00
9180182d5b Optimized variables 2025-08-21 16:27:10 +02:00
535094d15d Added more update tasks for ESPOCRM config 2025-08-21 16:23:08 +02:00
658003f5b9 Added test user entry 2025-08-21 09:56:50 +02:00
3ff783df17 Updated mailu move docs 2025-08-21 09:49:36 +02:00
3df511aee9 Changed constructor order. emails need to be defned before users 2025-08-20 18:54:44 +02:00
c27d16322b Optimized variables 2025-08-20 18:17:13 +02:00
7a6e273ea4 In between commit, updated matrix and optimized mailu 2025-08-20 17:51:17 +02:00
384beae7c1 Added task to update default email settings 2025-08-20 16:41:53 +02:00
ad7e61e8b1 Set default buffer level for proxy basic conf, which are necessary for OIDC login 2025-08-20 15:56:32 +02:00
fa46523433 Update trusted domains for matomo 2025-08-20 15:35:08 +02:00
f4a380d802 Optimized alarm and system handlers 2025-08-20 15:17:04 +02:00
42d6c1799b sys-service: add systemd_directive filter and refactor service template
Introduced custom filter plugin to render optional systemd directives, refactored template to loop over directives, and adjusted default vars (TimeoutStartSec, RuntimeMaxSec handling).

Details: see ChatGPT conversation
https://chatgpt.com/share/68a5a730-6344-800f-b9a3-dc62d5902e9b
2025-08-20 12:46:07 +02:00
8608d89653 Implemented correct template for collabora 2025-08-20 09:07:33 +02:00
a4f39ac732 Renamed webserver roles to more speakable names 2025-08-20 08:54:17 +02:00
9cfb8f3a60 Different optimations for collabora 2025-08-20 08:34:12 +02:00
3e5344a46c Optimized Collabora CSP for Nextcloud 2025-08-20 07:03:02 +02:00
ec07d1a20b Added logic to start docker compose pull just once per directory 2025-08-20 07:02:27 +02:00
594d9417d1 handlers(docker): add once-per-directory docker compose pull with lockfile
- Introduced a new handler 'docker compose pull' that runs only once per
  {{ docker_compose.directories.instance }} directory by using a lock
  file under /run/ansible/compose-pull.
- Ensures idempotency by marking the task as changed only when a pull
  was actually executed.
- Restricted execution with 'when: MODE_UPDATE | bool'.
- Improves update workflow by avoiding redundant docker pulls during
  the same Ansible run.

Reference: ChatGPT discussion
https://chatgpt.com/share/68a55151-959c-800f-8b70-160ffe43e776
2025-08-20 06:42:49 +02:00
dc125e4843 Solved path bug 2025-08-20 06:18:52 +02:00
39a54294dd Moved update commands to nextcloud role 2025-08-20 06:07:33 +02:00
a57fe718de Optimized spacinbg 2025-08-20 05:49:35 +02:00
b6aec5fe33 Optimized features 2025-08-20 05:39:49 +02:00
de07d890dc Solvewd 'sys-ctl-bkp-docker-2-loc' bug 2025-08-20 05:25:24 +02:00
e27f355697 Solvewd tabulator bug 2025-08-20 05:02:16 +02:00
790762d397 Renamed some web apps to web servicesy 2025-08-20 05:00:24 +02:00
4ce681e643 Add integration test: ensure roles including 'sys-service' define system_service_id
This test scans all roles for tasks including:
  - include_role:
      name: sys-service

If present, the role must define a non-empty 'system_service_id' in vars/main.yml.
Helps enforce consistency and prevent misconfiguration.

Ref: https://chatgpt.com/share/68a536e5-c384-800f-937a-f9d91249950c
2025-08-20 04:46:27 +02:00
55cf3d0d8e Solved unit performance tests 2025-08-20 04:35:46 +02:00
2708b67751 Optimized webserver on failure 2025-08-20 04:12:42 +02:00
f477ee3731 Deactivated redis, moved version to correct place for web-svc-collabora 2025-08-20 03:40:37 +02:00
6d70f78989 fix(domain-filters): support dependency expansion via seed param
- Added missing 'Iterable' import in 'canonical_domains_map' to avoid NameError.
- Introduced 'seed' parameter so the filter can start traversal from current play apps
  while still emitting canonical domains for discovered dependencies (e.g. web-svc-collabora).
- Updated 01_constructor.yml to pass full 'applications' and a clean 'seed' list
  (using dict2items → key) instead of '.keys()' method calls, fixing integration
  test error: 'reference to application keys is invalid'.

This resolves issues where collabora domains were missing and integration tests failed.

Ref: https://chatgpt.com/share/68a51f9b-3924-800f-a41b-803d8dd10397
2025-08-20 03:07:14 +02:00
b867a52471 Refactor and extend role dependency resolution:
- Introduced module_utils/role_dependency_resolver.py with full support for include_role, import_role, meta dependencies, and run_after.
- Refactored cli/build/tree.py to use RoleDependencyResolver (added toggles for include/import/dependencies/run_after).
- Extended filter_plugins/canonical_domains_map.py with optional 'recursive' mode (ignores run_after by design).
- Updated roles/web-app-nextcloud to properly include Collabora dependency.
- Added comprehensive unittests under tests/unit/module_utils for RoleDependencyResolver.

Ref: https://chatgpt.com/share/68a519c8-8e54-800f-83c0-be38546620d9
2025-08-20 02:42:07 +02:00
78ee3e3c64 Deactivated on_failure for telegram and email 2025-08-20 01:20:06 +02:00
d7ece2a8c3 Optimized message 2025-08-20 01:03:07 +02:00
3794aa87b0 Optimized spacing 2025-08-20 01:02:29 +02:00
4cf996b1bb Removed old collabora 2025-08-20 01:02:11 +02:00
79517b2fe9 Optimized spacing 2025-08-20 01:01:32 +02:00
a84ee1240a Optimized collabora name 2025-08-20 01:00:51 +02:00
7019b307c5 Optimized collabora draft 2025-08-20 01:00:20 +02:00
838a8fc7a1 Solved svc-opt-ssd-hdd path bug 2025-08-19 21:50:55 +02:00
95aba805c0 Removed variable which leads to bugs in other contexts 2025-08-19 20:50:08 +02:00
0856c340c7 Removed unnecessary logic 2025-08-19 20:35:02 +02:00
b90a2f6c87 sys-ctl-alm-{email,telegram}: unescape instance names before alerts
Use `systemd-escape --unescape` to restore human-readable unit identifiers in
Telegram and Email alerts. Also ensure Telegram messages are URL-encoded and
Email status checks try both raw and escaped forms for robustness.

Fixes issue where slashes were shown as dashes in notifications.

Context: see ChatGPT conversation
https://chatgpt.com/share/68a4c171-db08-800f-8399-7e07f237a441
2025-08-19 20:25:15 +02:00
98e045196b Removed cleanup service lock 2025-08-19 19:06:58 +02:00
a10dd402b8 refactor: improve service handling and introduce MODE_ASSERT
- Improved get_service_name filter plugin (clearer suffix handling, consistent var names).
- Added MODE_ASSERT flag to optionally execute validation/assertion tasks.
- Fixed systemd unit handling: consistent use of %I instead of %i, correct escaping of instance names.
- Unified on_failure behavior and alarm composer scripts.
- Cleaned up redundant logging, handlers, and debug config.
- Strengthened sys-service template resolution with assert (only active when MODE_ASSERT).
- Simplified timer and suffix handling with get_service_name filter.
- Hardened sensitive tasks with no_log.
- Added conditional asserts across roles (Keycloak, DNS, Mailu, Discourse, etc.).

These changes improve consistency, safety, and validation across the automation stack.

Conversation: https://chatgpt.com/share/68a4ae28-483c-800f-b2f7-f64c7124c274
2025-08-19 19:02:52 +02:00
6e538eabc8 Enhance tree builder: detect include_role dependencies from tasks/*.yml
- Added logic to scan each role’s tasks/*.yml files for include_role usage
- Supports:
  * loop/with_items with literal strings → adds each role
  * patterns with variables inside literals (e.g. svc-db-{{database_type}}) → expanded to glob and matched
  * pure variable-only names ({{var}}) → ignored
  * pure literal names → added directly
- Merges discovered dependencies under graphs["dependencies"]["include_role"]
- Added dedicated unit test covering looped includes, glob patterns, pure literals, and ignoring pure variables

See ChatGPT conversation (https://chatgpt.com/share/68a4ace0-7268-800f-bd32-b475c5c9ba1d) for context.
2025-08-19 19:00:03 +02:00
82cc24a7f5 Added reset condition for openresty 2025-08-19 17:48:02 +02:00
26b392ea76 refactor!: replace sys-systemctl with sys-service, add sys-daemon, and rename systemctl_* → system_service_* across repo
- Swap role includes: sys-systemctl → sys-service in all roles
- Rename variables everywhere: systemctl_* → system_service_* (incl. systemctl_id → system_service_id)
- Templates: ExecStart now uses {{ system_service_script_exec }}; add optional RuntimeMaxSec via SYS_SERVICE_DEFAULT_RUNTIME
- Move SYS_SERVICE defaults into roles/sys-service/defaults (remove SYS_SERVICE_ALL_ENABLED & SYS_SERVICE_DEFAULT_STATE from group_vars/07_services.yml)
- Tidy group_vars/all/08_timer.yml formatting
- Introduce roles/sys-daemon:
  - default manager timeouts (timeouts.conf)
  - optional purge of /etc/systemd/system.conf.d
  - validation via systemd-analyze verify
  - handlers for daemon-reload & daemon-reexec
- Refactor sys-timer to system_service_* variables (docs and templates updated)
- Move filter_plugins/filetype.py under sys-service
- Update meta/README to point to official systemd docs
- Touch many roles (backup/cleanup/health/repair/certs/nginx/csp/wireguard/ssd-hdd/keyboard/update-docker/alarm compose/email/telegram/etc.) to new naming

BREAKING CHANGE:
- Role path/name change: use `sys-service` instead of `sys-systemctl`
- All `systemctl_*` vars are now `system_service_*` (e.g., on_calendar, state, timer_enabled, script_exec, id)
- If you have custom templates, adopt RuntimeMaxSec and new variable names

Chat context: https://chatgpt.com/share/68a47568-312c-800f-af3f-e98575446327
2025-08-19 15:00:44 +02:00
b49fdc509e Refactor alarm compose service and systemctl templates
- Fixed bug where not both alarm services (email + telegram) were triggered.
- Removed direct OnFailure references for email and telegram,
  now handled by unified compose service.
- Introduced 01_core.yml in sys-ctl-alm-compose to structure
  role execution (subservices → core service → test run).
- Added configurable variables SYSTEMCTL_ALARM_COMPOSER_SUBSERVICES
  and SYSTEMCTL_ALARM_COMPOSER_DUMMY_MESSAGE.
- Replaced dedicated @.service template with generic systemctl template
  using systemctl_tpl_* variables for flexibility.
- Updated script.sh.j2 to collect exit codes and print clear errors.
- Fixed typos and streamlined vars in sys-systemctl.

See conversation: https://chatgpt.com/share/68a46172-7c3c-800f-a69c-0cb9edd6839f
2025-08-19 13:35:39 +02:00
b1e8339283 Added /bin/systemctl start {{ SYS_SERVICE_CLEANUP_BACKUPS_OLD }} 2025-08-19 12:56:25 +02:00
f5db786878 Restart and activate all services and timer when in debug mode 2025-08-19 12:20:19 +02:00
7ef20474a0 Renamed sys-ctl-cln-backups to sys-ctl-cln-bkps 2025-08-19 12:15:33 +02:00
83b9f697ab Encapsulated again to see output in journald 2025-08-19 11:25:07 +02:00
dd7b5e844c removed /bin/sh -c encapsulation and solved wrong --ignore names 2025-08-19 11:15:36 +02:00
da01305cac Replaced {{ systemctl_id | get_service_script_path( by systemctl_script_exec 2025-08-19 10:56:46 +02:00
1082caddae refactor(sys-ctl-alm-compose, sys-timer-cln-bkps):
- update alarm compose unit to run email/telegram notifiers independently via multiple ExecStart lines
- ensure cleanup backup dependencies are included before timer setup with handler flush
conversation: https://chatgpt.com/share/68a43429-c0cc-800f-9cc9-9a5ae258dc50
2025-08-19 10:22:38 +02:00
242347878d Moved email host and domain SPOT to SYSTEM_EMAIL constant 2025-08-19 10:00:35 +02:00
f46aabe884 Moved healthcheck to the end so that it is setup after email configuration 2025-08-19 09:46:12 +02:00
d3cc187c3b Made System Email Variables UPPER 2025-08-19 09:34:18 +02:00
0a4b9bc8e4 Generated service names with function 2025-08-19 02:01:15 +02:00
2887e54cca Solved path bug 2025-08-19 01:48:43 +02:00
630fd43382 refactor(services): unify service/timer runtime control and cleanup handling
- Introduce SYS_SERVICE_ALL_ENABLED and SYS_TIMER_ALL_ENABLED runtime flags
- Add SYS_SERVICE_DEFAULT_STATE for consistent default handling
- Ensure all on-failure service names use lowercase software_name
- Load sys-svc-cln-anon-volumes role during Docker cleanup
- Allow forced service refresh when SYS_SERVICE_ALL_ENABLED is true
- Replace ACTIVATE_ALL_TIMERS with SYS_TIMER_ALL_ENABLED
- Use SYS_SERVICE_DEFAULT_STATE in sys-systemctl vars
- Remove redundant MIG build job fail check

Related to service/timer process control refactoring.
2025-08-19 01:27:37 +02:00
3114a7b586 solved missing vars bug 2025-08-19 01:01:09 +02:00
34d771266a Solved path bug 2025-08-19 00:46:47 +02:00
73b7d2728e Solved timer bug 2025-08-19 00:33:00 +02:00
fc4df980c5 Solved empty entry bug 2025-08-18 23:54:23 +02:00
763b43b44c Implemented dynamic script path to sys-ctl-cln-disc-space 2025-08-18 23:50:28 +02:00
db860e6ae3 Adapted load order 2025-08-18 23:47:14 +02:00
2ba486902f Deactivated file copying for sys-ctl-cln-faild-bkps 2025-08-18 23:34:06 +02:00
7848226f83 Optimized service configuration for allerts 2025-08-18 23:28:41 +02:00
185f37af52 Refactor systemctl service handling with @ support
- Unified variable naming: system_service_id → systemctl_id
- Added automatic removal of trailing '@' for role directory resolution
- Improved first_found search: prefer target role, fallback to sys-systemctl defaults
- Split template resolution logic to avoid undefined variable errors
- Added assertion in sys-timer to forbid '@' in systemctl_id
- Corrected default systemctl.service.j2 template description
- Cleaned up path handling and script directory generation

Context: conversation about fixing template resolution and @ handling
https://chatgpt.com/share/68a39994-1bb0-800f-a219-109e643c3efb
2025-08-18 23:22:46 +02:00
b9461026a6 refactor: improve get_service_name suffix handling and handler usage
- Updated filter_plugins/get_service_name.py:
  * Default suffix handling: auto-select .service (no '@') or .timer (with '@')
  * Explicit False disables suffix entirely
  * Explicit string suffix still supported
- Updated sys-systemctl handler to use new filter instead of SYS_SERVICE_SUFFIX
- Extended unit tests to cover new suffix behavior

Ref: https://chat.openai.com/share/8c2de9e6-daa0-44dd-ae13-d7a7d8d8b6d9
2025-08-18 22:36:31 +02:00
bf63e01b98 refactor(systemd-services): migrate SYS_SERVICE_SUFFIX usage to get_service_name filter
Replaced all hardcoded service name concatenations with the new get_service_name filter.
This ensures consistency, proper lowercase formatting, and correct handling of '@' suffixed units.

Added unittests for the filter (normal, custom suffix, '@'-units, and lowercase normalization).

Context: see ChatGPT discussion https://chatgpt.com/share/68a38beb-b9bc-800f-b7ed-cdd2b64b2604
2025-08-18 22:24:33 +02:00
4a600ac531 Added get_service_name 2025-08-18 22:10:52 +02:00
dc0bb555c1 Added another group_names validation 2025-08-18 21:37:07 +02:00
5adce08aea Optimized variable names 2025-08-18 21:26:46 +02:00
2569abc0be Refactor systemctl services and timers
- Unified service templates into generic systemctl templates
- Introduced reusable filter plugins for script path handling
- Updated path variables and service/timer definitions
- Migrated roles (backup, cleanup, repair, etc.) to use systemctl role
- Added sys-daemon role for core systemd cleanup
- Simplified timer handling via sys-timer role

Note: This is a large refactor and some errors may still exist. Further testing and adjustments will be needed.
2025-08-18 21:22:16 +02:00
3a839cfe37 Refactor systemctl services and categories due to alarm bugs
This commit restructures systemctl service definitions and category mappings.

Motivation: Alarm-related bugs revealed inconsistencies in service and role handling.

Preparation step: lays the groundwork for fixing the alarm issues by aligning categories, roles, and service templates.
2025-08-18 13:35:43 +02:00
29f50da226 Add custom Ansible filter plugin get_category_entries
This commit introduces a new Ansible filter plugin named
'get_category_entries', which returns all role names under the
roles/ directory that start with a given prefix.

Additionally, unit tests (unittest framework) have been added under
tests/unit/filterplugins/ to ensure correct behavior, including:

- Returns empty list when roles/ directory is missing
- Correctly filters and sorts by prefix
- Ignores non-directory entries
- Supports custom roles_path argument
- Returns all roles when prefix is empty

Reference: https://chatgpt.com/share/68a2f1ab-1fe8-800f-b22a-28c1c95802c2
2025-08-18 11:27:26 +02:00
a5941763ff refactor: normalize Jinja2 spacing in volume paths and add async support in backup task
- Standardized spacing in {{ docker_compose.directories.volumes }} across multiple roles
- Added async and poll support to sys-bkp-docker-2-loc database seeding and file permission tasks
- Moved Installation.md for web-app-matrix into docs/ for better structure
2025-08-18 01:05:01 +02:00
3d7bbabd7b mailu: enable central database, improve token creation task, and add migration guide
- Enabled central_database in Mailu config
- Improved API token creation task:
  * use curl -f to fail on HTTP errors
  * added explicit failed_when and changed_when conditions
- Adjusted docker-compose template spacing for readability
- Made logging level configurable (DEBUG when MODE_DEBUG is set)
- Added new documentation Move_Domain.md explaining safe procedure for migrating mailboxes to a new domain
2025-08-18 01:03:40 +02:00
e4b8c97e03 Solved port-ui keycloak url bug and optimized var names 2025-08-18 00:46:11 +02:00
29df95ed82 Optimized RBAC variables and async in keycloak 2025-08-18 00:15:41 +02:00
6443771d93 Optimized Mailu docs 2025-08-18 00:14:58 +02:00
d1cd87c843 Fix RBAC groups handling and refactor Keycloak role
- Fixed incorrect handling of RBAC group configuration (moved from OIDC claims into dedicated RBAC variable set).
- Unified RBAC group usage across applications (LAM, pgAdmin, phpLDAPadmin, phpMyAdmin, YOURLS).
- Replaced old 'KEYCLOAK_OIDC_RBAC_SCOPE_NAME' with dedicated 'KEYCLOAK_RBAC_GROUP_*' variables.
- Updated OAuth2 Proxy configuration to use 'RBAC.GROUP.CLAIM'.
- Refactored Keycloak role task structure:
  * Renamed and reorganized task files for clarity ('_update.yml', '02_cleanup.yml', etc.).
  * Introduced meta and dependency handling separation.
- Cleaned up Keycloak config defaults and recaptcha placeholders.
2025-08-17 23:27:01 +02:00
5f0762e4f6 Finished implementation of oauth2 import 2025-08-17 21:59:58 +02:00
5642793f4a Added parameter to skipp dependency loading to speed up debugging 2025-08-17 21:44:15 +02:00
7d0502ebc5 feat(keycloak): implement SPOT with Realm
Replace 01_import.yml with 01_initialize.yml (KEYCLOAK_HOST_IMPORT_DIR)
Add generic 02_update.yml (kcadm updater for clients/components)
- Resolve ID → read current → merge (kc_merge_path optional)
- Preserve immutable fields; support kc_force_attrs
Update tasks/main.yml:
- Readiness via KEYCLOAK_MASTER_REALM_URL; kcadm login
- Merge LDAP component config from Realm when KEYCLOAK_LDAP_ENABLED
- Update client settings incl. frontchannel.logout.url
realm.json.j2: include ldap.json in UserStorageProvider
ldap.json.j2: use KEYCLOAK_LDAP_* vars for bindDn/credential/connectionUrl
vars/main.yml: add KEYCLOAK_* URLs/dirs and KEYCLOAK_DICTIONARY_REALM(_RAW)
docker-compose.yml.j2: mount KEYCLOAK_HOST_IMPORT_DIR
Cleanup: remove 02_update_client_redirects.yml, 03_update-ldap-bind.yml, 04_ssh_public_key.yml; drop obsolete config flag; formatting

Note: redirectUris/webOrigins ordering may still cause changed=true; consider sorting for stability in a follow-up.
2025-08-17 14:27:33 +02:00
20c8d46f54 Keycloak import templates cleanup
- Removed all static 'id' fields from realm.json.j2, ldap.json.j2, and client.json.j2
- Replaced 'desktop-secret' with correct 'client-secret' authenticator type
- Standardized Jinja filters to use 'to_json' consistently
- Corrected defaultClientScopes entry from 'web-app-origins' to built-in 'web-origins'
- Verified LDAP mapper definitions and optional realm role mapping
- Ensured realm.json.j2 contains only required scopes

References: Chat with ChatGPT (2025-08-17)
https://chatgpt.com/share/68a1aaae-1b04-800f-aa8d-8a0ef6d33cba
2025-08-17 12:11:14 +02:00
a524c52f89 Created own ldap.json.j2 for better readability in keycloak 2025-08-17 11:49:50 +02:00
5c9ca20e04 Optimized keycloak variables 2025-08-17 11:40:15 +02:00
bfe18dd83c Refactor Keycloak role:
- Replace KEYCLOAK_KCADM_PATH with KEYCLOAK_EXEC_KCADM consistently
- Externalize client.json to separate Jinja2 template and include it in realm.json
- Simplify LDAP bind update to use explicit KEYCLOAK_LDAP_* vars
- Add async/poll support for long-running kcadm updates
- Restructure vars/main.yml: clearer grouping (General, Docker, Server, Update, LDAP, API)
- Compute redirectUris/webOrigins centrally in vars
- Align post.logout.redirect.uris handling with playbook

Conversation: https://chatgpt.com/share/68a1a11f-f8ac-800f-bada-cdc99a4fa1bf
2025-08-17 11:30:33 +02:00
0a83f3159a Updated keycloak variables 2025-08-17 10:47:40 +02:00
fb7b3a3c8e Added setting of frontchannel.logout.url for keycloak 2025-08-17 10:38:25 +02:00
42f9ebad34 Solved escaping bug 2025-08-17 09:35:19 +02:00
33b2d3f582 Optimized docker2local variables and constants 2025-08-17 09:26:46 +02:00
14e868a644 Fix OIDC issuer URL concatenation for Mastodon bug
- Removed trailing slash in '_oidc_client_issuer_url' to avoid issuer mismatch
- Use '.rstrip('/')' to normalize '_oidc_url'
- Switched to '~' concatenation instead of inline slashes for all OIDC endpoints
- Ensures that Mastodon and other OIDC clients match the issuer from Keycloak discovery

Change motivated by Mastodon issuer mismatch bug (OpenIDConnect::Discovery::DiscoveryFailed).
See related discussion: https://chatgpt.com/share/68a17d3c-c980-800f-934c-d56955b45f81
2025-08-17 09:02:38 +02:00
2a1a956739 feat(web-opt-rdr-www): split flavors into edge (Cloudflare redirect rule) and origin (Nginx redirect) with dynamic selection via prefered_flavor 2025-08-17 01:29:37 +02:00
bd2dde3af6 refactor: replace srv-web-7-7-dns-records with sys-dns-cloudflare-records
- removed obsolete role `srv-web-7-7-dns-records` (README, meta, tasks)
- updated Gitea role to use `sys-dns-cloudflare-records` with explicit record vars
- updated web-opt-rdr-www role to use new DNS role with zone detection (`to_zone`)
- added REDIRECT_WWW_FLAVOR var to support "edge" flavor selection
2025-08-16 23:52:46 +02:00
1126765da2 Fix variable definition test to detect set_fact and ansible.builtin.set_fact (both block and inline forms)
- Support fully qualified ansible.builtin.set_fact
- Parse inline set_fact mappings (e.g. set_fact: { a: 1, b: 2 })
- Continue scanning inside vars/set_fact blocks for Jinja {% set %}, {% for %}, and {% macro %}
- Ensures variables defined by set_fact are correctly recognized as defined
2025-08-16 23:51:27 +02:00
2620ee088e refactor(dns): unify Cloudflare + Hetzner handling across roles
- replaced CERTBOT_DNS_API_TOKEN with CLOUDFLARE_API_TOKEN everywhere
- introduced generic sys-dns-cloudflare-records role for managing DNS records
- added sys-dns-hetzner-rdns role with both Cloud (hcloud) and Robot API flavors
- updated Mailu role to:
  - generate DKIM before DNS setup
  - delegate DNS + rDNS records to the new generic roles
- removed legacy per-role Cloudflare vars (MAILU_CLOUDFLARE_API_TOKEN)
- extended group vars with HOSTING_PROVIDER for rDNS flavor decision
- added hetzner.hcloud collection to requirements

This consolidates DNS management into reusable roles,
supports both Cloudflare and Hetzner providers,
and standardizes variable naming across the project.
2025-08-16 21:43:01 +02:00
838a55ea94 Solved realm bug which appeared due to refactoring 2025-08-16 18:38:22 +02:00
1b26f1da8d Deactivated IP6 for Mailu 2025-08-16 18:17:09 +02:00
43362e1694 Optimized sys-hlth-csp performance 2025-08-16 18:03:44 +02:00
14d3f65a70 Included docker compose handler flush for mailu 2025-08-16 18:02:40 +02:00
b8ccd50ab2 Added async und logs 2025-08-16 17:29:16 +02:00
4a39cc90c0 Solved variable bugs in sys-svc-cert-sync-docker 2025-08-16 17:27:56 +02:00
0de26fa6c7 Solved bug existed due to difference between mailu domain and hostname difference. also refactored during this to find the bug 2025-08-16 14:29:07 +02:00
1bed83078e Added no_logs, asyncs, and optimized listmonk variable names 2025-08-16 02:00:13 +02:00
7ffd79ebd9 Added no_logs to mailu 2025-08-16 01:49:48 +02:00
2b7950920c Added no_logs 2025-08-16 01:41:37 +02:00
f0b323afee Added auto snippet for webserver injection 2025-08-16 01:31:49 +02:00
eadcb62f2a Added web-svc-logout as dependency for keycloak 2025-08-16 00:05:33 +02:00
cc2c1dc730 Renamed injection services 2025-08-16 00:01:46 +02:00
3b4821f7e7 Solved missing logout injection bug and refactored srv-web-7-7-inj-compose 2025-08-15 23:55:19 +02:00
5b64b47754 Added no_log 2025-08-15 23:18:44 +02:00
cb2b9462e1 Removed default 2025-08-15 21:56:20 +02:00
03564b34bb Optimized reset routine for docker images and specially discourse 2025-08-15 21:35:45 +02:00
e3b09e7f1a Refactoring of discourse role during debugging 2025-08-15 20:06:56 +02:00
3adb08fc68 Prevent exposition of applications credentials 2025-08-15 20:06:01 +02:00
e9a41bd40c Added deletion of containers to reset routine 2025-08-15 20:05:05 +02:00
cb539b038c Marked as not changed 2025-08-15 19:00:03 +02:00
3ac9bd9f90 Optimized variable typos 2025-08-15 18:43:42 +02:00
85a2f4b3d2 Solved matrix federation port bug 2025-08-15 18:37:18 +02:00
012426cf3b Added more matrix constants for easier debugging and readability 2025-08-15 18:15:58 +02:00
6c966bce2e Added health check and restart policy to openresty 2025-08-15 17:59:09 +02:00
3587531bda Removed unnecessary wait_for logic from mig 2025-08-15 15:45:20 +02:00
411a1f8931 Optimized LDAP_DN_BASE for hostname 2025-08-15 15:31:38 +02:00
cc51629337 Added spacing between {{}} 2025-08-15 15:21:48 +02:00
022800425d THE HUGE REFACTORING CALENDER WEEK 33; Optimized Matrix and during this updated variables, and implemented better reset and cleanup mode handling, also solved some initial setup bugs 2025-08-15 15:15:48 +02:00
0228014d34 Replaced .infinito.service and .infinito.timer by SOFTWARE_NAME suffix, optimized LICENSE link and update OIDC Realm and ID conf 2025-08-14 14:39:18 +02:00
1b638c366e Introduced variable SOFTWARE_NAME, to make better visible when software components are used. Will be relevant for OIDC 2025-08-14 12:49:06 +02:00
5c90c252d0 Optimized typos 2025-08-14 12:32:21 +02:00
4a65a254ae replaced port-ui-desktop with desktop to make it more speakable 2025-08-14 11:45:08 +02:00
5e00deea19 Implemented desktop csp policies 2025-08-14 11:40:09 +02:00
bf7b24c3ee Implemented get_app_conf 2025-08-14 11:14:15 +02:00
85924ab3c5 Optimized openproject csp 2025-08-14 10:59:19 +02:00
ac293c90f4 Optimized links, description and docs 2025-08-14 08:45:01 +02:00
e0f35c4bbd Added todos 2025-08-14 08:20:29 +02:00
989bee9522 Merged hp spectre and msi 2025-08-14 08:16:55 +02:00
2f12d8ea83 Added handler for discourse buiöd 2025-08-14 00:27:18 +02:00
58620f6695 Added async for DNS Records creation 2025-08-14 00:23:42 +02:00
abc064fa56 Added async for openproject settings 2025-08-14 00:07:09 +02:00
7f42462514 Fixed reload button bug 2025-08-13 23:50:35 +02:00
41cd6b7702 Replaced get_domain with get_url 2025-08-13 23:33:49 +02:00
a40d48bb03 Refactor srv-web-7-7-inj-port-ui-desktop to use CDN-served JS file with inline initializer
- Added vars/main.yml to define iframe-handler.js file name and destination
- Implemented 01_deploy.yml to deploy iframe-handler.js to CDN and set mtime-based version fact
- Split original iframe logic into:
  • iframe-handler.js (full logic, served from CDN)
  • iframe-init_one_liner.js.j2 (small inline bootstrap, CSP-hashed)
- Updated head_sub.j2 to load script from CDN instead of embedding full code
- Added body_sub.j2 for inline init code
- Updated iframe-handler.js.j2 with initIframeHandler() function and global exposure
- Activated role earlier in inj-compose with public: true so vars are available for templates
- Included 'port-ui-desktop' in body_snippets loop in location.lua.j2
- Disabled 'port-ui-desktop' feature in web-svc-cdn config by default

https://chatgpt.com/share/689d03a8-4c28-800f-8b06-58ce2807b075
2025-08-13 23:29:32 +02:00
2fba32d384 Solved listmonk path bug 2025-08-13 22:39:43 +02:00
f2a765d69a Removed unused ansible matrix role 2025-08-13 22:01:09 +02:00
c729edb525 Refactor async task handling
- Standardize async/poll usage with 'ASYNC_ENABLED | bool'
- Add async/poll parameters to Cloudflare, Nginx, Mailu, MIG, Nextcloud, and OpenLDAP tasks
- Update async configuration in 'group_vars/all/00_general.yml' to ensure boolean evaluation
- Allow CAA, cache, and DNS tasks to run asynchronously when enabled

https://chatgpt.com/share/689cd8cc-7fbc-800f-bd06-a667561573bf
2025-08-13 21:56:26 +02:00
597e9d5222 Refactor async execution handling across LDAP and Nextcloud roles
- Introduce global async configuration in group_vars/all/00_general.yml:
  - ASYNC_ENABLED (disabled in debug mode)
  - ASYNC_TIME (default 300s, omitted if async disabled)
  - ASYNC_POLL (0 for async fire-and-forget, 10 for sync mode)
- Replace hardcoded async/poll values with global vars in:
  - svc-db-openldap (03_users.yml, 04_update.yml)
  - web-app-mig (02_build_data.yml)
  - web-app-nextcloud (03_admin.yml, 04_system_config.yml, 05_plugin.yml,
    06_plugin_routines.yml, 07_plugin_enable_and_configure.yml)
- Guard changed_when and failed_when conditions to only evaluate in synchronous
  mode to avoid accessing undefined rc/stdout/stderr in async runs

  https://chatgpt.com/share/689cd8cc-7fbc-800f-bd06-a667561573bf
2025-08-13 20:26:40 +02:00
db0e030900 Renamed general and mode constants and implemented a check to verify that constants are just defined ones over the whole repository 2025-08-13 19:11:14 +02:00
004507e233 Optimized handler flushing 2025-08-13 18:17:05 +02:00
e2014b9b59 nextcloud(role): remove async → use batched shell; more robust changed_when/failed_when; fix quoting; refactor plugin routines; clean up vars
• 02_add_missing_indices.yml: switched to shell (+ansible_command_timeout), removed async/poll.

• 04_system_config.yml: batch OCC calls (set -euo pipefail, /bin/bash), safer quoting, change detection via ' set to '.

• 05_plugin.yml: disable task with stricter failed_when/changed_when (combine stdout+stderr).

• 06_plugin_routines.yml: disable incompatible plugins in a single batch; no async_status; robust changed_when.

• 07_plugin_enable_and_configure.yml: batch config:app:set, safe quoting, clear changed_when/failed_when.

• config/main.yml & vars/main.yml: removed performance.async.wait_for and nextcloud_wait_for_async_enabled.
2025-08-13 18:15:50 +02:00
567b1365c0 Nextcloud: async overhaul & task refactor (conditional wait, faster polling)
• Add config.performance.async.wait_for and expose as nextcloud_wait_for_async_enabled to toggle waiting for async jobs.

• Split system/admin/index maintenance into separate tasks: 02_add_missing_indices.yml, 03_admin.yml, 04_system_config.yml.

• Refactor plugin flow: rename 02_plugin→05_plugin, 03_plugin_routines→06_plugin_routines, 04_plugin_enable_and_configure→07_plugin_enable_and_configure; remove old 03_plugin_routines and 05_system.

• Harden async handling: filter async_status loops by ansible_job_id; conditionally wait only when nextcloud_wait_for_async_enabled; reduce delay to 1s.

• Reorder main.yml to run system steps before plugin setup; keep handlers flush earlier.

• env.j2: simplify get_app_conf lookups (drop extra True flag).

• vars/main.yml: add nextcloud_host_nginx_path and nextcloud_wait_for_async_enabled.

https://chatgpt.com/share/689c9d4a-1748-800f-b490-06a5a48dd831
2025-08-13 16:13:00 +02:00
e99fa77b91 Optimized docker handlers for espocrm and wordpress 2025-08-13 13:34:12 +02:00
80dad1a5ed Removed proxy_extra_configuration fact 2025-08-13 06:32:52 +02:00
03290eafe1 feat(proxy,bigbluebutton): use parameterized HTML location template & add build retry
- proxy(html.conf.j2):
  * Make proxy_pass more robust (strip '=', '^~' prefixes; ignore @/~ match locations)
  * Switch WS header to $connection_upgrade
  * Unify timeouts (proxy_connect_timeout 5s)
  * Lua optional: include only when proxy_lua_enabled=true; unset Accept-Encoding only then
  * Buffering via flag: proxy_buffering/proxy_request_buffering 'on' with Lua, otherwise 'off'
- proxy(media.conf.j2): minor formatting/spacing fix
- inj-css(head_sub.j2): consistent spacing for global_css_version
- bigbluebutton(tasks/main.yml):
  * Render HTML location block once before include_role (location='^~ /html5client', OAuth2/Lua disabled)
  * Pass rendered snippet via proxy_extra_configuration to the vHost
  * Cleanup afterwards: proxy_extra_configuration = undef()
- docker-compose(handlers):
  * Build with retry: if 'docker compose build' fails -> retry with '--no-cache --pull'
  * Enable BuildKit (DOCKER_BUILDKIT=1, COMPOSE_DOCKER_CLI_BUILD=1)
- vars: trailing newline / minor formatting

Motivation:
- BBB HTML5 client (^~ /html5client) needs a separate location without Lua/buffering.
- More resilient CI/CD builds via automatic no-cache retry.
- Cleaner headers/proxy defaults and fewer side effects.

Files:
- roles/docker-compose/handlers/main.yml
- roles/srv-proxy-7-4-core/templates/location/html.conf.j2
- roles/srv-proxy-7-4-core/templates/location/media.conf.j2
- roles/srv-web-7-7-inj-css/templates/head_sub.j2
- roles/web-app-bigbluebutton/tasks/main.yml
- roles/web-app-bigbluebutton/vars/main.yml
2025-08-13 06:01:50 +02:00
58c64bd7c6 Placed docker compose flush more specific 2025-08-13 03:53:13 +02:00
e497c001d6 keycloak: robust LDAP bind and connectionUrl update via kcadm (argv + JSON); strict ldap.*; idempotent
Switch to command:argv to avoid shell quoting and argument splitting issues.

Pass -s config values as JSON arrays via to_json, fixing previous errors: Cannot parse the JSON / failed at splitting arguments.

Also reconcile config.connectionUrl from ldap.server.uri.

Source desired values strictly from ldap.* (no computed defaults) and assert their presence.

Keep operation idempotent by reading current values and updating only on change.

Minor refactor: build reusable kcadm_argv_base and expand client state extraction.

Touch: roles/web-app-keycloak/tasks/03_update-ldap-bind.yml

https://chatgpt.com/share/689bea84-7188-800f-ba51-830a0735f24c
2025-08-13 03:30:14 +02:00
4fa1c6cfbd ansible: quote file modes; keycloak: robust LDAP bind update + config cleanup
Highlights
- Quote all file modes as strings ("0755"/"0770") across multiple roles to avoid YAML octal quirks and improve portability.
- Keycloak: introduce actions.{import_realm,update_ldap_bind} feature flags and wire them via vars/config.
- Implement idempotent LDAP bind updater (tasks/03_update-ldap-bind.yml):
  * kcadm login with no_log protection,
  * fetch LDAP UserStorage component by name,
  * compare current bindDn/bindCredential and update only when changed.
- Keycloak realm import template: keep providerId="ldap" and set name from keycloak_ldap_component_name.
- Centralize Keycloak readiness check in tasks/main.yml; remove duplicate waits from 02_update_client_redirects.yml and 04_ssh_public_key.yml.
- 01_import.yml: fix typo (keycloak), quote modes, tidy spacing, and replace Jinja-in-Jinja fileglob with concatenation.
- 02_update_client_redirects.yml: correct assert fail_msg filename; keep login-first flow.
- Minor template/vars tidy-ups (spacing, comments, consistent variable usage).

Files touched (excerpt)
- roles/*/*: replace 0755/0770 → "0755"/"0770"
- roles/web-app-keycloak/config/main.yml: add actions map
- roles/web-app-keycloak/vars/main.yml: unify Keycloak vars and feature flags
- roles/web-app-keycloak/tasks/{01_import,02_update_client_redirects,03_update-ldap-bind,04_ssh_public_key,main}.yml
- roles/web-app-keycloak/templates/{docker-compose.yml.j2,import/realm.json.j2}

https://chatgpt.com/share/689bda16-b138-800f-8258-e13f6d7d8239
2025-08-13 02:20:38 +02:00
53770f5308 Optimized flush order to solve yourls oauth2 proxy bug 2025-08-13 01:03:31 +02:00
13d8663796 Added version and repository to bbb 2025-08-13 00:35:14 +02:00
f31565e4c5 Optimized URLS 2025-08-13 00:33:47 +02:00
a4d8de2152 feat(web-app-espocrm): ensure 'siteUrl' is updated to canonical domain on deploy
Use EspoCRM's ConfigWriter API to patch the 'siteUrl' setting during updates.
This makes the process idempotent, avoids brittle regex replacements, and
ensures the running configuration stays in sync with the deployment domain.

https://chatgpt.com/share/689bb860-ba90-800f-adb5-4fa5a992b267
2025-08-12 23:56:19 +02:00
c744ebe3f9 feat(web-app-wordpress): add idempotent single-site domain update via WP-CLI
- New task 04_update_domain.yml updates home/siteurl only when needed
- DB-wide search-replace (old → new), GUID-safe, precise, tables-with-prefix
- Normalizes http→https, strips trailing slashes, then flushes cache/rewrites
- Guarded by is_multisite()==0; multisite untouched
- Wired into main.yml with auto target URL via domains|get_url

Fixes post-domain-change mixed/CSP issues due to hard-coded old URLs.

https://chatgpt.com/share/689bac2d-3610-800f-b6f0-41dc79d13a14
2025-08-12 23:03:59 +02:00
ce029881d0 cmp-rdbms: make vars resilient when database_type is empty
Fix a templating crash during docker-compose.yml rendering when a role sets database_type to an empty string or does not expose it (e.g., svc-prx-openresty). Previously _database_id resolved to 'svc-db-' and get_app_conf attempted to read 'docker.services..name', raising AppConfigKeyError: Application ID 'svc-db-' not found.

Changes:
- Introduce _dbtype = (database_type | d('') | trim) and build _database_id only if _dbtype is non-empty.
- Guard central DB lookups: use get_app_conf(..., strict=False, default='') and only when _dbtype is set.
- Default _database_consumer_entity_name to get_entity_name of database_application_id or fallback to application_id.
- Only resolve database_port when _dbtype is set; otherwise empty.
- Minor formatting fixes for env and URL strings.

Impact:
- Prevents failures in roles without a DB or with database_type=''.
- Keeps previous behavior intact for apps with a valid database_type (mariadb/postgres).
- Eliminates 'config_path: docker.services..name' errors while keeping compose templates stable.

https://chatgpt.com/share/689b9d11-6308-800f-b20c-2d9f18d832f1
2025-08-12 21:59:37 +02:00
94da112736 perf(friendica): single-pass patch for DB creds + system.url; align env URL; tidy vars
- Patch local.config.php in one sed exec:
  * hostname, database, username, password
  * system.url via '#' delimiter to avoid URL slash escaping
  * Single notify: docker compose up
- env.j2:
  * FRIENDICA_URL now uses domains|get_url(application_id, WEB_PROTOCOL)
  * Simplify FRIENDICA_DEBUGGING with |lower
  * Normalize spacing for readability
- vars/main.yml:
  * Minor cleanups (comment header, spacing)
  * Consistent friendica_docker_ldap_config path construction

Why: fewer container execs ⇒ faster runs; idempotent key updates; consistent URL configuration across env and PHP config.
Risk: requires WEB_PROTOCOL and domains|get_url to be defined in inventory/vars as elsewhere in the project.

https://chatgpt.com/share/689b92af-b184-800f-9664-2450e00b29d6
2025-08-12 21:15:33 +02:00
b62df5599d Optimized typos 2025-08-12 19:17:02 +02:00
c9a7830953 Renamed to CONSTANT DATABASE_VARS_FILE 2025-08-12 17:45:19 +02:00
53e5c563ae Refactor MIG build process to run asynchronously with optional wait control
- Moved MIG data build commands into a dedicated 02_build_data.yml task file.
- Added async execution (async: 3600, poll: 0) for non-blocking build.
- Introduced mig_wait_for_build variable to optionally wait for completion.
- Added debug message to inform how to disable waiting via build_data.wait_for=false for performance.
- Updated config to use nested build_data.enabled and build_data.wait_for structure.
- Adjusted variable lookups accordingly.

https://chatgpt.com/share/689b54d2-e3b0-800f-91df-939ebc5e12ef
2025-08-12 16:51:24 +02:00
0b3b3a810a Solved bug which prevented backup2loc to be activated 2025-08-12 15:42:26 +02:00
6d14f16dfd Optimized sys-timer 2025-08-12 15:00:12 +02:00
632d922977 Solved discourse flush handlers bug 2025-08-12 14:59:00 +02:00
26b29debc0 Add integration test to ensure no Jinja variables are used in handler names
This test scans roles/*/handlers/main.yml and fails if a handler's 'name' contains a Jinja variable ({{ ... }}).
Reason:
- Handler names must be static to ensure reliable 'notify' resolution.
- Dynamic names can break handler matching, cause undefined-variable errors, and produce unstable logs.
Recommendation:
- Keep handler names static and, if dynamic behavior is needed, use a static 'listen:' key.

https://chatgpt.com/share/689b37dc-e1e4-800f-bd56-00b43c7701f6
2025-08-12 14:48:43 +02:00
0c4cd283c4 Optimized CDN variables during bug research 2025-08-12 14:31:24 +02:00
5d36a806ff svc-db-postgres: add retry mechanism to all PostgreSQL tasks and fix condition handling
- Added register, until, retries, and delay to all PostgreSQL-related tasks
  in 02_init.yml to handle transient 'tuple concurrently updated' and similar errors.
- Changed 'when: "{{ postgres_init }}"' to 'when: postgres_init | bool' in main.yml
  for correct boolean evaluation.
- Switched 'role' to 'roles' in postgresql_privs tasks for forward compatibility.
- Added postgres_retry_retries and postgres_retry_delay defaults in vars/main.yml
  to centralize retry configuration.

  https://chatgpt.com/share/689b2360-a8a4-800f-9acb-6d88d6aa5cb7
2025-08-12 13:20:30 +02:00
84de85d905 Solved matrix flush handler bug 2025-08-12 12:54:27 +02:00
457f3659fa Solved mobilizon flush docker handler bug 2025-08-12 12:03:53 +02:00
4c7ee0441e Solved baserow variable bugs 2025-08-12 11:23:56 +02:00
140572a0a4 Solved missing deployment of postgres bug 2025-08-12 10:58:09 +02:00
a30cd4e8b5 Solved listmonk handler bugs 2025-08-12 04:38:41 +02:00
2067804e9f Solved ansible multiplexing auth bug 2025-08-12 04:23:45 +02:00
1a42e8bd14 Replaced depenencies by includes for performance reasons 2025-08-12 03:08:33 +02:00
8634b5e1b3 Finished move_unnecessary_dependencies implementation 2025-08-12 02:39:22 +02:00
1595a7c4a6 Optimized tests für run once 2025-08-12 02:38:37 +02:00
82aaf7ad74 fixed move_unnecessary_dependencies.py 2025-08-11 23:41:48 +02:00
7e4a1062af Added draft for fixing dependencies 2025-08-11 23:16:32 +02:00
d5e5f57f92 Optimized openproject for new repository structure 2025-08-11 23:03:24 +02:00
f671678720 Add integration test to detect unnecessary meta dependencies
This test scans all roles/*/meta/main.yml for meta dependencies that are
likely unnecessary and could be replaced with guarded include_role/import_role
calls to improve performance.

A dependency is flagged as unnecessary when:
- The consumer role does not use provider variables in defaults/vars/handlers
  (no early variable requirement), and
- Any usage of provider variables or handler notifications in tasks occurs
  only after an explicit include/import of the provider in the same file,
  or there is no usage at all.

Purpose:
Helps reduce redundant parsing/execution of roles and improves Ansible
performance by converting heavy global dependencies into conditional,
guarded includes where possible.

https://chatgpt.com/share/689a59ee-52f4-800f-8349-4f477dc97c7c
2025-08-11 23:00:49 +02:00
2219696c3f Removed redirects for performance 2025-08-11 22:21:17 +02:00
fbaee683fd Removed dependencies and used include_roles to raise performance and make infinito to a racing car 2025-08-11 21:56:34 +02:00
b301e58ee6 Removed redirect to safe performance 2025-08-11 21:48:33 +02:00
de15c42de8 Added database patch to wordpress 2025-08-11 21:46:29 +02:00
918355743f Updated ansible.cfg for better performance and tracking 2025-08-11 21:00:33 +02:00
f6e62525d1 Optimized wordpress variables 2025-08-11 20:00:48 +02:00
f72ac30884 Replaced redirects by origine to raise performance 2025-08-11 19:44:14 +02:00
1496f1de95 Replaced community.general.pacman: by pacman to raise performance 2025-08-11 19:33:28 +02:00
38de10ba65 Solved bigbluebutton admin creation bug 2025-08-11 19:24:08 +02:00
e8c19b4b84 Implemented correct path replace not just for context: but also for build: paths 2025-08-11 18:46:02 +02:00
b0737b1cdb Merge branch 'master' of github.com:kevinveenbirkenbach/cymais 2025-08-11 14:31:19 +02:00
e4cc928eea Encapsulated SAN in block with when 2025-08-11 14:31:10 +02:00
c9b2136578 Merge pull request #5 from ocrampete16/logs-dir
Create logs dir to prevent failing test
2025-08-11 14:15:39 +02:00
5709935c92 Improved performance by avoiding the load of roles which are anyhow just protected by one condition 2025-08-11 13:52:24 +02:00
c7badc608a Solved typo 2025-08-11 13:25:32 +02:00
0e59d35129 Update RunOnceSchemaTest to skip files with deactivated run_once variables via comment https://chatgpt.com/share/6899d297-4bec-800f-a748-6816398d8c7e 2025-08-11 13:23:20 +02:00
1ba50397db Optimized performance by moving multiple similar when includes to own tasks file 2025-08-11 13:15:31 +02:00
6318611931 Add integration test to detect excessive duplicate 'when' conditions in tasks files
This test scans all .yml/.yaml files under any tasks/ directory and flags cases where the same
'when' condition appears on more than 3 tasks in the same file. Excessive duplication of identical
conditions can harm Ansible performance because the condition is re-evaluated for every task.

The test suggests replacing repeated conditions with an include_tasks call or a block guarded
by the condition to evaluate it only once.

https://chatgpt.com/share/6899c605-6f40-800f-a954-ccb62f8bbcf1
2025-08-11 12:29:57 +02:00
6e04ac58d2 Moved blocks to include_tasks to raise performance. Deploy was really slow 2025-08-11 12:28:31 +02:00
b6e571a496 Solved config path entry bug 2025-08-11 12:19:24 +02:00
21b6362bc1 test(integration): fail if reset.yml exists but is never included
Updated test_mode_reset.py to also validate roles that contain a reset
task file (*_reset.yml or reset.yml) even when no mode_reset keyword is
found. The test now:

- Detects roles with reset files but no include, and fails accordingly.
- Ignores commented include_tasks and when lines.
- Ensures exactly one non-commented include of the reset file exists.
- Requires that the include is guarded in the same task block by a
  when containing mode_reset | bool (with optional extra conditions).

This prevents silent omissions of reset task integration.

https://chatgpt.com/share/6899b745-7150-800f-98f3-ca714486f5ba
2025-08-11 11:27:15 +02:00
1fcf072257 Added performance violation test for blocks 2025-08-11 10:50:42 +02:00
ea0149b5d4 Replaced nextcloud-application by nextcloud container name 2025-08-11 10:41:06 +02:00
fe76fe1e62 Added correct flush parameters for docker compose 2025-08-11 10:33:48 +02:00
3431796283 Wrapped docker compose file routines tasks in block for docker compose 2025-08-11 10:20:06 +02:00
b5d8ac5462 Reactivated keycloak docker and webserver tasks and implemented correct logic for element and synapse redirect handling 2025-08-11 02:21:02 +02:00
5426014096 Optimized handlers order for mailu 2025-08-11 01:56:22 +02:00
a9d77de2a4 Optimized docker compose ensure logic 2025-08-11 01:26:31 +02:00
766ef8619f Encapsulated cmp-docker-oauth2 into block 2025-08-11 01:25:31 +02:00
66013a4da3 Added line 2025-08-11 01:24:02 +02:00
1cb5a12d85 Encapsulated srv-web-7-7-letsencrypt into block 2025-08-11 01:23:00 +02:00
6e8ae793e3 Added auto setting for redirect urls for keycloak clients. Element and Synapse still need to be mapped 2025-08-11 00:17:18 +02:00
0746acedfd Introduced run_once_ block for srv-web-6-6-tls-renew 2025-08-10 21:50:39 +02:00
f5659a44f8 Optimized blocks in roles/srv-proxy-6-6-domain/tasks/main.yml 2025-08-10 18:31:12 +02:00
77816ac4e7 Solved bkp_docker_to_local_pkg bug 2025-08-10 18:17:52 +02:00
8779afd1f7 Removed beep backup sound 2025-08-10 17:54:14 +02:00
0074bcbd69 Implemented functioning warning sound 2025-08-10 17:39:33 +02:00
149c563831 Optimized logic for database backups and integrated test to verify that database feature is used correct 2025-08-10 15:06:37 +02:00
e9ef62b95d Optimized cloudflare purge and cache dev mdoe 2025-08-10 14:18:29 +02:00
aeaf84de6f Deactivated central_database for lam 2025-08-10 13:42:52 +02:00
fdceb0f792 Implmented dev mode für cloudflare 2025-08-10 12:18:17 +02:00
2fd83eaf55 Keep logs during deploy cleanup 2025-08-10 12:01:34 +02:00
Marco Petersen
21eb614912 Create logs dir to prevent failing test 2025-08-10 12:50:13 +03:00
b880b98ac3 Added hints for infinito modes 2025-08-10 11:34:33 +02:00
acfb1a2ee7 Made logs folder permanent 2025-08-10 11:31:56 +02:00
4885ad7eb4 Overwritte handlers for CDN 2025-08-09 18:08:30 +02:00
d9669fc6dd Added test to verify that no handlers are skipped due to when condition 2025-08-09 15:24:47 +02:00
8e0341c120 Solved some handler reloading bugs 2025-08-08 19:33:16 +02:00
22c8c395f0 Refactored handlers loading 2025-08-08 19:01:12 +02:00
aae69ea15b Ensure that keycloak is up 2025-08-08 17:25:31 +02:00
c7b25ed093 Normalized run_once_, made openresty handlers without when aviable and forced flush in run_once when blocks to avoid handlers with when conditions 2025-08-08 15:32:26 +02:00
e675aa5886 Wrapped in block to avoid multiple similar when conditions for 7-4 web core 2025-08-08 12:25:09 +02:00
14f07adc9d Wrapped in block to avoid multiple similar when conditions 2025-08-08 12:14:01 +02:00
dba12b89d8 Normalized cmp-docker-proxy include 2025-08-08 12:02:14 +02:00
0607974dac Patched url in moodle config 2025-08-08 11:46:23 +02:00
e8fa22cb43 Normalized variable 2025-08-08 11:27:34 +02:00
eedfe83ece Solved missing redirect bug 2025-08-08 11:03:43 +02:00
9f865dd215 Removed catetory domain präfix from redirect domains 2025-08-08 09:47:31 +02:00
220e3e1c60 Optimized namings in moodle 2025-08-08 09:12:50 +02:00
2996c7cbb6 Added default value for internet interfadces 2025-08-08 08:39:40 +02:00
59bd4ca8eb Added handling of multiple domains and used get_url function in mailu 2025-08-08 08:39:09 +02:00
da58691d25 Added comments why autoflush isn't possible 2025-08-08 08:37:52 +02:00
c96f278ac3 Added autoflush to mastodon für docker 2025-08-08 08:37:12 +02:00
2715479c95 Assert just applications which are in group_names 2025-08-08 08:36:07 +02:00
926640371f Optimized description 2025-08-08 08:35:16 +02:00
cdc97c8ba5 Raised certbot_dns_propagation_wait_seconds to 5min 2025-08-08 08:34:49 +02:00
4124e97aeb Added domain validator for web- apps and services for port-ui 2025-08-07 20:37:47 +02:00
7f0d40bdc3 Optimized code 2025-08-07 18:17:38 +02:00
8dc2238ba2 Optimized Funkwhale bug 2025-08-07 17:52:34 +02:00
b9b08feadd Added logout overwritte logic for espocrm 2025-08-07 17:35:13 +02:00
dc437c7621 Activated logout catcher 2025-08-07 16:11:20 +02:00
7d63d92166 Solved status codes bug 2025-08-07 15:46:56 +02:00
3eb51a32ce Adapted webserver test for web-app-yourls 2025-08-07 15:35:33 +02:00
6272303b55 Changed LAM container name 2025-08-07 15:34:40 +02:00
dfd7be9d72 Solved database naming bug 2025-08-07 15:11:45 +02:00
90ad688ca9 Solved bbb backup bug 2025-08-07 14:57:02 +02:00
2f02ad6c15 Moved docs and anylyses from code to cloud 2025-08-07 13:41:31 +02:00
1257bef61d Solved reset bug 2025-08-07 13:28:40 +02:00
3eca5dabdf Fixed certificate renewal bug 2025-08-07 13:21:38 +02:00
5a0684fa2d Adapted CSP to new server dict structure 2025-08-07 13:00:52 +02:00
051e4accd6 Activated redirect for yourls homepage to admin pannel 2025-08-07 12:59:54 +02:00
7f53cc3a12 Replaced web_protocol by WEB_PROTOCOL 2025-08-07 12:31:20 +02:00
9228d51e86 Restructured server config 2025-08-07 11:31:06 +02:00
99c6c9ec92 Optimized CSP check 2025-08-07 09:33:19 +02:00
34f9d773bd Deactivated meta CSP via HTML due to management via infintio.nexus 2025-08-06 16:26:35 +02:00
5edb9d19cf Activated sphinx listener 2025-08-06 16:12:38 +02:00
7a09f223af Implemented the correct setup of the bbb administrator 2025-08-06 15:51:08 +02:00
f88e57ca52 Optimized debugging documentation and deprecated warning for openresty 2025-08-06 14:18:32 +02:00
7bc11f9b31 Renamed parameter 2025-08-06 12:56:31 +02:00
0b25161af6 Merge branch 'master' of github.com:kevinveenbirkenbach/cymais 2025-08-06 12:30:20 +02:00
14c3ff1253 Renamed doamin mappigns to redirect_domain_mappings 2025-08-06 12:30:12 +02:00
234cfea02f Merge pull request #4 from ocrampete16/normalize-line-endings
Normalize line endings
2025-08-06 00:47:54 +02:00
Marco Petersen
69e29029af Normalize line endings 2025-08-05 22:05:46 +03:00
bc5374cf52 Merge pull request #3 from ocrampete16/clone-on-windows
Enable cloning on Windows
2025-08-05 19:28:44 +02:00
Marco Petersen
1660bcd384 Remove duplicate README.md 2025-08-05 00:28:29 +03:00
Marco Petersen
41d924af1c Remove mistakenly cloned file 2025-08-05 00:24:31 +03:00
80278f2bb0 Solved CLI bug 2025-07-29 16:46:50 +02:00
44e0fea0b2 Renamed cymais to infinito and did some other optimations and logout implementations 2025-07-29 16:35:42 +02:00
a9e7ed3605 Implemented flexible upload limits for wordpress and matrix :) 2025-07-26 11:22:01 +02:00
f9f76892af Solved peertube bugs 2025-07-26 08:08:51 +02:00
996244b672 Solved application_id overwritting bug 2025-07-25 22:15:09 +02:00
9f61b4e50b Added database type to postgres 2025-07-25 21:32:40 +02:00
3549f4de32 Activated domains creation for svc-db- due to that the domains are used for certificate creation and they need it to use secure communication 2025-07-25 21:12:45 +02:00
552bb1bbae Moved python packages to requirements.txt for venv instead of local install 2025-07-25 20:44:45 +02:00
1b385c5215 Added request to requirements.txt 2025-07-25 20:41:08 +02:00
1240d3bfdf Added debugging option to keycloak 2025-07-25 20:14:04 +02:00
27973c2773 Optimized injection layer on lua base, as replace for nginx replace. Also optimized cloudflare cache deletion(no everytime for cleanup). Still CDN is required for logout mechanism via JS and Nextcloud deploy is buggy after changing from nginx to openresty. Propably some variable overwritte topic. Should be solved tomorrow. 2025-07-24 19:13:13 +02:00
f62355e490 Replaced nginx native with openresty for logout injection. Right now still buggy on nextcloud and espocrm 2025-07-24 03:19:16 +02:00
f5213fd59c Optimized virtualbox draft 2025-07-23 21:18:09 +02:00
0472fecd64 Solved ooauth2 bugs and restructured postgres roile to implement extensions used by discourse 2025-07-23 13:24:55 +02:00
d1fcbedef6 Set correct roles path for oidc keycloak groups\roles 2025-07-22 22:11:00 +02:00
c8be88e3b1 Activated redis for oauth2 for large cookies 2025-07-22 22:00:11 +02:00
5e315f9603 Activated correct oidc solution for nextcloud 2025-07-22 21:32:26 +02:00
bab1035a24 Activated oauth2 for lam 2025-07-22 21:31:11 +02:00
30930c4136 Fixed empty canonicals 2025-07-22 19:26:44 +02:00
bba663f95d Added missing canonicals 2025-07-22 19:20:29 +02:00
c2f83abb60 Added better debugging 2025-07-22 19:14:40 +02:00
3bc64023af Added logout pages to some applications 2025-07-22 18:49:23 +02:00
d94254effb Made canonical domains obligatorix 2025-07-22 18:47:38 +02:00
ff18c7cd73 Expect this to solve openldap import bug 2025-07-22 14:18:33 +02:00
a84abbdade Deactivated ESPOCRM for port-ui tmp until bug is solved 2025-07-22 14:14:41 +02:00
5dc8ec2344 Deactivated caching 2025-07-22 13:53:20 +02:00
4b9e7dd3b7 Implemented universal logout 2025-07-22 13:14:06 +02:00
22ff2dc1f3 Solved cleanup file naming bug 2025-07-22 12:48:22 +02:00
16c1a5d834 Refactored get_app_conf 2025-07-22 10:08:47 +02:00
b25f7f52b3 Left hint 2025-07-22 08:34:26 +02:00
4826de621e Solved drive optimizer path bug 2025-07-22 08:33:58 +02:00
4501c31756 Solved docker compose handler bugs 2025-07-22 08:33:36 +02:00
c185c537cb Added auto seeding of credentials 2025-07-21 17:52:19 +02:00
809ac1adf4 Removed unnecessary schema 2025-07-21 17:43:45 +02:00
1a2451af4e Added workflow deploy routine draft 2025-07-21 17:41:57 +02:00
e78974b469 Solved openldap folder naming bug 2025-07-21 17:41:18 +02:00
b1bf7aaba5 Fixed BBB stuff 2025-07-21 15:10:05 +02:00
a1643870db Optimized auto playbook creation 2025-07-21 15:09:38 +02:00
aeeae776c7 Finished implementation of correct application id 2025-07-21 11:33:35 +02:00
356c214718 Renamed multiple roles incl. oauth2 to to web-app-* 2025-07-21 11:28:54 +02:00
4717e33649 Renamed multiple roles incl. gitlab to to web-app-* 2025-07-21 11:25:24 +02:00
ee4ee9a1b7 Changed funkwhale to web-app-funkwhale 2025-07-21 11:14:02 +02:00
57211c2076 Changed phpldapadmin to web-app-phpldapadmin 2025-07-21 11:12:05 +02:00
2ffaadfaca Changed bluesky to web-app-bluesky 2025-07-21 11:10:06 +02:00
bc5059fe62 Solved taiga path bugs 2025-07-21 10:56:55 +02:00
e6db73c02a Changed taiga to web-app-taiga 2025-07-21 10:47:45 +02:00
4ad6f1f8ea Changed roulette-wheel to web-app-roulette-wheel 2025-07-21 10:40:02 +02:00
7e58b825ea Changed pgadmin to web-app-pgadmin 2025-07-21 10:36:51 +02:00
f3aa7625fe Renamed presentation to navigator 2025-07-21 09:22:30 +02:00
d9c4493e0d Optimized mode_reset test 2025-07-21 09:08:03 +02:00
14dde77134 Implemented correct sphinx id 2025-07-21 08:56:23 +02:00
fd422a14ce Set correct id for simpleicons 2025-07-21 08:52:22 +02:00
5343536d27 Optimized snipe-it und bbb 2025-07-21 01:40:42 +02:00
6e2e3e45a7 Solved matrix bug 2025-07-21 01:36:10 +02:00
ed866bf177 Finished bbb implementation 2025-07-20 20:07:43 +02:00
a580f41edd Replaced aur_builder by builder in dockerfile 2025-07-20 18:39:54 +02:00
dcb57af6f7 Implemented gitea database patch 2025-07-20 18:14:20 +02:00
2699edd197 Optimized friendica database patch 2025-07-20 16:13:48 +02:00
257d0c4673 Set entity name as default domain instead of application_id 2025-07-20 15:44:28 +02:00
4cbd29735f Solved pixelfed bugs 2025-07-20 15:43:48 +02:00
8ea86d2bd7 Solved friendica path bug and closed all failed tests! PAAAAAAAAAAAAAAAAAARTY! 2025-07-20 14:34:57 +02:00
3951376a29 Added draft for neovim and micro 2025-07-20 14:27:09 +02:00
e1d36045da Solved open run_once issues 2025-07-20 14:23:08 +02:00
c572d535e2 Optimized test for tree creation 2025-07-20 11:41:16 +02:00
c79dbeec68 Optimized run_once variable 2025-07-20 11:31:15 +02:00
5501e40b7b Optimized run_once test 2025-07-20 11:21:14 +02:00
e84c7e5612 Optimized desk-copyq draft and implemented server to use in gnome 2025-07-20 11:20:49 +02:00
be675d5f9e Solved variable name bugs 2025-07-20 10:52:33 +02:00
bf16a44e87 Implemented allowed_groups 2025-07-20 10:46:35 +02:00
98cc3d5070 Changed yourls to yourls and additional optimations 2025-07-20 10:41:06 +02:00
2db5f75888 Changed snipe-it to web-app-snipe-it and additional optimations 2025-07-20 10:26:09 +02:00
867b377115 Changed mobolizon to web-app-mobilizon 2025-07-20 10:10:17 +02:00
1882fcfef5 Changed lam to web-app-lam 2025-07-20 09:59:31 +02:00
15dc99a221 Activated port ui desktop for mobilizon 2025-07-20 09:45:41 +02:00
6b35454f35 Solved openproject variable bug 2025-07-20 09:44:14 +02:00
d86ca6cc0e Adapted discourse version to new code after the big refactoring 2025-07-20 09:29:56 +02:00
1b9775ccb5 Added draft for desk-copyq (untested) 2025-07-19 17:02:25 +02:00
45d9da3125 Implemented friendica database credentials update (untested) 2025-07-19 16:45:04 +02:00
8ccfb1dfbe Added icon to mig 2025-07-19 16:26:10 +02:00
6a1a83432f Different optimations and mig integration. test will fail due to strickter validation checks. need to be cleaned up tomorrow 2025-07-18 20:08:20 +02:00
85195e01f9 Activated loading of env depending on if it exist 2025-07-18 19:40:34 +02:00
45624037b1 Added shadow option to tree for mig 2025-07-18 19:35:44 +02:00
d4fbdb409f Added missing sounds file from previous commit 2025-07-18 14:44:38 +02:00
a738199868 Added run_once_validator 2025-07-18 14:43:53 +02:00
c1da74de3f Optimized sound for cli 2025-07-18 14:43:09 +02:00
c23624e30c Added workflow todos 2025-07-18 11:45:46 +02:00
0f1f40f2e0 Optimized deployment script 2025-07-18 11:42:05 +02:00
d1982af63d Optimized mastodon and network integration. added options for mig build to make 2025-07-17 18:50:28 +02:00
409e659143 Overall optimations for application id naming 2025-07-17 17:41:52 +02:00
562603a8cd Restructured libraries 2025-07-17 16:38:20 +02:00
6d4b7227ce Added variable desktop_username to identify the user on a single user pc workstation 2025-07-17 16:10:39 +02:00
9a8ef5e047 Implemented new appid for bbb 2025-07-17 16:04:05 +02:00
ad449c3b6a Adapted roles to new architecture 2025-07-17 15:39:31 +02:00
9469452275 Finalized matomo integration into new architecture 2025-07-17 12:09:20 +02:00
fd8ef26b53 Solved streaming bugs 2025-07-17 09:47:08 +02:00
8cda54c46e Finished moodle adaptation to new structure 2025-07-17 09:18:24 +02:00
90bc52632e Moved web-app-phpmyadmin to new structure 2025-07-17 08:24:07 +02:00
0b8d2e0b40 Solved variable bug 2025-07-17 08:22:59 +02:00
40491dbc2e Solved typos in port-ui 2025-07-17 07:54:19 +02:00
fac8971982 Solved typo 2025-07-17 07:49:05 +02:00
c791e86b8b Solved discourse variable bug 2025-07-17 07:46:39 +02:00
d222b55f30 Changed espocrm application id to new forma 2025-07-17 07:43:50 +02:00
a04a1710d3 Changed keycloak application id 2025-07-17 07:16:38 +02:00
4f06f94023 Added credentials replacement draft for matomo 2025-07-17 06:57:35 +02:00
2529c7cdb3 Optimized moodle variables 2025-07-17 06:56:54 +02:00
ab12a933f6 Optimized keycloak variables 2025-07-17 06:56:26 +02:00
529efc0bd7 Optimized moodle variable names 2025-07-17 06:38:51 +02:00
725fea1169 Solved database credentials bug 2025-07-17 06:32:53 +02:00
84322f81ef Implemented draft for auto database credentials change moodle 2025-07-17 06:31:55 +02:00
fd637c58e3 Solved oauth2 path bugs 2025-07-17 05:49:45 +02:00
bfc42ce2ac Different little optimations 2025-07-17 04:23:05 +02:00
1bdfb71f2f Finished backup update 2025-07-17 00:34:54 +02:00
807fab42c3 Solved variable escaping bug 2025-07-16 23:09:42 +02:00
2f45038bef Solved variable bugs 2025-07-16 23:01:25 +02:00
f263992393 Added recursion test for group_vars 2025-07-16 22:31:48 +02:00
f4d1f2a303 Added partial test and skip-build flag 2025-07-16 22:16:22 +02:00
3b2190f7ab Replaced by loading of default values 2025-07-16 21:46:44 +02:00
7145213f45 Finished new backup implementation logik 2025-07-16 20:49:20 +02:00
70f7953027 Added backup value key mapper 2025-07-16 20:03:00 +02:00
c155e82f8c Solved variable bugs 2025-07-16 19:30:54 +02:00
169493179e Restructuring for new backup solution 2025-07-16 19:09:31 +02:00
dea2669de2 Solved unclosed file <_io.TextIOWrapper warnings 2025-07-16 14:33:10 +02:00
e4ce3848fc Optimized for github workflow 2025-07-16 14:22:47 +02:00
8113e412dd Deactivated tests during docker build, in the hope that it now passes the git workflow 2025-07-16 14:07:20 +02:00
94796efae8 Replaced cp by rsync to keep .git folder for workflow 2025-07-16 13:45:33 +02:00
7aed3dd8c2 Created autocreate of .dockerignore via Makefile 2025-07-16 13:30:02 +02:00
1a649568ce Removed emojis 2025-07-16 13:14:42 +02:00
f9f7d9b299 Optimized README.md 2025-07-16 13:13:25 +02:00
9d8e48d303 Added explicit testing during container build. It isn't possible to build the container if it doesn'nt pass the tests. 2025-07-16 12:46:56 +02:00
f9426cfb74 Optimized role structure in preparation for new backup script 2025-07-16 12:31:01 +02:00
e56c960900 Added missing moduls to requirements.txt 2025-07-16 10:43:21 +02:00
41934ab285 Removed unnecessary 'cymais' 2025-07-16 10:24:31 +02:00
932ce7c8ca Changed from Badge to text 2025-07-16 10:23:57 +02:00
0730c1efd5 Optimized README.md try it out text 2025-07-16 10:23:01 +02:00
fd370624c7 Optimized README.md 2025-07-16 10:15:45 +02:00
4b8b04f29c Removed unnecessary 'cymais' präfix from github workflow command 2025-07-16 09:41:34 +02:00
2d276cfa5e Optimized Dockerfile and github workflow 2025-07-16 09:38:19 +02:00
241c5c6da8 Optimized test_main.py 2025-07-16 08:25:16 +02:00
af3ea9039c Restructure and cleaned up in preparation of new backup logic 2025-07-15 23:51:51 +02:00
c8054ffbc3 Optimized get paths and applications generation 2025-07-15 22:48:59 +02:00
54490faca7 Ignore comment out paths 2025-07-15 22:31:11 +02:00
b6eb73dee4 Implemented that schemas are recognized 2025-07-15 22:22:22 +02:00
3fed9eb75a Ignore ansible_memtotal_mb 2025-07-15 21:40:32 +02:00
45c18b69ba Ignore {% 2025-07-15 21:39:41 +02:00
ac3bc5742d Added credentials for telegram bot 2025-07-15 20:36:16 +02:00
f6c767f122 Optimized svc-bkp-loc-2-usb 2025-07-15 20:29:01 +02:00
5e83f306b4 Set default swapfile size to memory size 2025-07-15 18:39:29 +02:00
2e2501980c Added recognition of option_kv 2025-07-15 18:19:48 +02:00
cb9a7b2ade used set_fact 2025-07-15 18:17:42 +02:00
a6afbaff38 Implemented vars files scanning on n levels 2025-07-15 18:13:33 +02:00
111d6ac50d Optimized pkgmgr-install 2025-07-15 17:59:32 +02:00
766fe39c4c Optimized desk-ssh conf 2025-07-15 17:52:05 +02:00
8254bc9f07 Optimized dev-npm role 2025-07-15 17:46:29 +02:00
a8139c2e72 Removed not used variable 2025-07-15 17:36:34 +02:00
f8264b88d5 Removed unnecessary variable 2025-07-15 17:33:38 +02:00
779823eb09 Implemented correct variable 2025-07-15 17:31:52 +02:00
0d5f369755 Moved to web-app-matrix-ansible 2025-07-15 17:28:01 +02:00
4627d9031c Optimized svc-bkp-rmt-2-loc and moved conf into role config 2025-07-15 17:25:19 +02:00
8ac88475d5 Added todos for roles 2025-07-15 17:11:02 +02:00
da88871108 Added todos for keycloak 2025-07-15 17:10:32 +02:00
b61f695aac Added test for no_stop_required attribute 2025-07-15 17:10:05 +02:00
a6000d7666 Updated role template draft 2025-07-15 17:08:32 +02:00
b5b65c4f67 Made updates invokable 2025-07-15 17:07:50 +02:00
ea79b9456a Optimized variable typo 2025-07-15 17:07:14 +02:00
7c9b895dbe Updated pkgmgr docs 2025-07-15 17:06:29 +02:00
3c759cbb4c Renamed to matrix ansible 2025-07-15 17:05:32 +02:00
733356b4f7 Added pattern for register: variables 2025-07-15 17:04:36 +02:00
21b4fdee47 Added pattern to whitelist set- for- 2025-07-15 16:57:39 +02:00
294a43bd97 Added missing application id 2025-07-15 16:40:47 +02:00
dd73a87e19 Moved nextcloud client configuration 2025-07-15 16:34:25 +02:00
bb7859ab44 Optimized update roles 2025-07-15 15:18:07 +02:00
bbabc58cf9 Optimized webport and certbot_dns_api_token 2025-07-15 15:04:27 +02:00
959c48c1a1 Optimized svc-opt-ssd-hdd config 2025-07-15 14:58:15 +02:00
253b088cdb Optimized swapfile config 2025-07-15 14:54:55 +02:00
c99def5724 Optimized variable definition tester 2025-07-15 14:31:03 +02:00
75a5ab455e Moved language definition to hunspell and libreoffice role 2025-07-15 14:30:26 +02:00
d5c14ad53c Added varaible defintion test draft 2025-07-15 13:54:10 +02:00
e90c9a18b0 Added get_cymais_path (Rename it later) 2025-07-15 11:58:21 +02:00
fff06d52b8 Added variable usage test 2025-07-15 11:57:31 +02:00
f02ca50f88 Renamed backup roles 2025-07-14 19:04:30 +02:00
4acf2137e8 Activated flush 2025-07-14 18:43:20 +02:00
6a447a1426 Solved Openldap network bug 2025-07-14 18:42:25 +02:00
d1c8036fa4 Implemented DB Credentials Update for Nextcloud and solved bug 2025-07-14 18:41:30 +02:00
30d583f0c9 Activated autoflush for EspoCRM and updated docs concerning this option 2025-07-14 13:22:02 +02:00
f7aab39167 Optimized reload button 2025-07-14 13:04:41 +02:00
e4028fccf4 General optimations during inventory cleanup 2025-07-14 13:02:06 +02:00
b6ee7b9f98 Optimized openldap network 2025-07-14 12:13:11 +02:00
67122800f3 Optimized openldap role 2025-07-14 12:00:18 +02:00
bfd1a2ee70 Optimized keycloak variables 2025-07-14 11:20:10 +02:00
076a2058cc Solved variable naming bugs 2025-07-14 11:19:54 +02:00
9dc55c5893 Optimized warnings 2025-07-14 11:19:29 +02:00
81ef808191 Optimized mariadb 2025-07-14 10:26:12 +02:00
8161dd1b6d Optimized postgres 2025-07-14 10:05:22 +02:00
ac72544b72 Added validation for deploy application ids 2025-07-14 09:52:53 +02:00
732607bbb6 Added provisioning switches for openldap to improve performance 2025-07-14 08:45:53 +02:00
c6f49dc6e2 Solved oauth2 configuration bugs 2025-07-14 00:33:39 +02:00
ce68391b4e Solved variable naming bug 2025-07-14 00:32:57 +02:00
c42d7cdf19 Updated database variables 2025-07-14 00:32:23 +02:00
f012b4fc78 Restructured openldap tasks 2025-07-14 00:31:47 +02:00
56f6a2dc3b Solved default variable bug 2025-07-14 00:04:13 +02:00
632ad14bd8 Solved application id bug in keycloak 2025-07-13 23:12:13 +02:00
fb0ca533ae Moved database port mapping to central port configuration file 2025-07-13 23:06:11 +02:00
6fbe550afe Solved Database bugs 2025-07-13 22:30:41 +02:00
294d402990 Finished Dockerfile 2025-07-13 21:39:13 +02:00
95cbce93f0 Optimized web app role template 2025-07-13 21:29:23 +02:00
77b3ca5fa2 Allowed key entries with - 2025-07-13 21:20:52 +02:00
33d14741e2 Added j2 sniffer and solved syntax bugs 2025-07-13 21:20:23 +02:00
ed67ca0501 Solved typo bug 2025-07-13 21:10:50 +02:00
8f31b2fbfe Execute Matomo before other roles 2025-07-13 21:10:20 +02:00
325695777a Finished CyMaIS Dockerfile setup base 2025-07-13 20:38:29 +02:00
4c9ae52fd7 Optimized virtual environment und sudo 2025-07-13 20:30:00 +02:00
3c22fb8d36 Catch not fitting to scheme bug 2025-07-13 20:21:42 +02:00
ae8a0d608b Deactivated second openldap network 2025-07-13 20:21:14 +02:00
f9aa1ed2a4 Solved docker network bug 2025-07-13 20:20:14 +02:00
8e4e497d2c Added Dockerfile draft 2025-07-13 19:55:06 +02:00
24d2c0edb5 Solved variable but 2025-07-13 19:19:57 +02:00
e1d090ce04 Removed is_feature_enabled entry 2025-07-13 18:32:50 +02:00
56caecc5d8 Restored get_docker_image functionality 2025-07-13 18:27:24 +02:00
63bf7f7640 Removed legacy code function 2025-07-13 18:02:44 +02:00
ad60f5fb37 Rmeoved is_feature_enabled function 2025-07-13 17:54:09 +02:00
991ed7d614 Finished integration test 2025-07-13 17:27:56 +02:00
840836702d Ignored .py .sh 2025-07-13 17:19:12 +02:00
9142eeba3c Improved performance 2025-07-13 17:02:37 +02:00
882cf47c20 Added credentials testing 2025-07-13 16:58:33 +02:00
e8992f254c Solved bugs identified during unit test 2025-07-13 16:55:08 +02:00
92245b5935 Added basic integration test for get_app_path values to verify if they exists 2025-07-13 16:43:33 +02:00
a98332bfb9 Semi bsr replace part two 2025-07-13 15:35:55 +02:00
422e4c136d Added another test to check that get_app_conf delivers dict correct 2025-07-13 15:13:38 +02:00
756597668c Semi bsr for applications[] to prevent heavy to debug bugs in j2 - part 1 2025-07-13 15:11:38 +02:00
4cc4195fab Added refactoring script 2025-07-13 14:34:56 +02:00
78031855b9 Replaced portfolio_iframe by port-ui-desktop 2025-07-13 14:22:36 +02:00
5340d580ce Optimized filter functions 2025-07-13 14:20:22 +02:00
c8669e19cf Implemented new get_app_conf function 2025-07-13 13:36:52 +02:00
a18e888044 Implemented new matomo setup 2025-07-13 12:58:10 +02:00
4e3c124f55 Added a tool to get full j2 files for debugging 2025-07-13 02:58:19 +02:00
f744747cef Added some variable debugging tools 2025-07-13 02:57:03 +02:00
bff6f8b5a0 Changed to docker 2025-07-13 02:44:41 +02:00
99316c1088 Added github workflow 2025-07-13 02:42:01 +02:00
3c701118e8 Optimized menu 2025-07-13 00:42:25 +02:00
f07557c322 Implemented dict renderer to resolve assets 2025-07-12 23:25:31 +02:00
4f5afa1220 Finished portfolio implementation 2025-07-12 22:06:57 +02:00
ead60dab84 Fail safed more parts of the code 2025-07-12 21:35:33 +02:00
066b4d59d6 Optimized rdr roles 2025-07-12 18:59:07 +02:00
0fd5cdb5d6 Renamed portfolio to portwebui 2025-07-12 18:41:13 +02:00
f15f498c1d Restructured webserver optimation roles 2025-07-12 18:08:44 +02:00
46bba3564d Renamed redis role 2025-07-12 17:58:04 +02:00
e2b5491e1f Optimized roles documentation 2025-07-12 17:52:36 +02:00
32dc27aebd Optimized categories and passed all unit tests 2025-07-12 17:47:35 +02:00
adec2aed84 Renamed generate commands to build 2025-07-12 17:11:41 +02:00
3eb8b54a1a Restructured CLI meta commands 2025-07-12 17:05:00 +02:00
80ca12938b Added ports tests 2025-07-12 16:27:23 +02:00
3b03c5171d Renamed the mariadb, openldap and postgres database 2025-07-12 16:06:13 +02:00
e174523fc6 Solved collection dependency bug 2025-07-12 13:42:45 +02:00
b2e32aacf3 Optimized template descriptions 2025-07-12 13:42:07 +02:00
6db7144b08 Added warnings concerning application_id 2025-07-12 12:01:05 +02:00
34d5c415bb Added invokable test 2025-07-12 11:56:20 +02:00
c09dec8b0f Moved sys-opt-ssd-hdd to a callable version in svc-opt-ssd-hdd 2025-07-12 11:42:25 +02:00
f2187e4bc0 Added git cleanup tag to makefile 2025-07-12 10:51:46 +02:00
abd2545346 Solved validation import bug 2025-07-12 10:20:30 +02:00
e14e6b96e9 Renamed Database roles 2025-07-12 10:11:52 +02:00
44834f9873 Added more debugging stuff 2025-07-11 21:04:55 +02:00
5dcc13cb24 Added additional unit test to debug html edge cas 2025-07-11 20:29:52 +02:00
25e4a50974 Cleaning up of gen roles 2025-07-11 19:19:24 +02:00
33276263b0 Another bulk of refaktoring cleanup 2025-07-11 18:57:40 +02:00
168c5c0da6 Another big round of refactoring and cleaning... 2025-07-11 17:55:26 +02:00
aa61bf2a44 Removed unecessary application_id s 2025-07-11 15:25:58 +02:00
25cee9a4c7 Finished Graph and Tree implementation 2025-07-11 14:33:27 +02:00
6780950257 Added run_after integration test 2025-07-11 13:53:12 +02:00
23bbe0520c Added draft for graph generation 2025-07-11 07:40:41 +02:00
3c63936970 Different optimations 2025-07-11 05:29:06 +02:00
9fa39e5f25 Added graph functions 2025-07-11 05:28:19 +02:00
b494b80520 Fixed refactoring bugs of role namis 2025-07-11 03:16:16 +02:00
691b204512 Added validation for get_domain calls 2025-07-11 03:05:41 +02:00
7fba13b550 Solved wrong namings 2025-07-11 02:59:25 +02:00
f9b3fb8cfa Renamed group for better identification 2025-07-11 02:26:20 +02:00
60ab31c623 Optimized inventory validation 2025-07-11 02:03:33 +02:00
80d26ca068 Validated use of correct applications in group_names 2025-07-11 01:53:38 +02:00
d43fdc63ea Optimized inventory validator for wrong groups 2025-07-11 01:34:44 +02:00
6e32b20240 Finished new role identification system implementation 2025-07-11 00:42:36 +02:00
292918da81 Implemented auto creation of role groups 2025-07-10 23:40:18 +02:00
1f4dee49bc Solved last open tests 2025-07-10 23:19:44 +02:00
3141166fb5 Added application ids to all relevant roles 2025-07-10 23:08:47 +02:00
dca04540d4 Solved relative path bug 2025-07-10 22:50:52 +02:00
e6075738b7 Finished main.py 2025-07-10 22:02:26 +02:00
38d83d18d2 Added highlight and more usability stuff to cli 2025-07-10 21:54:13 +02:00
4de60d4162 Optimized cli script 2025-07-10 21:40:57 +02:00
c160c58a5c Restructured CLI logic 2025-07-10 21:26:44 +02:00
8457325b5c Added new logic in cli proxy script to allow better restructuring of cli files 2025-07-10 19:27:36 +02:00
74ebb375d0 Added invokable paths for role categories 2025-07-10 18:28:39 +02:00
12d833d20c Added new categories description scheme 2025-07-10 15:36:40 +02:00
8b2768daea Added application ids to driver 2025-07-10 14:43:32 +02:00
81ab323c29 Fixed util- roles application ids 2025-07-10 14:35:31 +02:00
3c3739c234 Fixed desk roles application ids 2025-07-10 14:31:09 +02:00
e794da47e2 Renamed desk roles and added vars/main.yml files where mising 2025-07-10 14:19:59 +02:00
5a3535187a Restructured service und web role naming in inventor 2025-07-10 14:01:12 +02:00
c1975faa7b Merge branch 'master' of github.com:kevinveenbirkenbach/cymais 2025-07-10 12:46:09 +02:00
bafd9e0f23 REmoved dep because they get included via task 2025-07-10 12:45:59 +02:00
3f7a46177b Changed utils- to util- 2025-07-10 12:42:50 +02:00
ff38b86493 Added more debugging hints to tls-core 2025-07-10 12:40:47 +02:00
96268e7161 Renamed server roles by osi they work on 2025-07-10 12:33:46 +02:00
c94d623f8f Added role log at iframe injector 2025-07-10 11:52:46 +02:00
707cc9d2d1 Removed ignore errors from db management in discourse 2025-07-10 11:44:35 +02:00
41d023abee Solved oauth2 bug 2025-07-09 22:45:08 +02:00
f3439861bb minor improvements 2025-07-09 20:28:58 +02:00
7a38241485 Made code more modular and refactored to cmp roles 2025-07-09 20:15:32 +02:00
993469fd82 Added meta/main.yml #2 2025-07-09 18:16:23 +02:00
944707ec41 Solved dependency bug which appeared due to autogeneration of meta/main.yml files 2025-07-09 18:01:58 +02:00
0b80ba6f54 Added auto generated meta/main.yml #1 for sphinx run 2025-07-09 17:47:43 +02:00
22049cd1ca Optimized README's and meta/main.ymls for Sphinx Build 2025-07-09 17:42:28 +02:00
b610d211c5 Updated portfolio categories 2025-07-09 17:16:11 +02:00
da0b339995 Solved bug which appeared during refactoring in ESPOCRM 2025-07-09 16:41:51 +02:00
5adcc5b931 Moved build before validation, because otherwise it will fail 2025-07-09 16:23:58 +02:00
338b09b755 Added flush 2025-07-09 15:48:59 +02:00
f3939661e4 Implemented filter functions to get roles by application_id 2025-07-09 14:52:51 +02:00
c9c73cbdb2 Decoupeld database, docker and proxy 2025-07-09 14:21:30 +02:00
73329506a9 Solved bug which existed due to user structure refactoring 2025-07-09 12:31:37 +02:00
e7322a239e Solved different bugs 2025-07-09 11:51:42 +02:00
a026681553 Task include tests implemented, nginx restart, etc. 2025-07-09 11:41:17 +02:00
46cf65f296 Optimized Matomo role 2025-07-09 10:59:36 +02:00
af3767fdfa General optimations 2025-07-09 10:17:32 +02:00
a69b2c9cb2 Solved run_after dependency bug 2025-07-09 06:47:10 +02:00
39d2e6c0fa Shortend Applications 2025-07-09 05:40:54 +02:00
69ad91ee91 Added Applications to README.md 2025-07-09 05:32:36 +02:00
5cd94c1d0a Added README.md 2025-07-09 05:25:43 +02:00
a0a61ad304 Removed text 2025-07-09 05:17:42 +02:00
50c502d331 Updated README.md 2025-07-09 05:16:36 +02:00
575df76ec3 Shortened service- to svc- 2025-07-09 05:00:41 +02:00
db384c6261 Shortened server- to srv- 2025-07-09 04:45:15 +02:00
2108702a2b Shortened network- to net- 2025-07-09 04:35:21 +02:00
66198ca1ec Shortened webserver to srv-web- 2025-07-09 04:27:58 +02:00
1f43536018 Little tweaks :) 2025-07-09 03:55:42 +02:00
94bb060a5b Shorted generic- to gen- 2025-07-09 03:55:24 +02:00
8c411a21c7 Updated README's 2025-07-09 03:51:28 +02:00
3fdd900ed8 Shorted driver- to drv- 2025-07-09 03:49:01 +02:00
f548faa80f Shorted cleanup- to cln- 2025-07-09 03:45:02 +02:00
9668e74139 Shorted backup- to bkp- 2025-07-09 03:36:44 +02:00
d0bd33fee3 Shorted maintenance- to maint- 2025-07-09 03:25:03 +02:00
ae5f021b8d Shorted monitor-bot- to mon-bot- 2025-07-09 03:22:01 +02:00
dd1aab70fb Shortend desktop to desk 2025-07-09 03:18:07 +02:00
e4ff99e336 Deleted personas and replaced by utils 2025-07-09 03:09:12 +02:00
ed0cd9b8c0 Restructured users 2025-07-09 02:26:50 +02:00
22b4342300 Implemented schema/main.yml und config/main.yml file 2025-07-09 02:03:32 +02:00
7362accab0 Renamed alert-bot to alert-compose 2025-07-09 00:11:41 +02:00
8da2e41463 Solved letsencrypt reference bugs 2025-07-09 00:07:12 +02:00
563d5fd528 Huge role refactoring/cleanup. Other commits will propably follow. Because some bugs will exist. Still important for longrun and also for auto docs/help/slideshow generation 2025-07-08 23:43:13 +02:00
6b87a049d4 Added infinite proxy execution mode 2025-07-08 17:12:01 +02:00
9cbd2d4f4b Solved OAuth2 Bug 2025-07-08 14:03:51 +02:00
36ff93e64e General optimations and debugging 2025-07-08 13:50:23 +02:00
cb29a479b3 Added registration information to README.md 2025-07-08 05:26:20 +02:00
e729706ec6 Solved None key bugs and implemented tests to prevent it in the future 2025-07-08 02:13:47 +02:00
9159a0c7d3 Finished Iframe Implementation 2025-07-08 01:34:18 +02:00
a100c9e63d Solved condition and tab bugs 2025-07-07 21:44:33 +02:00
f254c9711d Activated iframe for all applications 2025-07-07 20:20:39 +02:00
cbe9efbdc8 little tweeks 2025-07-07 14:52:22 +02:00
a6d226769c Different optimations and bugs 2025-07-07 12:52:37 +02:00
e2b0e7b492 Embeded via iframe in portfolio 2025-07-07 12:50:21 +02:00
a7b9467304 Optimized template 2025-07-07 07:34:41 +02:00
8200abad85 Renamed matomo 2025-07-07 07:27:51 +02:00
3f87f1fcd8 Added simpleicons network and port configuration 2025-07-07 07:26:55 +02:00
63af5b8ef6 Finished simpleicons implementation 2025-07-07 07:25:57 +02:00
a51bc1f4c7 Solved Moodle port mapping bug 2025-07-07 05:21:36 +02:00
b9e5c3a337 Added tests for create docker function 2025-07-07 04:58:03 +02:00
75d603db5b Finished role creator 2025-07-07 04:53:18 +02:00
a1465ef886 Solved tab bug 2025-07-07 04:51:04 +02:00
eccace60f4 Optimized docker creation script 2025-07-07 04:41:42 +02:00
634f1835fc Optimized role creation script 2025-07-07 04:31:43 +02:00
9762de2901 Added line breaks 2025-07-07 04:31:20 +02:00
e25565c517 Solved docker refactoring bug 2025-07-07 03:58:40 +02:00
ca0602a1c8 Finished docker refactoring 2025-07-07 03:48:19 +02:00
38ed1e94e8 Refactored docker-compose roles 2025-07-07 03:24:54 +02:00
2ea7a606b6 Optimized READMEs 2025-07-06 21:48:09 +02:00
e61ef82f17 Optimized READMEs 2025-07-06 21:44:50 +02:00
acad3f217f Finished docker template 2025-07-06 21:14:47 +02:00
fe9d3aa4aa Replaced Additional Ressources with Further Ressources 2025-07-06 21:05:39 +02:00
86d7be5615 Solved variable bug 2025-07-06 21:04:02 +02:00
5919f49741 Solved other refactoring bugs and optimized docker role template 2025-07-06 19:54:51 +02:00
ea9cc07112 Solved not defined variable bug 2025-07-06 19:14:30 +02:00
03eaf75c4a Solved docker repository path 2025-07-06 19:04:34 +02:00
0347d238c2 Great docker refactoring 2025-07-06 18:53:45 +02:00
bd9e43506f Refactored file creation 2025-07-06 15:20:43 +02:00
cfeb8a5bf8 General optimations and refactorings in preparation for simpleicon role implementation 2025-07-06 14:54:31 +02:00
eed72368c1 Added simple-icons role draft 2025-07-06 12:08:37 +02:00
c537a1f5b6 Solved wrong variable naming bug 2025-07-05 11:24:48 +02:00
018b4843f7 Optimized documentation 2025-07-05 11:22:19 +02:00
b76f0e2190 Optimized email 2025-07-05 02:21:28 +02:00
7a42e6d9ce Updated Portfolio Infos 2025-07-05 02:12:23 +02:00
a918dbfe03 Renamed Nextcloud 2025-07-05 01:59:46 +02:00
8cd7379419 Added draft for nested groups 2025-07-04 23:43:38 +02:00
dc6454e910 Updated portfolio categories 2025-07-04 23:36:52 +02:00
1df0e38f06 Updated docu 2025-07-04 23:28:55 +02:00
c3575e5647 Solved other minor bugs 2025-07-04 22:12:42 +02:00
7950a3f517 Solved minor bugs 2025-07-04 21:59:57 +02:00
52f467c15c Added application ids filter for easier partial deployment 2025-07-04 21:52:37 +02:00
9f1d153053 Added new Fediverse Ideas 2025-07-04 21:49:56 +02:00
1858c1970f Added ldap support 2025-07-04 21:49:31 +02:00
06b864ad52 Refactored LDAP and Keycloak implementation and added RBAC based groups to Keycloak 2025-07-04 16:16:45 +02:00
ee0561db72 Optimized RBAC via LDAP 2025-07-04 08:03:27 +02:00
a9f55579a2 Reorgenized test structure and added validation of inventory before deployment 2025-07-04 01:14:00 +02:00
fe04f1955f removed default value 2025-07-04 00:41:59 +02:00
d5af5cd78a Added inventory validator for applications 2025-07-04 00:39:02 +02:00
56b3f854c5 Added gid to applications to make them posix group ldap compatible 2025-07-03 23:51:14 +02:00
a93e1520d4 Optimized RBAC implementation 2025-07-03 22:51:42 +02:00
1486862327 Added notifier and plugin check for peertube oidc plugin 2025-07-03 21:19:58 +02:00
3600874223 Solved users recreated by backup restore bug 2025-07-03 21:04:40 +02:00
a3fd74c2e0 Removed generation of alphanumeric users 2025-07-03 20:00:05 +02:00
e032fd1aa4 Added mailu_token_enabled condition 2025-07-03 12:39:28 +02:00
fd63f84f21 Optimized Postgres role 2025-07-03 12:18:18 +02:00
eea0adb764 Optimized CRM email titel 2025-07-03 09:56:43 +02:00
0766bb4162 Implemented new run_after logic 2025-07-03 09:39:35 +02:00
03db141316 Updated user logic 2025-07-02 18:29:53 +02:00
9cf18cae0e Solved default password bug 2025-07-02 16:27:54 +02:00
e807a3e956 Rewrote to unittest 2025-07-02 16:01:04 +02:00
ef663a1356 Implemented unittest import check 2025-07-02 15:59:40 +02:00
821275ce70 Add blacklisted usernames 2025-07-02 15:57:14 +02:00
9d1b44319c Optimized logic for user generation 2025-07-02 15:20:55 +02:00
cb6fbba8f4 Added new user generation script and optimized mail config 2025-07-02 15:08:42 +02:00
2ccfdf0de6 Finished Funkwhale implementation 2025-07-02 02:07:41 +02:00
28b41382d2 Deactivated login mask 2025-07-01 22:31:55 +02:00
4cffddab51 Finished Mobilizon OIDC implementation 2025-07-01 22:15:05 +02:00
3ce6e958b4 Optimized LDAP. Implemented passwordchange, usernames etc. 2025-07-01 16:45:03 +02:00
ff2b402ea7 Removed setting of password 2025-07-01 15:13:56 +02:00
bdc0074542 Finished LDAP implementation 2025-07-01 15:11:13 +02:00
abc9a46667 Optimized LDAP implementation for Snipe-IT and implemented Mobilizon draft 2025-07-01 09:08:12 +02:00
4963503f2c Adapted LDAP user directory filter 2025-07-01 04:18:07 +02:00
15121fd905 Whitelisted Server IP's and implemented deactivation option for ldap user directory in nextcloud 2025-07-01 02:25:05 +02:00
b83d596789 Solved ESPOCRM CSP bug 2025-07-01 00:59:16 +02:00
925f20f1e1 optimized CSP for peertube 2025-06-30 18:10:19 +02:00
02d478186c Added LDAP draft for snipe it 2025-06-30 11:06:25 +02:00
227c206d69 Added Smoke Test (Blackbox not reviewed) for create_credentials 2025-06-28 19:47:09 +02:00
68dabf6c97 Optimized create_credentials to skip existing values 2025-06-28 19:43:14 +02:00
1344d1a2ea Added DNS configuration for gitea 2025-06-28 17:58:17 +02:00
e63895b5b7 Solved Nextcloud LDAP User Bug 2025-06-28 17:09:59 +02:00
c464cc6688 Optimized Nextcloud implementation 2025-06-28 15:19:51 +02:00
b3cc070394 Changed ldap.attributes.lastname to ldap.attributes.surname 2025-06-28 00:06:46 +02:00
d815b9ee62 Added SSH Public Key Logic for keycloak 2025-06-27 23:27:59 +02:00
b3e82fa457 Added SSH Pub Key implementation in Gitea 2025-06-27 17:25:12 +02:00
40edaa52ad Refactored ldap implementation for ssh keys 2025-06-27 16:41:10 +02:00
bb73e948d3 Replaced OIDC login for gitea with oauth2 proxy and LDAP to guaranty correct username etc. 2025-06-27 02:19:12 +02:00
6d4723b321 Implemented OIDC für LDAP 2025-06-26 21:16:07 +02:00
f86568fb85 Added link how to sync ldap 2025-06-23 23:28:25 +02:00
ffcce08f28 Added message sending for all host variable types 2025-06-23 23:19:28 +02:00
cfc052c129 Solved bugs appearing during backup-server setup (light weigth installation) 2025-06-20 15:50:24 +02:00
20c3fdd455 Added base for openproject nextcloud integration bug 2025-06-20 13:13:15 +02:00
68287c3c66 Activated Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always for Nextcloud 2025-06-20 10:23:37 +02:00
716c1c40e9 Added optimized CSS für modals 2025-06-20 10:06:04 +02:00
aa4d54c0c2 Merge branch 'master' of github.com:kevinveenbirkenbach/cymais 2025-06-20 09:52:13 +02:00
0ca33139b8 Solved variable refence bugs 2025-06-20 09:51:58 +02:00
1ed26ab706 Implemented discourse LDAP draft 2025-06-20 05:45:43 +02:00
13141ac7d6 Solved discourse mail bug 2025-06-20 03:55:51 +02:00
7abfe85021 Solved https bug 2025-06-20 03:00:35 +02:00
c1c2921ce5 Added correct username policy, compatible with all oidc services 2025-06-20 00:43:57 +02:00
0114b30824 Solved EOL bug 2025-06-19 14:49:50 +02:00
7dd8fd4a5f Added --git-clean function to cleanup before run 2025-06-19 12:56:31 +02:00
c700ff3ee7 Implemented --log option to create logfile.log 2025-06-19 12:47:45 +02:00
03192dd4f3 Implemented OIDC für pixelfed 2025-06-19 10:02:03 +02:00
ceab517dfa Solved alias domain bug for mysql.cymais.cloud, mariadb.cymais.cloud in context of docker-phpmyadmin 2025-06-19 00:57:37 +02:00
ada1f84c0b Solved matrix bridge bug 2025-06-19 00:56:55 +02:00
94dd57d5cd Added Collabora draft for nextcloud 2025-06-19 00:56:28 +02:00
ae25673853 Solved different small bugs 2025-06-18 21:04:04 +02:00
19a489b3c5 Finished Moodle OIDC Login Base 2025-06-18 18:25:23 +02:00
f5bacf17b3 Added draft for pixelfed OIDC 2025-06-18 15:15:48 +02:00
8b5c61953e Solved CSP bugs 2025-06-18 14:29:16 +02:00
25ba93cbfd Implemented new filter for image logic in docker-compose.yml.j2 und env.j2 files 2025-06-18 14:28:06 +02:00
ced5e27453 Optimized run order so that it doesn't fail if matomo is not up 2025-06-18 14:27:09 +02:00
380aa4a37b Optimized code, so that 'docker compose up' can run until setup is finished without any interruptions 2025-06-17 15:08:42 +02:00
4fbf8f505c Solved moodle database character issue: https://github.com/bitnami/containers/issues/81439#issuecomment-2977590924 2025-06-17 12:29:33 +02:00
fedaa02067 Solved another mailu CSP bug 2025-06-16 18:03:25 +02:00
4c53a95e79 Solved another CSP for mailu bug 2025-06-12 17:48:31 +02:00
0767d4175c Optimized CSP for mailu 2025-06-12 12:01:26 +02:00
66fae5815d Optimized CSP for portfolio 2025-06-12 11:40:51 +02:00
2541cc1c91 Solved CSP bugs for echoserver 2025-06-10 18:25:39 +02:00
90e9e00205 Deactivated CSS for open project temporary 2025-06-10 14:02:12 +02:00
04e07b072d Solved peertube CSP bug 2025-06-10 13:41:32 +02:00
5077f5f6ad Optimized Wordpress conf and solved snipe-it CSP bug 2025-06-05 00:06:43 +02:00
24cd75ac26 Solved different bugs e.g. csp and optimized deploy help 2025-06-04 19:50:11 +02:00
6d857663fb Solved csp bugs 2025-06-03 17:49:55 +02:00
ebd74db3c4 Optimized CSP rules 2025-06-03 14:32:15 +02:00
cc9b634bb8 Solved recaptcha csp bug (propably will lead to other bugs, which then need to be solved) 2025-06-02 19:14:48 +02:00
28c298636d Solved bigbluebutton bugs 2025-06-02 19:13:42 +02:00
b2df1ef649 Allowed embeding of peertube 2025-06-01 19:33:07 +02:00
4f0962b4a2 Solved Snipe-IT und MariaDB Bugs 2025-06-01 12:16:11 +02:00
96e2a0033f Optimized healh checks 2025-05-29 13:39:36 +02:00
aacc6877cb General Optimations 2025-05-28 02:42:39 +02:00
70bf9ad3fb Optimized espocrm 2025-05-26 19:22:04 +02:00
b599a528b8 Optimized images and version configuration for dockerfiles 2025-05-26 13:06:21 +02:00
9e19a050a6 Changed coturn to image until coturn 2025-05-26 10:30:42 +02:00
cdfd464bce Refactored docker logic 2025-05-25 17:44:58 +02:00
7a7825cc61 Optimized Taiga default configuration 2025-05-25 09:35:39 +02:00
dad7ee2f20 Solved order bug 2025-05-22 05:58:53 +02:00
2717651189 Little tweaks 2025-05-22 05:55:33 +02:00
c7ff39169a Optimized moodle role 2025-05-21 14:20:34 +02:00
9d400911f4 Solved buggies 2025-05-20 20:46:29 +02:00
49937f6ecc Finished peertube implementation 2025-05-20 18:53:12 +02:00
6026d7ec03 Optimized peertube 2025-05-20 17:40:24 +02:00
97b9e19c5b Solved variable 2025-05-20 14:48:42 +02:00
9000972de6 Optimized test 2025-05-20 14:35:42 +02:00
fa3636cf26 Added show_vault_variables_draft.py 2025-05-20 14:31:50 +02:00
5470be50a9 Optimized database encryption 2025-05-20 13:59:09 +02:00
5ad8a7e857 Optimized credential logics 2025-05-20 13:39:43 +02:00
331da375b7 Added --force parameter 2025-05-20 12:56:29 +02:00
dfb67918c8 Refactored 2025-05-20 12:53:10 +02:00
969a176be1 Optimized dependency loading 2025-05-20 10:34:30 +02:00
5948d7aa93 General code optimations and peertube optimation 2025-05-20 07:00:29 +02:00
a051fde662 Added run order unit test 2025-05-20 06:32:07 +02:00
23ccaca3aa Finished integration test for dependencies 2025-05-20 06:29:17 +02:00
a51a474cb3 Added integration test for dependencies 2025-05-20 06:16:25 +02:00
d5dd568994 Optimized code and solved bugs 2025-05-20 04:19:10 +02:00
2f1d6a5178 Optimized Peertube OIDC draft 2025-05-20 04:18:27 +02:00
3c7825fd23 Solved matomo bug 2025-05-20 00:39:49 +02:00
865f3577d4 Solved portfolio bug 2025-05-20 00:39:31 +02:00
f748f9cef1 Big restructuring 2025-05-20 00:13:45 +02:00
efe994a4c5 Optimized redirect 2025-05-19 19:24:53 +02:00
03f3a31d21 Optimized redirect function 2025-05-19 19:04:36 +02:00
1b50f73803 Refactored domain logic 2025-05-19 18:38:41 +02:00
37dcc5f74e In between commit domain restruturing 2025-05-19 17:17:57 +02:00
cc3f5d75ea Optimized CSP 2025-05-19 10:05:30 +02:00
ab8b99b2c1 Solved path bug 2025-05-19 09:04:16 +02:00
35446b6d94 Solved variable bug 2025-05-19 08:45:25 +02:00
c1b94778b4 Optimized warning sounds 2025-05-17 19:48:29 +02:00
338f66352a Optimized warning sounds 2025-05-17 19:32:17 +02:00
d4f9aa21e5 Added warning sound 2025-05-17 19:18:30 +02:00
624566d34e Added sound and solved cymais bug 2025-05-17 19:05:31 +02:00
08ad58e7c8 Solved matrix domain and portfolio iframe bug 2025-05-17 17:40:05 +02:00
d1a027c1cf Added dict parsing 2025-05-17 17:26:46 +02:00
d115a6f139 Solved bug 2025-05-17 15:00:48 +02:00
3388d3c592 Added get_domain function 2025-05-17 14:53:55 +02:00
ad51597e2e Optimized safe options 2025-05-17 13:39:57 +02:00
2506065142 Optimized safe logic 2025-05-17 13:19:09 +02:00
cc399e3899 Added safe_var function 2025-05-17 12:45:45 +02:00
1c0224d1df Added base_sld_domains filter 2025-05-17 12:19:50 +02:00
76f303da27 Optimized filter logic for all domains 2025-05-17 11:54:23 +02:00
ca5c3c6e8a Optimized matrix domain mapping 2025-05-17 11:53:49 +02:00
a3d5bb3277 Added tests for recusion 2025-05-17 10:57:56 +02:00
7756bbfd62 Changed bluesky domain naming 2025-05-17 10:51:06 +02:00
d51be05d83 Added recursiv dependency resolution 2025-05-17 10:48:58 +02:00
06238343df Added 'group_domain_filters' draft(needs to be optimized to load dependencies) 2025-05-16 17:03:44 +02:00
0900126e4a Deactivated Mastodon for Matrix due to inline CSP restrictions 2025-05-16 15:47:57 +02:00
39b312b997 Added journalctl logging for docker up's and execute portfolio just once condition 2025-05-16 15:26:51 +02:00
ae48aebcd7 Optimized conditions for ChatGPT Bridge for matrix 2025-05-16 13:00:05 +02:00
e9e9925bde Solved moodle variable bug 2025-05-16 12:34:11 +02:00
02137576bd Optimized CLI 2025-05-16 12:12:17 +02:00
94a57312dd Fixed tabs 2025-05-16 12:00:10 +02:00
b5e27a4c89 Renamed file 2025-05-16 11:57:32 +02:00
9dd08396bc Refactored main.yml 2025-05-16 11:46:25 +02:00
4b56393264 Changed copy to template 2025-05-16 10:36:06 +02:00
8ffb6a9cee Solved is_feature_enabled bug and implemented Dockerfile for moodle 2025-05-16 10:22:54 +02:00
52ba4dc3a1 Added OIDC draft 2025-05-16 09:58:28 +02:00
98346c5988 Solved matrix bug 2025-05-16 09:57:54 +02:00
a3bc86ad51 Added pytest dependency 2025-05-16 09:14:17 +02:00
f06ad0af18 Deactivated OIDC 2025-05-15 22:10:45 +02:00
76aef5949b Optimized Docker Matrix Role in Preparation for use on CyMaIS.Cloud Server 2025-05-15 21:11:21 +02:00
9c65c320f9 Optimized more CSP policies and recaptcha 2025-05-15 19:36:46 +02:00
2302cbfeb4 Added missing 'import datetime' 2025-05-15 18:53:37 +02:00
9c45d070b4 Added datetime logs 2025-05-15 18:49:52 +02:00
2478e4013f Refactored docker role include 2025-05-15 18:35:21 +02:00
2aac8b5f80 Solved portfolio iframe naming bug 2025-05-15 17:36:22 +02:00
c492c824b7 Solved integration tests 2025-05-15 17:22:58 +02:00
77e32cc5a6 Added --set for plain 2025-05-15 17:13:19 +02:00
778c4803ed Added csp integration test 2025-05-15 17:12:21 +02:00
c2eed82353 Updated tests 2025-05-15 16:40:46 +02:00
db095b77dc Solved linebreak bug 2025-05-15 16:35:57 +02:00
9eca1958ec Updated Vault Creation script 2025-05-15 16:27:02 +02:00
e8305fa598 Updated CSP for peertube 2025-05-15 15:27:14 +02:00
a42d5e39cf Solved TAIGA and Peertube variable bug 2025-05-15 15:22:24 +02:00
fd698e9cc6 Optimized CSP policies 2025-05-15 15:11:55 +02:00
be0da93c9c Solved bug 2025-05-15 13:09:29 +02:00
20020cca92 Added more CSP conditions 2025-05-15 12:56:22 +02:00
f7cfd13d5a Added more CSP Configurations for services running on veen.world 2025-05-15 11:31:30 +02:00
1031b61f6a Optimized more CSP policies 2025-05-15 11:00:13 +02:00
6b7314baac Solved unsafe inline bug 2025-05-15 10:04:34 +02:00
779c60ef20 Optimized CSP 2025-05-15 09:03:01 +02:00
551c041452 Optimized CSP 2025-05-14 21:25:17 +02:00
25d16eb620 Removed unnecessary function from list 2025-05-14 18:02:35 +02:00
02d773b6e1 Removed unnecessary function 2025-05-14 18:01:03 +02:00
ec5dbc7e80 Refactored CSP j2 filter logic to python code 2025-05-14 17:55:57 +02:00
0ac9dac658 Solved Taiga folder bug 2025-05-14 14:31:38 +02:00
7052f8205a Refactored condition 2025-05-14 14:08:31 +02:00
8fac2296fe Solved j2 specific variable bug 2025-05-14 14:02:01 +02:00
ec0d266975 Deactivated caching for puctures 2025-05-14 12:59:53 +02:00
93af817d4b Solved condition bug 2025-05-14 11:37:58 +02:00
026855b197 Optimized defaults_redirect_domain_mappings for dynamic creating by roles 2025-05-14 11:17:20 +02:00
d0844ce44f Renamed applications.discourse to use application_id 2025-05-14 10:35:28 +02:00
4ebe7ee918 Added rebuild procedure and solved condition bug 2025-05-13 16:12:01 +02:00
13e98beed2 Added CSP exceptions for presentation and portfolio 2025-05-13 16:03:17 +02:00
3cb4cbf0d2 Added checkcsp to health-csp 2025-05-13 15:43:17 +02:00
894e31bc3f Added checkcsp logic 2025-05-13 15:33:06 +02:00
383fb5bd90 Solved sphinx configuration bug 2025-05-13 15:22:12 +02:00
dc4964eda1 Solved oauth2 bugs and deactivated health-csp role temporary 2025-05-13 14:34:16 +02:00
687f9b0703 Solved health-csp bugs 2025-05-13 09:41:25 +02:00
b2f11bcf69 Removed unnecessary unit test and updated dependencies 2025-05-13 09:19:35 +02:00
7ce480bd5c Solved oauth2 proxy configuration bugs 2025-05-13 09:16:43 +02:00
9ea92ea9ec Solved oauth2 proxy configuration bugs 2025-05-13 09:15:12 +02:00
40dd7ea5c4 Added health-csp to nginx dependency 2025-05-13 09:12:26 +02:00
24fb56845b General discourse optimations 2025-05-13 09:11:28 +02:00
23496f2fab Added draft for CSP health checker 2025-05-13 09:10:20 +02:00
72baa9ea28 Solved variable naming bugs, which exist because of big refactoring on friday 2025-05-12 11:33:04 +02:00
1e9a1a6564 Solved LDAP administrator name variable bug 2025-05-11 12:29:34 +02:00
064dd01508 Refactored database_password and solved related bugs 2025-05-11 12:19:33 +02:00
3405f3a8f9 Solved variable bugs for bb 2025-05-11 11:26:49 +02:00
0b88ad6585 Solved variable bugs 2025-05-11 11:19:20 +02:00
8ae99aaf46 Solved 'capplications' typo bug 2025-05-09 19:04:24 +02:00
27bfee2438 Solved database feature naming bug 2025-05-09 19:00:01 +02:00
e7c193f409 Solved some variable bugs and cleaned up 2025-05-09 18:33:47 +02:00
0d8027c908 Adapted tests and solved bugs 2025-05-09 18:25:03 +02:00
a2e6c9881a Solved application generation bugs 2025-05-09 18:03:48 +02:00
5b47333955 Raw refactoring of roles 2025-05-09 17:47:33 +02:00
82f442f40e Updated CLI draft 2025-05-09 09:26:52 +02:00
9764941c7e Added draft for new role schema cli management tools and tests 2025-05-09 09:17:43 +02:00
9d9f11cb3d Added integration test for application_id 2025-05-09 09:16:34 +02:00
1d52fcec75 Solved proxy cache bugs 2025-05-08 11:45:37 +02:00
d5f194b2c0 Solved certreap bugs, implemented caching for pictures, optimized CSP policies (stricter), optimized recaptcha implementation for keycloak, solved mariadb wait bug, solved nextcloud plugin bugs, optimized ignore handling of tasks 2025-05-08 09:51:38 +02:00
f71c9e4b31 Solved pull bug of openproject 2025-05-07 07:20:35 +02:00
9fb1655111 Updated snipe-it source 2025-05-07 07:17:07 +02:00
7afa368594 Added role cleanup-certs based on certreap 2025-05-07 06:38:07 +02:00
9575ee31ff Optimized nginx CSP (prop. leads to problems due to too high restrictions for some roles) and implemented health check for mailer 2025-04-30 17:21:05 +02:00
858cc770ec Implemented new html volume and changed data mount path for friendica 2025-04-30 08:19:42 +02:00
fa9831ef08 Optimized DKIM and DNS for mailu and Letsencrypt. Solved some bugs 2025-04-29 20:24:09 +02:00
f4db4ca6ea Optimized DKIM and DNS for mailu 2025-04-29 15:49:06 +02:00
0f12ffd513 Optimized nextcloud plugin tasks 2025-04-29 07:27:12 +02:00
90f9d97c54 Last SAN optimations 2025-04-29 06:37:12 +02:00
d38d4204f8 Optimized cert speed, testing etc. 2025-04-29 05:16:55 +02:00
8d5408bf42 Solved another wildcard bug 2025-04-29 04:05:53 +02:00
c950862b80 Solved wildcard redirect bug 2025-04-29 03:28:29 +02:00
9a71ad7af9 Optimized changed when 2025-04-29 03:07:19 +02:00
25952fc7e9 Solved certificate bug 2025-04-29 03:01:45 +02:00
e5e394d470 Optimized cloudflare implementation 2025-04-29 02:20:10 +02:00
d796158c61 Optimized cloudflare implementation 2025-04-29 00:10:10 +02:00
04deeef385 Implemented SAN via Letsencrypt and Certbot 2025-04-28 16:47:51 +02:00
0fc9c3e495 Implemented certbot for cloudflare\hetzner, optimized documentation and solved bugs 2025-04-28 00:33:55 +02:00
3e816130d3 Refactored database urls 2025-04-27 18:13:16 +02:00
da89bb6ed1 Optimized mastodon create administrator 2025-04-27 18:12:02 +02:00
cd2f5f8717 Added syncope draft 2025-04-27 18:11:28 +02:00
fb96c5b7fb Solved get bug 2025-04-27 18:10:31 +02:00
6c1c728acb Solved ldap schema bug 2025-04-27 15:56:17 +02:00
7ae3c6cc51 Different optimations 2025-04-25 21:57:47 +02:00
39668a428c Added nginx-domains-cleanup draft 2025-04-25 21:57:06 +02:00
2fa5e57c5d Solved LDAP Bug 2025-04-25 21:43:56 +02:00
331ff20272 Finished EspoCRM implementation 2025-04-25 19:05:17 +02:00
4958b08ca7 Further optimations of espocrm 2025-04-25 17:22:05 +02:00
87262f7373 Refactored ws implementation to use it in mastodon and in new espocrm role 2025-04-25 14:44:33 +02:00
4e04f882e5 Optimized espocrm websocket and docker-compose 2025-04-25 12:51:28 +02:00
edf2be504c Implemented espocrm draft 2025-04-25 12:34:09 +02:00
79d6a68dc1 Finished ldap optimation 2025-04-25 12:30:56 +02:00
72deb13d07 Restructured LDAP role 2025-04-25 11:34:14 +02:00
ec79cb8921 Implemented user_objects 2025-04-24 21:17:06 +02:00
3203151e84 Added {SSHA} 2025-04-24 20:38:18 +02:00
bab66baedb Deactivated password login if oidc enabled 2025-04-24 20:17:56 +02:00
ae94dd974a Updated administrator email 2025-04-24 20:07:31 +02:00
fca8eee8e7 Finished listmonk bounce implementation 2025-04-24 19:52:27 +02:00
36606b5594 Further optimisation of system user creation 2025-04-24 19:25:39 +02:00
59e985eb3b In between commit auto user creation before system email refactoring 2025-04-24 14:42:38 +02:00
f27076a5cc Solved concate bug 2025-04-24 13:12:02 +02:00
250f26e03c Optimized listmonk settings 2025-04-24 13:11:25 +02:00
c9ab0cd7cc Updated settings 2025-04-23 18:41:22 +02:00
f892a5b54d Solved issuer url bug 2025-04-23 18:26:38 +02:00
6a1be99f1e Optimized oidc und hcaptcha autosetup für listmonk 2025-04-23 18:08:24 +02:00
3b3ec5196a Optimized listmonk, wordpress and activity pub for wordpress 2025-04-23 15:05:26 +02:00
fd0a978a16 Different small optimatiosn 2025-04-23 13:25:52 +02:00
1376930e5c Solved bbb database bug and changed logo 2025-04-23 12:40:48 +02:00
86dd349e8f Optimized configuration 2025-04-23 11:51:46 +02:00
8bb7f607c1 Implemented discourse wordpress raw settings 2025-04-23 11:24:14 +02:00
c26167ce61 Optimized wordpress discourse implementation 2025-04-22 16:38:14 +02:00
965af4fbaa Added auto admin creation and oidc draft for listmonk 2025-04-22 16:01:47 +02:00
3653b3111a Added wordpress disourse draft 2025-04-22 12:50:48 +02:00
e1df746346 Finished openproject container, ldap, settings bug and implemented administrator setting 2025-04-22 01:42:54 +02:00
65b1fef24e Removed anonymous docker volumes and decoupelt container bug 2025-04-21 22:49:13 +02:00
4590331a2b Solved openproject mount bug 2025-04-21 22:16:50 +02:00
a6e7303f26 Removed autoheal from OpenProject 2025-04-21 19:02:18 +02:00
3eb9163412 Solved features bug 2025-04-21 18:28:35 +02:00
b0dd574c26 Optimized database backup seeder implementation 2025-04-21 16:16:54 +02:00
f8c984d6c2 Refactored CyMaIS basic features and optimized wordpress implementation 2025-04-18 23:17:29 +02:00
ec5beff22f Finished Wordpress OIDC implementation 2025-04-17 16:45:43 +02:00
8f8796f598 Solved settings save bug 2025-04-17 15:00:45 +02:00
b5b4550cfb Redesigned oidc attributs 2025-04-17 14:50:04 +02:00
7e24d9b1c3 Added OIDC draft für wordpress 2025-04-17 11:51:37 +02:00
7d5d69c380 Solved database backup buck 2025-04-16 13:27:27 +02:00
a50d8159fc Added database variable seeder failed test 2025-04-16 10:37:35 +02:00
91fba5dbeb Deactivated restart because it isn't possible at this point 2025-04-16 10:26:50 +02:00
de94fe4ae3 Solved cleanup-failed-docker-backups path bug 2025-04-16 10:18:18 +02:00
9c680a26f7 Solved bug 2025-04-16 02:54:54 +02:00
c03330dcd3 Moved Healthcheck to Dockerfile 2025-04-16 02:31:09 +02:00
dfcd35bacc Implemented inverted color scheme 2025-04-16 02:26:13 +02:00
4ec3037474 Implemented new css scheme 2025-04-16 00:57:29 +02:00
567622f523 Solved OpenProject build bug 2025-04-16 00:56:29 +02:00
4b824ecd6c Solved domain bug 2025-04-15 22:22:09 +02:00
c418399807 Solved wordpress bug 2025-04-15 16:33:06 +02:00
58229e2255 Optimized healing function for port conflicts 2025-04-15 15:27:33 +02:00
b5dc999584 Removed list bug 2025-04-15 13:32:38 +02:00
cf44cb59b3 Finished presi for today 2025-04-12 12:58:13 +02:00
9e73218535 Optimized docs 2025-04-12 12:19:09 +02:00
7379006327 Optimized market analyses 2025-04-12 00:28:54 +02:00
7d502e799f Added market analyses 2025-04-11 22:16:43 +02:00
794466d7e3 Restructured Presentation 2025-04-11 16:27:36 +02:00
c8a91c1c46 Restructured code for personas 2025-04-11 15:14:58 +02:00
2158309020 Renamed Role 2025-04-11 11:59:00 +02:00
536c3091e5 Solved ldap reference bug for nextcloud and cleaned up 2025-04-11 11:35:28 +02:00
2dcf8159e5 Solved missing ldap network bug 2025-04-10 21:20:37 +02:00
e92c331f44 Added dependency pull 2025-04-10 20:18:53 +02:00
8e18a5c1e3 Optimized categories 2025-04-10 18:13:55 +02:00
2183038240 Optimized for portfolio, presentation and docs 2025-04-10 17:49:47 +02:00
33a8d8b579 Optimized debugging 2025-04-10 14:55:43 +02:00
2ca000795d Optimized portfolio and pkgmgr update procedures 2025-04-10 14:07:50 +02:00
150e15625d Added tags reading and optimized presentation 2025-04-10 09:39:49 +02:00
557869802a Added a role creation doc 2025-04-10 00:30:26 +02:00
e3ddc43944 Implemented presentation 2025-04-10 00:28:23 +02:00
50e7d75932 Removed update order 2025-04-10 00:17:51 +02:00
ba67306960 Updated problem and vision statement 2025-04-09 22:54:08 +02:00
9107c1926a Optimized links 2025-04-09 18:03:09 +02:00
385e582fc6 Restructured mds 2025-04-09 17:57:57 +02:00
72becedee5 Solved build bug 2025-04-09 17:42:58 +02:00
09b08c8744 Added more docker compose build notifiers 2025-04-09 17:02:02 +02:00
36bf5af288 Decoupeled Sphinx 2025-04-09 16:56:41 +02:00
fc552d1130 Merge branch 'master' of github.com:kevinveenbirkenbach/cymais 2025-04-09 11:30:53 +02:00
1913003ea2 Moved passlib install from pip to pacman 2025-04-09 11:23:43 +02:00
d1d19830b0 Added implementation instructions for gitea 2025-04-09 09:23:21 +02:00
61ad100ef1 Solved bugs 2025-04-09 02:36:14 +02:00
28e25f0232 Optimized descriptions, README.md's and meta/main.yml's for portfolio and sphinx docs 2025-04-09 00:29:23 +02:00
da5962c337 Refactored and solved bugs 2025-04-08 21:33:43 +02:00
1be413f20d Added fusion directory draft 2025-04-08 17:58:06 +02:00
adecee43ec Implemented README.md's und meta/main.yml and solved bugs 2025-04-08 12:55:53 +02:00
a13bd1883e In between commit refactoring LDAP, to continue working on other computer 2025-04-08 11:23:16 +02:00
a43d1302ac Deactivated useless code 2025-04-08 00:30:21 +02:00
734ddc44bf Solved health check bug 2025-04-08 00:03:36 +02:00
87d5854831 Optimized memberof for docker-ldap. LAM integration not functioning yet 2025-04-07 23:39:06 +02:00
b00988e792 Implemented pre configuration for pgadmin 2025-04-07 21:09:46 +02:00
aceb111f86 Added role cleanup-docker-anonymous-volumes 2025-04-07 15:25:30 +02:00
0b42193d3c Solved openproject bugs 2025-04-07 15:24:21 +02:00
f9b8f86fce Added cleanup-failed-docker-backups 2025-04-07 15:19:15 +02:00
715d5fdb85 Optimized OIDC integration for mailu 2025-04-07 13:18:52 +02:00
2997fb4f5f Activated auto settings for ldap and smtp 2025-04-07 09:19:37 +02:00
fe39a7f701 Deactivated OIDC 2025-04-06 21:48:01 +02:00
0eaaa73e23 Cleaned up OIDC für taiga draft 2025-04-06 21:38:15 +02:00
a9c25a28c6 Solved bugs 2025-04-06 19:06:56 +02:00
df538033d9 Solved a taiga variable bug 2025-04-06 10:41:32 +02:00
27d9244254 Solved another bbb variable bug 2025-04-06 10:02:37 +02:00
37418b2658 Solved bbb variable bug 2025-04-06 09:43:59 +02:00
be3bd18c34 Optimized Taiga README.md 2025-04-06 09:14:45 +02:00
4461f73c86 Solved bbb bugs 2025-04-06 09:09:41 +02:00
949feb912a Implemented OIDC draft for Taiga 2025-04-06 09:08:53 +02:00
bfd1839a8b Solved variable definition bug 2025-04-06 07:33:01 +02:00
31462aeec7 Optimized BBB Nextcloud Plugin implementation 2025-04-06 07:30:13 +02:00
ef2d62adac Changed variable structure for bbb 2025-04-06 05:19:30 +02:00
8d58aa2364 Updated bigbluebutton role 2025-04-06 05:01:09 +02:00
ade8053430 Deactivated update-python because it breaks the system packages 2025-04-05 21:30:42 +02:00
54bef2a091 Setup cleanup-backups variable bug 2025-04-05 20:56:25 +02:00
3ae3da3673 Optimized developer personas, implemented gcc and solved python-pip update bug 2025-04-05 20:39:56 +02:00
d5ba306081 Replaced HOST and HOSTNAME variable through hostname command to make it more distribution indepentend 2025-04-05 18:28:20 +02:00
c31a8fb329 Solved pgadmin healthcheck bug 2025-04-05 18:17:44 +02:00
4407d99a1b Solved pgadmin bugs and added to portfolio 2025-04-04 17:16:13 +02:00
5151a21575 Ignored non functional code 2025-04-04 12:00:19 +02:00
ccfc23f3fe Added passlib to requirements 2025-04-04 11:34:16 +02:00
b77f116bdf Addapt pgadmin variables 2025-04-04 11:20:38 +02:00
2c964cfbee Added pgadmin draft and optimized phpadmin 2025-04-04 07:35:47 +02:00
e024542d8e Solved msmtp bug and implemented healthchecks for it 2025-04-03 15:09:10 +02:00
170636d098 Implemented msmtp for wordpress 2025-04-03 14:05:00 +02:00
fa10fe558d Solved path bugs 2025-04-02 19:33:23 +02:00
b1d8e21772 Added ssh agent for all shells 2025-04-02 19:25:22 +02:00
cf823c0061 Activated lid switch, optimized zsh and more 2025-04-02 19:00:04 +02:00
b98f032141 Optimized persona gamer, gnome, and refactored others 2025-04-02 15:09:56 +02:00
30b138ffa3 Solved bugs, restructured and added new functionality for clients/personal computers 2025-04-02 12:28:28 +02:00
500f8b508d Disabled password managers for chromium and firefox, due to keepassxc support 2025-04-02 01:14:01 +02:00
5dda19cdc5 Added draft for lid-switch 2025-04-02 01:09:39 +02:00
a2955a34ab Solved variable bugs of chromium and firefox 2025-04-02 00:52:24 +02:00
00c663a694 Optimized libreoffice role 2025-04-02 00:48:01 +02:00
d1de427653 Solved condition typo bug II 2025-04-02 00:31:33 +02:00
6cbbd4b84b Solved condition typo bug 2025-04-02 00:29:50 +02:00
b4ea171908 Optimized nextcloud variable declaration 2025-04-02 00:19:55 +02:00
2629603012 solved variable bug 2025-04-02 00:07:22 +02:00
9dc571062c Optimized git-config role 2025-04-01 23:57:52 +02:00
83007983a5 Renamed task 2025-04-01 23:14:42 +02:00
98b7b15548 Added correct swap forge implementation 2025-04-01 23:09:59 +02:00
c628c1edcd Added dependencies for yay 2025-04-01 22:57:07 +02:00
28ebb675a7 catched missing user definition exception 2025-04-01 21:33:00 +02:00
080b46329e Removed unneccessary MAkefile 2025-04-01 21:19:05 +02:00
663e5604fd Optimized gnome for personal computers 2025-04-01 18:55:04 +02:00
b488ea949f Added role make and added it to package-manager 2025-04-01 17:53:35 +02:00
7a8a22a3a8 Added HOST parameter 2025-04-01 17:36:51 +02:00
213b74ff84 Solved package-manager bugs 2025-04-01 17:33:19 +02:00
7042f28a79 Removed wrong license hint 2025-04-01 14:41:54 +02:00
526f1c952d Refactored git clone to Kevin's Package Manager (Draft not fully tested) 2025-04-01 14:40:04 +02:00
659c24eb14 Moved browser extensions to configuration 2025-04-01 12:24:52 +02:00
887db59a57 Implemented browsers with keepassxc and ublock origine default setup 2025-04-01 12:08:28 +02:00
4541e2d636 Updated pc roles and implemented update-pip role 2025-04-01 11:23:36 +02:00
99f633d222 Optimized nextcloud keycloak ldap implementation 2025-03-21 22:50:48 +01:00
e2166235ad Adapted portfolio url for keycloak 2025-03-21 20:25:46 +01:00
bb48e8ae36 Solved portfolio bug, entered keycloak entries for portfolio, added hints to phpmyadmin and updated mailu documentary 2025-03-21 20:19:12 +01:00
12ad339221 Addapted css for phpmyadmin 2025-03-21 18:56:20 +01:00
0928245853 Solved nextcloud plugin bugs in context ldap 2025-03-21 18:43:06 +01:00
c51f935eff Solved ldap_user nextcloud var import bug (hopefully) and optimized README.md's and metas 2025-03-21 18:01:11 +01:00
e4a0473f9e Optimized css for phpmyadmin 2025-03-21 17:19:07 +01:00
92000e5d43 Added more debugging info 2025-03-21 16:19:34 +01:00
ad9b22a792 Optimized headlines 2025-03-21 14:28:41 +01:00
c24694565f Optimized headlines 2025-03-21 14:27:16 +01:00
d549923538 solved last sphinx bugs 2025-03-21 14:22:09 +01:00
f8512e9e35 Optimized features 2025-03-21 13:54:19 +01:00
c402583f2b Redrafted Sphinx for CyMaIS 2025-03-21 13:48:42 +01:00
fe85d4bd37 solved path bugs in main.py 2025-03-21 12:59:36 +01:00
da8830493f Added pandoc requirement 2025-03-20 18:30:26 +01:00
9919e1ecc2 Added .gitkeep for assets/img/ 2025-03-20 18:23:08 +01:00
80d99dfd18 Updated Base Docu 2025-03-20 18:10:14 +01:00
275e4bd453 Finished optimization for today 2025-03-20 17:00:07 +01:00
096934e795 Optimized docs 2025-03-20 15:08:18 +01:00
4c29fc9f02 Implemented more auto docs 2025-03-20 14:13:03 +01:00
d5f10276ee Moved sphinx files 2025-03-20 12:52:55 +01:00
6868b0d8ba Optimations for makefile and iframes 2025-03-20 12:37:41 +01:00
6680f64e50 Implemented draft for py yml and optimized assets urls 2025-03-20 11:22:55 +01:00
0611ddda11 Changed iframe options 2025-03-20 04:31:02 +01:00
87ca1ccc11 Implemented assets server 2025-03-20 03:47:12 +01:00
836a3e0238 Big cleanup 2025-03-20 02:20:00 +01:00
6520350731 Changed variable name 2025-03-19 20:28:46 +01:00
72693e09e2 Implemented more detailed configuration for landing_page, css and matomo and restructured code 2025-03-19 20:26:43 +01:00
f23850068a Restructured documentary 2025-03-19 18:31:28 +01:00
061d2c9d17 Solved nextcloud config directory bug 2025-03-19 18:03:09 +01:00
d96ca6f799 Solved reset bug 2025-03-19 17:47:24 +01:00
57c3cfc8fa Implemented vault password 2025-03-19 15:43:04 +01:00
8e0bb19e49 Refactored code 2025-03-19 15:37:29 +01:00
fd1b160d93 Implemented realm import parameter 2025-03-19 15:37:12 +01:00
718bd41666 Implemented iframe option 2025-03-19 15:36:36 +01:00
e92515184a Changed mode for main.py 2025-03-19 15:35:16 +01:00
e78d6edefa Solved matomo bug 2025-03-19 15:34:51 +01:00
1620a3f7ed Optimized READMEs 2025-03-19 15:34:13 +01:00
24cb08b358 Removed playbook.constructor.yml 2025-03-19 13:22:20 +01:00
83de47921d Refactored playbooks and optimized main.py 2025-03-19 13:05:03 +01:00
bd4241d74e Removed buggy condition for wildcard cert 2025-03-19 09:23:46 +01:00
dea7052da0 Activated iframe loading for proxy 2025-03-19 09:21:55 +01:00
8be422cc99 Updated ldap docu and implemented change draft 2025-03-18 20:25:07 +01:00
1712088c5a Added draft for main.py 2025-03-18 16:38:01 +01:00
8d8016a01e Moved js 2025-03-17 17:28:56 +01:00
d390b500b4 Added logo and favicon 2025-03-17 17:25:25 +01:00
be62b72e90 Added remove of current 2025-03-17 16:50:17 +01:00
af27d50214 Added marked as current 2025-03-17 16:47:02 +01:00
e6fa74df61 Prevent js exception 2025-03-17 16:41:50 +01:00
4cde1ed9e4 Refactored js 2025-03-17 16:31:07 +01:00
858b906722 Optimized static current 2025-03-17 16:23:05 +01:00
3a32b65454 finished mvp for js menu 2025-03-17 16:16:29 +01:00
12df136ccf Optimized js menu 2025-03-17 16:11:34 +01:00
71cde6bf3f Optimized headers 2025-03-17 15:33:21 +01:00
9dfd019e0a Optimized Index 2025-03-17 15:20:11 +01:00
756407d407 Implemented -v parameter 2025-03-17 14:42:29 +01:00
f21120e9f7 Added horizontal scrolling 2025-03-17 13:53:42 +01:00
8055c7b994 Updated mds 2025-03-17 13:43:12 +01:00
efad73415d Replaced Other Resources without icon 2025-03-17 13:21:05 +01:00
c3988ce812 Added current directory 2025-03-17 13:19:23 +01:00
75a110fde9 Refactored sphinx 2025-03-17 13:05:59 +01:00
8b0308589d Optimized subfolder explorer 2025-03-17 12:57:41 +01:00
9232db4ef7 Added README.md file 2025-03-17 12:37:57 +01:00
c157e93011 Optimized Documentation about Sphinx and created Makefile in root 2025-03-17 12:05:39 +01:00
2667f3c259 Optimized mds 2025-03-17 05:10:43 +01:00
7b17362986 Optimized mds 2025-03-17 04:57:05 +01:00
9a30e0f49b Optimized menu 2025-03-17 04:13:24 +01:00
9194abee4a Doc optimations 2025-03-17 03:41:54 +01:00
cf22ff49fc Refactored README.md 2025-03-17 03:16:46 +01:00
d84ffc375b Solved header bug 2025-03-17 02:50:11 +01:00
e1da02db3d Solved double ul bug 2025-03-17 02:37:35 +01:00
bdbaabe4a0 Optimized text 2025-03-17 02:17:59 +01:00
e005ced3d4 Optimized animation for menu 2025-03-17 02:14:45 +01:00
5677a91e82 Optimized subfolders 2025-03-17 01:42:01 +01:00
d36fc0c916 Refactored Sphinx Code 2025-03-17 01:29:10 +01:00
48b32c2816 Made headline bigger 2025-03-17 00:32:36 +01:00
4697e71c54 Optimized role categories 2025-03-17 00:28:22 +01:00
281413d571 Refactored documentation 2025-03-16 23:57:42 +01:00
3cfa69a248 Created SETUP.md 2025-03-16 22:53:57 +01:00
74edb197de Implemented subfolders in navigation 2025-03-16 22:14:34 +01:00
871dc04fc9 placed index.rst und README.md as first in list 2025-03-16 21:34:30 +01:00
c4943ef3b3 Implemented rst file parsing 2025-03-16 21:17:55 +01:00
6a1d6e40a7 Removed toggle button 2025-03-16 20:50:07 +01:00
b6eb9a0dd3 Optimized sphinx theme 2025-03-16 20:35:01 +01:00
c9c716e5fe Removed sorting 2025-03-16 18:43:46 +01:00
18fba35173 Implemented new template and optimized navigation 2025-03-16 18:42:03 +01:00
3e1a9e9dde Solved Sphinx Role bugs 2025-03-16 18:09:37 +01:00
985ed797bd General Sphinx optimations 2025-03-16 17:24:50 +01:00
2095f16402 Added sphinx docker role draft 2025-03-15 21:31:10 +01:00
c1aa6823b0 Optimized sphinx and documentation 2025-03-15 18:33:59 +01:00
12e0367c66 Optimized sphinx 2025-03-15 16:10:02 +01:00
cc458753b3 Implemented category draft 2025-03-15 14:48:55 +01:00
b446fb5476 Added asc sorted headings 2025-03-15 14:32:15 +01:00
cd21645148 Optimized headlines 2025-03-15 14:26:11 +01:00
c264424464 Implemented all mds on same level in sidebar 2025-03-15 14:16:56 +01:00
c7c633621f Moved sphinx files to an own folder 2025-03-15 13:59:58 +01:00
9fd96f01c9 Optimized indexes 2025-03-15 12:09:23 +01:00
f83d00f955 implemented relative path 2025-03-15 11:10:11 +01:00
164f86a775 Added gitkeep 2025-03-15 11:08:46 +01:00
9ec40f8025 Added sphinx indexes 2025-03-15 11:06:24 +01:00
f6a42a4a5d Solved index bug 2025-03-14 16:41:28 +01:00
c3c889784a Added Sphinx draft 2025-03-14 15:29:47 +01:00
b310e176de Removed docs folder 2025-03-14 14:54:18 +01:00
ce82a61018 Small .md optimations 2025-03-14 14:46:52 +01:00
892403cf8c Optimized .mds and meta/main.yml for client-wireguard roles and refactored README.md of Docker Roles 2025-03-14 14:42:59 +01:00
17e2c992b3 Optimized .mds and meta/main.yml for cleanup roles 2025-03-14 13:48:15 +01:00
abdddc0d42 Optimized .mds and meta/main.yml for backups-provider 2025-03-14 13:36:44 +01:00
26abfd441a Optimized .mds and meta/main.yml for postfix,python-pip,restart-docker & sshd 2025-03-14 13:33:28 +01:00
efa139705a Optimized .mds and meta/main.yml for system roles 2025-03-14 13:21:52 +01:00
c480e39e39 Optimized .mds and meta/main.yml for systemd-timer 2025-03-14 13:10:20 +01:00
2dbaad04d5 Optimized .mds and meta/main.yml for update roles 2025-03-14 13:07:11 +01:00
4c186a4204 Optimized .mds and meta/main.yml for wireguard. 2025-03-14 12:43:06 +01:00
8a5997e54e Optimized .mds and meta/main.yml for user. 2025-03-14 12:37:15 +01:00
632b4e9b22 Optimized .mds and meta/main.yml for user-root. Also included user as meta for user-administrator 2025-03-14 12:31:39 +01:00
1689bdfdbc Removed user-alarm, due to that it is managed by other scripts 2025-03-14 12:26:00 +01:00
cc622d060a Optimized .mds and meta/main.yml for user-administrator 2025-03-14 12:24:27 +01:00
d014d25e40 Optimized .mds and meta/main.yml for sudo 2025-03-14 12:19:23 +01:00
36c76fd00e Optimized .mds and meta/main.yml for systemd-notifier 2025-03-14 12:12:40 +01:00
d4850ec8bb Optimized .mds and meta/main.yml for systemd-notifier-telegram 2025-03-14 12:09:17 +01:00
e9aef3468e Optimized .mds and meta/main.yml for systemd-notifier-email 2025-03-14 12:02:15 +01:00
0ee2c041a6 Optimized .mds and meta/main.yml for backups-provider-user 2025-03-14 11:54:51 +01:00
856ffb9fea Optimized .mds and meta/main.yml for backup-remote-to-local 2025-03-14 11:50:19 +01:00
5756eb33b9 Optimized .mds and meta/main.yml for backup-docker-to-local 2025-03-14 11:41:48 +01:00
de52b1a16e Optimized .mds and meta/main.yml for backup-directory-validator 2025-03-14 11:32:02 +01:00
9c4aeff807 Optimized overall READMEs and backup-data-to-usb role 2025-03-14 11:21:51 +01:00
2a33c6a6dc moved .md to docs 2025-03-14 01:32:53 +01:00
d321fa043f Update VISION_STATEMENT.md 2025-03-14 00:20:43 +01:00
ef74fd5363 Activated user push repo for gitea and implemented (untested) smtp mail 2025-03-13 15:56:23 +01:00
14136a9e69 Added Funding 2025-03-12 20:52:48 +01:00
863f221780 Included Support Links 2025-03-12 19:33:17 +01:00
9053cced6e Updated README.md and CSS 2025-03-12 11:14:40 +01:00
c60a296e3d Added more css for taiga 2025-03-05 14:18:01 +01:00
2898cc6086 Used {{ nextcloud_docker_config_additives_directory }} as identification string 2025-02-28 17:01:14 +01:00
e3f6b320de Solved variable bug 2025-02-28 15:58:31 +01:00
93ff9ea575 Optimized PHP performance 2025-02-28 15:53:27 +01:00
9a49e7aa3b Added coturn draft 2025-02-28 15:00:38 +01:00
08334be18d Solved configuration file path bug 2025-02-28 14:04:49 +01:00
be0f813394 Solved oidc template condition bug 2025-02-28 13:52:44 +01:00
1a7e7b3851 Solved path bug and optimized memcache 2025-02-28 13:45:19 +01:00
d20e900ab2 Optimized Nextcloud Configuration 2025-02-28 13:19:34 +01:00
d24b33f045 Added migration hints 2025-02-27 17:51:46 +01:00
fbf95c0f41 Added nextcloud maintanance window 2025-02-27 16:30:46 +01:00
7e4d296092 Solved Nextcloud Plugin Routine Bugs 2025-02-27 16:12:08 +01:00
1756babbc2 Implemented Nextcloud Plugin Routine 2025-02-27 15:28:43 +01:00
3d096f1fc7 Enabled password hashing for LDAP and Keycloak 2025-02-27 10:47:50 +01:00
2b3cdd58d6 chenged ldap_uid to preferred_username 2025-02-26 18:11:44 +01:00
a9de544a8d Solved https bug 2025-02-26 17:54:17 +01:00
7893ee068c Specified user dn 2025-02-26 17:52:28 +01:00
0471eb5d4a Solved s01ldap_base_users bug 2025-02-26 17:47:16 +01:00
9720fc1813 Activated oidc_login by default and optimized documentation for applications 2025-02-26 15:54:46 +01:00
54dab4ba6a Optimized CSS for Taiga 2025-02-26 15:38:23 +01:00
22ce80cd23 Set LDAP uid variable 2025-02-26 10:42:25 +01:00
545af78e60 Optimized README.md 2025-02-26 10:10:48 +01:00
db7ef0e8a5 Optimized formatation 2025-02-26 09:59:46 +01:00
ae1d7c785f Solved OIDC sociallogin bug 2025-02-26 09:49:32 +01:00
61eb9a3aed Optimized OIDC for Nextcloud 2025-02-25 19:59:58 +01:00
72b787814e Optimized OIDC Login for Nextcloud 2025-02-25 19:35:48 +01:00
9a9bae4f2c Optimized Nextcloud for OIDC flavor login and adapted user administrator credentials 2025-02-25 15:17:56 +01:00
ab258cb6dd Added LDAP integration for Nextcloud and optimized CSS 2025-02-24 23:53:12 +01:00
6d5113b6ea Updated security for OAuth2 and optimized CSS 2025-02-24 21:00:22 +01:00
bc455a4344 Optimized CSS 2025-02-24 19:29:27 +01:00
5b9553d042 Updated README.md of nextcloud 2025-02-24 16:30:08 +01:00
aa591de3e5 implemented oidc draft for matrix - but deactivated due to infinite redirect loop 2025-02-23 13:04:12 +01:00
1aa6c01c5a deactivated css for openproject 2025-02-23 11:30:38 +01:00
9a6c835244 Merge branch 'master' of github.com:kevinveenbirkenbach/cymais 2025-02-22 18:09:33 +01:00
cd7568e4f8 deactivated code 2025-02-22 18:09:21 +01:00
1a951648cb solved bugs and optimized css 2025-02-22 16:44:32 +01:00
64f8b56e2d solved mastodon bugs and optimized discourse 2025-02-22 16:30:53 +01:00
657918c96e Optimized keykloak, mailu and css 2025-02-22 14:51:13 +01:00
c2975262ea Added administrator account creation for mastodon 2025-02-22 12:13:46 +01:00
8b072c0ed2 Optimized css for mailu 2025-02-22 10:16:25 +01:00
08ee5dff9c Solved mastodon and peertube domain bug 2025-02-21 12:34:31 +01:00
ba49c2a840 Uncommented code 2025-02-21 11:40:29 +01:00
8afb2a3b84 Solved some bugs and optimized nextcloud 2025-02-21 10:53:19 +01:00
a61fa3e614 Solved naming bug 2025-02-21 09:36:00 +01:00
8c951f6a19 Implemented role to recieve certs & do modification routines. Also optimized nextcloud 2025-02-21 09:28:01 +01:00
0805929d41 Solved Matomo, Peertube, Nextcloud Bugs 2025-02-21 08:59:07 +01:00
10b2ead705 More optimation of domain bugs 2025-02-21 08:04:52 +01:00
c4b622ccdb Solved more domain related bugs 2025-02-21 06:32:12 +01:00
82e69fc7a6 Removed set_fact domain 2025-02-21 05:49:26 +01:00
40a30cc927 Removed set_fact https_port 2025-02-21 05:46:42 +01:00
88194ac3d3 Replaced http_port by dedicated application port -> Result of previous bugs 2025-02-21 05:28:09 +01:00
9f41e25166 Replaced enable_central_database by configuration in application 2025-02-21 05:06:39 +01:00
b6eb866b36 Optimized CSS and solved bugs 2025-02-21 04:47:09 +01:00
bdeaf14285 Solved multiple bugs and propably produced 100 more.... Usual Nightshift... 2025-02-21 03:53:27 +01:00
5694023da8 Added font 2025-02-21 01:18:29 +01:00
7ce58a7203 Solved comma bug 2025-02-21 00:37:06 +01:00
07beddb5a2 Redesigned LDAP (DRAFT) 2025-02-21 00:26:33 +01:00
a39f1914ea solved pixelfed bug 2025-02-20 22:29:13 +01:00
6e8e19523d Optimized peertube css 2025-02-20 22:16:02 +01:00
b9c518a6ff Optimized css 2025-02-20 21:30:04 +01:00
86bc5595f2 Solved portfolio bugs 2025-02-20 20:35:43 +01:00
63c2538027 Implemented new gradients, removed important and mapped bootstrap css variables new 2025-02-20 19:32:24 +01:00
6597d980df Added randomized gradients 2025-02-20 19:00:56 +01:00
a69f78d336 Optimized css and added gradients 2025-02-20 18:52:52 +01:00
97256bfa15 Solved docker_repository_path bug 2025-02-20 17:44:55 +01:00
a4c3bcd6af Adapted realm and global styling 2025-02-20 17:07:39 +01:00
0782dc404d Updated styling 2025-02-20 15:48:01 +01:00
2f76ba32ec Solved multiple bugs like networking, variables etc. which occured on veen.world server 2025-02-20 15:09:36 +01:00
19aa38ac5d Solved escaping bug 2025-02-20 14:23:16 +01:00
5b40fe1740 Added bashrc routines 2025-02-20 14:22:08 +01:00
439072c6b1 removed deprecated parameter 2025-02-20 11:47:08 +01:00
b2ccc69628 Refactored oidc, solved network bugs and refactored 2025-02-20 11:44:50 +01:00
4dd694c4e2 Optimized design 2025-02-20 10:21:52 +01:00
286517b127 Optimized nextcloud database variable 2025-02-20 01:26:44 +01:00
6e02e09471 Optimized Mastodon, Discourse etc. for Flock.Town 2025-02-20 01:19:25 +01:00
a70b0ed48f Optimized Mastodon for flock.town 2025-02-20 00:31:47 +01:00
5829edf23c In between commit mastodon optimation and cleanup 2025-02-19 22:57:26 +01:00
7d24e1d414 Further feature implementation for flock.town 2025-02-19 22:03:17 +01:00
dfa740456f Solved escaping error 2025-02-19 20:54:13 +01:00
96f96ebe77 Added missing domain variable 2025-02-19 20:49:14 +01:00
fd5c10b103 In between commit development coporate design for flock.town 2025-02-19 20:46:14 +01:00
fce9c1a72d Solved closing breakets name 2025-02-19 17:56:56 +01:00
6f158aa749 Solved endif bug 2025-02-19 17:48:15 +01:00
d83c7e280f Optimized default portfolio conf 2025-02-19 17:43:07 +01:00
e10deb9e54 Optimized and refactored portfolio for flock.town 2025-02-19 16:27:16 +01:00
0c7af2ce89 Added configuration_filters 2025-02-19 13:46:45 +01:00
7377aa9c20 Cleaned up matomo integration 2025-02-19 12:01:36 +01:00
6282330226 Solved OpenProject Subnet bug 2025-02-19 06:32:13 +01:00
3f284de07b Optimized comments 2025-02-19 06:06:21 +01:00
9762645b6d Solved location bug 2025-02-19 06:00:37 +01:00
916cb6e314 Implemented location dedicated OAuth2 Proxy and solved other bugs 2025-02-19 05:53:00 +01:00
e4502bbe54 Solved discourse network bug 2025-02-19 04:36:09 +01:00
1d360dfa95 Refactored OAuth2 Proxy Configuration 2025-02-19 03:58:21 +01:00
74d8dad94c Solved typo bug 2025-02-19 03:46:25 +01:00
2c4ee620c1 Optimized Matomo 2025-02-19 03:37:56 +01:00
f84774a390 Solved more matomo bugs 2025-02-19 03:20:34 +01:00
bd1395926b Solved Matomo domain bug and refactored 2025-02-19 02:00:41 +01:00
8b1ada7450 Optimized iam and realm 2025-02-18 21:54:40 +01:00
c0916ce25b Solved variable bug and updated README.md of docker 2025-02-18 21:16:27 +01:00
0f44e65bf1 Optimized LDAP integration, keycloak realm import and health checks for docker images 2025-02-18 21:00:14 +01:00
e87c3e2090 Optimized setup procedure in preparation for automatic keycloak realm import 2025-02-18 15:07:09 +01:00
671448dbfc Optimized ldap integration 2025-02-18 14:46:09 +01:00
82bdbbaf57 Changed default saturation 2025-02-18 14:29:00 +01:00
fcac18f77f Optimized CSS for Mastodon 2025-02-18 14:21:33 +01:00
c7901949cc Deactivated global css for wordpress 2025-02-18 12:57:03 +01:00
0a26499a34 Added css for gitea 2025-02-18 12:33:00 +01:00
ff1f7b53af Optimized CSS for modal 2025-02-18 11:59:17 +01:00
ba35f43902 Optimized LDAP and CSS integration 2025-02-18 11:20:56 +01:00
c8debee1ca Updated CSS 2025-02-18 09:26:13 +01:00
2e5a97b0a1 Solved color bug 2025-02-18 08:54:15 +01:00
d03eb9e7f2 Added keycloak import draft 2025-02-17 20:02:09 +01:00
ce01a2f387 Optimized CSS and LDAP role 2025-02-17 16:53:56 +01:00
b740b978b5 Added more scalable oauth2_proxy_active configuration 2025-02-17 16:07:26 +01:00
77ad71436e Adapted saturation and hue filters 2025-02-17 15:29:38 +01:00
0161f855ae Adapted CSS for Keycloak 2025-02-17 15:12:04 +01:00
20f56c6b91 Adapted CSS for Keycloak 2025-02-17 14:56:16 +01:00
e874fa41f0 Adapted global css for wordpress 2025-02-17 14:39:38 +01:00
f7953f74bd Adapted global css for dark mode and better automatic color scaling 2025-02-17 13:51:22 +01:00
326f048639 Refactored and solved matomo variable bug 2025-02-17 11:04:40 +01:00
62f9bab052 Solved bugs and refactored 2025-02-15 17:43:36 +01:00
c7da4ddd8f Refactored applications.keycloak* variables 2025-02-15 16:24:31 +01:00
0b98bc1541 Adapted code for virgin setup 2025-02-15 16:02:27 +01:00
99b262c0a6 Optimized CSS generation, auto generated on base color 2025-02-15 14:52:39 +01:00
3a6fc106a8 Solved discourse update bug 2025-02-14 09:37:22 +01:00
c5de205e87 Added nbetwork bound for discourse and central-postgres 2025-02-13 14:17:04 +01:00
998f4e383d Updated discourse for docker-update role 2025-02-13 14:11:06 +01:00
d276918bcf Optimized CSS for Mailu and Keycloak 2025-02-13 10:52:20 +01:00
e947c203a1 Optimized setup routine for memberOf ldap 2025-02-12 19:06:32 +01:00
d947d0a49d Added link to references 2025-02-12 15:12:36 +01:00
19f6b181bc Automatized logging by enable_debug variable 2025-02-12 13:36:29 +01:00
eaca564c6f Added LDAP Draft for Funkwhale 2025-02-12 12:41:13 +01:00
c687b19a6d Added ldap ldif import draft 2025-02-11 18:09:26 +01:00
e193e92443 Added ldap roles draft 2025-02-11 16:19:08 +01:00
2a2d70e4da Added roles draft 2025-02-11 13:30:32 +01:00
de475e7347 Optimized CSS for Keycloak 2025-02-11 13:26:32 +01:00
f76e7ae8b7 Deleted LAM Cache 2025-02-11 11:43:24 +01:00
7fc44b9a35 Restricted taiga port 80 to 127.0.0.1 2025-02-11 05:27:39 +01:00
a7f50e05de Implemented static IP's to solve fastcgi bug in nextcloud. https://chatgpt.com/c/67aa957f-03fc-800f-b092-9b219e36c260 2025-02-11 05:01:20 +01:00
60c84d57ba Optimized networking and matomo 2025-02-11 04:49:21 +01:00
5cb1aa45ad Added more nextcloud css 2025-02-11 01:38:24 +01:00
0c3f088810 Solved Taiga variable bug 2025-02-11 01:04:25 +01:00
12a390229c Implemented health checks for nextcloud 2025-02-11 00:31:32 +01:00
33aa31e55e Added remove orphans 2025-02-11 00:16:54 +01:00
0717d386e0 Optimized peertube 2025-02-11 00:06:41 +01:00
74683bc1fc In between re-draft for nextcloud 2025-02-10 22:42:08 +01:00
762c564c61 Added more nginx optimation 2025-02-10 20:58:20 +01:00
93542ea34f Solved Nextcloud bugs 2025-02-10 19:07:25 +01:00
87b176a7b7 Finished Nextcloud CSS 2025-02-10 17:27:43 +01:00
26d89a9ac2 Merged 2025-02-10 17:19:03 +01:00
90b9422f65 Adapted CSS for nextcloud 2025-02-10 17:17:43 +01:00
490a215dce Deactivated dark theming and optimized mastodon 2025-02-10 16:24:27 +01:00
eb405b4b25 Addded configuration for op 2025-02-10 14:49:37 +01:00
401f748509 Addapted global css für nextcloud 2025-02-10 14:11:29 +01:00
5caf9180d1 Implemented last conf für Taiga 2025-02-08 11:58:56 +01:00
d149ae486c Changed styling for kanban 2025-02-08 11:19:44 +01:00
769b43ce07 Finished Global CSS Draft. Fine Optimation for all apps still needed. But overall happy with the result 2025-02-07 20:09:17 +01:00
bebcdfd2da Added helper role 2025-02-07 19:25:31 +01:00
c11bcfa10f Implemented logic to don't generate everytime a new version and instead use the template modification timestamp 2025-02-07 18:09:18 +01:00
043a33acd9 Solved link bugs 2025-02-07 17:33:29 +01:00
93d2a862c4 Implemented correct loading order 2025-02-07 17:25:53 +01:00
38e031da13 Solved mastodon svg bug 2025-02-07 16:06:42 +01:00
c3dd6e6a34 Added link for OICD plugin isntallation with peertube 2025-02-07 15:27:07 +01:00
8b9bd80d20 Added potential fix for mastodon styling bug 2025-02-07 15:24:45 +01:00
26ffabf0a5 Removed all style elements which aren't color or text styling 2025-02-07 15:07:43 +01:00
b9d29ee06d dynamic modal colors 2025-02-07 14:35:46 +01:00
fedc5572f1 Optimized Global CSS for portfolio 2025-02-07 14:08:18 +01:00
9efca268c9 Implemented Global CSS draft 2025-02-07 13:39:46 +01:00
44438dab64 Finished bluesky implementation for today! 2025-02-07 02:18:35 +01:00
2e338b0506 Optimized bluesky env variables 2025-02-07 01:34:15 +01:00
20209cce7e Updated bluesky variables 2025-02-07 00:32:54 +01:00
22309acfff Refactored bluesky variables 2025-02-07 00:12:05 +01:00
f0760d3969 Refactored bluesky 2025-02-06 23:59:53 +01:00
c2f97cde59 Updated Nextcloud README.md 2025-02-06 23:08:32 +01:00
b1ff11a0b8 Implemented automatic OIDC connection for Nextcloud 2025-02-06 23:04:37 +01:00
eaeab18103 Solved merge variable bug 2025-02-06 21:18:25 +01:00
e641539a94 Updated Mastodon README.md 2025-02-06 18:55:30 +01:00
bd68e42312 Adapted URLs and SSO naming 2025-02-06 18:47:04 +01:00
95f3fdb130 Implemented OIDC für mastodon 2025-02-06 18:19:42 +01:00
31ee369a90 Solved bugs for not to internet exposed ldap 2025-02-06 17:15:33 +01:00
f5c9c3edba solved locale network bugs of ldap 2025-02-06 16:27:00 +01:00
4192c153a2 implemented password redirect url for mailu 2025-02-06 16:01:12 +01:00
280ef536da Added detailled logging for nginx 2025-02-06 15:47:18 +01:00
b788a7e32b Implemented OIDC for mailu 2025-02-06 15:02:33 +01:00
ea30612de9 Merge branch 'master' of github.com:kevinveenbirkenbach/cymais 2025-02-06 12:27:50 +01:00
7bcd636e44 Solved variable name bug 2025-02-06 12:27:41 +01:00
208150f797 Added hints for friendica oidc implementation 2025-02-06 11:00:20 +01:00
dacb3c74fb Finalized Snipe IT role. SAML Support still missing 2025-02-05 15:49:45 +01:00
53af17b2ab Solved Snipe IT bug 2025-02-05 12:53:06 +01:00
26942a9265 Continued snipe-it implementation 2025-02-05 11:44:11 +01:00
e98d18f369 Solved taiga bug and adapted it to new database layout 2025-02-05 02:09:42 +01:00
8e6a383617 Removed double restart policy 2025-02-05 01:54:58 +01:00
01ae2c3b38 solved environment variable bug 2025-02-04 23:52:21 +01:00
8083e2b51c optimized snipe-it draf 2025-02-04 23:48:18 +01:00
df44ea524c Solved open project environment variaböe bug 2025-02-04 23:15:05 +01:00
e50fd54f4e Implemented a new docker compose structure which seperates between docker compose files and environment variable file to protect credentials better. Also did recatoring. Changes not fully tested 2025-02-04 22:37:07 +01:00
5503326ea6 Implemented helper role docker-central-database and refactored code 2025-02-04 18:14:37 +01:00
cb6a42e97d Implemented pre-defined subnets for docker due to network clashes 2025-02-04 16:43:34 +01:00
aaac98249c Optimized snipe-it draft 2025-02-04 16:40:08 +01:00
49aafaf5b8 Solved redirect bug 2025-02-04 11:01:00 +01:00
207030cb48 Solved matrix port bug 2025-02-03 23:07:42 +01:00
75ff756808 Solved redirected_domains merge 2025-02-03 22:28:42 +01:00
7781083161 Solved mapping bugs 2025-02-03 22:08:16 +01:00
8a6adf3958 Implemented tmp healthcheck for etherpad 2025-02-03 20:27:58 +01:00
734d4f8ed3 Implemented wildcard function for www redirects and solved bugs 2025-02-03 18:10:07 +01:00
ccc87ad24b Solved docker variable bug 2025-02-03 17:24:18 +01:00
8e2c8360d4 Solved wildcard certificate for non-wildcard domains and network variable bug 2025-02-03 16:05:25 +01:00
b91a132407 Solved mailu env bug 2025-02-03 15:45:17 +01:00
57649698c2 Optimized formatation 2025-02-03 15:39:41 +01:00
b8d73f6b09 Moved mailu subnet configuration to defaults_networks 2025-02-03 15:10:03 +01:00
83c84f6e86 Optimized locales and networks variable 2025-02-03 14:56:12 +01:00
30ccd30fa6 Optimized snipe-it role draft 2025-02-03 14:54:31 +01:00
15c5508239 solved variable bug 2025-02-03 14:07:52 +01:00
d2478120ba Solved funkwhale variable bug 2025-02-03 13:22:53 +01:00
b671f9dd05 Solved directory naming bug 2025-02-03 13:07:14 +01:00
4768d66fbb Solved merge bug 2025-02-03 12:49:38 +01:00
b11879650c Refactored application variables 2025-02-03 11:44:13 +01:00
ce13beff68 Added draft for snipe-it 2025-02-03 11:13:17 +01:00
11752f5e2e Nginx variable refactoring and general bug solving. Got interupted commit not tested 2025-01-31 13:14:07 +01:00
b96d95f3e4 Adapted variable 2025-01-30 15:42:44 +01:00
ca7d28dcf4 Added wildcard certs for bbb 2025-01-30 15:19:10 +01:00
4c0aba2eea HUGE REFACTORING; Implementing ldap networks, new port mappings, heal script optimizing etc. 2025-01-30 15:04:23 +01:00
61890dcf1f Solved ldap bug 2025-01-30 12:14:18 +01:00
45b56a7aaa Solved domain bug 2025-01-30 11:41:34 +01:00
ab66a18b53 Removed --build flag 2025-01-29 18:30:57 +01:00
c515c2f439 Optimized conditions for certificate cleanup 2025-01-29 17:15:30 +01:00
21728ab60f Added cleanup mode for certs and solved peertube variable bug 2025-01-29 17:01:54 +01:00
6c9a069cf0 changed variable name 2025-01-29 16:52:09 +01:00
4d1a71befd Optimized instructions and default values for wildcard certificates 2025-01-29 16:45:09 +01:00
eb6fdd29d3 Implemented draft for wildcard certificate 2025-01-29 15:52:40 +01:00
eaed9837d1 Replaced domains name 2025-01-29 15:03:51 +01:00
077e38e6a4 Set variable global 2025-01-29 14:42:13 +01:00
7ff03ef46b Solved minor bugs which appeared during refactoring 2025-01-29 14:34:46 +01:00
aca3399e9d Big code and variable refactoring 2025-01-29 14:20:34 +01:00
13429d8e68 Merge branch 'master' of github.com:kevinveenbirkenbach/cymais 2025-01-28 19:58:56 +01:00
ad2d1e574f Added xmpp role for documentation reasons 2025-01-28 19:55:52 +01:00
72c944d13d Merge branch 'master' of github.com:kevinveenbirkenbach/cymais 2025-01-28 16:54:48 +01:00
3244b7d62e Added funkwhale draft and set variablesfor db ports 2025-01-28 16:54:39 +01:00
7e2966b02c Added OIDC automation draft for nextcloud 2025-01-28 00:38:09 +01:00
6f851973fa Deactivated default login mask 2025-01-27 12:48:25 +01:00
69a98c4c24 Added auto oidc parameters to discourse 2025-01-27 11:51:14 +01:00
c896057400 Added condition for OIDC bbb 2025-01-27 10:57:59 +01:00
2d38f97b17 solved protocol bug 2025-01-27 10:49:51 +01:00
f1607b9045 Added OIDC for bigbluebutton 2025-01-27 10:17:25 +01:00
338c7b5830 Solved variable and handler bugs 2025-01-27 00:52:49 +01:00
b6836d9bb1 Added README.md 2025-01-26 23:53:44 +01:00
2ff54d4c50 Updated variable names 2025-01-26 23:45:16 +01:00
cb972b1b91 Moved to one client for Oauth2-Proxy 2025-01-26 22:43:48 +01:00
54cac88d26 Implemented OAuth2-Proxy for LDAP 2025-01-26 22:16:58 +01:00
b742ffd476 Implemented OAuth2-Proxy and other security measures for phpmyadmin 2025-01-26 20:57:34 +01:00
ec5768f3d4 Added phpmyadmin 2025-01-26 19:47:01 +01:00
a474511e27 Added README.md 2025-01-26 18:15:08 +01:00
49fbdce398 solved variable bug 2025-01-26 17:38:34 +01:00
2460 changed files with 63539 additions and 11508 deletions

13
.dockerignore Normal file
View File

@@ -0,0 +1,13 @@
# The .gitignore is the single point of truth for files which should be ignored.
# Add patterns, files and folders to the .gitignore and execute 'make build'
# NEVER TOUCH THE .dockerignore, BECAUSE IT ANYHOW WILL BE OVERWRITTEN
site.retry
*__pycache__
venv
*.log
*.bak
*tree.json
roles/list.json
*.pyc
.git

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto eol=lf

7
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
github: kevinveenbirkenbach
patreon: kevinveenbirkenbach
buy_me_a_coffee: kevinveenbirkenbach
custom: https://s.veen.world/paypaldonate

4
.github/workflows/TODO.md vendored Normal file
View File

@@ -0,0 +1,4 @@
# Todo
- Create workflow test-server, which tests all server roles
- Create workflow test-desktop, which tests all desktop roles
- For the backup services keep in mind to setup a tandem, which pulls the backups from each other to verify that this also works

32
.github/workflows/test-cli.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Build & Test Infinito.Nexus CLI in Docker Container
on:
push:
branches:
- master
pull_request:
jobs:
build-and-test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Build Docker image
run: |
docker build -t infinito:latest .
- name: Clean build artifacts
run: |
docker run --rm infinito:latest make clean
- name: Generate project outputs
run: |
docker run --rm infinito:latest make build
- name: Run tests
run: |
docker run --rm infinito:latest make test

11
.gitignore vendored
View File

@@ -1 +1,12 @@
# The .gitignore is the single point of truth for files which should be ignored.
# Add patterns, files and folders to the .gitignore and execute 'make build'
# NEVER TOUCH THE .dockerignore, BECAUSE IT ANYHOW WILL BE OVERWRITTEN
site.retry
*__pycache__
venv
*.log
*.bak
*tree.json
roles/list.json
*.pyc

38
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,38 @@
# Code of Conduct
In order to foster a welcoming, open, and respectful community for everyone, we expect all contributors and participants in the Infinito.Nexus project to abide by the following Code of Conduct.
## Our Pledge
We are committed to creating a friendly, safe, and inclusive environment for all members of our community—regardless of age, race, gender, sexual orientation, disability, religion, or any other status. We pledge to treat everyone with respect and courtesy.
## Expected Behavior
- **Be Respectful:** Communicate and collaborate with courtesy, empathy, and respect. Listen to others opinions and value their input.
- **Be Inclusive:** Welcome contributions from all backgrounds and experiences. Encourage diverse perspectives and engage in constructive dialogue.
- **Practice Professionalism:** Use clear and professional language in all communications. Maintain focus on ideas and project goals rather than personal attributes.
- **Be Collaborative:** Foster an environment where everyone can contribute freely. Offer help and constructive feedback, and work together towards common goals.
- **Respect Boundaries:** Understand and honor others personal and professional boundaries.
## Unacceptable Behavior
- **Harassment and Discrimination:** Any form of harassment, hate speech, or discriminatory behavior will not be tolerated.
- **Intimidation and Threats:** Verbal or written intimidation, threats, or aggressive behavior toward any community member is strictly prohibited.
- **Personal Attacks:** Avoid personal insults or demeaning comments toward any contributor or participant.
- **Exclusionary Behavior:** Do not engage in behaviors or comments that might exclude or isolate community members.
## Reporting and Enforcement
If you experience or witness any behavior that violates this Code of Conduct, please report it promptly. Reports should be sent to kevin@veen.world. All reports will be treated with discretion and confidentiality.
Our project maintainers and community leaders will review all reports and take appropriate action, which may include warnings, temporary suspension, or permanent expulsion from the community if necessary.
## Scope
This Code of Conduct applies to all spaces managed by the Infinito.Nexus project, including GitHub repositories, mailing lists, chat rooms, and other communication channels.
## Acknowledgment
By participating in the Infinito.Nexus project, you agree to adhere to this Code of Conduct. We appreciate your cooperation in helping us build a positive and productive community.
Thank you for contributing to a safe and inclusive Infinito.Nexus community!

View File

@@ -1,81 +0,0 @@
# Common Applications
This section outlines the common applications tailored for both servers and end-users, offering a wide range of functionalities to enhance system performance, security, and usability.
## Base Setup
Key for initial system configuration, this section includes hostname setting, systemd journal management, locale configurations, and swapfile handling. Essential for both server and end-user setups, it ensures a solid foundation for system operations.
- **[Hostname](./roles/hostname/)**: Sets the system's hostname.
- **[Journalctl](./roles/journalctl/)**: Configures systemd journal settings.
- **[Locales](./roles/locales/)**: Configures system locales.
- **[System-Swapfile](./roles/system-swapfile/)**: Configures swapfile creation and management.
## Administration Tools
These tools are crucial for effective system administration, encompassing Git setup, Linux admin tools, and sudo configuration, suitable for both server environments and power users.
- **[Git](./roles/git/)**: Basic Git version control system setup.
- **[Administrator-Tools](./roles/pc-administrator-tools/)**: Installs basic Linux administration tools.
- **[Sudo](./roles/sudo/)**: Installs and configures sudo.
## Update
This category focuses on automated updates and maintenance for the system and its components, including package managers and Docker containers, ensuring systems are up-to-date and secure.
- **[update](./roles/update/)**: Automates the process of system updates.
- **[update-apt](./roles/update-apt/)**: Updates system packages using apt (for Debian-based systems).
- **[update-docker](./roles/update-docker/)**: Keeps Docker containers up to date.
- **[update-pacman](./roles/update-pacman/)**: Updates system packages using Pacman (for Arch-based systems).
- **[update-yay](./roles/update-yay/)**: Updates system packages using yay.
## Driver
Caters to a range of devices and needs for hardware driver installation and configuration, an integral part for both server hardware optimization and end-user device functionality.
- **[driver-epson-multiprinter](./roles/driver-epson-multiprinter/)**: Installs drivers for Epson multi-function printers.
- **[driver-intel](./roles/driver-intel/)**: Installs Intel drivers, typically for graphics and other hardware.
- **[driver-msi-keyboard-color](./roles/driver-msi-keyboard-color/)**: Configures MSI keyboard color settings.
- **[driver-non-free](./roles/driver-non-free/)**: Installs non-free drivers, generally for specific hardware needs.
## Security
Enhances system security with roles focused on security measures, user configurations, and SSH settings. It's vital for protecting both server environments and end-user systems.
- **[System Security](./roles/system-security/)**: Enhances overall system security.
- **[User Administrator](./roles/user-administrator/)**: Setup for system administrator user.
- **[User Alarm](./roles/user-alarm/)**: Manages the alarm user.
- **[PC SSH](./roles/pc-ssh/)**: Configuration of SSH for secure remote access.
- **[SSHD](./roles/sshd/)**: Configures SSH daemon settings.
- **[System Maintenance Lock](./roles/system-maintenance-lock)**: Locks maintenance services to prevent dangerous inteactions between services
## Virtual Private Network (VPN)
Centers on VPN configurations for secure and efficient network connectivity, particularly crucial for remote server access and end-users needing secure connections.
- **[client-wireguard](./roles/client-wireguard/)**: Configures Wireguard VPN client.
- **[client-wireguard-behind-firewall](./roles/client-wireguard-behind-firewall/)**: Sets up Wireguard client functionality behind a firewall.
- **[wireguard](./roles/wireguard/)**: Installs and configures Wireguard for secure VPN connections.
## Notifier
Sets up system event notifications via email and Telegram, a versatile feature for server administrators and end-users alike to stay informed about their system's status.
- **[Systemd-Notifier](./roles/systemd-notifier/)**: Notifier service for systemd.
- **[Systemd-Notifier-Email](./roles/systemd-notifier-email/)**: Email notifications for systemd services.
- **[Systemd-Notifier-Telegram](./roles/systemd-notifier-telegram/)**: Telegram notifications for systemd services.
## Backup Solutions
Focuses on comprehensive backup strategies and cleanup procedures, encompassing data backups, remote server backups, and maintenance of backup storage efficiency, crucial for data integrity in both servers and personal devices.
### Backups
For USB devices, Docker volumes, remote servers, and user configurations.
- **[backup-data-to-usb](./roles/backup-data-to-usb/)**: Automates data backup to USB devices.
- **[backup-docker-to-local](./roles/backup-docker-to-local/)**: Backs up Docker volumes to local storage.
- **[backup-remote-to-local](./roles/backup-remote-to-local/)**: Pulls backups from remote servers for local storage.
- **[backups-provider](./roles/backups-provider/)**: Manages backup processes and storage solutions.
- **[backups-provider-user](./roles/backups-provider-user/)**: Creates and configures users for backup processes.
### Backups Cleanup
Manages disk space and cleans up old or failed backups.
- **[cleanup-backups-service](./roles/cleanup-backups-service/)**: Service to clean up old backups automatically.
- **[cleanup-backups-timer](./roles/cleanup-backups-timer/)**: Timer for scheduling the backup cleanup service.
- **[cleanup-disc-space](./roles/cleanup-disc-space/)**: Manages and frees up disk space on the system.
- **[cleanup-failed-docker-backups](./roles/cleanup-failed-docker-backups/)**: Cleans up failed Docker backups.
## Other
Encompasses miscellaneous essential tools and systems, including package management, spellchecking, and typesetting, beneficial for both server maintenance and enhancing end-user experience.
- **[System-Aur-Helper](./roles/system-aur-helper/)**: Installs and configures AUR helper (yay).
- **[Hunspell](./roles/hunspell/)**: Installation of Hunspell spellchecker.
- **[Latex](./roles/pc-latex/)**: Installation of LaTeX typesetting system.
- **[Java](./roles/java/)**: Installs Java Development Kit (JDK).
- **[Python Pip](./roles/python-pip/)**: Installation of Python Pip package manager.

17
CONTACT.md Normal file
View File

@@ -0,0 +1,17 @@
# Contact
<img src="https://cybermaster.space/wp-content/uploads/sites/7/2023/11/FVG_8364BW-scaled.jpg" width="300" style="float: right; margin-left: 30px;">
My name is Kevin Veen-Birkenbach and I'm the author and founder of Infinito.Nexus.
I'm glad to assist you in the implementation of your secure and scalable IT infrastrucutre solution with Infinito.Nexus.
My expertise in server administration, digital corporate infrastructure, custom software, and information security, all underpinned by a commitment to Open Source solutions, guarantees that your IT setup meets the highest industry standards.
Discover how Infinito.Nexus can transform your IT landscape.
Contact me for more details:
🌍 Website: [www.CyberMaster.Space](https://cybermaster.space)<br />
📧 Email: [kevin@veen.world](mailto:kevin@veen.world)<br />
☎️ Phone: [+ 49 178 179 80 23](tel:00491781798023)

57
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,57 @@
# Contributing
Thank you for your interest in contributing to Infinito.Nexus! We welcome contributions from the community to help improve and enhance this project. Your input makes the project stronger and more adaptable to a wide range of IT infrastructure needs.
## How to Contribute
There are several ways you can help:
- **Reporting Issues:** Found a bug or have a feature request? Please open an issue on our [GitHub Issues page](https://s.infinito.nexus/issues) with a clear description and steps to reproduce the problem.
- **Code Contributions:** If you'd like to contribute code, fork the repository, create a new branch for your feature or bug fix, and submit a pull request. Ensure your code adheres to our coding style and includes tests where applicable.
- **Documentation:** Improving the documentation is a great way to contribute. Whether it's clarifying an existing section or adding new guides, your contributions help others understand and use Infinito.Nexus effectively.
- **Financial Contributions:** If you appreciate Infinito.Nexus and want to support its ongoing development, consider making a financial contribution. For more details, please see our [donate options](12_DONATE.md).
## Code of Conduct
All contributors are expected to adhere to our [Code of Conduct](CODE_OF_CONDUCT.md). Please review it to ensure that our community remains welcoming and respectful.
## Pull Request Guidelines
Before submitting a pull request, please ensure that:
- Your code is well-documented and follows the project's coding standards.
- All tests pass and, if necessary, new tests are added to cover your changes.
- The commit messages are clear and descriptive.
- The relevant documentation is updated to reflect your changes.
## Reporting Issues
When reporting an issue, please include:
- A descriptive title and detailed explanation.
- Steps to reproduce the issue.
- Information about your environment (e.g., operating system, Docker version, Ansible version, etc.).
- Any relevant logs or error messages.
## Coding Style
Please follow these guidelines when contributing code:
- Write clean, readable code that integrates with the existing codebase.
- Use descriptive names for variables and functions.
- Comment your code where necessary, especially in complex sections.
- Format your code according to the project's style guidelines.
## License and Commercial Use
Infinito.Nexus is primarily designed for private use. Commercial use of Infinito.Nexus is not permitted without a proper licensing agreement. By contributing to this project, you agree that your contributions will be licensed under the same terms as the rest of the project.
## Getting Started
1. **Fork** the repository on GitHub.
2. **Clone** your fork to your local machine.
3. **Create** a new branch for your feature or bug fix.
4. **Implement** your changes and commit them with clear messages.
5. **Push** your branch to GitHub and open a pull request.
## Community and Support
If you have any questions or need help, feel free to open an issue or join our community discussions. We appreciate your efforts and are here to support you.
Thank you for contributing to Infinito.Nexus and helping us build a better, more efficient IT infrastructure solution!

9
DONATE.md Normal file
View File

@@ -0,0 +1,9 @@
# Support Us
Infinito.Nexus is an Open Source Based transformative tool designed to redefine IT infrastructure setup for organizations and individuals alike. Your contributions directly support the ongoing development and innovation behind Infinito.Nexus, ensuring that it continues to grow and serve its community effectively.
If you enjoy using Infinito.Nexus and would like to contribute to its improvement, please consider donating. Every contribution, no matter the size, helps us maintain and expand this project.
[![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-blue?logo=github)](https://github.com/sponsors/kevinveenbirkenbach) [![Patreon](https://img.shields.io/badge/Support-Patreon-orange?logo=patreon)](https://www.patreon.com/c/kevinveenbirkenbach) [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20me%20a%20Coffee-Funding-yellow?logo=buymeacoffee)](https://buymeacoffee.com/kevinveenbirkenbach) [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal)](https://s.veen.world/paypaldonate)
Thank you for your support!

69
Dockerfile Normal file
View File

@@ -0,0 +1,69 @@
FROM archlinux:latest
# 1) Update system and install build/runtime deps
RUN pacman -Syu --noconfirm \
base-devel \
git \
python \
python-pip \
python-setuptools \
alsa-lib \
go \
rsync \
&& pacman -Scc --noconfirm
# 2) Stub out systemctl & yay so post-install hooks and AUR calls never fail
RUN printf '#!/bin/sh\nexit 0\n' > /usr/bin/systemctl \
&& chmod +x /usr/bin/systemctl \
&& printf '#!/bin/sh\nexit 0\n' > /usr/bin/yay \
&& chmod +x /usr/bin/yay
# 3) Build & install python-simpleaudio from AUR manually (as non-root)
RUN useradd -m aur_builder \
&& su aur_builder -c "git clone https://aur.archlinux.org/python-simpleaudio.git /home/aur_builder/psa && \
cd /home/aur_builder/psa && \
makepkg --noconfirm --skippgpcheck" \
&& pacman -U --noconfirm /home/aur_builder/psa/*.pkg.tar.zst \
&& rm -rf /home/aur_builder/psa
# 4) Clone Kevins Package Manager and create its venv
ENV PKGMGR_REPO=/opt/package-manager \
PKGMGR_VENV=/root/.venvs/pkgmgr
RUN git clone https://github.com/kevinveenbirkenbach/package-manager.git $PKGMGR_REPO \
&& python -m venv $PKGMGR_VENV \
&& $PKGMGR_VENV/bin/pip install --upgrade pip \
# install pkgmgrs own deps + the ansible Python library so infinito import yaml & ansible.plugins.lookup work
&& $PKGMGR_VENV/bin/pip install --no-cache-dir -r $PKGMGR_REPO/requirements.txt ansible \
# drop a thin wrapper so `pkgmgr` always runs inside that venv
&& printf '#!/bin/sh\n. %s/bin/activate\nexec python %s/main.py "$@"\n' \
"$PKGMGR_VENV" "$PKGMGR_REPO" > /usr/local/bin/pkgmgr \
&& chmod +x /usr/local/bin/pkgmgr
# 5) Ensure pkgmgr venv bin and user-local bin are on PATH
ENV PATH="$PKGMGR_VENV/bin:/root/.local/bin:${PATH}"
# 6) Copy local Infinito.Nexus source into the image for override
COPY . /opt/infinito-src
# 7) Install Infinito.Nexus via pkgmgr (clone-mode https)
RUN pkgmgr install infinito --clone-mode https
# 8) Override installed Infinito.Nexus with local source and clean ignored files
RUN INFINITO_PATH=$(pkgmgr path infinito) && \
rm -rf "$INFINITO_PATH"/* && \
rsync -a --delete --exclude='.git' /opt/infinito-src/ "$INFINITO_PATH"/
# 9) Symlink the infinito script into /usr/local/bin so ENTRYPOINT works
RUN INFINITO_PATH=$(pkgmgr path infinito) && \
ln -sf "$INFINITO_PATH"/main.py /usr/local/bin/infinito && \
chmod +x /usr/local/bin/infinito
# 10) Run integration tests
# This needed to be deactivated becaus it doesn't work with gitthub workflow
#RUN INFINITO_PATH=$(pkgmgr path infinito) && \
# cd "$INFINITO_PATH" && \
# make test
ENTRYPOINT ["infinito"]
CMD ["--help"]

View File

@@ -1,46 +0,0 @@
# End User Applications
End User Applications provide a diverse suite of tools and software designed to enhance the computing experience for personal computer users, including those using desktops and laptops. These applications cover various aspects such as multimedia, productivity, virtualization, and more, catering to the everyday needs of end users.
## Common Applications
In addition to the specialized software found in this document, the [COMMON_APPLICATIONS.md](./COMMON_APPLICATIONS.md) offers a comprehensive range of functionalities that cater to both server and end-user needs. This section enhances system performance, security, and usability with a variety of tools and configurations suitable for diverse computing environments.
## Desktop
This category focuses on tools and configurations that enhance the desktop computing experience. It includes utilities to maintain system activity, and software for optimizing the desktop environment, ensuring a seamless and user-friendly interface for day-to-day computer usage.
- **[Caffeine](./roles/pc-caffeine/)**: Utility to keep your computer awake.
- **[Gnome](./roles/pc-gnome/)**: Installation and configuration of Gnome desktop environment.
## Entertainment
Geared towards leisure and entertainment, this section includes software for playing Blu-ray media, accessing a vast collection of music, and installing various computer games. It's designed to enrich your personal computing experience with multimedia enjoyment and gaming.
- **[Bluray Player Tools](./roles/pc-bluray-player-tools/)**: Software for playing Blu-ray media on personal computers.
- **[Spotify](./roles/pc-spotify/)**: Installation of Spotify for music streaming.
- **[Games](./roles/pc-games/)**: Installation of various computer games.
## Office
This segment caters to professional productivity needs. It encompasses a range of office-related software, from comprehensive office suites and video conferencing tools to cloud storage solutions, facilitating efficient and organized work in various office environments.
- **[LibreOffice](./roles/pc-libreoffice/)**: Installation of the LibreOffice suite.
- **[Office](./roles/pc-office/)**: Various office productivity tools.
- **[Video Conference](./roles/pc-video-conference/)**: Video conferencing software setup.
- **[Nextcloud Client](./roles/pc-nextcloud/)**: Client setup for Nextcloud cloud storage service.
- **[GnuCash](./roles/pc-gnucash/)**: Software to manage finances
- **[Jrnl](./roles/pc-jrnl/)**: CLI Journaling
## Anonymization
Focusing on privacy and security, the Anonymization section offers tools for secure file sharing and anonymous web browsing. It includes software solutions that prioritize user privacy, ensuring secure online activities and data protection.
- **[Qbittorrent](./roles/pc-qbittorrent/)**: Installation of qBittorrent for file sharing.
- **[Torbrowser](./roles/pc-torbrowser/)**: Installation of Tor Browser for anonymous browsing.
## Content Creation
Dedicated to creatives and content producers, this category provides tools essential for video streaming, recording, graphic design, and 3D modeling. It's tailored for those involved in digital content creation, offering the necessary software to bring creative projects to life.
- **[Streaming Tools](./roles/pc-streaming-tools/)**: Software for video streaming and recording.
- **[Designer Tools](./roles/pc-designer-tools/)**: Graphic design and 3D modeling software.
## Development Environment
Targets software developers with tools and environments for various programming languages and development needs.
- **[Developer Tools](./roles/pc-developer-tools/)**: Basic developer tools setup.
- **[Developer Tools for Arduino](./roles/pc-developer-tools-arduino/)**: Setup for Arduino development.
- **[Developer Tools for Bash](./roles/pc-developer-tools-bash/)**: Tools for Bash scripting.
- **[Developer Tools for Java](./roles/pc-developer-tools-java/)**: Java development environment setup.
- **[Developer Tools for PHP](./roles/pc-developer-tools-php/)**: PHP development environment setup.
- **[Developer Tools for Python](./roles/pc-developer-tools-python/)**: Python development environment setup.
- **[Virtual Box](./roles/pc-virtual-box/)**: VirtualBox setup for creating virtual machines.
- **[Network Analyze Tools](./roles/pc-network-analyze-tools/)**: Network analysis and troubleshooting utilities.

View File

@@ -1,10 +1,12 @@
# License Agreement
## Definitions
- **"Software":** Refers to *"[CyMaIS - Cyber Master Infrastructure Solution](https://cymais.cloud/)"* and its associated source code.
## Infinito.Nexus NonCommercial License
### Definitions
- **"Software":** Refers to *"[Infinito.Nexus](https://infinito.nexus/)"* and its associated source code.
- **"Commercial Use":** Any use of the Software intended for direct or indirect financial gain, including but not limited to sales, rentals, or provision of services.
## Provisions
### Provisions
1. **Attribution of the Original Licensor:** In any distribution or publication of the Software or derivative works, the original licensor, *Kevin Veen-Birkenbach, Email: [license@veen.world](mailto:license@veen.world), Website: [https://www.veen.world/](https://www.veen.world/)* must be explicitly named.
@@ -23,5 +25,5 @@
7. **Ownership of Rights:** All rights, including copyright, trademark, and other forms of intellectual property related to the Software, belong exclusively to Kevin Veen-Birkenbach.
## Consent
### Consent
By using, modifying, or distributing the Software, you agree to these terms.

85
Makefile Normal file
View File

@@ -0,0 +1,85 @@
ROLES_DIR := ./roles
APPLICATIONS_OUT := ./group_vars/all/04_applications.yml
APPLICATIONS_SCRIPT := ./cli/build/defaults/applications.py
USERS_OUT := ./group_vars/all/03_users.yml
USERS_SCRIPT := ./cli/build/defaults/users.py
INCLUDES_SCRIPT := ./cli/build/role_include.py
INCLUDE_GROUPS := $(shell python3 main.py meta categories invokable -s "-" --no-signal | tr '\n' ' ')
# Directory where these include-files will be written
INCLUDES_OUT_DIR := ./tasks/groups
# Compute extra users as before
EXTRA_USERS := $(shell \
find $(ROLES_DIR) -maxdepth 1 -type d -printf '%f\n' \
| sed -E 's/.*-//' \
| grep -E -x '[a-z0-9]+' \
| sort -u \
| paste -sd, - \
)
.PHONY: build install test
clean-keep-logs:
@echo "🧹 Cleaning ignored files but keeping logs/…"
git clean -fdX -- ':!logs' ':!logs/**'
clean:
@echo "Removing ignored git files"
git clean -fdX
list:
@echo Generating the roles list
python3 main.py build roles_list
tree:
@echo Generating Tree
python3 main.py build tree -D 2 --no-signal
mig: list tree
@echo Creating meta data for meta infinity graph
dockerignore:
@echo Create dockerignore
cat .gitignore > .dockerignore
echo ".git" >> .dockerignore
messy-build: dockerignore
@echo "🔧 Generating users defaults → $(USERS_OUT)"
python3 $(USERS_SCRIPT) \
--roles-dir $(ROLES_DIR) \
--output $(USERS_OUT) \
--extra-users "$(EXTRA_USERS)"
@echo "✅ Users defaults written to $(USERS_OUT)\n"
@echo "🔧 Generating applications defaults → $(APPLICATIONS_OUT)"
python3 $(APPLICATIONS_SCRIPT) \
--roles-dir $(ROLES_DIR) \
--output-file $(APPLICATIONS_OUT)
@echo "✅ Applications defaults written to $(APPLICATIONS_OUT)\n"
@echo "🔧 Generating role-include files for each group…"
@mkdir -p $(INCLUDES_OUT_DIR)
@$(foreach grp,$(INCLUDE_GROUPS), \
out=$(INCLUDES_OUT_DIR)/$(grp)roles.yml; \
echo "→ Building $$out (pattern: '$(grp)')…"; \
python3 $(INCLUDES_SCRIPT) $(ROLES_DIR) \
-p $(grp) -o $$out; \
echo "$$out"; \
)
messy-test:
@echo "🧪 Running Python tests…"
PYTHONPATH=. python -m unittest discover -s tests
@echo "📑 Checking Ansible syntax…"
ansible-playbook playbook.yml --syntax-check
install: build
@echo "⚙️ Install complete."
build: clean messy-build
@echo "Full build with cleanup before was executed."
test: build messy-test
@echo "Full test with build before was executed."

110
README.md
View File

@@ -1,80 +1,94 @@
# CyMaIS - Cyber Master Infrastructure Solution
# Infinito.Nexus 🚀
<img src="https://cybermaster.space/wp-content/uploads/sites/7/2023/12/logo_cymais.png" width="300" style="float: right; margin-left: 10px;">
**🔐 One login. ♾️ Infinite application**
Welcome to CyMaIS (Cyber Master Infrastructure Solution), a transformative tool designed to redefine IT infrastructure setup for organizations and individuals alike.
![Infinito.Nexus Logo](assets/img/logo.png)
---
At its core, CyMaIS leverages the power of Docker, Linux, and Ansible to offer a streamlined, automated solution for deploying and managing IT systems.
## What is Infinito.Nexus? 📌
Whether you're a small startup, a growing enterprise, or an individual seeking efficient IT management, CyMaIS provides a comprehensive suite of tools that cater to a wide range of needs. From simple system setups to complex server configurations and end-user PC management, CyMaIS simplifies the entire process.
**Infinito.Nexus** is an **automated, modular infrastructure framework** built on **Docker**, **Linux**, and **Ansible**, equally suited for cloud services, local server management, and desktop workstations. At its core lies a **web-based desktop with single sign-on**—backed by an **LDAP directory** and **OIDC**—granting **seamless access** to an almost limitless portfolio of self-hosted applications. It fully supports **ActivityPub applications** and is **Fediverse-compatible**, while integrated **monitoring**, **alerting**, **cleanup**, **self-healing**, **automated updates**, and **backup solutions** provide everything an organization needs to run at scale.
Our intuitive interface, coupled with in-depth documentation, makes it accessible to both tech-savvy users and those with limited IT experience.
| 📚 | 🔗 |
|---|---|
| 🌐 Try It Live | [![Infinito.Nexus](https://img.shields.io/badge/Infinito.Nexus-%2ECloud-000000?labelColor=004B8D&style=flat&borderRadius=8)](https://infinito.nexus) |
| 🔧 Request Your Setup | [![CyberMaster.Space](https://img.shields.io/badge/CyberMaster-%2ESpace-000000?labelColor=004B8D&style=flat&borderRadius=8)](https://cybermaster.space) |
| 📖 About This Project | [![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-blue?logo=github)](https://github.com/sponsors/kevinveenbirkenbach) [![Build & Test Infinito.Nexus CLI in Docker Container](https://github.com/kevinveenbirkenbach/infinito-nexus/actions/workflows/test-cli.yml/badge.svg)](https://github.com/kevinveenbirkenbach/infinito-nexus/actions/workflows/test-cli.yml) [![View Source](https://img.shields.io/badge/View_Source-Repository-000000?logo=github&labelColor=004B8D&style=flat&borderRadius=8)](https://s.infinito.nexus/code) |
| ☕️ Support Us | [![Patreon](https://img.shields.io/badge/Support-Patreon-orange?logo=patreon)](https://www.patreon.com/c/kevinveenbirkenbach) [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20me%20a%20Coffee-Funding-yellow?logo=buymeacoffee)](https://buymeacoffee.com/kevinveenbirkenbach) [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal)](https://s.veen.world/paypaldonate) [![Sponsor Infinito.Nexus](https://img.shields.io/badge/DonateInfinito.Nexus-000000?style=flat&labelColor=004B8D&logo=github-sponsors&logoColor=white&borderRadius=8)](https://github.com/sponsors/kevinveenbirkenbach) |
With CyMaIS, setting up a secure, scalable, and robust IT infrastructure is not just faster and easier, but also aligned with the best industry practices, ensuring that your organization stays ahead in the ever-evolving digital landscape.
---
## Vision
Our project is anchored in the vision of transforming IT infrastructure deployment into a seamless, secure, and scalable experience.
## Key Features 🎯
We are committed to developing a fully automated solution that enables businesses of any size and industry to set up a 100% secure and infinitely scalable IT infrastructure in just 24 hours.
* **Automated Deployment** 📦
Turn up servers and workstations in minutes with ready-made Ansible roles.
Leveraging the power of Open Source, our tool not only promises to uphold the highest standards of security and adaptability but also embodies a commitment to transparency and community-driven innovation.
* **Enterprise-Grade Security** 🔒
Centralized user management via LDAP & OIDC (Keycloak), plus optional 2FA and encrypted storage.
This is not just a step towards simplifying IT management it's a leap towards democratizing access to advanced technology, ensuring every business can quickly adapt and thrive in the digital age.
* **Modular Scalability** 📈
Grow from small teams to global enterprises by composing only the services you need.
For a deeper understanding of our goals and the ethos driving our project, we invite you to explore our detailed **[Vision Statement](./VISION_STATEMENT.md)**. Here, you'll find the cornerstone principles that guide our development process and our commitment to making a lasting impact in the realm of IT infrastructure.
* **Fediverse & ActivityPub Support** 🌐
Seamlessly integrate Mastodon, Peertube, Matrix and other ActivityPub apps out of the box.
## Solutions Overview
* **Self-Healing & Maintenance** ⚙️
Automated cleanup, container healing, and auto-updates keep infrastructure healthy without human intervention.
To help you navigate through our repository, we have categorized our extensive range of tools and solutions into three key areas:
* **Monitoring, Alerting & Analytics** 📊
Built-in system, application, and security monitoring with multi-channel notifications.
1. **[Server Applications](./SERVER_APPLICATIONS.md)**: Detailed information on server-focused tools and configurations, ideal for managing and optimizing server environments.
* **Backup & Disaster Recovery** 💾
Scheduled backups and scripted recovery processes to safeguard your data.
2. **[End User Applications](./END_USER_APPLICATIONS.md)**: A guide to applications and tools specifically designed for end-user PCs, enhancing personal computing experience.
* **Continuous Updates** 🔄
Automatic patching and version upgrades across the stack.
3. **[Common Applications](./COMMON_APPLICATIONS.md)**: A comprehensive list of tools and applications that are versatile and useful across both server and end-user environments.
* **Application Ecosystem** 🚀
A curated suite of self-hosted apps—from **project management**, **version control**, and **CI/CD** to **chat**, **video conferencing**, **CMS**, **e-learning**, **social networking**, and **e-commerce**—all seamlessly integrated.
Each of these documents provides a tailored overview, ensuring you can find the right tools and information relevant to your specific needs, whether for server management, personal computing, or general IT infrastructure.
More informations about the features you will find [here](docs/overview/Features.md).
## Key Benefits of CyMaIS for Your Business
---
**CyMaIS - Cyber Master Infrastructure Solution** revolutionizes IT infrastructure management, making it simpler, safer, and more adaptable for businesses of all sizes. Here's how it can benefit your organization:
## Get Started 🚀
1. **Effortless Setup and Management**: CyMaIS makes setting up and managing IT systems a breeze. Whether you're using Linux servers or personal computers, our tool automates the process, saving you time and effort.
### Use it online 🌐
2. **Everything You Need in One Place**: From the basics of system setup to advanced features like VPN and Docker, CyMaIS provides a complete range of tools. It's like having an IT expert at your fingertips, offering solutions for every need.
Try [Infinito.Nexus](https://infinito.nexus) sign up in seconds, explore the platform, and discover what our solution can do for you! 🚀🔧✨
3. **Tailored to Your Business**: We understand that every business is unique. That's why CyMaIS is designed to be flexible, with customizable options to fit your specific requirements, whether you're a start-up, a growing business, or an established enterprise.
### Install locally 💻
1. **Install Infinito.Nexus** via [Kevin's Package Manager](https://github.com/kevinveenbirkenbach/package-manager)
2. **Setup Infinito.Nexus** using:
```sh
pkgmgr install infinito
```
3. **Explore Commands** with:
```sh
infinito --help
```
---
4. **Stay Ahead with Proactive Monitoring**: Our tool doesn't just set up your IT infrastructure; it keeps it running smoothly. With automated updates and proactive monitoring, you can rest assured that your systems are always up-to-date and performing optimally.
### Setup with Docker🚢
5. **Uncompromised Security and Reliability**: Protecting your data is our top priority. CyMaIS comes with robust security features and comprehensive backup solutions, giving you peace of mind that your business's sensitive information is safe and secure.
Get Infinito.Nexus up and running inside Docker in just a few steps. For detailed build options and troubleshooting, see the [Docker Guide](docs/Docker.md).
6. **User-Friendly with Expert Support**: While familiarity with Docker, Linux, and Ansible enhances your experience with CyMaIS, it's not a requirement. Our comprehensive roles for servers and end-user PCs simplify the setup process. With these intuitive tools and our detailed guides, managing your IT infrastructure becomes more accessible, even if you're not a seasoned IT professional. Plus, our support team is always ready to assist you, bridging any knowledge gaps and ensuring a smooth operation of your systems.
```bash
# 1. Build the Docker image: the Docker image:
docker build -t infinito:latest .
7. **Open Source Trust and Transparency**: With CyMaIS, you benefit from the reliability and security of open-source software. Our tool is transparent, community-driven, and aligned with the highest standards of software ethics and security.
# 2. Run the CLI interactively:
docker run --rm -it infinito:latest infinito --help
```
CyMaIS is more than just an IT solution; it's a commitment to empowering your business with the technology it needs to thrive in todays digital landscape, effortlessly and securely.
---
## Professional CyMaIS Implementation
<img src="https://cybermaster.space/wp-content/uploads/sites/7/2023/11/FVG_8364BW-scaled.jpg" width="300" style="float: right; margin-left: 30px;">
## License ⚖️
My name is Kevin Veen-Birkenbach and I'm glad to assist you in the implementation of your secure and scalable IT infrastrucutre solution with CyMaIS.
Infinito.Nexus is distributed under the **Infinito.Nexus NonCommercial License**. Please see [LICENSE.md](LICENSE.md) for full terms.
My expertise in server administration, digital corporate infrastructure, custom software, and information security, all underpinned by a commitment to Open Source solutions, guarantees that your IT setup meets the highest industry standards.
---
Discover how CyMaIS can transform your IT landscape.
## Professional Setup & Support 💼
Contact me for more details:
🌍 Website: [www.CyberMaster.Space](https://cybermaster.space)<br />
📧 Email: [kevin@veen.world](mailto:kevin@veen.world)<br />
☎️ Phone: [+ 49 178 179 80 23](tel:00491781798023)
## Showcases
The following list showcases the extensive range of solutions that CyMaIS incorporates, each playing a vital role in providing a comprehensive, efficient, and secure IT infrastructure setup:
[ELK Stack](./roles/docker-elk), [Intel Driver](./roles/driver-intel), [Nginx Docker Reverse Proxy](./roles/nginx-docker-reverse-proxy), [Sudo](./roles/sudo), [Funkwhale](./roles/docker-funkwhale), [MSI Keyboard Color Driver](./roles/driver-msi-keyboard-color), [Nginx Domain Redirect](./roles/nginx-domain-redirect), [GnuCash](./roles/pc-gnucash), [Backup Data to USB](./roles/backup-data-to-usb), [Gitea](./roles/docker-gitea), [Non-Free Driver](./roles/driver-non-free), [Nginx Homepage](./roles/nginx-static-repository), [Jrnl](./roles/pc-jrnl), [Systemd Notifier](./roles/systemd-notifier), [Backup Docker to Local](./roles/backup-docker-to-local), [Jenkins](./roles/docker-jenkins), [Git](./roles/git), [Nginx HTTPS](./roles/nginx-https), [Latex](./roles/pc-latex), [Email Notifier](./roles/systemd-notifier-email), [Remote to Local Backup Solution](./roles/backup-remote-to-local), [Joomla](./roles/docker-joomla), [Heal Defect Docker Installations](./roles/heal-docker), [Nginx Matomo Tracking](./roles/nginx-matomo-tracking), [LibreOffice](./roles/pc-libreoffice), [Telegram Notifier](./roles/systemd-notifier-telegram), [Listmonk](./roles/docker-listmonk), [Btrfs Health Check](./roles/health-btrfs), [Nginx WWW Redirect](./roles/nginx-www-redirect), [Network Analyze Tools](./roles/pc-network-analyze-tools), [System Security](./roles/system-security), [Mailu](./roles/docker-mailu), [Disc Space Health Check](./roles/health-disc-space), [Administrator Tools](./roles/pc-administrator-tools), [Nextcloud Client](./roles/pc-nextcloud), [Swapfile Setup](./roles/system-swapfile), [Backups Cleanup](./roles/cleanup-backups-service), [Mastodon](./roles/docker-mastodon), [Docker Container Health Checker](./roles/health-docker-container), [Blu-ray Player Tools](./roles/pc-bluray-player-tools), [Office](./roles/pc-office), [Update Solutions](./roles/update), [Matomo](./roles/docker-matomo), [Docker Volumes Health Checker](./roles/health-docker-volumes), [Caffeine](./roles/pc-caffeine), [Qbittorrent](./roles/pc-qbittorrent), [Update Apt](./roles/update-apt), [Disc Space Cleanup](./roles/cleanup-disc-space), [Matrix](./roles/docker-matrix), [Health Journalctl](./roles/health-journalctl), [Designer Tools](./roles/pc-designer-tools), [Security Tools](./roles/pc-security-tools), [Update Docker](./roles/update-docker), [Failed Docker Backups Cleanup](./roles/cleanup-failed-docker-backups), [MediaWiki](./roles/docker-mediawiki), [Nginx Health Checker](./roles/health-nginx), [Developer Tools](./roles/pc-developer-tools), [Spotify](./roles/pc-spotify), [Update Pacman](./roles/update-pacman), [Client Wireguard](./roles/client-wireguard), [MyBB](./roles/docker-mybb), [Developer Tools for Arduino](./roles/pc-developer-tools-arduino), [SSH](./roles/pc-ssh), [Update Yay](./roles/update-yay), [Client Setup for Wireguard Behind Firewall](./roles/client-wireguard-behind-firewall), [Nextcloud Server](./roles/docker-nextcloud), [Hunspell](./roles/hunspell), [Developer Tools for Bash](./roles/pc-developer-tools-bash), [Streaming Tools](./roles/pc-streaming-tools), [Administrator](./roles/user-administrator), [Docker](./roles/docker), [Peertube](./roles/docker-peertube), [Java](./roles/java), [Developer Tools for Java](./roles/pc-developer-tools-java), [Tor Browser](./roles/pc-torbrowser), [Video Conference](./roles/pc-video-conference), [Wireguard](./roles/wireguard), [Akaunting](./roles/docker-akaunting), [Pixelfed](./roles/docker-pixelfed), [Journalctl](./roles/journalctl), [Developer Tools for PHP](./roles/pc-developer-tools-php), [Virtual Box](./roles/pc-virtual-box), [Postfix](./roles/postfix), [Attendize](./roles/docker-attendize), [Wordpress](./roles/docker-wordpress), [Locales](./roles/locales), [Docker for End Users](./roles/pc-docker), [Games](./roles/pc-games), [Python Pip](./roles/python-pip), [Discourse](./roles/docker-discourse), [Epson Multiprinter Driver](./roles/driver-epson-multiprinter), [Nginx Certbot](./roles/nginx-certbot), [Git](./roles/pc-git), [SSHD](./roles/sshd), [YOURLS](./roles/docker-yourls), [BigBlueButton](./roles/docker-bigbluebutton),[System Maintenance Lock](./roles/system-maintenance-lock),[Open Project](./roles/docker-openproject)...
## License
This project is licensed from Kevin Veen-Birkenbach. The full license is available in the [LICENSE.md](./LICENSE.md) of this repository.
For expert installation and configuration visit [cybermaster.space](https://cybermaster.space/) or write to us at **[contact@cymais.cloud](mailto:contact@cymais.cloud)**.

View File

@@ -1,96 +0,0 @@
# Server Applications
Server applications encompass a wide array of functionalities designed to enhance the performance, reliability, and usability of server infrastructures. These applications are essential for maintaining server health, managing web services, facilitating containerization, and providing various tools for specific server needs.
## Common Applications
For a detailed overview of the broad spectrum of server applications, including base setup, administration tools, update mechanisms, driver installations, security enhancements, VPN configurations, notifier services, backup solutions, and other essential tools and systems, please refer to the **[COMMON_APPLICATIONS.md](./COMMON_APPLICATIONS.md)**. This document provides insights into categories and specific roles catered to both server and end-user environments, ensuring comprehensive server management and optimization.
## Server Health
Addresses server maintenance and health monitoring, ensuring optimal performance and reliability of the server infrastructure.
- **[Health Btrfs](./roles/health-btrfs/)**: Monitors the health of Btrfs filesystems.
- **[Health Disc Space](./roles/health-disc-space/)**: Checks for available disk space.
- **[Health Docker Container](./roles/health-docker-container/)**: Monitors the health of Docker containers.
- **[Health Docker Volumes](./roles/health-docker-volumes/)**: Checks the status of Docker volumes.
- **[Health Journalctl](./roles/health-journalctl/)**: Monitors and manages the system journal.
- **[Health Nginx](./roles/health-nginx/)**: Ensures the Nginx server is running smoothly.
- **[Heal Docker](./roles/heal-docker/)**: Automated healing and maintenance tasks for Docker.
## Webserver
Focuses on web server roles and applications, covering SSL certificates, Nginx configurations, reverse proxies, and email services.
- **[Letsencrypt](./roles/letsencrypt/)**: Configures Let's Encrypt for SSL certificates.
- **[Nginx](./roles/nginx/)**: Installs and configures Nginx web server.
- **[Nginx-Docker-Reverse-Proxy](./roles/nginx-docker-reverse-proxy/)**: Sets up a reverse proxy for Docker containers.
- **[nginx-static-repository](./roles/nginx-static-repository/)**: Configures a homepage for Nginx.
- **[Nginx-Https](./roles/nginx-https/)**: Enables HTTPS configuration for Nginx.
- **[Nginx-Matomo-Tracking](./roles/nginx-matomo-tracking/)**: Integrates Matomo tracking with Nginx.
- **[Nginx-Domain-Redirect](./roles/nginx-domain-redirect/)**: Manages URL redirects in Nginx.
- **[Nginx-WWW-Redirect](./roles/nginx-www-redirect/)**: Redirects all domains with the prefix www. from www.domain.tld to domain.tld
- **[Nginx-Certbot](./roles/nginx-certbot/)**: Integrates Certbot with Nginx for SSL certificates.
- **[Postfix](./roles/postfix/)**: Setup for the Postfix mail transfer agent.
## Docker and Containerization
Dedicated to Docker container setups and application management, offering a wide array of software deployment options.
- **[Docker](./roles/docker/)**: Basic Docker and Docker Compose setup.
### Finance and Project Management
Facilitating the deployment of finance-related and project management applications.
- **[Docker Akaunting](./roles/docker-akaunting/)**: Deployment of the Akaunting finance software.
- **[Open Project](./roles/docker-openproject)**: Project Management Software
- **[Taiga](./roles/docker-taiga)**: Scrum and Kanban Software
### Continues Integration and Continues Delivery
Setups for development platforms and version control systems.
- **[Gitea](./roles/docker-gitea/)**: Setup for the Gitea git server.
- **[Jenkins](./roles/docker-jenkins/)**: Jenkins automation server setup.
- **[ELK](./roles/docker-elk/)**: Elasticsearch, Logstash, and Kibana (ELK) stack setup.
### Content Management
Deployment of various content management systems for web platforms.
- **[Wordpress](./roles/docker-wordpress/)**: Wordpress blog and website platform setup.
- **[Joomla](./roles/docker-joomla/)**: Joomla content management system setup.
### Fediverse Networks
Implementing federated and decentralized social platforms.
- **[Funkwhale](./roles/docker-funkwhale/)**: Deployment of Funkwhale, a federated music streaming server.
- **[Mastodon](./roles/docker-mastodon/)**: Deployment of the Mastodon social network server.
- **[Peertube](./roles/docker-peertube/)**: Deployment of the PeerTube video platform.
- **[Pixelfed](./roles/docker-pixelfed/)**: Pixelfed, a federated image sharing platform, setup.
### Analytics Solutions
Tools for web and data analytics.
- **[Matomo](./roles/docker-matomo/)**: Setup for Matomo, an open-source analytics platform.
### Forum Software
Deployments for community-driven forum platforms.
- **[MyBB](./roles/docker-mybb/)**: Setup for MyBB forum software.
- **[Discourse](./roles/docker-discourse/)**: Setup of Discouse a forum and community platform.
### Wiki and Documentation
Setting up platforms for collaborative information sharing.
- **[MediaWiki](./roles/docker-mediawiki/)**: MediaWiki setup for creating wikis.
### Event and Shop Management
Tools for managing events and online retail.
- **[Attendize](./roles/docker-attendize/)**: Setup for the Attendize event management tool.
### Data and Cloud Storage
Solutions for data management and cloud-based storage.
- **[Baserow](./roles/docker-baserow/)**: Deployment of Baserow, an open-source no-code database tool.
- **[Nextcloud](./roles/docker-nextcloud/)**: Cloud storage solution setup.
### Communication and Collaboration
Platffor enhancing communication and collaborative efforts.
- **[BigBlueButton](./roles/docker-bigbluebutton/)**: Setup for the BigBlueButton video conferencing tool.
- **[Mailu](./roles/docker-mailu/)**: Complete mail server solution.
- **[Matrix](./roles/docker-matrix/)**: Setup and deployment of the Matrix server for secure, decentralized communication.
### Marketing and Communication Tools
Focusing on tools that assist in communication, marketing, and outreach efforts.
- **[Listmonk](./roles/docker-listmonk/)**: Setup for Listmonk, a self-hosted newsletter and mailing list manager.
### Web Utilities and Services
Encompassing tools that enhance web functionality or provide essential web services.
- **[YOURLS](./roles/docker-yourls/)**: Setup for YOURLS, a URL shortening service.
### Miscellaneous
Diverse tools for specific needs and utilities.
- **[Roulette Wheel](./roles/docker-roulette-wheel/)**: Setup for a custom roulette wheel application.

5
TODO.md Normal file
View File

@@ -0,0 +1,5 @@
# Todos
- Implement multi language
- Implement rbac administration interface
- Implement ``MASK_CREDENTIALS_IN_LOGS`` for all sensible tasks
- [Enable IP6 for docker](https://chatgpt.com/share/68a0acb8-db20-800f-9d2c-b34e38b5cdee).

View File

@@ -1,17 +0,0 @@
# Vision Statement
At the heart of our endeavor lies the creation of an unparalleled tool, designed to revolutionize the way IT infrastructure is deployed and managed in businesses of all scales and across various industries. Our vision is to develop a fully automated solution capable of establishing a 100% secure and infinitely scalable corporate IT infrastructure.
This tool, grounded firmly in Open Source principles, will not only champion transparency and innovation but also ensure adaptability and accessibility for every business, regardless of its size or industry. We aim to make the complex process of IT setup not just simpler but also faster achieving full deployment within an audacious timeframe of 24 hours.
We envision a future where businesses are no longer constrained by the complexities of IT infrastructure setup. Instead, they will be empowered with a tool that seamlessly integrates into their operational fabric, offering a robust, secure, and scalable digital backbone. This tool will not only cater to the immediate IT needs of a company but also be agile enough to evolve with their growing demands and the ever-changing technological landscape.
Our commitment is to break down barriers to advanced IT infrastructure, democratizing access to high-level technology solutions. By harnessing the power of Open Source, our solution will not only uphold the highest standards of security and scalability but also foster a community-driven approach to continuous improvement and innovation.
In essence, our vision is to redefine the paradigm of IT infrastructure deployment, making it a swift, secure, and scalable journey for every business, and setting a new benchmark in the industry for efficiency and reliability.
---
Kevin Veen-Birkenbach
Berlin
2023-12-13

0
__init__.py Normal file
View File

33
ansible.cfg Normal file
View File

@@ -0,0 +1,33 @@
[defaults]
# --- Performance & Behavior ---
forks = 25
strategy = linear
gathering = smart
timeout = 120
retry_files_enabled = False
host_key_checking = True
deprecation_warnings = True
interpreter_python = auto_silent
# --- Output & Profiling ---
stdout_callback = yaml
callbacks_enabled = profile_tasks,timer
# --- Plugin paths ---
filter_plugins = ./filter_plugins
lookup_plugins = ./lookup_plugins
module_utils = ./module_utils
[ssh_connection]
# Multiplexing: safer socket path in HOME instead of /tmp
ssh_args = -o ControlMaster=auto -o ControlPersist=20s -o ControlPath=~/.ssh/ansible-%h-%p-%r \
-o ServerAliveInterval=15 -o ServerAliveCountMax=3 -o StrictHostKeyChecking=accept-new \
-o PreferredAuthentications=publickey,password,keyboard-interactive
# Pipelining boosts speed; works fine if sudoers does not enforce "requiretty"
pipelining = True
scp_if_ssh = smart
[persistent_connection]
connect_timeout = 30
command_timeout = 60

BIN
assets/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

BIN
assets/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1015 KiB

3
cli/TODO.md Normal file
View File

@@ -0,0 +1,3 @@
# Todo
- Test this script. It's just a draft. Checkout https://chatgpt.com/c/681d9e2b-7b28-800f-aef8-4f1427e9021d
- Solve bugs in show_vault_variables.py

0
cli/__init__.py Normal file
View File

0
cli/build/__init__.py Normal file
View File

View File

View File

@@ -0,0 +1,110 @@
#!/usr/bin/env python3
import argparse
import yaml
import sys
import time
from pathlib import Path
# Ensure project root on PYTHONPATH so module_utils is importable
repo_root = Path(__file__).resolve().parent.parent.parent.parent
sys.path.insert(0, str(repo_root))
# Add lookup_plugins for application_gid
plugin_path = repo_root / "lookup_plugins"
sys.path.insert(0, str(plugin_path))
from module_utils.dict_renderer import DictRenderer
from application_gid import LookupModule
def load_yaml_file(path: Path) -> dict:
if not path.exists():
return {}
with path.open("r", encoding="utf-8") as f:
return yaml.safe_load(f) or {}
class DefaultsGenerator:
def __init__(self, roles_dir: Path, output_file: Path, verbose: bool, timeout: float):
self.roles_dir = roles_dir
self.output_file = output_file
self.verbose = verbose
self.renderer = DictRenderer(verbose=verbose, timeout=timeout)
self.gid_lookup = LookupModule()
def log(self, message: str):
if self.verbose:
print(f"[DefaultsGenerator] {message}")
def run(self):
result = {"defaults_applications": {}}
for role_dir in sorted(self.roles_dir.iterdir()):
role_name = role_dir.name
vars_main = role_dir / "vars" / "main.yml"
config_file = role_dir / "config" / "main.yml"
if not vars_main.exists():
self.log(f"Skipping {role_name}: vars/main.yml missing")
continue
vars_data = load_yaml_file(vars_main)
application_id = vars_data.get("application_id")
if not application_id:
self.log(f"Skipping {role_name}: application_id not defined")
continue
if not config_file.exists():
self.log(f"Config missing for {role_name}, adding empty defaults for '{application_id}'")
result["defaults_applications"][application_id] = {}
continue
config_data = load_yaml_file(config_file)
if config_data:
try:
gid_number = self.gid_lookup.run([application_id], roles_dir=str(self.roles_dir))[0]
except Exception as e:
print(f"Warning: failed to determine gid for '{application_id}': {e}", file=sys.stderr)
sys.exit(1)
config_data["group_id"] = gid_number
result["defaults_applications"][application_id] = config_data
# Inject users mapping as Jinja2 references
users_meta = load_yaml_file(role_dir / "users" / "main.yml")
users_data = users_meta.get("users", {})
transformed = {user: f"{{{{ users[\"{user}\"] }}}}" for user in users_data}
if transformed:
result["defaults_applications"][application_id]["users"] = transformed
# Render placeholders in entire result context
self.log("Starting placeholder rendering...")
try:
result = self.renderer.render(result)
except Exception as e:
print(f"Error during rendering: {e}", file=sys.stderr)
sys.exit(1)
# Write output
self.output_file.parent.mkdir(parents=True, exist_ok=True)
with self.output_file.open("w", encoding="utf-8") as f:
yaml.dump(result, f, sort_keys=False)
# Print location of generated file (absolute if not under cwd)
try:
rel = self.output_file.relative_to(Path.cwd())
except ValueError:
rel = self.output_file
print(f"✅ Generated: {rel}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Generate defaults_applications YAML...")
parser.add_argument("--roles-dir", default="roles", help="Path to the roles directory")
parser.add_argument("--output-file", required=True, help="Path to output YAML file")
parser.add_argument("--verbose", action="store_true", help="Enable verbose logging")
parser.add_argument("--timeout", type=float, default=10.0, help="Timeout for rendering")
args = parser.parse_args()
cwd = Path.cwd()
roles_dir = (cwd / args.roles_dir).resolve()
output_file = (cwd / args.output_file).resolve()
DefaultsGenerator(roles_dir, output_file, args.verbose, args.timeout).run()

241
cli/build/defaults/users.py Normal file
View File

@@ -0,0 +1,241 @@
#!/usr/bin/env python3
import os
import sys
import argparse
import yaml
import glob
from collections import OrderedDict
def represent_str(dumper, data):
"""
Custom YAML string representer that forces double quotes around any string
containing a Jinja2 placeholder ({{ ... }}).
"""
if isinstance(data, str) and '{{' in data:
return dumper.represent_scalar(
'tag:yaml.org,2002:str',
data,
style='"'
)
return dumper.represent_scalar(
'tag:yaml.org,2002:str',
data
)
def build_users(defs, primary_domain, start_id, become_pwd):
"""
Construct user entries with auto-incremented UID/GID, default username/email,
and optional description.
Args:
defs (OrderedDict): Mapping of user keys to their override settings.
primary_domain (str): The primary domain for email addresses (e.g. 'example.com').
start_id (int): Starting number for UID/GID allocation (e.g. 1001).
become_pwd (str): Default password string for users without an override.
Returns:
OrderedDict: Complete user definitions with all required fields filled in.
Raises:
ValueError: If there are duplicate UIDs, usernames, or emails.
"""
users = OrderedDict()
used_uids = set()
# Collect any preset UIDs to avoid collisions
for key, overrides in defs.items():
if 'uid' in overrides:
uid = overrides['uid']
if uid in used_uids:
raise ValueError(f"Duplicate uid {uid} for user '{key}'")
used_uids.add(uid)
next_uid = start_id
def allocate_uid():
nonlocal next_uid
# Find the next free UID not already used
while next_uid in used_uids:
next_uid += 1
free_uid = next_uid
used_uids.add(free_uid)
next_uid += 1
return free_uid
# Build each user entry
for key, overrides in defs.items():
username = overrides.get('username', key)
email = overrides.get('email', f"{username}@{primary_domain}")
description = overrides.get('description')
roles = overrides.get('roles', [])
password = overrides.get('password', become_pwd)
# Determine UID and GID
if 'uid' in overrides:
uid = overrides['uid']
else:
uid = allocate_uid()
gid = overrides.get('gid', uid)
entry = {
'username': username,
'email': email,
'password': password,
'uid': uid,
'gid': gid,
'roles': roles
}
if description is not None:
entry['description'] = description
users[key] = entry
# Ensure uniqueness of usernames and emails
seen_usernames = set()
seen_emails = set()
for key, entry in users.items():
un = entry['username']
em = entry['email']
if un in seen_usernames:
raise ValueError(f"Duplicate username '{un}' in merged users")
if em in seen_emails:
raise ValueError(f"Duplicate email '{em}' in merged users")
seen_usernames.add(un)
seen_emails.add(em)
return users
def load_user_defs(roles_directory):
"""
Scan all roles/*/users/main.yml files and merge any 'users:' sections.
Args:
roles_directory (str): Path to the directory containing role subdirectories.
Returns:
OrderedDict: Merged user definitions from all roles.
Raises:
ValueError: On invalid format or conflicting override values.
"""
pattern = os.path.join(roles_directory, '*/users/main.yml')
files = sorted(glob.glob(pattern))
merged = OrderedDict()
for filepath in files:
with open(filepath, 'r') as f:
data = yaml.safe_load(f) or {}
users = data.get('users', {})
if not isinstance(users, dict):
continue
for key, overrides in users.items():
if not isinstance(overrides, dict):
raise ValueError(f"Invalid definition for user '{key}' in {filepath}")
if key not in merged:
merged[key] = overrides.copy()
else:
existing = merged[key]
for field, value in overrides.items():
if field in existing and existing[field] != value:
raise ValueError(
f"Conflict for user '{key}': field '{field}' has existing value '{existing[field]}', tried to set '{value}' in {filepath}"
)
existing.update(overrides)
return merged
def dictify(data):
"""
Recursively convert OrderedDict to regular dict for YAML dumping.
"""
if isinstance(data, OrderedDict):
return {k: dictify(v) for k, v in data.items()}
if isinstance(data, dict):
return {k: dictify(v) for k, v in data.items()}
if isinstance(data, list):
return [dictify(v) for v in data]
return data
def parse_args():
parser = argparse.ArgumentParser(
description='Generate a users.yml by merging all roles/*/users/main.yml definitions.'
)
parser.add_argument(
'--roles-dir', '-r', required=True,
help='Directory containing roles (e.g., roles/*/users/main.yml).'
)
parser.add_argument(
'--output', '-o', required=True,
help='Path to the output YAML file (e.g., users.yml).'
)
parser.add_argument(
'--start-id', '-s', type=int, default=1001,
help='Starting UID/GID number (default: 1001).'
)
parser.add_argument(
'--extra-users', '-e',
help='Comma-separated list of additional usernames to include.',
default=None
)
return parser.parse_args()
def main():
args = parse_args()
primary_domain = '{{ SYSTEM_EMAIL.DOMAIN }}'
become_pwd = '{{ lookup("password", "/dev/null length=42 chars=ascii_letters,digits") }}'
try:
definitions = load_user_defs(args.roles_dir)
except ValueError as e:
print(f"Error merging user definitions: {e}", file=sys.stderr)
sys.exit(1)
# Add extra users if specified
if args.extra_users:
for name in args.extra_users.split(','):
user_key = name.strip()
if not user_key:
continue
if user_key in definitions:
print(f"Warning: extra user '{user_key}' already defined; skipping.", file=sys.stderr)
else:
definitions[user_key] = {}
try:
users = build_users(
definitions,
primary_domain,
args.start_id,
become_pwd
)
except ValueError as e:
print(f"Error building user entries: {e}", file=sys.stderr)
sys.exit(1)
# Convert OrderedDict into plain dict for YAML
default_users = {'default_users': users}
plain_data = dictify(default_users)
# Register custom string representer
yaml.SafeDumper.add_representer(str, represent_str)
# Dump the YAML file
with open(args.output, 'w') as f:
yaml.safe_dump(
plain_data,
f,
default_flow_style=False,
sort_keys=False,
width=120
)
if __name__ == '__main__':
main()

173
cli/build/graph.py Normal file
View File

@@ -0,0 +1,173 @@
#!/usr/bin/env python3
import os
import argparse
import yaml
import json
import re
from typing import List, Dict, Any, Set
JINJA_PATTERN = re.compile(r'{{.*}}')
ALL_DEP_TYPES = ['run_after', 'dependencies', 'include_tasks', 'import_tasks', 'include_role', 'import_role']
ALL_DIRECTIONS = ['to', 'from']
ALL_KEYS = [f"{dep}_{dir}" for dep in ALL_DEP_TYPES for dir in ALL_DIRECTIONS]
def find_role_meta(roles_dir: str, role: str) -> str:
path = os.path.join(roles_dir, role, 'meta', 'main.yml')
if not os.path.isfile(path):
raise FileNotFoundError(f"Metadata not found for role: {role}")
return path
def find_role_tasks(roles_dir: str, role: str) -> str:
path = os.path.join(roles_dir, role, 'tasks', 'main.yml')
if not os.path.isfile(path):
raise FileNotFoundError(f"Tasks not found for role: {role}")
return path
def load_meta(path: str) -> Dict[str, Any]:
with open(path, 'r') as f:
data = yaml.safe_load(f) or {}
galaxy_info = data.get('galaxy_info', {}) or {}
return {
'galaxy_info': galaxy_info,
'run_after': galaxy_info.get('run_after', []) or [],
'dependencies': data.get('dependencies', []) or []
}
def load_tasks(path: str, dep_type: str) -> List[str]:
with open(path, 'r') as f:
data = yaml.safe_load(f) or []
included_roles = []
for task in data:
if dep_type in task:
entry = task[dep_type]
if isinstance(entry, dict):
entry = entry.get('name', '')
if entry and not JINJA_PATTERN.search(entry):
included_roles.append(entry)
return included_roles
def build_single_graph(
start_role: str,
dep_type: str,
direction: str,
roles_dir: str,
max_depth: int
) -> Dict[str, Any]:
nodes: Dict[str, Dict[str, Any]] = {}
links: List[Dict[str, str]] = []
def traverse(role: str, depth: int, path: Set[str]):
if role not in nodes:
meta = load_meta(find_role_meta(roles_dir, role))
node = {'id': role}
node.update(meta['galaxy_info'])
node['doc_url'] = f"https://docs.infinito.nexus/roles/{role}/README.html"
node['source_url'] = f"https://s.infinito.nexus/code/tree/master/roles/{role}"
nodes[role] = node
if max_depth > 0 and depth >= max_depth:
return
neighbors = []
if dep_type in ['run_after', 'dependencies']:
meta = load_meta(find_role_meta(roles_dir, role))
neighbors = meta.get(dep_type, [])
else:
try:
neighbors = load_tasks(find_role_tasks(roles_dir, role), dep_type)
except FileNotFoundError:
neighbors = []
if direction == 'to':
for tgt in neighbors:
links.append({'source': role, 'target': tgt, 'type': dep_type})
if tgt in path:
continue
traverse(tgt, depth + 1, path | {tgt})
else: # direction == 'from'
for other in os.listdir(roles_dir):
try:
other_neighbors = []
if dep_type in ['run_after', 'dependencies']:
meta_o = load_meta(find_role_meta(roles_dir, other))
other_neighbors = meta_o.get(dep_type, [])
else:
other_neighbors = load_tasks(find_role_tasks(roles_dir, other), dep_type)
if role in other_neighbors:
links.append({'source': other, 'target': role, 'type': dep_type})
if other in path:
continue
traverse(other, depth + 1, path | {other})
except FileNotFoundError:
continue
traverse(start_role, depth=0, path={start_role})
return {'nodes': list(nodes.values()), 'links': links}
def build_mappings(
start_role: str,
roles_dir: str,
max_depth: int
) -> Dict[str, Any]:
result: Dict[str, Any] = {}
for key in ALL_KEYS:
dep_type, direction = key.rsplit('_', 1)
try:
result[key] = build_single_graph(start_role, dep_type, direction, roles_dir, max_depth)
except Exception:
result[key] = {'nodes': [], 'links': []}
return result
def output_graph(graph_data: Any, fmt: str, start: str, key: str):
base = f"{start}_{key}"
if fmt == 'console':
print(f"--- {base} ---")
print(yaml.safe_dump(graph_data, sort_keys=False))
elif fmt in ('yaml', 'json'):
path = f"{base}.{fmt}"
with open(path, 'w') as f:
if fmt == 'yaml':
yaml.safe_dump(graph_data, f, sort_keys=False)
else:
json.dump(graph_data, f, indent=2)
print(f"Wrote {path}")
else:
raise ValueError(f"Unknown format: {fmt}")
def main():
script_dir = os.path.dirname(os.path.abspath(__file__))
default_roles_dir = os.path.abspath(os.path.join(script_dir, '..', '..', 'roles'))
parser = argparse.ArgumentParser(description="Generate dependency graphs")
parser.add_argument('-r', '--role', required=True, help="Starting role name")
parser.add_argument('-D', '--depth', type=int, default=0, help="Max recursion depth")
parser.add_argument('-o', '--output', choices=['yaml', 'json', 'console'], default='console')
parser.add_argument('--roles-dir', default=default_roles_dir, help="Roles directory")
args = parser.parse_args()
graphs = build_mappings(args.role, args.roles_dir, args.depth)
for key in ALL_KEYS:
graph_data = graphs.get(key, {'nodes': [], 'links': []})
output_graph(graph_data, args.output, args.role, key)
if __name__ == '__main__':
main()

View File

127
cli/build/inventory/full.py Normal file
View File

@@ -0,0 +1,127 @@
#!/usr/bin/env python3
# cli/build/inventory/full.py
import argparse
import sys
import os
try:
from filter_plugins.get_all_invokable_apps import get_all_invokable_apps
except ImportError:
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')))
from filter_plugins.get_all_invokable_apps import get_all_invokable_apps
import yaml
import json
def build_group_inventory(apps, host):
"""
Build an Ansible inventory in which each application is a group containing the given host.
"""
groups = {app: {"hosts": [host]} for app in apps}
inventory = {
"all": {
"hosts": [host],
"children": {app: {} for app in apps},
},
**groups
}
return inventory
def build_hostvar_inventory(apps, host):
"""
Alternative: Build an inventory where all invokable apps are set as a host variable (as a list).
"""
return {
"all": {
"hosts": [host],
},
"_meta": {
"hostvars": {
host: {
"invokable_applications": apps
}
}
}
}
def main():
parser = argparse.ArgumentParser(
description='Build a dynamic Ansible inventory for a given host with all invokable applications.'
)
parser.add_argument(
'--host',
required=True,
help='Hostname to assign to all invokable application groups'
)
parser.add_argument(
'-f', '--format',
choices=['json', 'yaml'],
default='yaml',
help='Output format (yaml [default], json)'
)
parser.add_argument(
'--inventory-style',
choices=['group', 'hostvars'],
default='group',
help='Inventory style: group (default, one group per app) or hostvars (list as hostvar)'
)
parser.add_argument(
'-c', '--categories-file',
default=os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'roles', 'categories.yml')),
help='Path to roles/categories.yml (default: roles/categories.yml at project root)'
)
parser.add_argument(
'-r', '--roles-dir',
default=os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'roles')),
help='Path to roles/ directory (default: roles/ at project root)'
)
parser.add_argument(
'-o', '--output',
help='Write output to file instead of stdout'
)
parser.add_argument(
'-i', '--ignore',
action='append',
default=[],
help='Application ID(s) to ignore (can be specified multiple times or comma-separated)'
)
args = parser.parse_args()
try:
apps = get_all_invokable_apps(
categories_file=args.categories_file,
roles_dir=args.roles_dir
)
except Exception as e:
sys.stderr.write(f"Error: {e}\n")
sys.exit(1)
# Combine all ignore arguments into a flat set
ignore_ids = set()
for entry in args.ignore:
ignore_ids.update(i.strip() for i in entry.split(',') if i.strip())
if ignore_ids:
apps = [app for app in apps if app not in ignore_ids]
# Build the requested inventory style
if args.inventory_style == 'group':
inventory = build_group_inventory(apps, args.host)
else:
inventory = build_hostvar_inventory(apps, args.host)
# Output in the chosen format
if args.format == 'json':
output = json.dumps(inventory, indent=2)
else:
output = yaml.safe_dump(inventory, default_flow_style=False)
if args.output:
with open(args.output, 'w') as f:
f.write(output)
else:
print(output)
if __name__ == '__main__':
main()

224
cli/build/role_include.py Normal file
View File

@@ -0,0 +1,224 @@
#!/usr/bin/env python3
import os
import sys
import yaml
import argparse
from collections import defaultdict, deque
def find_roles(roles_dir, prefixes=None):
"""
Find all roles in the given directory whose names start with
any of the provided prefixes. If prefixes is empty or None,
include all roles.
"""
for entry in os.listdir(roles_dir):
if prefixes:
if not any(entry.startswith(pref) for pref in prefixes):
continue
path = os.path.join(roles_dir, entry)
meta_file = os.path.join(path, 'meta', 'main.yml')
if os.path.isdir(path) and os.path.isfile(meta_file):
yield path, meta_file
def load_run_after(meta_file):
"""Load the 'run_after' from the meta/main.yml of a role."""
with open(meta_file, 'r') as f:
data = yaml.safe_load(f) or {}
return data.get('galaxy_info', {}).get('run_after', [])
def load_application_id(role_path):
"""Load the application_id from the vars/main.yml of the role."""
vars_file = os.path.join(role_path, 'vars', 'main.yml')
if os.path.exists(vars_file):
with open(vars_file, 'r') as f:
data = yaml.safe_load(f) or {}
return data.get('application_id')
return None
def build_dependency_graph(roles_dir, prefixes=None):
"""
Build a dependency graph where each key is a role name and
its value is a list of roles that depend on it.
Also return in_degree counts and the roles metadata map.
"""
graph = defaultdict(list)
in_degree = defaultdict(int)
roles = {}
for role_path, meta_file in find_roles(roles_dir, prefixes):
run_after = load_run_after(meta_file)
application_id = load_application_id(role_path)
role_name = os.path.basename(role_path)
roles[role_name] = {
'role_name': role_name,
'run_after': run_after,
'application_id': application_id,
'path': role_path
}
for dependency in run_after:
graph[dependency].append(role_name)
in_degree[role_name] += 1
if role_name not in in_degree:
in_degree[role_name] = 0
return graph, in_degree, roles
def find_cycle(roles):
"""
Detect a cycle in the run_after relations:
roles: dict mapping role_name -> { 'run_after': [...], ... }
Returns a list of role_names forming the cycle (with the start repeated at end), or None.
"""
visited = set()
stack = set()
def dfs(node, path):
visited.add(node)
stack.add(node)
path.append(node)
for dep in roles.get(node, {}).get('run_after', []):
if dep not in visited:
res = dfs(dep, path)
if res:
return res
elif dep in stack:
idx = path.index(dep)
return path[idx:] + [dep]
stack.remove(node)
path.pop()
return None
for role in roles:
if role not in visited:
cycle = dfs(role, [])
if cycle:
return cycle
return None
def topological_sort(graph, in_degree, roles=None):
"""
Perform topological sort on the dependency graph.
If a cycle is detected, raise an Exception with detailed debug info.
"""
from collections import deque
queue = deque([r for r, d in in_degree.items() if d == 0])
sorted_roles = []
local_in = dict(in_degree)
while queue:
role = queue.popleft()
sorted_roles.append(role)
for nbr in graph.get(role, []):
local_in[nbr] -= 1
if local_in[nbr] == 0:
queue.append(nbr)
if len(sorted_roles) != len(in_degree):
# Something went wrong: likely a cycle
cycle = find_cycle(roles or {})
unsorted = [r for r in in_degree if r not in sorted_roles]
header = "❌ Dependency resolution failed"
if cycle:
reason = f"Circular dependency detected: {' -> '.join(cycle)}"
else:
reason = "Unresolved dependencies among roles (possible cycle or missing role)."
details = []
if unsorted:
details.append("Unsorted roles and their declared run_after dependencies:")
for r in unsorted:
deps = roles.get(r, {}).get('run_after', [])
details.append(f" - {r} depends on {deps!r}")
graph_repr = f"Full dependency graph: {dict(graph)!r}"
raise Exception("\n".join([header, reason] + details + [graph_repr]))
return sorted_roles
def print_dependency_tree(graph):
"""Print the dependency tree visually on the console."""
def print_node(role, indent=0):
print(" " * indent + role)
for dep in graph.get(role, []):
print_node(dep, indent + 1)
all_roles = set(graph.keys())
dependent = {r for deps in graph.values() for r in deps}
roots = all_roles - dependent
for root in roots:
print_node(root)
def gen_condi_role_incl(roles_dir, prefixes=None):
"""
Generate playbook entries based on the sorted order.
Raises a ValueError if application_id is missing.
"""
graph, in_degree, roles = build_dependency_graph(roles_dir, prefixes)
sorted_names = topological_sort(graph, in_degree, roles)
entries = []
for role_name in sorted_names:
role = roles[role_name]
if role.get('application_id') is None:
vars_file = os.path.join(role['path'], 'vars', 'main.yml')
raise ValueError(f"'application_id' missing in {vars_file}")
app_id = role['application_id']
entries.append(
f"- name: setup {app_id}\n"
f" when: ('{app_id}' | application_allowed(group_names, allowed_applications))\n"
f" include_role:\n"
f" name: {role_name}\n"
)
entries.append(
f"- name: flush handlers after {app_id}\n"
f" meta: flush_handlers\n"
)
return entries
def main():
parser = argparse.ArgumentParser(
description='Generate an Ansible playbook include file from Docker roles, sorted by run_after order.'
)
parser.add_argument('roles_dir', help='Path to directory containing role folders')
parser.add_argument(
'-p', '--prefix',
action='append',
help='Only include roles whose names start with any of these prefixes; can be specified multiple times'
)
parser.add_argument('-o', '--output', default=None,
help='Output file path (default: stdout)')
parser.add_argument('-t', '--tree', action='store_true',
help='Display the dependency tree of roles and exit')
args = parser.parse_args()
prefixes = args.prefix or []
if args.tree:
graph, _, _ = build_dependency_graph(args.roles_dir, prefixes)
print_dependency_tree(graph)
sys.exit(0)
entries = gen_condi_role_incl(args.roles_dir, prefixes)
output = ''.join(entries)
if args.output:
os.makedirs(os.path.dirname(args.output), exist_ok=True)
with open(args.output, 'w') as f:
f.write(output)
print(f"Playbook entries written to {args.output}")
else:
print(output)
if __name__ == '__main__':
main()

65
cli/build/roles_list.py Normal file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""
Generate a JSON file listing all Ansible role directories.
Usage:
python roles_list.py [--roles-dir path/to/roles] [--output path/to/roles/list.json | console]
"""
import os
import json
import argparse
def find_roles(roles_dir: str):
"""Return sorted list of role names under roles_dir."""
return sorted([
entry for entry in os.listdir(roles_dir)
if os.path.isdir(os.path.join(roles_dir, entry))
])
def write_roles_list(roles, out_file):
"""Write the list of roles to out_file as JSON."""
os.makedirs(os.path.dirname(out_file), exist_ok=True)
with open(out_file, 'w', encoding='utf-8') as f:
json.dump(roles, f, indent=2)
print(f"Wrote roles list to {out_file}")
def main():
# Determine default roles_dir relative to this script: ../../.. -> roles
script_dir = os.path.dirname(os.path.abspath(__file__))
default_roles_dir = os.path.abspath(
os.path.join(script_dir, '..', '..', 'roles')
)
default_output = os.path.join(default_roles_dir, 'list.json')
parser = argparse.ArgumentParser(description='Generate roles/list.json')
parser.add_argument(
'--roles-dir', '-r',
default=default_roles_dir,
help=f'Directory containing role subfolders (default: {default_roles_dir})'
)
parser.add_argument(
'--output', '-o',
default=default_output,
help=(
'Output path for roles list JSON '
'(or "console" to print to stdout, default: %(default)s)'
)
)
args = parser.parse_args()
if not os.path.isdir(args.roles_dir):
parser.error(f"Roles directory not found: {args.roles_dir}")
roles = find_roles(args.roles_dir)
if args.output.lower() == 'console':
# Print JSON to stdout
print(json.dumps(roles, indent=2))
else:
write_roles_list(roles, args.output)
if __name__ == '__main__':
main()

104
cli/build/tree.py Normal file
View File

@@ -0,0 +1,104 @@
#!/usr/bin/env python3
import os
import argparse
import json
from typing import Dict, Any
from cli.build.graph import build_mappings, output_graph
from module_utils.role_dependency_resolver import RoleDependencyResolver
def find_roles(roles_dir: str):
for entry in os.listdir(roles_dir):
path = os.path.join(roles_dir, entry)
if os.path.isdir(path):
yield entry, path
def main():
script_dir = os.path.dirname(os.path.abspath(__file__))
default_roles_dir = os.path.abspath(os.path.join(script_dir, "..", "..", "roles"))
parser = argparse.ArgumentParser(
description="Generate all graphs for each role and write meta/tree.json"
)
parser.add_argument("-d", "--role_dir", default=default_roles_dir,
help=f"Path to roles directory (default: {default_roles_dir})")
parser.add_argument("-D", "--depth", type=int, default=0,
help="Max recursion depth (>0) or <=0 to stop on cycle")
parser.add_argument("-o", "--output", choices=["yaml", "json", "console"],
default="json", help="Output format")
parser.add_argument("-p", "--preview", action="store_true",
help="Preview graphs to console instead of writing files")
parser.add_argument("-s", "--shadow-folder", type=str, default=None,
help="If set, writes tree.json to this shadow folder instead of the role's actual meta/ folder")
parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose logging")
# Toggles
parser.add_argument("--no-include-role", action="store_true", help="Do not scan include_role")
parser.add_argument("--no-import-role", action="store_true", help="Do not scan import_role")
parser.add_argument("--no-dependencies", action="store_true", help="Do not read meta/main.yml dependencies")
parser.add_argument("--no-run-after", action="store_true",
help="Do not read galaxy_info.run_after from meta/main.yml")
args = parser.parse_args()
if args.verbose:
print(f"Roles directory: {args.role_dir}")
print(f"Max depth: {args.depth}")
print(f"Output format: {args.output}")
print(f"Preview mode: {args.preview}")
print(f"Shadow folder: {args.shadow_folder}")
resolver = RoleDependencyResolver(args.role_dir)
for role_name, role_path in find_roles(args.role_dir):
if args.verbose:
print(f"Processing role: {role_name}")
graphs: Dict[str, Any] = build_mappings(
start_role=role_name,
roles_dir=args.role_dir,
max_depth=args.depth
)
# Direct deps (depth=1) getrennt erfasst für buckets
inc_roles, imp_roles = resolver._scan_tasks(role_path)
meta_deps = resolver._extract_meta_dependencies(role_path)
run_after = set()
if not args.no_run_after:
run_after = resolver._extract_meta_run_after(role_path)
if any([not args.no_include_role and inc_roles,
not args.no_import_role and imp_roles,
not args.no_dependencies and meta_deps,
not args.no_run_after and run_after]):
deps_root = graphs.setdefault("dependencies", {})
if not args.no_include_role and inc_roles:
deps_root["include_role"] = sorted(inc_roles)
if not args.no_import_role and imp_roles:
deps_root["import_role"] = sorted(imp_roles)
if not args.no_dependencies and meta_deps:
deps_root["dependencies"] = sorted(meta_deps)
if not args.no_run_after and run_after:
deps_root["run_after"] = sorted(run_after)
graphs["dependencies"] = deps_root
if args.preview:
for key, data in graphs.items():
if args.verbose:
print(f"Previewing graph '{key}' for role '{role_name}'")
output_graph(data, "console", role_name, key)
else:
if args.shadow_folder:
tree_file = os.path.join(args.shadow_folder, role_name, "meta", "tree.json")
else:
tree_file = os.path.join(role_path, "meta", "tree.json")
os.makedirs(os.path.dirname(tree_file), exist_ok=True)
with open(tree_file, "w", encoding="utf-8") as f:
json.dump(graphs, f, indent=2)
print(f"Wrote {tree_file}")
if __name__ == "__main__":
main()

0
cli/create/__init__.py Normal file
View File

240
cli/create/credentials.py Normal file
View File

@@ -0,0 +1,240 @@
#!/usr/bin/env python3
"""
Selectively add & vault NEW credentials in your inventory, preserving comments
and formatting. Existing values are left untouched unless --force is used.
Usage example:
infinito create credentials \
--role-path roles/web-app-akaunting \
--inventory-file host_vars/echoserver.yml \
--vault-password-file .pass/echoserver.txt \
--set credentials.database_password=mysecret
"""
import argparse
import sys
from pathlib import Path
from typing import Dict, Any, Union
from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedMap
from module_utils.manager.inventory import InventoryManager
from module_utils.handler.vault import VaultHandler # uses your existing handler
# ---------- helpers ----------
def ask_for_confirmation(key: str) -> bool:
"""Prompt the user for confirmation to overwrite an existing value."""
confirmation = input(
f"Are you sure you want to overwrite the value for '{key}'? (y/n): "
).strip().lower()
return confirmation == 'y'
def ensure_map(node: CommentedMap, key: str) -> CommentedMap:
"""
Ensure node[key] exists and is a mapping (CommentedMap) for round-trip safety.
"""
if key not in node or not isinstance(node.get(key), CommentedMap):
node[key] = CommentedMap()
return node[key]
def _is_ruamel_vault(val: Any) -> bool:
"""Detect if a ruamel scalar already carries the !vault tag."""
try:
return getattr(val, 'tag', None) == '!vault'
except Exception:
return False
def _is_vault_encrypted(val: Any) -> bool:
"""
Detect if value is already a vault string or a ruamel !vault scalar.
Accept both '$ANSIBLE_VAULT' and '!vault' markers.
"""
if _is_ruamel_vault(val):
return True
if isinstance(val, str) and ("$ANSIBLE_VAULT" in val or "!vault" in val):
return True
return False
def _vault_body(text: str) -> str:
"""
Return only the vault body starting from the first line that contains
'$ANSIBLE_VAULT'. If not found, return the original text.
Also strips any leading '!vault |' header if present.
"""
lines = text.splitlines()
for i, ln in enumerate(lines):
if "$ANSIBLE_VAULT" in ln:
return "\n".join(lines[i:])
return text
def _make_vault_scalar_from_text(text: str) -> Any:
"""
Build a ruamel object representing a literal block scalar tagged with !vault
by parsing a tiny YAML snippet. This avoids depending on yaml_set_tag().
"""
body = _vault_body(text)
indented = " " + body.replace("\n", "\n ") # proper block scalar indentation
snippet = f"v: !vault |\n{indented}\n"
y = YAML(typ="rt")
return y.load(snippet)["v"]
def to_vault_block(vault_handler: VaultHandler, value: Union[str, Any], label: str) -> Any:
"""
Return a ruamel scalar tagged as !vault. If the input value is already
vault-encrypted (string contains $ANSIBLE_VAULT or is a !vault scalar), reuse/wrap.
Otherwise, encrypt plaintext via ansible-vault.
"""
# Already a ruamel !vault scalar → reuse
if _is_ruamel_vault(value):
return value
# Already an encrypted string (may include '!vault |' or just the header)
if isinstance(value, str) and ("$ANSIBLE_VAULT" in value or "!vault" in value):
return _make_vault_scalar_from_text(value)
# Plaintext → encrypt now
snippet = vault_handler.encrypt_string(str(value), label)
return _make_vault_scalar_from_text(snippet)
def parse_overrides(pairs: list[str]) -> Dict[str, str]:
"""
Parse --set key=value pairs into a dict.
Supports both 'credentials.key=val' and 'key=val' (short) forms.
"""
out: Dict[str, str] = {}
for pair in pairs:
k, v = pair.split("=", 1)
out[k.strip()] = v.strip()
return out
# ---------- main ----------
def main() -> int:
parser = argparse.ArgumentParser(
description="Selectively add & vault NEW credentials in your inventory, preserving comments/formatting."
)
parser.add_argument("--role-path", required=True, help="Path to your role")
parser.add_argument("--inventory-file", required=True, help="Host vars file to update")
parser.add_argument("--vault-password-file", required=True, help="Vault password file")
parser.add_argument(
"--set", nargs="*", default=[],
help="Override values key[.subkey]=VALUE (applied to NEW keys; with --force also to existing)"
)
parser.add_argument(
"-f", "--force", action="store_true",
help="Allow overrides to replace existing values (will ask per key unless combined with --yes)"
)
parser.add_argument(
"-y", "--yes", action="store_true",
help="Non-interactive: assume 'yes' for all overwrite confirmations when --force is used"
)
args = parser.parse_args()
overrides = parse_overrides(args.set)
# Initialize inventory manager (provides schema + app_id + vault)
manager = InventoryManager(
role_path=Path(args.role_path),
inventory_path=Path(args.inventory_file),
vault_pw=args.vault_password_file,
overrides=overrides
)
# 1) Load existing inventory with ruamel (round-trip)
yaml_rt = YAML(typ="rt")
yaml_rt.preserve_quotes = True
with open(args.inventory_file, "r", encoding="utf-8") as f:
data = yaml_rt.load(f) # CommentedMap or None
if data is None:
data = CommentedMap()
# 2) Get schema-applied structure (defaults etc.) for *non-destructive* merge
schema_inventory: Dict[str, Any] = manager.apply_schema()
# 3) Ensure structural path exists
apps = ensure_map(data, "applications")
app_block = ensure_map(apps, manager.app_id)
creds = ensure_map(app_block, "credentials")
# 4) Determine defaults we could add
schema_apps = schema_inventory.get("applications", {})
schema_app_block = schema_apps.get(manager.app_id, {})
schema_creds = schema_app_block.get("credentials", {}) if isinstance(schema_app_block, dict) else {}
# 5) Add ONLY missing credential keys
newly_added_keys = set()
for key, default_val in schema_creds.items():
if key in creds:
# existing → do not touch (preserve plaintext/vault/formatting/comments)
continue
# Value to use for the new key
# Priority: --set exact key → default from schema → empty string
ov = overrides.get(f"credentials.{key}", None)
if ov is None:
ov = overrides.get(key, None)
if ov is not None:
value_for_new_key: Union[str, Any] = ov
else:
if _is_vault_encrypted(default_val):
# Schema already provides a vault value → take it as-is
creds[key] = to_vault_block(manager.vault_handler, default_val, key)
newly_added_keys.add(key)
continue
value_for_new_key = "" if default_val is None else str(default_val)
# Insert as !vault literal (encrypt if needed)
creds[key] = to_vault_block(manager.vault_handler, value_for_new_key, key)
newly_added_keys.add(key)
# 6) ansible_become_password: only add if missing;
# never rewrite an existing one unless --force (+ confirm/--yes) and override provided.
if "ansible_become_password" not in data:
val = overrides.get("ansible_become_password", None)
if val is not None:
data["ansible_become_password"] = to_vault_block(
manager.vault_handler, val, "ansible_become_password"
)
else:
if args.force and "ansible_become_password" in overrides:
do_overwrite = args.yes or ask_for_confirmation("ansible_become_password")
if do_overwrite:
data["ansible_become_password"] = to_vault_block(
manager.vault_handler, overrides["ansible_become_password"], "ansible_become_password"
)
# 7) Overrides for existing credential keys (only with --force)
if args.force:
for ov_key, ov_val in overrides.items():
# Accept both 'credentials.key' and bare 'key'
key = ov_key.split(".", 1)[1] if ov_key.startswith("credentials.") else ov_key
if key in creds:
# If we just added it in this run, don't ask again or rewrap
if key in newly_added_keys:
continue
if args.yes or ask_for_confirmation(key):
creds[key] = to_vault_block(manager.vault_handler, ov_val, key)
# 8) Write back with ruamel (preserve formatting & comments)
with open(args.inventory_file, "w", encoding="utf-8") as f:
yaml_rt.dump(data, f)
print(f"✅ Added new credentials without touching existing formatting/comments → {args.inventory_file}")
return 0
if __name__ == "__main__":
sys.exit(main())

166
cli/create/role.py Normal file
View File

@@ -0,0 +1,166 @@
#!/usr/bin/env python3
import argparse
import shutil
import ipaddress
import difflib
from jinja2 import Environment, FileSystemLoader
from ruamel.yaml import YAML
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from module_utils.entity_name_utils import get_entity_name
# Paths to the group-vars files
PORTS_FILE = './group_vars/all/10_ports.yml'
NETWORKS_FILE = './group_vars/all/09_networks.yml'
ROLE_TEMPLATE_DIR = './templates/roles/web-app'
ROLES_DIR = './roles'
yaml = YAML()
yaml.preserve_quotes = True
def load_yaml_with_comments(path):
with open(path) as f:
return yaml.load(f)
def dump_yaml_with_comments(data, path):
with open(path, 'w') as f:
yaml.dump(data, f)
def get_next_network(networks_dict, prefixlen):
"""Select the next contiguous subnet, based on the highest existing subnet + one network offset."""
nets = []
local = networks_dict['defaults_networks']['local']
for name, info in local.items():
# info is a dict with 'subnet' key
net = ipaddress.ip_network(info['subnet'])
if net.prefixlen == prefixlen:
nets.append(net)
if not nets:
raise RuntimeError(f"No existing /{prefixlen} subnets to base allocation on.")
nets.sort(key=lambda n: int(n.network_address))
last = nets[-1]
offset = last.num_addresses
next_net = ipaddress.ip_network((int(last.network_address) + offset, prefixlen))
return next_net
def get_next_port(ports_dict, category):
"""Assign the next port by taking the max existing plus one."""
loc = ports_dict['ports']['localhost'][category]
existing = [int(v) for v in loc.values()]
return (max(existing) + 1) if existing else 1
def prompt_conflict(dst_file):
print(f"Conflict detected: {dst_file}")
print("[1] overwrite, [2] skip, [3] merge")
choice = None
while choice not in ('1', '2', '3'):
choice = input("Enter 1, 2, or 3: ").strip()
return choice
def render_templates(src_dir, dst_dir, context):
env = Environment(loader=FileSystemLoader(src_dir), keep_trailing_newline=True, autoescape=False)
env.filters['bool'] = lambda x: bool(x)
env.filters['get_entity_name'] = get_entity_name
for root, _, files in os.walk(src_dir):
rel = os.path.relpath(root, src_dir)
target = os.path.join(dst_dir, rel)
os.makedirs(target, exist_ok=True)
for fn in files:
tpl = env.get_template(os.path.join(rel, fn))
rendered = tpl.render(**context)
out = fn[:-3] if fn.endswith('.j2') else fn
dst_file = os.path.join(target, out)
if os.path.exists(dst_file):
choice = prompt_conflict(dst_file)
if choice == '2':
print(f"Skipping {dst_file}")
continue
if choice == '3':
with open(dst_file) as f_old:
old_lines = f_old.readlines()
new_lines = rendered.splitlines(keepends=True)
additions = [l for l in new_lines if l not in old_lines]
if additions:
with open(dst_file, 'a') as f:
f.writelines(additions)
print(f"Merged {len(additions)} lines into {dst_file}")
else:
print(f"No new lines to merge into {dst_file}")
continue
# overwrite
print(f"Overwriting {dst_file}")
with open(dst_file, 'w') as f:
f.write(rendered)
else:
# create new file
with open(dst_file, 'w') as f:
f.write(rendered)
def main():
# Load dynamic port categories
ports_data = load_yaml_with_comments(PORTS_FILE)
categories = list(ports_data['ports']['localhost'].keys())
parser = argparse.ArgumentParser(
description="Create or update a Docker Ansible role, and globally assign network and ports with comments preserved"
)
parser.add_argument('-a', '--application-id', required=True, help="Unique application ID")
parser.add_argument('-n', '--network', choices=['24', '28'], required=True, help="Network prefix length (/24 or /28)")
parser.add_argument('-p', '--ports', nargs='+', choices=categories, required=True, help=f"Port categories to assign (allowed: {', '.join(categories)})")
args = parser.parse_args()
app = args.application_id
role = f"web-app-{app}"
role_dir = os.path.join(ROLES_DIR, role)
if os.path.exists(role_dir):
if input(f"Role {role} exists. Continue? [y/N]: ").strip().lower() != 'y':
print("Aborting.")
sys.exit(1)
else:
os.makedirs(role_dir)
# 1) Render all templates with conflict handling
render_templates(ROLE_TEMPLATE_DIR, role_dir, {'application_id': app, 'role_name': role, 'database_type': 0})
print(f"→ Templates applied to {role_dir}")
# 2) Update global networks file, preserving comments
networks = load_yaml_with_comments(NETWORKS_FILE)
prefix = int(args.network)
new_net = get_next_network(networks, prefix)
networks['defaults_networks']['local'][app] = {'subnet': str(new_net)}
shutil.copy(NETWORKS_FILE, NETWORKS_FILE + '.bak')
dump_yaml_with_comments(networks, NETWORKS_FILE)
print(f"→ Assigned network {new_net} in {NETWORKS_FILE}")
# 3) Update global ports file, preserving comments
ports_data = load_yaml_with_comments(PORTS_FILE)
assigned = {}
for cat in args.ports:
loc = ports_data['ports']['localhost'].setdefault(cat, {})
if app in loc:
print(f"→ Existing port for {cat} and {app}: {loc[app]}, skipping.")
else:
pnum = get_next_port(ports_data, cat)
loc[app] = pnum
assigned[cat] = pnum
if assigned:
shutil.copy(PORTS_FILE, PORTS_FILE + '.bak')
dump_yaml_with_comments(ports_data, PORTS_FILE)
print(f"→ Assigned ports {assigned} in {PORTS_FILE}")
else:
print("→ No new ports assigned.")
if __name__ == '__main__':
main()

221
cli/deploy.py Normal file
View File

@@ -0,0 +1,221 @@
#!/usr/bin/env python3
import argparse
import subprocess
import os
import datetime
import sys
def run_ansible_playbook(
inventory,
modes,
limit=None,
allowed_applications=None,
password_file=None,
verbose=0,
skip_tests=False,
skip_validation=False,
skip_build=False,
cleanup=False,
logs=False
):
start_time = datetime.datetime.now()
print(f"\n▶️ Script started at: {start_time.isoformat()}\n")
if cleanup:
cleanup_command = ["make", "clean-keep-logs"] if logs else ["make", "clean"]
print("\n🧹 Cleaning up project (" + " ".join(cleanup_command) +")...\n")
subprocess.run(cleanup_command, check=True)
else:
print("\n⚠️ Skipping build as requested.\n")
if not skip_build:
print("\n🛠️ Building project (make messy-build)...\n")
subprocess.run(["make", "messy-build"], check=True)
else:
print("\n⚠️ Skipping build as requested.\n")
script_dir = os.path.dirname(os.path.realpath(__file__))
playbook = os.path.join(os.path.dirname(script_dir), "playbook.yml")
# Inventory validation step
if not skip_validation:
print("\n🔍 Validating inventory before deployment...\n")
try:
subprocess.run(
[sys.executable,
os.path.join(script_dir, "validate/inventory.py"),
os.path.dirname(inventory)
],
check=True
)
except subprocess.CalledProcessError:
print(
"\n❌ Inventory validation failed. Deployment aborted.\n",
file=sys.stderr
)
sys.exit(1)
else:
print("\n⚠️ Skipping inventory validation as requested.\n")
if not skip_tests:
print("\n🧪 Running tests (make messy-test)...\n")
subprocess.run(["make", "messy-test"], check=True)
# Build ansible-playbook command
cmd = ["ansible-playbook", "-i", inventory, playbook]
if limit:
cmd.extend(["--limit", limit])
if allowed_applications:
joined = ",".join(allowed_applications)
cmd.extend(["-e", f"allowed_applications={joined}"])
for key, value in modes.items():
val = str(value).lower() if isinstance(value, bool) else str(value)
cmd.extend(["-e", f"{key}={val}"])
if password_file:
cmd.extend(["--vault-password-file", password_file])
else:
cmd.extend(["--ask-vault-pass"])
if verbose:
cmd.append("-" + "v" * verbose)
print("\n🚀 Launching Ansible Playbook...\n")
subprocess.run(cmd, check=True)
end_time = datetime.datetime.now()
print(f"\n✅ Script ended at: {end_time.isoformat()}\n")
duration = end_time - start_time
print(f"⏱️ Total execution time: {duration}\n")
def validate_application_ids(inventory, app_ids):
"""
Abort the script if any application IDs are invalid, with detailed reasons.
"""
from module_utils.valid_deploy_id import ValidDeployId
validator = ValidDeployId()
invalid = validator.validate(inventory, app_ids)
if invalid:
print("\n❌ Detected invalid application_id(s):\n")
for app_id, status in invalid.items():
reasons = []
if not status['in_roles']:
reasons.append("not defined in roles (infinito)")
if not status['in_inventory']:
reasons.append("not found in inventory file")
print(f" - {app_id}: " + ", ".join(reasons))
sys.exit(1)
def main():
parser = argparse.ArgumentParser(
description="Run the central Ansible deployment script to manage infrastructure, updates, and tests."
)
parser.add_argument(
"inventory",
help="Path to the inventory file (INI or YAML) containing hosts and variables."
)
parser.add_argument(
"-l", "--limit",
help="Restrict execution to a specific host or host group from the inventory."
)
parser.add_argument(
"-T", "--host-type",
choices=["server", "desktop"],
default="server",
help="Specify whether the target is a server or a personal computer. Affects role selection and variables."
)
parser.add_argument(
"-r", "--reset", action="store_true",
help="Reset all Infinito.Nexus files and configurations, and run the entire playbook (not just individual roles)."
)
parser.add_argument(
"-t", "--test", action="store_true",
help="Run test routines instead of production tasks. Useful for local testing and CI pipelines."
)
parser.add_argument(
"-u", "--update", action="store_true",
help="Enable the update procedure to bring software and roles up to date."
)
parser.add_argument(
"-b", "--backup", action="store_true",
help="Perform a full backup of critical data and configurations before the update process."
)
parser.add_argument(
"-c", "--cleanup", action="store_true",
help="Clean up unused files and outdated configurations after all tasks are complete. Also cleans up the repository before the deployment procedure."
)
parser.add_argument(
"-d", "--debug", action="store_true",
help="Enable detailed debug output for Ansible and this script."
)
parser.add_argument(
"-p", "--password-file",
help="Path to the file containing the Vault password. If not provided, prompts for the password interactively."
)
parser.add_argument(
"-s", "--skip-tests", action="store_true",
help="Skip running 'make test' even if tests are normally enabled."
)
parser.add_argument(
"-V", "--skip-validation", action="store_true",
help="Skip inventory validation before deployment."
)
parser.add_argument(
"-B", "--skip-build", action="store_true",
help="Skip running 'make build' before deployment."
)
parser.add_argument(
"-i", "--id",
nargs="+",
default=[],
dest="id",
help="List of application_id's for partial deploy. If not set, all application IDs defined in the inventory will be executed."
)
parser.add_argument(
"-v", "--verbose", action="count", default=0,
help="Increase verbosity level. Multiple -v flags increase detail (e.g., -vvv for maximum log output)."
)
parser.add_argument(
"--logs", action="store_true",
help="Keep the CLI logs during cleanup command"
)
args = parser.parse_args()
validate_application_ids(args.inventory, args.id)
modes = {
"MODE_RESET": args.reset,
"MODE_TEST": args.test,
"MODE_UPDATE": args.update,
"MODE_BACKUP": args.backup,
"MODE_CLEANUP": args.cleanup,
"MODE_LOGS": args.logs,
"MODE_DEBUG": args.debug,
"MODE_ASSERT": not args.skip_validation,
"host_type": args.host_type
}
run_ansible_playbook(
inventory=args.inventory,
modes=modes,
limit=args.limit,
allowed_applications=args.id,
password_file=args.password_file,
verbose=args.verbose,
skip_tests=args.skip_tests,
skip_validation=args.skip_validation,
skip_build=args.skip_build,
cleanup=args.cleanup,
logs=args.logs
)
if __name__ == "__main__":
main()

0
cli/encrypt/__init__.py Normal file
View File

66
cli/encrypt/inventory.py Normal file
View File

@@ -0,0 +1,66 @@
import argparse
import subprocess
import sys
from pathlib import Path
import yaml
from typing import Dict, Any
from module_utils.handler.vault import VaultHandler, VaultScalar
from module_utils.handler.yaml import YamlHandler
from yaml.dumper import SafeDumper
def ask_for_confirmation(key: str) -> bool:
"""Prompt the user for confirmation to overwrite an existing value."""
confirmation = input(f"Do you want to encrypt the value for '{key}'? (y/n): ").strip().lower()
return confirmation == 'y'
def encrypt_recursively(data: Any, vault_handler: VaultHandler, ask_confirmation: bool = True, prefix: str = "") -> Any:
"""Recursively encrypt values in the data."""
if isinstance(data, dict):
for key, value in data.items():
new_prefix = f"{prefix}.{key}" if prefix else key
data[key] = encrypt_recursively(value, vault_handler, ask_confirmation, new_prefix)
elif isinstance(data, list):
for i, item in enumerate(data):
data[i] = encrypt_recursively(item, vault_handler, ask_confirmation, prefix)
elif isinstance(data, str):
# Only encrypt if it's not already vaulted
if not data.lstrip().startswith("$ANSIBLE_VAULT"):
if ask_confirmation:
# Ask for confirmation before encrypting if not `--all`
if not ask_for_confirmation(prefix):
print(f"Skipping encryption for '{prefix}'.")
return data
encrypted_value = vault_handler.encrypt_string(data, prefix)
lines = encrypted_value.splitlines()
indent = len(lines[1]) - len(lines[1].lstrip())
body = "\n".join(line[indent:] for line in lines[1:])
return VaultScalar(body) # Store encrypted value as VaultScalar
return data
def main():
parser = argparse.ArgumentParser(
description="Encrypt all fields, ask for confirmation unless --all is specified."
)
parser.add_argument("--inventory-file", required=True, help="Host vars file to update")
parser.add_argument("--vault-password-file", required=True, help="Vault password file")
parser.add_argument("--all", action="store_true", help="Encrypt all fields without confirmation")
args = parser.parse_args()
# Initialize the VaultHandler and load the inventory
vault_handler = VaultHandler(vault_password_file=args.vault_password_file)
updated_inventory = YamlHandler.load_yaml(Path(args.inventory_file))
# 1) Encrypt all fields recursively
updated_inventory = encrypt_recursively(updated_inventory, vault_handler, ask_confirmation=not args.all)
# 2) Save the updated inventory to file
with open(args.inventory_file, "w", encoding="utf-8") as f:
yaml.dump(updated_inventory, f, sort_keys=False, Dumper=SafeDumper)
print(f"✅ Inventory selectively vaulted → {args.inventory_file}")
if __name__ == "__main__":
main()

0
cli/fix/__init__.py Normal file
View File

47
cli/fix/ini_py.py Normal file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env python3
"""
This script creates __init__.py files in every subdirectory under the specified
folder relative to the project root.
"""
import os
import argparse
def create_init_files(root_folder):
"""
Walk through all subdirectories of root_folder and create an __init__.py file
in each directory if it doesn't already exist.
"""
for dirpath, dirnames, filenames in os.walk(root_folder):
init_file = os.path.join(dirpath, '__init__.py')
if not os.path.exists(init_file):
open(init_file, 'w').close()
print(f"Created: {init_file}")
else:
print(f"Skipped (already exists): {init_file}")
def main():
parser = argparse.ArgumentParser(
description='Create __init__.py files in every subdirectory.'
)
parser.add_argument(
'folder',
help='Relative path to the target folder (e.g., cli/fix)'
)
args = parser.parse_args()
# Determine the absolute path based on the current working directory
root_folder = os.path.abspath(args.folder)
if not os.path.isdir(root_folder):
print(f"Error: The folder '{args.folder}' does not exist or is not a directory.")
exit(1)
create_init_files(root_folder)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,480 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Move unnecessary meta dependencies to guarded include_role/import_role
for better performance, while preserving YAML comments, quotes, and layout.
Heuristic (matches tests/integration/test_unnecessary_role_dependencies.py):
- A dependency is considered UNNECESSARY if:
* The consumer does NOT use provider variables in defaults/vars/handlers
(no early-var need), AND
* In tasks, any usage of provider vars or provider-handler notifications
occurs only AFTER an include/import of the provider in the same file,
OR there is no usage at all.
Action:
- Remove such dependencies from roles/<role>/meta/main.yml.
- Prepend a guarded include block to roles/<role>/tasks/01_core.yml (preferred)
or roles/<role>/tasks/main.yml if 01_core.yml is absent.
- If multiple dependencies are moved for a role, use a loop over include_role.
Notes:
- Creates .bak backups for modified YAML files.
- Requires ruamel.yaml to preserve comments/quotes everywhere.
"""
import argparse
import glob
import os
import re
import shutil
import sys
from typing import Dict, Set, List, Tuple, Optional
# --- Require ruamel.yaml for full round-trip preservation ---
try:
from ruamel.yaml import YAML
from ruamel.yaml.comments import CommentedMap, CommentedSeq
from ruamel.yaml.scalarstring import SingleQuotedScalarString
_HAVE_RUAMEL = True
except Exception:
_HAVE_RUAMEL = False
if not _HAVE_RUAMEL:
print("[ERR] ruamel.yaml is required to preserve comments/quotes. Install with: pip install ruamel.yaml", file=sys.stderr)
sys.exit(3)
yaml_rt = YAML()
yaml_rt.preserve_quotes = True
yaml_rt.width = 10**9 # prevent line wrapping
# ---------------- Utilities ----------------
def _backup(path: str):
if os.path.exists(path):
shutil.copy2(path, path + ".bak")
def read_text(path: str) -> str:
try:
with open(path, "r", encoding="utf-8") as f:
return f.read()
except Exception:
return ""
def load_yaml_rt(path: str):
try:
with open(path, "r", encoding="utf-8") as f:
data = yaml_rt.load(f)
return data if data is not None else CommentedMap()
except FileNotFoundError:
return CommentedMap()
except Exception as e:
print(f"[WARN] Failed to parse YAML: {path}: {e}", file=sys.stderr)
return CommentedMap()
def dump_yaml_rt(data, path: str):
_backup(path)
with open(path, "w", encoding="utf-8") as f:
yaml_rt.dump(data, f)
def roles_root(project_root: str) -> str:
return os.path.join(project_root, "roles")
def iter_role_dirs(project_root: str) -> List[str]:
root = roles_root(project_root)
return [d for d in glob.glob(os.path.join(root, "*")) if os.path.isdir(d)]
def role_name_from_dir(role_dir: str) -> str:
return os.path.basename(role_dir.rstrip(os.sep))
def path_if_exists(*parts) -> Optional[str]:
p = os.path.join(*parts)
return p if os.path.exists(p) else None
def gather_yaml_files(base: str, patterns: List[str]) -> List[str]:
files: List[str] = []
for pat in patterns:
files.extend(glob.glob(os.path.join(base, pat), recursive=True))
return [f for f in files if os.path.isfile(f)]
def sq(v: str):
"""Return a single-quoted scalar (ruamel) for consistent quoting."""
return SingleQuotedScalarString(v)
# ---------------- Providers: vars & handlers ----------------
def flatten_keys(data) -> Set[str]:
out: Set[str] = set()
if isinstance(data, dict):
for k, v in data.items():
if isinstance(k, str):
out.add(k)
out |= flatten_keys(v)
elif isinstance(data, list):
for item in data:
out |= flatten_keys(item)
return out
def collect_role_defined_vars(role_dir: str) -> Set[str]:
"""Vars a role 'provides': defaults/vars keys + set_fact keys in tasks."""
provided: Set[str] = set()
for rel in ("defaults/main.yml", "vars/main.yml"):
p = path_if_exists(role_dir, rel)
if p:
data = load_yaml_rt(p)
provided |= flatten_keys(data)
# set_fact keys
task_files = gather_yaml_files(os.path.join(role_dir, "tasks"), ["**/*.yml", "*.yml"])
for tf in task_files:
data = load_yaml_rt(tf)
if isinstance(data, list):
for task in data:
if isinstance(task, dict) and "set_fact" in task and isinstance(task["set_fact"], dict):
provided |= set(task["set_fact"].keys())
noisy = {"when", "name", "vars", "tags", "register"}
return {v for v in provided if isinstance(v, str) and v and v not in noisy}
def collect_role_handler_names(role_dir: str) -> Set[str]:
"""Handler names defined by a role (for notify detection)."""
handler_file = path_if_exists(role_dir, "handlers/main.yml")
if not handler_file:
return set()
data = load_yaml_rt(handler_file)
names: Set[str] = set()
if isinstance(data, list):
for task in data:
if isinstance(task, dict):
nm = task.get("name")
if isinstance(nm, str) and nm.strip():
names.add(nm.strip())
return names
# ---------------- Consumers: usage scanning ----------------
def find_var_positions(text: str, varname: str) -> List[int]:
"""Return byte offsets for occurrences of varname (word-ish boundary)."""
positions: List[int] = []
if not varname:
return positions
pattern = re.compile(rf"(?<!\w){re.escape(varname)}(?!\w)")
for m in pattern.finditer(text):
positions.append(m.start())
return positions
def first_var_use_offset_in_text(text: str, provided_vars: Set[str]) -> Optional[int]:
first: Optional[int] = None
for v in provided_vars:
for off in find_var_positions(text, v):
if first is None or off < first:
first = off
return first
def first_include_offset_for_role(text: str, producer_role: str) -> Optional[int]:
"""
Find earliest include/import of a given role in this YAML text.
Handles compact dict and block styles.
"""
pattern = re.compile(
r"(include_role|import_role)\s*:\s*\{[^}]*\bname\s*:\s*['\"]?"
+ re.escape(producer_role) + r"['\"]?[^}]*\}"
r"|"
r"(include_role|import_role)\s*:\s*\n(?:\s+[a-z_]+\s*:\s*.*\n)*\s*name\s*:\s*['\"]?"
+ re.escape(producer_role) + r"['\"]?",
re.IGNORECASE,
)
m = pattern.search(text)
return m.start() if m else None
def find_notify_offsets_for_handlers(text: str, handler_names: Set[str]) -> List[int]:
"""
Heuristic: for each handler name, find occurrences where 'notify' appears within
the preceding ~200 chars. Works for single string or list-style notify blocks.
"""
if not handler_names:
return []
offsets: List[int] = []
for h in handler_names:
for m in re.finditer(re.escape(h), text):
start = m.start()
back = max(0, start - 200)
context = text[back:start]
if re.search(r"notify\s*:", context):
offsets.append(start)
return sorted(offsets)
def parse_meta_dependencies(role_dir: str) -> List[str]:
meta = path_if_exists(role_dir, "meta/main.yml")
if not meta:
return []
data = load_yaml_rt(meta)
dd = data.get("dependencies")
deps: List[str] = []
if isinstance(dd, list):
for item in dd:
if isinstance(item, str):
deps.append(item)
elif isinstance(item, dict) and "role" in item:
deps.append(str(item["role"]))
elif isinstance(item, dict) and "name" in item:
deps.append(str(item["name"]))
return deps
# ---------------- Fix application ----------------
def sanitize_run_once_var(role_name: str) -> str:
"""
Generate run_once variable name from role name.
Example: 'sys-front-inj-logout' -> 'run_once_sys_front_inj_logout'
"""
return "run_once_" + role_name.replace("-", "_")
def build_include_block_yaml(consumer_role: str, moved_deps: List[str]) -> List[dict]:
"""
Build a guarded block that includes one or many roles.
This block will be prepended to tasks/01_core.yml or tasks/main.yml.
"""
guard_var = sanitize_run_once_var(consumer_role)
if len(moved_deps) == 1:
inner_tasks = [
{
"name": f"Include dependency '{moved_deps[0]}'",
"include_role": {"name": moved_deps[0]},
}
]
else:
inner_tasks = [
{
"name": "Include dependencies",
"include_role": {"name": "{{ item }}"},
"loop": moved_deps,
}
]
# Always set the run_once fact at the end
inner_tasks.append({"set_fact": {guard_var: True}})
# Correct Ansible block structure
block_task = {
"name": "Load former meta dependencies once",
"block": inner_tasks,
"when": f"{guard_var} is not defined",
}
return [block_task]
def prepend_tasks(tasks_path: str, new_tasks, dry_run: bool):
"""
Prepend new_tasks (CommentedSeq) to an existing tasks YAML list while preserving comments.
If the file does not exist, create it with new_tasks.
"""
if os.path.exists(tasks_path):
existing = load_yaml_rt(tasks_path)
if isinstance(existing, list):
combined = CommentedSeq()
for item in new_tasks:
combined.append(item)
for item in existing:
combined.append(item)
elif isinstance(existing, dict):
# Rare case: tasks file with a single mapping; coerce to list
combined = CommentedSeq()
for item in new_tasks:
combined.append(item)
combined.append(existing)
else:
combined = new_tasks
else:
os.makedirs(os.path.dirname(tasks_path), exist_ok=True)
combined = new_tasks
if dry_run:
print(f"[DRY-RUN] Would write {tasks_path} with {len(new_tasks)} prepended task(s).")
return
dump_yaml_rt(combined, tasks_path)
print(f"[OK] Updated {tasks_path} (prepended {len(new_tasks)} task(s)).")
def update_meta_remove_deps(meta_path: str, remove: List[str], dry_run: bool):
"""
Remove entries from meta.dependencies while leaving the rest of the file intact.
Quotes, comments, key order, and line breaks are preserved.
Returns True if a change would be made (or was made when not in dry-run).
"""
if not os.path.exists(meta_path):
return False
doc = load_yaml_rt(meta_path)
deps = doc.get("dependencies")
if not isinstance(deps, list):
return False
def dep_name(item):
if isinstance(item, dict):
return item.get("role") or item.get("name")
return item
keep = CommentedSeq()
removed = []
for item in deps:
name = dep_name(item)
if name in remove:
removed.append(name)
else:
keep.append(item)
if not removed:
return False
if keep:
doc["dependencies"] = keep
else:
if "dependencies" in doc:
del doc["dependencies"]
if dry_run:
print(f"[DRY-RUN] Would rewrite {meta_path}; removed: {', '.join(removed)}")
return True
dump_yaml_rt(doc, meta_path)
print(f"[OK] Rewrote {meta_path}; removed: {', '.join(removed)}")
return True
def dependency_is_unnecessary(consumer_dir: str,
consumer_name: str,
producer_name: str,
provider_vars: Set[str],
provider_handlers: Set[str]) -> bool:
"""Apply heuristic to decide if we can move this dependency."""
# 1) Early usage in defaults/vars/handlers? If yes -> necessary
defaults_files = [p for p in [
path_if_exists(consumer_dir, "defaults/main.yml"),
path_if_exists(consumer_dir, "vars/main.yml"),
path_if_exists(consumer_dir, "handlers/main.yml"),
] if p]
for p in defaults_files:
text = read_text(p)
if first_var_use_offset_in_text(text, provider_vars) is not None:
return False # needs meta dep
# 2) Tasks: any usage before include/import? If yes -> keep meta dep
task_files = gather_yaml_files(os.path.join(consumer_dir, "tasks"), ["**/*.yml", "*.yml"])
for p in task_files:
text = read_text(p)
if not text:
continue
include_off = first_include_offset_for_role(text, producer_name)
var_use_off = first_var_use_offset_in_text(text, provider_vars)
notify_offs = find_notify_offsets_for_handlers(text, provider_handlers)
if var_use_off is not None:
if include_off is None or include_off > var_use_off:
return False # used before include
for noff in notify_offs:
if include_off is None or include_off > noff:
return False # notify before include
# If we get here: no early use, and either no usage at all or usage after include
return True
def process_role(role_dir: str,
providers_index: Dict[str, Tuple[Set[str], Set[str]]],
only_role: Optional[str],
dry_run: bool) -> bool:
"""
Returns True if any change suggested/made for this role.
"""
consumer_name = role_name_from_dir(role_dir)
if only_role and only_role != consumer_name:
return False
meta_deps = parse_meta_dependencies(role_dir)
if not meta_deps:
return False
# Build provider vars/handlers accessors
moved: List[str] = []
for producer in meta_deps:
# Only consider local roles we can analyze
producer_dir = path_if_exists(os.path.dirname(role_dir), producer) or path_if_exists(os.path.dirname(roles_root(os.path.dirname(role_dir))), "roles", producer)
if producer not in providers_index:
# Unknown/external role → skip (we cannot verify safety)
continue
pvars, phandlers = providers_index[producer]
if dependency_is_unnecessary(role_dir, consumer_name, producer, pvars, phandlers):
moved.append(producer)
if not moved:
return False
# 1) Remove from meta
meta_path = os.path.join(role_dir, "meta", "main.yml")
update_meta_remove_deps(meta_path, moved, dry_run=dry_run)
# 2) Prepend include block to tasks/01_core.yml or tasks/main.yml
target_tasks = path_if_exists(role_dir, "tasks/01_core.yml")
if not target_tasks:
target_tasks = os.path.join(role_dir, "tasks", "main.yml")
include_block = build_include_block_yaml(consumer_name, moved)
prepend_tasks(target_tasks, include_block, dry_run=dry_run)
return True
def build_providers_index(all_roles: List[str]) -> Dict[str, Tuple[Set[str], Set[str]]]:
"""
Map role_name -> (provided_vars, handler_names)
"""
index: Dict[str, Tuple[Set[str], Set[str]]] = {}
for rd in all_roles:
rn = role_name_from_dir(rd)
index[rn] = (collect_role_defined_vars(rd), collect_role_handler_names(rd))
return index
def main():
parser = argparse.ArgumentParser(
description="Move unnecessary meta dependencies to guarded include_role for performance (preserve comments/quotes)."
)
parser.add_argument(
"--project-root",
default=os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")),
help="Path to project root (default: two levels up from this script).",
)
parser.add_argument(
"--role",
dest="only_role",
default=None,
help="Only process a specific role name (e.g., 'docker-core').",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Analyze and print planned changes without modifying files.",
)
args = parser.parse_args()
roles = iter_role_dirs(args.project_root)
if not roles:
print(f"[ERR] No roles found under {roles_root(args.project_root)}", file=sys.stderr)
sys.exit(2)
providers_index = build_providers_index(roles)
changed_any = False
for role_dir in roles:
changed = process_role(role_dir, providers_index, args.only_role, args.dry_run)
changed_any = changed_any or changed
if not changed_any:
print("[OK] No unnecessary meta dependencies to move (per heuristic).")
else:
if args.dry_run:
print("[DRY-RUN] Completed analysis. No files were changed.")
else:
print("[OK] Finished moving unnecessary dependencies.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,5 @@
# Just a little refactoring script, you can delete it later
ATTR="$1"
OLD="applications[application_id].$ATTR"
NEW="applications | get_app_conf(application_id, '$ATTR', True)"
bsr ./ "$OLD" -rFfc -n "$NEW"

57
cli/fix/tabs.py Normal file
View File

@@ -0,0 +1,57 @@
#!/usr/bin/env python3
import os
import argparse
from pathlib import Path
FILES_FIXED = []
def fix_tabs_in_file(file_path):
"""Replaces tab characters with two spaces in the specified file."""
with open(file_path, "r", encoding="utf-8") as f:
lines = f.readlines()
if any('\t' in line for line in lines):
fixed_lines = [line.replace('\t', ' ') for line in lines]
with open(file_path, "w", encoding="utf-8") as f:
f.writelines(fixed_lines)
FILES_FIXED.append(str(file_path))
def find_yml_files(path):
"""Yield all .yml files under a given path recursively."""
for file in path.rglob("*.yml"):
if file.is_file():
yield file
def main():
parser = argparse.ArgumentParser(
description="Fix tab characters in all .yml files under a given path (recursively)."
)
parser.add_argument(
"path",
nargs="?",
default="./",
help="Base path to search for .yml files (default: ./)"
)
args = parser.parse_args()
base_path = Path(args.path).resolve()
if not base_path.exists():
print(f"❌ Path does not exist: {base_path}")
exit(1)
print(f"🔍 Searching for .yml files under: {base_path}\n")
for yml_file in find_yml_files(base_path):
fix_tabs_in_file(yml_file)
if FILES_FIXED:
print("✅ Fixed tab characters in the following files:")
for f in FILES_FIXED:
print(f" - {f}")
else:
print("✅ No tabs found in any .yml files.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""
Script to ensure each Ansible role under ../roles/ with a given prefix has a vars/main.yml
containing the correct application_id. Can preview actions or overwrite mismatches.
"""
import argparse
import sys
import yaml
from pathlib import Path
# Directory containing roles; can be overridden by tests
MODULE_DIR = Path(__file__).resolve().parent
ROLES_DIR = (MODULE_DIR.parent.parent / "roles").resolve()
def process_role(role_dir: Path, prefix: str, preview: bool, overwrite: bool):
name = role_dir.name
if not name.startswith(prefix):
return
# Expected application_id is role name minus prefix
expected_id = name[len(prefix):]
vars_dir = role_dir / "vars"
vars_file = vars_dir / "main.yml"
if vars_file.exists():
# Load existing variables
try:
existing = yaml.safe_load(vars_file.read_text()) or {}
except yaml.YAMLError as e:
print(f"Error parsing YAML in {vars_file}: {e}", file=sys.stderr)
return
actual_id = existing.get("application_id")
if actual_id == expected_id:
# Already correct
return
if overwrite:
# Update only application_id
existing["application_id"] = expected_id
if preview:
print(f"[PREVIEW] Would update {vars_file}: application_id -> {expected_id}")
else:
with open(vars_file, "w") as f:
yaml.safe_dump(existing, f, default_flow_style=False, sort_keys=False)
print(f"Updated {vars_file}: application_id -> {expected_id}")
else:
print(f"Mismatch in {vars_file}: application_id='{actual_id}', expected='{expected_id}'")
else:
# Create new vars/main.yml
if preview:
print(f"[PREVIEW] Would create {vars_file} with application_id: {expected_id}")
else:
vars_dir.mkdir(parents=True, exist_ok=True)
content = {"application_id": expected_id}
with open(vars_file, "w") as f:
yaml.safe_dump(content, f, default_flow_style=False, sort_keys=False)
print(f"Created {vars_file} with application_id: {expected_id}")
def run(prefix: str, preview: bool = False, overwrite: bool = False):
"""
Ensure vars/main.yml for roles under ROLES_DIR with the given prefix has correct application_id.
"""
for role in sorted(Path(ROLES_DIR).iterdir()):
if role.is_dir():
process_role(role, prefix, preview, overwrite)
def main():
parser = argparse.ArgumentParser(
description="Ensure vars/main.yml for roles with a given prefix has correct application_id"
)
parser.add_argument(
"--prefix", required=True,
help="Role name prefix to filter (e.g. 'web-', 'svc-', 'desk-')"
)
parser.add_argument(
"--preview", action="store_true",
help="Show what would be done without making changes"
)
parser.add_argument(
"--overwrite", action="store_true",
help="If vars/main.yml exists but application_id mismatches, overwrite only that key"
)
args = parser.parse_args()
# Run processing
run(prefix=args.prefix, preview=args.preview, overwrite=args.overwrite)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,126 @@
#!/usr/bin/env python3
"""
Run the full localhost integration flow entirely inside the infinito Docker container,
without writing any artifacts to the host filesystem.
Catches missing schema/config errors during credential vaulting and skips those apps.
"""
import subprocess
import os
import sys
def main():
repo = os.path.abspath(os.getcwd())
bash_script = '''
set -e
ART=/integration-artifacts
mkdir -p "$ART"
echo testpassword > "$ART/vaultpw.txt"
# 1) Generate inventory
python3 -m cli.build.inventory.full \
--host localhost \
--inventory-style hostvars \
--format yaml \
--output "$ART/inventory.yml"
# 2) Credentials per-app
apps=$(python3 <<EOF
import yaml
inv = yaml.safe_load(open('/integration-artifacts/inventory.yml'))
print(' '.join(inv['_meta']['hostvars']['localhost']['invokable_applications']))
EOF
)
for app in $apps; do
echo "⏳ Vaulting credentials for $app..."
output=$(python3 -m cli.create.credentials \
--role-path "/repo/roles/$app" \
--inventory-file "$ART/inventory.yml" \
--vault-password-file "$ART/vaultpw.txt" \
--force 2>&1) || rc=$?; rc=${rc:-0}
if [ "$rc" -eq 0 ]; then
echo "✅ Credentials generated for $app"
elif echo "$output" | grep -q "No such file or directory"; then
echo "⚠️ Skipping $app (no schema/config)"
elif echo "$output" | grep -q "Plain algorithm for"; then
# Collect all plain-algo keys
keys=( $(echo "$output" | grep -oP "Plain algorithm for '\K[^']+") )
overrides=()
for key in "${keys[@]}"; do
if [[ "$key" == *api_key ]]; then
val=$(python3 - << 'PY'
import random, string
print(''.join(random.choices(string.ascii_letters+string.digits, k=32)))
PY
)
elif [[ "$key" == *password ]]; then
val=$(python3 - << 'PY'
import random, string
print(''.join(random.choices(string.ascii_letters+string.digits, k=12)))
PY
)
else
val=$(python3 - << 'PY'
import random, string
print(''.join(random.choices(string.ascii_letters+string.digits, k=16)))
PY
)
fi
echo " → Overriding $key=$val"
overrides+=("--set" "$key=$val")
done
# Retry with overrides
echo "🔄 Retrying with overrides..."
retry_out=$(python3 -m cli.create.credentials \
--role-path "/repo/roles/$app" \
--inventory-file "$ART/inventory.yml" \
--vault-password-file "$ART/vaultpw.txt" \
"${overrides[@]}" \
--force 2>&1) || retry_rc=$?; retry_rc=${retry_rc:-0}
if [ "$retry_rc" -eq 0 ]; then
echo "✅ Credentials generated for $app (with overrides)"
else
echo "❌ Override failed for $app:"
echo "$retry_out"
fi
else
echo "❌ Credential error for $app:"
echo "$output"
fi
done
# 3) Show generated files
ls -R "$ART" 2>/dev/null
echo "
===== inventory.yml ====="
cat "$ART/inventory.yml"
echo "
===== vaultpw.txt ====="
cat "$ART/vaultpw.txt"
# 4) Deploy
python3 -m cli.deploy \
"$ART/inventory.yml" \
--limit localhost \
--vault-password-file "$ART/vaultpw.txt" \
--verbose
'''
cmd = [
"docker", "run", "--rm",
"-v", f"{repo}:/repo",
"-w", "/repo",
"--entrypoint", "bash",
"infinito:latest",
"-c", bash_script
]
print(f"\033[96m> {' '.join(cmd)}\033[0m")
rc = subprocess.call(cmd)
sys.exit(rc)
if __name__ == '__main__':
main()

50
cli/make.py Normal file
View File

@@ -0,0 +1,50 @@
#!/usr/bin/env python3
"""
CLI wrapper for Makefile targets within Infinito.Nexus.
Invokes `make` commands in the project root directory.
"""
import argparse
import os
import subprocess
import sys
def main():
parser = argparse.ArgumentParser(
prog='infinito make',
description='Run Makefile targets for Infinito.Nexus project'
)
parser.add_argument(
'targets',
nargs=argparse.REMAINDER,
help='Make targets and options to pass to `make`'
)
args = parser.parse_args()
# Default to 'build' if no target is specified
make_args = args.targets or ['build']
# Determine repository root (one level up from cli/)
script_dir = os.path.dirname(os.path.realpath(__file__))
repo_root = os.path.abspath(os.path.join(script_dir, os.pardir))
# Check for Makefile
makefile_path = os.path.join(repo_root, 'Makefile')
if not os.path.isfile(makefile_path):
print(f"Error: Makefile not found in {repo_root}", file=sys.stderr)
sys.exit(1)
# Invoke make in repo root
cmd = ['make'] + make_args
try:
result = subprocess.run(cmd, cwd=repo_root)
sys.exit(result.returncode)
except FileNotFoundError:
print("Error: 'make' command not found. Please install make.", file=sys.stderr)
sys.exit(1)
except KeyboardInterrupt:
sys.exit(1)
if __name__ == '__main__':
main()

0
cli/meta/__init__.py Normal file
View File

View File

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env python3
# cli/meta/applications/all.py
import argparse
import sys
# Import the Ansible filter implementation
try:
from filter_plugins.get_all_application_ids import get_all_application_ids
except ImportError:
sys.stderr.write("Filter plugin `get_all_application_ids` not found. Ensure `filter_plugins/get_all_application_ids.py` is in your PYTHONPATH.\n")
sys.exit(1)
def find_application_ids():
"""
Legacy function retained for reference.
Delegates to the `get_all_application_ids` filter plugin.
"""
return get_all_application_ids()
def main():
parser = argparse.ArgumentParser(
description='Output a list of all application_id values defined in roles/*/vars/main.yml'
)
parser.parse_args()
try:
ids = find_application_ids()
except Exception as e:
sys.stderr.write(f"Error retrieving application IDs: {e}\n")
sys.exit(1)
for app_id in ids:
print(app_id)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""
CLI wrapper for applications_if_group_and_deps filter.
"""
import argparse
import sys
import os
import yaml
from filter_plugins.applications_if_group_and_deps import FilterModule
def find_role_dirs_by_app_id(app_ids, roles_dir):
"""
Map application_ids to role directory names based on vars/main.yml in each role.
"""
mapping = {}
for role in os.listdir(roles_dir):
role_path = os.path.join(roles_dir, role)
vars_file = os.path.join(role_path, 'vars', 'main.yml')
if not os.path.isfile(vars_file):
continue
try:
with open(vars_file) as f:
data = yaml.safe_load(f) or {}
except Exception:
continue
app_id = data.get('application_id')
if isinstance(app_id, str) and app_id:
mapping[app_id] = role
# Translate each requested app_id to role dir if exists
dirs = []
for gid in app_ids:
if gid in mapping:
dirs.append(mapping[gid])
else:
# keep original if it matches a directory
if os.path.isdir(os.path.join(roles_dir, gid)):
dirs.append(gid)
return dirs
def main():
parser = argparse.ArgumentParser(
description="Filter applications by group names (role dirs or application_ids) and their recursive role dependencies."
)
parser.add_argument(
"-a", "--applications",
type=str,
required=True,
help="Path to YAML file defining the applications dict."
)
parser.add_argument(
"-g", "--groups",
nargs='+',
required=True,
help="List of group names to filter by (role directory names or application_ids)."
)
args = parser.parse_args()
# Load applications
try:
with open(args.applications) as f:
data = yaml.safe_load(f)
except Exception as e:
print(f"Error loading applications file: {e}", file=sys.stderr)
sys.exit(1)
# Unwrap under 'applications' key if present
if isinstance(data, dict) and 'applications' in data and isinstance(data['applications'], dict):
applications = data['applications']
else:
applications = data
if not isinstance(applications, dict):
print(
f"Expected applications YAML to contain a mapping (or 'applications' mapping), got {type(applications).__name__}",
file=sys.stderr
)
sys.exit(1)
# Determine roles_dir relative to project root
script_dir = os.path.dirname(__file__)
project_root = os.path.abspath(os.path.join(script_dir, '..', '..', '..'))
roles_dir = os.path.join(project_root, 'roles')
# Map user-provided groups (which may be application_ids) to role directory names
group_dirs = find_role_dirs_by_app_id(args.groups, roles_dir)
if not group_dirs:
print(f"No matching role directories found for groups: {args.groups}", file=sys.stderr)
sys.exit(1)
# Run filter using role directory names
try:
filtered = FilterModule().applications_if_group_and_deps(
applications,
group_dirs
)
except Exception as e:
print(f"Error running filter: {e}", file=sys.stderr)
sys.exit(1)
# Output result as YAML
print(yaml.safe_dump(filtered, default_flow_style=False))
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python3
# cli/meta/applications/invokable.py
import argparse
import sys
import os
# Import filter plugin for get_all_invokable_apps
try:
from filter_plugins.get_all_invokable_apps import get_all_invokable_apps
except ImportError:
# Try to adjust sys.path if running outside Ansible
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')))
try:
from filter_plugins.get_all_invokable_apps import get_all_invokable_apps
except ImportError:
sys.stderr.write("Could not import filter_plugins.get_all_invokable_apps. Check your PYTHONPATH.\n")
sys.exit(1)
def main():
parser = argparse.ArgumentParser(
description='List all invokable applications (application_ids) based on invokable paths from categories.yml and available roles.'
)
parser.add_argument(
'-c', '--categories-file',
default=os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'roles', 'categories.yml')),
help='Path to roles/categories.yml (default: roles/categories.yml at project root)'
)
parser.add_argument(
'-r', '--roles-dir',
default=os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'roles')),
help='Path to roles/ directory (default: roles/ at project root)'
)
args = parser.parse_args()
try:
result = get_all_invokable_apps(
categories_file=args.categories_file,
roles_dir=args.roles_dir
)
except Exception as e:
sys.stderr.write(f"Error: {e}\n")
sys.exit(1)
for app_id in result:
print(app_id)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,74 @@
#!/usr/bin/env python3
"""
CLI Script: get_role_folder_cli.py
This script determines the appropriate Ansible role folder based on the provided application_id
by inspecting each role's vars/main.yml within the roles directory. By default, it assumes the
roles directory is located at the project root, relative to this script's location.
"""
import os
import sys
import argparse
import yaml
def get_role(application_id, roles_path):
"""
Find the role directory under `roles_path` whose vars/main.yml contains the specified application_id.
:param application_id: The application_id to match.
:param roles_path: Path to the roles directory.
:return: The name of the matching role directory.
:raises RuntimeError: If no match is found or if an error occurs while reading files.
"""
if not os.path.isdir(roles_path):
raise RuntimeError(f"Roles path not found: {roles_path}")
for role in sorted(os.listdir(roles_path)):
role_dir = os.path.join(roles_path, role)
vars_file = os.path.join(role_dir, 'vars', 'main.yml')
if os.path.isfile(vars_file):
try:
with open(vars_file, 'r') as f:
data = yaml.safe_load(f) or {}
except Exception as e:
raise RuntimeError(f"Failed to load {vars_file}: {e}")
if data.get('application_id') == application_id:
return role
raise RuntimeError(f"No role found with application_id '{application_id}' in {roles_path}")
def main():
parser = argparse.ArgumentParser(
description='Determine the Ansible role folder by application_id'
)
parser.add_argument(
'application_id',
help='The application_id defined in vars/main.yml to search for'
)
parser.add_argument(
'-r', '--roles-path',
default=os.path.join(
os.path.dirname(os.path.realpath(__file__)),
os.pardir, os.pardir, os.pardir,
'roles'
),
help='Path to the roles directory (default: roles/ at project root)'
)
args = parser.parse_args()
try:
folder = get_role(args.application_id, args.roles_path)
print(folder)
sys.exit(0)
except RuntimeError as err:
print(f"Error: {err}", file=sys.stderr)
sys.exit(1)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""
CLI for extracting invokable or non-invokable role paths from a nested roles YAML file using argparse.
Assumes a default roles file at the project root if none is provided.
"""
import os
import sys
# ─── Determine project root ───
if "__file__" in globals():
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
else:
project_root = os.getcwd()
# Ensure project root on PYTHONPATH so 'filter_plugins' can be imported
sys.path.insert(0, project_root)
import argparse
import yaml
from filter_plugins.invokable_paths import get_invokable_paths, get_non_invokable_paths
def main():
parser = argparse.ArgumentParser(
description="Extract invokable or non-invokable role paths from a nested roles YAML file."
)
parser.add_argument(
"roles_file",
nargs='?',
default=None,
help="Path to the roles YAML file (default: roles/categories.yml at project root)"
)
parser.add_argument(
"--suffix", "-s",
help="Optional suffix to append to each path.",
default=None
)
mode_group = parser.add_mutually_exclusive_group()
mode_group.add_argument(
"--non-invokable", "-n",
action='store_true',
help="List paths where 'invokable' is False or not set."
)
mode_group.add_argument(
"--invokable", "-i",
action='store_true',
help="List paths where 'invokable' is True. (default behavior)"
)
args = parser.parse_args()
# Default to invokable if neither flag is provided
list_non = args.non_invokable
list_inv = args.invokable or not (args.non_invokable or args.invokable)
try:
if list_non:
paths = get_non_invokable_paths(args.roles_file, args.suffix)
else:
paths = get_invokable_paths(args.roles_file, args.suffix)
except FileNotFoundError as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
except yaml.YAMLError as e:
print(f"Error parsing YAML: {e}", file=sys.stderr)
sys.exit(1)
except ValueError as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
for p in paths:
print(p)
if __name__ == "__main__":
main()

0
cli/meta/j2/__init__.py Normal file
View File

76
cli/meta/j2/compiler.py Executable file
View File

@@ -0,0 +1,76 @@
#!/usr/bin/env python3
import argparse
import os
import re
import sys
# Projekt-Root: vier Ebenen über diesem File
PROJECT_ROOT = os.path.dirname(
os.path.dirname(
os.path.dirname(
os.path.dirname(__file__)
)
)
)
INCLUDE_RE = re.compile(r"^(\s*)\{%\s*include\s*['\"]([^'\"]+)['\"]\s*%\}")
def expand_includes(rel_path, seen=None):
"""
Liest die Datei rel_path (relative zum PROJECT_ROOT),
ersetzt rekursiv alle "{% include 'path' %}"-Zeilen durch den
Inhalt der jeweiligen Datei (mit gleicher Einrückung).
"""
if seen is None:
seen = set()
rp = rel_path.replace("\\", "/")
if rp in seen:
raise RuntimeError(f"Circular include detected: {rp}")
seen.add(rp)
abs_path = os.path.join(PROJECT_ROOT, rp)
if not os.path.isfile(abs_path):
raise FileNotFoundError(f"Template not found: {rp}")
output_lines = []
for line in open(abs_path, encoding="utf-8"):
m = INCLUDE_RE.match(line)
if not m:
output_lines.append(line.rstrip("\n"))
else:
indent, inc_rel = m.group(1), m.group(2)
# rekursiver Aufruf
for inc_line in expand_includes(inc_rel, seen):
output_lines.append(indent + inc_line)
seen.remove(rp)
return output_lines
def parse_args():
p = argparse.ArgumentParser(
description="Expand all {% include '...' %} directives in a Jinja2 template (no variable rendering)."
)
p.add_argument("template", help="Template path relative to project root")
p.add_argument(
"--out",
help="If given, write output to this file instead of stdout",
default=None
)
return p.parse_args()
def main():
args = parse_args()
try:
lines = expand_includes(args.template)
text = "\n".join(lines)
if args.out:
with open(args.out, "w", encoding="utf-8") as f:
f.write(text + "\n")
else:
print(text)
except Exception as e:
sys.stderr.write(f"Error: {e}\n")
sys.exit(1)
if __name__ == "__main__":
main()

0
cli/validate/__init__.py Normal file
View File

154
cli/validate/inventory.py Normal file
View File

@@ -0,0 +1,154 @@
#!/usr/bin/env python3
import argparse
import sys
import yaml
import re
from pathlib import Path
# Ensure imports work when run directly
script_dir = Path(__file__).resolve().parent
repo_root = script_dir.parent.parent
sys.path.insert(0, str(repo_root))
from cli.meta.applications.all import find_application_ids
def load_yaml_file(path):
try:
with open(path, 'r', encoding='utf-8') as f:
content = f.read()
content = re.sub(r'(?m)^([ \t]*[^\s:]+):\s*!vault[\s\S]+?(?=^\S|\Z)', r"\1: \"<vaulted>\"\n", content)
return yaml.safe_load(content)
except Exception as e:
print(f"Warning: Could not parse {path}: {e}", file=sys.stderr)
return None
def recursive_keys(d, prefix=''):
keys = set()
if isinstance(d, dict):
for k, v in d.items():
full = f"{prefix}.{k}" if prefix else k
keys.add(full)
keys.update(recursive_keys(v, full))
return keys
def compare_application_keys(applications, defaults, source):
errs = []
for app_id, conf in applications.items():
if app_id not in defaults:
errs.append(f"{source}: Unknown application '{app_id}' (not in defaults_applications)")
continue
default = defaults[app_id]
app_keys = recursive_keys(conf)
def_keys = recursive_keys(default)
for key in app_keys:
if key.startswith('credentials'):
continue
if key not in def_keys:
errs.append(f"{source}: Missing default for {app_id}: {key}")
return errs
def compare_user_keys(users, default_users, source):
errs = []
for user, conf in users.items():
if user not in default_users:
print(f"Warning: {source}: Unknown user '{user}' (not in default_users)", file=sys.stderr)
continue
def_conf = default_users[user]
for key in conf:
if key in ('password','credentials','mailu_token'):
continue
if key not in def_conf:
errs.append(f"Missing default for user '{user}': key '{key}'")
return errs
def load_inventory_files(inv_dir):
all_data = {}
p = Path(inv_dir)
for f in p.glob('*.yml'):
data = load_yaml_file(f)
if isinstance(data, dict):
apps = data.get('applications') or data.get('defaults_applications')
if apps:
all_data[str(f)] = apps
for d in p.glob('*_vars'):
if d.is_dir():
for f in d.rglob('*.yml'):
data = load_yaml_file(f)
if isinstance(data, dict):
apps = data.get('applications') or data.get('defaults_applications')
if apps:
all_data[str(f)] = apps
return all_data
def validate_host_keys(app_ids, inv_dir):
errs = []
p = Path(inv_dir)
# Scan all top-level YAMLs for 'all.children'
for f in p.glob('*.yml'):
data = load_yaml_file(f)
if not isinstance(data, dict):
continue
all_node = data.get('all', {})
children = all_node.get('children')
if not isinstance(children, dict):
continue
for grp in children.keys():
if grp not in app_ids:
errs.append(f"{f}: Invalid group '{grp}' (not in application_ids)")
return errs
def find_single_file(pattern):
c = list(Path('group_vars/all').glob(pattern))
if len(c)!=1:
raise RuntimeError(f"Expected exactly one {pattern} in group_vars/all, found {len(c)}")
return c[0]
def main():
p = argparse.ArgumentParser()
p.add_argument('inventory_dir')
args = p.parse_args()
# defaults
dfile = find_single_file('*_applications.yml')
ufile = find_single_file('*users.yml')
ddata = load_yaml_file(dfile) or {}
udata = load_yaml_file(ufile) or {}
defaults = ddata.get('defaults_applications',{})
default_users = udata.get('default_users',{})
if not defaults:
print(f"Error: No 'defaults_applications' found in {dfile}", file=sys.stderr)
sys.exit(1)
if not default_users:
print(f"Error: No 'default_users' found in {ufile}", file=sys.stderr)
sys.exit(1)
app_errs = []
inv_files = load_inventory_files(args.inventory_dir)
for src, apps in inv_files.items():
app_errs.extend(compare_application_keys(apps, defaults, src))
user_errs = []
for fpath in Path(args.inventory_dir).rglob('*.yml'):
data = load_yaml_file(fpath)
if isinstance(data, dict) and 'users' in data:
errs = compare_user_keys(data['users'], default_users, str(fpath))
for e in errs:
print(e, file=sys.stderr)
user_errs.extend(errs)
host_errs = validate_host_keys(find_application_ids(), args.inventory_dir)
app_errs.extend(host_errs)
if app_errs or user_errs:
if app_errs:
print('Validation failed with the following issues:')
for e in app_errs:
print(f"- {e}")
sys.exit(1)
print('Inventory directory is valid against defaults and hosts.')
sys.exit(0)
if __name__=='__main__':
main()

20
cli/vault.py Normal file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env python3
import argparse
import subprocess
def run_ansible_vault(action, filename, password_file):
cmd = ["ansible-vault", action, filename, "--vault-password-file", password_file]
subprocess.run(cmd, check=True)
def main():
parser = argparse.ArgumentParser(description="Manage Ansible Vault")
parser.add_argument("action", choices=["edit", "decrypt", "encrypt"], help="Vault action")
parser.add_argument("filename", help="File to process")
parser.add_argument("--password-file", required=True, help="Path to the Vault password file")
args = parser.parse_args()
run_ansible_vault(args.action, args.filename, args.password_file)
if __name__ == "__main__":
main()

58
docs/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,58 @@
# Infinito.Nexus Architecture
## Introduction
[Infinito.Nexus](https://infinito.nexus) is a modular, open-source IT infrastructure automation platform designed to simplify the deployment, management, and security of self-hosted environments.
It provides a flexible, scalable, and secure architecture based on modern [DevOps](https://en.wikipedia.org/wiki/DevOps) principles, leveraging technologies like [Ansible](https://en.wikipedia.org/wiki/Ansible_(software)), [Docker](https://en.wikipedia.org/wiki/Docker_(software)), and [Infrastructure as Code (IaC)](https://en.wikipedia.org/wiki/Infrastructure_as_code).
An additional optional security layer allows full server encryption during installation using [LUKS](https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup) based on this solution:
https://github.com/kevinveenbirkenbach/hetzner-arch-luks
---
## Key Points
- Modular role-based architecture
- Infrastructure-as-Code (IaC)
- Docker-based containerization
- Centralized Identity & Access Management (IAM)
- Security by Design
- Integration instead of forced migration
- Optional [full disk encryption](https://github.com/kevinveenbirkenbach/hetzner-arch-luks) layer for servers
## Architecture Layers
### 1. Automation Layer
- Ansible Playbooks & Roles
- Git-managed configuration repository
- Inventory-driven infrastructure definition
### 2. Container Orchestration Layer
- Docker Compose service deployment
- Per-role service templates
- Automated health checks & updates
### 3. Security & Identity Layer
- Centralized user management via LDAP
- Single Sign-On (SSO) with Keycloak
- Secrets management via Ansible Vault
### 4. Networking Layer
- Secure VPN via WireGuard & OpenVPN
- Nginx Reverse Proxy with automated TLS via Let's Encrypt
- Encrypted server setup using [hetzner-arch-luks](https://github.com/kevinveenbirkenbach/hetzner-arch-luks)
### 5. Application Layer
- Modular application roles (Nextcloud, Gitea, Matrix, etc.)
- Dynamic domain configuration
- Integration of external/legacy services into the platform
### 6. Monitoring & Maintenance Layer
- System health monitoring (BTRFS, Docker, Nginx)
- Automated backup roles (local/remote)
- Maintenance automation (cleanup, update, restart tasks)
---
> *Infinito.Nexus — Modular. Secure. Automated. Decentralized.*

124
docs/Docker.md Normal file
View File

@@ -0,0 +1,124 @@
# Docker Build Guide 🚢
This guide explains how to build the **Infinito.Nexus** Docker image with advanced options to avoid common issues (e.g. mirror timeouts) and control build caching.
---
## 1. Enable BuildKit (Optional but Recommended)
Modern versions of Docker support **BuildKit**, which speeds up build processes and offers better caching.
```bash
# On your host, enable BuildKit for the current shell session:
export DOCKER_BUILDKIT=1
```
> **Note:** You only need to set this once per terminal session.
---
## 2. Build Arguments Explained
When you encounter errors like:
```text
:: Synchronizing package databases...
error: failed retrieving file 'core.db' from geo.mirror.pkgbuild.com : Connection timed out after 10002 milliseconds
error: failed to synchronize all databases (failed to retrieve some files)
```
it usually means the default container network cannot reach certain Arch Linux mirrors. To work around this, use:
* `--network=host`
Routes all build-time network traffic through your hosts network stack.
* `--no-cache`
Forces a fresh build of every layer by ignoring Dockers layer cache. Useful if you suspect stale cache entries.
---
## 3. Recommended Build Command
```bash
# 1. (Optional) Enable BuildKit
export DOCKER_BUILDKIT=1
# 2. Build with host networking and no cache
docker build \
--network=host \
--no-cache \
-t infinito:latest \
.
```
**Flags:**
* `--network=host`
Ensures all `pacman -Syu` and other network calls hit your host network directly—eliminating mirror connection timeouts.
* `--no-cache`
Guarantees that changes to package lists or dependencies are picked up immediately by rebuilding every layer.
* `-t infinito:latest`
Tags the resulting image as `infinito:latest`.
---
## 4. Running the Container
Once built, you can run Infinito.Nexus as usual:
```bash
docker run --rm -it \
-v "$(pwd)":/opt/infinito \
-w /opt/infinito \
infinito:latest --help
```
Mount any host directory into `/opt/infinito/logs` to persist logs across runs.
---
## 5. Further Troubleshooting
* **Mirror selection:** If you still see slow or unreachable mirrors, consider customizing `/etc/pacman.d/mirrorlist` in a local Docker stage or on your host to prioritize faster mirrors.
* **Firewall or VPN:** Ensure your hosts firewall or VPN allows outgoing connections on port 443/80 to Arch mirror servers.
* **Docker daemon config:** On some networks, you may need to configure Dockers daemon proxy settings under `/etc/docker/daemon.json`.
## 6. Live Development via Volume Mount
The Infinito.Nexus installation inside the container always resides at:
```
/root/Repositories/github.com/kevinveenbirkenbach/infinito
```
To apply code changes without rebuilding the image, mount your local installation directory into that static path:
```bash
# 1. Determine the Infinito.Nexus install path on your host
INFINITO_PATH=$(pkgmgr path infinito)
# 2. Launch the container with a bind mount:
docker run --rm -it \
-v "${INFINITO_PATH}:/root/Repositories/github.com/kevinveenbirkenbach/infinito" \
-w "/root/Repositories/github.com/kevinveenbirkenbach/infinito" \
infinito:latest make build
```
Or, to test the CLI help interactively:
```bash
docker run --rm -it \
-v "${INFINITO_PATH}:/root/Repositories/github.com/kevinveenbirkenbach/infinito" \
-w "/root/Repositories/github.com/kevinveenbirkenbach/infinito" \
infinito:latest --help
```
Any edits you make in `${INFINITO_PATH}` on your host are immediately reflected inside the container, eliminating the need for repeated `docker build` cycles.
---
With these options, your Docker builds should complete reliably, even in restrictive network environments. Happy building! 🚀

2
docs/TODO.md Normal file
View File

@@ -0,0 +1,2 @@
# TODO
- Move this files to https://hub.cymais.cloud

View File

@@ -0,0 +1,38 @@
# Configuration
## Ansible Vault Basics
Infinito.Nexus uses Ansible Vault to protect sensitive data (e.g. passwords). Use these common commands:
### Edit an Encrypted File
```bash
ansible-vault edit <filename.yml> --vault-password-file <your-vault-pass-file>
```
### Decrypt a File
```bash
ansible-vault decrypt <filename.yml> --vault-password-file <your-vault-pass-file>
```
### Encrypt a File
```bash
ansible-vault encrypt <filename.yml> --vault-password-file <your-vault-pass-file>
```
### Encrypt a String
```bash
ansible-vault encrypt_string --vault-password-file <your-vault-pass-file> 'example' --name 'test'
```
## Password Generation
You can generate a secure random password and encrypt it with Ansible Vault. For example:
```bash
ansible-vault encrypt_string "$(cat /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 32)" --vault-password-file /path/to/your/vault_pass.txt | xclip -selection clipboard
```
This command generates a 32-character alphanumeric password, encrypts it, and copies the result to your clipboard.
## Final Notes
- **Customizing Paths and Variables:**
All file paths and configuration variables are defined in group variables (e.g., `group_vars/all/*.yml`) and role variable files. Adjust these to suit your deployment environment.

View File

@@ -0,0 +1,100 @@
# 🚀 Deployment Guide
This section explains how to deploy and manage **[Infinito.Nexus](https://infinito.nexus)** using Ansible. Infinito.Nexus uses a collection of Ansible tasks, which are controlled via different **"modes"** — such as **updates**, **backups**, **resets**, and **cleanup** operations.
---
## ✅ Prerequisites
Before deploying, ensure the following are in place:
- **🧭 Inventory File:** A valid Ansible inventory file that defines your target systems (servers, personal computers, etc.). Adjust example paths to your environment.
- **📦 Infinito.Nexus Installed:** Install via [Kevin's Package-Manager](https://github.com/kevinveenbirkenbach/package-manager).
- **🔐 (Optional) Vault Password File:** If you don't want to enter your vault password interactively, create a password file.
---
## 📘 Show Infinito.Nexus Help
To get a full overview of available options and usage instructions, run:
```bash
infinito --help
```
---
## 💡 Example Deploy Command
To deploy Infinito.Nexus on a personal computer (e.g., a laptop), you can run:
```bash
infinito playbook \
--limit hp-spectre-x360 \
--host-type personal-computer \
--update \
--password-file ~/Repositories/git.veen.world/kevinveenbirkenbach/computer-inventory/.pass/general.txt \
~/Repositories/git.veen.world/kevinveenbirkenbach/computer-inventory/pcs.yml
```
### 🧠 What does this command do?
| Parameter | Description |
|----------|-------------|
| `playbook` | Executes the playbook subcommand of Infinito.Nexus. |
| `--limit hp-spectre-x360` | Limits execution to a specific host (`hp-spectre-x360`). |
| `--host-type personal-computer` | Defines the host type. Default is `server`; here it is set to `personal-computer`. |
| `--update` | Enables update mode to apply software or configuration updates. |
| `--password-file` | Specifies the vault password file path for decrypting sensitive values. |
| `pcs.yml` | The path to the inventory file containing host definitions. |
---
## 🔐 Using a Vault Password File
To avoid typing your vault password interactively, you can provide a file:
```bash
--password-file /path/to/your/vault_pass.txt
```
> ⚠️ **Security Tip:** Ensure the password file is properly protected (e.g., `chmod 600 vault_pass.txt`).
---
## 🔍 Full Command-Line Reference
Heres a breakdown of all available parameters from `infinito playbook --help`:
| Argument | Description |
|----------|-------------|
| `inventory` *(positional)* | Path to the Ansible inventory file. |
| `--limit <HOST>` | Run the playbook only on the specified host. |
| `--host-type {server, personal-computer}` | Define the target system type (default is `server`). |
| `--reset` | Enables reset mode (restores or resets specific configurations). |
| `--test` | Enables test mode (dry-run style). No actual changes are applied. |
| `--update` | Enables update mode to upgrade packages or configs. |
| `--backup` | Triggers backup routines for data or configurations. |
| `--cleanup` | Cleans up temporary files, old data, etc. |
| `--debug` | Enables debug logging in the playbook. |
| `--password-file <PATH>` | Uses a vault password file instead of interactive prompt. |
| `-v, -vv, -vvv` | Increases output verbosity. More `v`s = more detail. |
---
## 🔧 Combine Multiple Modes
You can mix and match modes like this:
```bash
infinito playbook --update --backup --cleanup pcs.yml
```
This will update the system, create a backup, and clean up unnecessary files in one run.
---
## 📝 Footnote
> 📄 *This documentation page was generated with the help of AI.*
> 🤖 [View the original conversation (ChatGPT)](https://chatgpt.com/share/67ecfe25-3fb8-800f-923d-8cd3fc4efd2f)

View File

@@ -0,0 +1,22 @@
# Administrator Guide
This guide is for **system administrators** who are deploying and managing Infinito.Nexus infrastructure.
## Setting Up Infinito.Nexus 🏗️
Follow these guides to install and configure Infinito.Nexus:
- [Setup Guide](SETUP_GUIDE.md)
- [Configuration Guide](CONFIGURATION.md)
- [Deployment Guide](DEPLOY.md)
## Key Responsibilities 🔧
- **User Management** - Configure LDAP, Keycloak, and user permissions.
- **Security & Backups** - Set up `sys-bkp-rmt-2-loc`, `svc-bkp-loc-2-usb`, and `core-security` roles.
- **Application Hosting** - Deploy services like `Nextcloud`, `Matrix`, `Gitea`, and more.
- **Networking & VPN** - Configure `WireGuard`, `OpenVPN`, and `Nginx Reverse Proxy`.
## Managing & Updating Infinito.Nexus 🔄
- Regularly update services using `update-pacman`, or `update-apt`.
- Monitor system health with `sys-ctl-hlth-btrfs`, `sys-ctl-hlth-webserver`, and `sys-ctl-hlth-docker-container`.
- Automate system maintenance with `sys-lock`, `sys-ctl-cln-bkps`, and `sys-ctl-rpr-docker-hard`.
For more details, refer to the specific guides above.

View File

@@ -0,0 +1,29 @@
# Security Guidelines
Infinito.Nexus is designed with security in mind. However, while following our guidelines can greatly improve your systems security, no IT system can be 100% secure. Please report any vulnerabilities as soon as possible.
Additional to the user securitry guidelines administrators have additional responsibilities to secure the entire system:
- **Deploy on an Encrypted Server**
It is recommended to install Infinito.Nexus on an encrypted server to prevent hosting providers from accessing end-user data. For a practical guide on setting up an encrypted server, refer to the [Hetzner Arch LUKS repository](https://github.com/kevinveenbirkenbach/hetzner-arch-luks) 🔐. (Learn more about [disk encryption](https://en.wikipedia.org/wiki/Disk_encryption) on Wikipedia.)
- **Centralized User Management & SSO**
For robust authentication and central user management, set up Infinito.Nexus using Keycloak and LDAP.
This configuration enables centralized [Single Sign-On (SSO)](https://en.wikipedia.org/wiki/Single_sign-on) (SSO), simplifying user management and boosting security.
- **Enforce 2FA and Use a Password Manager**
Administrators should also enforce [2FA](https://en.wikipedia.org/wiki/Multi-factor_authentication) and use a password manager with auto-generated passwords. We again recommend [KeePass](https://keepass.info/). The KeePass database can be stored securely in your Nextcloud instance and synchronized between devices.
- **Avoid Root Logins & Plaintext Passwords**
Infinito.Nexus forbids logging in via the root user or using simple passwords. Instead, an SSH key must be generated and transferred during system initialization. When executing commands as root, always use `sudo` (or, if necessary, `sudo su`—but only if you understand the risks). (More information on [SSH](https://en.wikipedia.org/wiki/Secure_Shell) and [sudo](https://en.wikipedia.org/wiki/Sudo) is available on Wikipedia.)
- **Manage Inventories Securely**
Your inventories for running Infinito.Nexus should be managed in a separate repository and secured with tools such as [Ansible Vault](https://en.wikipedia.org/wiki/Encryption) 🔒. Sensitive credentials must never be stored in plaintext; use a password file to secure these details.
- **Reporting Vulnerabilities**
If you discover a security vulnerability in Infinito.Nexus, please report it immediately. We encourage proactive vulnerability reporting so that issues can be addressed as quickly as possible. Contact our security team at [security@infinito.nexus](mailto:security@infinito.nexus)
**DO NOT OPEN AN ISSUE.**
---
By following these guidelines, both end users and administrators can achieve a high degree of security. Stay vigilant, keep your systems updated, and report any suspicious activity. Remember: while we strive for maximum security, no system is completely infallible.

View File

@@ -0,0 +1,26 @@
# Setup Guide
To setup Infinito.Nexus follow this steps:
## Prerequisites
Before you setup Infinito.Nexus you need to install [Kevin's Package Manager](https://github.com/kevinveenbirkenbach/package-manager).
Follow the installation instruction descriped [here](https://github.com/kevinveenbirkenbach/package-manager)
## Setup Infinito.Nexus
To setup Infinito.Nexus execute:
```bash
pkgmgr install infinito
```
This command will setup Infinito.Nexus on your system with the alias **infinito**.
## Get Help
After you setuped Infinito.Nexus you can receive more help by executing:
```bash
infinito --help
```

View File

@@ -0,0 +1,111 @@
## 📖 Infinito.Nexus Ansible & Python Directory Guide
This document provides a **decision matrix** for when to use each default Ansible plugin and module directory in the context of **Infinito.Nexus development** with Ansible and Python. It links to official docs, explains use-cases, and points back to our conversation.
---
### 🔗 Links & References
* Official Ansible Plugin Guide: [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_plugins.html](https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html)
* Official Ansible Module Guide: [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_modules.html](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules.html)
* This conversation: [Link to this conversation](https://chat.openai.com/)
---
### 🛠️ Repo Layout & Default Directories
```plaintext
ansible-repo/
├── library/ # 📦 Custom Ansible modules
├── filter_plugins/ # 🔍 Custom Jinja2 filters
├── lookup_plugins/ # 👉 Custom lookup plugins
├── module_utils/ # 🛠️ Shared Python helpers for modules
├── action_plugins/ # ⚙️ Task-level orchestration logic
├── callback_plugins/ # 📣 Event callbacks (logging, notifications)
├── inventory_plugins/ # 🌐 Dynamic inventory sources
├── strategy_plugins/ # 🧠 Task execution strategies
└── ... # Other plugin dirs (connection, cache, etc.)
```
---
### 🎯 Decision Matrix: Which Folder for What?
| Folder | Type | Use-Case | Example (Infinito.Nexus) | Emoji |
| -------------------- | -------------------- | ---------------------------------------- | ----------------------------------------------------- | ----- |
| `library/` | **Module** | Write idempotent actions | `cloud_network.py`: manage VPCs, subnets | 📦 |
| `filter_plugins/` | **Filter plugin** | Jinja2 data transforms in templates/vars | `to_camel_case.py`: convert keys for API calls | 🔍 |
| `lookup_plugins/` | **Lookup plugin** | Fetch external/secure data at runtime | `vault_lookup.py`: pull secrets from Infinito.Nexus Vault | 👉 |
| `module_utils/` | **Utility library** | Shared Python code for modules | `infinito_client.py`: common API client base class | 🛠️ |
| `action_plugins/` | **Action plugin** | Complex task orchestration wrappers | `deploy_stack.py`: sequence Terraform + Ansible steps | ⚙️ |
| `callback_plugins/` | **Callback plugin** | Customize log/report behavior | `notify_slack.py`: send playbook status to Slack | 📣 |
| `inventory_plugins/` | **Inventory plugin** | Dynamic host/group sources | `azure_inventory.py`: list hosts from Azure tags | 🌐 |
| `strategy_plugins/` | **Strategy plugin** | Control task execution order/parallelism | `rolling_batch.py`: phased rollout of VMs | 🧠 |
---
### 📝 Detailed Guidance
1. **library/** 📦
* **When?** Implement **one-off, idempotent actions** (create/delete cloud resources).
* **Why?** Modules under `library/` are first in search path for `ansible` modules.
* **Docs:** [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_modules.html](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules.html)
2. **filter\_plugins/** 🔍
* **When?** You need **data manipulation** (lists, strings, dicts) inside Jinja2.
* **Why?** Extends `|` filters in templates and variable declarations.
* **Docs:** [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_plugins.html#filter-plugins](https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#filter-plugins)
3. **lookup\_plugins/** 👉
* **When?** You must **retrieve secret/external data** during playbook compile/runtime.
* **Why?** Lookup plugins run before tasks, enabling dynamic variable resolution.
* **Docs:** [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_plugins.html#lookup-plugins](https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#lookup-plugins)
4. **module\_utils/** 🛠️
* **When?** Multiple modules share **common Python code** (HTTP clients, validation).
* **Why?** Avoid code duplication; modules import these utilities.
* **Docs:** [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_modules.html#module-utils](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules.html#module-utils)
5. **action\_plugins/** ⚙️
* **When?** You need to **wrap or extend** module behavior at task invocation time.
* **Why?** Provides hooks before/after module execution.
* **Docs:** [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_plugins.html#action-plugins](https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#action-plugins)
6. **callback\_plugins/** 📣
* **When?** You want **custom event handlers** (logging, progress, notifications).
* **Why?** Receive play/task events for custom output.
* **Docs:** [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_plugins.html#callback-plugins](https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#callback-plugins)
7. **inventory\_plugins/** 🌐
* **When?** Hosts/groups come from **dynamic sources** (cloud APIs, databases).
* **Why?** Replace static `inventory.ini` with code-driven inventories.
* **Docs:** [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_plugins.html#inventory-plugins](https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#inventory-plugins)
8. **strategy\_plugins/** 🧠
* **When?** You need to **customize execution strategy** (parallelism, ordering).
* **Why?** Override default `linear` strategy (e.g., `free`, custom batches).
* **Docs:** [https://docs.ansible.com/ansible/latest/dev\_guide/developing\_plugins.html#strategy-plugins](https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#strategy-plugins)
---
### 🚀 Infinito.Nexus Best Practices
* **Organize modules** by service under `library/cloud/` (e.g., `vm`, `network`, `storage`).
* **Shared client code** in `module_utils/infinito/` for authentication, request handling.
* **Secrets lookup** via `lookup_plugins/vault_lookup.py` pointing to Infinito.Nexus Vault.
* **Filters** to normalize data formats from cloud APIs (e.g., `snake_to_camel`).
* **Callbacks** to stream playbook results into Infinito.Nexus Monitoring.
Use this matrix as your **single source of truth** when extending Ansible for Infinito.Nexus! 👍
---
This matrix was created with the help of ChatGPT 🤖—see our conversation [here](https://chatgpt.com/canvas/shared/682b1a62d6dc819184ecdc696c51290a).

View File

@@ -0,0 +1,53 @@
Developer Guide
===============
Welcome to the **Infinito.Nexus Developer Guide**! This guide provides essential information for developers who want to contribute to the Infinito.Nexus open-source project.
Explore Infinito.Nexus Solutions
------------------------
Infinito.Nexus offers various solutions for IT infrastructure automation. Learn more about the available applications:
- :doc:`../../../roles/application_glosar`
- :doc:`../../../roles/application_categories`
For Developers
--------------
Understanding Ansible Roles
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Infinito.Nexus is powered by **Ansible** roles to automate deployments. Developers can explore the technical details of our roles here:
- :doc:`../../../roles/ansible_role_glosar`
Contributing to Infinito.Nexus
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Want to contribute to the project or explore the source code? Check out our **GitHub repository**:
- `Infinito.Nexus GitHub Repository <https://s.infinito.nexus/code/tree/master/roles>`_
Contribution Guidelines
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1. **Fork the Repository** Start by forking the Infinito.Nexus repository.
2. **Create a New Branch** Make changes in a dedicated branch.
3. **Follow Coding Standards** Ensure your code is well-documented and follows best practices.
4. **Submit a Pull Request** Once your changes are tested, submit a PR for review.
For detailed guidelines, refer to:
- :doc:`../../../CONTRIBUTING`
- :doc:`../../../CODE_OF_CONDUCT`
Community & Support
-------------------
If you have questions or need help, visit the **Infinito.Nexus Information Hub**:
- `hub.infinito.nexus <https://hub.infinito.nexus>`_
This is the best place to ask questions, get support, and collaborate with other contributors.
Stay connected, collaborate, and help improve Infinito.Nexus together!
Happy coding! 🚀

View File

@@ -0,0 +1,17 @@
# Enterprise Guide
Are you looking for a **reliable IT infrastructure** for your business or organization? **Infinito.Nexus** is here to help!
## Who Can Benefit? 🎯
**Small & Medium Businesses** - IT infrastructure with everything included what you need. E.g. data clouds, mailservers, vpn's, homepages, documentation tools, etc.
**Enterprises** - Scale the solutions for Small & Medium Businesses up for an unlimeted amount of users
**NGOs & Organizations** - Secure, cost-effective infrastructure solutions on Open Source Base
**Journalists & Content Creators** - Host your content on your own servers, share it via the Fediverse and avoid cencorship
## Why Choose Infinito.Nexus? 🚀
- **Fast Deployment** - Get your IT setup running in minutes
- **Security First** - Encrypted backups, 2FA, and secure logins
- **Scalable & Customizable** - Adapts to your specific needs
- **Cost-Effective** - Open-source, no licensing fees
For enterprise solutions, check [Enterprise Solutions](10_ENTERPRISE_SOLUTIONS.md) or contact [Kevin Veen-Birkenbach](mailto:kevin@veen.world).

View File

@@ -0,0 +1,66 @@
# User Guide
Welcome to **Infinito.Nexus**! This guide is designed for **end-users** who want to use cloud services, email, and collaboration tools securely and efficiently. Whether you're an **enterprise user** or an **individual**, Infinito.Nexus provides a wide range of services tailored to your needs.
## What Can Infinito.Nexus Do for You? 💡
Infinito.Nexus enables you to securely and efficiently use a variety of **cloud-based applications**, including:
### 📂 Cloud Storage & File Sharing
- **Nextcloud** Securely store, sync, and share files across devices.
- **OnlyOffice** Work on documents, spreadsheets, and presentations directly within Nextcloud.
- **LibreOffice** A powerful office suite alternative to Microsoft Office.
### 💬 Secure Communication & Collaboration
- **Matrix (Element)** Encrypted messaging for teams and individuals.
- **XMPP** Secure instant messaging with various supported clients.
- **Mailu** A private, self-hosted email solution.
- **Etherpad** Real-time collaborative document editing.
- **BigBlueButton** Web conferencing with screen sharing and presentations.
- **Jitsi** Secure video conferencing without account requirements.
### 🎵 Social Media & Content Sharing
- **Mastodon** Decentralized microblogging platform (alternative to Twitter/X).
- **Pixelfed** Decentralized image sharing (alternative to Instagram).
- **Friendica** Social network supporting federation with Mastodon and others.
- **Peertube** Decentralized video streaming platform (alternative to YouTube).
- **Funkwhale** Self-hosted music streaming for individuals and communities.
### 🎮 Entertainment & Media
- **Jellyfin** Open-source media server for movies, TV, and music.
- **Kodi** Media center application with extensive plugin support.
- **qBittorrent** Open-source torrent client with secure remote access.
### 🔒 Privacy & Security
- **WireGuard** Secure and fast VPN solution.
- **Tor Browser** Browse the web anonymously and bypass censorship.
- **Bitwarden** Open-source password manager for secure credential storage.
- **2FA Authentication** Securely log in to your services with Two-Factor Authentication.
### 🔧 Developer & Productivity Tools
- **Gitea** Self-hosted Git repository management (alternative to GitHub/GitLab).
- **Jenkins** Automate software development pipelines.
- **Discourse** Community discussion forums for support and engagement.
- **MediaWiki** Create and manage knowledge bases and wikis.
## 🏢 Enterprise Users
### How to Get Started 🏁
If your organization provides Infinito.Nexus services, follow these steps:
- Your **administrator** will provide login credentials.
- Access **cloud services** via a web browser or mobile apps.
- For support, contact your **system administrator**.
## 🏠 Private Users
### How to Get Started 🏁
If you're an **individual user**, you can sign up for Infinito.Nexus services:
- **Register an account** at [infinito.nexus](https://infinito.nexus).
- Choose the applications and services you need.
- Follow the setup guide and start using Infinito.Nexus services immediately.
## 📚 Learn More
Discover more about Infinito.Nexus applications:
- :doc:`roles/application_glosar`
- :doc:`roles/application_categories`
For further information, visit our **[Information Hub](https://hub.infinito.nexus)** for tutorials, FAQs, and community support.
You can also register for updates and support from our community.

View File

@@ -0,0 +1,23 @@
# Security Guidelines
Infinito.Nexus is designed with security in mind. However, while following our guidelines can greatly improve your systems security, no IT system can be 100% secure. Please report any vulnerabilities as soon as possible.
For optimal personal security, we **strongly recommend** the following:
- **Use a Password Manager**
Use a reliable password manager such as [KeePass](https://keepass.info/) 🔐. (Learn more about [password managers](https://en.wikipedia.org/wiki/Password_manager) on Wikipedia.) KeePass is available for both smartphones and PCs, and it can automatically generate strong, random passwords.
- **Enable Two-Factor Authentication (2FA)**
Always enable 2FA whenever possible. Many password managers (like KeePass) can generate [TOTP](https://en.wikipedia.org/wiki/Time-based_One-Time_Password) tokens, adding an extra layer of security even if your password is compromised.
Synchronize your password database across devices using the [Nextcloud Client](https://nextcloud.com/) 📱💻.
- **Use Encrypted Systems**
We recommend running Infinito.Nexus only on systems with full disk encryption. For example, Linux distributions such as [Manjaro](https://manjaro.org/) (based on ArchLinux) with desktop environments like [GNOME](https://en.wikipedia.org/wiki/GNOME) provide excellent security. (Learn more about [disk encryption](https://en.wikipedia.org/wiki/Disk_encryption) on Wikipedia.)
- **Beware of Phishing and Social Engineering**
Always verify email senders, avoid clicking on unknown links, and never share your passwords or 2FA codes with anyone. (Learn more about [Phishing](https://en.wikipedia.org/wiki/Phishing) and [Social Engineering](https://en.wikipedia.org/wiki/Social_engineering_(security)) on Wikipedia.)
Following these guidelines will significantly enhance your personal security—but remember, no system is completely immune to risk.
A tutorial how to setup secure password management you will find [here](https://blog.veen.world/blog/2025/04/04/%f0%9f%9b%a1%ef%b8%8f-keepassxc-infinito-cloud-the-ultimate-guide-to-cross-device-password-security/)
---

27
filter_plugins/README.md Normal file
View File

@@ -0,0 +1,27 @@
# Custom Filter Plugins for Infinito.Nexus
This directory contains custom **Ansible filter plugins** used within the Infinito.Nexus project.
## When to Use a Filter Plugin
- **Transform values:** Use filters to transform, extract, reformat, or compute values from existing variables or facts.
- **Inline data manipulation:** Filters are designed for inline use in Jinja2 expressions (in templates, tasks, vars, etc.).
- **No external lookups:** Filters only operate on data you explicitly pass to them and cannot access external files, the Ansible inventory, or runtime context.
### Examples
```jinja2
{{ role_name | get_entity_name }}
{{ my_list | unique }}
{{ user_email | regex_replace('^(.+)@.*$', '\\1') }}
````
## When *not* to Use a Filter Plugin
* If you need to **load data from an external source** (e.g., file, environment, API), use a lookup plugin instead.
* If your logic requires **access to inventory, facts, or host-level information** that is not passed as a parameter.
## Further Reading
* [Ansible Filter Plugins Documentation](https://docs.ansible.com/ansible/latest/plugins/filter.html)
* [Developing Ansible Filter Plugins](https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#developing-filter-plugins)

View File

@@ -0,0 +1,44 @@
#!/usr/bin/env python3
# Provides a filter to control which applications (roles) should be deployed
from ansible.errors import AnsibleFilterError
def application_allowed(application_id: str, group_names: list, allowed_applications: list = []):
"""
Return True if:
- application_id exists in group_names, AND
- either allowed_applications is not provided (or empty), OR application_id is in allowed_applications.
Parameters:
application_id (str): Name of the application/role to check.
group_names (list): List of groups the current host belongs to.
allowed_applications (list, optional): List of application IDs to allow.
Returns:
bool: True if this application is allowed to deploy, False otherwise.
"""
# Ensure group_names is iterable
if not isinstance(group_names, (list, tuple)):
raise AnsibleFilterError(f"Expected group_names to be a list, str or tuple, got {type(group_names)}")
# Must be part of the host's groups
if application_id not in group_names:
return False
# If allowed_applications provided, only allow if ID is in that list
if allowed_applications:
if not isinstance(allowed_applications, (list, tuple, str)):
raise AnsibleFilterError(f"allowed_applications must be a list or tuple if provided, got {type(allowed_applications)}")
return application_id in allowed_applications
# No filter provided → allow all in group_names
return True
class FilterModule(object):
def filters(self):
return {
'application_allowed': application_allowed,
}

View File

@@ -0,0 +1,102 @@
from ansible.errors import AnsibleFilterError
import os
import yaml
class FilterModule(object):
def filters(self):
return {
'applications_if_group_and_deps': self.applications_if_group_and_deps,
}
def applications_if_group_and_deps(self, applications, group_names):
"""
Return only those applications whose key is either:
1) directly in group_names, or
2) the application_id of any role reachable (recursively)
from any group in group_names via meta/dependencies.
"""
self._validate_inputs(applications, group_names)
roles_dir = self._get_roles_directory()
included_roles = self._collect_reachable_roles(group_names, roles_dir)
included_app_ids = self._gather_application_ids(included_roles, roles_dir)
return self._filter_applications(applications, group_names, included_app_ids)
def _validate_inputs(self, applications, group_names):
"""Validate the inputs for correct types."""
if not isinstance(applications, dict):
raise AnsibleFilterError(f"Expected applications as dict, got {type(applications).__name__}")
if not isinstance(group_names, (list, tuple)):
raise AnsibleFilterError(f"Expected group_names as list/tuple, got {type(group_names).__name__}")
def _get_roles_directory(self):
"""Locate and return the roles directory."""
plugin_dir = os.path.dirname(__file__)
project_root = os.path.abspath(os.path.join(plugin_dir, '..'))
return os.path.join(project_root, 'roles')
def _collect_reachable_roles(self, group_names, roles_dir):
"""Recursively collect all roles reachable from the given groups via meta/dependencies."""
included_roles = set()
for group in group_names:
self._collect_roles_from_group(group, included_roles, roles_dir)
return included_roles
def _collect_roles_from_group(self, group, seen, roles_dir):
"""Recursively collect roles from a specific group."""
if group in seen:
return
seen.add(group)
meta_file = os.path.join(roles_dir, group, 'meta', 'main.yml')
if not os.path.isfile(meta_file):
return
try:
with open(meta_file) as f:
meta = yaml.safe_load(f) or {}
except Exception:
return
for dep in meta.get('dependencies', []):
dep_name = self._get_dependency_name(dep)
if dep_name:
self._collect_roles_from_group(dep_name, seen, roles_dir)
def _get_dependency_name(self, dependency):
"""Extract the dependency role name from the meta data."""
if isinstance(dependency, str):
return dependency
elif isinstance(dependency, dict):
return dependency.get('role') or dependency.get('name')
return None
def _gather_application_ids(self, included_roles, roles_dir):
"""Gather application_ids from the roles."""
included_app_ids = set()
for role in included_roles:
vars_file = os.path.join(roles_dir, role, 'vars', 'main.yml')
if not os.path.isfile(vars_file):
continue
try:
with open(vars_file) as f:
vars_data = yaml.safe_load(f) or {}
except Exception:
continue
app_id = vars_data.get('application_id')
if isinstance(app_id, str) and app_id:
included_app_ids.add(app_id)
return included_app_ids
def _filter_applications(self, applications, group_names, included_app_ids):
"""Filter and return the applications that match the conditions."""
result = {}
for app_key, cfg in applications.items():
if app_key in group_names or app_key in included_app_ids:
result[app_key] = cfg
return result

View File

@@ -0,0 +1,116 @@
from ansible.errors import AnsibleFilterError
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from module_utils.entity_name_utils import get_entity_name
from module_utils.role_dependency_resolver import RoleDependencyResolver
from typing import Iterable
class FilterModule(object):
def filters(self):
return {'canonical_domains_map': self.canonical_domains_map}
def canonical_domains_map(
self,
apps,
PRIMARY_DOMAIN,
*,
recursive: bool = False,
roles_base_dir: str | None = None,
seed: Iterable[str] | None = None,
):
"""
Build { app_id: [canonical domains...] }.
Rekursiv werden nur include_role, import_role und meta/main.yml:dependencies verfolgt.
'run_after' wird hier absichtlich ignoriert.
"""
if not isinstance(apps, dict):
raise AnsibleFilterError(f"'apps' must be a dict, got {type(apps).__name__}")
app_keys = set(apps.keys())
seed_keys = set(seed) if seed is not None else app_keys
if recursive:
roles_base_dir = roles_base_dir or os.path.join(os.getcwd(), "roles")
if not os.path.isdir(roles_base_dir):
raise AnsibleFilterError(
f"roles_base_dir '{roles_base_dir}' not found or not a directory."
)
resolver = RoleDependencyResolver(roles_base_dir)
discovered_roles = resolver.resolve_transitively(
start_roles=seed_keys,
resolve_include_role=True,
resolve_import_role=True,
resolve_dependencies=True,
resolve_run_after=False,
max_depth=None,
)
# all discovered roles that actually have config entries in `apps`
target_apps = discovered_roles & app_keys
else:
target_apps = seed_keys
result = {}
seen_domains = {}
for app_id in sorted(target_apps):
cfg = apps.get(app_id)
if cfg is None:
continue
if not str(app_id).startswith(("web-", "svc-db-")):
continue
if not isinstance(cfg, dict):
raise AnsibleFilterError(
f"Invalid configuration for application '{app_id}': expected dict, got {cfg!r}"
)
domains_cfg = cfg.get('server', {}).get('domains', {})
if not domains_cfg or 'canonical' not in domains_cfg:
self._add_default_domain(app_id, PRIMARY_DOMAIN, seen_domains, result)
continue
canonical_domains = domains_cfg['canonical']
self._process_canonical_domains(app_id, canonical_domains, seen_domains, result)
return result
def _add_default_domain(self, app_id, PRIMARY_DOMAIN, seen_domains, result):
entity_name = get_entity_name(app_id)
default_domain = f"{entity_name}.{PRIMARY_DOMAIN}"
if default_domain in seen_domains:
raise AnsibleFilterError(
f"Domain '{default_domain}' is already configured for "
f"'{seen_domains[default_domain]}' and '{app_id}'"
)
seen_domains[default_domain] = app_id
result[app_id] = [default_domain]
def _process_canonical_domains(self, app_id, canonical_domains, seen_domains, result):
if isinstance(canonical_domains, dict):
for _, domain in canonical_domains.items():
self._validate_and_check_domain(app_id, domain, seen_domains)
result[app_id] = canonical_domains.copy()
elif isinstance(canonical_domains, list):
for domain in canonical_domains:
self._validate_and_check_domain(app_id, domain, seen_domains)
result[app_id] = list(canonical_domains)
else:
raise AnsibleFilterError(
f"Unexpected type for 'server.domains.canonical' in application '{app_id}': "
f"{type(canonical_domains).__name__}"
)
def _validate_and_check_domain(self, app_id, domain, seen_domains):
if not isinstance(domain, str) or not domain.strip():
raise AnsibleFilterError(
f"Invalid domain entry in 'canonical' for application '{app_id}': {domain!r}"
)
if domain in seen_domains:
raise AnsibleFilterError(
f"Domain '{domain}' is already configured for '{seen_domains[domain]}' and '{app_id}'"
)
seen_domains[domain] = app_id

View File

@@ -0,0 +1,210 @@
from ansible.errors import AnsibleFilterError
import hashlib
import base64
import sys
import os
# Ensure module_utils is importable when this filter runs from Ansible
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from module_utils.config_utils import get_app_conf
from module_utils.get_url import get_url
class FilterModule(object):
"""
Custom filters for Content Security Policy generation and CSP-related utilities.
"""
def filters(self):
return {
'build_csp_header': self.build_csp_header,
}
# -------------------------------
# Helpers
# -------------------------------
@staticmethod
def is_feature_enabled(applications: dict, feature: str, application_id: str) -> bool:
"""
Returns True if applications[application_id].features[feature] is truthy.
"""
return get_app_conf(
applications,
application_id,
'features.' + feature,
False,
False
)
@staticmethod
def get_csp_whitelist(applications, application_id, directive):
"""
Returns a list of additional whitelist entries for a given directive.
Accepts both scalar and list in config; always returns a list.
"""
wl = get_app_conf(
applications,
application_id,
'server.csp.whitelist.' + directive,
False,
[]
)
if isinstance(wl, list):
return wl
if wl:
return [wl]
return []
@staticmethod
def get_csp_flags(applications, application_id, directive):
"""
Returns CSP flag tokens (e.g., "'unsafe-eval'", "'unsafe-inline'") for a directive,
merging sane defaults with app config.
Default: 'unsafe-inline' is enabled for style-src and style-src-elem.
"""
# Defaults that apply to all apps
default_flags = {}
if directive in ('style-src', 'style-src-elem'):
default_flags = {'unsafe-inline': True}
configured = get_app_conf(
applications,
application_id,
'server.csp.flags.' + directive,
False,
{}
)
# Merge defaults with configured flags (configured overrides defaults)
merged = {**default_flags, **configured}
tokens = []
for flag_name, enabled in merged.items():
if enabled:
tokens.append(f"'{flag_name}'")
return tokens
@staticmethod
def get_csp_inline_content(applications, application_id, directive):
"""
Returns inline script/style snippets to hash for a given directive.
Accepts both scalar and list in config; always returns a list.
"""
snippets = get_app_conf(
applications,
application_id,
'server.csp.hashes.' + directive,
False,
[]
)
if isinstance(snippets, list):
return snippets
if snippets:
return [snippets]
return []
@staticmethod
def get_csp_hash(content):
"""
Computes the SHA256 hash of the given inline content and returns
a CSP token like "'sha256-<base64>'".
"""
try:
digest = hashlib.sha256(content.encode('utf-8')).digest()
b64 = base64.b64encode(digest).decode('utf-8')
return f"'sha256-{b64}'"
except Exception as exc:
raise AnsibleFilterError(f"get_csp_hash failed: {exc}")
# -------------------------------
# Main builder
# -------------------------------
def build_csp_header(
self,
applications,
application_id,
domains,
web_protocol='https',
matomo_feature_name='matomo'
):
"""
Builds the Content-Security-Policy header value dynamically based on application settings.
- Flags (e.g., 'unsafe-eval', 'unsafe-inline') are read from server.csp.flags.<directive>,
with sane defaults applied in get_csp_flags (always 'unsafe-inline' for style-src and style-src-elem).
- Inline hashes are read from server.csp.hashes.<directive>.
- Whitelists are read from server.csp.whitelist.<directive>.
- Inline hashes are added only if the final tokens do NOT include 'unsafe-inline'.
"""
try:
directives = [
'default-src', # Fallback source list for content types not explicitly listed
'connect-src', # Allowed URLs for XHR, WebSockets, EventSource, fetch()
'frame-ancestors', # Who may embed this page
'frame-src', # Sources for nested browsing contexts (e.g., <iframe>)
'script-src', # Sources for script execution
'script-src-elem', # Sources for <script> elements
'style-src', # Sources for inline styles and <style>/<link> elements
'style-src-elem', # Sources for <style> and <link rel="stylesheet">
'font-src', # Sources for fonts
'worker-src', # Sources for workers
'manifest-src', # Sources for web app manifests
'media-src', # Sources for audio and video
]
parts = []
for directive in directives:
tokens = ["'self'"]
# 1) Load flags (includes defaults from get_csp_flags)
flags = self.get_csp_flags(applications, application_id, directive)
tokens += flags
# 2) Allow fetching from internal CDN by default for selected directives
if directive in ['script-src-elem', 'connect-src', 'style-src-elem']:
tokens.append(get_url(domains, 'web-svc-cdn', web_protocol))
# 3) Matomo integration if feature is enabled
if directive in ['script-src-elem', 'connect-src']:
if self.is_feature_enabled(applications, matomo_feature_name, application_id):
tokens.append(get_url(domains, 'web-app-matomo', web_protocol))
# 4) ReCaptcha integration (scripts + frames) if feature is enabled
if self.is_feature_enabled(applications, 'recaptcha', application_id):
if directive in ['script-src-elem', 'frame-src']:
tokens.append('https://www.gstatic.com')
tokens.append('https://www.google.com')
# 5) Frame ancestors handling (desktop + logout support)
if directive == 'frame-ancestors':
if self.is_feature_enabled(applications, 'desktop', application_id):
# Allow being embedded by the desktop app domain (and potentially its parent)
domain = domains.get('web-app-desktop')[0]
sld_tld = ".".join(domain.split(".")[-2:]) # e.g., example.com
tokens.append(f"{sld_tld}")
if self.is_feature_enabled(applications, 'logout', application_id):
# Allow embedding via logout proxy and Keycloak app
tokens.append(get_url(domains, 'web-svc-logout', web_protocol))
tokens.append(get_url(domains, 'web-app-keycloak', web_protocol))
# 6) Custom whitelist entries
tokens += self.get_csp_whitelist(applications, application_id, directive)
# 7) Add inline content hashes ONLY if final tokens do NOT include 'unsafe-inline'
# (Check tokens, not flags, to include defaults and later modifications.)
if "'unsafe-inline'" not in tokens:
for snippet in self.get_csp_inline_content(applications, application_id, directive):
tokens.append(self.get_csp_hash(snippet))
# Append directive
parts.append(f"{directive} {' '.join(tokens)};")
# 8) Static img-src directive (kept permissive for data/blob and any host)
parts.append("img-src * data: blob:;")
return ' '.join(parts)
except Exception as exc:
raise AnsibleFilterError(f"build_csp_header failed: {exc}")

View File

@@ -0,0 +1,31 @@
from ansible.errors import AnsibleFilterError
import copy
def append_csp_hash(applications, application_id, code_one_liner):
"""
Ensures that applications[application_id].csp.hashes['script-src-elem']
exists and appends the given one-liner (if not already present).
"""
if not isinstance(applications, dict):
raise AnsibleFilterError("`applications` must be a dict")
if application_id not in applications:
raise AnsibleFilterError(f"Unknown application_id: {application_id}")
apps = copy.deepcopy(applications)
app = apps[application_id]
server = app.setdefault('server', {})
csp = server.setdefault('csp', {})
hashes = csp.setdefault('hashes', {})
existing = hashes.get('script-src-elem', [])
if code_one_liner not in existing:
existing.append(code_one_liner)
hashes['script-src-elem'] = existing
return apps
class FilterModule(object):
def filters(self):
return {
'append_csp_hash': append_csp_hash
}

View File

@@ -0,0 +1,25 @@
class FilterModule(object):
''' Custom filter to safely check if a docker service is enabled for an application_id '''
def filters(self):
return {
'is_docker_service_enabled': self.is_docker_service_enabled
}
@staticmethod
def is_docker_service_enabled(applications, application_id, service_name):
"""
Returns True if applications[application_id].docker.services[service_name].enabled is truthy,
otherwise returns False (even if intermediate keys are missing).
"""
try:
return bool(
applications
and application_id in applications
and applications[application_id].get('docker', {})
.get('services', {})
.get(service_name, {})
.get('enabled', False)
)
except Exception:
return False

View File

@@ -0,0 +1,97 @@
from ansible.errors import AnsibleFilterError
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from module_utils.entity_name_utils import get_entity_name
class FilterModule(object):
def filters(self):
return {'domain_mappings': self.domain_mappings}
def domain_mappings(self, apps, PRIMARY_DOMAIN):
"""
Build a flat list of redirect mappings for all apps:
- source: each alias domain
- target: the first canonical domain
Skip mappings where source == target, since they make no sense.
"""
def parse_entry(domains_cfg, key, app_id):
if key not in domains_cfg:
return None
entry = domains_cfg[key]
if isinstance(entry, dict):
values = list(entry.values())
elif isinstance(entry, list):
values = entry
else:
raise AnsibleFilterError(
f"Unexpected type for 'domains.{key}' in application '{app_id}': {type(entry).__name__}"
)
for d in values:
if not isinstance(d, str) or not d.strip():
raise AnsibleFilterError(
f"Invalid domain entry in '{key}' for application '{app_id}': {d!r}"
)
return values
def default_domain(app_id:str, primary:str):
subdomain = get_entity_name(app_id)
return f"{subdomain}.{primary}"
# 1) Compute canonical domains per app (always as a list)
canonical_map = {}
for app_id, cfg in apps.items():
domains_cfg = cfg.get('server',{}).get('domains',{})
entry = domains_cfg.get('canonical')
if entry is None:
canonical_map[app_id] = [default_domain(app_id, PRIMARY_DOMAIN)]
elif isinstance(entry, dict):
canonical_map[app_id] = list(entry.values())
elif isinstance(entry, list):
canonical_map[app_id] = list(entry)
else:
raise AnsibleFilterError(
f"Unexpected type for 'server.domains.canonical' in application '{app_id}': {type(entry).__name__}"
)
# 2) Compute alias domains per app
alias_map = {}
for app_id, cfg in apps.items():
domains_cfg = cfg.get('server',{}).get('domains',{})
if domains_cfg is None:
alias_map[app_id] = []
continue
if isinstance(domains_cfg, dict) and not domains_cfg:
alias_map[app_id] = [default_domain(app_id, PRIMARY_DOMAIN)]
continue
aliases = parse_entry(domains_cfg, 'aliases', app_id) or []
default = default_domain(app_id, PRIMARY_DOMAIN)
has_aliases = 'aliases' in domains_cfg
has_canonical = 'canonical' in domains_cfg
if has_aliases:
if default not in aliases:
aliases.append(default)
elif has_canonical:
canon = canonical_map.get(app_id, [])
if default not in canon and default not in aliases:
aliases.append(default)
alias_map[app_id] = aliases
# 3) Build flat list of {source, target} entries,
# skipping self-mappings
mappings = []
for app_id, sources in alias_map.items():
canon_list = canonical_map.get(app_id, [])
target = canon_list[0] if canon_list else default_domain(app_id, PRIMARY_DOMAIN)
for src in sources:
if src == target:
# skip self-redirects
continue
mappings.append({
'source': src,
'target': target
})
return mappings

View File

@@ -0,0 +1,19 @@
# filter_plugins/domain_tools.py
# Returns the DNS zone (SLD.TLD) from a hostname.
# Pure-Python, no external deps; handles simple cases. For exotic TLDs use tldextract (see note).
from ansible.errors import AnsibleFilterError
def to_zone(hostname: str) -> str:
if not isinstance(hostname, str) or not hostname.strip():
raise AnsibleFilterError("to_zone: hostname must be a non-empty string")
parts = hostname.strip(".").split(".")
if len(parts) < 2:
raise AnsibleFilterError(f"to_zone: '{hostname}' has no TLD part")
# naive default: last two labels -> SLD.TLD
return ".".join(parts[-2:])
class FilterModule(object):
def filters(self):
return {
"to_zone": to_zone,
}

View File

@@ -0,0 +1,31 @@
from ansible.errors import AnsibleFilterError
class FilterModule(object):
def filters(self):
return {'generate_all_domains': self.generate_all_domains}
def generate_all_domains(self, domains_dict, include_www=True):
"""
Transform a dict of domains (values: str, list, dict) into a flat list,
optionally add 'www.' prefixes, dedupe and sort alphabetically.
"""
# lokaler Helfer zum Flatten
def _flatten(domains):
flat = []
for v in (domains or {}).values():
if isinstance(v, str):
flat.append(v)
elif isinstance(v, list):
flat.extend(v)
elif isinstance(v, dict):
flat.extend(v.values())
return flat
try:
flat = _flatten(domains_dict)
if include_www:
original = list(flat)
flat.extend([f"www.{d}" for d in original])
return sorted(set(flat))
except Exception as exc:
raise AnsibleFilterError(f"generate_all_domains failed: {exc}")

View File

@@ -0,0 +1,44 @@
import re
from ansible.errors import AnsibleFilterError
class FilterModule(object):
def filters(self):
return {'generate_base_sld_domains': self.generate_base_sld_domains}
def generate_base_sld_domains(self, domains_list):
"""
Given a list of hostnames, extract the second-level domain (SLD.TLD) for any hostname
with two or more labels, return single-label hostnames as-is, and reject IPs,
empty or malformed strings, and non-strings. Deduplicate and sort.
"""
if not isinstance(domains_list, list):
raise AnsibleFilterError(
f"generate_base_sld_domains expected a list, got {type(domains_list).__name__}"
)
ip_pattern = re.compile(r'^\d{1,3}(?:\.\d{1,3}){3}$')
results = set()
for hostname in domains_list:
# type check
if not isinstance(hostname, str):
raise AnsibleFilterError(f"Invalid domain entry (not a string): {hostname!r}")
# malformed or empty
if not hostname or hostname.startswith('.') or hostname.endswith('.') or '..' in hostname:
raise AnsibleFilterError(f"Invalid domain entry (malformed): {hostname!r}")
# IP addresses disallowed
if ip_pattern.match(hostname):
raise AnsibleFilterError(f"IP addresses not allowed: {hostname!r}")
# single-label hostnames
labels = hostname.split('.')
if len(labels) == 1:
results.add(hostname)
else:
# always keep only the last two labels (SLD.TLD)
sld = ".".join(labels[-2:])
results.add(sld)
return sorted(results)

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env python3
# filter_plugins/get_all_application_ids.py
import glob
import os
import yaml
def get_all_application_ids(roles_dir='roles'):
"""
Ansible filter to retrieve all unique application_id values
defined in roles/*/vars/main.yml files.
:param roles_dir: Base directory for Ansible roles (default: 'roles')
:return: Sorted list of unique application_id strings
"""
pattern = os.path.join(roles_dir, '*', 'vars', 'main.yml')
app_ids = []
for filepath in glob.glob(pattern):
try:
with open(filepath, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
except Exception:
continue
if isinstance(data, dict) and 'application_id' in data:
app_ids.append(data['application_id'])
return sorted(set(app_ids))
class FilterModule(object):
"""
Ansible filter plugin for retrieving application IDs.
"""
def filters(self):
return {
'get_all_application_ids': get_all_application_ids
}

View File

@@ -0,0 +1,54 @@
import os
import yaml
def get_all_invokable_apps(
categories_file=None,
roles_dir=None
):
"""
Return all application_ids (or role names) for roles whose directory names match invokable paths from categories.yml.
:param categories_file: Path to categories.yml (default: roles/categories.yml at project root)
:param roles_dir: Path to roles directory (default: roles/ at project root)
:return: List of application_ids (or role names)
"""
# Resolve defaults
here = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.abspath(os.path.join(here, '..'))
if not categories_file:
categories_file = os.path.join(project_root, 'roles', 'categories.yml')
if not roles_dir:
roles_dir = os.path.join(project_root, 'roles')
# Get invokable paths
from filter_plugins.invokable_paths import get_invokable_paths
invokable_paths = get_invokable_paths(categories_file)
if not invokable_paths:
return []
result = []
if not os.path.isdir(roles_dir):
return []
for role in sorted(os.listdir(roles_dir)):
role_path = os.path.join(roles_dir, role)
if not os.path.isdir(role_path):
continue
if any(role == p or role.startswith(p + '-') for p in invokable_paths):
vars_file = os.path.join(role_path, 'vars', 'main.yml')
if os.path.isfile(vars_file):
try:
with open(vars_file, 'r', encoding='utf-8') as f:
data = yaml.safe_load(f) or {}
app_id = data.get('application_id', role)
except Exception:
app_id = role
else:
app_id = role
result.append(app_id)
return sorted(result)
class FilterModule(object):
def filters(self):
return {
'get_all_invokable_apps': get_all_invokable_apps
}

View File

@@ -0,0 +1,10 @@
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from module_utils.config_utils import get_app_conf, AppConfigKeyError,ConfigEntryNotSetError
class FilterModule(object):
''' Infinito.Nexus application config extraction filters '''
def filters(self):
return {
'get_app_conf': get_app_conf,
}

View File

@@ -0,0 +1,31 @@
# Custom Ansible filter to get all role names under "roles/" with a given prefix.
import os
def get_category_entries(prefix, roles_path="roles"):
"""
Returns a list of role names under the given roles_path
that start with the specified prefix.
:param prefix: String prefix to match role names.
:param roles_path: Path to the roles directory (default: 'roles').
:return: List of matching role names.
"""
if not os.path.isdir(roles_path):
return []
roles = []
for entry in os.listdir(roles_path):
full_path = os.path.join(roles_path, entry)
if os.path.isdir(full_path) and entry.startswith(prefix):
roles.append(entry)
return sorted(roles)
class FilterModule(object):
""" Custom filters for Ansible """
def filters(self):
return {
"get_category_entries": get_category_entries
}

View File

@@ -0,0 +1,19 @@
def get_docker_image(applications, application_id, image_key:str=None):
image_key = image_key if image_key else application_id
docker = applications.get(application_id, {}).get("docker", {})
version = docker.get("versions", {}).get(image_key)
image = docker.get("images", {}).get(image_key)
if not image:
raise ValueError(f"Missing image for {application_id}:{image_key}")
if not version:
raise ValueError(f"Missing version for {application_id}:{image_key}")
return f"{image}:{version}"
class FilterModule(object):
def filters(self):
return {
'get_docker_image': get_docker_image,
}

View File

@@ -0,0 +1,33 @@
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from module_utils.entity_name_utils import get_entity_name
def get_docker_paths(application_id: str, path_docker_compose_instances: str) -> dict:
"""
Build the docker_compose dict based on
path_docker_compose_instances and application_id.
Uses get_entity_name to extract the entity name from application_id.
"""
entity = get_entity_name(application_id)
base = f"{path_docker_compose_instances}{entity}/"
return {
'directories': {
'instance': base,
'env': f"{base}.env/",
'services': f"{base}services/",
'volumes': f"{base}volumes/",
'config': f"{base}config/",
},
'files': {
'env': f"{base}.env/env",
'docker_compose': f"{base}docker-compose.yml",
'dockerfile': f"{base}Dockerfile",
}
}
class FilterModule(object):
def filters(self):
return {
'get_docker_paths': get_docker_paths,
}

View File

@@ -0,0 +1,19 @@
#!/usr/bin/python
import os
import sys
from ansible.errors import AnsibleFilterError
class FilterModule(object):
def filters(self):
plugin_dir = os.path.dirname(__file__)
project_root = os.path.dirname(plugin_dir)
module_utils = os.path.join(project_root, 'module_utils')
if module_utils not in sys.path:
sys.path.append(module_utils)
try:
from domain_utils import get_domain
except ImportError as e:
raise AnsibleFilterError(f"could not import domain_utils: {e}")
return {'get_domain': get_domain}

View File

@@ -0,0 +1,9 @@
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from module_utils.entity_name_utils import get_entity_name
class FilterModule(object):
def filters(self):
return {
'get_entity_name': get_entity_name,
}

View File

@@ -0,0 +1,48 @@
'''
Ansible filter plugin: get_role
This filter inspects each role under the given roles directory, loads its vars/main.yml,
and returns the role folder name whose application_id matches the provided value.
'''
from ansible.errors import AnsibleFilterError
import os
import yaml
def get_role(application_id, roles_path='roles'):
"""
Find the role directory under `roles_path` whose vars/main.yml contains the given application_id.
:param application_id: The application_id to match.
:param roles_path: Path to the roles directory (default: 'roles').
:return: The name of the matching role directory.
:raises AnsibleFilterError: If vars file is unreadable or no match is found.
"""
if not os.path.isdir(roles_path):
raise AnsibleFilterError(f"Roles path not found: {roles_path}")
for role in os.listdir(roles_path):
role_dir = os.path.join(roles_path, role)
vars_file = os.path.join(role_dir, 'vars', 'main.yml')
if os.path.isfile(vars_file):
try:
with open(vars_file, 'r') as f:
data = yaml.safe_load(f) or {}
except Exception as e:
raise AnsibleFilterError(f"Failed to load {vars_file}: {e}")
if data.get('application_id') == application_id:
return role
raise AnsibleFilterError(f"No role found with application_id '{application_id}' in {roles_path}")
class FilterModule(object):
"""
Register the get_role filter
"""
def filters(self):
return {
'get_role': get_role,
}

View File

@@ -0,0 +1,37 @@
"""
Custom Ansible filter to build a systemctl unit name (always lowercase).
Rules:
- If `systemctl_id` ends with '@': drop the '@' and return
"{systemctl_id_without_at}.{software_name}@{suffix_handling}".
- Else: return "{systemctl_id}.{software_name}{suffix_handling}".
Suffix handling:
- Default "" → automatically pick:
- ".service" if no '@' in systemctl_id
- ".timer" if '@' in systemctl_id
- Explicit False → no suffix at all
- Any string → ".{suffix}" (lowercased)
"""
def get_service_name(systemctl_id, software_name, suffix=""):
sid = str(systemctl_id).strip().lower()
software_name = str(software_name).strip().lower()
# Determine suffix
if suffix is False:
sfx = "" # no suffix at all
elif suffix == "" or suffix is None:
sfx = ".service"
else:
sfx = str(suffix).strip().lower()
if sid.endswith("@"):
base = sid[:-1] # drop the trailing '@'
return f"{base}.{software_name}@{sfx}"
else:
return f"{sid}.{software_name}{sfx}"
class FilterModule(object):
def filters(self):
return {"get_service_name": get_service_name}

View File

@@ -0,0 +1,24 @@
# filter_plugins/get_service_script_path.py
# Custom Ansible filter to generate service script paths.
def get_service_script_path(systemctl_id, script_type):
"""
Build the path to a service script based on systemctl_id and type.
:param systemctl_id: The identifier of the system service.
:param script_type: The script type/extension (e.g., sh, py, yml).
:return: The full path string.
"""
if not systemctl_id or not script_type:
raise ValueError("Both systemctl_id and script_type are required")
return f"/opt/scripts/systemctl/{systemctl_id}/script.{script_type}"
class FilterModule(object):
""" Custom filters for Ansible """
def filters(self):
return {
"get_service_script_path": get_service_script_path
}

11
filter_plugins/get_url.py Normal file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/python
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from module_utils.get_url import get_url
class FilterModule(object):
''' Infinito.Nexus application config extraction filters '''
def filters(self):
return {
'get_url': get_url,
}

14
filter_plugins/has_env.py Normal file
View File

@@ -0,0 +1,14 @@
import os
def has_env(application_id, base_dir='.'):
"""
Check if env.j2 exists under roles/{{ application_id }}/templates/env.j2
"""
path = os.path.join(base_dir, 'roles', application_id, 'templates', 'env.j2')
return os.path.isfile(path)
class FilterModule(object):
def filters(self):
return {
'has_env': has_env,
}

View File

@@ -0,0 +1,113 @@
import os
import yaml
from typing import Dict, List, Optional
def get_invokable_paths(
roles_file: Optional[str] = None,
suffix: Optional[str] = None
) -> List[str]:
"""
Load nested roles YAML and return dash-joined paths where 'invokable' is True. Appends suffix if provided.
"""
if not roles_file:
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(script_dir)
roles_file = os.path.join(project_root, 'roles', 'categories.yml')
try:
with open(roles_file, 'r') as f:
data = yaml.safe_load(f) or {}
except FileNotFoundError:
raise FileNotFoundError(f"Roles file not found: {roles_file}")
except yaml.YAMLError as e:
raise yaml.YAMLError(f"Error parsing YAML {roles_file}: {e}")
if not isinstance(data, dict):
raise ValueError("YAML root is not a dictionary")
roles = data
if 'roles' in roles and isinstance(roles['roles'], dict) and len(roles) == 1:
roles = roles['roles']
def _recurse(subroles: Dict[str, dict], parent: List[str] = None) -> List[str]:
parent = parent or []
found: List[str] = []
METADATA = {'title', 'description', 'icon', 'invokable'}
for key, cfg in subroles.items():
path = parent + [key]
if cfg.get('invokable', False):
p = '-'.join(path)
if suffix:
p += suffix
found.append(p)
children = {
ck: cv for ck, cv in cfg.items()
if ck not in METADATA and isinstance(cv, dict)
}
if children:
found.extend(_recurse(children, path))
return found
return _recurse(roles)
def get_non_invokable_paths(
roles_file: Optional[str] = None,
suffix: Optional[str] = None
) -> List[str]:
"""
Load nested roles YAML and return dash-joined paths where 'invokable' is False or missing.
Appends suffix if provided.
"""
if not roles_file:
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(script_dir)
roles_file = os.path.join(project_root, 'roles', 'categories.yml')
try:
with open(roles_file, 'r') as f:
data = yaml.safe_load(f) or {}
except FileNotFoundError:
raise FileNotFoundError(f"Roles file not found: {roles_file}")
except yaml.YAMLError as e:
raise yaml.YAMLError(f"Error parsing YAML {roles_file}: {e}")
if not isinstance(data, dict):
raise ValueError("YAML root is not a dictionary")
roles = data
if 'roles' in roles and isinstance(roles['roles'], dict) and len(roles) == 1:
roles = roles['roles']
def _recurse_non(subroles: Dict[str, dict], parent: List[str] = None) -> List[str]:
parent = parent or []
found: List[str] = []
METADATA = {'title', 'description', 'icon', 'invokable'}
for key, cfg in subroles.items():
path = parent + [key]
p = '-'.join(path)
inv = cfg.get('invokable', False)
if not inv:
entry = p + (suffix or "")
found.append(entry)
children = {
ck: cv for ck, cv in cfg.items()
if ck not in METADATA and isinstance(cv, dict)
}
if children:
found.extend(_recurse_non(children, path))
return found
return _recurse_non(roles)
class FilterModule:
def filters(self):
return {
'invokable_paths': get_invokable_paths,
'non_invokable_paths': get_non_invokable_paths
}

View File

@@ -0,0 +1,42 @@
# filter_plugins/merge_mapping.py
from ansible.errors import AnsibleFilterError
def merge_mapping(list1, list2, key_name='source'):
"""
Merge two lists of dicts on a given key.
- list1, list2: each must be a List[Dict]
- key_name: the field to match on
If both lists contain an item with the same key_name value,
their dictionaries are merged (fields from list2 overwrite or add to list1).
"""
if not isinstance(list1, list) or not isinstance(list2, list):
raise AnsibleFilterError("merge_mapping expects two lists")
merged = {}
# First, copy items from list1
for item in list1:
if key_name not in item:
raise AnsibleFilterError(f"Item {item} is missing the key '{key_name}'")
merged[item[key_name]] = item.copy()
# Then merge in items from list2
for item in list2:
if key_name not in item:
raise AnsibleFilterError(f"Item {item} is missing the key '{key_name}'")
k = item[key_name]
if k in merged:
# update will overwrite existing fields or add new ones
merged[k].update(item)
else:
merged[k] = item.copy()
# Return as a list of dicts again
return list(merged.values())
class FilterModule(object):
def filters(self):
return {
'merge_mapping': merge_mapping,
}

Some files were not shown because too many files have changed in this diff Show More