diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index a81d7d6c..2e6d18f1 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -21,18 +21,53 @@ jobs:
fail-fast: false
matrix:
include:
- - name: api-rate-limiter
- type: python
- path: PROJECTS/advanced/api-rate-limiter
- - name: dns-lookup
- type: python
- path: PROJECTS/beginner/dns-lookup
+ # Python (ruff) - Beginner
+ - name: caesar-cipher
+ type: ruff
+ path: PROJECTS/beginner/caesar-cipher
- name: keylogger
- type: python
+ type: ruff
path: PROJECTS/beginner/keylogger
- - name: docker-security-audit
- type: go
- path: PROJECTS/beginner/docker-security-audit
+ - name: dns-lookup
+ type: ruff
+ path: PROJECTS/beginner/dns-lookup
+ - name: metadata-scrubber-tool
+ type: ruff
+ path: PROJECTS/beginner/metadata-scrubber-tool
+ - name: network-traffic-analyzer
+ type: ruff
+ path: PROJECTS/beginner/network-traffic-analyzer
+ - name: base64-tool
+ type: ruff
+ path: PROJECTS/beginner/base64-tool
+ - name: c2-beacon-backend
+ type: ruff
+ path: PROJECTS/beginner/c2-beacon/backend
+ # Python (ruff) - Intermediate
+ - name: api-security-scanner-backend
+ type: ruff
+ path: PROJECTS/intermediate/api-security-scanner/backend
+ - name: siem-dashboard-backend
+ type: ruff
+ path: PROJECTS/intermediate/siem-dashboard/backend
+ # Python (ruff) - Advanced
+ - name: bug-bounty-platform-backend
+ type: ruff
+ path: PROJECTS/advanced/bug-bounty-platform/backend
+ - name: encrypted-p2p-chat-backend
+ type: ruff
+ path: PROJECTS/advanced/encrypted-p2p-chat/backend
+ - name: api-rate-limiter
+ type: ruff
+ path: PROJECTS/advanced/api-rate-limiter
+ - name: ai-threat-detection-backend
+ type: ruff
+ path: PROJECTS/advanced/ai-threat-detection/backend
+ # Python (ruff) - Templates
+ - name: fullstack-template-backend
+ type: ruff
+ path: TEMPLATES/fullstack-template/backend
+ # Biome (frontend)
- name: bug-bounty-platform-frontend
type: biome
path: PROJECTS/advanced/bug-bounty-platform/frontend
@@ -51,6 +86,10 @@ jobs:
- name: fullstack-template-frontend
type: biome
path: TEMPLATES/fullstack-template/frontend
+ # Go
+ - name: docker-security-audit
+ type: go
+ path: PROJECTS/beginner/docker-security-audit
defaults:
run:
@@ -60,28 +99,16 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- # Python Setup
+ # Ruff Setup
- name: Set up Python
- if: matrix.type == 'python'
+ if: matrix.type == 'ruff'
uses: actions/setup-python@v5
with:
python-version: '3.12'
- - name: Cache pip dependencies
- if: matrix.type == 'python'
- uses: actions/cache@v4
- with:
- path: ~/.cache/pip
- key: ${{ runner.os }}-pip-${{ matrix.name }}-${{ hashFiles(format('{0}/pyproject.toml', matrix.path)) }}
- restore-keys: |
- ${{ runner.os }}-pip-${{ matrix.name }}-
- ${{ runner.os }}-pip-
-
- - name: Install Python dependencies
- if: matrix.type == 'python'
- run: |
- python -m pip install --upgrade pip
- pip install -e ".[dev]"
+ - name: Install ruff
+ if: matrix.type == 'ruff'
+ run: pip install ruff
# Biome Setup
- name: Setup Node.js
@@ -118,24 +145,9 @@ jobs:
go-version: '1.21'
cache-dependency-path: ${{ matrix.path }}/go.sum
- # Python Linting
- - name: Run pylint
- if: matrix.type == 'python'
- id: pylint
- run: |
- echo "Running pylint..."
- if pylint . > pylint-output.txt 2>&1; then
- echo "PYLINT_PASSED=true" >> $GITHUB_ENV
- echo "No pylint errors found!"
- else
- echo "PYLINT_PASSED=false" >> $GITHUB_ENV
- echo "Pylint found issues!"
- fi
- cat pylint-output.txt
- continue-on-error: true
-
+ # Ruff Linting
- name: Run ruff
- if: matrix.type == 'python'
+ if: matrix.type == 'ruff'
id: ruff
run: |
echo "Running ruff check..."
@@ -149,21 +161,6 @@ jobs:
cat ruff-output.txt
continue-on-error: true
- - name: Run mypy
- if: matrix.type == 'python'
- id: mypy
- run: |
- echo "Running mypy..."
- if mypy . > mypy-output.txt 2>&1; then
- echo "MYPY_PASSED=true" >> $GITHUB_ENV
- echo "No mypy errors found"
- else
- echo "MYPY_PASSED=false" >> $GITHUB_ENV
- echo "Mypy found issues"
- fi
- cat mypy-output.txt
- continue-on-error: true
-
# Biome Linting
- name: Run Biome
if: matrix.type == 'biome'
@@ -196,30 +193,14 @@ jobs:
cat golangci-output.txt
continue-on-error: true
- # Create Summary for Python
- - name: Create Python Lint Summary
- if: matrix.type == 'python' && github.event_name == 'pull_request'
+ # Create Summary for Ruff
+ - name: Create Ruff Lint Summary
+ if: matrix.type == 'ruff' && github.event_name == 'pull_request'
run: |
{
echo "## Lint Results: ${{ matrix.name }}"
echo ''
- # Pylint Status
- if [[ "${{ env.PYLINT_PASSED }}" == "true" ]]; then
- echo '### Pylint: **Passed**'
- echo 'No pylint issues found.'
- else
- echo '### Pylint: **Issues Found**'
- echo 'View pylint output
'
- echo ''
- echo '```'
- head -100 pylint-output.txt
- echo '```'
- echo ' '
- fi
- echo ''
-
- # Ruff Status
if [[ "${{ env.RUFF_PASSED }}" == "true" ]]; then
echo '### Ruff: **Passed**'
echo 'No ruff issues found.'
@@ -234,23 +215,7 @@ jobs:
fi
echo ''
- # Mypy Status
- if [[ "${{ env.MYPY_PASSED }}" == "true" ]]; then
- echo '### Mypy: **Passed**'
- echo 'No mypy issues found.'
- else
- echo '### Mypy: **Issues Found**'
- echo 'View mypy output
'
- echo ''
- echo '```'
- head -100 mypy-output.txt
- echo '```'
- echo ' '
- fi
- echo ''
-
- # Overall Summary
- if [[ "${{ env.PYLINT_PASSED }}" == "true" ]] && [[ "${{ env.RUFF_PASSED }}" == "true" ]] && [[ "${{ env.MYPY_PASSED }}" == "true" ]]; then
+ if [[ "${{ env.RUFF_PASSED }}" == "true" ]]; then
echo '---'
echo '### All checks passed!'
else
@@ -269,7 +234,6 @@ jobs:
echo "## Lint Results: ${{ matrix.name }}"
echo ''
- # Biome Status
if [[ "${{ env.BIOME_PASSED }}" == "true" ]]; then
echo '### Biome: **Passed**'
echo 'No Biome issues found.'
@@ -284,7 +248,6 @@ jobs:
fi
echo ''
- # Overall Summary
if [[ "${{ env.BIOME_PASSED }}" == "true" ]]; then
echo '---'
echo '### All checks passed!'
@@ -304,7 +267,6 @@ jobs:
echo "## Lint Results: ${{ matrix.name }}"
echo ''
- # golangci-lint Status
if [[ "${{ env.GOLANGCI_PASSED }}" == "true" ]]; then
echo '### golangci-lint: **Passed**'
echo 'No golangci-lint issues found.'
@@ -319,7 +281,6 @@ jobs:
fi
echo ''
- # Overall Summary
if [[ "${{ env.GOLANGCI_PASSED }}" == "true" ]]; then
echo '---'
echo '### All checks passed!'
@@ -344,9 +305,9 @@ jobs:
# Exit with proper status
- name: Check lint status
run: |
- if [[ "${{ matrix.type }}" == "python" ]]; then
- if [[ "${{ env.PYLINT_PASSED }}" == "false" ]] || [[ "${{ env.RUFF_PASSED }}" == "false" ]] || [[ "${{ env.MYPY_PASSED }}" == "false" ]]; then
- echo "Python lint checks failed"
+ if [[ "${{ matrix.type }}" == "ruff" ]]; then
+ if [[ "${{ env.RUFF_PASSED }}" == "false" ]]; then
+ echo "Ruff lint checks failed"
exit 1
fi
elif [[ "${{ matrix.type }}" == "biome" ]]; then
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index eaae4495..8ee84f61 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,16 +1,95 @@
repos:
- # Python Backend Ruff Checks
+ # Python Ruff Checks
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.15.0
+ rev: v0.15.1
hooks:
+ # Beginner projects
- id: ruff
- name: ruff check (backend)
+ name: ruff check (caesar-cipher)
args: [--fix, --exit-non-zero-on-fix]
- files: ^PROJECTS/api-security-scanner/backend/
- exclude: ^PROJECTS/api-security-scanner/backend/(\.venv|__pycache__|\.pytest_cache)/
+ files: ^PROJECTS/beginner/caesar-cipher/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+ - id: ruff
+ name: ruff check (keylogger)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/beginner/keylogger/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
- # TODO: add additional ruff checks for remaining projects
+ - id: ruff
+ name: ruff check (dns-lookup)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/beginner/dns-lookup/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ - id: ruff
+ name: ruff check (metadata-scrubber-tool)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/beginner/metadata-scrubber-tool/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ - id: ruff
+ name: ruff check (network-traffic-analyzer)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/beginner/network-traffic-analyzer/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ - id: ruff
+ name: ruff check (base64-tool)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/beginner/base64-tool/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ - id: ruff
+ name: ruff check (c2-beacon backend)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/beginner/c2-beacon/backend/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ # Intermediate projects
+ - id: ruff
+ name: ruff check (api-security-scanner backend)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/intermediate/api-security-scanner/backend/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ - id: ruff
+ name: ruff check (siem-dashboard backend)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/intermediate/siem-dashboard/backend/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ # Advanced projects
+ - id: ruff
+ name: ruff check (bug-bounty-platform backend)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/advanced/bug-bounty-platform/backend/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ - id: ruff
+ name: ruff check (encrypted-p2p-chat backend)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/advanced/encrypted-p2p-chat/backend/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ - id: ruff
+ name: ruff check (api-rate-limiter)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/advanced/api-rate-limiter/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ - id: ruff
+ name: ruff check (ai-threat-detection backend)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^PROJECTS/advanced/ai-threat-detection/backend/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
+
+ # Templates
+ - id: ruff
+ name: ruff check (fullstack-template backend)
+ args: [--fix, --exit-non-zero-on-fix]
+ files: ^TEMPLATES/fullstack-template/backend/
+ exclude: (\.venv|__pycache__|\.pytest_cache)/
# TODO: add golangci checks for GO projects
diff --git a/PROJECTS/advanced/ai-threat-detection/backend/app/core/detection/rules.py b/PROJECTS/advanced/ai-threat-detection/backend/app/core/detection/rules.py
index 92b41e8f..04a86c77 100644
--- a/PROJECTS/advanced/ai-threat-detection/backend/app/core/detection/rules.py
+++ b/PROJECTS/advanced/ai-threat-detection/backend/app/core/detection/rules.py
@@ -115,7 +115,7 @@ class RuleEngine:
for trule in _THRESHOLD_RULES:
value = features.get(trule.feature_key, 0)
- if isinstance(value, (int, float)) and value > trule.threshold:
+ if isinstance(value, int | float) and value > trule.threshold:
matched.append((trule.name, trule.score))
if not matched:
diff --git a/PROJECTS/advanced/ai-threat-detection/backend/tests/test_api.py b/PROJECTS/advanced/ai-threat-detection/backend/tests/test_api.py
index 8441e262..45b33567 100644
--- a/PROJECTS/advanced/ai-threat-detection/backend/tests/test_api.py
+++ b/PROJECTS/advanced/ai-threat-detection/backend/tests/test_api.py
@@ -26,7 +26,7 @@ async def test_health_returns_200() -> None:
data = response.json()
assert data["status"] == "healthy"
assert "uptime_seconds" in data
- assert isinstance(data["uptime_seconds"], (int, float))
+ assert isinstance(data["uptime_seconds"], int | float)
assert "pipeline_running" in data
diff --git a/PROJECTS/advanced/api-rate-limiter/examples/app.py b/PROJECTS/advanced/api-rate-limiter/examples/app.py
index 142af93c..1b0ffd8d 100644
--- a/PROJECTS/advanced/api-rate-limiter/examples/app.py
+++ b/PROJECTS/advanced/api-rate-limiter/examples/app.py
@@ -6,7 +6,6 @@ app.py
from __future__ import annotations
import uvicorn
-from typing import Annotated
from contextlib import asynccontextmanager
from fastapi import (
@@ -17,7 +16,6 @@ from fastapi import (
from fastapi_420 import (
RateLimiter,
RateLimiterSettings,
- RateLimitMiddleware,
ScopedRateLimiter,
FingerprintSettings,
StorageSettings,
diff --git a/PROJECTS/advanced/api-rate-limiter/tests/conftest.py b/PROJECTS/advanced/api-rate-limiter/tests/conftest.py
index 0473431c..9370889f 100644
--- a/PROJECTS/advanced/api-rate-limiter/tests/conftest.py
+++ b/PROJECTS/advanced/api-rate-limiter/tests/conftest.py
@@ -10,15 +10,12 @@ import time
from collections.abc import AsyncGenerator, Generator
from dataclasses import dataclass, field
from typing import Any
-from unittest.mock import MagicMock
import pytest
from fastapi import FastAPI, Request
from httpx import ASGITransport, AsyncClient
from starlette.testclient import TestClient
-from fastapi_420.algorithms import create_algorithm
-from fastapi_420.algorithms.base import BaseAlgorithm
from fastapi_420.algorithms.fixed_window import FixedWindowAlgorithm
from fastapi_420.algorithms.sliding_window import SlidingWindowAlgorithm
from fastapi_420.algorithms.token_bucket import TokenBucketAlgorithm
@@ -50,7 +47,6 @@ from fastapi_420.types import (
RateLimitKey,
RateLimitResult,
RateLimitRule,
- StorageType,
TokenBucketState,
WindowState,
)
@@ -687,7 +683,7 @@ def rate_limiter_settings(
@pytest.fixture
-async def memory_storage() -> AsyncGenerator[MemoryStorage, None]:
+async def memory_storage() -> AsyncGenerator[MemoryStorage]:
"""
Create and manage MemoryStorage instance
"""
@@ -791,8 +787,7 @@ async def circuit_breaker() -> CircuitBreaker:
async def rate_limiter(
rate_limiter_settings: RateLimiterSettings,
memory_storage: MemoryStorage,
-) -> AsyncGenerator[RateLimiter,
- None]:
+) -> AsyncGenerator[RateLimiter]:
"""
Create and manage RateLimiter instance
"""
@@ -922,8 +917,7 @@ async def test_app_with_limiter(
@pytest.fixture
-async def async_client(test_app: FastAPI) -> AsyncGenerator[AsyncClient,
- None]:
+async def async_client(test_app: FastAPI) -> AsyncGenerator[AsyncClient]:
"""
Create async HTTP client for testing
"""
@@ -937,8 +931,7 @@ async def async_client(test_app: FastAPI) -> AsyncGenerator[AsyncClient,
@pytest.fixture
async def rate_limited_client(
test_app_with_limiter: FastAPI,
-) -> AsyncGenerator[AsyncClient,
- None]:
+) -> AsyncGenerator[AsyncClient]:
"""
Create async HTTP client with rate limiting
"""
@@ -950,7 +943,7 @@ async def rate_limited_client(
@pytest.fixture
-def sync_client(test_app: FastAPI) -> Generator[TestClient, None, None]:
+def sync_client(test_app: FastAPI) -> Generator[TestClient]:
"""
Create sync test client
"""
diff --git a/PROJECTS/advanced/api-rate-limiter/tests/test_algorithms.py b/PROJECTS/advanced/api-rate-limiter/tests/test_algorithms.py
index 70d68e6a..681966d5 100644
--- a/PROJECTS/advanced/api-rate-limiter/tests/test_algorithms.py
+++ b/PROJECTS/advanced/api-rate-limiter/tests/test_algorithms.py
@@ -4,7 +4,6 @@ test_algorithms.py
"""
from __future__ import annotations
-import time
import pytest
@@ -17,7 +16,6 @@ from fastapi_420.types import Algorithm
from tests.conftest import (
WINDOW_MINUTE,
- WINDOW_SECOND,
RuleFactory,
)
@@ -75,8 +73,8 @@ class TestSlidingWindowAlgorithm:
storage = MemoryStorage()
rule = RuleFactory.per_minute(100)
- for i in range(50):
- result = await algo.check(storage, f"multi_key", rule)
+ for _i in range(50):
+ result = await algo.check(storage, "multi_key", rule)
assert result.allowed is True
assert result.remaining == 50
diff --git a/PROJECTS/advanced/api-rate-limiter/tests/test_fingerprinting.py b/PROJECTS/advanced/api-rate-limiter/tests/test_fingerprinting.py
index 09a68b9a..d0d3bbff 100644
--- a/PROJECTS/advanced/api-rate-limiter/tests/test_fingerprinting.py
+++ b/PROJECTS/advanced/api-rate-limiter/tests/test_fingerprinting.py
@@ -67,7 +67,7 @@ class TestIPExtractor:
def test_ipv6_custom_prefix_length(self) -> None:
extractor = IPExtractor(ipv6_prefix_length = 48)
request = RequestFactory.create(client_ip = TEST_IP_V6)
- raw_ip, normalized_ip = extractor.extract(request)
+ _, normalized_ip = extractor.extract(request)
assert "::" in normalized_ip or normalized_ip != TEST_IP_V6
@@ -75,7 +75,7 @@ class TestIPExtractor:
extractor = IPExtractor()
ipv4_mapped = "::ffff:192.168.1.100"
request = RequestFactory.create(client_ip = ipv4_mapped)
- raw_ip, normalized_ip = extractor.extract(request)
+ _, normalized_ip = extractor.extract(request)
assert normalized_ip == "192.168.1.100"
@@ -323,7 +323,7 @@ class TestAuthExtractor:
extractor = AuthExtractor(hash_identifiers = False)
request = RequestFactory.with_auth(
auth_type = "bearer",
- token = "invalid"
+ token = "invalid" # noqa: S106
)
identifier = extractor.extract(request)
diff --git a/PROJECTS/advanced/api-rate-limiter/tests/test_limiter.py b/PROJECTS/advanced/api-rate-limiter/tests/test_limiter.py
index 3694f7b6..874f1a92 100644
--- a/PROJECTS/advanced/api-rate-limiter/tests/test_limiter.py
+++ b/PROJECTS/advanced/api-rate-limiter/tests/test_limiter.py
@@ -10,11 +10,9 @@ from fastapi_420.config import RateLimiterSettings
from fastapi_420.exceptions import EnhanceYourCalm, HTTP_420_ENHANCE_YOUR_CALM
from fastapi_420.limiter import RateLimiter
from fastapi_420.storage import MemoryStorage
-from fastapi_420.types import Algorithm, FingerprintLevel
+from fastapi_420.types import Algorithm
from tests.conftest import (
- WINDOW_MINUTE,
- DEFAULT_LIMIT_REQUESTS,
RequestFactory,
)
diff --git a/PROJECTS/advanced/api-rate-limiter/tests/test_storage.py b/PROJECTS/advanced/api-rate-limiter/tests/test_storage.py
index 349b7245..397196df 100644
--- a/PROJECTS/advanced/api-rate-limiter/tests/test_storage.py
+++ b/PROJECTS/advanced/api-rate-limiter/tests/test_storage.py
@@ -15,8 +15,6 @@ from fastapi_420.types import StorageType
from tests.conftest import (
WINDOW_MINUTE,
- WINDOW_SECOND,
- DEFAULT_LIMIT_REQUESTS,
)
@@ -163,7 +161,6 @@ class TestMemoryStorageSlidingWindow:
previous_window = current_window - 1
prev_key = f"{key}:{previous_window}"
- curr_key = f"{key}:{current_window}"
storage._windows[prev_key] = storage._windows.__class__().__class__
from fastapi_420.storage.memory import WindowEntry
@@ -360,7 +357,6 @@ class TestMemoryStorageCleanup:
storage = MemoryStorage(cleanup_interval = 1)
await storage.start_cleanup_task()
- task = storage._cleanup_task
await storage.close()
assert storage._cleanup_task is None
diff --git a/PROJECTS/advanced/bug-bounty-platform/backend/app/config.py b/PROJECTS/advanced/bug-bounty-platform/backend/app/config.py
index 77261727..89cafe19 100644
--- a/PROJECTS/advanced/bug-bounty-platform/backend/app/config.py
+++ b/PROJECTS/advanced/bug-bounty-platform/backend/app/config.py
@@ -188,9 +188,8 @@ class Settings(BaseSettings):
"""
Enforce security constraints in production environment.
"""
- if self.ENVIRONMENT == Environment.PRODUCTION:
- if self.DEBUG:
- raise ValueError("DEBUG must be False in production")
+ if self.ENVIRONMENT == Environment.PRODUCTION and self.DEBUG:
+ raise ValueError("DEBUG must be False in production")
return self
diff --git a/PROJECTS/advanced/bug-bounty-platform/backend/app/factory.py b/PROJECTS/advanced/bug-bounty-platform/backend/app/factory.py
index c8f790e4..87024b26 100644
--- a/PROJECTS/advanced/bug-bounty-platform/backend/app/factory.py
+++ b/PROJECTS/advanced/bug-bounty-platform/backend/app/factory.py
@@ -12,7 +12,7 @@ from fastapi.responses import JSONResponse
from slowapi import _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded
-from config import settings, Environment, API_PREFIX
+from config import settings, API_PREFIX
from core.database import sessionmanager
from core.exceptions import BaseAppException
from core.logging import configure_logging
@@ -74,8 +74,6 @@ def create_app() -> FastAPI:
"""
Application factory
"""
- is_production = settings.ENVIRONMENT == Environment.PRODUCTION
-
app = FastAPI(
title = settings.APP_NAME,
summary = settings.APP_SUMMARY,
diff --git a/PROJECTS/advanced/encrypted-p2p-chat/backend/app/api/encryption.py b/PROJECTS/advanced/encrypted-p2p-chat/backend/app/api/encryption.py
index 1a30faf2..355e7504 100644
--- a/PROJECTS/advanced/encrypted-p2p-chat/backend/app/api/encryption.py
+++ b/PROJECTS/advanced/encrypted-p2p-chat/backend/app/api/encryption.py
@@ -4,7 +4,6 @@ Encryption endpoints for X3DH prekey bundles
"""
import logging
-from typing import Optional
from uuid import UUID
from fastapi import APIRouter, Depends, status
diff --git a/PROJECTS/beginner/c2-beacon/backend/tests/conftest.py b/PROJECTS/beginner/c2-beacon/backend/tests/conftest.py
index 196689ea..2acc3424 100644
--- a/PROJECTS/beginner/c2-beacon/backend/tests/conftest.py
+++ b/PROJECTS/beginner/c2-beacon/backend/tests/conftest.py
@@ -3,7 +3,6 @@ AngelaMos | 2026
conftest.py
"""
-import tempfile
from pathlib import Path
import pytest
diff --git a/PROJECTS/beginner/c2-beacon/backend/tests/test_encoding.py b/PROJECTS/beginner/c2-beacon/backend/tests/test_encoding.py
index 4c4027f8..02ee1842 100644
--- a/PROJECTS/beginner/c2-beacon/backend/tests/test_encoding.py
+++ b/PROJECTS/beginner/c2-beacon/backend/tests/test_encoding.py
@@ -3,7 +3,6 @@ AngelaMos | 2026
test_encoding.py
"""
-import pytest
from core.encoding import decode, encode, xor_bytes
diff --git a/PROJECTS/beginner/c2-beacon/backend/tests/test_protocol.py b/PROJECTS/beginner/c2-beacon/backend/tests/test_protocol.py
index a837c453..53604bde 100644
--- a/PROJECTS/beginner/c2-beacon/backend/tests/test_protocol.py
+++ b/PROJECTS/beginner/c2-beacon/backend/tests/test_protocol.py
@@ -8,7 +8,6 @@ import pytest
from core.models import CommandType
from core.protocol import Message, MessageType, pack, unpack
-
TEST_KEY = "test-protocol-key"
diff --git a/PROJECTS/beginner/c2-beacon/backend/tests/test_tasking.py b/PROJECTS/beginner/c2-beacon/backend/tests/test_tasking.py
index 631639cd..8d56f224 100644
--- a/PROJECTS/beginner/c2-beacon/backend/tests/test_tasking.py
+++ b/PROJECTS/beginner/c2-beacon/backend/tests/test_tasking.py
@@ -172,11 +172,12 @@ class TestTaskManager:
await asyncio.sleep(0.1)
await task_manager.submit(_make_task("delayed"), db)
- asyncio.create_task(delayed_submit())
+ background_task = asyncio.create_task(delayed_submit())
retrieved = await asyncio.wait_for(
task_manager.get_next("beacon-t"), timeout=2.0
)
assert retrieved.id == "delayed"
+ await background_task
def test_remove_queue(self, task_manager: TaskManager) -> None:
"""
diff --git a/PROJECTS/beginner/dns-lookup/dnslookup/resolver.py b/PROJECTS/beginner/dns-lookup/dnslookup/resolver.py
index 31a121b5..165b94d1 100644
--- a/PROJECTS/beginner/dns-lookup/dnslookup/resolver.py
+++ b/PROJECTS/beginner/dns-lookup/dnslookup/resolver.py
@@ -9,10 +9,7 @@ from __future__ import annotations
import asyncio
import time
-from dataclasses import (
- dataclass,
- field
-)
+from dataclasses import dataclass, field
from enum import StrEnum
from typing import Any
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/scripts/generate_png_tests.py b/PROJECTS/beginner/metadata-scrubber-tool/scripts/generate_png_tests.py
index 7cab3219..ac1a6d6b 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/scripts/generate_png_tests.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/scripts/generate_png_tests.py
@@ -5,7 +5,6 @@ from pathlib import Path
from PIL import Image, PngImagePlugin
-
dest_dir = Path("tests/assets/test_images")
# Generate 45 PNG images with various metadata
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/src/commands/read.py b/PROJECTS/beginner/metadata-scrubber-tool/src/commands/read.py
index c827b0da..01ba37ff 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/src/commands/read.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/src/commands/read.py
@@ -15,7 +15,6 @@ from src.services.metadata_factory import MetadataFactory
from src.utils.display import print_metadata_table
from src.utils.get_target_files import get_target_files
-
console = Console()
log = logging.getLogger("metadata-scrubber")
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/src/commands/scrub.py b/PROJECTS/beginner/metadata-scrubber-tool/src/commands/scrub.py
index ef6f3b1c..c580f33e 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/src/commands/scrub.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/src/commands/scrub.py
@@ -27,7 +27,6 @@ from src.services.batch_processor import BatchProcessor
from src.utils.display import print_batch_summary
from src.utils.get_target_files import get_target_files
-
console = Console()
log = logging.getLogger("metadata-scrubber")
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/src/commands/verify.py b/PROJECTS/beginner/metadata-scrubber-tool/src/commands/verify.py
index 2b40810f..f0a99c9b 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/src/commands/verify.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/src/commands/verify.py
@@ -14,7 +14,6 @@ from rich.console import Console
from src.services.metadata_factory import MetadataFactory
from src.services.report_generator import ReportGenerator
-
console = Console()
log = logging.getLogger("metadata-scrubber")
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/src/core/png_metadata.py b/PROJECTS/beginner/metadata-scrubber-tool/src/core/png_metadata.py
index f970a28a..30cf78d9 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/src/core/png_metadata.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/src/core/png_metadata.py
@@ -91,7 +91,7 @@ class PngProcessor:
if key in ("icc_profile", "exif", "transparency", "gamma"):
continue
- if isinstance(value, (str, bytes)):
+ if isinstance(value, str | bytes):
found_metadata = True
if isinstance(value, bytes):
try:
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/src/services/batch_processor.py b/PROJECTS/beginner/metadata-scrubber-tool/src/services/batch_processor.py
index b7bee94a..222452de 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/src/services/batch_processor.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/src/services/batch_processor.py
@@ -19,7 +19,6 @@ from rich.console import Console
from src.services.metadata_factory import MetadataFactory
-
log = logging.getLogger("metadata-scrubber")
console = Console()
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/src/utils/display.py b/PROJECTS/beginner/metadata-scrubber-tool/src/utils/display.py
index 04ea030b..531d8e4f 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/src/utils/display.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/src/utils/display.py
@@ -15,7 +15,6 @@ from rich.text import Text
from src.utils.formatter import clean_value
-
console = Console()
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_read_command.py b/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_read_command.py
index bc4cb48a..4640b6ec 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_read_command.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_read_command.py
@@ -22,7 +22,6 @@ from tests.conftest import (
get_xlsx_test_file,
)
-
runner = CliRunner()
# Test file paths (cross-platform)
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_scrub_command.py b/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_scrub_command.py
index d9e77734..b00cb35c 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_scrub_command.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_scrub_command.py
@@ -22,7 +22,6 @@ from tests.conftest import (
get_xlsx_test_file,
)
-
runner = CliRunner()
# Test file paths (cross-platform)
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_verify_command.py b/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_verify_command.py
index 0d9592ac..0da4bad0 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_verify_command.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/tests/e2e/test_verify_command.py
@@ -13,7 +13,6 @@ from typer.testing import CliRunner
from src.main import app
-
runner = CliRunner()
diff --git a/PROJECTS/beginner/metadata-scrubber-tool/tests/integration/test_metadata_factory.py b/PROJECTS/beginner/metadata-scrubber-tool/tests/integration/test_metadata_factory.py
index 78a62220..bd46ac79 100644
--- a/PROJECTS/beginner/metadata-scrubber-tool/tests/integration/test_metadata_factory.py
+++ b/PROJECTS/beginner/metadata-scrubber-tool/tests/integration/test_metadata_factory.py
@@ -44,7 +44,7 @@ def test_read_image_metadata(x):
assert handler.metadata == metadata
assert isinstance(metadata, dict)
- if isinstance(handler, (JpegProcessor, PngProcessor)):
+ if isinstance(handler, JpegProcessor | PngProcessor):
assert (
handler.tags_to_delete is not None or handler.text_keys_to_delete is not None
)
diff --git a/PROJECTS/beginner/network-traffic-analyzer/tests/test_filters.py b/PROJECTS/beginner/network-traffic-analyzer/tests/test_filters.py
index 8ecf2c4a..eda0abf3 100644
--- a/PROJECTS/beginner/network-traffic-analyzer/tests/test_filters.py
+++ b/PROJECTS/beginner/network-traffic-analyzer/tests/test_filters.py
@@ -91,7 +91,7 @@ class TestFilterBuilder:
Verify OR operator joins expressions
"""
result = (
- FilterBuilder().port(80).port(443).build(operator = "or")
+ FilterBuilder().port(80).port(443).build(operator="or")
)
assert result == "port 80 or port 443"
@@ -137,14 +137,14 @@ class TestCombineFilters:
"""
Verify multiple filters combine with AND
"""
- result = combine_filters(["tcp", "port 80"], operator = "and")
+ result = combine_filters(["tcp", "port 80"], operator="and")
assert result == "(tcp) and (port 80)"
def test_combine_multiple_or(self):
"""
Verify multiple filters combine with OR
"""
- result = combine_filters(["port 80", "port 443"], operator = "or")
+ result = combine_filters(["port 80", "port 443"], operator="or")
assert result == "(port 80) or (port 443)"
diff --git a/PROJECTS/beginner/network-traffic-analyzer/tests/test_models.py b/PROJECTS/beginner/network-traffic-analyzer/tests/test_models.py
index 73e691c6..1f68ebc4 100644
--- a/PROJECTS/beginner/network-traffic-analyzer/tests/test_models.py
+++ b/PROJECTS/beginner/network-traffic-analyzer/tests/test_models.py
@@ -5,6 +5,7 @@ test_models.py
Basic happy path tests for data models
"""
+
import pytest
from netanal.models import (
@@ -43,16 +44,16 @@ class TestPacketInfo:
Verify PacketInfo stores all fields correctly
"""
packet = PacketInfo(
- timestamp = 1234567890.123,
- src_ip = "192.168.1.1",
- dst_ip = "192.168.1.2",
- protocol = Protocol.TCP,
- size = 1500,
- src_port = 443,
- dst_port = 54321,
+ timestamp=1234567890.123,
+ src_ip="192.168.1.1",
+ dst_ip="192.168.1.2",
+ protocol=Protocol.TCP,
+ size=1500,
+ src_port=443,
+ dst_port=54321,
)
- assert packet.timestamp == 1234567890.123
+ assert packet.timestamp == pytest.approx(1234567890.123)
assert packet.src_ip == "192.168.1.1"
assert packet.dst_ip == "192.168.1.2"
assert packet.protocol == Protocol.TCP
@@ -65,11 +66,11 @@ class TestPacketInfo:
Verify optional fields default to None
"""
packet = PacketInfo(
- timestamp = 0.0,
- src_ip = "10.0.0.1",
- dst_ip = "10.0.0.2",
- protocol = Protocol.ICMP,
- size = 64,
+ timestamp=0.0,
+ src_ip="10.0.0.1",
+ dst_ip="10.0.0.2",
+ protocol=Protocol.ICMP,
+ size=64,
)
assert packet.src_port is None
@@ -99,16 +100,16 @@ class TestCaptureConfig:
Verify custom configuration is stored correctly
"""
config = CaptureConfig(
- interface = "eth0",
- bpf_filter = "tcp port 80",
- packet_count = 100,
- timeout_seconds = 30.0,
+ interface="eth0",
+ bpf_filter="tcp port 80",
+ packet_count=100,
+ timeout_seconds=30.0,
)
assert config.interface == "eth0"
assert config.bpf_filter == "tcp port 80"
assert config.packet_count == 100
- assert config.timeout_seconds == 30.0
+ assert config.timeout_seconds == pytest.approx(30.0)
class TestEndpointStats:
@@ -119,7 +120,7 @@ class TestEndpointStats:
"""
Verify total_packets and total_bytes computed properties
"""
- endpoint = EndpointStats(ip_address = "192.168.1.100")
+ endpoint = EndpointStats(ip_address="192.168.1.100")
endpoint.packets_sent = 50
endpoint.packets_received = 30
endpoint.bytes_sent = 5000
@@ -149,36 +150,36 @@ class TestCaptureStatistics:
Verify duration_seconds computed property
"""
stats = CaptureStatistics(
- start_time = 1000.0,
- end_time = 1010.0,
+ start_time=1000.0,
+ end_time=1010.0,
)
- assert stats.duration_seconds == 10.0
+ assert stats.duration_seconds == pytest.approx(10.0)
def test_average_bandwidth(self):
"""
Verify average_bandwidth calculation (bytes/second)
"""
stats = CaptureStatistics(
- start_time = 1000.0,
- end_time = 1010.0,
- total_bytes = 10000,
+ start_time=1000.0,
+ end_time=1010.0,
+ total_bytes=10000,
)
- assert stats.average_bandwidth == 1000.0
+ assert stats.average_bandwidth == pytest.approx(1000.0)
def test_protocol_percentages(self):
"""
Verify get_protocol_percentages returns correct distribution
"""
- stats = CaptureStatistics(total_packets = 100)
+ stats = CaptureStatistics(total_packets=100)
stats.protocol_distribution[Protocol.TCP] = 70
stats.protocol_distribution[Protocol.UDP] = 30
percentages = stats.get_protocol_percentages()
- assert percentages[Protocol.TCP] == 70.0
- assert percentages[Protocol.UDP] == 30.0
+ assert percentages[Protocol.TCP] == pytest.approx(70.0)
+ assert percentages[Protocol.UDP] == pytest.approx(30.0)
def test_top_talkers(self):
"""
@@ -186,15 +187,15 @@ class TestCaptureStatistics:
"""
stats = CaptureStatistics()
- endpoint1 = EndpointStats(ip_address = "192.168.1.1")
+ endpoint1 = EndpointStats(ip_address="192.168.1.1")
endpoint1.bytes_sent = 1000
endpoint1.bytes_received = 500
- endpoint2 = EndpointStats(ip_address = "192.168.1.2")
+ endpoint2 = EndpointStats(ip_address="192.168.1.2")
endpoint2.bytes_sent = 5000
endpoint2.bytes_received = 2000
- endpoint3 = EndpointStats(ip_address = "192.168.1.3")
+ endpoint3 = EndpointStats(ip_address="192.168.1.3")
endpoint3.bytes_sent = 100
endpoint3.bytes_received = 50
@@ -202,7 +203,7 @@ class TestCaptureStatistics:
stats.endpoints["192.168.1.2"] = endpoint2
stats.endpoints["192.168.1.3"] = endpoint3
- top = stats.get_top_talkers(limit = 2)
+ top = stats.get_top_talkers(limit=2)
assert len(top) == 2
assert top[0].ip_address == "192.168.1.2"
diff --git a/PROJECTS/intermediate/api-security-scanner/backend/core/database.py b/PROJECTS/intermediate/api-security-scanner/backend/core/database.py
index d90feeae..3f6e273c 100644
--- a/PROJECTS/intermediate/api-security-scanner/backend/core/database.py
+++ b/PROJECTS/intermediate/api-security-scanner/backend/core/database.py
@@ -28,7 +28,7 @@ SessionLocal = sessionmaker(
Base = declarative_base()
-def get_db() -> Generator[Session, None, None]:
+def get_db() -> Generator[Session]:
"""
FastAPI dependency for database sessions
"""
diff --git a/PROJECTS/intermediate/siem-dashboard/backend/app/engine/normalizer.py b/PROJECTS/intermediate/siem-dashboard/backend/app/engine/normalizer.py
index 968db07c..184bf0e8 100644
--- a/PROJECTS/intermediate/siem-dashboard/backend/app/engine/normalizer.py
+++ b/PROJECTS/intermediate/siem-dashboard/backend/app/engine/normalizer.py
@@ -4,7 +4,8 @@ normalizer.py
"""
from datetime import datetime, UTC
-from typing import Any, Callable
+from typing import Any
+from collections.abc import Callable
from app.models.LogEvent import SourceType