@@ -3,7 +3,7 @@ import type * as CommandExecutor from "@effect/platform/CommandExecutor"
33import type { PlatformError } from "@effect/platform/Error"
44import type * as FileSystem from "@effect/platform/FileSystem"
55import type * as Path from "@effect/platform/Path"
6- import { Duration , Effect , Schedule } from "effect"
6+ import { Duration , Effect , Match , Schedule } from "effect"
77
88import type { AuthGithubLoginCommand , AuthGithubLogoutCommand , AuthGithubStatusCommand } from "../core/domain.js"
99import { defaultTemplateConfig } from "../core/domain.js"
@@ -15,6 +15,8 @@ import { buildDockerAuthSpec, normalizeAccountLabel } from "./auth-helpers.js"
1515import { migrateLegacyOrchLayout } from "./auth-sync.js"
1616import { ensureEnvFile , parseEnvEntries , readEnvText , removeEnvKey , upsertEnvKey } from "./env-file.js"
1717import { ensureGhAuthImage , ghAuthDir , ghAuthRoot , ghImageName } from "./github-auth-image.js"
18+ import type { GithubTokenValidationResult } from "./github-token-validation.js"
19+ import { validateGithubToken } from "./github-token-validation.js"
1820import { resolvePathFromCwd } from "./path-helpers.js"
1921import { withFsPathContext } from "./runtime.js"
2022import { ensureStateDotDockerGitRepo } from "./state-repo-github.js"
@@ -35,6 +37,8 @@ type EnvContext = {
3537 readonly current : string
3638}
3739
40+ type GithubTokenStatusEntry = GithubTokenEntry & GithubTokenValidationResult
41+
3842const ensureGithubOrchLayout = (
3943 cwd : string ,
4044 envGlobalPath : string
@@ -116,6 +120,21 @@ const withEnvContext = <A, E, R>(
116120 } )
117121 )
118122
123+ const renderGithubTokenStatusLine = ( entry : GithubTokenStatusEntry ) : string =>
124+ Match . value ( entry . status ) . pipe (
125+ Match . when ( "valid" , ( ) =>
126+ entry . login === null
127+ ? `- ${ entry . label } : valid (owner unavailable)`
128+ : `- ${ entry . label } : valid (owner: ${ entry . login } )`
129+ ) ,
130+ Match . when ( "invalid" , ( ) => `- ${ entry . label } : invalid` ) ,
131+ Match . when ( "unknown" , ( ) => `- ${ entry . label } : unknown (validation unavailable)` ) ,
132+ Match . exhaustive
133+ )
134+
135+ const renderGithubTokenStatusReport = ( entries : ReadonlyArray < GithubTokenStatusEntry > ) : string =>
136+ [ `GitHub tokens (${ entries . length } ):` , ...entries . map ( renderGithubTokenStatusLine ) ] . join ( "\n" )
137+
119138const resolveGithubTokenFromGh = (
120139 cwd : string ,
121140 accountPath : string
@@ -251,16 +270,16 @@ export const authGithubLogin = (
251270 } )
252271 )
253272
254- // CHANGE: show GitHub auth status from the shared env file
255- // WHY: surface current account labels without leaking tokens
273+ // CHANGE: show GitHub auth status with live token validation and owner login
274+ // WHY: presence in the env file is weaker than actual GitHub validity for operator diagnostics
256275// QUOTE(ТЗ): "система авторизации"
257- // REF: user-request-2026-01-28-auth
276+ // REF: user-request-2026-03-19-github-token-status-owner
258277// SOURCE: n/a
259- // FORMAT THEOREM: forall env: status(env) -> labels(env)
278+ // FORMAT THEOREM: forall env: status(env) -> validated( labels(env) )
260279// PURITY: SHELL
261280// EFFECT: Effect<void, PlatformError, FileSystem | Path>
262281// INVARIANT: tokens are never logged
263- // COMPLEXITY: O(n) where n = |env |
282+ // COMPLEXITY: O(n) env scan + O(n) network round-trips where n = |tokens |
264283export const authGithubStatus = (
265284 command : AuthGithubStatusCommand
266285) : Effect . Effect < void , PlatformError , GithubFsRuntime > =>
@@ -271,10 +290,22 @@ export const authGithubStatus = (
271290 yield * _ ( Effect . log ( `GitHub not connected (no tokens in ${ envPath } ).` ) )
272291 return
273292 }
274- const sample = tokens . slice ( 0 , 20 ) . map ( ( entry ) => entry . label ) . join ( ", " )
275- const remaining = tokens . length - Math . min ( tokens . length , 20 )
276- const suffix = remaining > 0 ? ` ... (+${ remaining } more)` : ""
277- yield * _ ( Effect . log ( `GitHub tokens (${ tokens . length } ): ${ sample } ${ suffix } ` ) )
293+
294+ const statuses = yield * _ (
295+ Effect . forEach ( tokens , ( entry ) =>
296+ validateGithubToken ( entry . token ) . pipe (
297+ Effect . map ( ( validation ) => ( {
298+ key : entry . key ,
299+ label : entry . label ,
300+ token : entry . token ,
301+ status : validation . status ,
302+ login : validation . login
303+ } ) )
304+ )
305+ )
306+ )
307+
308+ yield * _ ( Effect . log ( renderGithubTokenStatusReport ( statuses ) ) )
278309 } ) )
279310
280311// CHANGE: remove GitHub auth token from the shared env file
0 commit comments