From 874020f923928e7b0f301011016185af80032b38 Mon Sep 17 00:00:00 2001 From: durgeshninave9 Date: Sat, 23 Aug 2025 23:03:13 +0530 Subject: [PATCH 1/2] add github actions for lint, test and security scan --- .github/workflows/lint.yml | 34 +++++++++++++++++++++++++++++ .github/workflows/test.yml | 43 +++++++++++++++++++++++++++++++++++++ .github/workflows/trivy.yml | 24 +++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/trivy.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..7a04c10 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,34 @@ +name: Python Lint + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + python-lint: + name: Lint Python Code + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.13' + + - name: Install linters + run: | + python -m pip install --upgrade pip + pip install flake8 black isort + + - name: Run flake8 + run: | + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + + - name: Check import sorting with isort + run: | + isort . --check-only diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..709a4f1 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,43 @@ +name: Python Tests with Coverage + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + if: false # disables the job temporary + runs-on: ubuntu-latest + + strategy: + matrix: + python-version: ['3.11', '3.12', '3.13'] + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pytest pytest-cov + + - name: Run tests with coverage + run: | + pytest --cov=your_package_name --cov-report=term --cov-report=xml --cov-fail-under=80 + + # Optional: Upload coverage report to Codecov (for public repos or with CODECOV_TOKEN) + - name: Upload to Codecov + uses: codecov/codecov-action@v3 + with: + files: coverage.xml + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # Only needed for private repos diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml new file mode 100644 index 0000000..5b006b7 --- /dev/null +++ b/.github/workflows/trivy.yml @@ -0,0 +1,24 @@ +name: Trivy Security Scan + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + trivy-scan: + runs-on: ubuntu-latest + name: Trivy FS Scan + + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Run Trivy vulnerability scanner on file system + uses: aquasecurity/trivy-action@master + with: + scan-type: 'fs' + scan-ref: '.' + scanners: 'vuln,secret,config' + ignore-unfixed: true From 534b2ad20576149c144bcd0f1f71cb2d94e757d3 Mon Sep 17 00:00:00 2001 From: durgeshninave9 Date: Sat, 23 Aug 2025 23:08:24 +0530 Subject: [PATCH 2/2] fix lint issue --- app/alembic/env.py | 4 +--- app/api/routes/questions.py | 5 ++++- app/config/vectorestore.py | 7 +++++-- app/llm/provider.py | 3 +++ app/main.py | 1 + app/pipelines/daily_question_pipeline.py | 8 ++++++-- app/schemas/utils.py | 1 + app/services/questions.py | 6 ++++-- 8 files changed, 25 insertions(+), 10 deletions(-) diff --git a/app/alembic/env.py b/app/alembic/env.py index 0fb47dd..7ec92d3 100644 --- a/app/alembic/env.py +++ b/app/alembic/env.py @@ -1,9 +1,7 @@ from logging.config import fileConfig -from sqlalchemy import engine_from_config -from sqlalchemy import pool - from alembic import context +from sqlalchemy import engine_from_config, pool from app.config.database import Base from app.models import * # noqa: F401, F403 diff --git a/app/api/routes/questions.py b/app/api/routes/questions.py index 231eeb0..5156a6f 100644 --- a/app/api/routes/questions.py +++ b/app/api/routes/questions.py @@ -1,6 +1,9 @@ from fastapi import APIRouter -from app.services.questions import generate_daily_question as generate_daily_question_service + from app.schemas.utils import UserPrompt +from app.services.questions import \ + generate_daily_question as generate_daily_question_service + router = APIRouter() diff --git a/app/config/vectorestore.py b/app/config/vectorestore.py index 5a470f9..624cbd1 100644 --- a/app/config/vectorestore.py +++ b/app/config/vectorestore.py @@ -1,10 +1,13 @@ -from typing import List, Optional, Dict, Any +from typing import Any, Dict, List, Optional + from chromadb import PersistentClient from langchain_chroma import Chroma -from langchain_huggingface import HuggingFaceEmbeddings from langchain_core.documents import Document +from langchain_huggingface import HuggingFaceEmbeddings + from app.settings import settings + # Using singleton pattern for ChromaDB to ensure a single instance is used across the application class ChromaDB: """Singleton class for managing ChromaDB collections and operations.""" diff --git a/app/llm/provider.py b/app/llm/provider.py index f0a200a..93b09ec 100644 --- a/app/llm/provider.py +++ b/app/llm/provider.py @@ -1,8 +1,11 @@ import time from typing import Any, Dict + from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint + from app.settings import settings + def build_chat_model() -> ChatHuggingFace: """Builds and returns a ChatHuggingFace model instance configured with the settings from the app.""" llm = HuggingFaceEndpoint( diff --git a/app/main.py b/app/main.py index fd20c40..9b81e04 100644 --- a/app/main.py +++ b/app/main.py @@ -1,5 +1,6 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware + from app.api.main import api_router from app.settings import settings diff --git a/app/pipelines/daily_question_pipeline.py b/app/pipelines/daily_question_pipeline.py index 5f5d31f..fd5e98e 100644 --- a/app/pipelines/daily_question_pipeline.py +++ b/app/pipelines/daily_question_pipeline.py @@ -1,9 +1,13 @@ from typing import Dict -from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate + +from langchain_core.prompts import (ChatPromptTemplate, + HumanMessagePromptTemplate, + SystemMessagePromptTemplate) from langchain_core.runnables import RunnableParallel -from app.prompts.daily_question_prompt import system_template, human_template + from app.config.vectorestore import chroma_db from app.llm.provider import build_chat_model +from app.prompts.daily_question_prompt import human_template, system_template from app.settings import settings # using tech_description collection to retrieve context. diff --git a/app/schemas/utils.py b/app/schemas/utils.py index b4c468a..8e96644 100644 --- a/app/schemas/utils.py +++ b/app/schemas/utils.py @@ -1,5 +1,6 @@ from pydantic import BaseModel + class UserPrompt(BaseModel): """Schema for user prompt input.""" user_prompt: str | None = None diff --git a/app/services/questions.py b/app/services/questions.py index 13922d9..ba42372 100644 --- a/app/services/questions.py +++ b/app/services/questions.py @@ -1,7 +1,9 @@ from langchain_core.documents import Document -from app.pipelines.daily_question_pipeline import daily_question_chain -from app.llm.provider import invoke_with_retries + from app.config.vectorestore import chroma_db +from app.llm.provider import invoke_with_retries +from app.pipelines.daily_question_pipeline import daily_question_chain + def generate_daily_question(user_prompt: str = None) -> str: """Generate a daily question using the LLM pipeline."""