feat(runner): clone stage with ephemeral credential helper
Clone stage per tech spec §6, verbatim mechanics: every git invocation carries a BLANK credential.helper first (suppresses OS keychain helpers) then the inline veect helper; the PAT reaches git via child env only — never argv, URLs, logs, or .git/config. GIT_TERMINAL_PROMPT and GIT_ASKPASS are pinned so a headless clone can never hang on a TTY or ambient IDE askpass. Staged status events (start/heartbeat/final) + ready on success; named failures: invalid-git-url, auth-failed, clone-failed (daemon's 'repository not exported' maps to bad-URL, not auth). Integration suite clones the daemon-served vite-kitchen and an authenticated dumb-HTTP remote that asserts the exact Basic credential git presented, plus leak assertions over logs/argv/.git. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
@@ -33,6 +33,36 @@ manifest, no use-case layer, no DI container.
|
||||
- Zod issues are summarized as path + code only — payload values (which
|
||||
may include a PAT) are never echoed into errors or logs.
|
||||
|
||||
## Clone stage — credential mechanics (tech spec §6, verbatim)
|
||||
|
||||
- Every git invocation carries `-c credential.helper=` (BLANK first —
|
||||
resets the helper list, suppressing OS keychain helpers) followed by
|
||||
`-c credential.helper=<veect-helper>` (an inline shell function that
|
||||
answers `get` from env vars and ignores `store`/`erase`).
|
||||
- The PAT reaches git via the child's env (`VEECT_GIT_PAT`) — never
|
||||
argv (the helper string only names env vars), never in the URL, never
|
||||
written to `.git/config` or anywhere else on disk.
|
||||
- `GIT_TERMINAL_PROMPT=0` and `GIT_ASKPASS=echo` ride every invocation:
|
||||
a clone must never hang on a TTY prompt or an ambient IDE askpass.
|
||||
- Failures map to named causes (`src/stages/clone.ts`): unusable URL /
|
||||
unreachable repo → `invalid-git-url`, credential rejection →
|
||||
`auth-failed`, anything else → `clone-failed`.
|
||||
|
||||
### How the auth path is honestly tested
|
||||
|
||||
`git daemon` (story 01's transport) has no authentication, so it cannot
|
||||
prove credential delivery. The integration suite therefore also serves
|
||||
the same bare fixture over **authenticated dumb HTTP**
|
||||
(`tests/http-git-server.ts`): a real `git clone` probes, receives 401,
|
||||
consults the ephemeral helper, and retries with Basic auth — the test
|
||||
asserts the server received exactly `x-access-token:<PAT>`, that git's
|
||||
first probe was unauthenticated, and that the PAT appears nowhere in
|
||||
runner logs (which include every spawned git argv), `.git/config`, or
|
||||
any other file under `.git/`. Wrong/missing PAT → named `auth-failed`.
|
||||
What is NOT covered: a real smart-HTTP provider (GitHub et al.) — the
|
||||
dumb-HTTP fallback exercises the same credential machinery in git, but
|
||||
the smart-protocol surface itself first meets reality in later PRDs.
|
||||
|
||||
## Testing
|
||||
|
||||
- Unit suites live next to sources in `src/`; protocol/WS suites live in
|
||||
|
||||
Reference in New Issue
Block a user