fix(v2): deterministic Docker build — pin pnpm, fix supply-chain policy, workspace-level install
- Add workspace-level pnpm install in Dockerfile so pnpm-workspace.yaml supply-chain settings (onlyBuiltDependencies, allowBuilds) apply uniformly - Pin pnpm@11.5.2 via corepack with sha1 hash to prevent future policy drift - Downgrade postcss to ^8.5.22 (8.5.23 was <24h old, violated minimumReleaseAge) - Regenerate frontend/pnpm-lock.yaml and add root pnpm-lock.yaml for full workspace - Add binaryTargets to Prisma schema for linux-musl (Alpine) + debian compatibility - Run pnpm approve-builds to set allowBuilds for esbuild, ssh2, prisma, @prisma/* - Fix docker-compose.yml: postgres:18-alpine volume at /var/lib/postgresql (not /data) - Add .env.docker.example; ignore .env.docker in .gitignore Integration tests (Docker Compose against real Gitea 1.26.2): ✅ Docker image builds cleanly (pnpm frozen-lockfile, no policy violations) ✅ postgres:18-alpine starts healthy ✅ Prisma migrations run on startup ✅ Founder registration and session auth ✅ Gitea connection validated (PAT scope check) ✅ Webhook registered on test repo (Hook ID 11) ✅ PR opened → HMAC verified → preview created → DEPLOY job queued ✅ Gitea PR comment posted (write:issue scope confirmed working) ✅ Deploy fails correctly at AWS step: "Region is missing" (no creds in test env) ✅ PR closed → STOP job created and completed (status DONE) ✅ HMAC rejection: wrong signature → 401 ✅ /pp stop via issue_comment webhook → accepted Blocked (expected): EC2 provisioning requires AWS credentials not present in CI/test env. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# Copy to .env.docker and fill in real values before running docker compose
|
||||
SESSION_SECRET=change_me_min_32_chars_random_hex
|
||||
PP_BASE_URL=http://localhost:5000
|
||||
ENCRYPTION_KEY=change_me_64_hex_chars_used_to_encrypt_gitea_and_aws_credentials
|
||||
@@ -2,6 +2,7 @@ node_modules/
|
||||
backend/dist/
|
||||
frontend/dist/
|
||||
.env
|
||||
.env.docker
|
||||
*.env.local
|
||||
*.log
|
||||
.DS_Store
|
||||
|
||||
+33
-14
@@ -1,22 +1,41 @@
|
||||
FROM node:24-alpine AS frontend-builder
|
||||
WORKDIR /app/frontend
|
||||
COPY frontend/package.json frontend/pnpm-lock.yaml* ./
|
||||
RUN npm install -g pnpm && pnpm install --frozen-lockfile
|
||||
COPY frontend/ ./
|
||||
RUN pnpm build
|
||||
# Stage 1: Install all workspace dependencies
|
||||
# Using workspace-level install so pnpm-workspace.yaml settings (onlyBuiltDependencies,
|
||||
# supply-chain policies, etc.) apply uniformly — the canonical pnpm monorepo pattern.
|
||||
FROM node:24-alpine AS deps
|
||||
WORKDIR /app
|
||||
|
||||
FROM node:24-alpine AS backend-builder
|
||||
WORKDIR /app/backend
|
||||
COPY backend/package.json backend/pnpm-lock.yaml* ./
|
||||
RUN npm install -g pnpm && pnpm install --frozen-lockfile
|
||||
COPY backend/ ./
|
||||
COPY prisma/ ../prisma/
|
||||
RUN pnpm run generate && pnpm run build
|
||||
# Copy workspace manifest files first for layer caching
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||
COPY frontend/package.json ./frontend/
|
||||
COPY backend/package.json ./backend/
|
||||
COPY prisma/ ./prisma/
|
||||
|
||||
# corepack activates the exact pnpm version declared in package.json#packageManager.
|
||||
# This is hash-verified (sha1) and prevents newer pnpm from applying different
|
||||
# supply-chain policies (e.g. minimumReleaseAge) against a lockfile generated with
|
||||
# the pinned version.
|
||||
RUN corepack enable && corepack install && \
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# Stage 2: Build frontend
|
||||
FROM deps AS frontend-builder
|
||||
COPY frontend/ ./frontend/
|
||||
RUN pnpm --filter pp-frontend run build
|
||||
|
||||
# Stage 3: Build backend + Prisma client
|
||||
FROM deps AS backend-builder
|
||||
COPY backend/ ./backend/
|
||||
RUN pnpm --filter pp-backend run generate && \
|
||||
pnpm --filter pp-backend run build
|
||||
|
||||
# Stage 4: Minimal production runner
|
||||
FROM node:24-alpine AS runner
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache openssl
|
||||
|
||||
# Root node_modules contains prisma CLI and hoisted deps; backend node_modules has
|
||||
# the backend-specific symlinks. Both are needed at runtime.
|
||||
COPY --from=backend-builder /app/node_modules ./node_modules
|
||||
COPY --from=backend-builder /app/backend/dist ./backend/dist
|
||||
COPY --from=backend-builder /app/backend/node_modules ./backend/node_modules
|
||||
COPY --from=backend-builder /app/backend/package.json ./backend/package.json
|
||||
@@ -27,4 +46,4 @@ WORKDIR /app/backend
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
CMD sh -c "npx prisma migrate deploy --schema=../prisma/schema.prisma && node dist/index.js"
|
||||
CMD sh -c "../node_modules/.bin/prisma migrate deploy --schema=../prisma/schema.prisma && node dist/index.js"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"version": "1.0.0",
|
||||
"description": "PR Previews backend",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@11.5.2+sha1.7ab39d363d1ca5b2fb97795f45291083da4a1393",
|
||||
"scripts": {
|
||||
"dev": "rimraf dist && esbuild \"src/**/*.ts\" --platform=node --sourcemap --ignore-annotations --format=cjs --target=es2022 --outdir=dist && cd dist && node index.js",
|
||||
"build": "rimraf dist && esbuild \"src/**/*.ts\" --platform=node --sourcemap --ignore-annotations --format=cjs --target=es2022 --outdir=dist",
|
||||
|
||||
+1
-3
@@ -1,5 +1,3 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
pp-db:
|
||||
image: postgres:18-alpine
|
||||
@@ -9,7 +7,7 @@ services:
|
||||
POSTGRES_PASSWORD: pp_password
|
||||
POSTGRES_DB: pp
|
||||
volumes:
|
||||
- pp_db_data:/var/lib/postgresql/data
|
||||
- pp_db_data:/var/lib/postgresql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U pp"]
|
||||
interval: 10s
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"name": "pp-frontend",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@11.5.2+sha1.7ab39d363d1ca5b2fb97795f45291083da4a1393",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -9,18 +10,18 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"motion": "^12.0.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-router-dom": "^7.0.0",
|
||||
"react-toastify": "^11.0.0",
|
||||
"motion": "^12.0.0"
|
||||
"react-toastify": "^11.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/react-dom": "^19.0.0",
|
||||
"@vitejs/plugin-react": "^4.3.0",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"postcss": "^8.4.0",
|
||||
"postcss": "^8.5.22",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^6.0.0"
|
||||
|
||||
Generated
+22
-22
@@ -35,10 +35,10 @@ importers:
|
||||
version: 4.7.0(vite@6.4.3(jiti@1.21.7))
|
||||
autoprefixer:
|
||||
specifier: ^10.4.0
|
||||
version: 10.5.4(postcss@8.5.23)
|
||||
version: 10.5.4(postcss@8.5.22)
|
||||
postcss:
|
||||
specifier: ^8.4.0
|
||||
version: 8.5.23
|
||||
specifier: ^8.5.22
|
||||
version: 8.5.22
|
||||
tailwindcss:
|
||||
specifier: ^3.4.0
|
||||
version: 3.4.19
|
||||
@@ -820,8 +820,8 @@ packages:
|
||||
postcss-value-parser@4.2.0:
|
||||
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
||||
|
||||
postcss@8.5.23:
|
||||
resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==}
|
||||
postcss@8.5.22:
|
||||
resolution: {integrity: sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
@@ -1347,13 +1347,13 @@ snapshots:
|
||||
|
||||
arg@5.0.2: {}
|
||||
|
||||
autoprefixer@10.5.4(postcss@8.5.23):
|
||||
autoprefixer@10.5.4(postcss@8.5.22):
|
||||
dependencies:
|
||||
browserslist: 4.28.7
|
||||
caniuse-lite: 1.0.30001806
|
||||
fraction.js: 5.3.4
|
||||
picocolors: 1.1.1
|
||||
postcss: 8.5.23
|
||||
postcss: 8.5.22
|
||||
postcss-value-parser: 4.2.0
|
||||
|
||||
baseline-browser-mapping@2.11.1: {}
|
||||
@@ -1576,28 +1576,28 @@ snapshots:
|
||||
|
||||
pirates@4.0.7: {}
|
||||
|
||||
postcss-import@15.1.0(postcss@8.5.23):
|
||||
postcss-import@15.1.0(postcss@8.5.22):
|
||||
dependencies:
|
||||
postcss: 8.5.23
|
||||
postcss: 8.5.22
|
||||
postcss-value-parser: 4.2.0
|
||||
read-cache: 1.0.0
|
||||
resolve: 1.22.12
|
||||
|
||||
postcss-js@4.1.0(postcss@8.5.23):
|
||||
postcss-js@4.1.0(postcss@8.5.22):
|
||||
dependencies:
|
||||
camelcase-css: 2.0.1
|
||||
postcss: 8.5.23
|
||||
postcss: 8.5.22
|
||||
|
||||
postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.23):
|
||||
postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.22):
|
||||
dependencies:
|
||||
lilconfig: 3.1.3
|
||||
optionalDependencies:
|
||||
jiti: 1.21.7
|
||||
postcss: 8.5.23
|
||||
postcss: 8.5.22
|
||||
|
||||
postcss-nested@6.2.0(postcss@8.5.23):
|
||||
postcss-nested@6.2.0(postcss@8.5.22):
|
||||
dependencies:
|
||||
postcss: 8.5.23
|
||||
postcss: 8.5.22
|
||||
postcss-selector-parser: 6.1.4
|
||||
|
||||
postcss-selector-parser@6.1.4:
|
||||
@@ -1607,7 +1607,7 @@ snapshots:
|
||||
|
||||
postcss-value-parser@4.2.0: {}
|
||||
|
||||
postcss@8.5.23:
|
||||
postcss@8.5.22:
|
||||
dependencies:
|
||||
nanoid: 3.3.16
|
||||
picocolors: 1.1.1
|
||||
@@ -1732,11 +1732,11 @@ snapshots:
|
||||
normalize-path: 3.0.0
|
||||
object-hash: 3.0.0
|
||||
picocolors: 1.1.1
|
||||
postcss: 8.5.23
|
||||
postcss-import: 15.1.0(postcss@8.5.23)
|
||||
postcss-js: 4.1.0(postcss@8.5.23)
|
||||
postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.23)
|
||||
postcss-nested: 6.2.0(postcss@8.5.23)
|
||||
postcss: 8.5.22
|
||||
postcss-import: 15.1.0(postcss@8.5.22)
|
||||
postcss-js: 4.1.0(postcss@8.5.22)
|
||||
postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.22)
|
||||
postcss-nested: 6.2.0(postcss@8.5.22)
|
||||
postcss-selector-parser: 6.1.4
|
||||
resolve: 1.22.12
|
||||
sucrase: 3.35.1
|
||||
@@ -1780,7 +1780,7 @@ snapshots:
|
||||
esbuild: 0.25.12
|
||||
fdir: 6.5.0(picomatch@4.0.5)
|
||||
picomatch: 4.0.5
|
||||
postcss: 8.5.23
|
||||
postcss: 8.5.22
|
||||
rollup: 4.62.2
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"name": "pp",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@11.5.2+sha1.7ab39d363d1ca5b2fb97795f45291083da4a1393",
|
||||
"devDependencies": {
|
||||
"prisma": "^6.19.3"
|
||||
},
|
||||
|
||||
Generated
+3723
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -2,13 +2,13 @@ packages:
|
||||
- backend
|
||||
- frontend
|
||||
allowBuilds:
|
||||
'@prisma/client': set this to true or false
|
||||
'@prisma/engines': set this to true or false
|
||||
bufferutil: set this to true or false
|
||||
cpu-features: set this to true or false
|
||||
esbuild: set this to true or false
|
||||
prisma: set this to true or false
|
||||
ssh2: set this to true or false
|
||||
'@prisma/client': true
|
||||
'@prisma/engines': true
|
||||
bufferutil: true
|
||||
cpu-features: true
|
||||
esbuild: true
|
||||
prisma: true
|
||||
ssh2: true
|
||||
onlyBuiltDependencies:
|
||||
- '@prisma/client'
|
||||
- '@prisma/engines'
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "debian-openssl-3.0.x", "linux-musl-openssl-3.0.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
|
||||
Reference in New Issue
Block a user