diff --git a/.github/workflows/trojanchat-hygiene.yml b/.github/workflows/trojanchat-hygiene.yml index df06253..655a400 100644 --- a/.github/workflows/trojanchat-hygiene.yml +++ b/.github/workflows/trojanchat-hygiene.yml @@ -112,6 +112,7 @@ jobs: run: | pip-audit -r requirements.txt --progress-spinner off --format json --output pip-audit.json - name: Upload dependency audit + if: always() uses: actions/upload-artifact@v7 with: name: pip-audit-report diff --git a/Dockerfile b/Dockerfile index 13a1919..d7b0552 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,10 +18,11 @@ ENV PATH=/opt/venv/bin:$PATH \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONPATH=/app -# The base image ships build tooling that is unnecessary at runtime. Removing it -# also prevents scanners from treating setuptools' vendored build dependencies -# as remotely exploitable application packages. -RUN python -m pip uninstall --yes setuptools wheel \ +# The runtime executes Uvicorn from /opt/venv and does not install packages. +# Remove the base image's package-management tooling and bundled installer +# payloads so they cannot ship vulnerable vendored dependencies. +RUN python -m pip uninstall --yes pip setuptools wheel \ + && rm -rf /usr/local/lib/python3.14/ensurepip \ && useradd --create-home --uid 10001 appuser WORKDIR /app diff --git a/ml/experiments/prompt_eval.py b/ml/experiments/prompt_eval.py deleted file mode 100644 index 3e0402c..0000000 --- a/ml/experiments/prompt_eval.py +++ /dev/null @@ -1,12 +0,0 @@ -import time -from app.core.llm_client import LLMClient -from ml.tracking.mlflow_utils import log_chat_metrics - -def run_experiment(prompt: str): - llm = LLMClient(api_key="DUMMY") - start = time.time() - output = llm.generate(prompt) - latency = (time.time() - start) * 1000 - - log_chat_metrics(latency, len(output.split()), "v1") - return output \ No newline at end of file diff --git a/ml/ml/experiments/prompt_eval.py b/ml/ml/experiments/prompt_eval.py deleted file mode 100644 index 2fccc04..0000000 --- a/ml/ml/experiments/prompt_eval.py +++ /dev/null @@ -1,19 +0,0 @@ -import time -from app.core.llm_client import LLMClient -from ml.tracking.mlflow_utils import start_run, log_metrics, log_params -from ml.metrics import token_count - -def run_prompt_experiment(prompt: str, api_key: str): - llm = LLMClient(api_key) - with start_run("prompt-eval-v1"): - start = time.time() - output = llm.generate(prompt) - latency = (time.time() - start) * 1000 - - log_params({ - "model": "gpt-4.1", - "prompt_version": "v1" - }) - log_metrics(latency, token_count(output)) - - return output \ No newline at end of file diff --git a/ml/tracking/mlflow_utils.py b/ml/tracking/mlflow_utils.py deleted file mode 100644 index 0a41b15..0000000 --- a/ml/tracking/mlflow_utils.py +++ /dev/null @@ -1,13 +0,0 @@ -import mlflow - -def start_run(run_name: str): - mlflow.set_experiment("trojanchat-llm") - return mlflow.start_run(run_name=run_name) - -def log_metrics(latency_ms: float, tokens: int): - mlflow.log_metric("latency_ms", latency_ms) - mlflow.log_metric("tokens_used", tokens) - -def log_params(params: dict): - for key, value in params.items(): - mlflow.log_param(key, value) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8faf598..2d8783a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,6 @@ openai>=1.68.0 groq>=1.1.2 streamlit>=1.44.0 -mlflow>=2.22.0 pydantic>=2.10.0 pydantic-settings>=2.8.0 python-dotenv>=1.1.0 @@ -14,3 +13,8 @@ prometheus-client>=0.21.0 PyJWT>=2.12.0 passlib[bcrypt]>=1.7.4 python-json-logger>=2.0.7 + +# Security floors for transitive packages identified by the container scan. +cryptography>=50.0.0 +msgpack>=1.2.1 +setuptools>=78.1.1