PunimTag Web Application - Major Feature Release #1

Open
tanyar09 wants to merge 106 commits from dev into master
3 changed files with 63 additions and 28 deletions
Showing only changes of commit 922c468e9b - Show all commits

View File

@ -506,22 +506,39 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY || true
if [ "$LEAK_COUNT" -gt 0 ]; then
echo "### Leak Details" >> $GITHUB_STEP_SUMMARY || true
echo "### Leak Summary Table" >> $GITHUB_STEP_SUMMARY || true
echo "" >> $GITHUB_STEP_SUMMARY || true
echo "| File | Line | Rule | Description | Commit |" >> $GITHUB_STEP_SUMMARY || true
echo "|------|------|------|-------------|--------|" >> $GITHUB_STEP_SUMMARY || true
echo "| File | Line | Rule | Entropy | Commit | Author | Date |" >> $GITHUB_STEP_SUMMARY || true
echo "|------|------|------|---------|--------|--------|------|" >> $GITHUB_STEP_SUMMARY || true
# Extract and display leak details
jq -r '.[] | "| \(.File) | \(.Line) | \(.RuleID) | \(.Description // "N/A") | \(.Commit // "N/A") |"' gitleaks-report.json >> $GITHUB_STEP_SUMMARY || true
# Extract and display leak details in table format
jq -r '.[] | "| \(.File) | \(.Line) | \(.RuleID) | \(.Entropy // "N/A") | `\(.Commit[0:8])` | \(.Author // "N/A") | \(.Date // "N/A") |"' gitleaks-report.json >> $GITHUB_STEP_SUMMARY || true
echo "" >> $GITHUB_STEP_SUMMARY || true
echo "### Detailed Findings" >> $GITHUB_STEP_SUMMARY || true
echo "" >> $GITHUB_STEP_SUMMARY || true
# Display each finding with full details
jq -r '.[] |
"#### Finding: \(.RuleID) in \(.File):\(.Line)\n" +
"- **File:** `\(.File)`\n" +
"- **Line:** \(.Line)\n" +
"- **Rule ID:** \(.RuleID)\n" +
"- **Description:** \(.Description // "N/A")\n" +
"- **Entropy:** \(.Entropy // "N/A")\n" +
"- **Commit:** `\(.Commit)`\n" +
"- **Author:** \(.Author // "N/A") (\(.Email // "N/A"))\n" +
"- **Date:** \(.Date // "N/A")\n" +
"- **Fingerprint:** `\(.Fingerprint // "N/A")`\n"' gitleaks-report.json >> $GITHUB_STEP_SUMMARY || true
echo "" >> $GITHUB_STEP_SUMMARY || true
echo "### Full Report (JSON)" >> $GITHUB_STEP_SUMMARY || true
echo '```json' >> $GITHUB_STEP_SUMMARY || true
cat gitleaks-report.json >> $GITHUB_STEP_SUMMARY || true
echo '```' >> $GITHUB_STEP_SUMMARY || true
echo "" >> $GITHUB_STEP_SUMMARY || true
echo "⚠️ **Action Required:** Review and remove the secrets found above." >> $GITHUB_STEP_SUMMARY || true
echo "⚠️ **Action Required:** Review and remove the secrets found above. Secrets should be removed from the codebase and rotated if they were ever exposed." >> $GITHUB_STEP_SUMMARY || true
else
echo "✅ No secrets detected!" >> $GITHUB_STEP_SUMMARY || true
fi
@ -595,22 +612,36 @@ jobs:
steps:
- name: Generate workflow summary
run: |
echo "## 🔍 CI Workflow Summary" >> $GITHUB_STEP_SUMMARY || true
echo "" >> $GITHUB_STEP_SUMMARY || true
echo "### Job Results" >> $GITHUB_STEP_SUMMARY || true
echo "" >> $GITHUB_STEP_SUMMARY || true
echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY || true
echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY || true
echo "| 📝 Lint & Type Check | ${{ needs.lint-and-type-check.result }} |" >> $GITHUB_STEP_SUMMARY || true
echo "| 🐍 Python Lint | ${{ needs.python-lint.result }} |" >> $GITHUB_STEP_SUMMARY || true
echo "| 🧪 Backend Tests | ${{ needs.test-backend.result }} |" >> $GITHUB_STEP_SUMMARY || true
echo "| 🏗️ Build | ${{ needs.build.result }} |" >> $GITHUB_STEP_SUMMARY || true
echo "| 🔐 Secret Scanning | ${{ needs.secret-scanning.result }} |" >> $GITHUB_STEP_SUMMARY || true
echo "| 📦 Dependency Scan | ${{ needs.dependency-scan.result }} |" >> $GITHUB_STEP_SUMMARY || true
echo "| 🔍 SAST Scan | ${{ needs.sast-scan.result }} |" >> $GITHUB_STEP_SUMMARY || true
echo "" >> $GITHUB_STEP_SUMMARY || true
echo "### 📊 Summary" >> $GITHUB_STEP_SUMMARY || true
echo "" >> $GITHUB_STEP_SUMMARY || true
echo "All security and validation checks have completed." >> $GITHUB_STEP_SUMMARY || true
{
echo "## 🔍 CI Workflow Summary"
echo ""
echo "This table gives a **plain-English overview** of what ran in this pipeline and whether it passed."
echo ""
echo "### Job Results"
echo ""
echo "| Job | What it does | Status |"
echo "|-----|--------------|--------|"
echo "| 📝 Lint & Type Check | Runs ESLint on the admin UI and TypeScript type-checks the viewer UI | ${{ needs.lint-and-type-check.result }} |"
echo "| 🐍 Python Lint | Runs Python style and syntax checks over the backend | ${{ needs.python-lint.result }} |"
echo "| 🧪 Backend Tests | Runs \`pytest tests/ -v\` against the FastAPI backend (with coverage) | ${{ needs.test-backend.result }} |"
echo "| 🏗️ Build | Builds the admin frontend (Vite) and viewer frontend (Next.js) | ${{ needs.build.result }} |"
echo "| 🔐 Secret Scanning | Uses Gitleaks to look for committed secrets | ${{ needs.secret-scanning.result }} |"
echo "| 📦 Dependency Scan | Uses Trivy to scan dependencies for HIGH/CRITICAL vulns | ${{ needs.dependency-scan.result }} |"
echo "| 🔍 SAST Scan | Uses Semgrep to look for insecure code patterns | ${{ needs.sast-scan.result }} |"
echo ""
echo "Legend for the **Status** column:"
echo "- \`success\`: job finished and all checks/tests passed."
echo "- \`failure\`: job ran but one or more checks/tests failed (see that job's log)."
echo "- \`cancelled\`: job was stopped before finishing."
echo "- \`skipped\`: job did not run, usually because CI was skipped for this commit."
echo ""
echo "### 📊 How to read the backend test results"
echo ""
echo "- The **Backend Tests** row tells you if the test run as a whole passed or failed."
echo "- To see which specific tests failed or how they ran:"
echo " 1. Open the **test-backend** job in this workflow run."
echo " 2. Look at the **Run backend tests** step to see the \`pytest -v\` output."
echo " 3. For local debugging, run \`pytest tests/ -v\` in your dev environment."
} >> \"${GITHUB_STEP_SUMMARY:-/dev/stdout}\"
continue-on-error: true

View File

@ -3,6 +3,7 @@
from __future__ import annotations
import os
import uuid
from datetime import datetime, timedelta
from typing import Annotated
@ -87,7 +88,7 @@ def create_access_token(data: dict, expires_delta: timedelta) -> str:
"""Create JWT access token."""
to_encode = data.copy()
expire = datetime.utcnow() + expires_delta
to_encode.update({"exp": expire})
to_encode.update({"exp": expire, "jti": str(uuid.uuid4())})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
@ -95,7 +96,7 @@ def create_refresh_token(data: dict) -> str:
"""Create JWT refresh token."""
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
to_encode.update({"exp": expire, "type": "refresh"})
to_encode.update({"exp": expire, "type": "refresh", "jti": str(uuid.uuid4())})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

View File

@ -126,7 +126,7 @@ class TestTokenRefresh:
"""Test token refresh endpoint."""
def test_refresh_token_success(
self, test_client: TestClient, auth_token: str
self, test_client: TestClient
):
"""Verify successful token refresh."""
# Get refresh token from login
@ -134,7 +134,10 @@ class TestTokenRefresh:
"/api/v1/auth/login",
json={"username": "testadmin", "password": "testpass"}
)
refresh_token = login_response.json()["refresh_token"]
assert login_response.status_code == 200
login_data = login_response.json()
initial_access_token = login_data["access_token"]
refresh_token = login_data["refresh_token"]
# Use refresh token to get new access token
response = test_client.post(
@ -146,7 +149,7 @@ class TestTokenRefresh:
data = response.json()
assert "access_token" in data
assert "refresh_token" in data
assert data["access_token"] != auth_token # Should be different token
assert data["access_token"] != initial_access_token # Should be different token
def test_refresh_token_with_invalid_token(self, test_client: TestClient):
"""Verify 401 with invalid refresh token."""