Skip to content

Comments

feat(workflows): teams reuse bootstrap and deploy workflows for independence#252

Merged
amaralc merged 10 commits intomainfrom
247-independence-of-action
Feb 15, 2026
Merged

feat(workflows): teams reuse bootstrap and deploy workflows for independence#252
amaralc merged 10 commits intomainfrom
247-independence-of-action

Conversation

@amaralc
Copy link
Owner

@amaralc amaralc commented Feb 14, 2026

What and why was modified?

  • Enable teams (people, things) to orchestrate their own infrastructure bootstrap and deployments
  • Reuse kernel team's workflow patterns via git symlinks and NX implicit dependencies
  • Reduce central coordination overhead; teams operate independently with shared patterns
  • Add workflow confirmation pattern to project insights for improved PR discipline

How was it modified?

  • Created teams/kernel/github-workflows/bootstrap-team.yml - reusable bootstrap workflow
  • Created teams/kernel/github-workflows/deploy-team.yml - reusable deploy workflow
  • Created teams/people/iac/bootstrap/package.json and teams/things/iac/bootstrap/package.json
  • Added .github/workflows/bootstrap-all.yml entry point for top-level orchestration
  • Updated .github/workflows/deploy.yml to use team-specific deployment workflows
  • Updated project insights with workflow confirmation pattern for uncommitted changes

Experiment Record

Field Details
Date and step Issue #247: Independence of action for team infrastructure provisioning
Expected result and how to measure Teams can bootstrap and deploy independently without kernel coordination; CI executes in parallel
Type of experiment
  • Testing hypothesis
What happened Symlink-based workflow composition enables teams to reuse patterns from kernel; NX implicit dependencies document ordering constraints
What did we learn Team-owned reusable workflows under teams/*/ with entry points in .github/ enable discoverability while maintaining shared patterns

Summary by CodeRabbit

  • Chores

    • Added reusable per-team CI workflows enabling selective team bootstrap and modular per-team deployments; reorganized main pipeline to invoke those per-team jobs and include guarded placeholders.
    • Added workspace package entries to wire team bootstrap projects into the Nx workspace.
  • Documentation

    • Updated long-term and short-term insights to document the new reusable workflows and Nx wiring.

@vercel
Copy link

vercel bot commented Feb 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
explore Ready Ready Preview, Comment Feb 15, 2026 2:11pm

@coderabbitai
Copy link

coderabbitai bot commented Feb 14, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds reusable per-team GitHub Actions for bootstrap and deploy, an orchestrating bootstrap-all workflow, per-team Nx package.json manifests, and documentation updates reflecting the new workflows and dependencies.

Changes

Cohort / File(s) Summary
Orchestration Workflows
/.github/workflows/bootstrap-all.yml, /.github/workflows/deploy.yml
Adds bootstrap-all.yml to conditionally invoke per-team bootstraps; refactors deploy.yml to invoke per-team reusable deploy workflows, removes monolithic auth/TF steps, and disables the previous Compass emission.
Reusable Team Workflows
teams/kernel/github-workflows/bootstrap-team.yml, teams/kernel/github-workflows/deploy-team.yml
Adds reusable workflows: bootstrap-team.yml performs OIDC/GCP auth and runs team bootstrap scripts; deploy-team.yml runs Node/pnpm setup, GCP auth, Terraform init/plan/apply in a team IaC path with TF_VAR wiring.
Team IaC package manifests (Nx config)
teams/kernel/iac/bootstrap/package.json, teams/people/iac/bootstrap/package.json, teams/things/iac/bootstrap/package.json
Adds/updates package.json files marking ESM and declaring nx.implicitDependencies so people/things bootstrap depend on kernel bootstrap metadata.
Documentation
docs/insights-long-term.md, docs/insights-short-term.md
Updates long-term insight to reference reusable workflows/Nx dependencies and refreshes short-term insights content (content-only edits).

Sequence Diagram

sequenceDiagram
    participant Orchestrator as GitHub Actions (bootstrap-all)
    participant Reusable as Reusable Workflow (bootstrap-team / deploy-team)
    participant Scripts as Team Script (project-setup.sh / IaC)
    participant GCP as Google Cloud / Terraform

    Orchestrator->>Reusable: workflow_call(team-name, secrets)
    Reusable->>GCP: Authenticate via OIDC / Workload Identity
    Reusable->>Scripts: Run bootstrap or Terraform commands in iac-path
    Scripts->>GCP: Create/update projects & resources (gcloud / terraform)
    GCP-->>Scripts: Return status/results
    Reusable-->>Orchestrator: Report success/failure
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 Hopping through CI with a cheer so spry,
I call kernel, people, things to bootstrap and fly.
Reusable steps, secrets tucked tight,
Projects awaken in deployment light.
🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (6 files):

⚔️ .github/workflows/deploy.yml (content)
⚔️ CHANGELOG.md (content)
⚔️ docs/insights-long-term.md (content)
⚔️ docs/insights-short-term.md (content)
⚔️ package.json (content)
⚔️ teams/kernel/iac/bootstrap/package.json (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the primary change: introducing reusable bootstrap and deploy workflows for team independence.
Description check ✅ Passed The description covers required sections (what/why, how) with clear explanations, includes an experiment record aligned with the template, and provides concrete implementation details.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 247-independence-of-action

Comment @coderabbitai help to get the list of available commands and usage tips.

@amaralc amaralc self-assigned this Feb 14, 2026
@nx-cloud
Copy link

nx-cloud bot commented Feb 14, 2026

View your CI Pipeline Execution ↗ for commit c584fc1

Command Status Duration Result
nx affected --target=build --base=origin/main -... ✅ Succeeded <1s View ↗
nx affected --target=test --base=origin/main --... ✅ Succeeded <1s View ↗
nx affected --target=lint --base=origin/main --... ✅ Succeeded <1s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-15 14:12:22 UTC

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @.github/workflows/bootstrap-all.yml:
- Around line 1-12: Add a workflow-level permissions block to restrict
GITHUB_TOKEN rather than allowing full permissions; in the "Bootstrap All Team
Infrastructure" workflow, replace the implicit full-token usage by adding a
top-level permissions map that grants only the specific scopes needed by the
reusable workflow (for example, explicitly set permissions.contents and any
other minimal permissions required) so CodeQL warnings are silenced while
ensuring the reusable workflow still receives the permissions it expects;
reference the workflow name "Bootstrap All Team Infrastructure" and the existing
GITHUB_TOKEN env to locate where to insert the permissions block.
- Around line 42-48: The workflow uses needs: bootstrap-kernel together with if:
always() for the bootstrap-people job which causes bootstrap-people to run even
when bootstrap-kernel fails; update the job's if condition (referencing the
bootstrap-people job and its existing needs: bootstrap-kernel) to require kernel
success (e.g., replace always() with success() or use
needs.bootstrap-kernel.result == 'success' AND your existing team input checks)
so the people bootstrap is skipped if kernel fails; apply the same change to the
bootstrap-things job's if condition as well.

In @.github/workflows/deploy.yml:
- Around line 82-83: The workflow reference uses a reusable workflow file
located in a subdirectory (uses:
./teams/kernel/github-workflows/deploy-team.yml) which GitHub Actions requires
to be directly under .github/workflows; move the reusable workflow file to the
repository root workflows folder (e.g., .github/workflows/deploy-team.yml) and
update the uses: line in the calling workflow to point to the new location
(uses: ./github/workflows/deploy-team.yml or simply uses: ./deploy-team.yml as
appropriate), ensuring the reusable workflow filename (deploy-team.yml) matches
the moved file.
- Around line 105-136: The jobs deploy-people and deploy-things currently
declare needs: deploy-kernel but use if: always(), which lets them run even when
deploy-kernel failed; decide intent and fix accordingly: if deploy-kernel must
succeed before team deployments, change the conditional on deploy-people and
deploy-things from if: always() to if: needs.deploy-kernel.result == 'success'
(preserve needs: deploy-kernel), otherwise remove the needs: deploy-kernel lines
so those jobs run in parallel without the kernel dependency.
- Around line 159-163: Replace the constant `if: false` on the job named
emit-compass-deployment with a repository variable check (e.g. use the Actions
variables context to evaluate EMIT_COMPASS_DEPLOYMENT) so actionlint no longer
treats it as a constant; update the job's `if` to reference the variable (for
example compare EMIT_COMPASS_DEPLOYMENT to 'true' using the expression syntax)
and create the repository variable EMIT_COMPASS_DEPLOYMENT in Settings → Secrets
and variables → Actions → Variables.
🧹 Nitpick comments (4)
teams/kernel/github-workflows/bootstrap-team.yml (2)

70-87: Consider passing secrets via environment variables instead of CLI arguments.

Passing secrets as CLI arguments (e.g., --owner-account-email="${{ secrets.OWNER_ACCOUNT_EMAIL }}") can expose them in process listings. While GitHub Actions masks secrets in logs, using environment variables provides an additional layer of protection and aligns with the project's documented insight: "Pass secrets to scripts via env vars, not CLI args; GitHub auto-masks env: values."

♻️ Proposed fix: Use env vars for secrets
       - name: Run bootstrap script for ${{ inputs.team-name }}
+        env:
+          OWNER_ACCOUNT_EMAIL: ${{ secrets.OWNER_ACCOUNT_EMAIL }}
+          GCP_ORGANIZATION_ID: ${{ secrets.GCP_ORGANIZATION_ID }}
+          GCP_BILLING_ACCOUNT_ID: ${{ secrets.GCP_BILLING_ACCOUNT_ID }}
+          DOMAIN_NAME: ${{ secrets.DOMAIN_NAME }}
+          GITHUB_USERNAME: ${{ secrets.GITHUB_USERNAME }}
+          NEON_API_KEY: ${{ secrets.NEON_API_KEY }}
+          NEON_PROJECT_LOCATION: ${{ secrets.NEON_PROJECT_LOCATION }}
+          MONGODB_ATLAS_ORG_ID: ${{ secrets.MONGODB_ATLAS_ORG_ID }}
+          MONGODB_ATLAS_PUBLIC_KEY: ${{ secrets.MONGODB_ATLAS_PUBLIC_KEY }}
+          MONGODB_ATLAS_PRIVATE_KEY: ${{ secrets.MONGODB_ATLAS_PRIVATE_KEY }}
+          NX_CLOUD_ACCESS_TOKEN_READ_WRITE: ${{ secrets.NX_CLOUD_ACCESS_TOKEN_READ_WRITE }}
+          NX_CLOUD_ACCESS_TOKEN_READ: ${{ secrets.NX_CLOUD_ACCESS_TOKEN_READ }}
         run: |
           echo "Bootstrap: Starting ${{ inputs.team-name }} team infrastructure bootstrap"
-          sh teams/kernel/iac/bootstrap/project-setup.sh \
-            --owner-account-email="${{ secrets.OWNER_ACCOUNT_EMAIL }}" \
-            ...
+          sh teams/kernel/iac/bootstrap/project-setup.sh
           echo "Bootstrap: Completed ${{ inputs.team-name }} team infrastructure bootstrap"

This would require updating project-setup.sh to read from environment variables instead of CLI arguments.


61-68: Remove redundant gh CLI installation step.

GitHub-hosted ubuntu-latest runners come with GitHub CLI pre-installed. This manual installation step adds ~10-15 seconds of overhead per run and is unnecessary unless a specific version is required.

♻️ Proposed fix: Remove redundant installation
-      - name: Install gh CLI
-        run: |
-          type -p curl >/dev/null || (sudo apt update && sudo apt install curl -y)
-          curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
-          && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
-          && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
-          && sudo apt update \
-          && sudo apt install gh -y
.github/workflows/bootstrap-all.yml (1)

18-20: Inconsistent condition logic between kernel and other teams.

The bootstrap-kernel job lacks the contains() check that bootstrap-people and bootstrap-things have, creating an inconsistency. If a user inputs "kernel people" (space-separated), only people would bootstrap because kernel doesn't match the exact string 'kernel'.

♻️ Proposed fix: Add contains() check for consistency
   bootstrap-kernel:
     name: Bootstrap Kernel Team
     uses: ./teams/kernel/github-workflows/bootstrap-team.yml
     if: |
       github.event.inputs.teams == 'all' ||
-      github.event.inputs.teams == 'kernel'
+      github.event.inputs.teams == 'kernel' ||
+      contains(github.event.inputs.teams, 'kernel')
teams/kernel/github-workflows/deploy-team.yml (1)

91-92: Consider conditional Prisma generation based on team needs.

pnpm prisma:generate:postgres runs for all teams, but teams without PostgreSQL/Prisma dependencies may not need this step. This adds ~5-10 seconds of overhead per deployment for teams that don't use Prisma.

If team-specific needs vary, consider either:

  1. Making this step conditional based on inputs.team-name.
  2. Moving Prisma generation to team-specific workflows that need it.

Comment on lines 159 to 163
emit-compass-deployment:
name: Emit Compass Deployment Event
needs: [deploy-kernel, deploy-people, deploy-things]
if: false # Intentionally disabled
runs-on: ubuntu-latest
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the deploy.yml file at the specified lines
cat -n .github/workflows/deploy.yml | sed -n '155,170p'

Repository: amaralc/explore

Length of output: 767


🏁 Script executed:

# Check if actionlint configuration exists
find . -name ".actionlint*" -o -name "actionlint*" | head -20

Repository: amaralc/explore

Length of output: 41


🏁 Script executed:

# Search for actionlint configuration or mentions in the repo
rg -i "actionlint" --type yaml --type json --type toml --type txt -A 3 -B 3

Repository: amaralc/explore

Length of output: 41


🌐 Web query:

actionlint if: false constant expression warning

💡 Result:

actionlint reports if: false as an error because it treats it as a constant condition (usually leftover debug/dead code) and recommends removing the if: (or commenting/removing the step/job). The check is documented as “Constant conditions at if: and the sample output is constant expression "false" in condition. remove the if: section [if-cond]. [1]

Fix options

  1. Remove the step/job (preferred)
# delete the step entirely
  1. Comment it out (if you want to keep it around)
# - name: My disabled step
#   run: echo "..."
#   if: false

(This is explicitly suggested in the check doc for if: false.) [1]

  1. Make it a real condition (e.g., controlled by an input/variable)
if: ${{ inputs.enable_thing == 'true' }}
  1. Ignore this error via actionlint.yaml (message-regex filtering)
    Create .github/actionlint.yaml and ignore the if-cond message with a regex, e.g.:
paths:
  .github/workflows/**/*.{yml,yaml}:
    ignore:
      - 'constant expression "false" in condition\.'

Actionlint supports per-path ignore lists of regular expressions that filter errors by message. [2]

Sources: actionlint checks (“Constant conditions at if:”) [1], actionlint configuration (paths: ... ignore: regex filtering) [2].


🌐 Web query:

GitHub Actions if: condition repository variables syntax

💡 Result:

In GitHub Actions, repository (and org/environment) variables you define in Settings → Secrets and variables → Actions → Variables are accessed in expressions via the vars context:

  • Syntax: vars.<NAME> (property) or vars['NAME'] (index) (docs.github.com)
  • In if: conditions: you can write either if: ${{ ... }} or usually omit the wrapper and write if: ... (docs.github.com)
  • Unset variables: vars.MISSING_VAR evaluates to an empty string (docs.github.com)

Example:

jobs:
  build:
    if: ${{ vars.DEPLOY_ENABLED == 'true' }}
    runs-on: ubuntu-latest
    steps:
      - name: Only run when enabled
        if: vars.ENVIRONMENT == 'prod'
        run: echo "Running in prod"

Note: vars (and env) cannot be used to parameterize uses: owner/repo@ref; expressions aren’t allowed there (a common source of “Unrecognized named-value” errors). (stackoverflow.com)

Citations:


🏁 Script executed:

# Check for other uses of `if: false` in workflows
rg "if:\s*false" .github/workflows/ --type yaml -n

Repository: amaralc/explore

Length of output: 130


🏁 Script executed:

# Check if repository variables are already used in this workflow
rg "vars\." .github/workflows/deploy.yml

Repository: amaralc/explore

Length of output: 41


Use a repository variable instead of constant if: false to avoid actionlint errors.

actionlint flags if: false as a constant expression error. Replace it with a repository variable to keep actionlint green while preserving the intentionally disabled job.

🔧 Fix using a repository variable
  emit-compass-deployment:
    name: Emit Compass Deployment Event
    needs: [deploy-kernel, deploy-people, deploy-things]
-   if: false # Intentionally disabled
+   if: ${{ vars.EMIT_COMPASS_DEPLOYMENT == 'true' }}
    runs-on: ubuntu-latest

After applying this change, create a repository variable EMIT_COMPASS_DEPLOYMENT in Settings → Secrets and variables → Actions → Variables.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
emit-compass-deployment:
name: Emit Compass Deployment Event
needs: [deploy-kernel, deploy-people, deploy-things]
if: false # Intentionally disabled
runs-on: ubuntu-latest
emit-compass-deployment:
name: Emit Compass Deployment Event
needs: [deploy-kernel, deploy-people, deploy-things]
if: ${{ vars.EMIT_COMPASS_DEPLOYMENT == 'true' }}
runs-on: ubuntu-latest
🧰 Tools
🪛 actionlint (1.7.10)

[error] 162-162: constant expression "false" in condition. remove the if: section

(if-cond)

🤖 Prompt for AI Agents
In @.github/workflows/deploy.yml around lines 159 - 163, Replace the constant
`if: false` on the job named emit-compass-deployment with a repository variable
check (e.g. use the Actions variables context to evaluate
EMIT_COMPASS_DEPLOYMENT) so actionlint no longer treats it as a constant; update
the job's `if` to reference the variable (for example compare
EMIT_COMPASS_DEPLOYMENT to 'true' using the expression syntax) and create the
repository variable EMIT_COMPASS_DEPLOYMENT in Settings → Secrets and variables
→ Actions → Variables.

…ot contain permissions

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
- Remove workflow-level permissions from deploy.yml and bootstrap-all.yml
- Add explicit job-level `contents: read` permissions to bootstrap jobs
- Enforce principle of least privilege per GitHub security best practices
- Update insights with permissions scoping and PR creation patterns

Fixes CodeQL warnings about unrestricted GITHUB_TOKEN permissions.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @.github/workflows/bootstrap-all.yml:
- Around line 20-23: The kernel job's if condition currently only checks exact
matches (github.event.inputs.teams == 'kernel' or 'all'), so it won't trigger
for space-separated inputs; update the condition to use
contains(github.event.inputs.teams, 'kernel') (and keep the existing check for
'all') so inputs like "kernel people" also match—modify the job's if expression
that references github.event.inputs.teams to include contains(..., 'kernel')
consistent with the other bootstrap jobs.

In @.github/workflows/deploy.yml:
- Around line 76-101: Add explicit permissions blocks to the caller jobs to
match security best practices: for the deploy jobs (deploy-kernel,
deploy-people, deploy-things) add a permissions block with "contents: read" and
"id-token: write"; for the emit-compass-deployment job (even if disabled) add a
minimal permissions block of "{}" to indicate no repo or OIDC access required.
Update the job definitions (deploy-kernel, deploy-people, deploy-things,
emit-compass-deployment) to include these permissions entries directly in their
job specs.

In `@docs/insights-short-term.md`:
- Line 11: The insight line contains the lowercase platform name "github" —
update the text "Team-owned reusable workflows under teams/*/ with entry points
in .github/ for discoverability" to use the correct capitalization "GitHub"
(preserve the rest of the wording and the .github/ and teams/*/ references).

Move secrets from direct expansion in run blocks to env blocks.
This prevents secrets from leaking in logs and enables GitHub's
automatic secret masking.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
amaralc and others added 2 commits February 15, 2026 11:08
Captured key learning: Move secrets from run blocks to env: to enable
GitHub's automatic masking. This prevents accidental exposure in logs.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@sonarqubecloud
Copy link

@amaralc amaralc merged commit 15db657 into main Feb 15, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant