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

A private repository brought from another forge clones with its credential never in argv, config or logs #8988

Merged opened this

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

Merged

This adds a test proving that bringing a private repository from a connected forge never puts its credential on a command line, in the clone's config, or in a log. No source code changed. The code already worked this way: `gitAuthEnv` (`src/origins/credentials.ts`) sends the credential only through `GIT_CONFIG_*` env vars, as an `http.<scope>.extraHeader` limited to the origin's URL, with redirect…

shipped production is serving it deploy 119f4d2

opened this

This adds a test proving that bringing a private repository from a connected forge never puts its credential on a command line, in the clone's config, or in a log. No source code changed. The code already worked this way: gitAuthEnv (src/origins/credentials.ts) sends the credential only through GIT_CONFIG_* env vars, as an http.<scope>.extraHeader limited to the origin's URL, with redirects off. safeRemoteUrl refuses any clone URL with a username or password in it. What was missing was a test that would catch a regression.

test/bring-private-credential.test.ts

  • Setup: A real forge instance serves a private repository over smart HTTP. The test first checks that an anonymous info/refs request is refused. test/fake-origin.ts acts as the connected Forgejo, listing the repo as private: true. Alice connects it with the token and brings it through POST /bring.
  • Catching argv: A git shim placed first on PATH writes down every argument of every git process the server starts, then runs the real git. So the check is on what was actually started, not on what the code builds.
  • Assertions:

- The job reaches done and the copy has refs/heads/main, so the credential did get through, by the environment. - The token, both as plain text and as its Basic base64 blob, appears nowhere in the recorded argv, the clone's config, the job record, the bring page or anything the server printed to the console. - The shim's log must contain the upstream clone URL and the config must name the remote, so an empty log can't pass by accident.

  • Mutation check: I temporarily changed fetchMirror to pass -c http.extraHeader=… on the command line. The test failed, naming the leaked blob in argv. The source was then restored.

Not done: fetches use a header in the environment rather than an askpass helper. The issue allows either, and the environment header was already in place. I didn't update the plan with keep_plan because that tool isn't available in this run.

To try it: bun test test/bring-private-credential.test.ts. The gate, bun x tsc --noEmit, the 13 test files scripts/fast.ts names, and test/bring.test.ts all pass: 171 tests, 0 failures.

🤖 Generated with Claude Code

Closes #8963

commented

This adds a test proving that bringing a private repository from a connected forge never puts its credential on a command line, in the clone's config, or in a log. No source code changed. The code already worked this way: gitAuthEnv (src/origins/credentials.ts) sends the credential only through GIT_CONFIG_* env vars, as an http.<scope>.extraHeader limited to the origin's URL, with redirects off. safeRemoteUrl refuses any clone URL with a username or password in it. What was missing was a test that would catch a regression.

test/bring-private-credential.test.ts

  • Setup: A real forge instance serves a private repository over smart HTTP. The test first checks that an anonymous info/refs request is refused. test/fake-origin.ts acts as the connected Forgejo, listing the repo as private: true. Alice connects it with the token and brings it through POST /bring.
  • Catching argv: A git shim placed first on PATH writes down every argument of every git process the server starts, then runs the real git. So the check is on what was actually started, not on what the code builds.
  • Assertions:

- The job reaches done and the copy has refs/heads/main, so the credential did get through, by the environment. - The token, both as plain text and as its Basic base64 blob, appears nowhere in the recorded argv, the clone's config, the job record, the bring page or anything the server printed to the console. - The shim's log must contain the upstream clone URL and the config must name the remote, so an empty log can't pass by accident.

  • Mutation check: I temporarily changed fetchMirror to pass -c http.extraHeader=… on the command line. The test failed, naming the leaked blob in argv. The source was then restored.

Not done: fetches use a header in the environment rather than an askpass helper. The issue allows either, and the environment header was already in place. I didn't update the plan with keep_plan because that tool isn't available in this run.

To try it: bun test test/bring-private-credential.test.ts. The gate, bun x tsc --noEmit, the 13 test files scripts/fast.ts names, and test/bring.test.ts all pass: 171 tests, 0 failures.

🤖 Generated with Claude Code

Approved

A test-only pull that proves the existing behaviour (credentials.ts sends the token via GIT_CONFIG_* env only). The git shim records real argv, and the test also asserts the config, job record, bring page and console output are clean, in both plaintext and base64 forms. It guards against a vacuous pass by requiring the upstream URL to appear in the argv log and the config. It is small and single-purpose, and it adds no dependency and no README change. Next, in order: (1) also assert the token is absent from the clone's other files, such as packed refs and hooks, and from the app's data-dir log files, not only config; (2) restore console and PATH in a try/finally inside the test, so a failed settle cannot leak the replaced console into later assertions.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs