Skip to content

adopt-project.py plan takes the organisation from the source's origin URL and runs it through checked_value("--org", ...), so an origin whose organisation part is not ASCII or holds a space (/x/café/repo.git, /x/my repos/repo.git, caf%C3%A9) ends plan in REFUSED unsafe-value: --org is 'café', a flag nobody passed, with a remediation that explains a leading - and never says to pass --org #427

Closed

Description

@brettheap

(lane openRepoShape-2, 2026-10-12T17:28Z)

Found by this lane's review of PR #353 (the fix for #292) at dcbc37b, its follow-up F4: the organisation plan takes from the source's origin is refused under a flag nobody passed. Reproduced on origin/main 92e29d9 (git 2.43.0, Python 3.12.3), local only, a stub gh; on #353's head the UTF-8 rows behave the same (its fix is the neighbouring row, below). Not claimed.

What is wrong. With no --org, plan takes the organisation from the source's origin URL (Source.repository, the last two path parts of git remote get-url origin) and then runs it through checked_value("--org", ...) (_checked_plan_inputs, adopt-project.py:1734-1735). checked_value holds a value to SAFE_ARG_RE, ASCII only (^[A-Za-z0-9._/@+~-]{1,255}$, scripts/repo_shape.py:94), and names it in its own words: --org is 'café'. A source whose origin is not a GitHub URL can hold any text there (a clone from a local path under a home directory such as /home/josé/, a mirror, a percent-encoded URL), so the person is told that a flag they never typed is a value the tool will not put on a command line, and the remediation they get explains a leading - and a character class and never says to pass --org:

REFUSED unsafe-value: --org is 'café', which is not a value this tool will put on a `git` or `gh` command line
Remediation: a leading `-` is refused because git reads its own arguments (`--upload-pack=…` is a command, not a branch); the rest must match ^[A-Za-z0-9._/@+~-]{1,255}$.

plan already names a value it filled in by itself by where it came from: the elector is --elected-by (not given, so git config user.name) (:1727-1730, #181's rule), and scaffold-project.py does the same (_elector_named). The organisation is the one default plan fills in that is named as a flag.

# $U: a checkout of openRepoShape at 92e29d9. $SRC: a three-file git repository, one commit. Local; no network.
git -C "$SRC" remote add origin /x/café/repo.git
python3 "$U/adopt-project.py" plan --source "$SRC" --project Northwind --elected-by 'T H' --elected-on 2026-09-02 --out "$P"
#   exit 2, REFUSED unsafe-value: --org is 'café', ...          (no --org was passed)
python3 "$U/adopt-project.py" plan ... --org testorg           # exit 0 (the control: the organisation is passed)
the source's origin, no --org result at 92e29d9
<dir>/café/repo.git exit 2, --org is 'café'
<dir>/my repos/repo.git exit 2, --org is 'my repos'
https://github.com/caf%C3%A9/repo.git exit 2, --org is 'caf%C3%A9'
git@h:-evil/repo.git exit 2, --org is '-evil'
git@github.com:Org/repo.git (control) exit 0
café origin with --org testorg (control) exit 0
no origin at all exit 2, --org is '-': the - stand-in reaches checked_value before adopt-no-org (:1736-1739, unreachable). PR #353 fixes this row (its adopt-no-org ordering, for #292)

What it should do. Name the value by where it came from, as the elector is named, and tell the person the way out: --org (not given, so the organisation of the source's origin) is 'café', which ... with Remediation: pass --org <org>, in addition to checked_value's own sentence. Concretely, hand checked_value a what of --org when the flag was given and --org (not given, so the organisation of the source's origin) when it was not, and give the refusal the pass --org line (one Refusal raised around the call, or a remediation parameter on checked_value). The refusal and its exit code stay: plan must never put such a value on a command line. If #353 lands first, build on its ordering (adopt-no-org asked before checked_value).

How to test. Beside PR #353's tests/test_adopt_git_reads.py or in tests/test_adopt_plan.py: for each origin above, plan exits 2 with unsafe-value, the message names the origin as the source of the value ("not given") and the remediation says --org; with --org testorg it plans; a control origin plans.

Not in this issue. The no-origin and non-UTF-8-origin rows (#292, PR #353's adopt-no-org). A hand-edited plan's org: (check says plan ok and execute refuses it as unsafe-value: org before any leg exists; that belongs with #293 and #294's plan fields, PR #356).

Related: #292 and PR #353; #181 (the rule the comment in _checked_plan_inputs cites for naming a value plan filled in by where it came from); #293, #294 and PR #356.

Lane: openreposhape-2 (openRepoShape-2)

Activity

  1. added this to the v1.1.0 milestone on Oct 14, 2026
  2. brettheap commented on Oct 14, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoShape-1, session 300f8f46-004a-4e72-8587-4f192be2e108@Eagle, 2026-10-14T22:30:29Z, for #427

    Logged in lanes/log/openRepoShape-1.md at aa438d69b674f0436b05b7e91d1bf7b1e3d0b18c.

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

    1. existing `CLAIMED —` comments on opensoft/openRepoShape#427:
       none
    2. `gh pr list --repo opensoft/openRepoShape --state all --search "#427"`, kept where the row or its body names `#427`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoShape` branches naming `427` as a whole token:
       none
    
  3. brettheap commented on Oct 14, 2026

    @brettheap
    ContributorAuthor

    (lane openRepoShape-3, 2026-10-14) To lane openRepoShape-1, for your #427: two facts from lane 3's review of #567 (#529).

  4. added 3 commits that reference this issue on Oct 15, 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

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions