Skip to content
This repository was archived by the owner on Jun 19, 2026. It is now read-only.

Commit 5fd024d

Browse files
authored
Merge pull request #3 from rohitdash08/pre-commit
added security checks and pre-commit rules
2 parents 06b9525 + 0e4f25f commit 5fd024d

20 files changed

Lines changed: 255 additions & 65 deletions

.bandit

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[bandit]
2+
# Skip assert usage rule and tests directory
3+
skips = B101
4+
exclude = packages/backend/tests
5+
severity = LOW
6+
confidence = LOW

.flake8

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[flake8]
2+
max-line-length = 88
3+
extend-ignore = E203, W503
4+
exclude = .git,__pycache__,build,dist,.venv,venv
5+
per-file-ignores =
6+
packages/backend/tests/*: S101

.github/workflows/ci.yml

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,63 @@ on:
55
branches: ["**"]
66
pull_request:
77

8+
concurrency:
9+
group: ${{ github.workflow }}-${{ github.ref }}
10+
cancel-in-progress: true
11+
12+
permissions:
13+
contents: read
14+
815
jobs:
916
backend:
1017
runs-on: ubuntu-latest
18+
services:
19+
redis:
20+
image: redis:7
21+
ports:
22+
- 6379:6379
1123
steps:
1224
- uses: actions/checkout@v4
1325
- uses: actions/setup-python@v5
1426
with:
1527
python-version: "3.11"
28+
cache: pip
1629
- name: Install deps
30+
working-directory: packages/backend
1731
run: |
1832
python -m pip install --upgrade pip
19-
pip install -r backend/requirements.txt || pip install -r packages/backend/requirements.txt
20-
pip install black flake8 pytest
21-
# - name: Lint
22-
# run: |
23-
# if [ -d backend ]; then black --check backend && flake8 backend; else black --check packages/backend && flake8 packages/backend; fi
24-
- name: Tests
25-
run: pytest -q || true
26-
- name: Build Docker
33+
pip install -r requirements.txt
34+
pip install black==24.8.0 flake8==7.0.0 bandit==1.7.9 pytest==8.2.2
35+
- name: Lint (black, flake8)
36+
working-directory: packages/backend
2737
run: |
28-
if [ -d backend ]; then docker build -t finmind-backend ./backend; else docker build -t finmind-backend ./packages/backend; fi
38+
black --check .
39+
flake8 .
40+
- name: Tests (pytest)
41+
env:
42+
REDIS_URL: redis://localhost:6379/0
43+
working-directory: packages/backend
44+
run: python -m pytest -q
45+
46+
- name: Security Scan (Bandit)
47+
working-directory: packages/backend
48+
run: bandit -r app -ll
49+
50+
docker_scan:
51+
runs-on: ubuntu-latest
52+
needs: backend
53+
steps:
54+
- uses: actions/checkout@v4
55+
- name: Build backend image
56+
run: docker build -t finmind-backend:ci ./packages/backend
57+
- name: Trivy scan
58+
uses: aquasecurity/trivy-action@0.24.0
59+
with:
60+
image-ref: finmind-backend:ci
61+
format: table
62+
exit-code: 1
63+
vuln-type: os,library
64+
severity: CRITICAL,HIGH
2965

3066
frontend:
3167
runs-on: ubuntu-latest
@@ -41,11 +77,11 @@ jobs:
4177
- name: Lint
4278
run: |
4379
cd app
44-
npm run lint || true
80+
npm run lint
4581
- name: Test
4682
run: |
4783
cd app
48-
npm run test -- --run || true
84+
npm run test -- --run
4985
- name: Build
5086
run: |
5187
cd app

.github/workflows/codeql.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: "CodeQL"
2+
3+
on:
4+
push:
5+
branches: ["**"]
6+
pull_request:
7+
schedule:
8+
- cron: "0 3 * * 0" # weekly
9+
10+
permissions:
11+
contents: read
12+
security-events: write
13+
14+
jobs:
15+
analyze:
16+
name: Analyze (CodeQL)
17+
runs-on: ubuntu-latest
18+
strategy:
19+
fail-fast: false
20+
matrix:
21+
language: ["python", "javascript"]
22+
23+
steps:
24+
- name: Checkout repository
25+
uses: actions/checkout@v4
26+
27+
- name: Initialize CodeQL
28+
uses: github/codeql-action/init@v3
29+
with:
30+
languages: ${{ matrix.language }}
31+
32+
- name: Autobuild
33+
uses: github/codeql-action/autobuild@v3
34+
35+
- name: Perform CodeQL Analysis
36+
uses: github/codeql-action/analyze@v3
37+
with:
38+
category: "/language:${{ matrix.language }}"

.pre-commit-config.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
repos:
2+
- repo: https://github.com/psf/black
3+
rev: 24.8.0
4+
hooks:
5+
- id: black
6+
name: black (python formatter)
7+
language_version: python3.11
8+
additional_dependencies: []
9+
exclude: |
10+
^app/|^packages/backend/.+\.ipynb$
11+
12+
- repo: https://github.com/PyCQA/flake8
13+
rev: 7.0.0
14+
hooks:
15+
- id: flake8
16+
name: flake8 (python lint)
17+
additional_dependencies: []
18+
args: ["--config=.flake8"]
19+
20+
- repo: https://github.com/pre-commit/pre-commit-hooks
21+
rev: v4.6.0
22+
hooks:
23+
- id: end-of-file-fixer
24+
- id: trailing-whitespace
25+
- id: check-yaml
26+
files: \.(yml|yaml)$
27+
- id: check-json
28+
- id: check-merge-conflict
29+
30+
- repo: https://github.com/asottile/yesqa
31+
rev: v1.5.0
32+
hooks:
33+
- id: yesqa
34+
name: remove unused noqa comments
35+
36+
- repo: https://github.com/adrienverge/yamllint
37+
rev: v1.35.1
38+
hooks:
39+
- id: yamllint
40+
name: yamllint
41+
args: ["-d", "{extends: default, rules: {line-length: disable}}"]

docker-compose.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ services:
2121
volumes:
2222
- ./packages/backend/app:/app/app
2323
- ./packages/backend/wsgi.py:/app/wsgi.py
24-
- ./packages/backend/tests:/app/tests:ro
24+
- ./packages/backend/tests:/app/tests
25+
- ./.flake8:/app/.flake8:ro
26+
- ./.bandit:/app/.bandit:ro
2527
command: gunicorn --reload --workers=2 --threads=4 --bind 0.0.0.0:8000 wsgi:app
2628

2729
frontend:

packages/backend/app/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from flask import Flask, jsonify
22
from .config import Settings
3-
from .extensions import db, jwt, redis_client
3+
from .extensions import db, jwt
44
from .routes import register_routes
55
from flask_cors import CORS
66
import click
@@ -26,8 +26,10 @@ def create_app(settings: Settings | None = None) -> Flask:
2626

2727
# Logging
2828
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
29-
logging.basicConfig(level=getattr(logging, log_level, logging.INFO),
30-
format="%(asctime)s %(levelname)s [%(name)s] %(message)s")
29+
logging.basicConfig(
30+
level=getattr(logging, log_level, logging.INFO),
31+
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
32+
)
3133
logger = logging.getLogger("finmind")
3234
logger.info("Starting FinMind backend with log level %s", log_level)
3335

packages/backend/app/models.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from datetime import datetime, date
22
from enum import Enum
3-
from flask_sqlalchemy import SQLAlchemy
4-
from sqlalchemy import func, Enum as SAEnum
3+
from sqlalchemy import Enum as SAEnum
54
from .extensions import db
65

76

@@ -92,7 +91,9 @@ class UserSubscription(db.Model):
9291
__tablename__ = "user_subscriptions"
9392
id = db.Column(db.Integer, primary_key=True)
9493
user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=False)
95-
plan_id = db.Column(db.Integer, db.ForeignKey("subscription_plans.id"), nullable=False)
94+
plan_id = db.Column(
95+
db.Integer, db.ForeignKey("subscription_plans.id"), nullable=False
96+
)
9697
active = db.Column(db.Boolean, default=False, nullable=False)
9798
started_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
9899

packages/backend/app/routes/auth.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from flask import Blueprint, request, jsonify
22
from werkzeug.security import generate_password_hash, check_password_hash
3-
from flask_jwt_extended import create_access_token, create_refresh_token, jwt_required, get_jwt_identity
3+
from flask_jwt_extended import (
4+
create_access_token,
5+
create_refresh_token,
6+
jwt_required,
7+
get_jwt_identity,
8+
)
49
from ..extensions import db
510
from ..models import User
611
import logging

packages/backend/app/routes/bills.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,28 @@
1414
@jwt_required()
1515
def list_bills():
1616
uid = int(get_jwt_identity())
17-
items = db.session.query(Bill).filter_by(user_id=uid, active=True).order_by(Bill.next_due_date).all()
17+
items = (
18+
db.session.query(Bill)
19+
.filter_by(user_id=uid, active=True)
20+
.order_by(Bill.next_due_date)
21+
.all()
22+
)
1823
logger.info("List bills user=%s count=%s", uid, len(items))
19-
return jsonify([
20-
{
21-
"id": b.id,
22-
"name": b.name,
23-
"amount": float(b.amount),
24-
"currency": b.currency,
25-
"next_due_date": b.next_due_date.isoformat(),
26-
"cadence": b.cadence.value,
27-
"channel_whatsapp": b.channel_whatsapp,
28-
"channel_email": b.channel_email,
29-
}
30-
for b in items
31-
])
24+
return jsonify(
25+
[
26+
{
27+
"id": b.id,
28+
"name": b.name,
29+
"amount": float(b.amount),
30+
"currency": b.currency,
31+
"next_due_date": b.next_due_date.isoformat(),
32+
"cadence": b.cadence.value,
33+
"channel_whatsapp": b.channel_whatsapp,
34+
"channel_email": b.channel_email,
35+
}
36+
for b in items
37+
]
38+
)
3239

3340

3441
@bp.post("")
@@ -71,5 +78,7 @@ def mark_paid(bill_id: int):
7178
b.active = False
7279
db.session.commit()
7380
cache_delete_patterns([f"user:{uid}:upcoming_bills*"])
74-
logger.info("Marked bill paid id=%s user=%s next_due_date=%s", b.id, uid, b.next_due_date)
81+
logger.info(
82+
"Marked bill paid id=%s user=%s next_due_date=%s", b.id, uid, b.next_due_date
83+
)
7584
return jsonify(message="updated")

0 commit comments

Comments
 (0)