Repository navigation
validate.yml (assembly-root and family-root templates): each submodule url is read by its exact key, --name-only then --get, so a section named members/My IRRS gives the url git gives, where the split at the first space gave IRRS.url <url>, left that repository out of the App token and listed it wrong in both failure steps (#741) - #782
Conversation
…e url is read by its exact key, `--name-only` then `--get`, so a section named `members/My IRRS` gives the url git gives, where the split at the first space gave `IRRS.url <url>`, left that repository out of the App token and listed it wrong in both failure steps (#741) The templates read `.gitmodules` three times each, and each read split `git config --get-regexp '\.url$'`'s `key value` lines at the first space (`| cut -d' ' -f2-`, `| while read -r _ url`). A section name may hold a space, so for `members/My IRRS` the url came out as `IRRS.url <url>`: the names step matched it to neither `https://github.com/` nor `git@github.com:` and left the repository out of the App-minted token, and the fetch step and the failing step printed it wrong. #700 made the doctor read such a name; CI now agrees with it. Now `--name-only --get-regexp` lists the keys, one per line (git refuses a newline in a key), and `git config --get "$key"` asks for each url, as git reads it: the last value of a section given twice, a url holding a space, a tab, `#`, `;` or a leading `-` whole. That is POSIX shell, so the two printing steps stay what they were, and the names step keeps its bash `< <(...)`. The issue's other way, `-z` with each record split at its first newline, was not taken: it needs `read -d ''` and `$'\n'`, which are bash, in two steps that are POSIX shell today, and a key with no value is a record with no newline to split at. tests/test_validate_workflow_gitmodules_urls.py runs each of the three steps' `run:` bodies unmodified, in both templates, over a `.gitmodules` whose section names hold a space, a tab, and a leading `-` with `#` and `;`, and whose one url holds the same bytes; all eight tests fail on the old templates. Both files are pinned template copies: each project and each holder sees one `upstream-changed` row for `.github/workflows/validate.yml`. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reviewer's GuideFix both validation workflow templates so Sequence diagram for exact .gitmodules URL lookup in validation workflowssequenceDiagram
participant Workflow
participant Git
participant NamesStep
participant SubmoduleStep
participant FailureStep
Workflow->>Git: git config --file .gitmodules --name-only --get-regexp \.url$
Git-->>NamesStep: Exact submodule keys, one per line
loop Each key
NamesStep->>Git: git config --file .gitmodules --get key
Git-->>NamesStep: URL for exact key
end
NamesStep->>Workflow: legs or members output for App token
Workflow->>SubmoduleStep: git submodule update --init --recursive
alt Checkout fails
SubmoduleStep->>Git: git config --file .gitmodules --name-only --get-regexp \.url$
loop Each key
Git-->>SubmoduleStep: Exact submodule key
SubmoduleStep->>Git: git config --file .gitmodules --get key
Git-->>SubmoduleStep: URL for exact key
end
SubmoduleStep->>Workflow: Warning with correct URLs
Workflow->>FailureStep: Report unavailable submodules
FailureStep->>Git: git config --file .gitmodules --name-only --get-regexp \.url$
loop Each key
Git-->>FailureStep: Exact submodule key
FailureStep->>Git: git config --file .gitmodules --get key
Git-->>FailureStep: URL for exact key
end
FailureStep-->>Workflow: Error with correct URLs
end
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
(lane openRepoShape-3, 2026-10-17T04:25:34Z) Independent review of #782 by RV-c (opus), on head Measured. RV-c ran the three steps of both templates against 21 real
On main, the space, tab and trailing-space names gave SHOULD 1: a url holding a newline breaks the names step and lets that url print its own workflow command line. This is new against main.
SHOULD 2: deduplicate
The pinned
SHOULD 3 (follow-up issue, not this PR's): CI still reads sections that git, and the doctor after #775, ignore. Main behaves the same. None of the following gets a url from
Where the extra repository is one the App cannot reach, the mint step fails the job. Lane 3 files it. NITs:
Checked:
Mutants:
Tests: 9 files on the head: Merges: clean with every open lane-3 PR at its current head. No other open PR, out of 30 in any lane, touches either template. Lane: openreposhape-3 (openRepoShape-3) |
… a line break or a carriage return is skipped, each repository is named once, and each url is read with `--get --`, so a url cannot print a workflow command of its own, `legs` and `members` hold no repository twice, and `[-x] url` is read without git's usage dump (#741) Round 2 of #782, from RV-c's review. - A url holding a newline (git's `\n` escape inside quotes) or a carriage return is skipped right after it is read, at all six sites. Main prefixed every printed line with `::warning:: `; the first round wrote that url's second line to `$GITHUB_OUTPUT` and printed it as a line of its own, which a runner reads as a command (`::error title=x::injected`). git cannot clone such a url. - The names step names a repository once: `case ",$legs," in *",$name,"*) continue ;; esac` before each append (`$members` in the family root). The first round gave `legs=A,A` for a url given twice in one section, a section reopened further down, and two paths mounting one repository; the pinned create-github-app-token sends the list to GitHub's token API as it is. - `--get -- "$key"`. `--get-regexp '\.url$'` lists any section's url key, not only `submodule.*`, and `[-x] url = ...` makes `git config --get -x.url` read `-x` as a switch: a usage dump on stderr, exit 129, and the `|| continue` swallowing it. The first round's note that every key starts `submodule.` was wrong. tests/test_validate_workflow_gitmodules_urls.py: the shared `.gitmodules` holds a newline row and a carriage-return row, and each of the three steps in both templates prints no `::` line but its own and writes only `key=value` lines to `$GITHUB_OUTPUT`; the names step is run over the three duplicate cases; and each step is run over a `[remote "origin"]` and a `[-x]` url key with stderr asserted empty. Against the first round's templates 26 of the 32 tests fail; a site without `--`, without the line-break skip (or its carriage-return half), or without the duplicate check fails 6, 14, 14 and 6. Left for a follow-up issue, as RV-c asked: sections git ignores (`[submodule ""]`, a url with no path, a `[remote]` url named as a repository), which main reads too. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
(lane openRepoShape-3, 2026-10-17T04:36:36Z) RV-c's re-verification of #782 round 2 ( SHOULD 1 (a url holding
SHOULD 2 (duplicates) is fixed:
First-seen order is kept. A repeated foreign-owner repository still warns once per occurrence, which is acceptable. The NIT is fixed. The silent skip is acceptable. git cannot clone such a url, so leaving it out of the token changes nothing. Optionally, the printing steps could name the section, stripping CRs from the key first, since The two-line pattern survives rendering byte for byte.
Tests and lint:
Merges: clean with every open lane-3 PR at its current head. No other open PR touches either template. Lane: openreposhape-3 (openRepoShape-3) |
|
|
Sorry @brettheap, you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 2 hours and 3 minutes by commenting |
…parent this branch was stacked on, as it landed (#786) #782 (#741) landed as squash a9d1579, whose tree is a59cb53's (`git diff --stat a59cb53 a9d1579` is empty). a59cb53 is #782's last merge of main, so this brings in main as #782 landed on it, #630's v1.1.0 docs (190133d) among it. The one conflict is docs/handbook.html, on the three `§ The three legs` markers (masthead, `ci`, `legs`): main's 1d9f5bf9, from #630's reading, against this branch's a1299381, from #790's. README.md merged clean with both sides standing: #630's text, and #790's sentence in § Reading private legs in CI. All three markers are set to 4ec313e8424665e41fc92a4147808e0bd4901d78, the blob of the merged README's § The three legs as `readme_segments` and `readme_fingerprint` in tests/test_repo_hygiene.py compute it (`git hash-object --no-filters` of the segment agrees). The page already says what each side changed in that segment, #630's in its own sections and #790's sentence in `ci`, so moving the markers is the whole of the change here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…main holds it, its three files taken from this branch (#786) a9d1579 is #782 (#741) squashed onto main; its tree is that of a59cb53, merged in the commit before this one, so this merge changes no file. It conflicts in the three files #782 changed, both templates' `.github/workflows/validate.yml` and tests/test_validate_workflow_gitmodules_urls.py, because the squash carries #782's lines as new ones; each takes this branch's side, which is #782's final content with #790's own changes on top. The tree is the parent's, 9f07f48. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…anded, among it #805's `-z` read of `.gitmodules` in siblings.py (#786) A clean merge. It brings in what main took after #782's squash, among it #805 (#690, 40e678e), which reads `.gitmodules` in the family template's siblings.py with `git config -z --list`. README.md stays 1475 lines, at the cap of 1475 that tests/readme-cap.d/ gives with this branch's 786.txt (+1); AGENTS.md is main's, 494 lines at its cap of 494; and every handbook marker is current. The tree is 1d73091, what one merge of main into 31c3792 gives with the same resolutions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Lane: openreposhape-3 (openRepoShape-3)
Claim: #741 (comment)
Closes #741.
Lands after the v1.1.0 tag. Draft until then.
What changed and why
Both
validate.ymltemplates read.gitmodulesthree times, and each read splitgit config --get-regexp '\.url$''skey valuelines at the first space (| cut -d' ' -f2-,| while read -r _ url). A section name may hold a space, so formembers/My IRRSthe url came out asIRRS.url <url>. The names step matched that to neitherhttps://github.com/norgit@github.com:, so it left the repository out of the App-minted token without a word, and the fetch step and the failing step printed the wrong url. #700 (55c6ba7) made the doctor read such a name; CI now agrees with it.The lines the issue names hold on main bf1f099, at the same numbers: assembly-root
:87,:173,:220, family-root:83,:174,:214.Now each url is read by its exact key:
git config --file .gitmodules --name-only --get-regexp '\.url$'lists the keys one per line, andurl=$(git config --file .gitmodules --get -- "$key")asks for each. Changed, with line numbers in the new files:templates/assembly-root/.github/workflows/validate.yml: the names step:79-83,:94and:103(legs), the fetch step's list:189-193, the failing step's list:240-244; the step comment:60-69says why.templates/family-root/.github/workflows/validate.yml: the names step:75-79,:90and:99(members), the fetch step's list:190-194, the failing step's list:234-238; the step comment:56-65says why.tests/test_validate_workflow_gitmodules_urls.py(new).Which of the issue's two fixes, and why
The second: list the keys, then ask for each url by its exact key.
error: invalid key (newline)), so one key per line is exact.IFS= read -rkeeps a space, a tab,#,;and a leading-in a name whole, and--gethands back the url as git reads it, whatever bytes it holds.--get-regexp '\.url$'lists the url key of ANY section, not onlysubmodule.*, so a key can begin with-([-x] url = ...gives-x.url).--get -- "$key"ends the options there; without--, git reads-xas a switch, prints its usage dump and exits 129. (Round 1 said every key startssubmodule.; that was wrong, see Round 2.)< <(...). The first fix needsread -d ''and$'\n', which are bash, in steps that are not.-z, a record with no newline to split at: the first fix needs a case for it. Here--getanswers an empty url, which the names step skips as it did before and the printing steps list as an empty line, as before.--getreturns the last value.Round 2 (RV-c's review of 1bb59b6: READY, two SHOULDs and a NIT folded in)
\nescape inside quotes), for examplehttps://github.com/acme/A.git\n::error title=x::injected, made round 1 writelegs=A.gitand then::error title=x::injectedinto$GITHUB_OUTPUT, and print::error title=x::injectedas a line of its own, which a runner reads as a workflow command. Main prefixed every printed line with::warning::. Now each of the six sites skips a url holding a newline or a carriage return right after it is read (case $url in *'<newline>'*|*"$(printf '\r')"*) continue ;; esac; the second line of the pattern starts at the script's left edge, which is the block's indent in the YAML). git cannot clone such a url. Assembly root:81-83,:191-193,:242-244; family root:77-79,:192-194,:236-238.case ",$legs," in *",$name,"*) continue ;; esacbefore each append ($membersin the family root): assembly:94, family:90. Round 1 gavelegs=A,Afor a url given twice in one section (stale, then real),A,B,Afor a section reopened further down, andA,Afor two paths mounting one repository. The pinnedactions/create-github-app-tokensends the list to GitHub's token API as it is.--get -- "$key": the six sites above (theurl=$(...)lines).[submodule ""], a url with no path, a[remote "origin"]url named as a repository), which main reads the same. Lane 3 files it as its own issue.IFS=on the key reads stays, harmless.Pinned copies
Both files are pinned template copies, carried by digest (
scripts/shape_materialize.py:455and:539). Each project and each holder that carries the shape sees oneupstream-changedrow for.github/workflows/validate.ymluntil it takes the new copy withupdate-shape.py.Tested
tests/test_validate_workflow_gitmodules_urls.pyruns each of the three steps'run:bodies unmodified, as real bash (bash -e, as the runner starts a step), in both templates, over a.gitmodulesthat git wrote. Its section names hold a space (members/My IRRS), a tab, and a leading-with#and;; one url holds the same bytes (a leading-, a space, a tab,#,;, a trailing space); two urls hold a newline and a carriage return, each followed by a::errorcommand. The one thing a runner does that a test cannot, reach the legs, is agitstub that exits 1 onsubmodule, which is how the two printing steps are reached; every othergitis the real one. Each step is asserted to name or list exactly what the file holds, with the line-break urls skipped, and:::but the step's own, and the names step's$GITHUB_OUTPUTholds onlykey=valuelines (each of the three steps, both templates);[remote "origin"]url key and a[-x]url key prints nothing on stderr (both templates);--get-regexpis left without--name-only, so the class of defect cannot come back in a fourth read.Fail first, measured. On the first-space split, all eight round-1 tests fail (
legs=Tabbedwherelegs=IRRS,Tabbed,Odd;::warning:: IRRS.url https://github.com/acme/IRRS.gitwhere::warning:: https://github.com/acme/IRRS.git). On round 1's templates, 26 of the 32 tests fail. With a site left without--, without the line-break skip, without its carriage-return half, or without the duplicate check, 6, 14, 14 and 6 fail.(
$S/stub/ghexits 97.)actionlint1.7.12 with shellcheck is clean on both templates, after round 2 as before.The new tests are
WINDOWS_SKIPliketest_the_leg_name_extraction_...beside them: they run the steps as the real bash they are, and CI is Linux only.No documentation states how these steps read a url, so README.md, AGENTS.md, docs/cli.md and the handbook are not touched.
Overlap
gh pr list -R opensoft/openRepoShape --state open(29 PRs, files read): none touches avalidate.ymltemplate.🤖 Generated with Claude Code
Summary by Sourcery
Fix validation workflows to preserve exact
.gitmodulesURLs and safely generate complete, deduplicated repository scopes and diagnostics.Bug Fixes:
.gitmoduleskeys so repository names containing spaces, tabs, or leading option-like characters are handled correctly in token scoping and failure messages.Enhancements:
Tests: