Repository navigation
fix(server): add sanitized hints for common VCS command failures #11729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6fab3c6
d8e6823
116a1eb
07c730b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -113,6 +113,30 @@ const isTransientGitExit = (stderr: string) => | |||||||||
| /unable to create [^\n]*\.lock['"]?: file exists/i.test(stderr) || | ||||||||||
| /(?:unable to stat|lstat\(|error: open\()[^\n]+: no such file or directory/i.test(stderr); | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Fixed, secret-free hints for common failure modes. stderr is matched but never echoed, since | ||||||||||
| * VCS CLIs may print credentials. Order matters: more specific patterns come first. | ||||||||||
| */ | ||||||||||
| const COMMAND_FAILURE_HINTS: ReadonlyArray<readonly [RegExp, string]> = [ | ||||||||||
| [ | ||||||||||
| /permission denied \([^)]*(?:publickey|password|keyboard-interactive)[^)]*\)/i, | ||||||||||
| "SSH authentication failed. Check that your SSH key is set up for this host, or use an HTTPS URL.", | ||||||||||
| ], | ||||||||||
| [ | ||||||||||
| /detected dubious ownership in repository/i, | ||||||||||
| "The directory is owned by a different user, which git refuses to trust. Fix the directory ownership or add it to git's safe.directory list.", | ||||||||||
| ], | ||||||||||
| [ | ||||||||||
| /permission denied/i, | ||||||||||
| "Permission denied. Check that the directory is owned by your user account and writable.", | ||||||||||
|
Comment on lines
+130
to
+131
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '105,145p;190,218p' apps/server/src/vcs/VcsProcess.ts
rg -n 'classifyNonZeroExit|resolveCommandFailureHint|fallbackErrorDetail' apps/server/src/vcs/VcsProcess.ts apps/server/src/vcs/GitVcsDriverCore.tsRepository: pingdotgg/t3code Length of output: 5730 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- VcsProcess classification and resolver ---'
sed -n '45,82p;120,142p;186,214p' apps/server/src/vcs/VcsProcess.ts
printf '%s\n' '--- Git driver failure-detail helpers and direct resolver call ---'
sed -n '880,940p;980,1030p;3318,3380p' apps/server/src/vcs/GitVcsDriverCore.ts
printf '%s\n' '--- Git push-related definitions/callers ---'
rg -n -C 5 'push|runUnbounded|allowNonZeroExit|fetchFailureDetail|resolveCommandFailureHint' apps/server/src/vcs/GitVcsDriverCore.ts | head -n 260Repository: pingdotgg/t3code Length of output: 20100 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- Complete non-zero classifier ---'
sed -n '60,118p' apps/server/src/vcs/VcsProcess.ts
printf '%s\n' '--- Fetch-specific diagnostic helper ---'
sed -n '470,525p' apps/server/src/vcs/GitVcsDriverCore.ts
printf '%s\n' '--- Push call sites and surrounding logic ---'
rg -n -C 12 '["'\"'\"']push["'\"'\"']|pushRemote|push failed|push.*commit|commit.*push' apps/server/src/vcs/GitVcsDriverCore.ts
printf '%s\n' '--- Resolver tests or fixtures ---'
rg -n -C 8 'resolveCommandFailureHint|Permission denied|permission denied' apps/server/src apps/server/test apps/server 2>/dev/null | head -n 220Repository: pingdotgg/t3code Length of output: 4598 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- Push symbols in VCS sources ---'
rg -n -C 10 '\bpush\b|pushRemote|Push' apps/server/src/vcs -g '*.ts' | head -n 320Repository: pingdotgg/t3code Length of output: 26946 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- Repository-owned Git push callers ---'
rg -n -C 8 'git[[:space:]]+push|["'\"'\"']push["'\"'\"']|args:.*push|command:.*git' apps -g '*.ts' -g '*.tsx' | head -n 360
printf '%s\n' '--- VcsProcess and Git driver construction/callers ---'
rg -n -C 6 'VcsProcess\.VcsProcess|VcsProcess\.run|new VcsProcess|GitVcsDriverCore|GitVcsDriver\.execute|\.execute\(' apps/server/src -g '*.ts' | head -n 260Repository: pingdotgg/t3code Length of output: 302 🏁 Script executed: #!/bin/bash
set -e
rg -n -C 6 'push' apps/server/src --glob '*.ts' | head -n 300Repository: pingdotgg/t3code Length of output: 26910 Use a neutral hint for generic permission failures.
Suggested fix [
/permission denied/i,
- "Permission denied. Check that the directory is owned by your user account and writable.",
+ "Permission denied. Check the credentials and permissions required for this operation.",
],📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| ], | ||||||||||
| [/not a git repository/i, "The directory is not a git repository."], | ||||||||||
| ]; | ||||||||||
|
|
||||||||||
| /** Resolves a sanitized failure hint from stderr without retaining any of its content. */ | ||||||||||
| export const resolveCommandFailureHint = (stderr: string): string | undefined => | ||||||||||
| COMMAND_FAILURE_HINTS.find(([pattern]) => pattern.test(stderr))?.[1]; | ||||||||||
|
|
||||||||||
| export const make = Effect.gen(function* () { | ||||||||||
| const processRunner = yield* ProcessRunner.ProcessRunner; | ||||||||||
| const vcsProcesses = yield* Semaphore.make(VCS_PROCESS_CONCURRENCY); | ||||||||||
|
|
@@ -177,12 +201,15 @@ export const make = Effect.gen(function* () { | |||||||||
|
|
||||||||||
| if (!input.allowNonZeroExit && result.code !== 0) { | ||||||||||
| const failureKind = classifyNonZeroExit(input.command, result.stderr); | ||||||||||
| const failureDetail = | ||||||||||
| failureKind === "command-failed" ? resolveCommandFailureHint(result.stderr) : undefined; | ||||||||||
| return yield* VcsProcessExitError.fromProcessExit( | ||||||||||
| baseError, | ||||||||||
| { | ||||||||||
| exitCode: result.code, | ||||||||||
| stderr: result.stderr, | ||||||||||
| stderrTruncated: result.stderrTruncated, | ||||||||||
| ...(failureDetail !== undefined ? { failureDetail } : {}), | ||||||||||
| }, | ||||||||||
| failureKind, | ||||||||||
| input.command === "git" && | ||||||||||
|
|
||||||||||
Uh oh!
There was an error while loading. Please reload this page.