diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf727362..b323d895 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ on: jobs: ci-optimization: name: CI optimization - uses: dargmuesli/github-actions/.github/workflows/ci-optimization.yml@e9c9cf391baeb261cf62c0af6c4af2245bae0662 # 5.9.2 + uses: dargmuesli/github-actions/.github/workflows/ci-optimization.yml@ab0335fad9df7941df2880f0645d8f685278da1c # 5.9.4 permissions: pull-requests: read build: @@ -52,7 +52,7 @@ jobs: release-semantic: needs: build name: Semantic Release - uses: dargmuesli/github-actions/.github/workflows/release-semantic.yml@e9c9cf391baeb261cf62c0af6c4af2245bae0662 # 5.9.2 + uses: dargmuesli/github-actions/.github/workflows/release-semantic.yml@ab0335fad9df7941df2880f0645d8f685278da1c # 5.9.4 permissions: contents: write id-token: write diff --git a/.github/workflows/release-schedule.yml b/.github/workflows/release-schedule.yml index 2a0e9956..a1e6570f 100644 --- a/.github/workflows/release-schedule.yml +++ b/.github/workflows/release-schedule.yml @@ -10,7 +10,7 @@ on: jobs: release-schedule: name: "Release: Scheduled" - uses: dargmuesli/github-actions/.github/workflows/release-schedule.yml@e9c9cf391baeb261cf62c0af6c4af2245bae0662 # 5.9.2 + uses: dargmuesli/github-actions/.github/workflows/release-schedule.yml@ab0335fad9df7941df2880f0645d8f685278da1c # 5.9.4 permissions: contents: read secrets: diff --git a/AGENTS.md b/AGENTS.md index d1b2554a..f00bcce3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,11 +14,15 @@ applyTo: '**' **For contributing:** - [CONTRIBUTING.md](CONTRIBUTING.md): Development setup, dargstack guidelines, code style, git workflow +**Cross-service contracts** (policies two or more services must implement identically, with no code shared between them): +- [docs/password-strength.md](docs/password-strength.md): Password strength requirements enforced by `vibetype` and `postgraphile` + ## Code Style - Do not use abbreviations in naming, except where omitting them would look unnatural - Use natural language in any non-code text instead of referring to code directly, e.g. "the database's password" instead of "the `postgres_password`", except when a code reference is needed - Use backticks in any non-code text to refer to code, e.g. "`postgres`" instead of "postgres" +- In markdown prose, start each sentence on its own line (semantic line breaks); renders the same, but keeps diffs scoped to the sentence that changed - Sort YAML keys lexicographically except where order is semantically significant - Code formatting is done by the editor via `.editorconfig` diff --git a/CHANGELOG.md b/CHANGELOG.md index 33e9bbbf..98252af1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## [20.3.4](https://github.com/maevsi/stack/compare/20.3.3...20.3.4) (2026-08-24) + +### Bug Fixes + +* **traefik:** append production volumes ([30bc832](https://github.com/maevsi/stack/commit/30bc832458b7f963098aa003741b314e847aa1f5)) + +## [20.3.3](https://github.com/maevsi/stack/compare/20.3.2...20.3.3) (2026-08-24) + +### Bug Fixes + +* **traefik:** add acme volume ([e952b4c](https://github.com/maevsi/stack/commit/e952b4c9f45774c0006d428f129ccc176c357592)) + +## [20.3.2](https://github.com/maevsi/stack/compare/20.3.1...20.3.2) (2026-08-21) + +### Bug Fixes + +* **vibetype:** correct notification secret variable name ([#298](https://github.com/maevsi/stack/issues/298)) ([0d871bd](https://github.com/maevsi/stack/commit/0d871bdbd322ca6ecb28821080fbaa52f15104b9)) + ## [20.3.1](https://github.com/maevsi/stack/compare/20.3.0...20.3.1) (2026-08-14) ## [20.3.0](https://github.com/maevsi/stack/compare/20.2.2...20.3.0) (2026-08-13) diff --git a/Dockerfile.md b/Dockerfile.md index 3db88ff2..7555193b 100644 --- a/Dockerfile.md +++ b/Dockerfile.md @@ -1,3 +1,3 @@ # -FROM ghcr.io/dargstack/dargstack:4.13.0 +FROM ghcr.io/dargstack/dargstack:4.14.1 # diff --git a/docs/password-strength.md b/docs/password-strength.md new file mode 100644 index 00000000..c3cac1fe --- /dev/null +++ b/docs/password-strength.md @@ -0,0 +1,63 @@ +# Password strength policy + +This document is the single source of truth for the password strength policy that any implementation setting an account password must satisfy. +It lives here, rather than in `vibetype` or `postgraphile`, because both services implement it independently (code sharing between them is not an option), and a policy shared across services belongs in `stack` rather than being duplicated per repo. +When either service's implementation changes, check it against this document rather than against the other service's code. + +## Scope + +Applies to every operation that sets a password a user will authenticate with: + +| Operation | Field carrying the new password | Covered | +| ------------------------ | -------------------------------- | ------- | +| `accountRegistration` | `input.password` | yes | +| `accountPasswordReset` | `input.password` | yes | +| `accountPasswordChange` | `input.passwordNew` | yes | + +`accountPasswordChange`'s `input.passwordCurrent` is explicitly **out of scope**: it authenticates an existing password, which may predate this policy, and must never be strength-checked. + +## Requirements + +Both of the following must hold. + +1. **Minimum length**: 8 characters. + This matches NIST SP 800-63B's own floor. + It is a cheap sanity backstop, not the control doing the real work, see [Why keep a length floor](#why-keep-a-length-floor). +2. **Minimum strength**: a [zxcvbn](https://github.com/zxcvbn-ts/zxcvbn) score of at least 3 ("safely unguessable", resists an offline, slow-hash attack; see the library's own scoring guidance). + This is the control that actually determines whether a password is accepted in practice. + +### Why keep a length floor + +NIST SP 800-63B requires a minimum length (>= 8) plus screening against common or compromised passwords. +It does not separately mandate a guessability-estimator score on top of that. +zxcvbn's score already factors in length as one of its inputs, so once score >= 3 is required, an 8 character floor rarely does independent work: empirically, the shortest fully random password (e.g. `xK9#mL2qP`, drawn from a large character set) needed to reach score 3 is 9 characters, one above this floor. +The floor is kept anyway as a structural backstop that does not depend on zxcvbn's heuristics being correct for a given input, and as a small margin against future improvements in offline hash-cracking speed, which erode a short password's safety margin fastest regardless of how patternless it is. + +## Algorithm and configuration + +Both implementations must use identical configuration, or they will disagree on borderline passwords (a password accepted by the client but rejected by the server, or vice versa). + +- **Library**: `@zxcvbn-ts/core`, via `new ZxcvbnFactory(options).check(password).score`. +- **Dictionaries**: `@zxcvbn-ts/language-common` (common passwords plus adjacency graphs for keyboard-pattern detection) merged with `@zxcvbn-ts/language-de` and `@zxcvbn-ts/language-en` (both dictionaries only; German and English are the platform's supported locales). +- **Translations**: `@zxcvbn-ts/language-en`. + This only affects zxcvbn's internal feedback strings. + Neither implementation surfaces them to the user, so the specific language here is not user-visible, but the `ZxcvbnFactory` constructor requires a non-empty value. +- **Package versions**: pinned independently in each repo's `package.json`. + Keep `@zxcvbn-ts/core`, `@zxcvbn-ts/language-common`, `@zxcvbn-ts/language-de`, and `@zxcvbn-ts/language-en` at the same version in both repos. + A dictionary update can change which side of the score-3 boundary a given password falls on. + +## Current implementation status + +| Layer | Minimum length (8) | zxcvbn score (>= 3) | +| ------------------------------- | -------------------- | --------------------- | +| `vibetype` (client) | enforced, all 3 operations | enforced, all 3 operations | +| `postgraphile` (server) | not this layer's job, see below | enforced, all 3 operations | +| `sqitch` (database) | enforced, all 3 operations (`char_length(...) < 8` in each function) | not applicable, zxcvbn cannot run in SQL | + +`postgraphile` intentionally does not re-check length: since every underlying sqitch function already rejects anything shorter than 8 characters, and that is exactly this policy's floor, duplicating the check in `postgraphile` would add no protection. + +## Where each side implements this + +- `vibetype`: `src/app/utils/passwordStrength.ts` (scoring), `src/app/utils/validation.ts` (`SCHEMA_PASSWORD_V2`, length), `src/app/composables/useAuthPasswordValidation.ts` and `usePasswordPairValidation.ts` (live field validation wiring). +- `postgraphile`: `src/presets/passwordStrength.ts` (`PasswordStrengthPlugin`, a Grafserv middleware that inspects `accountRegistration`, `accountPasswordReset`, and `accountPasswordChange` mutations before they execute). +- `sqitch`: the `char_length(...) < 8` check in `function_account_registration.sql`, `function_account_password_reset.sql`, and `function_account_password_change.sql`. diff --git a/src/development/adminer/compose.yaml b/src/development/adminer/compose.yaml index 12147458..26fcd52f 100644 --- a/src/development/adminer/compose.yaml +++ b/src/development/adminer/compose.yaml @@ -29,6 +29,6 @@ services: timeout: 5s retries: 3 start_period: 10s - image: adminer:5.5.1-standalone + image: adminer:6.0.1-standalone volumes: - ./configurations/adminer.css:/var/www/html/adminer.css:ro diff --git a/src/development/debezium/configurations/entrypoint.sh b/src/development/debezium/configurations/entrypoint.sh index 4a61818f..45973796 100755 --- a/src/development/debezium/configurations/entrypoint.sh +++ b/src/development/debezium/configurations/entrypoint.sh @@ -27,8 +27,17 @@ curl --fail --output /dev/null --silent --show-error \ "database.password": "'"$POSTGRES_PASSWORD"'", "database.user": "'"$POSTGRES_USER"'", "plugin.name": "pgoutput", - "table.include.list": "vibetype.event,vibetype.upload,vibetype_private.notification", - "topic.prefix" : "vibetype" + "table.include.list": "vibetype_private.outbox", + "topic.prefix" : "vibetype", + "transforms": "outbox", + "transforms.outbox.type": "io.debezium.transforms.outbox.EventRouter", + "transforms.outbox.route.by.field": "aggregate_type", + "transforms.outbox.route.topic.replacement": "vibetype.outbox.${routedByValue}", + "transforms.outbox.table.field.event.key": "aggregate_id", + "transforms.outbox.predicate": "isOutbox", + "predicates": "isOutbox", + "predicates.isOutbox.type": "org.apache.kafka.connect.transforms.predicates.TopicNameMatches", + "predicates.isOutbox.pattern": "vibetype\\.vibetype_private\\.outbox" }' echo "PostgreSQL connector '$CONNECTOR_NAME' is up to date." diff --git a/src/development/elasticsearch/compose.yaml b/src/development/elasticsearch/compose.yaml index a3922a0e..21c4fbf8 100644 --- a/src/development/elasticsearch/compose.yaml +++ b/src/development/elasticsearch/compose.yaml @@ -25,7 +25,7 @@ services: # timeout: 10s # retries: 3 # start_period: 60s - image: elasticsearch:9.5.1 + image: elasticsearch:9.5.2 secrets: - source: elasticsearch-keystore-password uid: "1000" diff --git a/src/development/grafana/compose.yaml b/src/development/grafana/compose.yaml index fe445f9b..e4569f00 100644 --- a/src/development/grafana/compose.yaml +++ b/src/development/grafana/compose.yaml @@ -40,7 +40,7 @@ services: timeout: 5s retries: 3 start_period: 30s - image: grafana/grafana:13.1.3 + image: grafana/grafana:13.2.0 secrets: - grafana-admin-email - grafana-admin-password diff --git a/src/development/jobber/compose.yaml b/src/development/jobber/compose.yaml index 8b0ff062..e9d131a7 100644 --- a/src/development/jobber/compose.yaml +++ b/src/development/jobber/compose.yaml @@ -19,6 +19,8 @@ services: # You cannot access the jobber via a web interface. environment: AWS_SHARED_CREDENTIALS_FILE: /run/secrets/jobber-aws-credentials + POSTGRES_DB_FILE: /run/secrets/postgres-db + POSTGRES_HOST: postgres image: ghcr.io/dargmuesli/jobber-aws-msmtp:1.3.0 secrets: - source: jobber-aliases @@ -29,6 +31,9 @@ services: target: /home/jobberuser/.aws/config - source: jobber-msmtprc target: /etc/msmtprc + - postgres-db + - postgres-role-service-jobber-password + - postgres-role-service-jobber-username volumes: - ./configurations/.jobber:/home/jobberuser/.jobber:ro - ./configurations/sinks:/srv/sinks:ro diff --git a/src/development/jobber/configurations/.jobber b/src/development/jobber/configurations/.jobber index 906ff841..a824435b 100644 --- a/src/development/jobber/configurations/.jobber +++ b/src/development/jobber/configurations/.jobber @@ -10,3 +10,12 @@ jobs: - type: system-email notifyOnFailure: - type: system-email + OutboxPurge: + cmd: PGPASSWORD="$(cat /run/secrets/postgres-role-service-jobber-password)" psql -v ON_ERROR_STOP=1 -h "$POSTGRES_HOST" -U "$(cat /run/secrets/postgres-role-service-jobber-username)" -d "$(cat "$POSTGRES_DB_FILE")" -c "DELETE FROM vibetype_private.outbox WHERE created_at < now() - interval '24 hours'" + time: 0 0 */2 * + notifyOnSuccess: + - type: system-email + notifyOnError: + - type: system-email + notifyOnFailure: + - type: system-email diff --git a/src/development/jobber/configurations/sinks/sentry-outbox-purge/error.sh b/src/development/jobber/configurations/sinks/sentry-outbox-purge/error.sh new file mode 100755 index 00000000..e769052f --- /dev/null +++ b/src/development/jobber/configurations/sinks/sentry-outbox-purge/error.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +curl "${SENTRY_CRONS_OUTBOX_PURGE}?status=error" diff --git a/src/development/jobber/configurations/sinks/sentry-outbox-purge/in-progress.sh b/src/development/jobber/configurations/sinks/sentry-outbox-purge/in-progress.sh new file mode 100755 index 00000000..8658bb7b --- /dev/null +++ b/src/development/jobber/configurations/sinks/sentry-outbox-purge/in-progress.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +curl "${SENTRY_CRONS_OUTBOX_PURGE}?status=in_progress" diff --git a/src/development/jobber/configurations/sinks/sentry-outbox-purge/ok.sh b/src/development/jobber/configurations/sinks/sentry-outbox-purge/ok.sh new file mode 100755 index 00000000..d17c2407 --- /dev/null +++ b/src/development/jobber/configurations/sinks/sentry-outbox-purge/ok.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +curl "${SENTRY_CRONS_OUTBOX_PURGE}?status=ok" diff --git a/src/development/portainer/compose.yaml b/src/development/portainer/compose.yaml index a49d89cc..88bddd8f 100644 --- a/src/development/portainer/compose.yaml +++ b/src/development/portainer/compose.yaml @@ -27,7 +27,7 @@ services: timeout: 5s retries: 3 start_period: 30s - image: portainer/portainer-ce:2.44.0-alpine + image: portainer/portainer-ce:2.45.0-alpine secrets: - portainer-admin-password volumes: @@ -41,7 +41,7 @@ services: placement: constraints: - node.platform.os == linux - image: portainer/agent:2.44.0 + image: portainer/agent:2.45.0 volumes: - /var/run/docker.sock:/var/run/docker.sock - /var/lib/docker/volumes:/var/lib/docker/volumes diff --git a/src/development/postgres/compose.yaml b/src/development/postgres/compose.yaml index 546cb761..251be610 100644 --- a/src/development/postgres/compose.yaml +++ b/src/development/postgres/compose.yaml @@ -11,6 +11,12 @@ secrets: postgres-role-service-grafana-username: # The username of the observation dashboard's database role. file: ~~/artifacts/secrets/postgres-role-service-grafana-username.secret + postgres-role-service-jobber-password: + # The password of the job scheduler's database role. + file: ~~/artifacts/secrets/postgres-role-service-jobber-password.secret + postgres-role-service-jobber-username: + # The username of the job scheduler's database role. + file: ~~/artifacts/secrets/postgres-role-service-jobber-username.secret postgres-role-service-postgraphile-password: # The password of the GraphQL API database wrapper's database role. file: ~~/artifacts/secrets/postgres-role-service-postgraphile-password.secret @@ -90,6 +96,11 @@ x-dargstack: type: random_string postgres-role-service-grafana-username: type: wordlist_word + postgres-role-service-jobber-password: + special_characters: false + type: random_string + postgres-role-service-jobber-username: + type: wordlist_word postgres-role-service-postgraphile-password: special_characters: false type: random_string diff --git a/src/development/prometheus/compose.yaml b/src/development/prometheus/compose.yaml index 411de8b8..5027a40d 100644 --- a/src/development/prometheus/compose.yaml +++ b/src/development/prometheus/compose.yaml @@ -18,7 +18,7 @@ services: timeout: 5s retries: 3 start_period: 15s - image: prom/prometheus:v3.13.2 + image: prom/prometheus:v3.14.0 volumes: - ./configurations/prometheus.yaml:/etc/prometheus/prometheus.yml:ro - prometheus-data:/prometheus diff --git a/src/development/redis/compose.yaml b/src/development/redis/compose.yaml index 4e8e8db9..5a21d72b 100644 --- a/src/development/redis/compose.yaml +++ b/src/development/redis/compose.yaml @@ -10,7 +10,7 @@ services: timeout: 5s retries: 5 start_period: 10s - image: redis:8.10.0-alpine + image: redis:8.10.1-alpine volumes: - redis-data:/data volumes: diff --git a/src/development/redpanda/compose.yaml b/src/development/redpanda/compose.yaml index 1617046b..57ec8045 100644 --- a/src/development/redpanda/compose.yaml +++ b/src/development/redpanda/compose.yaml @@ -18,7 +18,7 @@ services: timeout: 10s retries: 3 start_period: 30s - image: redpandadata/redpanda:v26.2.1 + image: redpandadata/redpanda:v26.2.2 volumes: - redpanda-data:/var/lib/redpanda/data redpanda-console: @@ -42,7 +42,7 @@ services: timeout: 5s retries: 3 start_period: 15s - image: redpandadata/console:v3.10.0 + image: redpandadata/console:v3.11.0 volumes: - ./configurations/config.yaml:/srv/app/redpanda-config.yaml:ro volumes: diff --git a/src/development/sqitch/compose.yaml b/src/development/sqitch/compose.yaml index 12499b7b..aab6ca6e 100644 --- a/src/development/sqitch/compose.yaml +++ b/src/development/sqitch/compose.yaml @@ -16,6 +16,8 @@ services: secrets: - postgres-role-service-grafana-password - postgres-role-service-grafana-username + - postgres-role-service-jobber-password + - postgres-role-service-jobber-username - postgres-role-service-postgraphile-password - postgres-role-service-postgraphile-username - postgres-role-service-reccoom-password diff --git a/src/development/traefik/compose.yaml b/src/development/traefik/compose.yaml index b0b60d29..0aeee6e6 100644 --- a/src/development/traefik/compose.yaml +++ b/src/development/traefik/compose.yaml @@ -37,7 +37,7 @@ services: timeout: 5s retries: 3 start_period: 15s - image: traefik:v3.7.10 + image: traefik:v3.7.12 ports: # dargstack:dev-only - mode: host # dargstack:dev-only protocol: tcp # dargstack:dev-only diff --git a/src/development/vibetype/compose.yaml b/src/development/vibetype/compose.yaml index ad9ab920..1db9f3d7 100644 --- a/src/development/vibetype/compose.yaml +++ b/src/development/vibetype/compose.yaml @@ -53,7 +53,7 @@ services: image: vibetype/vibetype:development secrets: - source: vibetype-api-notification-secret - target: /run/environment-variables/NUXT_API_NOTIFICATION_SECRET + target: /run/environment-variables/NUXT_VIBETYPE_API_NOTIFICATION_SECRET - source: vibetype-aws-credentials target: /home/node/.aws/credentials - source: vibetype-firebase-service-account-credentials diff --git a/src/production/.env.template b/src/production/.env.template index 8ffc032b..8934c80b 100644 --- a/src/production/.env.template +++ b/src/production/.env.template @@ -1,5 +1,6 @@ CLOUDFLARED_TUNNEL_TOKEN= SENTRY_CRONS= +SENTRY_CRONS_OUTBOX_PURGE= STACK_DOMAIN= TRAEFIK_ACME_EMAIL= TRAEFIK_ACME_PROVIDER= \ No newline at end of file diff --git a/src/production/cloudflared/compose.yaml b/src/production/cloudflared/compose.yaml index c22ba4a9..3020076f 100644 --- a/src/production/cloudflared/compose.yaml +++ b/src/production/cloudflared/compose.yaml @@ -9,4 +9,4 @@ services: order: start-first environment: TUNNEL_TOKEN: ${CLOUDFLARED_TUNNEL_TOKEN} - image: cloudflare/cloudflared:2026.7.3 + image: cloudflare/cloudflared:2026.8.2 diff --git a/src/production/jobber/compose.yaml b/src/production/jobber/compose.yaml index 063fbc2f..764b0aa8 100644 --- a/src/production/jobber/compose.yaml +++ b/src/production/jobber/compose.yaml @@ -5,6 +5,7 @@ services: order: stop-first environment: SENTRY_CRONS: ${SENTRY_CRONS} + SENTRY_CRONS_OUTBOX_PURGE: ${SENTRY_CRONS_OUTBOX_PURGE} volumes: - (( append )) - postgres-backup-data:/backups/ diff --git a/src/production/jobber/configurations/.jobber b/src/production/jobber/configurations/.jobber index 162ba232..69266354 100644 --- a/src/production/jobber/configurations/.jobber +++ b/src/production/jobber/configurations/.jobber @@ -18,3 +18,17 @@ jobs: notifyOnFailure: - type: program path: /srv/sinks/sentry/error.sh + OutboxPurge: + cmd: | + /srv/sinks/sentry-outbox-purge/in-progress.sh + PGPASSWORD="$(cat /run/secrets/postgres-role-service-jobber-password)" psql -v ON_ERROR_STOP=1 -h "$POSTGRES_HOST" -U "$(cat /run/secrets/postgres-role-service-jobber-username)" -d "$(cat "$POSTGRES_DB_FILE")" -c "DELETE FROM vibetype_private.outbox WHERE created_at < now() - interval '24 hours'" + time: 0 0 */2 * + notifyOnSuccess: + - type: program + path: /srv/sinks/sentry-outbox-purge/ok.sh + notifyOnError: + - type: program + path: /srv/sinks/sentry-outbox-purge/error.sh + notifyOnFailure: + - type: program + path: /srv/sinks/sentry-outbox-purge/error.sh diff --git a/src/production/postgraphile/compose.yaml b/src/production/postgraphile/compose.yaml index f2bd0340..ca73df0c 100644 --- a/src/production/postgraphile/compose.yaml +++ b/src/production/postgraphile/compose.yaml @@ -8,4 +8,4 @@ services: - traefik.http.routers.postgraphile-secure-ruru.tls.certresolver=default update_config: order: start-first - image: ghcr.io/maevsi/postgraphile:2.2.2 + image: ghcr.io/maevsi/postgraphile:2.2.4 diff --git a/src/production/reccoom/compose.yaml b/src/production/reccoom/compose.yaml index 6a2d830b..82818bf3 100644 --- a/src/production/reccoom/compose.yaml +++ b/src/production/reccoom/compose.yaml @@ -5,21 +5,21 @@ services: order: start-first environment: SENTRY_TRACES_SAMPLE_RATE: "0.1" - image: ghcr.io/maevsi/reccoom:0.22.3 + image: ghcr.io/maevsi/reccoom:0.23.0 reccoom-consumer: deploy: update_config: order: start-first environment: SENTRY_TRACES_SAMPLE_RATE: "0.1" - image: ghcr.io/maevsi/reccoom:0.22.3 + image: ghcr.io/maevsi/reccoom:0.23.0 reccoom-migration: deploy: update_config: order: start-first environment: SENTRY_TRACES_SAMPLE_RATE: "0.1" - image: ghcr.io/maevsi/reccoom:0.22.3 + image: ghcr.io/maevsi/reccoom:0.23.0 volumes: (( prune )) reccoom-postgres: deploy: diff --git a/src/production/sqitch/compose.yaml b/src/production/sqitch/compose.yaml index f7334f16..56a57b25 100644 --- a/src/production/sqitch/compose.yaml +++ b/src/production/sqitch/compose.yaml @@ -3,5 +3,5 @@ services: deploy: update_config: order: stop-first - image: ghcr.io/maevsi/sqitch:12.2.1 + image: ghcr.io/maevsi/sqitch:12.3.0 volumes: (( prune )) diff --git a/src/production/traefik/compose.yaml b/src/production/traefik/compose.yaml index 8d430c9c..32982339 100644 --- a/src/production/traefik/compose.yaml +++ b/src/production/traefik/compose.yaml @@ -24,6 +24,9 @@ services: secrets: - traefik-cf-dns-api-token - traefik-cf-zone-api-token + volumes: + - (( append )) + - acme-data:/etc/traefik/acme/ traefik-certs-dumper: # You cannot access the reverse proxy's certificate helper directly. command: diff --git a/src/production/vibetype/compose.yaml b/src/production/vibetype/compose.yaml index 540767ce..7f4612e6 100644 --- a/src/production/vibetype/compose.yaml +++ b/src/production/vibetype/compose.yaml @@ -7,7 +7,7 @@ services: - traefik.http.routers.vibetype-secure.tls.certresolver=default update_config: order: start-first - image: ghcr.io/maevsi/vibetype:15.14.0 + image: ghcr.io/maevsi/vibetype:15.23.0 # vibetype-beta: # # You can access the main project frontend's beta version at [beta.app.localhost](https://beta.app.localhost/). # deploy: