How do you migrate forty packages from one shared publish token to trusted publishing?
answer
- inventory before you change anything
- one shared token equals forty compromises
- order by consumer impact, not volunteers
- done means the old credential is deleted
- count credentials that still exist
basics
~20 sInventory where the shared credential lives and what else it grants, order the cutover by consumer impact, migrate each package to a publisher bound to one repository and workflow, and treat deleting the shared token as the completion criterion.
solid answer
~40 sStart from blast-radius arithmetic: one shared bot token across forty modules means any of forty repositories leaking it compromises all forty, indefinitely - and such a token usually grants more than publishing. So first, inventory: which repositories hold the secret, which other systems accept that identity, who can read it. Second, order the work by consumer impact, not by which team volunteers. Third, migrate per package: register a publisher pinned to one repository, one workflow and an approval-gated environment, prove one real release, then remove that repository's copy of the shared secret. Fourth, for registries that do not support the mechanism, aim for one narrowly scoped, owned, expiring token per package instead of the shared forever-token. Finally delete the shared credential. The metric is how many long-lived publish credentials still exist.
go deeper
Take away the core idea: a credential shared across many packages means a leak anywhere compromises everything, so publish credentials should be scoped as narrowly as the registry allows.
Be ready to describe the per-package cutover in order - register the publisher, prove one real release, then delete that repository's copy of the old secret - and to say why the last step is not optional.
Show you would inventory the shared identity's full permissions first and sequence by consumer impact, and that you have a concrete plan for the registries that cannot support the mechanism.
Own the framing, the stopping condition and the metric: risk stated as blast-radius arithmetic, completion defined as deleting the shared credential, and progress measured by how many long-lived publish credentials still exist.
## Why this is a judgment problem, not a task Forty internal modules published from one shared bot account is a common shape: it started as a convenience, and it works. The migration is easy per repository and hard in aggregate, because the forty repositories belong to teams with their own roadmaps, some of the registries involved may not support the mechanism, and the shared identity has usually accreted permissions nobody remembers granting. The engineering is trivial; the sequencing, the stopping condition and the residual cases are the actual work. ## Step 1: state the arithmetic out loud A single shared publish token has a blast radius equal to the union of everything it can do, multiplied by every place it is stored: - **Every repository that holds it is a full compromise of all forty packages.** The weakest of forty release pipelines sets the security of the strongest. - **It is valid until revoked**, so a copy taken a year ago still works, and revoking it breaks all forty releases at once - which is why nobody revokes it. - **It is usually over-granted.** A publish identity that also carries write access to a documentation bucket and a release-notes site spans three artifact kinds; a single leak then means an attacker can ship a package *and* rewrite the page that would have told people about it. Scoping to one package would have cost a few minutes of configuration and would have removed that entire second-order problem. Stating this arithmetic is how you get the migration prioritised, because it converts a hygiene request into a stated risk. ## Step 2: inventory before you change anything You cannot delete a shared credential you cannot account for. Establish: - every repository, pipeline and personal machine that holds a copy; - everything the identity can do beyond publishing; - which packages have external consumers versus purely internal ones; - which target registries support an OIDC publisher at all. The last item is decisive. Every real organisation ends up with a mixed estate, and pretending otherwise produces a migration that stalls at eighty percent and is declared done. ## Step 3: order by consumer blast radius Migrate the packages whose compromise would hurt most first - the ones with the most dependents, the ones consumed by production services, the ones consumed outside the organisation. Do not order by team enthusiasm, and do not attempt a flag day: forty simultaneous cutovers means forty simultaneous release failures if anything is wrong with the pattern. Migrate one package first, deliberately, and turn its configuration into the template others copy. The second through fortieth cutovers should be a small, well-understood change. ## Step 4: cut over properly, per package For each package: register a publisher pinned as narrowly as the registry allows - repository, workflow file, ref, and an environment carrying a required approval. Then perform one real release through the new path. Then, and only then, remove that repository's copy of the shared secret. The ordering matters. Teams that add the new path and leave the old secret in place have not reduced risk at all; they have added a door. This is the single most common way this migration produces no security benefit while looking complete. ## Step 5: decide what to do about the registries that cannot do it Some targets will not support an OIDC publisher. For those the goal changes from *no credential* to *the smallest credential*: - one token per package, never one shared across many; - stored in exactly one repository, with a named owning team; - created with an expiry if the registry supports one, and rotated on a schedule you actually run; - recorded in the same inventory, so it stays visible rather than becoming folklore. Be honest with leadership that this is a different, weaker control, and treat those packages as the population where compensating controls - approval-gated release environments, restricted release refs - matter most. ## Step 6: define done as deletion The completion criterion is not *thirty-eight of forty migrated*. It is: the shared token deleted, the bot account disabled, and its other permissions removed or reassigned. Until then the old path exists and the risk is unchanged. Expect to find, at this step, one or two consumers of the shared identity nobody knew about - which is precisely why deletion is the test and inventory alone is not. ## The metric Track **the number of long-lived publish credentials that exist**, and where each one lives. It is a small number that only moves when something real changes, it is understandable by people who do not write pipelines, and it cannot be satisfied by adding a new mechanism while leaving the old one running. Counting migrated repositories, by contrast, can go up while the risk stays exactly where it was. ## What an interviewer is listening for That you led with blast radius rather than with the mechanism; that you sequenced by consumer impact; that you named deletion of the old credential as the completion criterion; and that you had a defensible answer for the parts of the estate the new mechanism cannot cover, instead of pretending they do not exist.
- A team says migrating their package is not worth the effort because it is internal-only. How do you respond?Internal-only limits who consumes it, not what a compromise of the shared token costs - and their repository holding a copy of that token is a risk to the other thirty-nine packages, not just theirs. The argument is not about their package's value; it is that they cannot opt out of a shared credential while keeping a copy of it.
- How do you avoid the migration stalling once the easy packages are done?Make the remaining set visible and small: publish the inventory with named owners and a per-package status, and set the deletion of the shared credential as a dated commitment. A stall usually means the last packages are the ones with an unsupported registry or an unowned repository, so treat those as their own workstream with a different, explicitly weaker target.
- What would make you keep a long-lived token deliberately rather than migrate?A target that offers no OIDC publisher and a package with genuinely low consumer impact, where the cost of a bespoke path exceeds the residual risk. That is a decision to record with an owner and a review date, not a silent exception - and it should still be one scoped token for that one package, never continued use of the shared identity.
One shared publish token is a master key cut forty times and handed out; the migration is not issuing better keys, it is getting every copy of the master back and melting it.
saying these in an interview costs you the question
- Plans a single flag-day cutover across all forty
- Counts migration done when the new path works
- Leaves the shared token in place as a fallback
- Ignores what else the shared identity can access
- Has no answer for registries lacking OIDC support