Repository protection restoration
Repository protection is restored after Git content has been copied and verified. This ordering is deliberate: activating rulesets or branch protection before the initial push, LFS transfer, default-branch establishment, or content verification could block the migration itself.
Ordering
For mutating Snapshot and FullHistory flows, the intended order is:
- discover source repository state;
- create or preserve/replace the destination as required;
- copy Git content;
- transfer Git LFS content when applicable;
- reload the destination and establish the expected default branch;
- verify Git content/history invariants;
- restore ordinary supported repository settings;
- restore transferable repository rulesets and legacy default-branch branch protection;
- read protection configuration back and verify it.
-PlanOnly and -WhatIf remain non-mutating. -SkipSettings also skips protection restoration.
Supported rulesets
Version 1 protection restoration copies repository-level rulesets when the rule can be recreated without carrying source-specific identities into the destination.
Supported rulesets preserve:
- name;
- target;
- enforcement mode;
- conditions;
- identity-free rules and rule parameters.
Organization-level inherited rulesets are not copied. They are intentionally queried with includes_parents=false; if organization policy independently applies to the destination, that is an external policy outcome rather than a copied repository setting.
Rulesets that are explicitly skipped
A repository ruleset is reported as skipped rather than weakened when it contains semantics that cannot be proven transferable:
- bypass actors (users, teams, apps, or other identity-bound actors);
- required deployment rules that depend on destination environments that this module does not create;
- required status checks tied to a specific integration ID.
The module does not silently remove those fields and create a weaker ruleset.
Legacy branch protection
The source default branch’s legacy branch-protection configuration is copied when it contains no identity-bound restrictions.
The transferable subset includes:
- required status-check contexts without app/integration identity binding;
- strict status-check behavior;
- administrator enforcement;
- required pull-request review settings without identity-bound dismissal restrictions;
- required approving-review count;
- code-owner review requirement;
- stale-review dismissal;
- last-push approval requirement when available;
- linear-history requirement;
- force-push allowance;
- deletion allowance;
- branch-creation blocking;
- conversation-resolution requirement;
- branch locking;
- fork-sync allowance;
- required commit signatures.
Legacy branch protection is reported as skipped when it contains:
- user/team/app push restrictions;
- user/team/app review-dismissal restrictions;
- required status checks tied to an app ID.
Only the default branch’s legacy branch protection is restored in the current implementation. Repository rulesets remain the preferred mechanism for broader branch/tag policy.
Verification
After mutation, repository-level rulesets are reloaded with inherited parent rules excluded. The module compares each restored ruleset’s name, target, enforcement, conditions, and rules with the transferable source configuration.
Legacy default-branch protection is reloaded and compared with the normalized source protection configuration. A mismatch is a terminating verification failure and is included in normal recovery reporting.
Permissions and GitHub plan behavior
Protection APIs require repository Administration permissions at the appropriate read/write level and may depend on the GitHub plan and repository visibility. If GitHub rejects a read or write because the authenticated identity or plan does not permit the operation, the migration fails with the GitHub API error rather than claiming protection was restored.
Safety guarantees
- Source protections are never weakened to make migration easier.
- Same-name archives remain preserved and are not modified merely to simplify replacement creation.
- Inherited organization policy is never reported as copied repository policy.
- Identity-bound semantics are surfaced explicitly instead of silently discarded.
- Protection is restored only after content verification.
- Recovery never automatically deletes or renames repositories.