forked from cartsnitch/cartsnitch
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e1d77d7789 | |||
| 8592701382 | |||
| 17447fb5e1 | |||
| b274fdff8e | |||
| a64dc7ab5e | |||
| 0fb99e6c16 |
+119
-8
@@ -13,6 +13,7 @@ concurrency:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
packages: write
|
packages: write
|
||||||
|
security-events: write
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
REGISTRY: ghcr.io
|
||||||
@@ -151,17 +152,43 @@ jobs:
|
|||||||
type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
|
type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
- name: Build and push Docker image
|
- name: Build Docker image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: ${{ github.event_name == 'push' }}
|
load: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
target: prod
|
target: prod
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Scan frontend image for vulnerabilities
|
||||||
|
uses: anchore/scan-action@v5
|
||||||
|
id: scan
|
||||||
|
with:
|
||||||
|
image: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }}"
|
||||||
|
fail-build: true
|
||||||
|
severity-cutoff: high
|
||||||
|
output-format: sarif
|
||||||
|
|
||||||
|
- name: Upload frontend scan results to GitHub Security
|
||||||
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
sarif_file: ${{ steps.scan.outputs.sarif }}
|
||||||
|
|
||||||
|
- name: Push Docker image
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
target: prod
|
||||||
|
cache-from: type=gha
|
||||||
|
|
||||||
- name: Create git tag
|
- name: Create git tag
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
run: |
|
run: |
|
||||||
@@ -221,14 +248,42 @@ jobs:
|
|||||||
type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
|
type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
- name: Build and push auth Docker image
|
- name: Build Docker image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: ./auth
|
context: ./auth
|
||||||
file: ./auth/Dockerfile
|
file: ./auth/Dockerfile
|
||||||
push: ${{ github.event_name == 'push' }}
|
load: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Scan auth image for vulnerabilities
|
||||||
|
uses: anchore/scan-action@v5
|
||||||
|
id: scan
|
||||||
|
with:
|
||||||
|
image: "${{ env.REGISTRY }}/${{ env.AUTH_IMAGE_NAME }}:sha-${{ github.sha }}"
|
||||||
|
fail-build: true
|
||||||
|
severity-cutoff: high
|
||||||
|
output-format: sarif
|
||||||
|
|
||||||
|
- name: Upload auth scan results to GitHub Security
|
||||||
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
sarif_file: ${{ steps.scan.outputs.sarif }}
|
||||||
|
|
||||||
|
- name: Push Docker image
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: ./auth
|
||||||
|
file: ./auth/Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
|
||||||
build-and-push-receiptwitness:
|
build-and-push-receiptwitness:
|
||||||
runs-on: runners-cartsnitch
|
runs-on: runners-cartsnitch
|
||||||
@@ -278,14 +333,42 @@ jobs:
|
|||||||
type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
|
type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
- name: Build and push receiptwitness image
|
- name: Build Docker image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./receiptwitness/Dockerfile
|
file: ./receiptwitness/Dockerfile
|
||||||
push: ${{ github.event_name == 'push' }}
|
load: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Scan receiptwitness image for vulnerabilities
|
||||||
|
uses: anchore/scan-action@v5
|
||||||
|
id: scan
|
||||||
|
with:
|
||||||
|
image: "${{ env.REGISTRY }}/${{ env.RECEIPTWITNESS_IMAGE_NAME }}:sha-${{ github.sha }}"
|
||||||
|
fail-build: true
|
||||||
|
severity-cutoff: high
|
||||||
|
output-format: sarif
|
||||||
|
|
||||||
|
- name: Upload receiptwitness scan results to GitHub Security
|
||||||
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
sarif_file: ${{ steps.scan.outputs.sarif }}
|
||||||
|
|
||||||
|
- name: Push Docker image
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./receiptwitness/Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
|
||||||
build-and-push-api:
|
build-and-push-api:
|
||||||
runs-on: runners-cartsnitch
|
runs-on: runners-cartsnitch
|
||||||
@@ -335,14 +418,42 @@ jobs:
|
|||||||
type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
|
type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||||
|
|
||||||
- name: Build and push API Docker image
|
- name: Build Docker image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: ./api
|
context: ./api
|
||||||
file: ./api/Dockerfile
|
file: ./api/Dockerfile
|
||||||
push: ${{ github.event_name == 'push' }}
|
load: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Scan api image for vulnerabilities
|
||||||
|
uses: anchore/scan-action@v5
|
||||||
|
id: scan
|
||||||
|
with:
|
||||||
|
image: "${{ env.REGISTRY }}/${{ env.API_IMAGE_NAME }}:sha-${{ github.sha }}"
|
||||||
|
fail-build: true
|
||||||
|
severity-cutoff: high
|
||||||
|
output-format: sarif
|
||||||
|
|
||||||
|
- name: Upload api scan results to GitHub Security
|
||||||
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
sarif_file: ${{ steps.scan.outputs.sarif }}
|
||||||
|
|
||||||
|
- name: Push Docker image
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: ./api
|
||||||
|
file: ./api/Dockerfile
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
cache-from: type=gha
|
||||||
|
|
||||||
deploy-dev:
|
deploy-dev:
|
||||||
runs-on: runners-cartsnitch
|
runs-on: runners-cartsnitch
|
||||||
|
|||||||
+4
-1
@@ -1,6 +1,6 @@
|
|||||||
# Stage 1: Build
|
# Stage 1: Build
|
||||||
FROM node:20-alpine AS build
|
FROM node:20-alpine AS build
|
||||||
|
RUN apk update && apk upgrade --no-cache
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package.json package-lock.json ./
|
COPY package.json package-lock.json ./
|
||||||
@@ -11,6 +11,9 @@ RUN npm run build
|
|||||||
|
|
||||||
# Stage 2: Production — uses nginxinc/nginx-unprivileged which runs as non-root (UID 101)
|
# Stage 2: Production — uses nginxinc/nginx-unprivileged which runs as non-root (UID 101)
|
||||||
FROM nginxinc/nginx-unprivileged:stable-alpine AS prod
|
FROM nginxinc/nginx-unprivileged:stable-alpine AS prod
|
||||||
|
USER root
|
||||||
|
RUN apk update && apk upgrade --no-cache
|
||||||
|
USER 101
|
||||||
|
|
||||||
COPY --from=build /app/dist /usr/share/nginx/html
|
COPY --from=build /app/dist /usr/share/nginx/html
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
FROM python:3.12-slim AS build
|
FROM python:3.12-slim AS build
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
build-essential \
|
build-essential \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
@@ -12,7 +12,7 @@ RUN pip install --no-cache-dir --prefix=/install .
|
|||||||
|
|
||||||
FROM python:3.12-slim AS prod
|
FROM python:3.12-slim AS prod
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends libpq5 && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends libpq5 && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN adduser --system --group --uid 1000 app
|
RUN adduser --system --group --uid 1000 app
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
FROM node:22-alpine AS builder
|
FROM node:22-alpine AS builder
|
||||||
|
RUN apk update && apk upgrade --no-cache
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package.json package-lock.json* ./
|
COPY package.json package-lock.json* ./
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
@@ -7,6 +8,7 @@ COPY src/ src/
|
|||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
FROM node:22-alpine
|
FROM node:22-alpine
|
||||||
|
RUN apk update && apk upgrade --no-cache
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
COPY package.json package-lock.json* ./
|
COPY package.json package-lock.json* ./
|
||||||
|
|||||||
Generated
+3
-3
@@ -941,9 +941,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/defu": {
|
"node_modules/defu": {
|
||||||
"version": "6.1.4",
|
"version": "6.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz",
|
||||||
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
"integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/delegates": {
|
"node_modules/delegates": {
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ if (!databaseUrl) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pool = new Pool({
|
export const pool = new Pool({
|
||||||
connectionString: databaseUrl ?? "postgresql://cartsnitch:cartsnitch@localhost:5432/cartsnitch",
|
connectionString: databaseUrl ?? "postgresql://cartsnitch:cartsnitch@localhost:5432/cartsnitch",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+17
-3
@@ -1,6 +1,6 @@
|
|||||||
import { createServer } from "node:http";
|
import { createServer } from "node:http";
|
||||||
import { toNodeHandler } from "better-auth/node";
|
import { toNodeHandler } from "better-auth/node";
|
||||||
import { auth } from "./auth.js";
|
import { auth, pool } from "./auth.js";
|
||||||
|
|
||||||
const port = parseInt(process.env.PORT ?? "3001", 10);
|
const port = parseInt(process.env.PORT ?? "3001", 10);
|
||||||
|
|
||||||
@@ -9,8 +9,22 @@ const handler = toNodeHandler(auth);
|
|||||||
const server = createServer(async (req, res) => {
|
const server = createServer(async (req, res) => {
|
||||||
// Health check
|
// Health check
|
||||||
if (req.url === "/health" && req.method === "GET") {
|
if (req.url === "/health" && req.method === "GET") {
|
||||||
res.writeHead(200, { "Content-Type": "application/json" });
|
try {
|
||||||
res.end(JSON.stringify({ status: "ok" }));
|
const client = await pool.connect();
|
||||||
|
try {
|
||||||
|
await Promise.race([
|
||||||
|
client.query("SELECT 1"),
|
||||||
|
new Promise((_, reject) => setTimeout(() => reject(new Error("DB timeout")), 2000)),
|
||||||
|
]);
|
||||||
|
} finally {
|
||||||
|
client.release();
|
||||||
|
}
|
||||||
|
res.writeHead(200, { "Content-Type": "application/json" });
|
||||||
|
res.end(JSON.stringify({ status: "ok", db: "connected" }));
|
||||||
|
} catch {
|
||||||
|
res.writeHead(503, { "Content-Type": "application/json" });
|
||||||
|
res.end(JSON.stringify({ status: "error", db: "unreachable" }));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Submodule
+1
Submodule cartsnitch added at a53daddb9a
@@ -5,7 +5,7 @@ WORKDIR /app
|
|||||||
|
|
||||||
# build-essential and libpq-dev are needed to compile any C-extension wheels
|
# build-essential and libpq-dev are needed to compile any C-extension wheels
|
||||||
# (e.g. psycopg2 fallback). No git needed — common/ is copied from the repo root.
|
# (e.g. psycopg2 fallback). No git needed — common/ is copied from the repo root.
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \
|
||||||
libpq-dev \
|
libpq-dev \
|
||||||
build-essential \
|
build-essential \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
@@ -25,7 +25,7 @@ FROM python:3.12-slim AS prod
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install Playwright system dependencies for Chromium
|
# Install Playwright system dependencies for Chromium
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \
|
||||||
libnss3 \
|
libnss3 \
|
||||||
libatk1.0-0 \
|
libatk1.0-0 \
|
||||||
libatk-bridge2.0-0 \
|
libatk-bridge2.0-0 \
|
||||||
|
|||||||
Reference in New Issue
Block a user