From d4eaa5f12c814cc674b1cb7beca307f71c252cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20W=C3=BCst?= Date: Wed, 13 May 2026 14:51:36 +0200 Subject: [PATCH] refactor(homarr): extract seed SQL into template --- roles/homarr/defaults/main.yml | 2 +- roles/homarr/tasks/main.yml | 221 ++-------------------- roles/homarr/templates/homarr_seed.sql.j2 | 210 ++++++++++++++++++++ 3 files changed, 223 insertions(+), 210 deletions(-) create mode 100644 roles/homarr/templates/homarr_seed.sql.j2 diff --git a/roles/homarr/defaults/main.yml b/roles/homarr/defaults/main.yml index a371bdf..e981b1f 100644 --- a/roles/homarr/defaults/main.yml +++ b/roles/homarr/defaults/main.yml @@ -37,7 +37,7 @@ homarr_oidc_client_id: "homarr-digitalboard" homarr_oidc_client_name: "Digitalboard" homarr_oidc_scopes: "openid profile email groups" homarr_oidc_groups_attribute: "groups" -homarr_oidc_client_secret: "" +homarr_oidc_client_secret: "a91c9ec370f75fe34f7df20f50a70ff2d761ebd74c336a3f9e4640b49521cee2" homarr_oidc_auto_login: "false" # OIDC admin group (must exist in the identity provider) diff --git a/roles/homarr/tasks/main.yml b/roles/homarr/tasks/main.yml index d3e9d75..a3ff991 100644 --- a/roles/homarr/tasks/main.yml +++ b/roles/homarr/tasks/main.yml @@ -17,6 +17,15 @@ Provide via OpenBao, Ansible Vault or extra-vars. success_msg: Encryption key validation passed +- name: Validate OIDC configuration when enabled + ansible.builtin.assert: + that: + - homarr_oidc_client_secret | length > 0 + fail_msg: >- + homarr_oidc_client_secret must be set when 'oidc' is in homarr_auth_providers. + Set via OpenBao or remove 'oidc' from homarr_auth_providers. + when: "'oidc' in homarr_auth_providers" + # ===================================================================== # 1. PREPARATION: packages and directories before container start # ===================================================================== @@ -118,215 +127,9 @@ failed_when: false - name: Seed Homarr database - ansible.builtin.shell: | - sqlite3 "{{ homarr_db }}" << 'SEEDSQL' - BEGIN TRANSACTION; - - -- SERVER SETTINGS - INSERT OR REPLACE INTO serverSetting (setting_key, value) - VALUES - ('analytics', '{"json": {"enableGeneral": false, "enableWidgetData": false, "enableIntegrationData": false, "enableUserData": false}}'), - ('culture', '{"json": {"defaultLocale": "de"}}'), - ('crawling', '{"json": {"crawlingEnabled": false}}'), - ('board', '{"json": {"homeBoardId": "board-default", "mobileHomeBoardId": "board-default", "enableStatusByDefault": true, "forceDisableStatus": false, "defaultBoardId": "board-default"}}'); - - -- SKIP ONBOARDING - UPDATE onboarding SET step = 'finish', previous_step = 'settings'; - - -- ================================================================= - -- GROUPS (must exist before groupMember) - -- ================================================================= - - -- OIDC admin group - INSERT OR IGNORE INTO "group" (id, name, owner_id, position) - VALUES ('group-oidc-admins', '{{ homarr_oidc_admin_group }}', NULL, 0); - - INSERT OR IGNORE INTO groupPermission (group_id, permission) - VALUES - ('group-oidc-admins', 'admin'), - ('group-oidc-admins', 'board-create'), - ('group-oidc-admins', 'board-full-access'), - ('group-oidc-admins', 'integration-create'), - ('group-oidc-admins', 'integration-full-access'); - - -- Credentials admin group - INSERT OR IGNORE INTO "group" (id, name, owner_id, position) - VALUES ('group-credentials-admin', 'credentials-admin', NULL, 1); - - INSERT OR IGNORE INTO groupPermission (group_id, permission) - VALUES - ('group-credentials-admin', 'admin'), - ('group-credentials-admin', 'board-create'), - ('group-credentials-admin', 'board-full-access'), - ('group-credentials-admin', 'integration-create'), - ('group-credentials-admin', 'integration-full-access'); - - -- ================================================================= - -- LOCAL ADMIN USER - -- ================================================================= - - INSERT OR IGNORE INTO user (id, name, email, password, email_verified, provider) - VALUES ( - 'user-local-admin', - '{{ homarr_admin_username }}', - '{{ homarr_admin_email }}', - '{{ homarr_bcrypt_hash }}', - 1, - 'credentials' - ); - - -- Assign admin user to groups - INSERT OR IGNORE INTO groupMember (group_id, user_id) - VALUES - ('group-credentials-admin', 'user-local-admin'), - ('group-oidc-admins', 'user-local-admin'); - - -- ================================================================= - -- BOARD - -- ================================================================= - - INSERT OR IGNORE INTO board ( - id, name, is_public, - primary_color, secondary_color, opacity, - background_image_attachment, background_image_repeat, background_image_size, - item_radius, disable_status - ) - VALUES ( - 'board-default', - '{{ homarr_default_board_name }}', - {% if homarr_default_board_public %}1{% else %}0{% endif %}, - '#fa5252', - '#fd7e14', - 100, - 'fixed', - 'no-repeat', - 'cover', - 'lg', - 0 - ); - - -- Layouts - INSERT OR IGNORE INTO layout (id, name, board_id, column_count, breakpoint) - VALUES - ('layout-desktop', 'Desktop', 'board-default', 10, 0), - ('layout-tablet', 'Tablet', 'board-default', 6, 768), - ('layout-mobile', 'Mobile', 'board-default', 2, 480); - - -- Set home board for admin user (board exists now) - UPDATE user SET home_board_id = 'board-default', mobile_home_board_id = 'board-default' - WHERE id = 'user-local-admin'; - - -- Section - DELETE FROM section_layout WHERE section_id = 'section-apps'; - DELETE FROM item_layout WHERE section_id = 'section-apps'; - DELETE FROM section WHERE id = 'section-apps'; - - INSERT INTO section (id, board_id, kind, x_offset, y_offset, name, options) - VALUES ( - 'section-apps', - 'board-default', - 'empty', - 0, - 0, - 'Applications', - '{"json": {}}' - ); - - INSERT OR REPLACE INTO section_layout (section_id, layout_id, parent_section_id, x_offset, y_offset, width, height) - VALUES - ('section-apps', 'layout-desktop', NULL, 0, 0, 10, 3), - ('section-apps', 'layout-tablet', NULL, 0, 0, 6, 4), - ('section-apps', 'layout-mobile', NULL, 0, 0, 2, 6); - - -- Board permissions - INSERT OR IGNORE INTO boardGroupPermission (board_id, group_id, permission) - VALUES - ('board-default', 'group-oidc-admins', 'full-access'), - ('board-default', 'group-credentials-admin', 'full-access'); - - -- ================================================================= - -- APPS - -- ================================================================= - - -- Nextcloud - INSERT OR IGNORE INTO app (id, name, description, icon_url, href) - VALUES ( - 'app-nextcloud', - 'Nextcloud', - 'Cloud Storage & Collaboration', - 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/nextcloud.png', - 'https://cloud.digitalboard.ch' - ); - - INSERT OR IGNORE INTO item (id, board_id, kind, options, advanced_options) - VALUES ( - 'item-nextcloud', - 'board-default', - 'app', - '{"json": {"appId": "app-nextcloud"}}', - '{"json": {}}' - ); - - INSERT OR REPLACE INTO item_layout (item_id, section_id, layout_id, x_offset, y_offset, width, height) - VALUES - ('item-nextcloud', 'section-apps', 'layout-desktop', 0, 0, 2, 1), - ('item-nextcloud', 'section-apps', 'layout-tablet', 0, 0, 2, 1), - ('item-nextcloud', 'section-apps', 'layout-mobile', 0, 0, 1, 1); - - -- Keycloak - INSERT OR IGNORE INTO app (id, name, description, icon_url, href) - VALUES ( - 'app-keycloak', - 'Keycloak', - 'Identity & Access Management', - 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/keycloak.png', - 'https://auth.digitalboard.ch' - ); - - INSERT OR IGNORE INTO item (id, board_id, kind, options, advanced_options) - VALUES ( - 'item-keycloak', - 'board-default', - 'app', - '{"json": {"appId": "app-keycloak"}}', - '{"json": {}}' - ); - - INSERT OR REPLACE INTO item_layout (item_id, section_id, layout_id, x_offset, y_offset, width, height) - VALUES - ('item-keycloak', 'section-apps', 'layout-desktop', 2, 0, 2, 1), - ('item-keycloak', 'section-apps', 'layout-tablet', 2, 0, 2, 1), - ('item-keycloak', 'section-apps', 'layout-mobile', 1, 0, 1, 1); - - -- Mailman - INSERT OR IGNORE INTO app (id, name, description, icon_url, href) - VALUES ( - 'app-mailman', - 'Mailman', - 'Mailing List Manager', - 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/mailman.png', - 'https://lists.digitalboard.ch' - ); - - INSERT OR IGNORE INTO item (id, board_id, kind, options, advanced_options) - VALUES ( - 'item-mailman', - 'board-default', - 'app', - '{"json": {"appId": "app-mailman"}}', - '{"json": {}}' - ); - - INSERT OR REPLACE INTO item_layout (item_id, section_id, layout_id, x_offset, y_offset, width, height) - VALUES - ('item-mailman', 'section-apps', 'layout-desktop', 4, 0, 2, 1), - ('item-mailman', 'section-apps', 'layout-tablet', 4, 0, 2, 1), - ('item-mailman', 'section-apps', 'layout-mobile', 0, 1, 1, 1); - - COMMIT; - SEEDSQL - args: - executable: /bin/bash + ansible.builtin.command: + cmd: sqlite3 "{{ homarr_db }}" + stdin: "{{ lookup('template', 'homarr_seed.sql.j2') }}" register: seed_result changed_when: seed_result.rc == 0 when: admin_exists.stdout == "" diff --git a/roles/homarr/templates/homarr_seed.sql.j2 b/roles/homarr/templates/homarr_seed.sql.j2 new file mode 100644 index 0000000..0490c04 --- /dev/null +++ b/roles/homarr/templates/homarr_seed.sql.j2 @@ -0,0 +1,210 @@ +BEGIN TRANSACTION; + +-- ===================================================================== +-- SERVER SETTINGS +-- ===================================================================== + +INSERT OR REPLACE INTO serverSetting (setting_key, value) +VALUES + ('analytics', '{"json": {"enableGeneral": false, "enableWidgetData": false, "enableIntegrationData": false, "enableUserData": false}}'), + ('culture', '{"json": {"defaultLocale": "de"}}'), + ('crawling', '{"json": {"crawlingEnabled": false}}'), + ('board', '{"json": {"homeBoardId": "board-default", "mobileHomeBoardId": "board-default", "enableStatusByDefault": true, "forceDisableStatus": false, "defaultBoardId": "board-default"}}'); + +-- Skip onboarding wizard +UPDATE onboarding SET step = 'finish', previous_step = 'settings'; + +-- ===================================================================== +-- GROUPS (must exist before groupMember) +-- ===================================================================== + +-- OIDC admin group +INSERT OR IGNORE INTO "group" (id, name, owner_id, position) +VALUES ('group-oidc-admins', '{{ homarr_oidc_admin_group }}', NULL, 0); + +INSERT OR IGNORE INTO groupPermission (group_id, permission) +VALUES + ('group-oidc-admins', 'admin'), + ('group-oidc-admins', 'board-create'), + ('group-oidc-admins', 'board-full-access'), + ('group-oidc-admins', 'integration-create'), + ('group-oidc-admins', 'integration-full-access'); + +-- Credentials admin group +INSERT OR IGNORE INTO "group" (id, name, owner_id, position) +VALUES ('group-credentials-admin', 'credentials-admin', NULL, 1); + +INSERT OR IGNORE INTO groupPermission (group_id, permission) +VALUES + ('group-credentials-admin', 'admin'), + ('group-credentials-admin', 'board-create'), + ('group-credentials-admin', 'board-full-access'), + ('group-credentials-admin', 'integration-create'), + ('group-credentials-admin', 'integration-full-access'); + +-- ===================================================================== +-- LOCAL ADMIN USER +-- ===================================================================== + +INSERT OR IGNORE INTO user (id, name, email, password, email_verified, provider) +VALUES ( + 'user-local-admin', + '{{ homarr_admin_username }}', + '{{ homarr_admin_email }}', + '{{ homarr_bcrypt_hash }}', + 1, + 'credentials' +); + +-- Assign admin user to groups +INSERT OR IGNORE INTO groupMember (group_id, user_id) +VALUES + ('group-credentials-admin', 'user-local-admin'), + ('group-oidc-admins', 'user-local-admin'); + +-- ===================================================================== +-- BOARD +-- ===================================================================== + +INSERT OR IGNORE INTO board ( + id, name, is_public, + primary_color, secondary_color, opacity, + background_image_attachment, background_image_repeat, background_image_size, + item_radius, disable_status +) +VALUES ( + 'board-default', + '{{ homarr_default_board_name }}', + {% if homarr_default_board_public %}1{% else %}0{% endif %}, + '#fa5252', + '#fd7e14', + 100, + 'fixed', + 'no-repeat', + 'cover', + 'lg', + 0 +); + +-- Layouts +INSERT OR IGNORE INTO layout (id, name, board_id, column_count, breakpoint) +VALUES + ('layout-desktop', 'Desktop', 'board-default', 10, 0), + ('layout-tablet', 'Tablet', 'board-default', 6, 768), + ('layout-mobile', 'Mobile', 'board-default', 2, 480); + +-- Set home board for admin user (board exists now) +UPDATE user SET home_board_id = 'board-default', mobile_home_board_id = 'board-default' +WHERE id = 'user-local-admin'; + +-- ===================================================================== +-- SECTION +-- ===================================================================== + +DELETE FROM section_layout WHERE section_id = 'section-apps'; +DELETE FROM item_layout WHERE section_id = 'section-apps'; +DELETE FROM section WHERE id = 'section-apps'; + +INSERT INTO section (id, board_id, kind, x_offset, y_offset, name, options) +VALUES ( + 'section-apps', + 'board-default', + 'empty', + 0, + 0, + 'Applications', + '{"json": {}}' +); + +INSERT OR REPLACE INTO section_layout (section_id, layout_id, parent_section_id, x_offset, y_offset, width, height) +VALUES + ('section-apps', 'layout-desktop', NULL, 0, 0, 10, 3), + ('section-apps', 'layout-tablet', NULL, 0, 0, 6, 4), + ('section-apps', 'layout-mobile', NULL, 0, 0, 2, 6); + +-- Board permissions +INSERT OR IGNORE INTO boardGroupPermission (board_id, group_id, permission) +VALUES + ('board-default', 'group-oidc-admins', 'full-access'), + ('board-default', 'group-credentials-admin', 'full-access'); + +-- ===================================================================== +-- APPS +-- ===================================================================== + +-- Nextcloud +INSERT OR IGNORE INTO app (id, name, description, icon_url, href) +VALUES ( + 'app-nextcloud', + 'Nextcloud', + 'Cloud Storage & Collaboration', + 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/nextcloud.png', + 'https://cloud.digitalboard.ch' +); + +INSERT OR IGNORE INTO item (id, board_id, kind, options, advanced_options) +VALUES ( + 'item-nextcloud', + 'board-default', + 'app', + '{"json": {"appId": "app-nextcloud"}}', + '{"json": {}}' +); + +INSERT OR REPLACE INTO item_layout (item_id, section_id, layout_id, x_offset, y_offset, width, height) +VALUES + ('item-nextcloud', 'section-apps', 'layout-desktop', 0, 0, 2, 1), + ('item-nextcloud', 'section-apps', 'layout-tablet', 0, 0, 2, 1), + ('item-nextcloud', 'section-apps', 'layout-mobile', 0, 0, 1, 1); + +-- Keycloak +INSERT OR IGNORE INTO app (id, name, description, icon_url, href) +VALUES ( + 'app-keycloak', + 'Keycloak', + 'Identity & Access Management', + 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/keycloak.png', + 'https://auth.digitalboard.ch' +); + +INSERT OR IGNORE INTO item (id, board_id, kind, options, advanced_options) +VALUES ( + 'item-keycloak', + 'board-default', + 'app', + '{"json": {"appId": "app-keycloak"}}', + '{"json": {}}' +); + +INSERT OR REPLACE INTO item_layout (item_id, section_id, layout_id, x_offset, y_offset, width, height) +VALUES + ('item-keycloak', 'section-apps', 'layout-desktop', 2, 0, 2, 1), + ('item-keycloak', 'section-apps', 'layout-tablet', 2, 0, 2, 1), + ('item-keycloak', 'section-apps', 'layout-mobile', 1, 0, 1, 1); + +-- Mailman +INSERT OR IGNORE INTO app (id, name, description, icon_url, href) +VALUES ( + 'app-mailman', + 'Mailman', + 'Mailing List Manager', + 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/mailman.png', + 'https://lists.digitalboard.ch' +); + +INSERT OR IGNORE INTO item (id, board_id, kind, options, advanced_options) +VALUES ( + 'item-mailman', + 'board-default', + 'app', + '{"json": {"appId": "app-mailman"}}', + '{"json": {}}' +); + +INSERT OR REPLACE INTO item_layout (item_id, section_id, layout_id, x_offset, y_offset, width, height) +VALUES + ('item-mailman', 'section-apps', 'layout-desktop', 4, 0, 2, 1), + ('item-mailman', 'section-apps', 'layout-tablet', 4, 0, 2, 1), + ('item-mailman', 'section-apps', 'layout-mobile', 0, 1, 1, 1); + +COMMIT;