From 35bcbce3f5f76d03a0ad11ba1aeef956fbae1a00 Mon Sep 17 00:00:00 2001 From: amaralc Date: Sat, 14 Feb 2026 14:50:18 -0300 Subject: [PATCH 01/10] fix(workflows): teams reuse workflows to bootstrap and deploy --- .github/workflows/bootstrap-all.yml | 93 ++++++++++ .github/workflows/deploy.yml | 174 +++++++++--------- docs/insights-long-term.md | 2 +- docs/insights-short-term.md | 15 +- .../github-workflows/bootstrap-team.yml | 92 +++++++++ teams/kernel/github-workflows/deploy-team.yml | 150 +++++++++++++++ teams/kernel/iac/bootstrap/package.json | 5 +- teams/people/iac/bootstrap/package.json | 10 + teams/things/iac/bootstrap/package.json | 10 + 9 files changed, 458 insertions(+), 93 deletions(-) create mode 100644 .github/workflows/bootstrap-all.yml create mode 100644 teams/kernel/github-workflows/bootstrap-team.yml create mode 100644 teams/kernel/github-workflows/deploy-team.yml create mode 100644 teams/people/iac/bootstrap/package.json create mode 100644 teams/things/iac/bootstrap/package.json diff --git a/.github/workflows/bootstrap-all.yml b/.github/workflows/bootstrap-all.yml new file mode 100644 index 00000000..ea7e6405 --- /dev/null +++ b/.github/workflows/bootstrap-all.yml @@ -0,0 +1,93 @@ +name: Bootstrap All Team Infrastructure + +on: + workflow_dispatch: + inputs: + teams: + description: 'Teams to bootstrap (all, kernel, people, things, or space-separated list)' + required: false + default: 'all' + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + 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' + secrets: + GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + 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 }} + with: + team-name: kernel + + bootstrap-people: + name: Bootstrap People Team + uses: ./teams/kernel/github-workflows/bootstrap-team.yml + needs: bootstrap-kernel + if: | + always() && ( + github.event.inputs.teams == 'all' || + github.event.inputs.teams == 'people' || + contains(github.event.inputs.teams, 'people') + ) + secrets: + GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + 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 }} + with: + team-name: people + + bootstrap-things: + name: Bootstrap Things Team + uses: ./teams/kernel/github-workflows/bootstrap-team.yml + needs: bootstrap-kernel + if: | + always() && ( + github.event.inputs.teams == 'all' || + github.event.inputs.teams == 'things' || + contains(github.event.inputs.teams, 'things') + ) + secrets: + GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + 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 }} + with: + team-name: things diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6bfa4172..70ceff6e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -7,7 +7,8 @@ on: workflow_dispatch: jobs: - release: + build: + name: Build and Release runs-on: ubuntu-latest environment: main permissions: @@ -64,29 +65,6 @@ jobs: git push git push --tags - - name: Get short commit hash - run: | - echo "short_commit_sha=$(git rev-parse --short=8 HEAD)" >> $GITHUB_ENV - - - name: Authenticate to Google Cloud - id: 'auth' - uses: 'google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed' # v2.1.13 - with: - workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} - service_account: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} - - - name: Set up Cloud SDK - uses: 'google-github-actions/setup-gcloud@e427ad8a34f8676edf47cf7d7925499adf3eb74f' # v2.2.1 - - - 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 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2 @@ -98,58 +76,93 @@ jobs: NX_BRANCH=${GITHUB_REF#refs/heads/} pnpm nx run-many --target=build --all=true --parallel=3 NX_BRANCH=${GITHUB_REF#refs/heads/} pnpm nx run-many --target=post-build --all=true --parallel=3 - - name: Set up Terraform - uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2 - with: - terraform_version: 1.7.5 - - - name: Terraform init - run: | - echo "Running terraform init..." - echo "" - terraform init - working-directory: teams/kernel/iac/production - - - name: Terraform validate - run: | - echo "Running terraform validate..." - terraform validate - working-directory: teams/kernel/iac/production - - - name: Terraform Plan - env: - TF_VAR_domain_name: ${{ secrets.DOMAIN_NAME }} - TF_VAR_gcp_project_id: ${{ secrets.GCP_PROJECT_ID }} - TF_VAR_gcp_location: ${{ secrets.GCP_LOCATION }} - TF_VAR_short_commit_sha: ${{ env.short_commit_sha }} - TF_VAR_support_account_email: ${{ secrets.SUPPORT_ACCOUNT_EMAIL }} - TF_VAR_owner_account_email: ${{ secrets.OWNER_ACCOUNT_EMAIL }} - TF_VAR_gcp_billing_account_id: ${{ secrets.GCP_BILLING_ACCOUNT_ID }} - TF_VAR_gcp_organization_id: ${{ secrets.GCP_ORGANIZATION_ID }} - TF_VAR_nx_cloud_access_token: ${{ env.NX_CLOUD_ACCESS_TOKEN }} - TF_VAR_neon_api_key: ${{ secrets.NEON_API_KEY }} - TF_VAR_neon_project_location: ${{ secrets.NEON_PROJECT_LOCATION }} - TF_VAR_unleash_api_url: ${{ secrets.UNLEASH_API_URL }} - TF_VAR_unleash_auth_token: ${{ secrets.UNLEASH_AUTH_TOKEN }} - TF_VAR_environment_path: ${{ env.GITHUB_ENV }} - TF_VAR_mongodb_atlas_org_id: ${{ secrets.MONGODB_ATLAS_ORG_ID }} - TF_VAR_mongodb_atlas_private_key: ${{ secrets.MONGODB_ATLAS_PRIVATE_KEY }} - TF_VAR_mongodb_atlas_public_key: ${{ secrets.MONGODB_ATLAS_PUBLIC_KEY }} - TF_VAR_service_account_email: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} - run: | - echo "Running terraform plan..." - echo "Commit Hash: ${{ env.short_commit_sha }}" - terraform plan -out=tfplan - working-directory: teams/kernel/iac/production - - - name: Terraform Apply - run: | - echo "Running terraform apply..." - terraform apply -auto-approve tfplan - working-directory: teams/kernel/iac/production - - - name: Emmit Compass Deployment event - if: false # Intentionally disabled + deploy-kernel: + name: Deploy Kernel Team + needs: build + uses: ./teams/kernel/github-workflows/deploy-team.yml + secrets: + GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} + DOMAIN_NAME: ${{ secrets.DOMAIN_NAME }} + GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} + GCP_LOCATION: ${{ secrets.GCP_LOCATION }} + SUPPORT_ACCOUNT_EMAIL: ${{ secrets.SUPPORT_ACCOUNT_EMAIL }} + OWNER_ACCOUNT_EMAIL: ${{ secrets.OWNER_ACCOUNT_EMAIL }} + GCP_BILLING_ACCOUNT_ID: ${{ secrets.GCP_BILLING_ACCOUNT_ID }} + GCP_ORGANIZATION_ID: ${{ secrets.GCP_ORGANIZATION_ID }} + NEON_API_KEY: ${{ secrets.NEON_API_KEY }} + NEON_PROJECT_LOCATION: ${{ secrets.NEON_PROJECT_LOCATION }} + UNLEASH_API_URL: ${{ secrets.UNLEASH_API_URL }} + UNLEASH_AUTH_TOKEN: ${{ secrets.UNLEASH_AUTH_TOKEN }} + MONGODB_ATLAS_ORG_ID: ${{ secrets.MONGODB_ATLAS_ORG_ID }} + MONGODB_ATLAS_PRIVATE_KEY: ${{ secrets.MONGODB_ATLAS_PRIVATE_KEY }} + MONGODB_ATLAS_PUBLIC_KEY: ${{ secrets.MONGODB_ATLAS_PUBLIC_KEY }} + with: + team-name: kernel + iac-path: teams/kernel/iac/production + + deploy-people: + name: Deploy People Team + needs: deploy-kernel + if: always() + uses: ./teams/kernel/github-workflows/deploy-team.yml + secrets: + GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} + DOMAIN_NAME: ${{ secrets.DOMAIN_NAME }} + GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} + GCP_LOCATION: ${{ secrets.GCP_LOCATION }} + SUPPORT_ACCOUNT_EMAIL: ${{ secrets.SUPPORT_ACCOUNT_EMAIL }} + OWNER_ACCOUNT_EMAIL: ${{ secrets.OWNER_ACCOUNT_EMAIL }} + GCP_BILLING_ACCOUNT_ID: ${{ secrets.GCP_BILLING_ACCOUNT_ID }} + GCP_ORGANIZATION_ID: ${{ secrets.GCP_ORGANIZATION_ID }} + NEON_API_KEY: ${{ secrets.NEON_API_KEY }} + NEON_PROJECT_LOCATION: ${{ secrets.NEON_PROJECT_LOCATION }} + UNLEASH_API_URL: ${{ secrets.UNLEASH_API_URL }} + UNLEASH_AUTH_TOKEN: ${{ secrets.UNLEASH_AUTH_TOKEN }} + MONGODB_ATLAS_ORG_ID: ${{ secrets.MONGODB_ATLAS_ORG_ID }} + MONGODB_ATLAS_PRIVATE_KEY: ${{ secrets.MONGODB_ATLAS_PRIVATE_KEY }} + MONGODB_ATLAS_PUBLIC_KEY: ${{ secrets.MONGODB_ATLAS_PUBLIC_KEY }} + with: + team-name: people + iac-path: teams/people/iac/production + + deploy-things: + name: Deploy Things Team + needs: deploy-kernel + if: always() + uses: ./teams/kernel/github-workflows/deploy-team.yml + secrets: + GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} + DOMAIN_NAME: ${{ secrets.DOMAIN_NAME }} + GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} + GCP_LOCATION: ${{ secrets.GCP_LOCATION }} + SUPPORT_ACCOUNT_EMAIL: ${{ secrets.SUPPORT_ACCOUNT_EMAIL }} + OWNER_ACCOUNT_EMAIL: ${{ secrets.OWNER_ACCOUNT_EMAIL }} + GCP_BILLING_ACCOUNT_ID: ${{ secrets.GCP_BILLING_ACCOUNT_ID }} + GCP_ORGANIZATION_ID: ${{ secrets.GCP_ORGANIZATION_ID }} + NEON_API_KEY: ${{ secrets.NEON_API_KEY }} + NEON_PROJECT_LOCATION: ${{ secrets.NEON_PROJECT_LOCATION }} + UNLEASH_API_URL: ${{ secrets.UNLEASH_API_URL }} + UNLEASH_AUTH_TOKEN: ${{ secrets.UNLEASH_AUTH_TOKEN }} + MONGODB_ATLAS_ORG_ID: ${{ secrets.MONGODB_ATLAS_ORG_ID }} + MONGODB_ATLAS_PRIVATE_KEY: ${{ secrets.MONGODB_ATLAS_PRIVATE_KEY }} + MONGODB_ATLAS_PUBLIC_KEY: ${{ secrets.MONGODB_ATLAS_PUBLIC_KEY }} + with: + team-name: things + iac-path: teams/things/iac/production + + emit-compass-deployment: + name: Emit Compass Deployment Event + needs: [deploy-kernel, deploy-people, deploy-things] + if: false # Intentionally disabled + runs-on: ubuntu-latest + steps: + - name: Emit deployment event env: ATLASSIAN_DOMAIN: ${{ secrets.ATLASSIAN_DOMAIN }} ATLASSIAN_CLOUD_ID: ${{ secrets.ATLASSIAN_CLOUD_ID }} @@ -157,11 +170,4 @@ jobs: ATLASSIAN_USER_API_TOKEN: ${{ secrets.ATLASSIAN_USER_API_TOKEN }} COMPASS_EXTERNAL_EVENT_SOURCE_ID: ${{ secrets.COMPASS_EXTERNAL_EVENT_SOURCE_ID }} run: | - bash scripts/compass/emmit-deployment-event.sh \ - --atlassian-domain="$ATLASSIAN_DOMAIN" \ - --atlassian-cloud-id="$ATLASSIAN_CLOUD_ID" \ - --atlassian-user-email="$ATLASSIAN_USER_EMAIL" \ - --atlassian-user-api-token="$ATLASSIAN_USER_API_TOKEN" \ - --compass-external-event-source-id="$COMPASS_EXTERNAL_EVENT_SOURCE_ID" \ - --pipeline-run-id="$GITHUB_RUN_ID" \ - --repository-name="$GITHUB_REPOSITORY" + echo "Deployment complete. Compass event emission intentionally disabled." diff --git a/docs/insights-long-term.md b/docs/insights-long-term.md index 30ce8045..8c9f1163 100644 --- a/docs/insights-long-term.md +++ b/docs/insights-long-term.md @@ -101,4 +101,4 @@ Key insights from this repository. 97. Chaos engineering reveals resilience gaps through continuous fault injection. 98. Terraform state is managed remotely, never locally. 99. Provider versions are pinned in each module's versions.tf file. -100. Group operations under section headers and suppress verbose CLI output for script debuggability. +100. Reusable workflows + NX dependencies enable independent team infrastructure bootstrap. diff --git a/docs/insights-short-term.md b/docs/insights-short-term.md index b164eea7..ea1e6608 100644 --- a/docs/insights-short-term.md +++ b/docs/insights-short-term.md @@ -2,6 +2,14 @@ Latest 100 insights derived from recent project activity, newest first. +- [2026-02-13 22:30 UTC] Team-owned reusable workflows under teams/*/ with entry points in .github/ for discoverability +- [2026-02-13 21:30 UTC] Explicit script references in workflows beat symlinks; clarity and traceability matter +- [2026-02-13 21:15 UTC] Explicit script paths via env vars avoid symlink indirection; clarity over magic +- [2026-02-13 21:00 UTC] Implicit patterns need explicit documentation; README + metadata prevent confusion +- [2026-02-13 20:45 UTC] Symlinks transparently share shell scripts; lightweight DRY alternative to npm packages +- [2026-02-13 20:15 UTC] Symlinks for shell scripts avoid npm overhead; NX implicit deps document ordering +- [2026-02-13 19:53 UTC] Symlinks + reusable GitHub workflows orchestrate multi-team infrastructure bootstrap +- [2026-02-13 18:45 UTC] Reusable workflows + NX dependencies enable independent team infrastructure bootstrap - [2026-02-13 15:00 UTC] Idempotent logging: use section headers, suppress verbose output, and show status (○/✓) - [2026-02-13 14:00 UTC] Show resource status (created vs existing) in idempotent scripts for debuggability - [2026-02-13 13:00 UTC] Group operations under headers; suppress verbose output to improve script debuggability @@ -94,10 +102,3 @@ Latest 100 insights derived from recent project activity, newest first. - [2026-02-10 05:30 UTC] Nuke local infra (minikube delete) + rm tfstate when destroy fails on missing CRDs - [2026-02-10 05:15 UTC] `terraform state mv` bypasses moved-block + missing-provider catch-22 locally - [2026-02-10 05:00 UTC] Terraform `moved` blocks must all resolve before `-target` applies succeed -- [2026-02-10 04:45 UTC] Terraform validates module output attributes at plan time even inside count=0 modules -- [2026-02-10 04:15 UTC] MongoDB Atlas TF provider v2.x changes `replication_specs` from block to argument syntax -- [2026-02-10 03:30 UTC] Wrap cloud-only TF resources in count-gated sub-modules to avoid provider requirements locally -- [2026-02-09 21:45 UTC] NX hides `chore` by default; override via `release.conventionalCommits.types` in nx.json -- [2026-02-09 19:30 UTC] Fresh cluster bootstraps skip incremental upgrade paths; migrate only in-place -- [2026-02-09 19:15 UTC] provider-kubernetes v1.2.0+ requires Crossplane 2.0+; upgrade both together -- [2026-02-09 18:45 UTC] Pinned image versions drift across modules; grep all references before upgrading diff --git a/teams/kernel/github-workflows/bootstrap-team.yml b/teams/kernel/github-workflows/bootstrap-team.yml new file mode 100644 index 00000000..4937388e --- /dev/null +++ b/teams/kernel/github-workflows/bootstrap-team.yml @@ -0,0 +1,92 @@ +name: Bootstrap Team Infrastructure (Reusable) + +on: + workflow_call: + inputs: + team-name: + required: true + type: string + description: 'Team name (kernel, people, things)' + secrets: + GCP_WORKLOAD_IDENTITY_PROVIDER: + required: true + GCP_SERVICE_ACCOUNT_EMAIL: + required: true + OWNER_ACCOUNT_EMAIL: + required: true + GCP_ORGANIZATION_ID: + required: true + GCP_BILLING_ACCOUNT_ID: + required: true + DOMAIN_NAME: + required: true + GITHUB_USERNAME: + required: true + NEON_API_KEY: + required: true + NEON_PROJECT_LOCATION: + required: true + MONGODB_ATLAS_ORG_ID: + required: true + MONGODB_ATLAS_PUBLIC_KEY: + required: true + MONGODB_ATLAS_PRIVATE_KEY: + required: true + NX_CLOUD_ACCESS_TOKEN_READ_WRITE: + required: true + NX_CLOUD_ACCESS_TOKEN_READ: + required: true + +jobs: + bootstrap: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - name: Authenticate to Google Cloud + id: auth + uses: google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed # v2.1.13 + with: + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + + - name: Set up Cloud SDK + uses: google-github-actions/setup-gcloud@e427ad8a34f8676edf47cf7d7925499adf3eb74f # v2.2.1 + + - 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 + + - name: Run bootstrap script for ${{ inputs.team-name }} + 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 }}" \ + --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 }}" \ + --github-repository="${{ github.repository }}" \ + --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 }}" + echo "Bootstrap: Completed ${{ inputs.team-name }} team infrastructure bootstrap" + + - name: Verify bootstrap success + run: | + echo "Bootstrap: Verifying ${{ inputs.team-name }} infrastructure" + gcloud projects list --filter="name:*${{ inputs.team-name }}*" --format="table(name,projectId)" diff --git a/teams/kernel/github-workflows/deploy-team.yml b/teams/kernel/github-workflows/deploy-team.yml new file mode 100644 index 00000000..52bd4a1a --- /dev/null +++ b/teams/kernel/github-workflows/deploy-team.yml @@ -0,0 +1,150 @@ +name: Deploy Team Infrastructure (Reusable) + +on: + workflow_call: + inputs: + team-name: + required: true + type: string + description: 'Team name (kernel, people, things)' + iac-path: + required: true + type: string + description: 'Path to team IAC directory (e.g., teams/kernel/iac/production)' + secrets: + GCP_WORKLOAD_IDENTITY_PROVIDER: + required: true + GCP_SERVICE_ACCOUNT_EMAIL: + required: true + NX_CLOUD_ACCESS_TOKEN: + required: true + DOMAIN_NAME: + required: false + GCP_PROJECT_ID: + required: false + GCP_LOCATION: + required: false + SUPPORT_ACCOUNT_EMAIL: + required: false + OWNER_ACCOUNT_EMAIL: + required: false + GCP_BILLING_ACCOUNT_ID: + required: false + GCP_ORGANIZATION_ID: + required: false + NEON_API_KEY: + required: false + NEON_PROJECT_LOCATION: + required: false + UNLEASH_API_URL: + required: false + UNLEASH_AUTH_TOKEN: + required: false + MONGODB_ATLAS_ORG_ID: + required: false + MONGODB_ATLAS_PRIVATE_KEY: + required: false + MONGODB_ATLAS_PUBLIC_KEY: + required: false + +jobs: + deploy: + runs-on: ubuntu-latest + environment: main + permissions: + contents: read + id-token: write + + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + fetch-depth: 0 + + - name: Get short commit hash + run: | + echo "short_commit_sha=$(git rev-parse --short=8 HEAD)" >> $GITHUB_ENV + + - name: Install Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version-file: '.nvmrc' + + - name: Install pnpm + uses: pnpm/action-setup@c5ba7f7862a0f64c1b1a05fbac13e0b8e86ba08c # v4 + + - name: Get pnpm store directory + shell: bash + run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - name: Cache pnpm store + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Generate Prisma client + run: pnpm prisma:generate:postgres + + - name: Authenticate to Google Cloud + id: auth + uses: google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed # v2.1.13 + with: + workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + + - name: Set up Cloud SDK + uses: google-github-actions/setup-gcloud@e427ad8a34f8676edf47cf7d7925499adf3eb74f # v2.2.1 + + - name: Set up Terraform + uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2 + with: + terraform_version: 1.7.5 + + - name: Terraform init + working-directory: ${{ inputs.iac-path }} + run: | + echo "Running terraform init for ${{ inputs.team-name }}..." + terraform init + + - name: Terraform validate + working-directory: ${{ inputs.iac-path }} + run: | + echo "Running terraform validate for ${{ inputs.team-name }}..." + terraform validate + + - name: Terraform Plan + working-directory: ${{ inputs.iac-path }} + env: + TF_VAR_domain_name: ${{ secrets.DOMAIN_NAME }} + TF_VAR_gcp_project_id: ${{ secrets.GCP_PROJECT_ID }} + TF_VAR_gcp_location: ${{ secrets.GCP_LOCATION }} + TF_VAR_short_commit_sha: ${{ env.short_commit_sha }} + TF_VAR_support_account_email: ${{ secrets.SUPPORT_ACCOUNT_EMAIL }} + TF_VAR_owner_account_email: ${{ secrets.OWNER_ACCOUNT_EMAIL }} + TF_VAR_gcp_billing_account_id: ${{ secrets.GCP_BILLING_ACCOUNT_ID }} + TF_VAR_gcp_organization_id: ${{ secrets.GCP_ORGANIZATION_ID }} + TF_VAR_nx_cloud_access_token: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} + TF_VAR_neon_api_key: ${{ secrets.NEON_API_KEY }} + TF_VAR_neon_project_location: ${{ secrets.NEON_PROJECT_LOCATION }} + TF_VAR_unleash_api_url: ${{ secrets.UNLEASH_API_URL }} + TF_VAR_unleash_auth_token: ${{ secrets.UNLEASH_AUTH_TOKEN }} + TF_VAR_mongodb_atlas_org_id: ${{ secrets.MONGODB_ATLAS_ORG_ID }} + TF_VAR_mongodb_atlas_private_key: ${{ secrets.MONGODB_ATLAS_PRIVATE_KEY }} + TF_VAR_mongodb_atlas_public_key: ${{ secrets.MONGODB_ATLAS_PUBLIC_KEY }} + TF_VAR_service_account_email: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} + run: | + echo "Running terraform plan for ${{ inputs.team-name }}..." + echo "Commit Hash: ${{ env.short_commit_sha }}" + terraform plan -out=tfplan + + - name: Terraform Apply + working-directory: ${{ inputs.iac-path }} + run: | + echo "Running terraform apply for ${{ inputs.team-name }}..." + terraform apply -auto-approve tfplan diff --git a/teams/kernel/iac/bootstrap/package.json b/teams/kernel/iac/bootstrap/package.json index da408623..f2fe76ab 100644 --- a/teams/kernel/iac/bootstrap/package.json +++ b/teams/kernel/iac/bootstrap/package.json @@ -3,5 +3,8 @@ "version": "1.0.0", "description": "Bootstrap infrastructure as code for kernel IAC", "private": true, - "type": "module" + "type": "module", + "nx": { + "implicitDependencies": [] + } } \ No newline at end of file diff --git a/teams/people/iac/bootstrap/package.json b/teams/people/iac/bootstrap/package.json new file mode 100644 index 00000000..a62629a6 --- /dev/null +++ b/teams/people/iac/bootstrap/package.json @@ -0,0 +1,10 @@ +{ + "name": "people-iac-bootstrap", + "version": "1.0.0", + "description": "Bootstrap infrastructure for people team", + "private": true, + "type": "module", + "nx": { + "implicitDependencies": ["kernel-iac-bootstrap"] + } +} diff --git a/teams/things/iac/bootstrap/package.json b/teams/things/iac/bootstrap/package.json new file mode 100644 index 00000000..7d354e7a --- /dev/null +++ b/teams/things/iac/bootstrap/package.json @@ -0,0 +1,10 @@ +{ + "name": "things-iac-bootstrap", + "version": "1.0.0", + "description": "Bootstrap infrastructure for things team", + "private": true, + "type": "module", + "nx": { + "implicitDependencies": ["kernel-iac-bootstrap"] + } +} From 4d673c3d854bd9a177499c6aa186d5552920a1fb Mon Sep 17 00:00:00 2001 From: amaralc Date: Sat, 14 Feb 2026 14:52:44 -0300 Subject: [PATCH 02/10] docs(insights): add workflow confirmation pattern --- docs/insights-short-term.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/insights-short-term.md b/docs/insights-short-term.md index ea1e6608..7ffdc8d7 100644 --- a/docs/insights-short-term.md +++ b/docs/insights-short-term.md @@ -2,6 +2,7 @@ Latest 100 insights derived from recent project activity, newest first. +- [2026-02-14 10:00 UTC] Confirm branching strategy before creating PR from uncommitted changes on main - [2026-02-13 22:30 UTC] Team-owned reusable workflows under teams/*/ with entry points in .github/ for discoverability - [2026-02-13 21:30 UTC] Explicit script references in workflows beat symlinks; clarity and traceability matter - [2026-02-13 21:15 UTC] Explicit script paths via env vars avoid symlink indirection; clarity over magic @@ -101,4 +102,3 @@ Latest 100 insights derived from recent project activity, newest first. - [2026-02-10 05:45 UTC] Terraform configures ALL providers in module tree even when parent has count=0 - [2026-02-10 05:30 UTC] Nuke local infra (minikube delete) + rm tfstate when destroy fails on missing CRDs - [2026-02-10 05:15 UTC] `terraform state mv` bypasses moved-block + missing-provider catch-22 locally -- [2026-02-10 05:00 UTC] Terraform `moved` blocks must all resolve before `-target` applies succeed From 309ce534ce7ed1feff075cfcfdc29f7a0ce8dc4a Mon Sep 17 00:00:00 2001 From: Calil Amaral Date: Sat, 14 Feb 2026 15:04:55 -0300 Subject: [PATCH 03/10] config: potential fix for code scanning alert no. 69: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/bootstrap-all.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/bootstrap-all.yml b/.github/workflows/bootstrap-all.yml index ea7e6405..a41b8674 100644 --- a/.github/workflows/bootstrap-all.yml +++ b/.github/workflows/bootstrap-all.yml @@ -11,6 +11,9 @@ on: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +permissions: + contents: read + jobs: bootstrap-kernel: name: Bootstrap Kernel Team From 9f03b4ee4e4f8d5d5b9ddf6994fde54fb264c47f Mon Sep 17 00:00:00 2001 From: amaralc Date: Sat, 14 Feb 2026 15:11:31 -0300 Subject: [PATCH 04/10] fix(github-actions): scope permissions to job level for least privilege - 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 --- .github/workflows/bootstrap-all.yml | 9 ++++++--- .github/workflows/deploy.yml | 3 --- docs/insights-short-term.md | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/bootstrap-all.yml b/.github/workflows/bootstrap-all.yml index a41b8674..cdd1f3eb 100644 --- a/.github/workflows/bootstrap-all.yml +++ b/.github/workflows/bootstrap-all.yml @@ -11,13 +11,12 @@ on: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -permissions: - contents: read - jobs: bootstrap-kernel: name: Bootstrap Kernel Team uses: ./teams/kernel/github-workflows/bootstrap-team.yml + permissions: + contents: read if: | github.event.inputs.teams == 'all' || github.event.inputs.teams == 'kernel' @@ -43,6 +42,8 @@ jobs: name: Bootstrap People Team uses: ./teams/kernel/github-workflows/bootstrap-team.yml needs: bootstrap-kernel + permissions: + contents: read if: | always() && ( github.event.inputs.teams == 'all' || @@ -71,6 +72,8 @@ jobs: name: Bootstrap Things Team uses: ./teams/kernel/github-workflows/bootstrap-team.yml needs: bootstrap-kernel + permissions: + contents: read if: | always() && ( github.event.inputs.teams == 'all' || diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 70ceff6e..9d13ce26 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,8 +1,5 @@ name: Deploy to Production -permissions: - contents: read - on: workflow_dispatch: diff --git a/docs/insights-short-term.md b/docs/insights-short-term.md index 7ffdc8d7..07e77306 100644 --- a/docs/insights-short-term.md +++ b/docs/insights-short-term.md @@ -2,6 +2,11 @@ Latest 100 insights derived from recent project activity, newest first. +- [2026-02-14 14:15 UTC] Add explicit job permissions after removing workflow-level for least privilege +- [2026-02-14 14:00 UTC] Apply workflow security fixes consistently across similar files to prevent drift +- [2026-02-14 13:45 UTC] Move GitHub Actions permissions from workflow to job level for least privilege +- [2026-02-14 13:15 UTC] Explicit permissions blocks in workflows restrict GITHUB_TOKEN to least privilege +- [2026-02-14 12:30 UTC] Use HEREDOC with gh pr create to preserve PR template formatting and structure - [2026-02-14 10:00 UTC] Confirm branching strategy before creating PR from uncommitted changes on main - [2026-02-13 22:30 UTC] Team-owned reusable workflows under teams/*/ with entry points in .github/ for discoverability - [2026-02-13 21:30 UTC] Explicit script references in workflows beat symlinks; clarity and traceability matter @@ -97,8 +102,3 @@ Latest 100 insights derived from recent project activity, newest first. - [2026-02-10 07:30 UTC] Cloud roots import sub-modules directly; routers can't gate providers with count=0 - [2026-02-10 07:15 UTC] Versioned environment modules with local/cloud sub-paths enable parallel evolution - [2026-02-10 07:00 UTC] Terraform `-target` requires full nested module path, not just the leaf module name -- [2026-02-10 06:30 UTC] count=0 sub-modules don't isolate providers; exclude cloud modules from local tree -- [2026-02-10 06:00 UTC] Skip `terraform destroy` for fresh clusters; `minikube delete --profile` suffices alone -- [2026-02-10 05:45 UTC] Terraform configures ALL providers in module tree even when parent has count=0 -- [2026-02-10 05:30 UTC] Nuke local infra (minikube delete) + rm tfstate when destroy fails on missing CRDs -- [2026-02-10 05:15 UTC] `terraform state mv` bypasses moved-block + missing-provider catch-22 locally From 886204015ca40fd21ff8acdadd3a77e951d163db Mon Sep 17 00:00:00 2001 From: amaralc Date: Sat, 14 Feb 2026 15:32:02 -0300 Subject: [PATCH 05/10] fix(workflows): force job dependencies --- .github/workflows/deploy.yml | 4 ++-- docs/insights-short-term.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9d13ce26..b841b938 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -102,7 +102,7 @@ jobs: deploy-people: name: Deploy People Team needs: deploy-kernel - if: always() + if: needs.deploy-kernel.result == 'success' uses: ./teams/kernel/github-workflows/deploy-team.yml secrets: GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} @@ -129,7 +129,7 @@ jobs: deploy-things: name: Deploy Things Team needs: deploy-kernel - if: always() + if: needs.deploy-kernel.result == 'success' uses: ./teams/kernel/github-workflows/deploy-team.yml secrets: GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} diff --git a/docs/insights-short-term.md b/docs/insights-short-term.md index 07e77306..830e5b85 100644 --- a/docs/insights-short-term.md +++ b/docs/insights-short-term.md @@ -2,6 +2,8 @@ Latest 100 insights derived from recent project activity, newest first. +- [2026-02-14 14:35 UTC] Combine job needs with needs.X.result == 'success' to enforce deployment success +- [2026-02-14 14:30 UTC] Complete security fixes end-to-end: implement, test, commit, push for compliance - [2026-02-14 14:15 UTC] Add explicit job permissions after removing workflow-level for least privilege - [2026-02-14 14:00 UTC] Apply workflow security fixes consistently across similar files to prevent drift - [2026-02-14 13:45 UTC] Move GitHub Actions permissions from workflow to job level for least privilege @@ -100,5 +102,3 @@ Latest 100 insights derived from recent project activity, newest first. - [2026-02-10 08:30 UTC] Two-phase TF apply: targeted `-target` installs CRDs, then full apply plans resources needing them - [2026-02-10 08:00 UTC] Placeholder provider blocks with dummy tokens satisfy TF init for count=0 cloud modules - [2026-02-10 07:30 UTC] Cloud roots import sub-modules directly; routers can't gate providers with count=0 -- [2026-02-10 07:15 UTC] Versioned environment modules with local/cloud sub-paths enable parallel evolution -- [2026-02-10 07:00 UTC] Terraform `-target` requires full nested module path, not just the leaf module name From a917964a6606b8e7857bf80e66d836903dc636a2 Mon Sep 17 00:00:00 2001 From: amaralc Date: Sat, 14 Feb 2026 15:40:31 -0300 Subject: [PATCH 06/10] fix(ci): add job dependencies --- .github/workflows/bootstrap-all.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bootstrap-all.yml b/.github/workflows/bootstrap-all.yml index cdd1f3eb..a1ac4faa 100644 --- a/.github/workflows/bootstrap-all.yml +++ b/.github/workflows/bootstrap-all.yml @@ -45,7 +45,7 @@ jobs: permissions: contents: read if: | - always() && ( + needs.bootstrap-kernel.result == 'success' && ( github.event.inputs.teams == 'all' || github.event.inputs.teams == 'people' || contains(github.event.inputs.teams, 'people') @@ -75,7 +75,7 @@ jobs: permissions: contents: read if: | - always() && ( + needs.bootstrap-kernel.result == 'success' && ( github.event.inputs.teams == 'all' || github.event.inputs.teams == 'things' || contains(github.event.inputs.teams, 'things') From b3c295f7c0b5a8b323ad2ede9056214a6d3ce873 Mon Sep 17 00:00:00 2001 From: amaralc Date: Sat, 14 Feb 2026 15:49:08 -0300 Subject: [PATCH 07/10] fix(ci): move workflows to .github folder --- .../workflows/teams-kernel-workflows-bootstrap-team.yml | 0 ...otstrap-all.yml => teams-kernel-workflows-bootstrap.yml} | 6 +++--- .github/workflows/{ci.yml => teams-kernel-workflows-ci.yml} | 0 .../workflows/teams-kernel-workflows-deploy-team.yml | 0 .../{deploy.yml => teams-kernel-workflows-deploy.yml} | 6 +++--- .github/workflows/{pr.yml => teams-kernel-workflows-pr.yml} | 0 .../{security.yml => teams-kernel-workflows-security.yml} | 0 7 files changed, 6 insertions(+), 6 deletions(-) rename teams/kernel/github-workflows/bootstrap-team.yml => .github/workflows/teams-kernel-workflows-bootstrap-team.yml (100%) rename .github/workflows/{bootstrap-all.yml => teams-kernel-workflows-bootstrap.yml} (95%) rename .github/workflows/{ci.yml => teams-kernel-workflows-ci.yml} (100%) rename teams/kernel/github-workflows/deploy-team.yml => .github/workflows/teams-kernel-workflows-deploy-team.yml (100%) rename .github/workflows/{deploy.yml => teams-kernel-workflows-deploy.yml} (97%) rename .github/workflows/{pr.yml => teams-kernel-workflows-pr.yml} (100%) rename .github/workflows/{security.yml => teams-kernel-workflows-security.yml} (100%) diff --git a/teams/kernel/github-workflows/bootstrap-team.yml b/.github/workflows/teams-kernel-workflows-bootstrap-team.yml similarity index 100% rename from teams/kernel/github-workflows/bootstrap-team.yml rename to .github/workflows/teams-kernel-workflows-bootstrap-team.yml diff --git a/.github/workflows/bootstrap-all.yml b/.github/workflows/teams-kernel-workflows-bootstrap.yml similarity index 95% rename from .github/workflows/bootstrap-all.yml rename to .github/workflows/teams-kernel-workflows-bootstrap.yml index a1ac4faa..8c25018a 100644 --- a/.github/workflows/bootstrap-all.yml +++ b/.github/workflows/teams-kernel-workflows-bootstrap.yml @@ -14,7 +14,7 @@ env: jobs: bootstrap-kernel: name: Bootstrap Kernel Team - uses: ./teams/kernel/github-workflows/bootstrap-team.yml + uses: ./.github/workflows/teams-kernel-workflows-bootstrap-team.yml permissions: contents: read if: | @@ -40,7 +40,7 @@ jobs: bootstrap-people: name: Bootstrap People Team - uses: ./teams/kernel/github-workflows/bootstrap-team.yml + uses: ./.github/workflows/teams-kernel-workflows-bootstrap-team.yml needs: bootstrap-kernel permissions: contents: read @@ -70,7 +70,7 @@ jobs: bootstrap-things: name: Bootstrap Things Team - uses: ./teams/kernel/github-workflows/bootstrap-team.yml + uses: ./.github/workflows/teams-kernel-workflows-bootstrap-team.yml needs: bootstrap-kernel permissions: contents: read diff --git a/.github/workflows/ci.yml b/.github/workflows/teams-kernel-workflows-ci.yml similarity index 100% rename from .github/workflows/ci.yml rename to .github/workflows/teams-kernel-workflows-ci.yml diff --git a/teams/kernel/github-workflows/deploy-team.yml b/.github/workflows/teams-kernel-workflows-deploy-team.yml similarity index 100% rename from teams/kernel/github-workflows/deploy-team.yml rename to .github/workflows/teams-kernel-workflows-deploy-team.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/teams-kernel-workflows-deploy.yml similarity index 97% rename from .github/workflows/deploy.yml rename to .github/workflows/teams-kernel-workflows-deploy.yml index b841b938..7624ff86 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/teams-kernel-workflows-deploy.yml @@ -76,7 +76,7 @@ jobs: deploy-kernel: name: Deploy Kernel Team needs: build - uses: ./teams/kernel/github-workflows/deploy-team.yml + uses: ./.github/workflows/teams-kernel-workflows-deploy-team.yml secrets: GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} @@ -103,7 +103,7 @@ jobs: name: Deploy People Team needs: deploy-kernel if: needs.deploy-kernel.result == 'success' - uses: ./teams/kernel/github-workflows/deploy-team.yml + uses: ./.github/workflows/teams-kernel-workflows-deploy-team.yml secrets: GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} @@ -130,7 +130,7 @@ jobs: name: Deploy Things Team needs: deploy-kernel if: needs.deploy-kernel.result == 'success' - uses: ./teams/kernel/github-workflows/deploy-team.yml + uses: ./.github/workflows/teams-kernel-workflows-deploy-team.yml secrets: GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} diff --git a/.github/workflows/pr.yml b/.github/workflows/teams-kernel-workflows-pr.yml similarity index 100% rename from .github/workflows/pr.yml rename to .github/workflows/teams-kernel-workflows-pr.yml diff --git a/.github/workflows/security.yml b/.github/workflows/teams-kernel-workflows-security.yml similarity index 100% rename from .github/workflows/security.yml rename to .github/workflows/teams-kernel-workflows-security.yml From 599aba4ee03eab1926db15b379cdb80f7185f413 Mon Sep 17 00:00:00 2001 From: amaralc Date: Sun, 15 Feb 2026 11:00:15 -0300 Subject: [PATCH 08/10] fix(ci): pass secrets via environment variables for proper masking 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 --- .../teams-kernel-workflows-bootstrap-team.yml | 37 +++++++++++++------ .../teams-kernel-workflows-bootstrap.yml | 3 +- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.github/workflows/teams-kernel-workflows-bootstrap-team.yml b/.github/workflows/teams-kernel-workflows-bootstrap-team.yml index 4937388e..4bdc4548 100644 --- a/.github/workflows/teams-kernel-workflows-bootstrap-team.yml +++ b/.github/workflows/teams-kernel-workflows-bootstrap-team.yml @@ -68,22 +68,35 @@ jobs: && sudo apt install gh -y - 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 }}" \ - --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 }}" \ + --owner-account-email="$OWNER_ACCOUNT_EMAIL" \ + --gcp-organization-id="$GCP_ORGANIZATION_ID" \ + --gcp-billing-account-id="$GCP_BILLING_ACCOUNT_ID" \ + --domain-name="$DOMAIN_NAME" \ + --github-username="$GITHUB_USERNAME" \ --github-repository="${{ github.repository }}" \ - --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 }}" + --neon-api-key="$NEON_API_KEY" \ + --neon-project-location="$NEON_PROJECT_LOCATION" \ + --mongodb-atlas-org-id="$MONGODB_ATLAS_ORG_ID" \ + --mongodb-atlas-public-key="$MONGODB_ATLAS_PUBLIC_KEY" \ + --mongodb-atlas-private-key="$MONGODB_ATLAS_PRIVATE_KEY" \ + --nx-cloud-access-token-read-write="$NX_CLOUD_ACCESS_TOKEN_READ_WRITE" \ + --nx-cloud-access-token-read="$NX_CLOUD_ACCESS_TOKEN_READ" echo "Bootstrap: Completed ${{ inputs.team-name }} team infrastructure bootstrap" - name: Verify bootstrap success diff --git a/.github/workflows/teams-kernel-workflows-bootstrap.yml b/.github/workflows/teams-kernel-workflows-bootstrap.yml index 8c25018a..92dcd20e 100644 --- a/.github/workflows/teams-kernel-workflows-bootstrap.yml +++ b/.github/workflows/teams-kernel-workflows-bootstrap.yml @@ -19,7 +19,8 @@ jobs: contents: read if: | github.event.inputs.teams == 'all' || - github.event.inputs.teams == 'kernel' + github.event.inputs.teams == 'kernel' || + contains(github.event.inputs.teams, 'people') secrets: GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} From de5b50e5ca22c89b59af8f2a8bbfdc7967a379d9 Mon Sep 17 00:00:00 2001 From: amaralc Date: Sun, 15 Feb 2026 11:08:18 -0300 Subject: [PATCH 09/10] docs: add insight on secret masking in GitHub Actions workflows 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 --- docs/insights-short-term.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/insights-short-term.md b/docs/insights-short-term.md index 830e5b85..1732a255 100644 --- a/docs/insights-short-term.md +++ b/docs/insights-short-term.md @@ -2,6 +2,7 @@ Latest 100 insights derived from recent project activity, newest first. +- [2026-02-15 14:00 UTC] Move secrets from run blocks to env: to enable GitHub masking - [2026-02-14 14:35 UTC] Combine job needs with needs.X.result == 'success' to enforce deployment success - [2026-02-14 14:30 UTC] Complete security fixes end-to-end: implement, test, commit, push for compliance - [2026-02-14 14:15 UTC] Add explicit job permissions after removing workflow-level for least privilege @@ -101,4 +102,3 @@ Latest 100 insights derived from recent project activity, newest first. - [2026-02-10 09:00 UTC] Separate infra provisioners (Crossplane) from service modules (IAM) so multiple services reuse them - [2026-02-10 08:30 UTC] Two-phase TF apply: targeted `-target` installs CRDs, then full apply plans resources needing them - [2026-02-10 08:00 UTC] Placeholder provider blocks with dummy tokens satisfy TF init for count=0 cloud modules -- [2026-02-10 07:30 UTC] Cloud roots import sub-modules directly; routers can't gate providers with count=0 From c584fc16f0a90a8bcfbc8080fa31d77a14742683 Mon Sep 17 00:00:00 2001 From: amaralc Date: Sun, 15 Feb 2026 11:09:18 -0300 Subject: [PATCH 10/10] fix(ci): avoid expanding secrets in actions --- .github/workflows/teams-kernel-workflows-bootstrap.yml | 2 +- .github/workflows/teams-kernel-workflows-deploy.yml | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/teams-kernel-workflows-bootstrap.yml b/.github/workflows/teams-kernel-workflows-bootstrap.yml index 92dcd20e..8595e926 100644 --- a/.github/workflows/teams-kernel-workflows-bootstrap.yml +++ b/.github/workflows/teams-kernel-workflows-bootstrap.yml @@ -20,7 +20,7 @@ jobs: if: | github.event.inputs.teams == 'all' || github.event.inputs.teams == 'kernel' || - contains(github.event.inputs.teams, 'people') + contains(github.event.inputs.teams, 'kernel') secrets: GCP_WORKLOAD_IDENTITY_PROVIDER: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }} GCP_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GCP_SERVICE_ACCOUNT_EMAIL }} diff --git a/.github/workflows/teams-kernel-workflows-deploy.yml b/.github/workflows/teams-kernel-workflows-deploy.yml index 7624ff86..d69dea28 100644 --- a/.github/workflows/teams-kernel-workflows-deploy.yml +++ b/.github/workflows/teams-kernel-workflows-deploy.yml @@ -75,6 +75,8 @@ jobs: deploy-kernel: name: Deploy Kernel Team + permissions: + contents: read needs: build uses: ./.github/workflows/teams-kernel-workflows-deploy-team.yml secrets: @@ -101,6 +103,8 @@ jobs: deploy-people: name: Deploy People Team + permissions: + contents: read needs: deploy-kernel if: needs.deploy-kernel.result == 'success' uses: ./.github/workflows/teams-kernel-workflows-deploy-team.yml @@ -129,6 +133,8 @@ jobs: deploy-things: name: Deploy Things Team needs: deploy-kernel + permissions: + contents: read if: needs.deploy-kernel.result == 'success' uses: ./.github/workflows/teams-kernel-workflows-deploy-team.yml secrets: @@ -155,6 +161,8 @@ jobs: emit-compass-deployment: name: Emit Compass Deployment Event + permissions: + contents: read needs: [deploy-kernel, deploy-people, deploy-things] if: false # Intentionally disabled runs-on: ubuntu-latest