Register only the federated credential format the repo actually uses - #17
Merged
Conversation
The Entra live test failed on PRs with AADSTS700213 because the app had no federated identity credential matching the subject GitHub sent. GitHub emits exactly one subject per OIDC token, and its format depends on the repo's subject claim customization. The microsoft org sets it to the ID-based form (repository_owner_id/repository_id), so the default repo:OWNER/REPO:... form is never emitted. This script registered BOTH formats unconditionally, which left two permanently-dead credentials on every app it provisioned. A tenant security sweep later removed them along with github-pr-id, and the only symptom was azure/login@v2 failing on PRs while main kept working. Changes: - Detect the subject customization and register only the matching pair, instead of registering the repo-slug pair unconditionally. - Make gh a hard requirement and fail loudly when the customization or the owner/repo IDs cannot be read. Previously it warned and skipped the ID-based credentials, silently provisioning an app that could never authenticate. - Warn about leftover credentials in the other format so they are visible before a security sweep removes them. - Document the subject formats, the AADSTS700213 failure mode, and how to audit credential changes via the Entra audit log. Note: jq's // operator treats false as absent, so use_default must be compared against true directly rather than via (.use_default // true). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0db6138a-d819-4d2f-88c0-a0e0b11ad755
pinodeca
approved these changes
Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The Entra Live Test fails on PRs during
azure/login@v2with:mainand scheduled runs pass; only PRs fail.Root cause
GitHub emits exactly one subject per OIDC token, and its format depends on the repo's subject claim customization:
With
use_default: false, therepo:OWNER/REPO:...form is never emitted. But this script registered both formats unconditionally:So every app it provisioned carried two permanently-dead credentials. A tenant security sweep (
SFIInitiative_July8) later removed them and tookgithub-pr-idwith them:*SFIInitiative_July8to the subjects ofgithub-pr,github-main, andgithub-pr-id, silently breaking themgithub-main-idwas untouched, which is whymainkept working and made this look like a PR-specific misconfiguration rather than a deletion.The credential has been restored out-of-band; this PR stops the script from recreating the problem.
Changes
ghis now a hard requirement. Previously, ifghwas missing or the repo lookup failed, the script warned and skipped the ID-based credentials, happily provisioning an app that could never authenticate.AADSTS700213failure mode, and how to audit credential changes via the Entra audit log.Also corrected a wrong example in the docs: FIC subjects are matched exactly, so the previous
refs/tags/v*wildcard example could never have worked.A jq gotcha worth flagging
The first version of the detection used
(.use_default // true) == false. jq's//treatsfalseas absent, so that yieldstrueforuse_default: false, inverting the check. Verified against the real templates and edge cases:duroxide-pg/duroxide-pg-opt(use_default:false, hasrepository_id){"use_default":true}{"use_default":false,"include_claim_keys":["repo","context"]}{}Testing
bash -nclean.Note for the sister repo
microsoft/duroxide-pg-opthas the identical script and was hit by the same sweep on the same days. Itsgithub-pr-idhas also been restored, and a matching PR follows, including a fix for its script defaulting to this repo'sGH_REPO/APP_NAME.Follow-up (not in this PR)
This was a deliberate, cadenced security sweep, not drift. Re-adding the credential does not exempt the app, so it is worth confirming with the sweep owner whether a bare
...:pull_requestsubject is acceptable or should be narrowed to an environment-scoped subject.