Skip to content

fix: scan

fix: scan #55

Workflow file for this run

# Deploy FastAPI (api/) to the VPS — venv + systemd + Nginx reload.
# MariaDB may be remote (e.g. o2switch): DATABASE_URL in secrets.
# On the VPS: install xvfb + xauth and run Uvicorn under xvfb-run (headed Chromium if VINTED_BROWSER_HEADLESS=false).
# Optional secret VINTED_BROWSER_HEADLESS: missing → true (legacy); false → less likely flagged by Vinted on Xvfb.
name: Deploy API (FastAPI)
on:
push:
branches: [main]
paths:
- 'api/**'
- '.github/workflows/deploy-api.yml'
pull_request:
branches: [main]
paths:
- 'api/**'
workflow_dispatch:
concurrency:
group: goupixdex-api-${{ github.ref }}
cancel-in-progress: true
jobs:
lint-pr:
name: Sanity check (PR — sans déploiement)
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
sparse-checkout: |
api
sparse-checkout-cone-mode: true
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install deps & import check
run: |
python -m pip install --upgrade pip
pip install -r api/requirements.txt
cd api && PYTHONPATH=. python -c "import main; print('import ok')"
deploy:
name: Deploy API
if: github.event_name == 'workflow_dispatch' || github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Checkout (api only)
uses: actions/checkout@v4
with:
fetch-depth: 1
sparse-checkout: |
api
sparse-checkout-cone-mode: true
- name: Write api/.env for upload
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
SEED_USER_EMAIL: ${{ secrets.SEED_USER_EMAIL }}
SEED_USER_PASSWORD: ${{ secrets.SEED_USER_PASSWORD }}
SEED_MARGIN_PERCENT: ${{ secrets.SEED_MARGIN_PERCENT }}
SEED_DEV_ARTICLES: ${{ secrets.SEED_DEV_ARTICLES }}
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_API_KEY: ${{ secrets.SUPABASE_API_KEY }}
SUPABASE_STORAGE_BUCKET: ${{ secrets.SUPABASE_STORAGE_BUCKET }}
POKE_WALLET_API_KEY: ${{ secrets.POKE_WALLET_API_KEY }}
POKE_WALLET_BASE_URL: ${{ secrets.POKE_WALLET_BASE_URL }}
POKE_WALLET_PROXY_SECRET: ${{ secrets.POKE_WALLET_PROXY_SECRET }}
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
VINTED_EMAIL_OR_USERNAME: ${{ secrets.VINTED_EMAIL_OR_USERNAME }}
VINTED_PASSWORD: ${{ secrets.VINTED_PASSWORD }}
CORS_ORIGINS: ${{ secrets.CORS_ORIGINS }}
VINTED_CHROME_EXECUTABLE: ${{ secrets.VINTED_CHROME_EXECUTABLE }}
VINTED_BROWSER_HEADLESS: ${{ secrets.VINTED_BROWSER_HEADLESS }}
EBAY_CLIENT_ID: ${{ secrets.EBAY_CLIENT_ID }}
EBAY_CLIENT_SECRET: ${{ secrets.EBAY_CLIENT_SECRET }}
EBAY_REDIRECT_URI: ${{ secrets.EBAY_REDIRECT_URI }}
EBAY_USE_SANDBOX: ${{ secrets.EBAY_USE_SANDBOX }}
EBAY_FR_FULFILLMENT_CARRIER_CODE: ${{ secrets.EBAY_FR_FULFILLMENT_CARRIER_CODE }}
EBAY_FR_FULFILLMENT_SERVICE_CODE: ${{ secrets.EBAY_FR_FULFILLMENT_SERVICE_CODE }}
run: |
set -euo pipefail
f=api/.env
CHROME_PATH="${VINTED_CHROME_EXECUTABLE:-/usr/bin/chromium}"
{
echo "DATABASE_URL=${DATABASE_URL}"
echo "JWT_SECRET=${JWT_SECRET}"
echo "SEED_USER_EMAIL=${SEED_USER_EMAIL:-}"
echo "SEED_USER_PASSWORD=${SEED_USER_PASSWORD:-}"
echo "SEED_MARGIN_PERCENT=${SEED_MARGIN_PERCENT:-60}"
echo "SEED_DEV_ARTICLES=${SEED_DEV_ARTICLES:-0}"
echo "SUPABASE_URL=${SUPABASE_URL:-}"
echo "SUPABASE_API_KEY=${SUPABASE_API_KEY:-}"
echo "SUPABASE_STORAGE_BUCKET=${SUPABASE_STORAGE_BUCKET:-GoupixDex}"
echo "POKE_WALLET_API_KEY=${POKE_WALLET_API_KEY:-}"
echo "POKE_WALLET_BASE_URL=${POKE_WALLET_BASE_URL:-https://api.pokewallet.io}"
echo "POKE_WALLET_PROXY_SECRET=${POKE_WALLET_PROXY_SECRET:-}"
echo "GROQ_API_KEY=${GROQ_API_KEY:-}"
echo "VINTED_EMAIL_OR_USERNAME=${VINTED_EMAIL_OR_USERNAME:-}"
echo "VINTED_PASSWORD=${VINTED_PASSWORD:-}"
echo "CORS_ORIGINS=${CORS_ORIGINS:-*}"
echo "VINTED_BROWSER_HEADLESS=${VINTED_BROWSER_HEADLESS:-true}"
echo "VINTED_CHROME_EXECUTABLE=${CHROME_PATH}"
echo "EBAY_CLIENT_ID=${EBAY_CLIENT_ID:-}"
echo "EBAY_CLIENT_SECRET=${EBAY_CLIENT_SECRET:-}"
echo "EBAY_REDIRECT_URI=${EBAY_REDIRECT_URI:-}"
echo "EBAY_USE_SANDBOX=${EBAY_USE_SANDBOX:-true}"
echo "EBAY_FR_FULFILLMENT_CARRIER_CODE=${EBAY_FR_FULFILLMENT_CARRIER_CODE:-Colissimo}"
echo "EBAY_FR_FULFILLMENT_SERVICE_CODE=${EBAY_FR_FULFILLMENT_SERVICE_CODE:-FR_ColiposteColissimo}"
} > "$f"
- name: Pack api tree
run: tar -czf api-bundle.tar.gz api
- name: Upload to VPS
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SSH_HOST }}
port: ${{ secrets.SSH_PORT }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: api-bundle.tar.gz
target: ${{ secrets.DEPLOY_API_DIR }}
- name: Extract, venv, systemd, nginx
uses: appleboy/ssh-action@v1.0.3
env:
DEPLOY_API_DIR: ${{ secrets.DEPLOY_API_DIR }}
API_SYSTEMD_SERVICE: ${{ secrets.API_SYSTEMD_SERVICE }}
API_PORT: ${{ secrets.API_APP_PORT }}
DEPLOY_USER: ${{ secrets.SSH_USERNAME }}
with:
host: ${{ secrets.SSH_HOST }}
port: ${{ secrets.SSH_PORT }}
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
envs: DEPLOY_API_DIR,API_SYSTEMD_SERVICE,API_PORT,DEPLOY_USER
script_stop: true
script: |
set -euo pipefail
TARGET="${DEPLOY_API_DIR%/}"
SVC="${API_SYSTEMD_SERVICE:-goupixdex-api.service}"
PORT="${API_PORT:-8000}"
mkdir -p "$TARGET"
rm -rf "$TARGET/api"
tar -xzf "$TARGET/api-bundle.tar.gz" -C "$TARGET"
rm -f "$TARGET/api-bundle.tar.gz"
APP_ROOT="$TARGET/api"
sudo chown -R "$USER:$USER" "$APP_ROOT" || true
sudo apt-get update -y
sudo apt-get install -y python3-venv python3-pip chromium fonts-liberation xvfb xauth
if [ ! -x "$APP_ROOT/.venv/bin/python" ]; then
python3 -m venv "$APP_ROOT/.venv"
fi
. "$APP_ROOT/.venv/bin/activate"
python -m pip install --upgrade pip wheel
pip install -r "$APP_ROOT/requirements.txt" --no-cache-dir
deactivate
# SQL migrations (files not already recorded in schema_migrations)
"$APP_ROOT/.venv/bin/python" "$APP_ROOT/migrations/run_migrations.py"
# Bootstrap DB if empty tables (user / margins; articles only if SEED_DEV_ARTICLES=1 on the VPS)
"$APP_ROOT/.venv/bin/python" "$APP_ROOT/seeders/conditional_seed.py"
sudo tee "/etc/systemd/system/${SVC}" > /dev/null <<EOF
[Unit]
Description=GoupixDex FastAPI (Uvicorn)
After=network.target
[Service]
Type=simple
User=${DEPLOY_USER}
WorkingDirectory=${APP_ROOT}
EnvironmentFile=${APP_ROOT}/.env
# Affichage virtuel : Chromium avec VINTED_BROWSER_HEADLESS=false a besoin d'un DISPLAY (xauth requis pour xvfb-run).
ExecStart=/usr/bin/xvfb-run -a --server-args="-screen 0 1920x1080x24" ${APP_ROOT}/.venv/bin/uvicorn main:app --host 127.0.0.1 --port ${PORT} --workers 1 --proxy-headers
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable "$SVC"
sudo systemctl restart "$SVC"
sudo systemctl --no-pager --full status "$SVC" || true
sudo nginx -t
sudo systemctl reload nginx