diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4f618f3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,66 @@ +name: CI + +on: + push: + branches: [main] + tags: ['v*.*.*'] + workflow_dispatch: + +jobs: + docker: + name: Build & Push Docker image + runs-on: ubuntu-latest + # Only publishes for a real version tag or an explicit manual run -- + # never for an ordinary push to main. Matches omnibioai-security-audit's + # own tag-gated convention; workflow_dispatch is additionally allowed + # here so this can be validated once before the first real tag push, + # the same way that repo's own pipeline was validated with -ci-test + # tags before trusting it for a real release. + if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v4 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=semver,pattern={{version}} + type=raw,value=latest + type=sha,prefix=sha-,format=short + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Build context is this repo alone (`.`) -- see the Dockerfile's own + # comment for why the previous parent-directory/sibling-COPY + # requirement no longer applies. IAM_CLIENT_READ_TOKEN must be a + # fine-grained PAT scoped to Contents:Read on omnibioai-iam-client + # only; it is NOT created or assumed present by this workflow. If + # the secret is missing, this step fails at the private-dependency + # install inside the Dockerfile's RUN --mount=type=secret layer -- + # a configuration gap to fix by adding the repo secret, not by + # working around it here. + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + secrets: | + github_token=${{ secrets.IAM_CLIENT_READ_TOKEN }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile index 03b245b..72f08c9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,28 +1,40 @@ +# syntax=docker/dockerfile:1 FROM python:3.11-slim RUN apt-get update \ - && apt-get install -y --no-install-recommends build-essential curl \ + && apt-get install -y --no-install-recommends build-essential curl git \ && rm -rf /var/lib/apt/lists/* WORKDIR /app -# Build context is the parent directory (/home/manish/Desktop/machine) -# so sibling repos are accessible during the build. - -# Install IAM client SDK from source, then discard the source tree. -# Re-added: removed as dead weight in a88f6ac when nothing imported it; -# app/services/iam_client.py now uses it for RS256/JWKS/HS256 token -# verification (IAM Foundation gateway integration). -COPY omnibioai-iam-client /tmp/omnibioai-iam-client -RUN pip install --no-cache-dir /tmp/omnibioai-iam-client \ - && rm -rf /tmp/omnibioai-iam-client - -# Install gateway Python dependencies. -COPY omnibioai-api-gateway/requirements.txt requirements.txt -RUN pip install --no-cache-dir -r requirements.txt - -# Copy the gateway service source. -COPY omnibioai-api-gateway . +# GHCR release follow-up: build context is now this repo alone (`.`), not +# the parent directory -- the previous COPY omnibioai-iam-client /tmp/... +# step required a sibling checkout, which no GitHub Actions workflow in +# this org has ever been able to do for a *private* sibling repo. Adopts +# the same pattern already proven in production by omnibioai-tes and +# omnibioai-rag instead: pyproject.toml declares omnibioai-iam-client as a +# pinned git+https dependency (private repo -- GitHub Packages has no +# PyPI-format registry), and `pip install .` re-resolves ALL declared +# deps including direct-URL ones (it does not trust a same-named package +# already being installed the way it does for plain version-range +# requirements), so the token must be available for pip's own git clone +# here, not just a separate pre-install step. +COPY pyproject.toml . +COPY app/ ./app/ + +# Uses a BuildKit secret mount (not ARG/ENV) -- ARG/ENV values get echoed +# into BuildKit's progress output for the RUN instruction that uses them, +# leaking the token into build logs. A secret mount is never printed and +# never persists in any image layer. hatchling is pre-installed explicitly +# (unlike omnibioai-tes/omnibioai-rag, both setuptools-backed) because this +# repo's own [build-system] uses hatchling.build -- confirmed necessary by +# an actual local build; see pyproject.toml's [tool.hatch.metadata] for the +# one other hatchling-specific allowance the pinned dependency below needs. +RUN --mount=type=secret,id=github_token \ + git config --global url."https://$(cat /run/secrets/github_token)@github.com/".insteadOf "https://github.com/" \ + && pip install --no-cache-dir hatchling \ + && pip install --no-cache-dir --upgrade-strategy only-if-needed . \ + && git config --global --unset url."https://$(cat /run/secrets/github_token)@github.com/".insteadOf EXPOSE 8080 diff --git a/pyproject.toml b/pyproject.toml index 0cf3a20..847809a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,18 @@ dependencies = [ "httpx", "redis[asyncio]", "pyjwt", + + # IAM Foundation gateway integration: app/services/iam_client.py uses + # AsyncIAMClient for RS256/JWKS/HS256 token verification. Pinned direct + # git reference -- omnibioai-iam-client is a private repo distributed + # via git+https, not a package index (GitHub Packages has no + # PyPI-format registry). Same pinned-tag distribution convention and + # version (latest, additive/backward-compatible UserContext fields) as + # omnibioai-tes/omnibioai-rag's own pyproject.toml entries for this + # same dependency -- see [tool.hatch.metadata] below for the one + # allowance this repo specifically needs that those two don't (they're + # both setuptools-backed, not hatchling). + "omnibioai-iam-client @ git+https://github.com/OmniBioAI/omnibioai-iam-client.git@v0.1.3", ] [project.optional-dependencies] @@ -25,6 +37,17 @@ dev = [ [tool.hatch.build.targets.wheel] packages = ["app"] +# Required for the pinned git+https omnibioai-iam-client dependency above: +# hatchling's own metadata validation otherwise rejects any PEP 508 "direct +# reference" (a `name @ ` dependency) with +# "Dependency ... cannot be a direct reference unless field +# tool.hatch.metadata.allow-direct-references is set to true" -- confirmed +# by an actual local `pip install .` build failing with exactly that error +# before this was added. Scoped to direct references only; does not +# otherwise relax dependency resolution. +[tool.hatch.metadata] +allow-direct-references = true + [tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"]