[Bug]: A root tea login prevents resolving another Gitea instance mounted on the same host #35904
Send to my agentSummary#
A configured tea login for a Gitea instance under a URL subpath becomes unusable when another login points to the host's root. T3 Code reports that no login matches even when the repository URL explicitly identifies the mounted instance. An isolated run of the production repository resolver reproduced the failure; the same repository resolves correctly with only the mounted login configured.
Before submitting#
- Related issues: none found in open and closed issues for this login-selection failure.
- Removed credentials, tokens, private paths, and sensitive data.
Area#
apps/server
Observed behavior#
With tea login URLs https://forge.example and https://forge.example/gitea, resolving https://forge.example/gitea/owner/repo.git fails with ForgejoCliError, reason authentication, and “No matching Forgejo login.” The same production call returns login mounted-instance, repository owner/repo, and base URL https://forge.example/gitea when the root login is absent. The fixture injects the process runner and filesystem; it executes no real fj or tea command and contacts no forge.
Reproduction#
- Save the script below as
repro-mount.sh. - Run
sh repro-mount.sh /path/to/t3codeagainst the stated commit. - Observe the passing single-login control followed by the authentication failure with both configured logins.
The completed script reproduced the failure in one recorded run. An earlier harness setup attempt was inconclusive because it read an incorrect Effect Result property; that harness error was corrected before the recorded run below.
The script requires POSIX sh, Git, Node with native TypeScript support and registerHooks, npm, and access to the npm registry. It downloads the repository-pinned Effect package with scripts disabled, imports unchanged production files through a temporary module resolver, and injects synthetic tea login-list output. All generated files and state live under a disposable directory that is removed on exit. Exit 1 means the defect reproduced, exit 0 means the mounted login resolved correctly, and exit 2 means setup or the control failed.
Reproduction script: repro-mount.sh
#!/bin/sh
set -u
root=$(cd "$1" && pwd) || exit 2
scratch=$(mktemp -d) || exit 2
trap 'rm -rf "$scratch"' EXIT HUP INT TERM
export HOME="$scratch/home" TMPDIR="$scratch/tmp" XDG_CONFIG_HOME="$scratch/config" XDG_DATA_HOME="$scratch/data" XDG_STATE_HOME="$scratch/state" T3CODE_HOME="$scratch/t3"
export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null
mkdir -p "$HOME" "$TMPDIR" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_STATE_HOME" "$T3CODE_HOME"
git -C "$root" rev-parse HEAD
node --version
npm --version
if ! (cd "$scratch" && npm pack effect@4.1.3 --ignore-scripts --silent > artifact-name && tar -xzf effect-4.1.3.tgz); then
echo 'RESULT: inconclusive'; exit 2
fi
cat > "$scratch/run.mjs" <<'JS'
import {registerHooks} from 'node:module';
import {pathToFileURL} from 'node:url';
import {resolve} from 'node:path';
const root=process.argv[2];
registerHooks({resolve(s,c,next){
if(s.startsWith('effect/')){
const p=s.slice(7);
return {url:pathToFileURL(resolve(import.meta.dirname,'package/dist',p+(['http','process'].includes(p)?'/index.js':'.js'))).href,shortCircuit:true};
}
if(s.startsWith('@t3tools/')){
const [,pkg,...rest]=s.split('/');
return {url:pathToFileURL(resolve(root,'packages',pkg,'src',rest.join('/')+'.ts')).href,shortCircuit:true};
}
return next(s,c);
}});
try {
const Effect=await import('effect/Effect');
const Layer=await import('effect/Layer');
const FileSystem=await import('effect/FileSystem');
const {HttpClient}=await import('effect/http');
const Cli=await import('@t3tools/source-control-forgejo/server/ForgejoCli');
const Host=await import('@t3tools/source-control-core/server/SourceControlHost');
const HostProcess=await import('@t3tools/shared/HostProcess');
console.log('effect 4.1.3');
const out=stdout=>({exitCode:0,stdout,stderr:'',stdoutTruncated:false,stderrTruncated:false});
const mounted={name:'mounted-instance',url:'https://forge.example/gitea',user:'reviewer',default:'false'};
const top={name:'root-instance',url:'https://forge.example',user:'reviewer',default:'false'};
async function run(rows){
const cli=await Effect.runPromise(Cli.make.pipe(
Effect.provide(Layer.mock(Host.SourceControlHost)({process:{run:i=>{
if(i.command!=='tea'||i.args.join(' ')!=='login list --output json')return Effect.die('Unexpected command');
return Effect.succeed(out(JSON.stringify(rows)));
}}})),
Effect.provideService(FileSystem.FileSystem,FileSystem.makeNoop({exists:()=>Effect.succeed(false)})),
Effect.provideService(HttpClient.HttpClient,HttpClient.make(()=>Effect.die('Network forbidden'))),
Effect.provideService(HostProcess.HomeDirectory,process.env.HOME)
));
return Effect.runPromise(cli.resolveRepository({cwd:process.env.HOME,repository:'https://forge.example/gitea/owner/repo.git'}).pipe(Effect.result));
}
const control=await run([mounted]);
if(control._tag!=='Success'||control.success.login!=='mounted-instance'||control.success.repository!=='owner/repo')throw new Error('Control failed');
console.log('Control: mounted-instance resolves owner/repo');
const result=await run([top,mounted]);
if(result._tag==='Failure'){
console.log('Root and mounted logins: '+result.failure.reason+'; '+result.failure.detail);
console.log('RESULT: defect reproduced');process.exitCode=1;
}else if(result.success.login==='mounted-instance'&&result.success.repository==='owner/repo'){
console.log('RESULT: expected behavior');
}else throw new Error('Unexpected resolution');
}catch(error){console.log('Setup or control failed: '+error.message);console.log('RESULT: inconclusive');process.exitCode=2;}
JS
node --disable-warning=ExperimentalWarning "$scratch/run.mjs" "$root"
Expected behavior#
An explicit repository URL under the mounted Gitea base should select its configured login even when another instance shares the hostname. T3's docs/user/source-control.md#L49-L64 documents mounted instances and full server URLs as supported inputs. Gitea's reverse-proxy documentation permits a server root containing a subpath; tea v0.16.0's login-list formatter supplies each configured login's complete URL.
Impact and scope#
Impact: P2 - Adding another valid login can disable repository resolution and subsequent Forgejo/Gitea operations for a mounted instance. The failure is bounded to overlapping instance base URLs on one host and does not affect the single-login control.
NOT_ENOUGH_INFO: A practical workaround within T3 Code was not verified; checking a separately configured tea environment would establish one. Choosing a default is not enough in the observed resolver: its default selection applies only when all matching login URLs are equal. No real accounts or installations were tested.
Version#
T3 Code commit 59e64eef881632a23f89c4138bcf37f23d92bf93; tea output follows released v0.16.0 formatter source. Effect 4.1.3, pinned by the repository.
Runtime and platform#
Darwin arm64; Node v26.12.1; npm 11.20.0 under the isolated HOME. Git revision printed by the script identifies the checkout. The fixture did not execute a tea or fj binary.
Interface#
Library: ForgejoCli.resolveRepository, used by the server's Forgejo/Gitea source-control provider.
Earliest failure stage#
Setup or configuration
Relevant output or evidence#
Recorded output from the script:
59e64eef881632a23f89c4138bcf37f23d92bf93
v26.12.1
11.20.0
effect 4.1.3
Control: mounted-instance resolves owner/repo
Root and mounted logins: authentication; No matching Forgejo login. Use `fj auth login`, `fj auth add-token`, or `tea login add` for this server; choose a default when multiple tea accounts match.
RESULT: defect reproduced
All hostnames, repository names, account names, and login names in the fixture are synthetic. The production matcher accepts both the root login and the longer mount prefix, then rejects matches with differing URLs: packages/source-control-forgejo/src/server/ForgejoCli.ts#L177-L210. The supported repository resolver applies that matcher and converts the unresolved selection to the observed authentication failure: packages/source-control-forgejo/src/server/ForgejoCli.ts#L590-L639.
Analysis or suspected cause#
Source evidence: A root login's empty path matches every repository on the host. The matcher does not distinguish the more specific mount in this input, and its default-login branch cannot select between different base URLs.
tanstack-source added labelsbug
github-actions[bot](GitHub profile, opens in a new tab) added labelsvouch:denounced
Sign in to join this conversation.