From f998954be9ef027e6540614acef8aee2f1fc3635 Mon Sep 17 00:00:00 2001 From: gov Date: Wed, 4 Nov 2026 16:55:41 -0500 Subject: [PATCH] feat: deploy cities labeler --- .gitea/workflows/deploy.yml | 10 +++++ README.md | 18 +++++++++ playbook.yml | 49 +++++++++++++++++++++++- templates/Caddyfile.j2 | 9 +++++ templates/cities-labeler-compose.yaml.j2 | 27 +++++++++++++ templates/cities-labeler.env.j2 | 3 ++ vars/main.yml.example | 9 +++++ 7 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 templates/cities-labeler-compose.yaml.j2 create mode 100644 templates/cities-labeler.env.j2 diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 9120367..40e596a 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -61,6 +61,16 @@ jobs: echo "pds_email_smtp_url: ${{ secrets.SMTP_URL }}" >> vars/main.yml fi echo "pds_email_from_address: techops@cosocial.ca" >> vars/main.yml + # Optional: cities labeler + if [ -n "${{ vars.PDS_CITIES_HOSTNAME }}" ]; then + cat >> vars/main.yml <` | Labeler account handle | +| `pds_cities_app_password` | yes (if enabled) | — | Labeler account app password with DM access | +| `pds_cities_signing_key` | yes (if enabled) | — | Label signing key (hex); its public key must match the labeler's DID document | + ### Backup service | Variable | Required | Default | Description | @@ -207,6 +221,8 @@ Auto-deploys on push to `main`. Set up these in Gitea repo settings (Settings > | `PDS_TELEMETRY_ENABLED` | *(optional)* Set to `true` to enable telemetry + monitoring stack | | `PDS_SERVICE_NAME` | *(optional)* PDS display name for branding | | `PDS_PRIMARY_COLOR` | *(optional)* Primary color (hex) for branding | +| `PDS_CITIES_HOSTNAME` | *(optional)* Set to deploy the cities labeler at this hostname | +| `PDS_CITIES_REPO` | *(with cities)* Git URL of the labeler repo | Outgoing emails are sent from `techops@cosocial.ca` (fixed in the workflow). @@ -218,5 +234,7 @@ Outgoing emails are sent from `techops@cosocial.ca` (fixed in the workflow). | `OVH_S3_ACCESS_KEY` | OVH S3 access key for blob storage | | `OVH_S3_SECRET_KEY` | OVH S3 secret key for blob storage | | `SMTP_URL` | *(optional)* SMTP URL with credentials (e.g., `smtps://user:pass@smtp.example.com/`) | +| `PDS_CITIES_APP_PASSWORD` | *(with cities)* Labeler account app password with DM access | +| `PDS_CITIES_SIGNING_KEY` | *(with cities)* Label signing key (hex) | The workflow installs Ansible, writes the SSH key from a secret, generates `inventory.yml` and `vars/main.yml` from vars and secrets, and runs the playbook. diff --git a/playbook.yml b/playbook.yml index 1135bfc..215b2ab 100644 --- a/playbook.yml +++ b/playbook.yml @@ -192,6 +192,41 @@ when: pds_operator_enabled is defined and pds_operator_enabled | bool notify: restart operator + - name: Clone cities labeler repo + git: + repo: "{{ pds_cities_repo }}" + dest: "{{ pds_data_dir }}/cities" + version: "{{ pds_cities_version | default('main') }}" + update: yes + force: no + when: pds_cities_enabled is defined and pds_cities_enabled | bool + notify: restart cities + + - name: Create cities labeler data directory + file: + path: "{{ pds_data_dir }}/cities/data" + state: directory + owner: "1000" + group: "1000" + mode: "0755" + when: pds_cities_enabled is defined and pds_cities_enabled | bool + + - name: Deploy cities labeler .env + template: + src: templates/cities-labeler.env.j2 + dest: "{{ pds_data_dir }}/cities/.env" + mode: "0600" + when: pds_cities_enabled is defined and pds_cities_enabled | bool + notify: restart cities + + - name: Deploy cities labeler compose + template: + src: templates/cities-labeler-compose.yaml.j2 + dest: "{{ pds_data_dir }}/cities/compose.yaml" + mode: "0644" + when: pds_cities_enabled is defined and pds_cities_enabled | bool + notify: restart cities + - name: Create monitoring directories file: path: "{{ item }}" @@ -248,7 +283,7 @@ shell: cd {{ pds_data_dir }}/monitoring && docker compose up -d when: pds_telemetry_enabled is defined and pds_telemetry_enabled | bool - - name: Flush handlers (operator + monitoring) + - name: Flush handlers (operator + cities + monitoring) meta: flush_handlers - name: Operator health check @@ -260,6 +295,15 @@ delay: 10 when: pds_operator_enabled is defined and pds_operator_enabled | bool + - name: Cities labeler health check + uri: + url: "https://{{ pds_cities_hostname }}/xrpc/_health" + method: GET + status_code: 200 + retries: 5 + delay: 10 + when: pds_cities_enabled is defined and pds_cities_enabled | bool + handlers: - name: apply changes shell: cd {{ pds_data_dir }} && docker compose up -d && docker restart caddy @@ -269,3 +313,6 @@ - name: restart operator shell: cd {{ pds_data_dir }}/operator && docker compose up -d --build + + - name: restart cities + shell: cd {{ pds_data_dir }}/cities && docker compose up -d --build diff --git a/templates/Caddyfile.j2 b/templates/Caddyfile.j2 index c3f1ca6..82a6573 100644 --- a/templates/Caddyfile.j2 +++ b/templates/Caddyfile.j2 @@ -24,3 +24,12 @@ reverse_proxy http://localhost:8787 } {% endif %} +{% if pds_cities_enabled is defined and pds_cities_enabled | bool %} +{{ pds_cities_hostname }} { + log { + output stdout + format json + } + reverse_proxy http://localhost:4100 +} +{% endif %} diff --git a/templates/cities-labeler-compose.yaml.j2 b/templates/cities-labeler-compose.yaml.j2 new file mode 100644 index 0000000..a79c0e9 --- /dev/null +++ b/templates/cities-labeler-compose.yaml.j2 @@ -0,0 +1,27 @@ +name: cities-labeler + +# Cities labeler — deployed by Ansible to +# {{ pds_data_dir }}/cities/compose.yaml + +services: + app: + build: . + env_file: .env + ports: + - "127.0.0.1:4100:4100" + # the host's /etc/hosts maps the PDS hostname to 127.0.1.1 (cloud-init + # manage_etc_hosts), which Docker propagates to container DNS — pin the + # real address so the labeler can log in to the PDS + extra_hosts: + - "{{ pds_hostname }}:{{ hostvars[inventory_hostname].ansible_default_ipv4.address }}" + volumes: + # bind mount keeps the label database under /pds — captured by the backup tarball + - ./data:/data + # runs unprivileged; ./data must be owned by uid 1000 + user: "1000:1000" + read_only: true + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + restart: unless-stopped diff --git a/templates/cities-labeler.env.j2 b/templates/cities-labeler.env.j2 new file mode 100644 index 0000000..dbb3cae --- /dev/null +++ b/templates/cities-labeler.env.j2 @@ -0,0 +1,3 @@ +LABELER_HANDLE={{ pds_cities_handle | default('cities.' ~ pds_hostname) }} +LABELER_APP_PASSWORD={{ pds_cities_app_password }} +SIGNING_KEY_HEX={{ pds_cities_signing_key }} diff --git a/vars/main.yml.example b/vars/main.yml.example index f877d1e..7d946f1 100644 --- a/vars/main.yml.example +++ b/vars/main.yml.example @@ -56,3 +56,12 @@ pds_operator_enabled: true pds_operator_repo: https://tangled.org/brookie.blog/pds-operator pds_operator_version: main pds_operator_hostname: pds-operator.cosocial.ca + +# Cities labeler (DM-driven city badges, serves labels at pds_cities_hostname) +# pds_cities_enabled: true +# pds_cities_repo: https://git.cosocial.info/CoSocial-Canada/atproto-cosocial-labeler.git +# pds_cities_version: main +# pds_cities_hostname: cities-labeler.cosocial.ca +# pds_cities_handle: cities.pds.cosocial.ca +# pds_cities_app_password: CHANGE_ME # app password with DM access +# pds_cities_signing_key: CHANGE_ME # SIGNING_KEY_HEX; its public key is in the labeler's DID doc