Repository navigation
setup-project.py: the credential-helper warnings speak where an insteadOf rule sends github.com over ssh, or a URL-scoped helper answers, and the check reads ~ files git does not read #1013
Description
Goal: setup-project.py's two credential-helper [??] warnings (the no-helper one, and #1008's store-holding-no-githubproxy.fjygbaifeng.eu.org-login one) stay silent on a machine where git will not ask a credential helper at all (a url.<base>.insteadOf rule sends github.com over ssh) or where a helper under a URL-scoped key does answer, and the check finds the ~ files store reads by asking git for them, so a HOME git cannot expand no longer sends it to files git never reads.
Filed by lane openRepoShape-3, from RV1008's review of #1008 (issuecomment-6278166602).
State. Read at origin/main 7fa60a57 and at #1008's head b2dbc8b2 (open, a draft, found READY by RV1008 with no MUST). #1008 closes #992 and is not merged, so the store warning, and with it NIT-1 to NIT-5 below, exist only at that head; the line numbers are #1008's, in setup-project.py and tests/test_setup_project_py.py. SHOULD-1's no-helper half is at main too, where the same code is _credential_helper_configured (:1288) and its warning (:1333). This follows #1008 and does not block it.
_credential_helpers(:1289) asks git for two keys only,credential.https://githubproxy.fjygbaifeng.eu.org.helperandcredential.helper(git config --get-all,:1303), from the folder the run starts in. It never asks which URL git will use for github.com._why_no_login(:1380-1406) says there is no login when that list is empty (the no-helper sentence, byte for byte as at main) or when every helper isstoreand no file of theirs holds a github.com login._check_credential_helper(:1409) prints the[??]and, at a terminal, offersgh auth setup-git. Onlyopts.local_modereturns before it._store_files(:1310) builds the two filesstorereads fromos.environ.get("HOME") or os.path.expanduser("~")(:1326) and$XDG_CONFIG_HOME, or~/.configwhere that is unset or empty.- The scaffold supports the ssh machines:
SSH_KEY_CLAUSE(scaffold-project.py:686at main) and the docstring of_exists_remedy(scaffold-project.py: a--reuse-empty-repore-run can stop at a git, ssh or helper prompt on its pushes and seed fetch, and an ssh-rewrite operator's refusal gives git's generic line and a remedy that does not apply #915) say that where aninsteadOfrule sendshttps://github.com/over ssh, git logs in with an ssh key, andgh auth setup-gitdoes nothing for it. The preflight's remedy is that very command.
What happens. Three groups. Exit codes and steps are unchanged in every row; what differs is the [??] line and, at a terminal, its offer. Each machine below is a hand-made git config.
RV1008's SHOULD-1, both warnings. With url.git@github.com:.insteadOf https://github.com/ in git's config, git ls-remote --get-url https://github.com/demoorg/x.git prints git@github.com:demoorg/x.git, so the push goes over ssh and git never asks a credential helper. Both warnings still speak there (RV1008's rows, read again by lane 3 at main 3864b18c and at #1008's head b2dbc8b2, git 2.43.0, --preflight exit 0 each time):
the machine main #1008 head
insteadOf rule, no helper [??] [??], the same line byte for byte
insteadOf rule, `store` over an empty
~/.git-credentials silent [??] and the offer
So the no-helper warning has always been blind to an insteadOf rule, and #1008's store warning adds a second false [??] for the same machines. A rule keyed to one org (url.git@github.com:demoorg/.insteadOf https://github.com/demoorg/) rewrites only that org: measured, git ls-remote --get-url gives git@github.com:demoorg/x.git for demoorg and https://github.com/other/x.git for other. A url.<base>.pushInsteadOf rule alone leaves --get-url at the https:// URL.
RV1008's NIT-1, a URL-scoped helper. With store in credential.helper and a helper under another spelling of the scoped key, credential.https://github.com/.helper (with the trailing slash), git asks that helper: measured, git credential fill with the prompt off exits 0 and prints a login from a made-up helper, where over store alone it exits 128 with fatal: could not read Username for 'https://github.com': terminal prompts disabled. The check reads only credential.https://githubproxy.fjygbaifeng.eu.org.helper (no slash), so it sees store alone: main silent, #1008's head [??] over an empty store file. Lane 3's row at both trees reads the same. #1008's decision 1 says only that such a helper "stays invisible to both warnings", which for the head is a new false [??], since main was silent over store there. git config --get-urlmatch credential.helper https://github.com/demoorg/x.git prints only the best match (the scoped helper, not store), so it is no drop-in fix.
RV1008's NIT-5, HOME unset and Git for Windows' own HOME. With HOME unset git cannot expand ~: git -c <k>='~/.git-credentials' config --type=path --get <k> prints fatal: failed to expand user dir in: '~/.git-credentials' and exits 128 (lane 3 read the same), so git's store reads no ~ file at all. The check falls back to os.path.expanduser("~") (:1326), the passwd home: lane 3's --preflight with HOME unset and store over nothing names <passwd home>/.git-credentials and <passwd home>/.config/git/credentials, two files git never reads there. Git for Windows also chooses its own HOME (HOMEDRIVE and HOMEPATH), which the check does not read; #1008 said that was not measured, and it is not measured here either.
Also in this issue, three smaller ones from the same review.
- NIT-2, a false docstring sentence.
:1390says "Any other helper beside them, or a file this cannot read, may answer", which is false of a file git cannot open;:1367-1368(_holds_a_github_login: "None where it cannot be read here: a file this can say nothing about") is where the reason belongs. RV1008 measured git'sstoretreating a file it may not open (EACCES, a mode-000 file) as empty:credential-store getexits 0 with no password andfillexits 128; a folder where the file goes makes git die. Either way the push fails. setup-project.py: astorecredential helper holding no login for github.com gets the preflight's[??]and itsgh auth setup-gitoffer, as a machine with no helper does, and the check no longer says every configured helper answers git's question for github.com (#992) #1008's decision 4 gives only "the check can say nothing about a file it cannot read" as its reason, which is incomplete. The silence is right and stays; the sentence is not. - NIT-3, a 106-character docstring line.
:1416, in_check_credential_helper, is a rewrap miss (an offer of the one command that fixes it.then_why_no_loginnames the two such machines it can see ...). The repository sets no line-length rule, and it is the one line over 79 columns in:1289-1470, the whole of the credential check. RV1008 ruled it a NIT for a follow-up, to be done with NIT-2's rewording and not worth a re-gate alone. - NIT-4, a test gap that predates setup-project.py: a
storecredential helper holding no login for github.com gets the preflight's[??]and itsgh auth setup-gitoffer, as a machine with no helper does, and the check no longer says every configured helper answers git's question for github.com (#992) #1008.tests/test_setup_project_py.py:1578-1588(_a_credential_store) puts_Runs(:1249), which matches a command by substring, in place ofrun, so no credential row asks real git at which scope a helper is read. RV1008's mutant R1, helpers read with--globalonly, survives-k credential(41 passed), the whole file (286 passed) andtests/test_setup_project_dry_run_offers.py(13 passed). RV1008 measured the right answer forstorein the system config (the[??]over an empty file, silence over a login) and no row of the file holds it.
Evidence.
- RV1008's review of setup-project.py: a
storecredential helper holding no login for github.com gets the preflight's[??]and itsgh auth setup-gitoffer, as a machine with no helper does, and the check no longer says every configured helper answers git's question for github.com (#992) #1008: setup-project.py: astorecredential helper holding no login for github.com gets the preflight's[??]and itsgh auth setup-gitoffer, as a machine with no helper does, and the check no longer says every configured helper answers git's question for github.com (#992) #1008 (comment). It found setup-project.py: astorecredential helper holding no login for github.com gets the preflight's[??]and itsgh auth setup-gitoffer, as a machine with no helper does, and the check no longer says every configured helper answers git's question for github.com (#992) #1008 READY with no MUST and asked for this follow-up for SHOULD-1 ("fix both in a follow-up"), carried NIT-1 into it, and ruled NIT-3 a NIT for a follow-up. - RV1008's measurements:
--preflightfrom a folder that is not the checkout, insideenv -i, under a stubghthat answers only--versionandauth statusand exits 97 on anything else,GH_TOKEN=bogus, an emptyGH_CONFIG_DIR,GIT_SSH_COMMAND=false, and system config, global config andHOMEin scratch. Exit 0 at main and at the head in every case. - Lane 3 ran the same kind of machine again for this issue (the table above, the URL-scoped row, and
HOMEunset) at main3864b18cand at setup-project.py: astorecredential helper holding no login for github.com gets the preflight's[??]and itsgh auth setup-gitoffer, as a machine with no helper does, and the check no longer says every configured helper answers git's question for github.com (#992) #1008's head, and read each as RV1008 did. - setup-project.py: a
storecredential helper holding no login for github.com gets the preflight's[??]and itsgh auth setup-gitoffer, as a machine with no helper does, and the check no longer says every configured helper answers git's question for github.com (#992) #1008's body names the four decisions; the README (:231,:406,:470) and the handbook (:904-909) still read true at its head, since they say the offer is for "whichever is missing".
Direction. As RV1008 gives it.
- SHOULD-1, both warnings. Ask
git ls-remote --get-url(local, no network) for the github.com URL the run will give git, and skip both warnings where the answer does not start withhttps://. Ask with the org--orgnames (opts.org) where the run has one: a rule keyed tohttps://github.com/<org>/answers for that org only (measured above). ApushInsteadOfrule alone does not change the answer, and the warnings stay as they are there; a row pins that. - NIT-1.
--get-urlmatchis no drop-in. Either read everycredential.<url>.helperkey whose URL matches github.com (git config --get-regexp) and count those helpers with the other two keys, or stay silent where such a key exists; the writer chooses, and a row pins the choice. Say in_check_credential_helper's docstring which spellings of the key it reads. - NIT-5. Ask git for each
~path:git -c <k>='~/.git-credentials' config --type=path --get <k>, and the same for~/.config/git/credentialswhereXDG_CONFIG_HOMEis unset or empty. Measured: withHOME=/fup1008/homeit prints/fup1008/home/.git-credentials; withHOMEunset it exits 128, which means "git reads no~file", so the check names none. That also covers Git for Windows' choice ofHOME. - NIT-2. Reword
:1390, and give:1367-1368the reason, to say that git'sstorereads a file it may not open as empty and dies on a folder, so this check cannot say what such a file holds and says nothing. Keep the silence. - NIT-3. Rewrap
:1416in the same edit. - NIT-4. Add one real-git row:
GIT_CONFIG_SYSTEMholdingcredential.helper=store, an empty scratchHOME, a global config without it, asserting the[??]. - No code outside
setup-project.pyand its test file, no flag or--helpline:AGENTS.md,docs/cli.mdand the handbook stay as they are, andsetup-project.pyis not a pinned copy, so no project re-pins. Re-read the README and handbook lines above after the fix, since a silent case is added to "whichever is missing".
Verify.
--preflightat a real git, run from a folder other than the checkout, under a stubghthat exits 97 on all but--versionandauth status, withGH_TOKEN=bogus, an emptyGH_CONFIG_DIR,GIT_SSH_COMMAND=false, and system config, global config andHOMEin scratch. Each row exits 0 and prints the following:url.git@github.com:.insteadOf https://github.com/with no helper: no credential[??], no offer. The same machine without the rule: the no-helper sentence, byte for byte as today.- The same rule with
storeover an empty~/.git-credentials: no[??], no offer. Without the rule: thestoresentence of setup-project.py: astorecredential helper holding no login for github.com gets the preflight's[??]and itsgh auth setup-gitoffer, as a machine with no helper does, and the check no longer says every configured helper answers git's question for github.com (#992) #1008's head, byte for byte. - A rule keyed to
https://github.com/demoorg/only: with--org demoorg, silent; with--org other, the[??]of today. storeincredential.helperplus a helper that prints a made-up login undercredential.https://github.com/.helper: silent (or whatever row the writer pinned in Direction 2).HOMEunset withstore: the[??]names no~file, and the row pins what it says where no file is left to name.HOMEset to a scratch folder: it names that folder's files, as today.
- In
tests/test_setup_project_py.py: a row per case above, and the NIT-4 real-git row, which fails with RV1008's mutant R1 (helpers read with--globalonly). git grepofsetup-project.pyfor "a file this cannot read, may answer" finds nothing, and no line of:1289-1470is longer than 79 columns.tests/test_setup_project_py.py,tests/test_setup_project_dry_run_offers.py, the docs guards (tests/test_agents_md_codes.py,tests/test_cli_reference.py,tests/test_update_add_codes_documented.pyandtests/test_repo_hygiene.py) andtests/test_no_auto_maintenance.pypass, one file at a time under a stubgh.
Size. Small to medium: one git ls-remote --get-url call and an early return in _check_credential_helper, one git config --type=path call in _store_files, two docstring edits and a rewrap, and about seven test rows. Medium if NIT-1 reads every URL-scoped key.
Lane: openreposhape-3 (openRepoShape-3)
Activity
setup-project.py: a `store` credential helper holding no login for gi…
brettheap commentedon Oct 19, 2026
CLAIMED — lane openRepoShape-3, session b30e8b49-f249-4668-adb1-1dbfa93c09e1@Eagle, 2026-10-19T22:45:10Z, for #1013
Logged in
lanes/log/openRepoShape-3.mdat40f29b5c9e0809a041d2441a4ca078b9efc95177.The three reads (lane-collision-protocol Rule 1):
setup-project.py: a url git cannot answer for, an empty url-scoped `h…
tests/test_setup_project_py.py: the rule comments list the two new ru…
setup-project.py: the credential-helper `[??]` and the `gh auth setup…