feat/tb-deploy
needs attentionviewing older commite81a781 · incrementalPR #261reviewed 2026-07-08 21:31 UTC0H · 4M · 4L · 1I- Purpose
- Wire Batu's Tinybird deployment strategy: three long-lived workspaces (dev/stg/prod) with hard isolation, ephemeral Forward branches per PR, and per-environment token split
- Goal
- Automate what was done by hand: provision batu_stg + batu_prod, create least-privilege tokens, add schema-CD lanes, and seed all environments from per-env secrets
- Sub-goals
- SG-1: Strategy rule doc + README de-stale + scoped-runtime-vs-deploy-token split
- SG-2: Per-env metrics-SSM seed (preview/staging/prod)
- SG-3: Vercel per-env tokens
- SG-4: Ephemeral per-PR Tinybird branch + cleanup
- SG-5: Schema-CD — tinybird-staging / tinybird-prod jobs
- SG-6: Fold per-env tokens + schema-CD into infrastructure.md / migration-pipeline.md
- What
- Added pinned composite action (.github/actions/tb-install) replacing curl|sh CLI installs across all 5 TB workflow jobs; added least-privilege permissions to tinybird-check, tinybird-staging, tinybird-prod, and deprovision jobs; wired tinybird-prod to run after cdk-deploy (expand/contract ordering); added tinybird-prod to rollback dependency graph; clarified SSM path convention in rule doc and branch cap in README.
- Why
- Eliminate the curl|sh supply-chain risk and add GITHUB_TOKEN least-privilege hardening as a follow-up to reviewer feedback on PR #261.
- Areas
- .github/actions+24−0.github/workflows+469−49.claude/rules+280−2infra/tinybird+111−57
- Blast
- 15 files total branch-wide (+929/-109); this increment: 8 files (+175/-51), all CI/infra and docs — zero application code changed
Findings · 9
security2
PyPI package pinned by version only — no content hash
.github/actions/tb-install/action.yml:23
uv tool install 'tinybird==4.6.9' pins by version string but not by artifact hash. A tampered or yanked-then-republished PyPI wheel at this version could execute arbitrary code in jobs that hold TINYBIRD_DEPLOY_TOKEN_PROD and similar secrets. The astral-sh/setup-uv action is correctly pinned to a commit SHA, making this asymmetry notable. Fix: generate a hash pin via uv pip compile --generate-hashes and pass --hash sha256:<digest> to the install command.
Tinybird deploy failure now triggers full PITR DB rollback
.github/workflows/release-promote.yml:860
needs.tinybird-prod.result == 'failure' now triggers rollback including PITR DB restore. Tinybird schema changes are expand-only per the deployment rule doc, so a Tinybird deploy failure does not require DB rollback. A transient Tinybird API or network error could induce an unnecessary prod DB PITR restore of ~1-5 minutes. Consider separating Tinybird failure handling from the DB PITR trigger, or documenting this as an accepted trade-off.
conventions1
tinybird-prod in rollback needs — no corresponding Tinybird rollback step
.github/workflows/release-promote.yml:856
The rollback job now lists tinybird-prod in its needs and fires when needs.tinybird-prod.result == 'failure'. However, the rollback job contains no tb command to revert a Tinybird schema deployment. It only handles CDK CloudFormation rollback, Vercel re-promotion, and DB PITR. This asymmetry misleads operators during an incident. Convention (matching db-backup): add an explicit comment noting that Tinybird schema rollback is intentionally unhandled here and describe the manual recovery path.
tests3
Silent continue-on-error CLI install degradation is not surfaced
.github/workflows/preview-provision.yml:297
continue-on-error: true on the tb-install step in preview-provision and preview-deprovision means a broken uv install shows a green step while subsequent code falls through and exits 0 with a warning. The job appears fully green while the preview silently runs against the shared dev workspace. Add a job summary notice or a step output flag to make the degradation observable in the PR UI.
No smoke-test workflow for the composite action
.github/actions/tb-install/action.yml
There is no workflow that directly exercises .github/actions/tb-install in isolation. Install failures only surface as buried failures inside provision/deprovision/staging runs rather than as fast, targeted signals. A PR-gated self-test (uses: ./.github/actions/tb-install then asserts tb --version) would prove the mechanism works as described.
No tb --version verification step in composite action
.github/actions/tb-install/action.yml
The action appends $HOME/.local/bin to GITHUB_PATH but does not run tb --version as a verification step. If uv places the binary at an unexpected location, the action exits 0 while tb is missing from PATH in subsequent steps.
improvement3
Branch slugification duplicated across provision and deprovision
.github/workflows/preview-deprovision.yml
The TB_SLUG derivation and BR convention appear identically in both preview-provision.yml and preview-deprovision.yml. If the two implementations drift, deprovision deletes the wrong branch and the 4-branch cap leaks. Extract to a shared composite action output, or store the computed branch name at provision time and read it back at deprovision time.
--force in uv tool install prevents cache reuse
.github/actions/tb-install/action.yml:23
--force causes uv to reinstall the tinybird tool even if the exact version is already present. If astral-sh/setup-uv's cache key ever covers the tool install directory, --force would negate it. Removing --force makes the install idempotent by default.
skip_cdk + tinybird ordering bypass undocumented
.github/workflows/release-promote.yml
tinybird-prod needs cdk-deploy enforces expand/contract ordering. However, if an operator passes skip_cdk: true but not skip_tinybird: true, GitHub Actions treats the skipped cdk-deploy as a satisfied dependency and tinybird-prod runs without the CDK gate. Documenting this in the dispatch input descriptions prevents a mis-invocation from violating the ordering invariant.
History · 10 commits
- 5d30429safeincremental0H · 0M · 1L2026-07-08 23:04
- 19bac85needs attentionincremental0H · 5M · 6L2026-07-08 22:46
- 92e890aneeds attentionincremental0H · 1M · 3L2026-07-08 21:46
- e81a781needs attentionincremental0H · 4M · 4L2026-07-08 21:31current
- 2eca91cneeds attentionfull5H · 13M · 12L2026-07-08 19:18
- cf63bb1needs attentionincremental4H · 4M · 7L2026-07-07 19:47
- f43d034needs attentionincremental2H · 3M · 3L2026-07-07 18:35
- b7800c0needs attentionincremental1H · 2M · 7L2026-07-07 03:31
- 5aef105needs attentionfull6H · 9M · 2L2026-07-06 17:52
- 95b4484blockedfull3H · 8M · 4L2026-07-06 05:36