chore(deps): bump huggingface-hub from 0.34.3 to 1.28.0 in /ml/hardware-recommender #121
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| jobs: | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| cache-dependency-path: | | |
| frontend/package-lock.json | |
| app/package-lock.json | |
| mastervault-mcp-server/package-lock.json | |
| - name: Install frontend dependencies | |
| working-directory: frontend | |
| run: npm ci | |
| - name: Install app dependencies | |
| working-directory: app | |
| run: npm ci | |
| - name: Install mastervault-mcp-server dependencies | |
| working-directory: mastervault-mcp-server | |
| run: npm ci | |
| - name: Lint frontend | |
| working-directory: frontend | |
| run: npm run lint | |
| - name: Typecheck frontend | |
| working-directory: frontend | |
| run: npx tsc -b | |
| - name: Typecheck app | |
| working-directory: app | |
| run: npx tsc -p tsconfig.json --noEmit | |
| - name: Test frontend | |
| working-directory: frontend | |
| run: npm test | |
| - name: Test app | |
| working-directory: app | |
| run: npm test | |
| - name: Build frontend | |
| working-directory: frontend | |
| run: npm run build | |
| - name: Build app | |
| working-directory: app | |
| run: npm run build | |
| - name: Test mastervault-mcp-server | |
| working-directory: mastervault-mcp-server | |
| run: npm test | |
| - name: Build bundled mastervault-mcp-server (the copy ModelForge packages) | |
| working-directory: mastervault-mcp-server | |
| run: npm run build:bundled | |
| - name: Smoke-test the bundled mastervault-mcp-server over stdio | |
| working-directory: mastervault-mcp-server | |
| run: | | |
| set -euo pipefail | |
| mkdir -p /tmp/mastervault-ci-vault | |
| echo '# CI test vault' > /tmp/mastervault-ci-vault/_orientation.md | |
| printf '%s\n%s\n' \ | |
| '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"ci","version":"1"}}}' \ | |
| '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \ | |
| | node dist-bundled/index.js /tmp/mastervault-ci-vault > worker-output.json | |
| cat worker-output.json | |
| test "$(grep -o 'mastervault_orient' worker-output.json | wc -l)" -ge 1 | |
| server: | |
| # server/ (the Fastify IAM/patient-case service) has its own package | |
| # boundary and DATABASE_URL/REDIS_URL-gated integration suites (see e.g. | |
| # store/postgres-case-store.test.ts's own disclosure comment) that | |
| # simply skip — not fail — when no real Postgres/Redis is reachable. | |
| # Real services are wired below so those suites actually run in CI | |
| # instead of only ever being exercised by a developer running them | |
| # locally; docs/ENTERPRISE_ARCHITECTURE_ROADMAP.md's P0 backlog item 18 | |
| # ("Run PostgreSQL and Redis suites in mandatory CI... No gated/skipped | |
| # enterprise suites") is exactly this gap. | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgres:16-alpine | |
| env: | |
| POSTGRES_USER: modelforge | |
| POSTGRES_PASSWORD: modelforge | |
| POSTGRES_DB: modelforge_test | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U modelforge" | |
| --health-interval 5s | |
| --health-timeout 3s | |
| --health-retries 10 | |
| redis: | |
| image: redis:7-alpine | |
| ports: | |
| - 6379:6379 | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 5s | |
| --health-timeout 3s | |
| --health-retries 10 | |
| env: | |
| # DATABASE_URL stays the migration-owner ("modelforge") role — every | |
| # postgres-*.test.ts file runs its own runMigrations() against | |
| # DATABASE_URL directly (see e.g. store/postgres-iam-store.test.ts), | |
| # which needs CREATE SCHEMA/CREATE FUNCTION/ALTER DEFAULT PRIVILEGES | |
| # rights a restricted runtime role deliberately doesn't have. | |
| # RUNTIME_DATABASE_URL is the separate, restricted role created below | |
| # — used by store/postgres-rls.test.ts to prove tenant isolation | |
| # (RLS on shared control-plane tables, pooled-connection tenant- | |
| # context cleanup) actually holds under a real NO BYPASSRLS, | |
| # non-owning role, not just under whatever role happened to run the | |
| # migrations. See migrations/010_runtime_role_grants.sql. | |
| DATABASE_URL: postgres://modelforge:modelforge@localhost:5432/modelforge_test | |
| RUNTIME_DATABASE_URL: postgres://modelforge_runtime:modelforge_runtime@localhost:5432/modelforge_test | |
| REDIS_URL: redis://localhost:6379 | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| - name: Install postgresql-client (for role setup below) | |
| run: sudo apt-get update -qq && sudo apt-get install -y -qq postgresql-client | |
| - name: Create restricted runtime database role | |
| # Created here (as the modelforge owner role, over the same | |
| # connection the app's migrations use) rather than via the | |
| # postgres:16-alpine service container's own init hooks, so the | |
| # exact privileges this role gets are visible in this workflow file | |
| # next to DATABASE_URL/RUNTIME_DATABASE_URL, not buried in image | |
| # config. NOSUPERUSER/NOBYPASSRLS is what makes | |
| # migrations/008_control_plane_rls.sql's tenant_isolation policies | |
| # actually apply to this role at all (a superuser or BYPASSRLS role | |
| # ignores row-level security entirely, which would make the RLS | |
| # penetration tests pass for the wrong reason). NOCREATEDB/ | |
| # NOCREATEROLE bounds what a compromised runtime process could do | |
| # beyond the schemas/tables migrations/010 explicitly grants it. | |
| run: | | |
| PGPASSWORD=modelforge psql -h localhost -U modelforge -d modelforge_test -v ON_ERROR_STOP=1 <<'SQL' | |
| DO $$ | |
| BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'modelforge_runtime') THEN | |
| CREATE ROLE modelforge_runtime WITH LOGIN PASSWORD 'modelforge_runtime' | |
| NOSUPERUSER NOCREATEDB NOCREATEROLE NOBYPASSRLS NOREPLICATION; | |
| END IF; | |
| END | |
| $$; | |
| GRANT CONNECT ON DATABASE modelforge_test TO modelforge_runtime; | |
| SQL | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| cache-dependency-path: server/package-lock.json | |
| - name: Install server dependencies | |
| working-directory: server | |
| run: npm ci | |
| - name: Typecheck server | |
| working-directory: server | |
| run: npm run typecheck | |
| - name: Test server (Postgres- and Redis-backed suites included, not skipped) | |
| working-directory: server | |
| run: npm test | |
| - name: Build server | |
| working-directory: server | |
| run: npm run build | |
| admin-console: | |
| # admin-console/ is a separate, standalone web app (its own trust | |
| # boundary per docs/ENTERPRISE_MULTIUSER_ARCHITECTURE.md §5, not the | |
| # Electron clinician app) for managing a ModelForge organization's IAM. | |
| # Its own job for the same reason server/e2e are separate: independent | |
| # dependency graph, no reason a flaky/slow run here should block them | |
| # or vice versa. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| cache-dependency-path: admin-console/package-lock.json | |
| - name: Install admin-console dependencies | |
| working-directory: admin-console | |
| run: npm ci | |
| - name: Typecheck admin-console | |
| working-directory: admin-console | |
| run: npx tsc -b | |
| - name: Lint admin-console | |
| working-directory: admin-console | |
| run: npm run lint | |
| - name: Test admin-console | |
| working-directory: admin-console | |
| run: npm test | |
| - name: Build admin-console | |
| working-directory: admin-console | |
| run: npm run build | |
| e2e: | |
| # Electron E2E tests spin up a real Electron process and a Vite preview | |
| # server per test, which is slower and flakier than the unit-test job | |
| # above — kept as its own job so a flaky e2e run never blocks/hides a | |
| # unit-test failure, and so it can be retried or skipped independently. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| cache-dependency-path: | | |
| frontend/package-lock.json | |
| app/package-lock.json | |
| e2e/package-lock.json | |
| - name: Install frontend dependencies | |
| working-directory: frontend | |
| run: npm ci | |
| - name: Install app dependencies | |
| working-directory: app | |
| run: npm ci | |
| - name: Install e2e dependencies | |
| working-directory: e2e | |
| run: npm ci | |
| - name: Install Playwright browsers | |
| working-directory: e2e | |
| run: npx playwright install --with-deps chromium | |
| - name: Build frontend | |
| working-directory: frontend | |
| run: npm run build | |
| - name: Build app | |
| working-directory: app | |
| run: npm run build | |
| - name: Run e2e suite | |
| working-directory: e2e | |
| # Electron needs a real (or virtual) display even headless-ish, hence | |
| # xvfb — there's no way to launch a BrowserWindow without one on Linux. | |
| run: xvfb-run --auto-servernum npx playwright test | |
| - name: Upload Playwright report | |
| if: always() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: playwright-report | |
| path: e2e/playwright-report | |
| retention-days: 7 | |
| rust: | |
| # lib/ (modelforge-native) is the napi-rs addon backing GGUF downloads | |
| # and, more recently, the JSON datastore/audit-hashing primitives (see | |
| # docs/ARCHITECTURE.md). fmt/clippy/cargo test only prove the Rust side | |
| # is correct on whichever OS runs them — they say nothing about whether | |
| # the resulting `.node` binary actually loads under Node on that OS, | |
| # which is a materially different failure mode (wrong ABI, missing | |
| # platform target, packaging mismatch). Previously this job only ran on | |
| # ubuntu-latest, so nothing in CI ever built or loaded the addon on | |
| # Windows or macOS despite installers shipping for both — see | |
| # docs/RUST_MIGRATION_ASSESSMENT.md's platform-matrix section. The | |
| # matrix below and the "napi build + require() smoke test" step close | |
| # that gap. | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| runs-on: ${{ matrix.os }} | |
| defaults: | |
| run: | |
| working-directory: lib | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| - name: Install rustfmt and clippy | |
| run: rustup component add rustfmt clippy | |
| - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| lib/target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('lib/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cargo- | |
| # fmt/clippy only need to run once — Rust source and formatting are | |
| # identical across OSes, so repeating this on all three runners would | |
| # just burn CI minutes for the same answer three times. | |
| - name: Format check | |
| if: matrix.os == 'ubuntu-latest' | |
| run: cargo fmt --check | |
| - name: Clippy | |
| if: matrix.os == 'ubuntu-latest' | |
| run: cargo clippy --all-targets -- -D warnings | |
| - name: Build | |
| run: cargo build --release | |
| - name: Test | |
| run: cargo test | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| cache-dependency-path: lib/package-lock.json | |
| - name: Install napi CLI | |
| run: npm ci | |
| - name: napi build (produces the real platform-specific .node binary) | |
| run: npm run build:debug | |
| # The actual gap this job exists to close: proves Node on *this* OS | |
| # can load the binary napi build just produced, not just that Cargo | |
| # compiled it. A wrong target triple, an ABI mismatch, or a packaging | |
| # error would fail cargo build's cross-compile silently-succeed case | |
| # but fail right here. | |
| - name: Load the built addon under Node and verify its exports | |
| shell: bash | |
| run: | | |
| node -e " | |
| const addon = require('../app/native'); | |
| const expected = ['downloadGgufFile', 'DownloadManager', 'readJsonFileNative', 'writeJsonFileAtomicNative', 'sha256HexNative', 'appendJsonArrayElementNative']; | |
| const missing = expected.filter((name) => !(name in addon)); | |
| if (missing.length > 0) { | |
| console.error('Native addon loaded but is missing expected exports:', missing); | |
| process.exit(1); | |
| } | |
| console.log('Native addon loaded successfully on ${{ matrix.os }} with all expected exports.'); | |
| " | |
| sbom: | |
| # Generates a CycloneDX SBOM per npm workspace so every release has an | |
| # auditable, machine-readable dependency manifest — required groundwork | |
| # for the supply-chain/provenance controls flagged in | |
| # docs/ENTERPRISE_READINESS_ASSESSMENT.md, and useful on its own for | |
| # answering "are we affected by CVE-X" without re-deriving the dependency | |
| # tree by hand. Runs independently of the test job so a flaky SBOM | |
| # generation never blocks the build/test signal. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| cache-dependency-path: | | |
| frontend/package-lock.json | |
| app/package-lock.json | |
| mastervault-mcp-server/package-lock.json | |
| - name: Install frontend dependencies | |
| working-directory: frontend | |
| run: npm ci | |
| - name: Install app dependencies | |
| working-directory: app | |
| run: npm ci | |
| - name: Install mastervault-mcp-server dependencies | |
| working-directory: mastervault-mcp-server | |
| run: npm ci | |
| - name: Generate SBOM (frontend) | |
| working-directory: frontend | |
| run: npx --yes @cyclonedx/cyclonedx-npm --output-file ../sbom-frontend.cdx.json | |
| - name: Generate SBOM (app) | |
| working-directory: app | |
| run: npx --yes @cyclonedx/cyclonedx-npm --output-file ../sbom-app.cdx.json | |
| - name: Generate SBOM (mastervault-mcp-server) | |
| working-directory: mastervault-mcp-server | |
| run: npx --yes @cyclonedx/cyclonedx-npm --output-file ../sbom-mastervault-mcp-server.cdx.json | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: sbom | |
| path: sbom-*.cdx.json | |
| retention-days: 90 | |
| security: | |
| # SAST + secret scanning — docs/ENTERPRISE_ARCHITECTURE_ROADMAP.md P1 | |
| # item 9 ("Add artifact signing, provenance, SAST, and secret-scanning | |
| # gates"), minus the signing/provenance half: that needs real | |
| # certificates/key-custody/HSM infrastructure this repository does not | |
| # build (a standing instruction — see that item's own note in the | |
| # roadmap's §14 P1 list). SAST and secret-scanning need neither, so | |
| # they're not blocked on it. Its own job, independent of test/build, so | |
| # a finding here is a distinct, unambiguous signal rather than mixed | |
| # into an unrelated build failure. | |
| # | |
| # Both tools were run locally against this exact repository (working | |
| # tree + full commit history) before this job was added, specifically | |
| # to avoid shipping an untested gate that immediately red-lines CI on | |
| # day one: gitleaks found zero leaks across 121 commits; Semgrep (see | |
| # config below) found zero real findings after fixing what it caught | |
| # (an unpinned-Actions supply-chain gap across every workflow file, two | |
| # `github`-context shell-injection spots in release.yml, a missing | |
| # explicit AES-GCM auth-tag length in app/src/case-encryption.ts, and a | |
| # missing Dependabot cooldown period) — see docs/OBSERVABILITY.md's | |
| # sibling P1 item 8 work for the same "verify locally before gating" | |
| # approach applied to the metrics endpoint. The one excluded rule below | |
| # is a genuine false-positive class for this codebase, not a suppressed | |
| # real finding — see its own comment. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| with: | |
| fetch-depth: 0 # gitleaks scans commit history, not just the working tree | |
| - name: Install gitleaks | |
| run: | | |
| set -euo pipefail | |
| GITLEAKS_VERSION=8.21.2 | |
| curl -sSL -o /tmp/gitleaks.tar.gz "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | |
| tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks | |
| sudo mv /tmp/gitleaks /usr/local/bin/gitleaks | |
| gitleaks version | |
| - name: Secret scan (gitleaks — full commit history) | |
| run: gitleaks detect --source . --redact -v | |
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | |
| with: | |
| python-version: "3.12" | |
| - name: Install Semgrep | |
| run: python -m pip install --upgrade semgrep | |
| - name: SAST scan (Semgrep — OWASP/JS/TS community rulesets, no account required) | |
| run: | | |
| semgrep scan \ | |
| --config p/ci \ | |
| --config p/owasp-top-ten \ | |
| --config p/javascript \ | |
| --config p/typescript \ | |
| --exclude-rule javascript.express.security.audit.xss.direct-response-write.direct-response-write \ | |
| --error \ | |
| --metrics=off | |
| # javascript.express.security.audit.xss.direct-response-write assumes | |
| # an Express-style app rendering HTML from `res.send()`. Every route | |
| # in server/ is a Fastify JSON API — `reply.send(jsonValue)` goes | |
| # through Fastify's own JSON serializer, never raw HTML, so there is | |
| # no XSS surface for this rule to be finding here. Confirmed by | |
| # manual review of every one of the 39 matches this rule produced | |
| # locally before adding this exclusion (see this job's own top | |
| # comment) — not a blanket "trust the tool less" suppression. | |
| python-recommender: | |
| # ml/hardware-recommender/ is a standalone project (its own venv, own | |
| # train/download-dataset scripts) that isn't part of the app's build — | |
| # only its exported ONNX model ships with the app | |
| # (app/python/artifacts/hardware_recommender.onnx), loaded at runtime by | |
| # app/python/recommender_worker.py. This job is deliberately scoped to | |
| # what release publishing actually depends on: the recommender package's | |
| # own unit tests (data/feature encoding logic, no dataset or GPU needed) | |
| # and a smoke test that the packaged worker script can actually load the | |
| # shipped artifact and answer a request — never train.py or | |
| # download_dataset.py, which need a real (large) dataset pull. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 | |
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 | |
| with: | |
| python-version: "3.12" | |
| cache: pip | |
| cache-dependency-path: ml/hardware-recommender/requirements.txt | |
| - name: Install dependencies (CPU-only torch for ML tests) | |
| working-directory: ml/hardware-recommender | |
| # torch's CPU wheels live on a separate index from the rest of | |
| # PyPI. Install it separately to keep the training/test stack CPU-only | |
| # and avoid a multi-gigabyte CUDA wheel download on a GPU-less runner; | |
| # the packaged app uses ONNX Runtime for inference and does not ship | |
| # torch in its managed runtime. | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install --only-binary=:all: --index-url https://download.pytorch.org/whl/cpu torch==2.13.0 | |
| # pip parses comments and blank lines correctly. Passing the file | |
| # through shell command substitution turned the first comment into | |
| # a literal `#` requirement and failed the job. | |
| python -m pip install --only-binary=:all: -r requirements.txt | |
| - name: Run hardware-recommender unit tests | |
| working-directory: ml/hardware-recommender | |
| run: python -m pytest tests/ -q | |
| - name: Verify the packaged model artifacts exist | |
| run: | | |
| test -f app/python/artifacts/hardware_recommender.onnx | |
| test -f app/python/artifacts/hardware_recommender.onnx.sha256 | |
| test -f app/python/artifacts/hardware_recommender.meta.json | |
| - name: Smoke-test the packaged recommender worker against the shipped artifact | |
| working-directory: app/python | |
| run: | | |
| printf '%s\n%s\n' \ | |
| '{"protocol":1,"id":"1","method":"health","params":{}}' \ | |
| '{"protocol":1,"id":"2","method":"recommend","params":{"model_params_b":7,"ram_gb":16,"vram_gb":8,"cpu_cores":8,"platform":"linux","gpu_backend":"cuda"}}' \ | |
| | python recommender_worker.py > worker-output.json | |
| cat worker-output.json | |
| test "$(grep -o '"ok": *true' worker-output.json | wc -l)" -eq 2 |