Merge CR round-1 findings (#45) #62
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: | |
| branches: [main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| # Cancel superseded runs on the same PR; never cancel runs on main (keep | |
| # CI signal for every commit that lands on the protected branch). | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| lint: | |
| name: lint | |
| runs-on: ubuntu-latest | |
| # WIF: mint an OIDC token for google-github-actions/auth to impersonate the | |
| # read-only co-pypi-reader SA and pull the cannobserv wheelhouse. | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v5 | |
| with: | |
| enable-cache: true | |
| - name: Install Python | |
| run: uv python install 3.12 | |
| # co-core / co-core-aio resolve from a wheelhouse mirrored from the | |
| # private GCS index. Authenticate keyless via Workload Identity Federation | |
| # — the read-scoped provider impersonating the objectViewer-only | |
| # co-pypi-reader SA — then sync before `uv sync`. | |
| # Fail fast and legibly when the org variable is not visible to this repo. | |
| # google-github-actions/auth validates its own inputs before contacting | |
| # Google, so an empty provider surfaces as "must specify exactly one of | |
| # workload_identity_provider or credentials_json" — which reads like a | |
| # workflow-authoring bug and sends you looking at GCP IAM, where the | |
| # problem is not. Assert the precondition here instead. | |
| - name: Assert wheelhouse auth is configured | |
| env: | |
| WIF_PROVIDER: ${{ vars.GCP_WIF_PROVIDER }} | |
| run: | | |
| if [ -z "$WIF_PROVIDER" ]; then | |
| echo "::error::vars.GCP_WIF_PROVIDER is empty for this repo. GCP is not the problem — the org variable is not visible here. Fix under Org Settings > Secrets and variables > Actions > Variables > GCP_WIF_PROVIDER > Repository access." | |
| exit 1 | |
| fi | |
| echo "WIF provider: $WIF_PROVIDER" | |
| - name: Authenticate to Google Cloud (WIF, read-only) | |
| uses: google-github-actions/auth@v2 | |
| with: | |
| workload_identity_provider: ${{ vars.GCP_WIF_PROVIDER }} | |
| service_account: co-pypi-reader@co-gcs.iam.gserviceaccount.com | |
| - name: Sync cannobserv wheelhouse | |
| run: uv run --no-project --with 'google-cloud-storage>=2,<4' python scripts/sync_wheelhouse.py | |
| - name: uv sync | |
| run: uv sync --frozen --group dev | |
| - name: ruff check | |
| run: uv run ruff check . | |
| - name: ruff format --check | |
| run: uv run ruff format --check . | |
| test: | |
| name: test | |
| runs-on: ubuntu-latest | |
| # WIF: mint an OIDC token for google-github-actions/auth (see the lint job). | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| # `submodules` is load-bearing for tests/test_skills_hook.py, which | |
| # dereferences the .claude/hooks/ symlink into skills-vendor/ — an | |
| # unpopulated submodule makes that link dangle and the test cannot pass. | |
| # Both submodules are public HTTPS in .gitmodules, so no token is needed. | |
| # The coupling this buys: an upstream force-push that GCs a pinned SHA | |
| # fails the job *at checkout*, which looks nothing like a test failure. | |
| # The lint job deliberately omits this — ruff extend-excludes | |
| # skills-vendor/ (pyproject.toml), so it never reads what it does not | |
| # fetch. Costs ~2.2s of a ~1m10s job. See docs/SKILLS.md. | |
| - uses: actions/checkout@v5 | |
| with: | |
| submodules: true | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v5 | |
| with: | |
| enable-cache: true | |
| - name: Install Python | |
| run: uv python install 3.12 | |
| # Fail fast and legibly when the org variable is not visible to this repo. | |
| # google-github-actions/auth validates its own inputs before contacting | |
| # Google, so an empty provider surfaces as "must specify exactly one of | |
| # workload_identity_provider or credentials_json" — which reads like a | |
| # workflow-authoring bug and sends you looking at GCP IAM, where the | |
| # problem is not. Assert the precondition here instead. | |
| - name: Assert wheelhouse auth is configured | |
| env: | |
| WIF_PROVIDER: ${{ vars.GCP_WIF_PROVIDER }} | |
| run: | | |
| if [ -z "$WIF_PROVIDER" ]; then | |
| echo "::error::vars.GCP_WIF_PROVIDER is empty for this repo. GCP is not the problem — the org variable is not visible here. Fix under Org Settings > Secrets and variables > Actions > Variables > GCP_WIF_PROVIDER > Repository access." | |
| exit 1 | |
| fi | |
| echo "WIF provider: $WIF_PROVIDER" | |
| - name: Authenticate to Google Cloud (WIF, read-only) | |
| uses: google-github-actions/auth@v2 | |
| with: | |
| workload_identity_provider: ${{ vars.GCP_WIF_PROVIDER }} | |
| service_account: co-pypi-reader@co-gcs.iam.gserviceaccount.com | |
| - name: Sync cannobserv wheelhouse | |
| run: uv run --no-project --with 'google-cloud-storage>=2,<4' python scripts/sync_wheelhouse.py | |
| - name: uv sync | |
| run: uv sync --frozen --group dev | |
| # Validates the wheelhouse end to end: the extras the MVP loop depends on | |
| # ([extract] for fingerprinting, [bus] for the Redis Streams driver) must | |
| # import, not merely resolve. | |
| - name: co-core import smoke (extras wired) | |
| run: | | |
| uv run python -c " | |
| from co_core.pure.util.hashing import sha256 | |
| from co_core.pure.extract import simhash | |
| from co_core.pure.adapters.bus import streams | |
| from co_core.pure.models.changes import BlobAvailableEvent, ContentFetchCommand | |
| from co_core_aio.bus import AsyncBusConsumer, AsyncBusPublisher | |
| from co_core_aio.fetch import AsyncFetchDriver | |
| assert streams.CONTENT_FETCH == 'content.fetch' | |
| assert streams.CONTENT_BLOBS == 'content.blobs' | |
| print('co-core extras OK') | |
| " | |
| # No Postgres service and no alembic steps: Replicator is DB-free. Its | |
| # durable state is the Redis consumer group's PEL plus content-addressed | |
| # blobs on disk. Unit tests use fakeredis; anything needing a real broker | |
| # is marked @pytest.mark.integration and excluded by default. | |
| - name: pytest (default, excludes integration) | |
| run: uv run pytest |