diff --git a/packages/seat/tests/publish.test.mjs b/packages/seat/tests/publish.test.mjs index 52822713c..c16538be7 100644 --- a/packages/seat/tests/publish.test.mjs +++ b/packages/seat/tests/publish.test.mjs @@ -5,7 +5,7 @@ import { test } from "node:test"; import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; -import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { gitEnv } from "../src/checkout.mjs"; @@ -78,6 +78,23 @@ test("T3: publish pushes the work commit by oid to / on the fork, assert.equal(spawnSync("git", [`--git-dir=${w.repo}`, "config", "--get-regexp", "^(remote|credential)\\."], { env: gitEnv() }).stdout.toString(), ""); }); +test("T3: the token is never in git's argv, the fork URL included; it reaches git on fd 3 only", async (t) => { + const w = await world(t); + // A git first on PATH that logs its argv and execs the real one; exec keeps fd 3. + const real = spawnSync("sh", ["-c", "command -v git"], { encoding: "utf8" }).stdout.trim(); + const shim = join(w.dir, "shim"); + mkdirSync(shim); + const log = join(w.dir, "argv.log"); + writeFileSync(join(shim, "git"), `#!/bin/sh\nprintf '%s\\n' "$@" >> '${log}'\nexec '${real}' "$@"\n`); + chmodSync(join(shim, "git"), 0o755); + assert.deepEqual(await w.remote({ env: { PATH: `${shim}:${process.env.PATH}` } }), { ref: DST, commit: w.work, previous: null }); + const argv = readFileSync(log, "utf8"); + assert.match(argv, /^ls-remote$/m); + assert.match(argv, /^push$/m); + assert.equal(argv.includes(TOKEN), false); + assert.equal(argv.includes(`${USER}:`), false, "no userinfo in a URL"); +}); + test("T3: a moved fork branch refuses non-fast-forward; no + and no force", async (t) => { const w = await world(t); const other = join(w.dir, "other"); @@ -127,11 +144,14 @@ test("T3: a wrong token refuses fork-unavailable; git's stderr isn't in the refu test("T3: a 302 is not followed: fork-unavailable, and the target sees no request", async (t) => { const w = await world(t); - const target = await fakeGitea({ dir: join(w.dir, "target"), tls: scratchCa(join(w.dir, "ca2")), user: USER, token: TOKEN }); + // One CA for both, which git trusts, so only http.followRedirects=false keeps git off the target; + // with a CA git doesn't trust, a followed redirect would fail at TLS and the target would see nothing anyway. + const ca = scratchCa(join(w.dir, "ca2")); + const target = await fakeGitea({ dir: join(w.dir, "target"), tls: ca, user: USER, token: TOKEN }); t.after(() => target.close()); - const bounce = await fakeGitea({ dir: join(w.dir, "bounce"), tls: scratchCa(join(w.dir, "ca3")), user: USER, token: TOKEN, redirect: target.origin }); + const bounce = await fakeGitea({ dir: join(w.dir, "bounce"), tls: ca, user: USER, token: TOKEN, redirect: target.origin }); t.after(() => bounce.close()); - const tls = ["-c", `http.sslCAInfo=${join(w.dir, "ca3", "ca.pem")}`]; + const tls = ["-c", `http.sslCAInfo=${ca.ca}`]; await rejects(w.remote({ fork: `${bounce.origin}/${USER}/stack`, tls }), "fork-unavailable"); assert.ok(bounce.requests.length > 0); assert.equal(target.requests.length, 0);