name: ENGIN CI on: push: branches: - main - prod-hardening pull_request: branches: - main jobs: production-check: name: Build, test and smoke runs-on: engin-ci timeout-minutes: 20 steps: - name: Checkout repository uses: actions/checkout@v4 - name: Clean previous CI resources run: | docker rm -f engin-ci-app 2>/dev/null || true docker image rm -f engin-console:ci 2>/dev/null || true docker image rm -f engin-console:test 2>/dev/null || true - name: Build test image run: docker build --target test --tag engin-console:test . - name: Run Ruff run: | docker run --rm \ --entrypoint sh \ engin-console:test \ -c "python -m pip install --quiet \ --disable-pip-version-check \ --root-user-action=ignore \ ruff==0.16.4 && ruff check --no-cache \ app.py engin tests final_pipeline.py ml_polish_benchmark.py scripts" - name: Check installed dependencies run: | docker run --rm \ --entrypoint python \ engin-console:test \ -m pip check - name: Run test suite run: | docker run --rm \ --entrypoint python \ engin-console:test \ -m unittest discover -v - name: Verify frozen model artifact run: | docker run --rm \ --entrypoint python \ engin-console:test \ -m scripts.build_model_artifact --verify-only - name: Validate Python syntax run: | docker run --rm \ --entrypoint python \ engin-console:test \ -m compileall -q app.py engin tests final_pipeline.py scripts - name: Build production image run: docker build --target runtime --tag engin-console:ci . - name: Assert runtime excludes training assets run: | docker run --rm \ --entrypoint sh \ engin-console:ci \ -c "test ! -e val.csv && test ! -e train.csv && test ! -e final_pipeline.py && test ! -e severity_benchmark.py && test -s artifacts/engin-2026.08.25-1/model.pkl && test -s artifacts/engin-2026.08.25-1/manifest.json" - name: Start application run: | docker run -d \ --name engin-ci-app \ engin-console:ci - name: Verify Streamlit health run: | set -eu attempt=1 while [ "$attempt" -le 30 ]; do if docker exec engin-ci-app python -c \ "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8501/_stcore/health', timeout=3).read()"; then exit 0 fi sleep 2 attempt=$((attempt + 1)) done docker logs engin-ci-app exit 1 - name: Cleanup if: always() run: | docker logs engin-ci-app 2>/dev/null || true docker rm -f engin-ci-app 2>/dev/null || true docker image rm -f engin-console:ci 2>/dev/null || true docker image rm -f engin-console:test 2>/dev/null || true