GoogleCloudPlatform / GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK

Release bigquery-agent-analytics-tracing 0.2.0: publish the Claude/Codex OTel admin stack to PyPI

Open
#349 22 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
47
Forks
21
Avg merge
2d 13h
Merged PRs (30d)
33

Description

## Why

The #316 → #324 → #317 → #344 arc shipped a complete, live-proven enterprise telemetry stack — `bqaa-otel bootstrap/config/verify`, the OTLP receiver/consumer, the crosswalk, signal/privacy tiers, and the rehearsed hero demo. Today none of it is installable: `bigquery-agent-analytics-tracing` is at `0.1.0` in `producers/pyproject.toml` and has never been published to PyPI. A platform admin who wants this must clone the repo and set `PYTHONPATH`. Publishing is what turns the demo's one-command story into something another company can actually run.

## Current state (verified)

- Release pipeline **already exists**: `.github/workflows/release-tracing.yml` — push a `tracing-vX.Y.Z` tag → verify tag/version match → tests on 3.12 → wheel + sdist + Claude Code plugin tarball → GitHub release → TestPyPI → PyPI via Trusted Publishing (approval-gated `pypi` environment).
- One-time org-side step still missing: registering the trusted publisher on PyPI (instructions are in the workflow header comments).
- `bqaa-otel` console script and the `[receiver]` extra are already wired in `producers/pyproject.toml`.

## The blocker: pip-installed `bootstrap --execute` cannot work today

The Cloud Build step uploads the current directory and requires `deploy/otlp_receiver/Dockerfile` — there is an explicit repo-root guard in the CLI. `config` and `verify` work from a wheel; the flagship deploy command does not.

**Decided (per review): prebuilt receiver image is the release contract.**

- **Registry (pinned)**: a **public Google Artifact Registry repo**, reader access granted to `allUsers`. Rationale corrected per review ([Cloud Run supported registries](https://docs.cloud.google.com/run/docs/deploying)): Cloud Run *can* deploy from Docker Hub directly and from other registries (incl. ghcr.io) via AR remote repositories — but AR-native is the right default because it needs zero customer-side remote-repo setup, is Google's own availability recommendation, and public-AR cross-project pulls work with the `allUsers` reader grant alone.
- **Workflow auth (pinned)**: GitHub Actions → GCP via **Workload Identity Federation** (no long-lived keys) — a one-time org-side setup, listed alongside the PyPI trusted-publisher registration.
- **Tag vs digest (one exact contract, staging→promote)** — resolves the gate-before-public-URI contradiction flagged in review:
1. Image build → push to the **staging repo** with a candidate tag (`otlp-receiver:-candidate.` — staging tags never reuse the public release-tag namespace) → container self-test → **capture digest**.
2. Inject the FINAL public coordinate + digest into the source tree as a packaged constant — **wheel AND sdist** built from it (never patched into one artifact). **The image cannot and does not embed this constant** (a digest cannot appear inside the artifact it is computed from): the image is built in step 1 from the pre-injection tree and never rebuilds; the digest constant belongs exclusively to the Python packaging artifacts the admin installs — the receiver at runtime has no use for it.
3. **TestPyPI full-lifecycle gate** installs from TestPyPI and runs `bootstrap --image @sha256:` — the explicit `--image` override exists precisely so the gate can run before the public URI resolves. **Staging pull IAM (pinned)**: the gate deploys into the same project that hosts the private staging repo, so Cloud Run's service agent pulls it with no cross-project grant; if the gate ever moves to a separate project, the deploying project's Cloud Run service agent needs explicit `artifactregistry.reader` on the staging repo. Preflight → execute → verify → teardown, all green.
**`--image` is a first-class parameter through the whole pipeline, not a deploy-only flag**: preflight validates against the provided URI (and derives mode from it), the plan output names it, deploy uses it, the post-deploy digest assertion asserts against ITS digest, and the written inventory records the actually-deployed image.
4. On pass: **promote** — copy to the public coordinate with the clean `` tag (content-addressed, digest unchanged).
5. **Post-promotion smoke WITHOUT `--image`**: a second bootstrap using only the embedded public default — the only test that proves what customers actually resolve — then teardown.
6. **Hard digest-equality gate in the release job**: staging digest == public digest == packaged constant (wheel and sdist) == release-notes value, asserted mechanically; any mismatch fails the release.
7. Publish the draft GitHub Release → approve production PyPI.

**Version-burn rule**: TestPyPI and PyPI carry byte-identical artifacts at the same version. A candidate that fails the gate BURNS that version everywhere — the next candidate bumps the version (0.2.0 → 0.2.1) and rebuilds from step 1. No rc-suffix scheme: it would ship different bytes than it tested.

`bootstrap` deploys `…/otlp-receiver:@sha256:` — pinned **by digest**, tag for readability, `latest` never published.

`bootstrap` in default prebuilt-image mode has **zero Cloud Build / customer Artifact Registry footprint**: it does not enable `cloudbuild.googleapis.com` or `artifactregistry.googleapis.com`, creates no repo, and checks no build permissions — the customer project never builds or hosts the image. Source builds remain available from a repo checkout (`--build-from-source` path) for enterprises that require them. The wheel and image version together or the release does not ship.

## Distribution model (three tiers — two already done)

1. **Platform admins** (unlocked by this issue): `pipx install bigquery-agent-analytics-tracing==0.2.0` → `bqaa-otel bootstrap/config/verify/teardown`. The base wheel is the contract; `[receiver]` is for local receiver/consumer development only.
2. **End developers (50+ users)**: install nothing — they receive *generated artifacts* through admin channels (Claude managed settings via admin console/MDM; Codex `config.toml` via managed dotfiles). Already the documented model; no change.
3. **Evaluators**: repo checkout → `demo/hero_story/` (rehearsed, #344). Release notes should link it as the evaluation path.

## Release checklist

- [ ] Wire receiver-image build+push into `release-tracing.yml`: immutable version tag, digest recorded, sha256 checksums attached for all artifacts (TDD where logic is testable). **Image self-test gates digest capture**: run the built container and assert the packaged version matches the release tag (and the app factory imports) BEFORE the digest is captured and injected into the wheel
- [ ] `bootstrap` defaults `--image` to the pinned released image (repo checkout keeps the source-build path); post-deploy digest assertion
- [ ] Import-graph audit so the **base** wheel runs all `bqaa-otel` subcommands (config, bootstrap, verify, teardown) without `[receiver]` (verify's BigQuery import is already lazy; confirm decode/proto paths); document `pipx install bigquery-agent-analytics-tracing==0.2.0` as the default install, `[receiver]` for local receiver/consumer development only
- [ ] `bqaa-otel bootstrap --preflight`: productize the demo `preflight.sh` checks (gcloud/bq auth, billing, permission probe, org-policy/allUsers, dataset state) — **mode-aware**: default prebuilt-image mode does NOT check `cloudbuild.builds.create` or `artifactregistry.repositories.create` (the customer never builds); `--build-from-source` adds them back. **No Claude/Codex CLI requirement** — the platform admin deploying infra does not need product CLIs on their machine (that was a demo-session assumption); product-CLI checks are opt-in (`--check-products`) for admins who will also run validation sessions. The demo script caught real gaps three times; it belongs in the product
- [ ] `bqaa-otel teardown` subcommand — **in scope** (resolved per review: a "no repo checkout" release cannot point at demo scripts for cleanup). TDD port of the proven demo teardown logic: dry-run default, allowlist guard, existence-based verification incl. the DTS scheduled MERGE. **Inventory contract (pinned)**: `bootstrap --execute` writes `inventory.json` into the `--out` directory alongside the config artifacts, recording exactly what THIS bootstrap created; `teardown` accepts `--inventory ` and, absent one, reconstructs it by live query from `--project`/`--dataset` (resource names are deterministic package constants; the DTS config name is queried) — allowlist-guarded either way. **Mode-awareness falls out of the inventory**: default released-image mode creates no customer AR repo, so the inventory contains none and teardown neither expects nor deletes one (the demo teardown's repo deletion was a source-build assumption); live-query reconstruction probes the AR repo and includes it only if present
- [ ] Bump `producers/pyproject.toml` to `0.2.0`; changelog covering #316 (OTLP receiver → BigQuery), #324 (admin CLI + traces tier), #317 (verified Codex contracts, deterministic `source_product`), and the live-found fixes (#340, #342, #343)
- [ ] Security artifacts (kept honest to "if easy"): sha256 checksums (trivial), `pip-audit` + Artifact Registry scan results linked, SBOM via syft if it doesn't drag the pipeline; token-rotation + private-ingress guidance promoted from the demo OPERATOR.md hardening table into package docs
- [ ] **Decision needed BEFORE PR 1 — public image coordinates (org owner)**: which GCP project hosts the public AR repo, and the exact path. Proposed convention: `us-docker.pkg.dev//bqaa/otlp-receiver:` (multi-region `us-docker.pkg.dev`, repo `bqaa`, image `otlp-receiver`). The coordinate is baked into the wheel default and the workflow — it must be final first
- [ ] One-time org-side setup (owner actions, parallel in spirit): PyPI Trusted Publishing registration for `bigquery-agent-analytics-tracing` (environments `testpypi` / `pypi` per the workflow comments) + Workload Identity Federation for the image push + the public AR repo with `allUsers` reader, created with **immutable tags ENFORCED** (the AR repository setting — enforced, not promised) + a private **staging repo** for pre-gate candidates + **abuse/cost guardrails** on the publisher project: budget alert + Cloud Monitoring alert on AR egress (public reader access bills egress to the publisher)
- [ ] Docs flip: README/OPERATOR/deploy docs present pipx/pip install as the primary path, repo checkout as the source-build path
- [ ] Customer-first release notes are **generated from a template in the repo** (not only GitHub auto-notes): install → preflight → bootstrap → config artifacts → verify → cleanup, with the image digest, sha256 checksums, hero demo linked as the evaluation path, verified product versions (Claude Code 2.1.203, Codex 0.142.5 minimum), and the monthly compatibility-smoke recommendation; auto-generated commit notes appended below
- [ ] Tag `tracing-v0.2.0` → pipeline runs; **TestPyPI gate is the full lifecycle, not a smoke-lite**: clean venv, NO repo checkout, install from TestPyPI → `bootstrap --preflight` → `bootstrap --execute` (released image, fresh dataset) → `verify --smoke` → `bqaa-otel teardown` with existence verification — ALL green BEFORE approving the `pypi` environment
- [ ] **Release ordering**: candidate images live only in the staging repo and the GitHub Release stays **draft** until the TestPyPI full-lifecycle gate passes; promotion to the public AR coordinate, release publication, and PyPI approval all happen after the gate — nothing customer-visible (image included) exists for a build that never survived the full lifecycle
- [ ] **Rollback rule (matches PyPI patch policy)**: images are immutable — never deleted or retagged. A bad release gets a patch release (new tag + digest); the bad PyPI version is yanked with a pointer to the patch, and the patch release notes name the superseded image digest
- [ ] **Post-release smoke (same evidence discipline as the rest of the arc)**: clean venv, NO repo checkout, `pip install` from PyPI, `bootstrap --preflight` then `bootstrap --execute` from an **empty directory** on a fresh dataset, deployed image digest asserted against the release notes, `verify --smoke` green, then the documented teardown — evidence posted on this issue
- [ ] Fresh-project pull proof: unauthenticated manifest pull of the public image + a deploy using only the public image path (single test project available — a true second-project deploy is the ideal and is noted as such)

## Acceptance criteria

- `pipx install bigquery-agent-analytics-tracing==0.2.0` on a clean machine (no repo checkout) yields a working `bqaa-otel` for **all subcommands — config, bootstrap (incl. --preflight), verify, teardown** — including a real deploy from an empty directory using the released public image
- Wheel, sdist, plugin tarball, and container image all carry the same version; **wheel and sdist both embed the identical public coordinate + digest** (source-level constant, verified equal in the release job); image referenced by immutable tag (enforced at the repo level) with digest in the release notes; sha256 checksums attached
- `bqaa-otel teardown` (not demo scripts) exercised as part of the smoke with existence-verified cleanup; post-release smoke evidence posted on this issue before closing
- **Post-promotion no-`--image` smoke passed**: bootstrap using only the embedded public default resolved, deployed, verified, and tore down — the embedded coordinate is proven, not assumed
- Preflight in default mode passes on a customer project that has NO Cloud Build or Artifact Registry permissions, and on a machine with NO Claude/Codex CLIs installed
- **Source-build fallback is exercised, not just promised**: one `bootstrap --build-from-source --execute` from a repo checkout deploys successfully (its preflight checks the build permissions; its inventory records the AR repo; its teardown removes it) — evidence posted alongside the default-mode smoke

Contributor guide

Open the contributing guide

Research direction

Start with .github/workflows/release-tracing.yml and producers/pyproject.toml, then trace the bqaa-otel bootstrap, preflight, verify, and teardown entry points and the demo teardown logic. The release is done only when the TestPyPI no-checkout lifecycle passes, image and package digests match, and the documented pipx installation path works.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, gcp, github-actions, python
Domain
ci-cd, cli, cloud, devops, documentation, release, testing-qa
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.