diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 0d1aed0..19e6ece 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -44,6 +44,8 @@ jobs: elif [ -f requirements.txt ]; then pip install -r requirements.txt fi + # Install the package itself so `import astroml` resolves in tests. + pip install -e . --no-deps - name: Run pytest (CPU) if: matrix.flavor == 'cpu' diff --git a/Dockerfile b/Dockerfile index 042f4a0..f94cc75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,10 @@ # ============================================================================ # BASE STAGE - Common dependencies and Python environment # ============================================================================ -FROM python:3.11-slim as base +# Pin the Python base image to an exact patch + distro (#196) so a rebuild +# six months from now produces the same intermediate layers. The slim +# bookworm tag is roughly 60% smaller than the default `python:3.11` image. +FROM python:3.11.9-slim-bookworm AS base # Set environment variables ENV PYTHONUNBUFFERED=1 \ @@ -15,8 +18,10 @@ ENV PYTHONUNBUFFERED=1 \ ASTROML_ENV=container \ FEATURE_STORE_PATH=/app/feature_store -# Install system dependencies -RUN apt-get update && apt-get install -y \ +# Install system dependencies. `--no-install-recommends` skips the long tail +# of suggested packages (man-db, locales, etc.) that ship with apt's default +# recommend resolution and add ~80MB to the image (#196). +RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ curl \ git \ @@ -25,6 +30,7 @@ RUN apt-get update && apt-get install -y \ netcat-openbsd \ jq \ wget \ + && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Create app user @@ -41,12 +47,13 @@ RUN pip install --upgrade pip && \ # ============================================================================ # INGESTION STAGE - Optimized for data ingestion and streaming with Feature Store # ============================================================================ -FROM base as ingestion +FROM base AS ingestion -# Install additional dependencies for ingestion -RUN apt-get update && apt-get install -y \ +# Install additional dependencies for ingestion. +RUN apt-get update && apt-get install -y --no-install-recommends \ jq \ netcat-openbsd \ + && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Copy application code @@ -75,10 +82,10 @@ CMD ["python", "-m", "astroml.ingestion"] # ============================================================================ # TRAINING STAGE - Optimized for ML training with GPU support # ============================================================================ -FROM nvidia/cuda:12.1-runtime-base-ubuntu22.04 as training-base +FROM nvidia/cuda:12.1-runtime-base-ubuntu22.04 AS training-base -# Install Python and system dependencies -RUN apt-get update && apt-get install -y \ +# Install Python and system dependencies. +RUN apt-get update && apt-get install -y --no-install-recommends \ python3.11 \ python3.11-pip \ python3.11-dev \ @@ -86,6 +93,7 @@ RUN apt-get update && apt-get install -y \ curl \ git \ postgresql-client \ + && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Create symbolic links for python diff --git a/pyproject.toml b/pyproject.toml index d14dce3..d254e23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,10 @@ where = ["."] include = ["astroml*"] [tool.pytest.ini_options] +# Scope collection to the dedicated tests/ tree so root-level standalone +# scripts (e.g. test_data_quality_import.py — a manual smoke that calls +# sys.exit(1) on ImportError) don't poison pytest collection. +testpaths = ["tests"] # Custom markers used by the CI matrix (#186). markers = [ "gpu: requires a CUDA-capable runner; auto-skipped on CPU-only environments", diff --git a/requirements-cpu.txt b/requirements-cpu.txt index e82a706..7897933 100644 --- a/requirements-cpu.txt +++ b/requirements-cpu.txt @@ -1,8 +1,10 @@ # CPU-only requirements for faster installation -torch>=2.0.0+cpu --index-url https://download.pytorch.org/whl/cpu +--extra-index-url https://download.pytorch.org/whl/cpu +torch==2.0.0+cpu torch-geometric>=2.3.0 numpy>=1.24 +scikit-learn>=1.3.0 pandas>=2.0 polars>=1.0 sqlalchemy>=2.0 diff --git a/requirements.txt b/requirements.txt index 04c326a..47fdb02 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,6 +34,11 @@ aiohttp-sse-client>=0.2.1 stellar-sdk>=9.0.0 tenacity>=8.4.0 +# Transitive constraint: pin starlette >= 1.0.1 to address PYSEC-2026-161 +# (Host header path injection). mlflow / fastapi-style deps pull it in +# transitively; without this pin pip-audit flags the older resolver pick. +starlette>=1.0.1 + # ── Observability ────────────────────────────────────────────────────────── prometheus-client>=0.19.0 @@ -68,5 +73,4 @@ ipykernel>=6.26.0 pre-commit>=3.7.0 isort>=5.13.0 ruff>=0.4.0 -``` diff --git a/src/auth_tests.rs b/src/auth_tests.rs index 441a060..bc59c1f 100644 --- a/src/auth_tests.rs +++ b/src/auth_tests.rs @@ -413,15 +413,18 @@ mod auth_tests { #[test] fn test_validator_registration_timestamp_persists() { let env = Env::default(); + // Env::default() starts at ledger timestamp 0; set a non-zero value + // so the contract's stored registration_timestamp is also non-zero. + env.ledger().set_timestamp(1_000_000); let (client, admin) = setup_contract(&env); - + let validator = Address::generate(&env); - + client.register_validator(&admin, &validator, &75_u32); - + let validator_info = client.get_validator(&validator); let timestamp = validator_info.registration_timestamp; - + // Timestamp should be non-zero (set during registration) assert!(timestamp > 0, "Registration timestamp should be set"); }