@@ -10,6 +10,7 @@ import { pathToFileURL } from "node:url";
1010
1111import {
1212 buildTaskFromEvent ,
13+ createFreshTaskAttemptDirectory ,
1314 createConfig ,
1415 githubRequestAllPages ,
1516 handleRequest ,
@@ -24,6 +25,7 @@ import {
2425 resumeTaskPublication ,
2526 runtimeInstallationTokenRequest ,
2627 runtimeIsolationIssue ,
28+ runtimeDiagnostic ,
2729 runtimeProcessEnvironment ,
2830 runtimeSandboxArgs ,
2931 runnableTaskIds ,
@@ -2893,11 +2895,12 @@ test("redacts credentials and passes only allowlisted ambient environment keys",
28932895 const secretText = [
28942896 "ghs_1234567890" , "ghp_1234567890" , "github_pat_1234567890" ,
28952897 "sk-proj-1234567890" , "Bearer topsecret" , "eyJabc.def.ghi" ,
2898+ "API error 429 on account `reviewer (reviewer@example.com)`." ,
28962899 "https://user:password@example.com/path" ,
28972900 "-----BEGIN PRIVATE KEY-----\nprivate-data\n-----END PRIVATE KEY-----" ,
28982901 ] . join ( "\n" ) ;
28992902 const redacted = redactTokenish ( secretText ) ;
2900- assert . doesNotMatch ( redacted , / 1 2 3 4 5 6 7 8 9 0 | t o p s e c r e t | p a s s w o r d | p r i v a t e - d a t a | e y J a b c / ) ;
2903+ assert . doesNotMatch ( redacted , / 1 2 3 4 5 6 7 8 9 0 | t o p s e c r e t | p a s s w o r d | p r i v a t e - d a t a | e y J a b c | r e v i e w e r @ e x a m p l e \. c o m | r e v i e w e r \( / ) ;
29012904 const env = sanitizedRuntimeEnvironment ( {
29022905 PATH : "/bin" , LANG : "C.UTF-8" , SSH_AUTH_SOCK : "/tmp/agent.sock" ,
29032906 DATABASE_URL : "postgres://user:pass@db" , AWS_ACCESS_KEY_ID : "AKIASECRET" ,
@@ -2906,6 +2909,57 @@ test("redacts credentials and passes only allowlisted ambient environment keys",
29062909 assert . deepEqual ( env , { PATH : "/bin" , LANG : "C.UTF-8" } ) ;
29072910} ) ;
29082911
2912+ test ( "preserves a useful redacted provider diagnostic for failed reviews" , async ( ) => {
2913+ const diagnostic = runtimeDiagnostic ( {
2914+ args : [ "coven-code" , "--headless" ] ,
2915+ returncode : 2 ,
2916+ stdout : "" ,
2917+ stderr : "API error 429: rate limit for model `gpt-5.4-mini` on account `reviewer (reviewer@example.com)`. Bearer topsecret sk-proj-1234567890\nProvider: codex" ,
2918+ signal : null ,
2919+ timed_out : false ,
2920+ spawn_error : "" ,
2921+ } ) ;
2922+ assert . match ( String ( diagnostic ) , / A P I e r r o r 4 2 9 / ) ;
2923+ assert . match ( String ( diagnostic ) , / g p t - 5 \. 4 - m i n i / ) ;
2924+ assert . match ( String ( diagnostic ) , / c o n f i g u r e d a c c o u n t / ) ;
2925+ assert . doesNotMatch ( String ( diagnostic ) , / r e v i e w e r @ e x a m p l e \. c o m | r e v i e w e r \( | t o p s e c r e t | 1 2 3 4 5 6 7 8 9 0 / ) ;
2926+
2927+ const stateDir = tempStateDir ( ) ;
2928+ const config = testConfig ( stateDir ) ;
2929+ const task = reviewTask ( "provider-failure-diagnostic" ) ;
2930+ task . runtime_diagnostic = diagnostic ;
2931+ prepareReviewWorkspace ( config , task ) ;
2932+ const result = completeReview ( ) ;
2933+ result . status = "failure" ;
2934+ const resultPath = join ( stateDir , "provider-failure.json" ) ;
2935+ writeFileSync ( resultPath , JSON . stringify ( result ) ) ;
2936+ let payload : JsonObject = { } ;
2937+ await withGithubApiMock ( ( url , init ) => {
2938+ const read = githubReadFixture ( url , init ) ;
2939+ if ( read ) return read ;
2940+ payload = JSON . parse ( String ( init . body ) ) as JsonObject ;
2941+ return { id : 409 , state : "PENDING" , html_url : "https://github.com/OpenCoven/example/pull/7#pullrequestreview-409" } ;
2942+ } , async ( ) => publishResultIfConfigured ( config , task , resultPath , "token" ) ) ;
2943+ assert . equal ( payload . event , "COMMENT" ) ;
2944+ assert . match ( String ( payload . body ) , / # # # R u n t i m e d i a g n o s t i c / ) ;
2945+ assert . match ( String ( payload . body ) , / A P I e r r o r 4 2 9 / ) ;
2946+ assert . doesNotMatch ( String ( payload . body ) , / r e v i e w e r @ e x a m p l e \. c o m | r e v i e w e r \( | t o p s e c r e t | 1 2 3 4 5 6 7 8 9 0 / ) ;
2947+ } ) ;
2948+
2949+ test ( "creates isolated attempt directories and refuses stale artifact reuse" , ( ) => {
2950+ const root = tempStateDir ( ) ;
2951+ const first = createFreshTaskAttemptDirectory ( root , "review-task" , 1 , "test attempt" ) ;
2952+ writeFileSync ( join ( first , "run.json" ) , "stale artifact\n" ) ;
2953+ const second = createFreshTaskAttemptDirectory ( root , "review-task" , 2 , "test attempt" ) ;
2954+ assert . notEqual ( first , second ) ;
2955+ assert . equal ( readFileSync ( join ( first , "run.json" ) , "utf8" ) , "stale artifact\n" ) ;
2956+ assert . deepEqual ( readdirSync ( second ) , [ ] ) ;
2957+ assert . throws (
2958+ ( ) => createFreshTaskAttemptDirectory ( root , "review-task" , 1 , "test attempt" ) ,
2959+ / a l r e a d y e x i s t s / ,
2960+ ) ;
2961+ } ) ;
2962+
29092963test ( "keeps idempotency marker after truncating and redacts issue publication text" , async ( ) => {
29102964 const stateDir = tempStateDir ( ) ;
29112965 const task : JsonObject = {
0 commit comments