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-appGitHub App and callsGET /app/installationsto 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-GitLabGroupsto override for a one-off run). - Default run is report-only — it diffs the discovered repos against
master-registry.dband writes a markdown report of anything unregistered. Nothing is created or changed anywhere by default. Pass-CreateAdoProjectsto also create a 1:1 Title-Case ADO project per newly discovered repo. master-registry.db'signored_repos:(specific repo, matched by(account, name)pair) andignored_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.
. D:\git\platform\scripts\Load-HCSEnvironment.ps1
# Report-only scan of the whole estate
pwsh D:\git\platform\scripts\onboarding\Invoke-RepoDiscovery.ps1Once 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
. 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.ps1After 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
. 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.ps1Phase 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
. 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.ps1Track 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
| Script | Purpose | Phase |
|---|---|---|
scripts/Load-HCSEnvironment.ps1 | Loads all secrets from KV into local session | All |
scripts/onboarding/Invoke-RepoDiscovery.ps1 | Finds repos not yet in master-registry.db | 0 |
scripts/identity/Invoke-TenantIdentitySetup.ps1 | Creates MIs, SPNs, KVs per tenant | 1 |
scripts/identity/Invoke-GitHubSecretsDistribution.ps1 | Seeds GitHub org-level Actions secrets | 2 |
scripts/identity/Invoke-GitLabVariableDistribution.ps1 | Seeds GitLab group CI/CD variables | 3 |
scripts/ado/Disable-ADOProjectServices.ps1 | Disables unused ADO project services | 4 |
scripts/onboarding/Invoke-RepoClaudeSetup.ps1 | Deploys Claude Code config to all repos | 5 |
scripts/onboarding/Test-RepoConformance.ps1 | Audits repos against platform standard | 6 |
scripts/onboarding/New-HCSRepo.ps1 | Creates a new repo with full scaffold | On demand |
scripts/ado/New-ADOProjects.ps1 | Creates ADO projects | On demand |