Files
semantica/.github/workflows/ci.yml
T
Mohd Kaif d4cd44e7f1 fix(docker): split explorer-extra.txt by Python version, fix broken build (#1341)
* fix(docker): split explorer-extra.txt by Python version, fix broken build

main's container-scan.yml has been failing since PR #1338 merged:

  ERROR: In --require-hashes mode, all requirements must have their
  versions pinned with ==. These do not:
      standard-aifc from .../standard_aifc-3.13.0-py3-none-any.whl
      (from audioread==3.1.0->-r explorer-extra.txt (line 30))

Root cause: explorer-extra.txt was compiled with `--python-version 3.11`
but is installed on the Dockerfile's actual python:3.13-slim interpreter.
librosa's audioread dependency needs standard-aifc/standard-sunau only
under `python_version >= "3.13"` (Python 3.13 dropped aifc/sunau from
stdlib) - a file resolved for 3.11 has no hash for those packages at all,
so --require-hashes fails outright once pip resolves against the real
3.13 environment instead of silently under-pinning.

Splits the file in two: explorer-extra-py311.txt (ci.yml, unchanged
resolution) and explorer-extra-py313.txt (Dockerfile, newly compiled for
--python-version 3.13). They aren't interchangeable and shouldn't be
recombined - documented in .github/requirements/README.md, including how
to catch this class of bug before it ships again.

* fix(ci): correct stale -o path in explorer-extra-py311.txt header

Qodo review on this PR: the autogenerated header comment still said
-o .github/requirements/explorer-extra.txt (the pre-rename path), which
would silently regenerate the wrong file if someone copy-pasted it.
2026-08-31 17:52:23 +05:30

121 lines
5.3 KiB
YAML

name: CI
permissions:
contents: read
on:
push:
branches: [main]
paths-ignore:
- 'docs/**'
- 'docs_check.py'
- '**/*.md'
pull_request:
branches: [main]
paths-ignore:
- 'docs/**'
- 'docs_check.py'
- '**/*.md'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
with:
python-version: '3.11'
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: explorer/package-lock.json
- name: Install Explorer frontend dependencies
working-directory: explorer
run: npm ci
- name: Install Playwright Chromium
working-directory: explorer
run: npx playwright install --with-deps chromium
- name: Test Explorer frontend
working-directory: explorer
run: |
npm run test:graph-store
npm run test:graph-workspace
npm run test:plugin-registry
npm run test:deterministic-e2e
- name: Build Explorer frontend
working-directory: explorer
run: npm run build
- name: Install Explorer backend test dependencies
run: |
# Run the deterministic backend path before the all-extras CI
# environment is installed. The Explorer extra supplies the
# production API dependencies without importing optional vector
# providers such as Pinecone during test collection.
#
# --no-deps + a separate hash-pinned install (rather than the old
# `pip install -e ".[explorer]" pytest==9.1.1`) so every fetched
# package is hash-verified (Scorecard Pinned-Dependencies); the
# local editable install itself has nothing to hash.
# .github/requirements/explorer-extra-py311.txt is
# `uv pip compile pyproject.toml --extra explorer --python-version 3.11 --constraint requirements-ci.txt --generate-hashes`
# - regenerate it the same way if pyproject.toml's base/explorer
# deps change. Resolved specifically for this job's python 3.11
# (see the Dockerfile's explorer-extra-py313.txt for why this
# can't be shared with python 3.13: audioread needs extra
# standard-aifc/standard-sunau hashes only on 3.13+).
#
# --no-deps only skips *runtime* dependency resolution - `-e .`
# still does a PEP 517 build, which by default creates an isolated
# build env and fetches [build-system] requires (setuptools,
# wheel) completely outside any hash checking. Install
# pep517-build.txt (pins that exact build-system.requires) first
# and pass --no-build-isolation so pip reuses those hash-verified
# copies instead of fetching its own.
pip install -r .github/requirements/pep517-build.txt --require-hashes
pip install --no-deps --no-build-isolation -e .
pip install -r .github/requirements/explorer-extra-py311.txt --require-hashes
pip install -r .github/requirements/pytest-tool.txt --require-hashes
- name: Test deterministic Explorer backend path
run: |
pytest -q tests/explorer/test_explorer_deterministic_rendering_e2e.py
- name: Install pinned Python dependencies
run: |
pip install -r requirements-ci.txt --require-hashes
- name: Verify requirements-ci.txt is up to date
run: |
pip install -r .github/requirements/uv-tool.txt --require-hashes
# Re-resolve with the committed file as a constraint: upstream package
# releases must NOT fail CI (deps only change when pyproject.toml
# changes intentionally). Compare only version lines (pkg==ver),
# ignoring the -c constraint comments and the `\` line continuations
# that --generate-hashes emits.
uv pip compile pyproject.toml --python-version 3.11 --extra all \
--constraint requirements-ci.txt -o /tmp/requirements-ci-check.txt
diff \
<(grep -E '^[a-zA-Z0-9._-]+==' requirements-ci.txt | sed 's/ \\$//') \
<(grep -E '^[a-zA-Z0-9._-]+==' /tmp/requirements-ci-check.txt)
# build is a dev-time dependency; wheel is build-time only (neither is
# in requirements-ci.txt) — install the same pinned versions
# [build-system] declares so --no-isolation works below.
- run: pip install -r .github/requirements/build-tools.txt --require-hashes
- name: Build package (no isolation — pinned deps)
run: python -m build --no-isolation
- name: Verify Explorer frontend is packaged
run: |
python - <<'PY'
import zipfile
from pathlib import Path
wheels = list(Path("dist").glob("*.whl"))
assert wheels, "No wheel was built"
with zipfile.ZipFile(wheels[0]) as wheel:
names = set(wheel.namelist())
assert "semantica/static/index.html" in names, "Explorer index.html missing from wheel"
assert any(name.startswith("semantica/static/assets/") for name in names), "Explorer assets missing from wheel"
print("Explorer frontend is packaged")
PY