Skip to content

Onboarding

End-to-end process for standing up platform identities, seeding secrets, and bringing every repo into compliance with HCS standards. All phases are tracked in the Onboarding Tracker.


Dependency order

Phase 0 (repo discovery) ──► master-registry.db entry ──┐
AB#21 (MIs + SPNs per tenant) ──────────────────────┤
AB#22 (GitHub org PATs) ─────────────────────────────┼──► AB#406 (seed org/group secrets) ──► AB#15 ‖ AB#16
AB#23 (GitLab account PATs) ─────────────────────────┘                                        (repo onboarding)

Phase 0 (discovery) can run any time, independently of everything else — it only reads remote GitHub/GitLab state and master-registry.db, and by default writes nothing. AB#21 and AB#22/23 can run in parallel. AB#406 (secrets distribution) requires all three to be done first. Repo onboarding (AB#15/16) runs last, and needs the target repo to already have a master-registry.db entry — which is exactly what Phase 0 produces for anything newly discovered.


Phase execution sequence

Phase 0 — Repo discovery (finding new repos before they can be onboarded)

Every other phase assumes the repo is already known — it isn't, until it has a master-registry.db entry. Phase 0 is how a brand-new repo (a new GitHub org/account the platform's GitHub App gets installed on, or a new repo inside an already-authorized GitLab subgroup tree) gets found in the first place.

Script: scripts/onboarding/Invoke-RepoDiscovery.ps1 (wrapped by the manual-trigger ADO pipeline Repo Discovery, defined in .ado/repo-discovery.yml)

  • GitHub scope is dynamic, not hardcoded: it authenticates as the hcs-platform-app GitHub App and calls GET /app/installations to get the live list of every account the App is installed on — a newly installed org or personal account is picked up automatically, no code change needed.
  • GitLab scope is a pinned list, not dynamic: the 3 documented-authorized subgroup trees under tierpoint/prodtech (azurelocal, docs, haas). A GitLab PAT's visibility reflects org-wide employee access, not an ownership boundary, so scanning "every group the token can see" would pull in other TierPoint teams' repos — deliberately not done. If the authorized scope changes, update the pinned list in the script (or pass -GitLabGroups to override for a one-off run).
  • Default run is report-only — it diffs the discovered repos against master-registry.db and writes a markdown report of anything unregistered. Nothing is created or changed anywhere by default. Pass -CreateAdoProjects to also create a 1:1 Title-Case ADO project per newly discovered repo.
  • master-registry.db's ignored_repos: (specific repo, matched by (account, name) pair) and ignored_accounts: (a whole account, e.g. a personal GitHub account that's permanently out of scope) sections let you permanently exclude things from ever being reported as "new" again, without editing the script.
powershell
. D:\git\platform\scripts\Load-HCSEnvironment.ps1

# Report-only scan of the whole estate
pwsh D:\git\platform\scripts\onboarding\Invoke-RepoDiscovery.ps1

Once a repo shows up in the discovery report: add it to master-registry.db with the right type/scope/company, then continue with Phase 5 (Invoke-RepoClaudeSetup.ps1) — RepoClaudeSetup now writes the full multi-model layout (AGENTS.md + CLAUDE.md shim + .codex//.mcp.json/.ai/) in the same pass as the Claude-specific .claude/settings.json/hooks/agents, so no separate script run is needed for that part.


Phase 1 — Tenant identities (AB#21)

Creates managed identities and service principals in all 7 tenants. Also creates two new platform Key Vaults (kv-azlmgmt-platform, kv-tppoc-platform) where they don't exist yet.

Script: scripts/identity/Invoke-TenantIdentitySetup.ps1
Config: config/tenant-identities.json

powershell
. D:\git\platform\scripts\Load-HCSEnvironment.ps1

# Preview all actions first
pwsh D:\git\platform\scripts\identity\Invoke-TenantIdentitySetup.ps1 -DryRun

# Run (requires MFA/device-code auth for the 5 azurelocal.cloud tenants)
pwsh D:\git\platform\scripts\identity\Invoke-TenantIdentitySetup.ps1

After running: update docs/identity/managed-identities.md, docs/identity/service-principals.md, and docs/identity/secret-inventory.md with the created resources. Tick the checkboxes in Table A.


Phase 2 — GitHub org PATs + org secrets (AB#22 + AB#406)

Creates one scoped PAT per GitHub org and seeds it as ORG_PAT in each org's Actions secrets. Uses a temporary god-mode PAT during bootstrap, then replaces it.

Guide: GitHub Credentials Guide
Script: scripts/identity/Invoke-GitHubSecretsDistribution.ps1


Phase 3 — GitLab account PATs + group CI/CD variables (AB#23 + AB#406)

Creates two scoped GitLab PATs (one per account) and seeds them plus per-tenant SPN credentials as group-level CI/CD variables.

Guide: GitLab Credentials Guide
Script: scripts/identity/Invoke-GitLabVariableDistribution.ps1

Prerequisite: Phase 1 must be complete — the SPN credentials for each tenant vault must already exist in KV before this phase can seed them into GitLab.


Phase 4 — ADO project services (AB#408)

Disables unused ADO services (Repos, Pipelines, Test Plans, Artifacts) across all 51 ADO projects. Leaves Boards on everywhere and Pipelines on in Platform Engineering only.

Script: scripts/ado/Disable-ADOProjectServices.ps1

powershell
. D:\git\platform\scripts\Load-HCSEnvironment.ps1

pwsh D:\git\platform\scripts\ado\Disable-ADOProjectServices.ps1 -DryRun
pwsh D:\git\platform\scripts\ado\Disable-ADOProjectServices.ps1

Phase 5 — Repo Claude Code configuration (AB#15)

Deploys the full multi-model layout to all repos across all managed GitHub orgs: AGENTS.md (the canonical cross-tool instruction file), CLAUDE.md as a thin @AGENTS.md shim, .codex/config.toml, .github/copilot-instructions.md, .mcp.json, .ai/ workspace scaffold, plus the Claude-specific .claude/settings.json (hooks wired), copied hook scripts, .claude/agents/<name>-engineer.md, and log stubs. Classifies each repo by file signature (TypeScript, MkDocs, PowerShell, IaC, static site) and generates appropriate config. No Claude API calls.

Script: scripts/onboarding/Invoke-RepoClaudeSetup.ps1

powershell
. D:\git\platform\scripts\Load-HCSEnvironment.ps1

# Preview all repos and their detected types
pwsh D:\git\platform\scripts\onboarding\Invoke-RepoClaudeSetup.ps1 -DryRun

# Run one org at a time to review commits before going broad
pwsh D:\git\platform\scripts\onboarding\Invoke-RepoClaudeSetup.ps1 -OrgFilter AzureLocal -DryRun
pwsh D:\git\platform\scripts\onboarding\Invoke-RepoClaudeSetup.ps1 -OrgFilter AzureLocal

# Then remaining orgs
pwsh D:\git\platform\scripts\onboarding\Invoke-RepoClaudeSetup.ps1

Track per-repo completion in Table D.


Phase 6 — Conformance audit (AB#15 / AB#16)

Verifies every repo meets the platform standard: CLAUDE.md, .gitignore, README.md, .claude/settings.json, no secrets committed.

Script: scripts/onboarding/Test-RepoConformance.ps1


Scripts reference

ScriptPurposePhase
scripts/Load-HCSEnvironment.ps1Loads all secrets from KV into local sessionAll
scripts/onboarding/Invoke-RepoDiscovery.ps1Finds repos not yet in master-registry.db0
scripts/identity/Invoke-TenantIdentitySetup.ps1Creates MIs, SPNs, KVs per tenant1
scripts/identity/Invoke-GitHubSecretsDistribution.ps1Seeds GitHub org-level Actions secrets2
scripts/identity/Invoke-GitLabVariableDistribution.ps1Seeds GitLab group CI/CD variables3
scripts/ado/Disable-ADOProjectServices.ps1Disables unused ADO project services4
scripts/onboarding/Invoke-RepoClaudeSetup.ps1Deploys Claude Code config to all repos5
scripts/onboarding/Test-RepoConformance.ps1Audits repos against platform standard6
scripts/onboarding/New-HCSRepo.ps1Creates a new repo with full scaffoldOn demand
scripts/ado/New-ADOProjects.ps1Creates ADO projectsOn demand

Copyright © Hybrid Cloud Solutions LLC — Kristopher Turner