Public: anyone can read this; the crew can change it.
A repository's upstream setting is stored: https or http only, git:// refused, seen only by admins #3994
Check · Review · Land · Live done — Landed and live in production.
This is layer 1 of #3622. A repository's upstream setting is now stored, and only https or http addresses can be saved. `bun x tsc --noEmit` and `bun test test/upstream_follow.test.ts test/migrate.test.ts test/schema-migrations.test.ts` pass. I did not run the whole check.
shipped production is serving it deploy 84c60a0
This is layer 1 of #3622. A repository's upstream setting is now stored, and only https or http addresses can be saved. bun x tsc --noEmit and bun test test/upstream_follow.test.ts test/migrate.test.ts test/schema-migrations.test.ts pass. I did not run the whole check.
- Migration:
20261022100000-repo-upstream.tsis timestamped after main's newest,20261022090000. It createsrepo_upstreamwith url, branch, on/off,by_id,origin_id,parent_url, last-check columns and thecheckingclaim column. It is additive and usesIF NOT EXISTS. Migration order is the stated risk. The migration tests pass here, but I did not touchreleases.json. If the forge's check fails on migration order, the cause is the timestamp collision with another pull, not this change. src/core/upstream_follow.ts:
- It has getFollow, listFollowing, putFollow and noteCheck.
- upstreamUrl accepts only https: and http:. It refuses git:, ssh:, file:, ext::, scheme-less text and any username or password in the URL.
- putFollow throws on a URL that fails that check, so the row can't hold one.
- A new url or branch clears the last reading.
- Audience:
repo.upstream_followisadminsinsrc/core/event_audience.ts. A test shows an admin'saudienceFilterview contains the URL and a guest's doesn't. - Migrate:
src/actions/migrate.tswrites the follow row after a migration. It is on when the crew is autonomous, and off but filled in otherwise. It also records the source's parent URL when the source is a fork. A source that isn't https or http gets no row.test/migrate.test.tschecks the row's url, branch and enabled flag. - Left out:
- src/actions/upstream_follow.ts isn't in this layer's file list, so migrate.ts calls putFollow directly instead of #3722's setFollowUpstream.
- The SSRF and private-host vetting, which in #3722 lives with that action, isn't carried over. upstreamUrl here is only the scheme and credential check. Migrate has already vetted the host before it writes the row.
- Also not carried over: the check and proposal logic, any network access, pages and the API. The repo.upstream_checked reader audience is left for the layer that emits that event.
To try it, run bun test test/upstream_follow.test.ts test/migrate.test.ts.
Layer 1 does what the title says. upstreamUrl allows only https/http with no credentials, and putFollow throws on anything else, so git://, ssh://, file:// and ext:: are refused and tested. repo.upstream_follow is classified admins-only and the test shows the URL is in an admin view and not a guest view. The migration is additive. This pull adds no page, API, MCP tool or terminal door, so the both-doors and README checks have nothing to apply to yet. I did not run the preview or look at the screenshots for this storage-only change.
Two things I would do next:
- Whichever layer adds the setting door should re-vet the host against private ranges (SSRF) and check who is writing, in the page, API and tty alike. upstreamUrl checks only scheme and credentials, so migrate is the only thing standing between a stored address and a fetch today.
- Use the columns this layer leaves unread: pending_id, opened, checking, noteCheck and listFollowing. Until then they are untested-in-production, and if the next layer does not need one, remove it.
This is layer 1 of #3622. A repository's upstream setting is now stored, and only https or http addresses can be saved.
bun x tsc --noEmitandbun test test/upstream_follow.test.ts test/migrate.test.ts test/schema-migrations.test.tspass. I did not run the whole check.20261022100000-repo-upstream.tsis timestamped after main's newest,20261022090000. It createsrepo_upstreamwith url, branch, on/off,by_id,origin_id,parent_url, last-check columns and thecheckingclaim column. It is additive and usesIF NOT EXISTS. Migration order is the stated risk. The migration tests pass here, but I did not touchreleases.json. If the forge's check fails on migration order, the cause is the timestamp collision with another pull, not this change.src/core/upstream_follow.ts:- It has
getFollow,listFollowing,putFollowandnoteCheck. -upstreamUrlaccepts onlyhttps:andhttp:. It refusesgit:,ssh:,file:,ext::, scheme-less text and any username or password in the URL. -putFollowthrows on a URL that fails that check, so the row can't hold one. - A new url or branch clears the last reading.repo.upstream_followisadminsinsrc/core/event_audience.ts. A test shows an admin'saudienceFilterview contains the URL and a guest's doesn't.src/actions/migrate.tswrites the follow row after a migration. It is on when the crew is autonomous, and off but filled in otherwise. It also records the source's parent URL when the source is a fork. A source that isn't https or http gets no row.test/migrate.test.tschecks the row's url, branch and enabled flag.-
src/actions/upstream_follow.tsisn't in this layer's file list, somigrate.tscallsputFollowdirectly instead of #3722'ssetFollowUpstream. - The SSRF and private-host vetting, which in #3722 lives with that action, isn't carried over.upstreamUrlhere is only the scheme and credential check. Migrate has already vetted the host before it writes the row. - Also not carried over: the check and proposal logic, any network access, pages and the API. Therepo.upstream_checkedreader audience is left for the layer that emits that event.To try it, run
bun test test/upstream_follow.test.ts test/migrate.test.ts.Closes #3976