Repository navigation
Classify a fork by its parent's topics - #23
Merged
matt-edmondson merged 1 commit intoSep 16, 2026
Merged
Conversation
A fork does not inherit its parent's topics. ktsu-dev/winget-pkgs, a fork of microsoft/winget-pkgs, is the proof to hand: the parent carries topics, the fork's repository object has none at all. detect required the dotnet topic, so as written it failed every fork of every ktsu repository -- and failed it by telling a stranger to add organization metadata they do not own. Before shared CI a fork got a complete local dotnet.yml and simply worked, so this was a regression I introduced. Borrow the parent's topics when the repository is a fork and has no dotnet topic of its own. A fork then classifies as whatever it was forked from. The marker-file check still applies and files are inherited, so nothing is loosened about what a fork has to actually be; a fork that sets its own topic is taken at its word and the parent is never consulted. Nothing else needed a fork gate. Checking rather than assuming turned up one already in place for each concern: ktsubuild is passed EXPECTED_OWNER and decides should_release itself, every Sonar step is gated on SONAR_TOKEN being non-empty, and the build tool installs from public NuGet without a secret. A second owner check would have duplicated deliberate existing intent. Ten cases were run against the extracted script with a stubbed gh: upstream public and private, a fork inheriting its parent's topic, a fork with its own topic (parent not consulted), a fork whose parent is unreadable, a fork with no parent field, a fork inheriting a topic but lacking global.json, and the topic-without-global.json case that blogs and ktsu.dev would hit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014RABe2NufFc9hwm94iB3Rf
matt-edmondson
deleted the
claude/dependabot-ci-workflow-rollout-fbrhdn
branch
September 16, 2026 10:55
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.
The problem
A fork does not inherit its parent's topics.
ktsu-dev/winget-pkgsis the proof to hand — a fork ofmicrosoft/winget-pkgs, where the parent carries topics and the fork's repository object has none at all.detectrequired thedotnettopic, so as written it failed every fork of every ktsu repository, and failed it like this:A stranger who forks
Sortingto fix a bug gets told to add organization metadata they do not own. Before shared CI a fork got a complete localdotnet.ymland simply worked, so this is a regression I introduced.The fix
Borrow the parent's topics when the repository is a fork and has no
dotnettopic of its own. A fork then classifies as whatever it was forked from.The marker-file check still applies, and files are inherited, so nothing is loosened about what a fork has to actually be. A fork that sets its own
dotnettopic is taken at its word and the parent is never consulted. A parent that cannot be read — deleted, or private to someone else — is not fatal on its own; it falls through to the existing checks, with a fork-specific message.What I did not add, and why
I proposed also gating publish and Sonar on the owner. Checking rather than assuming turned up one guard already in place for each concern:
ktsubuildis passedEXPECTED_OWNER: ktsu-devand decidesshould_releaseitselfenv.SONAR_TOKEN != '', which is empty in a forkdotnet tool install ktsu.KtsuBuild.Toolfrom public NuGet, no secretdotnet-private.ymladditionally hard-codesshould_release=falseunder a pre-release hold, and its commented-out computation already spells out the same idea —isOfficial = (not isFork) and isExpectedOwner.A second owner check would have duplicated deliberate existing intent in a third place. So a forker gets discovery, build and tests across all three platforms, and the steps needing ktsu's secrets skip themselves.
Testing
The
classifyscript was extracted from the YAML and run against a stubbedgh— ten cases, including the ones that only exist for forks:dotnettopic +global.jsonstack=dotnetstack=dotnet,private=truedotnetstack=dotnetdotnettopic.parentfieldglobal.jsondotnettopic, noglobal.json(blogs,ktsu.dev)global.jsonactionlint1.7.7 withshellcheckclean;markdownlint-cliclean.🤖 Generated with Claude Code
https://claude.ai/code/session_014RABe2NufFc9hwm94iB3Rf
Generated by Claude Code