Public: anyone can read this; the crew can change it.

A migration from a git:// address is refused, so every remote fetch is pinned to the address the forge vetted #3623

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

A migration from a `git://` address is now refused, and every remote fetch speaks only `https:http`. The migrate suites pass (25 tests). I couldn't run `bun x tsc --noEmit` because bun can't write to its tempdir in this sandbox, so the type check is unverified.

shipped production is serving it deploy f0961d3

opened this

A migration from a git:// address is now refused, and every remote fetch speaks only https:http. The migrate suites pass (25 tests). I couldn't run bun x tsc --noEmit because bun can't write to its tempdir in this sandbox, so the type check is unverified.

What changed

  • migrateUrl in src/actions/migrate.ts no longer lets git: through. It returns undefined, because safeRemoteUrl already rejects any scheme other than https and http.
  • The invalid_url message, shown on the migrate page and in the API's 422, now says: "A git:// address is not supported: use its https:// address."
  • I removed the ALLOWED_PROTOCOL = "https:http:git" constant. Both migration fetches now use the default REMOTE_PROTOCOLS, as the mirror fetch already did.
  • In test/migrate.test.ts, the old assertion that git:// passes through now asserts it is refused. It also asserts that an https:// address is still accepted and that the message names git://.
  • The new test/migrate-git-protocol.test.ts asserts that the default protocol list is https:http and that remoteGitEnv sets it. It also scans src/ for the old three-protocol string, a hard-coded GIT_ALLOW_PROTOCOL, and a caller passing its own protocol list. A source scan is cruder than an assertion on the environment each fetch runs with.

Left out

  • I added no separate error code for git://, and I didn't touch the TUI's generic "that URL is not valid" line. A distinct code would be wider than this issue needs.
  • A migration already in flight from git:// is not cancelled. Its fetch will now fail at git's protocol check, which the issue allows ("finish or fail").

Try it Run bun test test/migrate. In the migrate form, paste git://example.com/a/b.git. It should be refused with the new wording, and the https:// form of the same address should still go through.

🤖 Generated with Claude Code

Closes #3613

commented

A migration from a git:// address is now refused, and every remote fetch speaks only https:http. The migrate suites pass (25 tests). I couldn't run bun x tsc --noEmit because bun can't write to its tempdir in this sandbox, so the type check is unverified.

What changed

  • migrateUrl in src/actions/migrate.ts no longer lets git: through. It returns undefined, because safeRemoteUrl already rejects any scheme other than https and http.
  • The invalid_url message, shown on the migrate page and in the API's 422, now says: "A git:// address is not supported: use its https:// address."
  • I removed the ALLOWED_PROTOCOL = "https:http:git" constant. Both migration fetches now use the default REMOTE_PROTOCOLS, as the mirror fetch already did.
  • In test/migrate.test.ts, the old assertion that git:// passes through now asserts it is refused. It also asserts that an https:// address is still accepted and that the message names git://.
  • The new test/migrate-git-protocol.test.ts asserts that the default protocol list is https:http and that remoteGitEnv sets it. It also scans src/ for the old three-protocol string, a hard-coded GIT_ALLOW_PROTOCOL, and a caller passing its own protocol list. A source scan is cruder than an assertion on the environment each fetch runs with.

Left out

  • I added no separate error code for git://, and I didn't touch the TUI's generic "that URL is not valid" line. A distinct code would be wider than this issue needs.
  • A migration already in flight from git:// is not cancelled. Its fetch will now fail at git's protocol check, which the issue allows ("finish or fail").

Try it Run bun test test/migrate. In the migrate form, paste git://example.com/a/b.git. It should be refused with the new wording, and the https:// form of the same address should still go through.

🤖 Generated with Claude Code

Changes requested — before the latest push

The git:// refusal is right and tested, but the title promises more than the diff does: "every remote fetch is pinned to the address the forge vetted". It is not. In resolveSource, vetHost resolves the host and the vetted IP is thrown away; both migration fetches call remoteGitEnv(authEnv) with no Pin, so git re-resolves the name itself (DNS rebinding can answer differently from the vetted answer). The mirror fetch (src/origins/git-mirror.ts:70) does pin via pinFor. Fix first: keep the vetted address on Resolved (e.g. a pin built with pinFor(url, vetted.value[0])), pass it to remoteGitEnv in cloneInto and fetchForkHeads, and add a test that asserts the env the fetch runs with contains http.curloptResolve for the vetted IP. When the caller may reach private hosts (admin, trusted host) there is no vetting, so no pin is correct there. Second: the source-scan test checks text, not behaviour, and its regex forbids passing a pin-less third argument but would not notice a missing pin; replace it with the env assertion. Also the TUI path shows only a generic invalid-URL line, so the git:// guidance is on the page and API but not in src/tty.ts; say the same there. Type check was not run by the author.

commented

Both migration fetches are now pinned to the address the forge vetted, and a git:// migration is refused. The migrate tests pass (25). I could not run the type check: bun install and bun x tsc both fail here with "unable to write files to tempdir", and TypeScript isn't installed. The forge's check will be the first type check.

Changes

  • resolveSource in src/actions/migrate.ts now builds a pin from the vetted address with pinFor(url, vetted.value[0]) and keeps it on Resolved.pin. A small fetchEnv(source, authEnv) passes it to remoteGitEnv, and both cloneInto and fetchForkHeads use it.
  • When the caller may reach private hosts (admin, trusted host, or FORGE_MIGRATE_PRIVATE_HOSTS), nothing is vetted and nothing is pinned.
  • A public-looking name that fails to resolve is now refused as unreachable. Before, it went on to git unpinned, which left the rebinding window open.
  • test/migrate.test.ts has a new test. It checks that the env a vetted fetch runs with contains http.curloptResolve set to looks-public.example:443:93.184.216.34. It also checks that an unresolvable name is refused and that the unvetted path carries no pin.
  • The source-scan test is gone. test/migrate-git-protocol.test.ts now asserts on behaviour only: REMOTE_PROTOCOLS is https:http, and remoteGitEnv and fetchEnv set GIT_ALLOW_PROTOCOL to it.
  • The TUI's invalid_url line in src/tui/screens/common.ts now says a git:// address is not supported and to use its https:// address. It is a shared error table, so the added wording shows wherever invalid_url appears there.

Not done: a migration already in flight from git:// is not cancelled. Its fetch fails at the protocol check.

Try it: run bun test test/migrate. Pasting git://example.com/a/b.git into the migrate form is refused with the new wording.

🤖 Generated with Claude Code

Approved

Approved from the diff; the preview was unreachable from my sandbox, so I did not try it live. The change does what the issue asked. A git:// address is refused at the boundary. Both migration fetches go through one fetchEnv, which sets https:http and pins the vetted address. A host that does not resolve is now refused as unreachable instead of being fetched unpinned. Tests cover each of these, and the old git:// assertion was rightly flipped.

Two things I would do next:

  1. Check that the README and any migrate help text no longer list git:// as accepted. The diff does not touch the README.
  2. The pin uses only the first resolved address (vetted.value[0]). A host with several A records will fail if that one is down. Pinning the first is safe, so this is only a reliability point.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs