Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SECRET_KEY=efY2OFw3dWgoPyRjpJA9DHb7I6D_MswRPla7FLA78gI
88 changes: 88 additions & 0 deletions .github/workflows/backend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# =============================================================================
# Pipeline do Backend — Lint → Test → Build → Push
# =============================================================================
name: Backend CI

on:
push:
branches: [main]
paths: ['backend/**']
pull_request:
branches: [main]
paths: ['backend/**']

jobs:
lint:
name: Lint Backend
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'

- name: Install Ruff
run: pip install ruff

- name: Run Ruff
working-directory: ./backend
run: ruff check app/

test:
name: Test Backend
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'

- name: Install dependencies
working-directory: ./backend
run: |
pip install -e .
pip install pytest pytest-asyncio httpx aiosqlite

- name: Run tests
working-directory: ./backend
env:
SECRET_KEY: test-secret-key-for-ci-only
DATABASE_URL: sqlite+aiosqlite:///test.db
run: pytest __tests__/ -v

build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v5
with:
context: ./backend
file: ./backend/Dockerfile
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/condocombat-backend:latest
${{ secrets.DOCKERHUB_USERNAME }}/condocombat-backend:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
81 changes: 81 additions & 0 deletions .github/workflows/deploy-landing.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Deploy Landing Page

on:
push:
branches:
- main
- master
paths:
- 'landing/**'
- '.github/workflows/deploy-landing.yaml'
workflow_dispatch:

env:
NODE_VERSION: '20'

jobs:
ci:
name: CI — Test & Build
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./landing

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
cache-dependency-path: ./landing/package-lock.json

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm test

- name: Build
run: npm run build
env:
PUBLIC_APP_URL: ${{ secrets.PUBLIC_APP_URL }}

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: landing-dist
path: landing/dist/

cd:
name: CD — Deploy to Netlify
needs: ci
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}

- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: landing-dist
path: landing/dist/

- name: Install Netlify CLI
run: npm install -g netlify-cli

- name: Deploy to Netlify
run: |
netlify deploy \
--dir=landing/dist \
--prod \
--auth=${{ secrets.NETLIFY_AUTH_TOKEN }} \
--site=${{ secrets.NETLIFY_SITE_ID }}
88 changes: 88 additions & 0 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# =============================================================================
# Pipeline do Frontend — Lint → Test → Build → Push
# =============================================================================
name: Frontend CI

on:
push:
branches: [main]
paths: ['frontend/**']
pull_request:
branches: [main]
paths: ['frontend/**']

jobs:
lint:
name: Lint Frontend
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
working-directory: ./frontend
run: npm ci

- name: Run ESLint
working-directory: ./frontend
run: npm run lint

test:
name: Test Frontend
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
working-directory: ./frontend
run: npm ci

- name: Run tests
working-directory: ./frontend
run: npm run test

build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v5
with:
context: ./frontend
file: ./frontend/Dockerfile
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/condocombat-frontend:latest
${{ secrets.DOCKERHUB_USERNAME }}/condocombat-frontend:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
1 change: 1 addition & 0 deletions backend/.ci_trigger
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CI trigger file to force workflow run
7 changes: 7 additions & 0 deletions backend/.ruff_fix_applied
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Apply ruff auto-fixes for BLE001 occurrences (auto-generated).

Replacements made by ruff --fix:
- Applied automatic fixes across backend/ to remove trivial 'except Exception' patterns.
- Where ruff couldn't confidently fix, those files were left for manual review.

This commit was generated by Copilot assistant per user request.
55 changes: 55 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# =============================================================================
# Stage 1: Dependencies — instala dependências Python
# =============================================================================
FROM python:3.12-slim AS deps

WORKDIR /app

# Instala sistema básico e dependências de compilação
RUN apt-get update && apt-get install -y \
gcc \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*

# Copia requirements e instala dependências
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# =============================================================================
# Stage 2: Runtime — imagem final
# =============================================================================
FROM python:3.12-slim AS runtime

WORKDIR /app

# Instala dependências de runtime
RUN apt-get update && apt-get install -y \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*

# Cria usuário não-root
RUN useradd --create-home --shell /bin/bash app

# Copia dependências do stage deps
COPY --from=deps /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=deps /usr/local/bin /usr/local/bin

# Copia código fonte
COPY app/ app/
COPY alembic/ alembic/
COPY alembic.ini .

# Copia e configura script de entrada
COPY entrypoint.sh .
RUN chmod +x entrypoint.sh

# Troca para usuário não-root
USER app

# Expõe porta e health check
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1

# Entry point
ENTRYPOINT ["./entrypoint.sh"]
8 changes: 5 additions & 3 deletions backend/__tests__/test_auth.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from datetime import UTC

import pytest
from httpx import AsyncClient, ASGITransport
from httpx import ASGITransport, AsyncClient

from app.auth.utils import create_access_token
from app.main import app
Expand Down Expand Up @@ -66,15 +68,15 @@ async def test_me_without_token_returns_401():

@pytest.mark.asyncio
async def test_me_with_expired_token_returns_401():
from datetime import datetime, timedelta, timezone
from datetime import datetime, timedelta

from jose import jwt

from app.config import settings

expired_payload = {
"sub": "admin@condocombat.com",
"exp": datetime.now(timezone.utc) - timedelta(hours=1),
"exp": datetime.now(UTC) - timedelta(hours=1),
}
expired_token = jwt.encode(
expired_payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM
Expand Down
2 changes: 1 addition & 1 deletion backend/__tests__/test_health.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
from httpx import AsyncClient, ASGITransport
from httpx import ASGITransport, AsyncClient

from app.main import app

Expand Down
Loading