Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ mlruns/
models/*.pt
models/*.pth
models/*.ckpt
models/
data/
benchmarks/
scripts/
.git
.github
tests/
Expand Down
11 changes: 7 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
SECRET_KEY=change-this-to-a-long-random-secret
REDIS_URL=redis://localhost:6379
MLFLOW_TRACKING_URI=http://localhost:5000
ENVIRONMENT=development
API_KEY=replace-with-a-long-random-service-key
ENVIRONMENT=production
MODEL_BUNDLE_PATH=models/current
MAX_INFERENCE_MS=250
MAX_CONCURRENT_INFERENCES=8
CACHE_TTL_SECONDS=30
REQUESTS_PER_MINUTE=120
LOG_LEVEL=INFO
10 changes: 8 additions & 2 deletions .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@ jobs:
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install pytest pytest-benchmark
pip install pytest

- name: ⏱️ Profile Code Execution Speeds
run: |
pytest --benchmark-only --benchmark-skip || echo "Performance profiles logged successfully."
python -m benchmarks.inference --iterations 200 --warmup 20 > benchmark-results.json

- name: 📎 Upload benchmark evidence
uses: actions/upload-artifact@v4
with:
name: inference-benchmark
path: benchmark-results.json
39 changes: 38 additions & 1 deletion .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,41 @@ jobs:

- name: 🧪 Execute Recommender Test Suite
run: |
pytest --cov=. --cov-report=term-missing tests/ || echo "⚠️ Core Engine: Complete test coverage tracking."
pytest --cov=app --cov=src --cov-report=term-missing --cov-report=xml --cov-fail-under=85 tests/

- name: 📎 Upload test evidence
uses: actions/upload-artifact@v4
with:
name: test-evidence
path: coverage.xml

container-smoke:
name: Verified Bundle Container Smoke Test
runs-on: ubuntu-latest
needs: engine-test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: pip
- name: Build a pipeline-validation bundle
run: |
pip install -r requirements.txt
python -m scripts.generate_demo_data --output data/ci-events.jsonl
python -m src.training.train --dataset data/ci-events.jsonl --output models/current --epochs 1 --top-k 5
- name: Build and verify the production image
run: |
docker build -t deepsequence:${{ github.sha }} .
docker run -d --rm --name deepsequence-ci --read-only --tmpfs /tmp \
-e API_KEY=ci-test-key \
-v "${PWD}/models/current:/models/current:ro" \
-p 8000:8000 deepsequence:${{ github.sha }}
trap 'docker logs deepsequence-ci || true; docker stop deepsequence-ci >/dev/null 2>&1 || true' EXIT
for attempt in {1..30}; do
if curl --fail --silent http://127.0.0.1:8000/recommendations/health | grep '"trained_model":true'; then
exit 0
fi
sleep 2
done
exit 1
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ jobs:
- name: 📦 Provision Linting Binaries
run: |
python -m pip install --upgrade pip
pip install flake8
pip install ruff

# FIXED: Added F821 and W292 to ensure type hints or missing file newlines don't break the build
- name: 🚀 Verify PEP 8 Alignment
run: flake8 . --ignore=W293,W291,F401,E302,E305,E701,E203,E501,E261,W292,F821 --exclude=venv,.git,__pycache__,build,dist
run: ruff check app src benchmarks scripts tests streamlit_app.py
4 changes: 2 additions & 2 deletions .github/workflows/data-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ jobs:
- name: 📦 Install Data Integrity Frameworks
run: |
python -m pip install --upgrade pip
pip install pydantic great_expectations pytest
pip install pydantic pytest

- name: 🧬 Audit Ingestion Model Integrity
run: |
pytest tests/test_schema_contracts.py || pytest tests/ || echo "⚠️ Ingestion Schema: Skipping data validation pass."
pytest tests/test_schema_contracts.py
4 changes: 2 additions & 2 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ jobs:

- name: 📦 Evaluate Package Insecurities
run: |
pip install safety
safety check || echo "⚠️ Security Alert: Review reported package vulnerabilities."
pip install pip-audit
pip-audit -r requirements.txt
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ mlruns/
models/*.pt
models/*.pth
models/*.ckpt
models/
data/
testtmp/
benchmark-results.json
coverage.xml
45 changes: 26 additions & 19 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
FROM python:3.11-slim AS base

WORKDIR /app

# Install OS-level dependencies
RUN apt-get update && apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/*

FROM python:3.11-slim AS builder
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 PIP_NO_CACHE_DIR=1
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# ---- Runtime stage ----
FROM base AS runtime

COPY app/ app/

# Non-root user for security
RUN useradd -m appuser
USER appuser
RUN python -m venv /opt/venv \
&& /opt/venv/bin/pip install --upgrade pip \
&& /opt/venv/bin/pip install -r requirements.txt

FROM python:3.11-slim AS runtime
ENV PATH=/opt/venv/bin:$PATH \
PYTHONPATH=/app \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
ENVIRONMENT=production \
MODEL_BUNDLE_PATH=/models/current

RUN useradd --create-home --uid 10001 appuser \
&& mkdir -p /models/current \
&& chown -R appuser:appuser /models
WORKDIR /app
COPY --from=builder /opt/venv /opt/venv
COPY --chown=appuser:appuser app app
COPY --chown=appuser:appuser src src

USER 10001
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/recommendations/health', timeout=3)"

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--no-access-log"]
Loading
Loading