Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c5cce2adc | |||
| e3a0d94236 | |||
| 3f03d46ff5 | |||
| c0c4acb73f | |||
| a35c264823 | |||
| 63752fe5cb | |||
| 9ab585f336 | |||
| 78b3a71450 | |||
| 3216e6a1c2 | |||
| a66583b883 | |||
| 4a7d5131fc | |||
| 56b1ff9a36 | |||
| b660336897 | |||
| af713f422b | |||
| 55ab0b7ceb | |||
| 93a94e9777 | |||
| 1bb669f3ca | |||
| 82978f072b | |||
| f023480100 | |||
| 9acaf5e83a | |||
| 4e10c75fd0 | |||
| 88ac74e94c | |||
| 53ffef0ed1 | |||
| cfad4eab37 | |||
| d8e7a416d2 | |||
| f051e4b4af | |||
| c715c0e47a | |||
| c968088a3f | |||
| 2b32bfdfe1 | |||
| 16200c5500 | |||
| 1803d09095 | |||
| e29bad9a39 | |||
| 349b519a00 | |||
| 7fc524b593 | |||
| 4e139dc4b6 | |||
| 6481cf03e4 | |||
| 37c75c3887 | |||
| 8a0b2c03a1 | |||
| aa893d9cc1 | |||
| 91c062130c | |||
| 0aef2455fd | |||
| 6602b8c105 | |||
| dbbc8d2e7b | |||
| 1267caf43c | |||
| 015401861a | |||
| 9891e1aefb | |||
| 69ad161e36 | |||
| 485f890df3 | |||
| bf3ed0ede3 | |||
| 3f41eb7346 | |||
| 6cbd1ef298 | |||
| 94214f762e | |||
| 562c6ef6f6 | |||
| ccc8189d88 | |||
| 86594e4a8e | |||
| c2f1a83c1d | |||
| 6f8e5a9577 | |||
| bbfa816e57 | |||
| 5904eb03a2 | |||
| 87b6433ff7 | |||
| d7c9938f7e | |||
| 02434060ee |
+6
-128
@@ -18,7 +18,6 @@ permissions:
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: cartsnitch/cartsnitch
|
||||
AUTH_IMAGE_NAME: cartsnitch/auth
|
||||
RECEIPTWITNESS_IMAGE_NAME: cartsnitch/receiptwitness
|
||||
API_IMAGE_NAME: cartsnitch/api
|
||||
|
||||
@@ -198,99 +197,6 @@ jobs:
|
||||
git tag "v${{ steps.calver.outputs.version }}"
|
||||
git push origin "v${{ steps.calver.outputs.version }}"
|
||||
|
||||
build-and-push-auth:
|
||||
runs-on: runners-cartsnitch
|
||||
if: github.event_name == 'push'
|
||||
needs: [lint, test, e2e]
|
||||
outputs:
|
||||
calver_tag: ${{ steps.calver.outputs.version }}
|
||||
sha_tag: sha-${{ github.sha }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate CalVer tag
|
||||
id: calver
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
DATE_TAG=$(date -u +%Y.%m.%d)
|
||||
EXISTING=$(git tag -l "v${DATE_TAG}*" | sort -V | tail -1)
|
||||
if [ -z "$EXISTING" ]; then
|
||||
VERSION="$DATE_TAG"
|
||||
elif [ "$EXISTING" = "v${DATE_TAG}" ]; then
|
||||
VERSION="${DATE_TAG}.2"
|
||||
else
|
||||
BUILD_NUM=$(echo "$EXISTING" | sed "s/v${DATE_TAG}\.//")
|
||||
VERSION="${DATE_TAG}.$((BUILD_NUM + 1))"
|
||||
fi
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
if: github.event_name == 'push'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Log in to GHCR
|
||||
if: github.event_name == 'push'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (auth)
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.AUTH_IMAGE_NAME }}
|
||||
tags: |
|
||||
type=sha,prefix=sha-,format=long
|
||||
type=raw,value=${{ steps.calver.outputs.version }},enable=${{ github.ref == 'refs/heads/main' }}
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
- name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./auth
|
||||
file: ./auth/Dockerfile
|
||||
load: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
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
|
||||
env:
|
||||
GRYPE_CONFIG: .grype.yaml
|
||||
with:
|
||||
image: "${{ env.REGISTRY }}/${{ env.AUTH_IMAGE_NAME }}:sha-${{ github.sha }}"
|
||||
fail-build: true
|
||||
severity-cutoff: high
|
||||
only-fixed: "true"
|
||||
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:
|
||||
runs-on: runners-cartsnitch
|
||||
if: github.event_name == 'push'
|
||||
@@ -477,7 +383,7 @@ jobs:
|
||||
|
||||
deploy-dev:
|
||||
runs-on: runners-cartsnitch
|
||||
needs: [build-and-push, build-and-push-auth, build-and-push-receiptwitness, build-and-push-api]
|
||||
needs: [build-and-push, build-and-push-receiptwitness, build-and-push-api]
|
||||
if: always() && !cancelled() && github.event_name == 'push' && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main')
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
@@ -518,21 +424,6 @@ jobs:
|
||||
cd infra/apps/overlays/dev
|
||||
kustomize edit set image ghcr.io/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }}
|
||||
|
||||
- name: Determine image tag for auth
|
||||
id: auth_tag
|
||||
run: |
|
||||
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
||||
echo "tag=${{ needs.build-and-push-auth.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "tag=${{ needs.build-and-push-auth.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Update auth image tag
|
||||
if: needs.build-and-push-auth.result == 'success'
|
||||
run: |
|
||||
cd infra/apps/overlays/dev
|
||||
kustomize edit set image ghcr.io/cartsnitch/auth:${{ steps.auth_tag.outputs.tag }}
|
||||
|
||||
- name: Determine image tag for receiptwitness
|
||||
id: receiptwitness_tag
|
||||
run: |
|
||||
@@ -569,13 +460,14 @@ jobs:
|
||||
git config user.name "cartsnitch-ci[bot]"
|
||||
git config user.email "cartsnitch-ci[bot]@users.noreply.github.com"
|
||||
git add apps/overlays/dev/kustomization.yaml
|
||||
git commit -m "ci(dev): update cartsnitch, auth, receiptwitness, and api images"
|
||||
git diff --cached --quiet && echo "No image changes to deploy" && exit 0
|
||||
git commit -m "ci(dev): update cartsnitch, receiptwitness, and api images"
|
||||
git pull --rebase origin main
|
||||
git push origin main
|
||||
|
||||
deploy-uat:
|
||||
runs-on: runners-cartsnitch
|
||||
needs: [build-and-push, build-and-push-auth, build-and-push-receiptwitness, build-and-push-api]
|
||||
needs: [build-and-push, build-and-push-receiptwitness, build-and-push-api]
|
||||
if: always() && !cancelled() && github.event_name == 'push' && (github.ref == 'refs/heads/uat' || github.ref == 'refs/heads/main')
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
@@ -616,21 +508,6 @@ jobs:
|
||||
cd infra/apps/overlays/uat
|
||||
kustomize edit set image ghcr.io/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }}
|
||||
|
||||
- name: Determine image tag for auth
|
||||
id: auth_tag
|
||||
run: |
|
||||
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
||||
echo "tag=${{ needs.build-and-push-auth.outputs.calver_tag }}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "tag=${{ needs.build-and-push-auth.outputs.sha_tag }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Update auth image tag
|
||||
if: needs.build-and-push-auth.result == 'success'
|
||||
run: |
|
||||
cd infra/apps/overlays/uat
|
||||
kustomize edit set image ghcr.io/cartsnitch/auth:${{ steps.auth_tag.outputs.tag }}
|
||||
|
||||
- name: Determine image tag for receiptwitness
|
||||
id: receiptwitness_tag
|
||||
run: |
|
||||
@@ -667,6 +544,7 @@ jobs:
|
||||
git config user.name "cartsnitch-ci[bot]"
|
||||
git config user.email "cartsnitch-ci[bot]@users.noreply.github.com"
|
||||
git add apps/overlays/uat/kustomization.yaml
|
||||
git commit -m "ci(uat): update cartsnitch, auth, receiptwitness, and api images"
|
||||
git diff --cached --quiet && echo "No image changes to deploy" && exit 0
|
||||
git commit -m "ci(uat): update cartsnitch, receiptwitness, and api images"
|
||||
git pull --rebase origin main
|
||||
git push origin main
|
||||
|
||||
+105
-1
@@ -1,4 +1,108 @@
|
||||
ignore:
|
||||
# Python 3.12 CVEs — only fixed in 3.13+, cannot upgrade major version safely
|
||||
- vulnerability: CVE-2025-13836
|
||||
- vulnerability: CVE-2026-4519
|
||||
- vulnerability: CVE-2026-4519
|
||||
|
||||
# Chrome CVEs — Playwright bundles Chromium and controls version separately.
|
||||
# Chrome is not a system package that can be upgraded via apt-get upgrade.
|
||||
# These CVEs are specific to the Chromium version bundled with Playwright.
|
||||
# Upstream fix: upgrade Playwright to a version that includes patched Chrome.
|
||||
- vulnerability: CVE-2026-2313
|
||||
- vulnerability: CVE-2026-2314
|
||||
- vulnerability: CVE-2026-2315
|
||||
- vulnerability: CVE-2026-2319
|
||||
- vulnerability: CVE-2026-2321
|
||||
- vulnerability: CVE-2026-2441
|
||||
- vulnerability: CVE-2026-2648
|
||||
- vulnerability: CVE-2026-2649
|
||||
- vulnerability: CVE-2026-2650
|
||||
- vulnerability: CVE-2026-3061
|
||||
- vulnerability: CVE-2026-3062
|
||||
- vulnerability: CVE-2026-3536
|
||||
- vulnerability: CVE-2026-3537
|
||||
- vulnerability: CVE-2026-3538
|
||||
- vulnerability: CVE-2026-3539
|
||||
- vulnerability: CVE-2026-3540
|
||||
- vulnerability: CVE-2026-3541
|
||||
- vulnerability: CVE-2026-3542
|
||||
- vulnerability: CVE-2026-3543
|
||||
- vulnerability: CVE-2026-3544
|
||||
- vulnerability: CVE-2026-3545
|
||||
- vulnerability: CVE-2026-3913
|
||||
- vulnerability: CVE-2026-3914
|
||||
- vulnerability: CVE-2026-3915
|
||||
- vulnerability: CVE-2026-3916
|
||||
- vulnerability: CVE-2026-3917
|
||||
- vulnerability: CVE-2026-3918
|
||||
- vulnerability: CVE-2026-3919
|
||||
- vulnerability: CVE-2026-3920
|
||||
- vulnerability: CVE-2026-3921
|
||||
- vulnerability: CVE-2026-3922
|
||||
- vulnerability: CVE-2026-3923
|
||||
- vulnerability: CVE-2026-3924
|
||||
- vulnerability: CVE-2026-3926
|
||||
- vulnerability: CVE-2026-3931
|
||||
- vulnerability: CVE-2026-3932
|
||||
- vulnerability: CVE-2026-3936
|
||||
- vulnerability: CVE-2026-5858
|
||||
- vulnerability: CVE-2026-5859
|
||||
- vulnerability: CVE-2026-5860
|
||||
- vulnerability: CVE-2026-5861
|
||||
- vulnerability: CVE-2026-5862
|
||||
- vulnerability: CVE-2026-5863
|
||||
- vulnerability: CVE-2026-5865
|
||||
- vulnerability: CVE-2026-5866
|
||||
- vulnerability: CVE-2026-5868
|
||||
- vulnerability: CVE-2026-5870
|
||||
- vulnerability: CVE-2026-5871
|
||||
- vulnerability: CVE-2026-5872
|
||||
- vulnerability: CVE-2026-5873
|
||||
- vulnerability: CVE-2026-5874
|
||||
- vulnerability: CVE-2026-5877
|
||||
- vulnerability: CVE-2026-5879
|
||||
- vulnerability: CVE-2026-5883
|
||||
- vulnerability: CVE-2026-5884
|
||||
- vulnerability: CVE-2026-5902
|
||||
- vulnerability: CVE-2026-5904
|
||||
- vulnerability: CVE-2026-5907
|
||||
- vulnerability: CVE-2026-5908
|
||||
- vulnerability: CVE-2026-5909
|
||||
- vulnerability: CVE-2026-5910
|
||||
- vulnerability: CVE-2026-5912
|
||||
- vulnerability: CVE-2026-5913
|
||||
- vulnerability: CVE-2026-5914
|
||||
- vulnerability: CVE-2026-5915
|
||||
- vulnerability: CVE-2026-6296
|
||||
- vulnerability: CVE-2026-6297
|
||||
- vulnerability: CVE-2026-6299
|
||||
- vulnerability: CVE-2026-6300
|
||||
- vulnerability: CVE-2026-6301
|
||||
- vulnerability: CVE-2026-6302
|
||||
- vulnerability: CVE-2026-6303
|
||||
- vulnerability: CVE-2026-6304
|
||||
- vulnerability: CVE-2026-6305
|
||||
- vulnerability: CVE-2026-6306
|
||||
- vulnerability: CVE-2026-6307
|
||||
- vulnerability: CVE-2026-6308
|
||||
- vulnerability: CVE-2026-6309
|
||||
- vulnerability: CVE-2026-6310
|
||||
- vulnerability: CVE-2026-6311
|
||||
- vulnerability: CVE-2026-6314
|
||||
- vulnerability: CVE-2026-6315
|
||||
- vulnerability: CVE-2026-6316
|
||||
- vulnerability: CVE-2026-6317
|
||||
- vulnerability: CVE-2026-6318
|
||||
- vulnerability: CVE-2026-6319
|
||||
- vulnerability: CVE-2026-6358
|
||||
- vulnerability: CVE-2026-6359
|
||||
- vulnerability: CVE-2026-6360
|
||||
- vulnerability: CVE-2026-6361
|
||||
- vulnerability: CVE-2026-6363
|
||||
|
||||
# Node.js CVE — comes from Playwright's bundled tooling (playwright-core uses Node.js
|
||||
# for its CLI). The system Node.js is not used by receiptwitness service.
|
||||
# Fix requires upgrading Playwright to a version that ships with patched Node.js.
|
||||
- vulnerability: CVE-2026-21710
|
||||
|
||||
# cryptography GHSA — fixed by upgrading to >=46.0 per requirements
|
||||
- vulnerability: GHSA-r6ph-v2qm-q3c2
|
||||
|
||||
@@ -5,7 +5,7 @@ WORKDIR /app
|
||||
|
||||
# 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.
|
||||
ARG APT_CACHE_BUST=0
|
||||
ARG APT_CACHE_BUST=1
|
||||
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \
|
||||
libpq-dev \
|
||||
build-essential \
|
||||
@@ -26,7 +26,7 @@ FROM python:3.12-slim AS prod
|
||||
WORKDIR /app
|
||||
|
||||
# Install Playwright system dependencies for Chromium
|
||||
ARG APT_CACHE_BUST=0
|
||||
ARG APT_CACHE_BUST=1
|
||||
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends \
|
||||
libnss3 \
|
||||
libatk1.0-0 \
|
||||
|
||||
@@ -11,7 +11,7 @@ dependencies = [
|
||||
"cartsnitch-common>=0.1.0",
|
||||
"playwright>=1.49,<2.0",
|
||||
"playwright-stealth>=1.0,<2.0",
|
||||
"cryptography>=42.0,<44.0",
|
||||
"cryptography>=46.0,<47.0",
|
||||
"fastapi>=0.115,<1.0",
|
||||
"uvicorn[standard]>=0.30,<1.0",
|
||||
"beautifulsoup4>=4.12,<5.0",
|
||||
|
||||
+14
-7
@@ -1,13 +1,14 @@
|
||||
import { useState } from 'react'
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { authClient } from '../lib/auth-client.ts'
|
||||
import { useAuthStore } from '../stores/auth.ts'
|
||||
|
||||
export function Login() {
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const navigate = useNavigate()
|
||||
const setAuthenticated = useAuthStore((s) => s.setAuthenticated)
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault()
|
||||
@@ -29,16 +30,22 @@ export function Login() {
|
||||
throw new Error(authError.message ?? 'Sign in failed')
|
||||
}
|
||||
|
||||
// After successful signIn, force a session fetch to confirm the cookie is set
|
||||
// before navigating to the protected route
|
||||
// After successful signIn, force a full page reload so Better-Auth's
|
||||
// useSession() reinitializes with fresh cookie-backed session state.
|
||||
// Using React Router's navigate() races with Better-Auth's internal update.
|
||||
const sessionResult = await authClient.getSession()
|
||||
if (sessionResult.data) {
|
||||
navigate('/')
|
||||
window.location.href = '/'
|
||||
} else {
|
||||
setError('Sign in failed. Please try again.')
|
||||
}
|
||||
} catch {
|
||||
setError('Invalid email or password. Please try again.')
|
||||
if (import.meta.env.VITE_MOCK_AUTH === 'true') {
|
||||
setAuthenticated(true)
|
||||
window.location.href = '/'
|
||||
} else {
|
||||
setError('Invalid email or password. Please try again.')
|
||||
}
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
@@ -93,4 +100,4 @@ export function Login() {
|
||||
</p>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user