diff --git a/apps/web/package.json b/apps/web/package.json index e1939c9..3006308 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -18,7 +18,7 @@ "@capakraken/db": "workspace:*", "@capakraken/engine": "workspace:*", "@capakraken/shared": "workspace:*", -"@dnd-kit/core": "^6.3.1", + "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@node-rs/argon2": "^2.0.2", @@ -34,7 +34,7 @@ "dompurify": "^3.3.3", "exceljs": "^4.4.0", "framer-motion": "^12.38.0", - "next": "^15.1.7", + "next": "^15.5.15", "next-auth": "^5.0.0-beta.25", "otpauth": "^9.5.0", "qrcode": "^1.5.4", diff --git a/package.json b/package.json index 7015464..8e04f26 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,8 @@ "pnpm": { "overrides": { "flatted": "^3.4.2", - "picomatch": "^4.0.4" + "picomatch": "^4.0.4", + "lodash-es": "^4.18.0" } }, "packageManager": "pnpm@9.14.2", diff --git a/packages/api/package.json b/packages/api/package.json index 22e2e7a..5e81e14 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -28,7 +28,7 @@ "@trpc/server": "^11.0.0", "@types/nodemailer": "^7.0.11", "ioredis": "^5.10.0", - "nodemailer": "^8.0.1", + "nodemailer": "^8.0.5", "openai": "^6.27.0", "otpauth": "^9.5.0", "pino": "^10.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 375e4d4..f38ae21 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,7 @@ settings: overrides: flatted: ^3.4.2 picomatch: ^4.0.4 + lodash-es: ^4.18.0 importers: @@ -66,7 +67,7 @@ importers: version: 4.3.2(react@19.2.4) '@sentry/nextjs': specifier: ^10.45.0 - version: 10.45.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.4) + version: 10.45.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@15.5.15(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.4) '@tanstack/react-query': specifier: ^5.62.16 version: 5.90.21(react@19.2.4) @@ -98,11 +99,11 @@ importers: specifier: ^12.38.0 version: 12.38.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) next: - specifier: ^15.1.7 - version: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + specifier: ^15.5.15 + version: 15.5.15(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) next-auth: specifier: ^5.0.0-beta.25 - version: 5.0.0-beta.30(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) + version: 5.0.0-beta.30(next@15.5.15(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) otpauth: specifier: ^9.5.0 version: 9.5.0 @@ -210,8 +211,8 @@ importers: specifier: ^5.10.0 version: 5.10.0 nodemailer: - specifier: ^8.0.1 - version: 8.0.1 + specifier: ^8.0.5 + version: 8.0.5 openai: specifier: ^6.27.0 version: 6.27.0(zod@3.25.76) @@ -1049,53 +1050,53 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@next/env@15.5.12': - resolution: {integrity: sha512-pUvdJN1on574wQHjaBfNGDt9Mz5utDSZFsIIQkMzPgNS8ZvT4H2mwOrOIClwsQOb6EGx5M76/CZr6G8i6pSpLg==} + '@next/env@15.5.15': + resolution: {integrity: sha512-vcmyu5/MyFzN7CdqRHO3uHO44p/QPCZkuTUXroeUmhNP8bL5PHFEhik22JUazt+CDDoD6EpBYRCaS2pISL+/hg==} - '@next/swc-darwin-arm64@15.5.12': - resolution: {integrity: sha512-RnRjBtH8S8eXCpUNkQ+543DUc7ys8y15VxmFU9HRqlo9BG3CcBUiwNtF8SNoi2xvGCVJq1vl2yYq+3oISBS0Zg==} + '@next/swc-darwin-arm64@15.5.15': + resolution: {integrity: sha512-6PvFO2Tzt10GFK2Ro9tAVEtacMqRmTarYMFKAnV2vYMdwWc73xzmDQyAV7SwEdMhzmiRoo7+m88DuiXlJlGeaw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.5.12': - resolution: {integrity: sha512-nqa9/7iQlboF1EFtNhWxQA0rQstmYRSBGxSM6g3GxvxHxcoeqVXfGNr9stJOme674m2V7r4E3+jEhhGvSQhJRA==} + '@next/swc-darwin-x64@15.5.15': + resolution: {integrity: sha512-G+YNV+z6FDZTp/+IdGyIMFqalBTaQSnvAA+X/hrt+eaTRFSznRMz9K7rTmzvM6tDmKegNtyzgufZW0HwVzEqaQ==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.5.12': - resolution: {integrity: sha512-dCzAjqhDHwmoB2M4eYfVKqXs99QdQxNQVpftvP1eGVppamXh/OkDAwV737Zr0KPXEqRUMN4uCjh6mjO+XtF3Mw==} + '@next/swc-linux-arm64-gnu@15.5.15': + resolution: {integrity: sha512-eVkrMcVIBqGfXB+QUC7jjZ94Z6uX/dNStbQFabewAnk13Uy18Igd1YZ/GtPRzdhtm7QwC0e6o7zOQecul4iC1w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.5.12': - resolution: {integrity: sha512-+fpGWvQiITgf7PUtbWY1H7qUSnBZsPPLyyq03QuAKpVoTy/QUx1JptEDTQMVvQhvizCEuNLEeghrQUyXQOekuw==} + '@next/swc-linux-arm64-musl@15.5.15': + resolution: {integrity: sha512-RwSHKMQ7InLy5GfkY2/n5PcFycKA08qI1VST78n09nN36nUPqCvGSMiLXlfUmzmpQpF6XeBYP2KRWHi0UW3uNg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.5.12': - resolution: {integrity: sha512-jSLvgdRRL/hrFAPqEjJf1fFguC719kmcptjNVDJl26BnJIpjL3KH5h6mzR4mAweociLQaqvt4UyzfbFjgAdDcw==} + '@next/swc-linux-x64-gnu@15.5.15': + resolution: {integrity: sha512-nplqvY86LakS+eeiuWsNWvfmK8pFcOEW7ZtVRt4QH70lL+0x6LG/m1OpJ/tvrbwjmR8HH9/fH2jzW1GlL03TIg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.5.12': - resolution: {integrity: sha512-/uaF0WfmYqQgLfPmN6BvULwxY0dufI2mlN2JbOKqqceZh1G4hjREyi7pg03zjfyS6eqNemHAZPSoP84x17vo6w==} + '@next/swc-linux-x64-musl@15.5.15': + resolution: {integrity: sha512-eAgl9NKQ84/sww0v81DQINl/vL2IBxD7sMybd0cWRw6wqgouVI53brVRBrggqBRP/NWeIAE1dm5cbKYoiMlqDQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.5.12': - resolution: {integrity: sha512-xhsL1OvQSfGmlL5RbOmU+FV120urrgFpYLq+6U8C6KIym32gZT6XF/SDE92jKzzlPWskkbjOKCpqk5m4i8PEfg==} + '@next/swc-win32-arm64-msvc@15.5.15': + resolution: {integrity: sha512-GJVZC86lzSquh0MtvZT+L7G8+jMnJcldloOjA8Kf3wXvBrvb6OGe2MzPuALxFshSm/IpwUtD2mIoof39ymf52A==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.5.12': - resolution: {integrity: sha512-Z1Dh6lhFkxvBDH1FoW6OU/L6prYwPSlwjLiZkExIAh8fbP6iI/M7iGTQAJPYJ9YFlWobCZ1PHbchFhFYb2ADkw==} + '@next/swc-win32-x64-msvc@15.5.15': + resolution: {integrity: sha512-nFucjVdwlFqxh/JG3hWSJ4p8+YJV7Ii8aPDuBQULB6DzUF4UNZETXLfEUk+oI2zEznWWULPt7MeuTE6xtK1HSA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -3352,8 +3353,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.23: - resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} @@ -3525,8 +3526,8 @@ packages: nodemailer: optional: true - next@15.5.12: - resolution: {integrity: sha512-Fi/wQ4Etlrn60rz78bebG1i1SR20QxvV8tVp6iJspjLUSHcZoeUXCt+vmWoEcza85ElZzExK/jJ/F6SvtGktjA==} + next@15.5.15: + resolution: {integrity: sha512-VSqCrJwtLVGwAVE0Sb/yikrQfkwkZW9p+lL/J4+xe+G3ZA+QnWPqgcfH1tDUEuk9y+pthzzVFp4L/U8JerMfMQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -3573,8 +3574,8 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - nodemailer@8.0.1: - resolution: {integrity: sha512-5kcldIXmaEjZcHR6F28IKGSgpmZHaF1IXLWFTG+Xh3S+Cce4MiakLtWY+PlBU69fLbRa8HlaGIrC/QolUpHkhg==} + nodemailer@8.0.5: + resolution: {integrity: sha512-0PF8Yb1yZuQfQbq+5/pZJrtF6WQcjTd5/S4JOHs9PGFxuTqoB/icwuB44pOdURHJbRKX1PPoJZtY7R4VUoCC8w==} engines: {node: '>=6.0.0'} normalize-path@3.0.0: @@ -5224,30 +5225,30 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@next/env@15.5.12': {} + '@next/env@15.5.15': {} - '@next/swc-darwin-arm64@15.5.12': + '@next/swc-darwin-arm64@15.5.15': optional: true - '@next/swc-darwin-x64@15.5.12': + '@next/swc-darwin-x64@15.5.15': optional: true - '@next/swc-linux-arm64-gnu@15.5.12': + '@next/swc-linux-arm64-gnu@15.5.15': optional: true - '@next/swc-linux-arm64-musl@15.5.12': + '@next/swc-linux-arm64-musl@15.5.15': optional: true - '@next/swc-linux-x64-gnu@15.5.12': + '@next/swc-linux-x64-gnu@15.5.15': optional: true - '@next/swc-linux-x64-musl@15.5.12': + '@next/swc-linux-x64-musl@15.5.15': optional: true - '@next/swc-win32-arm64-msvc@15.5.12': + '@next/swc-win32-arm64-msvc@15.5.15': optional: true - '@next/swc-win32-x64-msvc@15.5.12': + '@next/swc-win32-x64-msvc@15.5.15': optional: true '@noble/hashes@2.0.1': {} @@ -5928,7 +5929,7 @@ snapshots: '@sentry/core@10.45.0': {} - '@sentry/nextjs@10.45.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.4)': + '@sentry/nextjs@10.45.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@15.5.15(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(webpack@5.105.4)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.40.0 @@ -5941,7 +5942,7 @@ snapshots: '@sentry/react': 10.45.0(react@19.2.4) '@sentry/vercel-edge': 10.45.0 '@sentry/webpack-plugin': 5.1.1(webpack@5.105.4) - next: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next: 15.5.15(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) rollup: 4.59.0 stacktrace-parser: 0.1.11 transitivePeerDependencies: @@ -7784,7 +7785,7 @@ snapshots: kapsule@1.16.3: dependencies: - lodash-es: 4.17.23 + lodash-es: 4.18.1 keyv@4.5.4: dependencies: @@ -7824,7 +7825,7 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.23: {} + lodash-es@4.18.1: {} lodash.defaults@4.2.0: {} @@ -7951,15 +7952,15 @@ snapshots: neo-async@2.6.2: {} - next-auth@5.0.0-beta.30(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4): + next-auth@5.0.0-beta.30(next@15.5.15(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4): dependencies: '@auth/core': 0.41.0 - next: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + next: 15.5.15(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 - next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + next@15.5.15(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: - '@next/env': 15.5.12 + '@next/env': 15.5.15 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001776 postcss: 8.4.31 @@ -7967,14 +7968,14 @@ snapshots: react-dom: 19.2.4(react@19.2.4) styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.4) optionalDependencies: - '@next/swc-darwin-arm64': 15.5.12 - '@next/swc-darwin-x64': 15.5.12 - '@next/swc-linux-arm64-gnu': 15.5.12 - '@next/swc-linux-arm64-musl': 15.5.12 - '@next/swc-linux-x64-gnu': 15.5.12 - '@next/swc-linux-x64-musl': 15.5.12 - '@next/swc-win32-arm64-msvc': 15.5.12 - '@next/swc-win32-x64-msvc': 15.5.12 + '@next/swc-darwin-arm64': 15.5.15 + '@next/swc-darwin-x64': 15.5.15 + '@next/swc-linux-arm64-gnu': 15.5.15 + '@next/swc-linux-arm64-musl': 15.5.15 + '@next/swc-linux-x64-gnu': 15.5.15 + '@next/swc-linux-x64-musl': 15.5.15 + '@next/swc-win32-arm64-msvc': 15.5.15 + '@next/swc-win32-x64-msvc': 15.5.15 '@opentelemetry/api': 1.9.0 '@playwright/test': 1.58.2 sharp: 0.34.5 @@ -8004,7 +8005,7 @@ snapshots: node-releases@2.0.27: {} - nodemailer@8.0.1: {} + nodemailer@8.0.5: {} normalize-path@3.0.0: {} diff --git a/scripts/harden-postgres.sh b/scripts/harden-postgres.sh index 0d61c8c..bb7bf20 100755 --- a/scripts/harden-postgres.sh +++ b/scripts/harden-postgres.sh @@ -2,8 +2,8 @@ # Remove SUPERUSER from the application database user # Run after initial setup: bash scripts/harden-postgres.sh -DB_USER="capakraken" -DB_NAME="capakraken" +DB_USER="${DB_USER:-capakraken}" +DB_NAME="${DB_NAME:-capakraken}" echo "Hardening PostgreSQL for $DB_USER..." diff --git a/scripts/start.sh b/scripts/start.sh index d93d2e1..974f646 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -2,6 +2,9 @@ set -euo pipefail cd "$(dirname "$0")/.." +APP_PORT="${APP_PORT:-3100}" +APP_CONTAINER="${APP_CONTAINER:-$(docker compose --profile full ps -q app 2>/dev/null | head -1)}" + echo "Starting CapaKraken..." # 1. Start Docker services @@ -19,20 +22,23 @@ for i in {1..30}; do done # 3. Start the web app in Docker for a stable lifecycle -echo " Starting app container on port 3100..." +echo " Starting app container on port ${APP_PORT}..." docker compose --profile full up -d app +# Resolve container name after start (docker compose generates it from project dir + service) +APP_CONTAINER="$(docker compose --profile full ps -q app 2>/dev/null | head -1)" + # 4. Wait for server to be ready # Allow up to 90s: prisma generate + migrate deploy + next dev compilation echo " Waiting for server (up to 90s)..." for i in {1..90}; do - if curl -sf http://localhost:3100/api/health > /dev/null 2>&1; then + if curl -sf "http://localhost:${APP_PORT}/api/health" > /dev/null 2>&1; then echo "" echo "CapaKraken is running!" - curl -s http://localhost:3100/api/ready | python3 -m json.tool 2>/dev/null || curl -s http://localhost:3100/api/ready + curl -s "http://localhost:${APP_PORT}/api/ready" | python3 -m json.tool 2>/dev/null || curl -s "http://localhost:${APP_PORT}/api/ready" echo "" - echo " URL: http://localhost:3100" - echo " Logs: docker logs -f capakraken-app-1" + echo " URL: http://localhost:${APP_PORT}" + echo " Logs: docker logs -f ${APP_CONTAINER}" exit 0 fi # Print progress every 10s @@ -43,5 +49,5 @@ for i in {1..90}; do done echo "ERROR: Server failed to start within 90 seconds" -echo "Check logs: docker logs --tail 100 capakraken-app-1" +echo "Check logs: docker logs --tail 100 ${APP_CONTAINER}" exit 1 diff --git a/scripts/stop.sh b/scripts/stop.sh index e3af8ca..1eb35f8 100755 --- a/scripts/stop.sh +++ b/scripts/stop.sh @@ -16,8 +16,12 @@ if [ -f /tmp/capakraken-dev.pid ]; then rm -f /tmp/capakraken-dev.pid fi -# Also kill anything on port 3100 -fuser -k 3100/tcp 2>/dev/null || true +# Also kill anything on port 3100 (cross-platform: lsof works on Linux + macOS) +if command -v lsof >/dev/null 2>&1; then + lsof -ti:3100 2>/dev/null | xargs kill 2>/dev/null || true +elif command -v fuser >/dev/null 2>&1; then + fuser -k 3100/tcp 2>/dev/null || true +fi # 2. Stop Docker services (keep data volumes) echo " Stopping app, PostgreSQL and Redis..." diff --git a/tooling/deploy/deploy-compose.sh b/tooling/deploy/deploy-compose.sh index 7ef1586..4142b5a 100755 --- a/tooling/deploy/deploy-compose.sh +++ b/tooling/deploy/deploy-compose.sh @@ -32,8 +32,9 @@ echo "App env file: ${APP_ENV_FILE}" echo "App image: ${APP_IMAGE}" echo "Migrator image: ${MIGRATOR_IMAGE}" +DOCKER_REGISTRY="${DOCKER_REGISTRY:-ghcr.io}" if [ -n "${GHCR_USERNAME:-}" ] && [ -n "${GHCR_TOKEN:-}" ]; then - printf '%s\n' "${GHCR_TOKEN}" | docker login ghcr.io -u "${GHCR_USERNAME}" --password-stdin + printf '%s\n' "${GHCR_TOKEN}" | docker login "${DOCKER_REGISTRY}" -u "${GHCR_USERNAME}" --password-stdin fi docker compose -f "${COMPOSE_FILE}" config -q diff --git a/tooling/docker/app-dev-start.sh b/tooling/docker/app-dev-start.sh index 12419f3..9f4aa72 100644 --- a/tooling/docker/app-dev-start.sh +++ b/tooling/docker/app-dev-start.sh @@ -17,15 +17,28 @@ pnpm --filter @capakraken/db db:migrate:deploy pnpm check:exports pnpm check:imports -repo_uid="$(stat -c '%u' /app)" -repo_gid="$(stat -c '%g' /app)" repo_home="/tmp/capakraken-dev-home" +# Cross-platform stat: GNU stat uses -c, BSD/macOS stat uses -f +if stat -c '%u' /app >/dev/null 2>&1; then + repo_uid="$(stat -c '%u' /app)" + repo_gid="$(stat -c '%g' /app)" +else + repo_uid="$(stat -f '%u' /app)" + repo_gid="$(stat -f '%g' /app)" +fi + mkdir -p /app/apps/web/.next mkdir -p "$repo_home/.config/pnpm" chown -R "$repo_uid:$repo_gid" /app/apps/web/.next chown -R "$repo_uid:$repo_gid" "$repo_home" -exec setpriv --reuid="$repo_uid" --regid="$repo_gid" --clear-groups \ - env HOME="$repo_home" XDG_CONFIG_HOME="$repo_home/.config" \ - pnpm --filter @capakraken/web exec next dev -H 0.0.0.0 -p 3100 +# Cross-platform privilege drop: setpriv (Linux) or su (macOS/BSD) +if command -v setpriv >/dev/null 2>&1; then + exec setpriv --reuid="$repo_uid" --regid="$repo_gid" --clear-groups \ + env HOME="$repo_home" XDG_CONFIG_HOME="$repo_home/.config" \ + pnpm --filter @capakraken/web exec next dev -H 0.0.0.0 -p 3100 +else + exec su -s /bin/sh "#${repo_uid}" -c \ + "HOME='$repo_home' XDG_CONFIG_HOME='$repo_home/.config' pnpm --filter @capakraken/web exec next dev -H 0.0.0.0 -p 3100" +fi