mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-29 23:08:06 +02:00
Added auto snippet for webserver injection
This commit is contained in:
@@ -50,5 +50,5 @@
|
||||
- name: docker compose restart
|
||||
command:
|
||||
cmd: 'docker compose restart'
|
||||
chdir: "{{docker_compose.directories.instance}}"
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
listen: docker compose restart
|
||||
|
@@ -1,7 +1,7 @@
|
||||
[Unit]
|
||||
Description=Let's Encrypt deploy to {{docker_compose.directories.instance}}
|
||||
Description=Let's Encrypt deploy to {{ docker_compose.directories.instance }}
|
||||
OnFailure=sys-alm-compose.infinito@%n.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/bash {{ PATH_ADMINISTRATOR_SCRIPTS }}/srv-proxy-6-6-tls-deploy.sh {{ssl_cert_folder}} {{docker_compose.directories.instance}}
|
||||
ExecStart=/usr/bin/bash {{ PATH_ADMINISTRATOR_SCRIPTS }}/srv-proxy-6-6-tls-deploy.sh {{ssl_cert_folder}} {{ docker_compose.directories.instance }}
|
||||
|
56
roles/sys-srv-web-inj-compose/filter_plugins/inj_snippets.py
Normal file
56
roles/sys-srv-web-inj-compose/filter_plugins/inj_snippets.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# roles/sys-srv-web-inj-compose/filter_plugins/inj_snippets.py
|
||||
"""
|
||||
Jinja filter: `inj_features(kind)` filters a list of features to only those
|
||||
that actually provide the corresponding snippet template file.
|
||||
|
||||
- kind='head' -> roles/sys-srv-web-inj-<feature>/templates/head_sub.j2
|
||||
- kind='body' -> roles/sys-srv-web-inj-<feature>/templates/body_sub.j2
|
||||
|
||||
If the feature's role directory (roles/sys-srv-web-inj-<feature>) does not
|
||||
exist, this filter raises FileNotFoundError.
|
||||
|
||||
Usage in a template:
|
||||
{% set head_features = SRV_WEB_INJ_COMP_FEATURES_ALL | inj_features('head') %}
|
||||
{% set body_features = SRV_WEB_INJ_COMP_FEATURES_ALL | inj_features('body') %}
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# This file lives at: roles/sys-srv-web-inj-compose/filter_plugins/inj_snippets.py
|
||||
_THIS_DIR = os.path.dirname(__file__)
|
||||
_ROLE_DIR = os.path.abspath(os.path.join(_THIS_DIR, "..")) # roles/sys-srv-web-inj-compose
|
||||
_ROLES_DIR = os.path.abspath(os.path.join(_ROLE_DIR, "..")) # roles
|
||||
|
||||
def _feature_role_dir(feature: str) -> str:
|
||||
return os.path.join(_ROLES_DIR, f"sys-srv-web-inj-{feature}")
|
||||
|
||||
def _has_snippet(feature: str, kind: str) -> bool:
|
||||
if kind not in ("head", "body"):
|
||||
raise ValueError("kind must be 'head' or 'body'")
|
||||
|
||||
role_dir = _feature_role_dir(feature)
|
||||
if not os.path.isdir(role_dir):
|
||||
raise FileNotFoundError(
|
||||
f"[inj_snippets] Expected role directory not found for feature "
|
||||
f"'{feature}': {role_dir}"
|
||||
)
|
||||
|
||||
path = os.path.join(role_dir, "templates", f"{kind}_sub.j2")
|
||||
return os.path.exists(path)
|
||||
|
||||
def inj_features_filter(features, kind: str = "head"):
|
||||
if not isinstance(features, (list, tuple)):
|
||||
return []
|
||||
# Validation + filtering in one pass; will raise if a role dir is missing.
|
||||
valid = []
|
||||
for f in features:
|
||||
name = str(f)
|
||||
if _has_snippet(name, kind):
|
||||
valid.append(name)
|
||||
return valid
|
||||
|
||||
class FilterModule(object):
|
||||
def filters(self):
|
||||
return {
|
||||
"inj_features": inj_features_filter,
|
||||
}
|
@@ -39,6 +39,8 @@
|
||||
- name: Reinitialize 'inj_enabled' for '{{ domain }}', after modification by CDN
|
||||
set_fact:
|
||||
inj_enabled: "{{ applications | inj_enabled(application_id, SRV_WEB_INJ_COMP_FEATURES_ALL) }}"
|
||||
inj_head_features: "{{ SRV_WEB_INJ_COMP_FEATURES_ALL | inj_features('head') }}"
|
||||
inj_body_features: "{{ SRV_WEB_INJ_COMP_FEATURES_ALL | inj_features('body') }}"
|
||||
|
||||
- name: "Activate Corporate CSS for '{{ domain }}'"
|
||||
include_role:
|
||||
|
@@ -1,15 +1,10 @@
|
||||
{# roles/sys-srv-web-inj-compose/templates/location.lua.j2 #}
|
||||
{% macro push_snippets(list_name, features) -%}
|
||||
{% for f in features -%}
|
||||
{% if inj_enabled.get(f) -%}
|
||||
{% set kind = list_name | regex_replace('_snippets$','') %}
|
||||
{% for f in features if inj_enabled.get(f) -%}
|
||||
{{ list_name }}[#{{ list_name }} + 1] = [=[
|
||||
{%- include
|
||||
'roles/sys-srv-web-inj-' ~ f ~
|
||||
'/templates/' ~
|
||||
('head' if list_name == 'head_snippets' else 'body') ~
|
||||
'_sub.j2'
|
||||
-%}
|
||||
{%- include 'roles/sys-srv-web-inj-' ~ f ~ '/templates/' ~ kind ~ '_sub.j2' -%}
|
||||
]=]
|
||||
{% endif -%}
|
||||
{% endfor -%}
|
||||
{%- endmacro %}
|
||||
|
||||
@@ -48,7 +43,7 @@ body_filter_by_lua_block {
|
||||
local whole = table.concat(ngx.ctx.buf)
|
||||
ngx.ctx.buf = nil -- clear buffer
|
||||
|
||||
-- remove html CSP, due to management via infinito nexus policies
|
||||
-- remove html CSP, due to management via Infinito.Nexus policies
|
||||
whole = whole:gsub(
|
||||
'<meta[^>]-http%-equiv=["\']Content%-Security%-Policy["\'][^>]->%s*',
|
||||
''
|
||||
@@ -57,21 +52,21 @@ body_filter_by_lua_block {
|
||||
-- build a list of head-injection snippets
|
||||
local head_snippets = {}
|
||||
|
||||
{{ push_snippets('head_snippets', ['css','matomo','desktop','javascript','logout']) }}
|
||||
{{ push_snippets('head_snippets', inj_head_features) }}
|
||||
|
||||
-- inject all collected snippets right before </head>
|
||||
local head_payload = table.concat(head_snippets, "\n") .. "</head>"
|
||||
whole = string.gsub(whole, "</head>", head_payload)
|
||||
whole = ngx.re.gsub(whole, "</head>", head_payload, "ijo", nil, 1)
|
||||
|
||||
-- build a list of body-injection snippets
|
||||
local body_snippets = {}
|
||||
|
||||
{{ push_snippets('body_snippets', ['matomo','logout','desktop']) }}
|
||||
{{ push_snippets('body_snippets', inj_body_features) }}
|
||||
|
||||
-- inject all collected snippets right before </body>
|
||||
local body_payload = table.concat(body_snippets, "\n") .. "</body>"
|
||||
whole = string.gsub(whole, "</body>", body_payload)
|
||||
whole = ngx.re.gsub(whole, "</body>", body_payload, "ijo", nil, 1)
|
||||
|
||||
-- finally send the modified HTML out
|
||||
ngx.arg[1] = whole
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
## update
|
||||
```bash
|
||||
cd {{docker_compose.directories.instance}}
|
||||
cd {{ docker_compose.directories.instance }}
|
||||
docker-compose down
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
@@ -17,7 +17,7 @@ Keep in mind to track and to don't interrupt the update process until the migrat
|
||||
|
||||
## recreate
|
||||
```bash
|
||||
cd {{docker_compose.directories.instance}} && docker-compose -p gitea up -d --force-recreate
|
||||
cd {{ docker_compose.directories.instance }} && docker-compose -p gitea up -d --force-recreate
|
||||
```
|
||||
|
||||
## database access
|
||||
|
@@ -27,7 +27,7 @@
|
||||
- name: Run Listmonk setup only if DB is empty
|
||||
command:
|
||||
cmd: docker compose run -T --rm application sh -c "yes | ./listmonk --install"
|
||||
chdir: "{{docker_compose.directories.instance}}"
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
when: "'No relations found.' in db_tables.stdout"
|
||||
|
||||
- name: Build OIDC settings JSON
|
||||
|
@@ -1,7 +1,7 @@
|
||||
- name: "Execute migration for '{{ application_id }}'"
|
||||
command:
|
||||
cmd: "docker-compose run --rm web bundle exec rails db:migrate"
|
||||
chdir: "{{docker_compose.directories.instance}}"
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
|
||||
- name: "Include administrator routines for '{{ application_id }}'"
|
||||
include_tasks: 02_administrator.yml
|
@@ -1,7 +1,7 @@
|
||||
# Routines to create the administrator account
|
||||
# @see https://chatgpt.com/share/67b9b12c-064c-800f-9354-8e42e6459764
|
||||
|
||||
- name: Check health status of {{ item }} container
|
||||
- name: Check health status of '{{ item }}' container
|
||||
shell: |
|
||||
cid=$(docker compose ps -q {{ item }})
|
||||
docker inspect \
|
||||
@@ -19,25 +19,29 @@
|
||||
- sidekiq
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
changed_when: false
|
||||
|
||||
- name: Remove line containing "- administrator" from config/settings.yml to allow creating administrator account
|
||||
command:
|
||||
cmd: "docker compose exec -u root web sed -i '/- administrator/d' config/settings.yml"
|
||||
chdir: "{{docker_compose.directories.instance}}"
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
when: users.administrator.username == "administrator"
|
||||
|
||||
- name: Create admin account via tootctl
|
||||
command:
|
||||
command:
|
||||
cmd: 'docker compose exec -u root web bash -c "RAILS_ENV=production bin/tootctl accounts create {{users.administrator.username}} --email {{ users.administrator.email }} --confirmed --role Owner"'
|
||||
chdir: "{{docker_compose.directories.instance}}"
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
register: tootctl_create
|
||||
changed_when: tootctl_create.rc == 0
|
||||
failed_when: >
|
||||
tootctl_create.rc != 0
|
||||
and
|
||||
("taken" not in tootctl_create.stderr | lower)
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: Approve the administrator account in Mastodon
|
||||
command:
|
||||
cmd: docker compose exec -u root web bash -c "RAILS_ENV=production bin/tootctl accounts modify {{users.administrator.username}} --approve"
|
||||
chdir: "{{docker_compose.directories.instance}}"
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
@@ -4,5 +4,5 @@
|
||||
name: cmp-db-docker-proxy
|
||||
|
||||
- name: add docker-compose.yml
|
||||
template: src=docker-compose.yml.j2 dest={{docker_compose.directories.instance}}docker-compose.yml
|
||||
template: src=docker-compose.yml.j2 dest={{ docker_compose.directories.instance }}docker-compose.yml
|
||||
notify: docker compose up
|
||||
|
@@ -32,5 +32,5 @@
|
||||
- name: add docker-compose.yml
|
||||
template:
|
||||
src: "docker-compose.yml.j2"
|
||||
dest: "{{docker_compose.directories.instance}}docker-compose.yml"
|
||||
dest: "{{ docker_compose.directories.instance }}docker-compose.yml"
|
||||
notify: docker compose up
|
||||
|
@@ -1,6 +1,6 @@
|
||||
---
|
||||
application_id: "web-app-mybb"
|
||||
docker_compose_instance_confd_directory: "{{docker_compose.directories.instance}}conf.d/"
|
||||
docker_compose_instance_confd_directory: "{{ docker_compose.directories.instance }}conf.d/"
|
||||
docker_compose_instance_confd_defaultconf_file: "{{docker_compose_instance_confd_directory}}default.conf"
|
||||
target_mount_conf_d_directory: "{{ NGINX.DIRECTORIES.HTTP.SERVERS }}"
|
||||
source_domain: "mybb.{{ PRIMARY_DOMAIN }}"
|
||||
|
@@ -1,2 +1,2 @@
|
||||
application_id: "web-app-roulette-wheel"
|
||||
app_path: "{{docker_compose.directories.instance}}/app/"
|
||||
app_path: "{{ docker_compose.directories.instance }}/app/"
|
@@ -2,7 +2,7 @@ application_id: "web-app-taiga"
|
||||
database_type: "postgres"
|
||||
docker_repository_address: "https://github.com/taigaio/taiga-docker"
|
||||
email_backend: "smtp" ## use an SMTP server or display the emails in the console (either "smtp" or "console")
|
||||
docker_compose_init: "{{docker_compose.directories.instance}}docker-compose-inits.yml.j2"
|
||||
docker_compose_init: "{{ docker_compose.directories.instance }}docker-compose-inits.yml.j2"
|
||||
taiga_image_backend: >-
|
||||
{{ 'robrotheram/taiga-back-openid' if applications | get_app_conf(application_id, 'features.oidc', True) and applications | get_app_conf(application_id, 'oidc.flavor', True) == 'robrotheram'
|
||||
else 'taigaio/taiga-back' }}
|
||||
|
Reference in New Issue
Block a user