Adoption (Customer-Tier Onboarding)
This runbook takes an organization outside the service repository's own org from nothing to a live-syncing, buildable customer-tier fork. The result is described in Fork Tiers: a true GitHub fork that mirrors the service repository's main, builds with your own credentials, and can contribute PRs back.
Adoption replaces initialization. A fork of an initialized repository inherits every deployed workflow and all configuration from the parent's main; what it lacks is state (branches, labels, rulesets, settings, variables), and the Adopt Fork workflow supplies exactly that.
Prerequisites
1. Create your organization's GitHub App
The workflows authenticate their write operations through a GitHub App, never through personal tokens. Create one in your org (Settings > Developer settings > GitHub Apps) with these repository permissions:
| Permission | Level | Used for |
|---|---|---|
| Contents | Read and write | Branch pushes, releases |
| Pull requests | Read and write | Sync, cascade, and release PRs; auto-merge |
| Administration | Read and write | Rulesets, repository settings |
| Variables | Read and write | Repository variables (a separate permission; Administration does not cover it) |
| Secrets | Read-only | The settings cadence reads secret names for deploy-readiness checks |
| Workflows | Read and write | Workflow file updates arriving through sync |
| Issues | Read and write | Tracking and failure issues, labels |
Generate a private key, and install the App on your organization (covering the fork you are about to create).
2. Fork the service repository
Fork the service repository into your organization through GitHub (keep "Copy the default branch only" checked). It must be a true GitHub fork: contribution PRs can only be opened from within the parent's fork network, and adoption auto-detects your upstream from the fork's parent.
After forking, open the fork's Actions tab and enable workflows (GitHub disables inherited workflows on new forks until a person enables them). Nothing runs until you do, including adoption itself.
That bulk enable does not reach workflows carrying a schedule: trigger. On a new fork they stay in state disabled_fork, which suppresses manual dispatch as well.
In this repository, those are:
sync.ymlcascade-monitor.ymlsettings-apply.ymlcodeql.ymlghcr-retention.ymlsync-template.ymlscorecard.yml
Adoption re-enables the fork-disabled workflows for you, but it deliberately leaves sync-template.yml disabled (ADR-039 gates template sync off at this tier because the mirror is the single delivery channel for workflow and configuration updates) and scorecard.yml disabled (it is inert on a fork as noted under Gotchas).
3. Set the required secrets
On the fork (Settings > Secrets and variables > Actions):
| Secret | Required | Purpose |
|---|---|---|
RELEASE_APP_ID | Yes | Your GitHub App's ID |
RELEASE_APP_PRIVATE_KEY | Yes | Your GitHub App's private key (PEM) |
GITLAB_TOKEN | For OSDU Java services | Community Maven registry access for builds |
OPENGROUP_MAVEN_USERNAME | For OSDU Java services | Community Maven credentials used by validation |
OPENGROUP_MAVEN_TOKEN | For OSDU Java services | Community Maven credentials used by validation |
AZURE_API_KEY, AZURE_API_BASE, AZURE_API_VERSION | Optional | AI-enhanced PR descriptions; everything degrades to templated text without them |
Set the build secrets before merging your first sync PR: mirror-mode sync PRs build the full profile set, so they need registry access from the start.
Run Adoption
Dispatch the Adopt Fork workflow from the Actions tab. No inputs are needed in the normal case; upstream_repo_url exists as an override for the unusual situation where the repository is not a GitHub fork.
What it does, in order:
- Refuses if the repository is already initialized (
INITIALIZATION_COMPLETEis set). This protects first-tier forks, which also carry this workflow. - Mints a token from your App and detects the upstream from the fork's GitHub parent.
- Creates
fork_upstreamandfork_integrationat the merge base with the upstream's default branch: the tip itself on a fresh fork, the fork point on a fork whosemainwas already customized. Local commits stay local instead of being reverted by the first sync. - Creates the system labels the sync and cascade machinery uses.
- Sets
UPSTREAM_REPO_URLandSYNC_MODE=mirror. - Applies the branch rulesets (the deploy and integration-test required checks are automatically stripped because the deploy-tier credentials are absent).
- Enables auto-merge and merge commits (the cascade's release PRs depend on both).
- Enables secret scanning and push protection (best effort; a warning tells you to enable them manually if the API declines).
- Re-enables the workflows that forking left disabled, apart from
sync-template.ymlandscorecard.yml. - Sets
INITIALIZATION_COMPLETE=true, last, and writes a summary.
Re-run semantics: the completion variable is both the guard and the final step. If adoption fails partway, fix the cause and dispatch it again; completed steps skip or reconcile. After a fully successful run, re-dispatching refuses by design.
First Sync and Cascade
- Dispatch Sync Upstream (it also runs nightly). It opens a PR into
fork_upstreamwhose tip commit is merge-shaped, carriesUpstream-ShaandFilter-Rev: mirrortrailers, and whose tree is byte-identical to the parent'smain. - Review and merge the sync PR. The cascade triggers automatically, merges
mainandfork_upstreamintofork_integration, builds the full profile set, and opens a release PR tomainwith auto-merge armed. - Always merge release PRs with a merge commit, never squash. Squashing breaks the branch ancestry the cascade monitor relies on.
Gotchas
- CODEOWNERS: the fork inherits the parent's
CODEOWNERSwith handles from the parent organization. Replace it with your own reviewers or delete it; unresolvable handles fail the file's validation. - Release conflicts: your release automation and the parent's both write
CHANGELOG.mdand.release-please-manifest.json. When both sides have released since your last sync, the cascade can hit a shallow conflict in those files. Resolution recipe: keep both changelog entries, keep your own manifest value. This is the accepted trade-off of ADR-039. - Standing differences: any change you keep on
mainthat is not upstream shows up as your side of every future cascade merge until it is contributed upstream or reverted. Prefer contributing back (the loop exists for exactly that). - Container images: builds publish to your own namespace,
ghcr.io/<your-org>, automatically. No registry configuration is needed for the default GHCR flow. - Contribution PRs: the first PR a new contributor opens against the parent requires a maintainer there to approve the workflow run before checks execute. Credential-bearing jobs never run for external heads regardless; build and validation give the real signal.
scorecard.yml: inherited but guarded to the template's own repository name; it is inert on your fork.- Adopt before customizing (recommended, not required): adoption pins the sync branches at the merge base with the upstream, so local commits made before adoption stay local instead of being reverted by the first sync. They still become standing differences that surface in every cascade until contributed upstream or reverted.