Skip to content

tests/conftest.py: the git() helper gives git no identity, so seven tests that commit through it (stage_unmerged's commit-tree, used by three tests in test_shape_doctor.py; commit in three tests of test_pin_validator.py and one of test_scaffold_e2e.py) fail with Author identity unknown wherever git cannot work one out, while 45 other calls in 18 files pass -c user.name=t -c user.email=t@t #279

Closed

Description

@brettheap

Lane: openreposhape-4 (openRepoShape-4)

Seen by three of this lane's agents today (writers and reviewers running tests/test_shape_doctor.py in a container whose git cannot work out an identity; each worked around it by exporting GIT_AUTHOR_* and GIT_COMMITTER_*). Re-verified on main eb6df75 (d89fffa plus #220, which added tests to tests/test_shape_doctor.py; every line cited was read on eb6df75). The three tests this lane first noticed are the commit-tree ones; reading the helper they go through found four more. Not claimed: why CI's three OSes do not hit it (a runner whose hostname resolves, or a global identity; not checked), and the rest of the suite was not run identity-less (see decision 3).

What is wrong. tests/conftest.py:83-89 git() runs subprocess.run(["git", *args], ...) with no env and no -c. A test that makes a commit through it, without supplying an identity itself, depends on git guessing one from the passwd entry and a hostname with a domain. Where git cannot, the commit fails:

# $U: a clean checkout at eb6df75. $EMPTY: an empty file. The four identity variables and EMAIL are unset; a container hostname with no domain.
GIT_CONFIG_GLOBAL=$EMPTY GIT_CONFIG_NOSYSTEM=1 python3 -m pytest tests/test_shape_doctor.py -q -k unmerged_path
#   FFF    3 failed, 188 deselected in 12.50s
#   E  AssertionError: git commit-tree <sha>^{tree} -p <sha> -m the other side in $T/.../Atlas/code failed:
#   E  Author identity unknown ... fatal: unable to auto-detect email address (got '<user>@<host>.(none)')
#   tests/test_shape_doctor.py:3642 in stage_unmerged  ->  tests/conftest.py:87 in git
GIT_CONFIG_GLOBAL=$EMPTY GIT_CONFIG_NOSYSTEM=1 python3 -m pytest tests/test_pin_validator.py \
    tests/test_scaffold_e2e.py::test_bootstrap_reports_a_pin_that_disagrees_with_a_branch_tip -q
#   4 failed, 16 passed in 7.06s
#   E  AssertionError: git commit -q --allow-empty -m advance the spec leg in $T/.../Atlas/spec failed:  Author identity unknown
# the same two runs with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL exported:
#   3 passed, 188 deselected in 13.09s          20 passed in 7.69s

The seven: test_an_unmerged_path_with_a_file_stage_is_still_judged_as_a_file[file-then-gitlink], [gitlink-then-file] and test_an_unmerged_path_whose_every_stage_is_a_gitlink_is_one_submodule (tests/test_shape_doctor.py:3663 and :3706, both through stage_unmerged, :3620-3660, whose commit-tree is at :3642); test_gitlink_ahead_of_the_pin_is_a_finding, test_a_staged_bump_with_the_pin_moved_to_match_passes and test_a_staged_bump_the_pin_did_not_follow_is_still_a_finding (tests/test_pin_validator.py:42, :45, :68, :86); test_bootstrap_reports_a_pin_that_disagrees_with_a_branch_tip (tests/test_scaffold_e2e.py:332).

Which identity variables they lack: all four. They pass no GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME or GIT_COMMITTER_EMAIL, and no -c user.name or -c user.email. Probed with a bare git commit-tree in a scratch repository: none set is Author identity unknown; the author pair alone is Committer identity unknown; the committer pair alone is Author identity unknown; all four succeed. (Whatever run_script sets does not help: tests/conftest.py:214-217 does env.setdefault of all four, but only into the environment of the SCRIPT it starts, never of git().)

Why. The suite already has two ways to supply an identity, and these seven use neither:

  • -c user.name=t -c user.email=t@t ahead of the verb, through this same helper: 45 calls in 18 files (git("-c", "user.name=t", "-c", "user.email=t@t", "commit", ...), for example tests/test_family.py:88, tests/test_update_shape.py:137, tests/test_bump_leg.py:86). Those two settings supply the author and the committer both, so they work for commit-tree too (checked).
  • The environment: GIT_IDENTITY in tests/test_shape_doctor.py:75-78 (all four variables), which that file's commit_all (:80-88) and six more sites use (:325, :1064, :1260, :1266, :2788, :4590); and conftest.py:325-328, make_source_repo's own four. stage_unmerged sits in the file that defines GIT_IDENTITY and does not use it.

What it should do. No test makes a commit that needs an identity it did not give, so the suite passes on a machine git cannot guess one on. The decisions are the author's:

  1. Where the identity comes from. Either git() supplies it (env={**os.environ, **IDENTITY}, with one IDENTITY dict that replaces the three spellings of the four variables at conftest.py:214-217, :325-328 and test_shape_doctor.py:75-78; an explicit env or -c at a call site must still win, because make_source_repo's tests commit as Source Human on purpose), which fixes the seven and the next one with one change; or the seven call sites take the 45-call convention (-c user.name=t -c user.email=t@t), a smaller change that leaves the helper as the next test's trap.
  2. A guard so it stays fixed: an autouse session fixture (or code at conftest.py import) that sets GIT_CONFIG_GLOBAL to an empty file, GIT_CONFIG_NOSYSTEM=1, and unsets the four variables and EMAIL, so every developer's machine runs as this container does and an identity-less commit fails in the author's own run. Optional; it would also surface any call the survey below missed.
  3. Whether to run the whole suite once with no identity (a full run takes 12-48 minutes on a loaded workstation; not done here). The survey behind "seven" is: every git( call on commit, commit-tree, tag, merge, cherry-pick, rebase and stash in tests/ (the one git("tag", "main", ...) is lightweight and needs no identity), and the three files run above.

How to test. After the change, the two runs above (the four variables unset, an empty GIT_CONFIG_GLOBAL, GIT_CONFIG_NOSYSTEM=1) pass all seven tests; today they fail 3 and 4. With decision 2 the whole suite runs under the guard, so a future test that commits through the helper with no identity fails in every developer's own run and not only on a machine git cannot guess for; that is the regression test for the helper.

Related: #126 (closed: the same file's environment hygiene, run_script blanking inherited SHAPE_PIN_SOURCE_*), tests/test_shape_doctor.py's GIT_IDENTITY and commit_all (the precedent in the file).

Activity

  1. brettheap commented on Oct 12, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoShape-4, session 3431c370-df80-4c11-a041-41bce42d8b38@Eagle, 2026-10-12T00:41:29Z, for #279

    Logged in lanes/log/openRepoShape-4.md at 44166c853cb387045571bab1d914d348523fb4b6.

    The three reads (lane-collision-protocol Rule 1):

    1. existing `CLAIMED —` comments on opensoft/openRepoShape#279:
       none
    2. `gh pr list --repo opensoft/openRepoShape --state all --search "#279"`, kept where the row or its body names `#279`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoShape` branches naming `279` as a whole token:
       none
    
  2. added 3 commits that reference this issue on Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions