Files
opensourcepos/docker-compose.yml
T
jekkos 23f52ddefd fix(security): run key-conversion as one locked transaction
Address CodeRabbit Major findings from the 4th re-review of the env
helper and its callers:

1. Hold .env.lock for the entire CI3 -> CI4 conversion transaction
   (backup -> rotate -> re-encrypt -> verify -> persist -> cleanup) so a
   concurrent worker cannot interleave a key write between the rotation
   and the ciphertext save. Split rotateEncryptionKey into a lock-free
   core (rotateEncryptionKeyUnlock) plus the existing lock wrapper and a
   new rotateEncryptionKeyTransaction that owns the lock across the full
   unit and performs both the in-lock rollback (abortEncryptionConversion)
   and the in-lock backup removal on success.

2. Treat the legacy value '0' as non-empty data so key rotation still
   persists the re-encrypted ciphertext when '0' is the only stored
   secret (array_filter would have dropped it and skipped saveAll).

3. Wrap the post-rotation re-encrypt/verify/saveAll sequence in a
   catch (Throwable) across all three call-sites so CI4
   EncryptionException, ReflectionException from batch_save, a failed
   round-trip verify, and any other failure all roll the .env key back
   to the pre-rotation state.

4. In Docker Compose, use long-syntax bind with create_host_path: false
   and document in INSTALL.md that the host .env must be a regular file
   (a missing one is no longer auto-created as a directory, and the
   mount now rejects a missing source on Compose implementations that
   support the flag).

Files touched: app/Helpers/security_helper.php, app/Commands/EnvProvision.php,
app/Database/Migrations/20220127000000_convertToCI4.php, docker-compose.yml,
INSTALL.md. All 4 existing helper tests still pass via CI.
2026-09-16 11:47:10 +00:00

38 lines
1.3 KiB
YAML

include:
- docker/docker-mysql.yml
services:
ospos:
image: jekkos/opensourcepos:master
restart: always
depends_on:
- mysql
ports:
- "80:80"
networks:
- app_net
command: ["sh", "-c", "php spark env:provision && exec apache2-foreground"]
volumes:
# .env holds the two runtime-generated secrets (encryption.key +
# throttle.key), persisted as a single host file so the same keys
# survive container recreation (a named volume is a directory and
# forces .env to be a directory, breaking atomicWriteFile's rename).
# create_host_path is explicitly false so a missing host file fails
# startup instead of being auto-created as a directory (see INSTALL.md).
- type: bind
source: ./.env
target: /app/.env
bind:
create_host_path: false
- uploads:/app/public/uploads
- logs:/app/writable/logs
environment:
- CI_ENVIRONMENT=production
- ALLOWED_HOSTNAMES=localhost
- FORCE_HTTPS=false
- PHP_TIMEZONE=UTC
- MYSQL_USERNAME=admin
- MYSQL_PASSWORD=pointofsale
- MYSQL_DB_NAME=ospos
- MYSQL_HOST_NAME=mysql