@@ -3,7 +3,10 @@ import * as CommandExecutor from "@effect/platform/CommandExecutor"
33import * as FileSystem from "@effect/platform/FileSystem"
44import * as Path from "@effect/platform/Path"
55import { NodeContext } from "@effect/platform-node"
6- import { claudeOauthTokenFileMode } from "@prover-coder-ai/docker-git-auth-oauth/claude-oauth-token"
6+ import {
7+ claudeOauthTokenFileMode ,
8+ dockerGitClaudeOauthTokenEnvKey
9+ } from "@prover-coder-ai/docker-git-auth-oauth/claude-oauth-token"
710import { describe , expect , it } from "@effect/vitest"
811import { Effect , Logger } from "effect"
912import * as Inspectable from "effect/Inspectable"
@@ -46,13 +49,15 @@ const isPingProbe = (args: ReadonlyArray<string>): boolean => args.includes("-p"
4649// REF: issue-439
4750const makeFakeExecutor = (
4851 token : string | null ,
49- pingExitCode : number
52+ pingExitCode : number ,
53+ invocations : Array < { readonly command : string ; readonly args : ReadonlyArray < string > } > = [ ]
5054) : CommandExecutor . CommandExecutor => {
5155 const start = ( command : Command . Command ) : Effect . Effect < CommandExecutor . Process , never > =>
5256 Effect . sync ( ( ) => {
5357 const flattened = Command . flatten ( command )
5458 const invocation = flattened [ flattened . length - 1 ] !
5559 const args = invocation . args
60+ invocations . push ( { command : invocation . command , args } )
5661
5762 const stdoutText = isSetupToken ( args )
5863 ? token === null
@@ -192,7 +197,12 @@ describe("authClaudeLogin", () => {
192197 it . effect ( "persists the OAuth token even when the post-login API probe fails" , ( ) =>
193198 withTempDir ( ( root ) =>
194199 withPatchedEnv (
195- { HOME : root , DOCKER_GIT_STATE_AUTO_SYNC : "0" , DOCKER_GIT_PROJECTS_ROOT : undefined } ,
200+ {
201+ HOME : root ,
202+ DOCKER_GIT_STATE_AUTO_SYNC : "0" ,
203+ DOCKER_GIT_PROJECTS_ROOT : undefined ,
204+ [ dockerGitClaudeOauthTokenEnvKey ] : undefined
205+ } ,
196206 Effect . gen ( function * ( _ ) {
197207 const { logs, tokenText } = yield * _ ( runLoginAndReadToken ( root , 7 ) )
198208 expect ( tokenText . trim ( ) ) . toBe ( oauthToken )
@@ -204,18 +214,61 @@ describe("authClaudeLogin", () => {
204214 it . effect ( "persists the OAuth token when the post-login API probe succeeds" , ( ) =>
205215 withTempDir ( ( root ) =>
206216 withPatchedEnv (
207- { HOME : root , DOCKER_GIT_STATE_AUTO_SYNC : "0" , DOCKER_GIT_PROJECTS_ROOT : undefined } ,
217+ {
218+ HOME : root ,
219+ DOCKER_GIT_STATE_AUTO_SYNC : "0" ,
220+ DOCKER_GIT_PROJECTS_ROOT : undefined ,
221+ [ dockerGitClaudeOauthTokenEnvKey ] : undefined
222+ } ,
208223 Effect . gen ( function * ( _ ) {
209224 const { tokenText } = yield * _ ( runLoginAndReadToken ( root , 0 ) )
210225 expect ( tokenText . trim ( ) ) . toBe ( oauthToken )
211226 } )
212227 )
213228 ) . pipe ( Effect . provide ( NodeContext . layer ) ) )
214229
230+ it . effect ( "uses a decoded docker-git OAuth env token without running setup-token" , ( ) =>
231+ withTempDir ( ( root ) =>
232+ withPatchedEnv (
233+ {
234+ HOME : root ,
235+ DOCKER_GIT_STATE_AUTO_SYNC : "0" ,
236+ DOCKER_GIT_PROJECTS_ROOT : undefined ,
237+ [ dockerGitClaudeOauthTokenEnvKey ] : ` ${ oauthToken } `
238+ } ,
239+ Effect . gen ( function * ( _ ) {
240+ const fs = yield * _ ( FileSystem . FileSystem )
241+ const path = yield * _ ( Path . Path )
242+ const invocations : Array < { readonly command : string ; readonly args : ReadonlyArray < string > } > = [ ]
243+ const claudeAuthPath = path . join ( root , ".docker-git/.orch/auth/claude" )
244+
245+ yield * _ (
246+ authClaudeLogin ( {
247+ _tag : "AuthClaudeLogin" ,
248+ label : null ,
249+ claudeAuthPath
250+ } ) . pipe (
251+ Effect . provideService ( CommandExecutor . CommandExecutor , makeFakeExecutor ( null , 0 , invocations ) )
252+ )
253+ )
254+
255+ const tokenText = yield * _ ( fs . readFileString ( path . join ( claudeAuthPath , "default" , ".oauth-token" ) ) )
256+ expect ( tokenText . trim ( ) ) . toBe ( oauthToken )
257+ expect ( invocations . some ( ( invocation ) => isSetupToken ( invocation . args ) ) ) . toBe ( false )
258+ expect ( invocations . some ( ( invocation ) => isPingProbe ( invocation . args ) ) ) . toBe ( true )
259+ } )
260+ )
261+ ) . pipe ( Effect . provide ( NodeContext . layer ) ) )
262+
215263 it . effect ( "replaces an existing token symlink without writing the secret to the symlink target" , ( ) =>
216264 withTempDir ( ( root ) =>
217265 withPatchedEnv (
218- { HOME : root , DOCKER_GIT_STATE_AUTO_SYNC : "0" , DOCKER_GIT_PROJECTS_ROOT : undefined } ,
266+ {
267+ HOME : root ,
268+ DOCKER_GIT_STATE_AUTO_SYNC : "0" ,
269+ DOCKER_GIT_PROJECTS_ROOT : undefined ,
270+ [ dockerGitClaudeOauthTokenEnvKey ] : undefined
271+ } ,
219272 Effect . gen ( function * ( _ ) {
220273 const fs = yield * _ ( FileSystem . FileSystem )
221274 const path = yield * _ ( Path . Path )
@@ -266,7 +319,12 @@ describe("authClaudeLogin", () => {
266319 it . effect ( "fails when setup-token completes without a captured OAuth token" , ( ) =>
267320 withTempDir ( ( root ) =>
268321 withPatchedEnv (
269- { HOME : root , DOCKER_GIT_STATE_AUTO_SYNC : "0" , DOCKER_GIT_PROJECTS_ROOT : undefined } ,
322+ {
323+ HOME : root ,
324+ DOCKER_GIT_STATE_AUTO_SYNC : "0" ,
325+ DOCKER_GIT_PROJECTS_ROOT : undefined ,
326+ [ dockerGitClaudeOauthTokenEnvKey ] : undefined
327+ } ,
270328 Effect . gen ( function * ( _ ) {
271329 yield * _ ( runLoginWithoutCapturedToken ( root ) )
272330 } )
0 commit comments