-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcodejob_gh_auth.go
More file actions
104 lines (86 loc) · 2.45 KB
/
Copy pathcodejob_gh_auth.go
File metadata and controls
104 lines (86 loc) · 2.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package devflow
import (
"fmt"
"os"
"strings"
"golang.org/x/term"
)
const ghTokenKey = "GH_TOKEN"
// GitHubPATAuth manages the GitHub PAT via the system keyring.
// It is used to recover the gh CLI session non-interactively.
type GitHubPATAuth struct {
kr *Keyring
log func(...any)
}
// NewGitHubPATAuth creates a GitHubPATAuth with an initialized keyring.
func NewGitHubPATAuth() (*GitHubPATAuth, error) {
kr, _ := NewKeyring()
return &GitHubPATAuth{
kr: kr,
log: func(...any) {},
}, nil
}
// SetLog sets the logging function.
func (a *GitHubPATAuth) SetLog(fn func(...any)) {
if fn != nil {
a.log = fn
}
}
// HasToken returns true if the GitHub PAT is already stored in the environment or keyring.
func (a *GitHubPATAuth) HasToken() bool {
if os.Getenv("GH_TOKEN") != "" {
return true
}
if a.kr == nil {
return false
}
tok, err := a.kr.Get(ghTokenKey)
return err == nil && tok != ""
}
// EnsureToken returns the PAT from the environment or keyring; if absent, prompts once and persists.
func (a *GitHubPATAuth) EnsureToken() (string, error) {
if envTok := os.Getenv("GH_TOKEN"); envTok != "" {
return envTok, nil
}
if a.kr == nil {
return "", fmt.Errorf("keyring is unavailable and GH_TOKEN env var is not set")
}
tok, err := a.kr.Get(ghTokenKey)
if err == nil && tok != "" {
return tok, nil
}
fmt.Fprintf(os.Stderr,
"GitHub token not found. Create a fine-grained PAT (Contents + Pull requests: Read/Write) at %s\nEnter it now: ",
termLink("https://github.com/settings/tokens", "https://github.com/settings/tokens"))
tok, err = readSecret()
if err != nil {
return "", err
}
if tok == "" {
return "", fmt.Errorf("no GitHub token provided")
}
if err := a.kr.Set(ghTokenKey, tok); err != nil {
a.log(fmt.Sprintf("warning: could not save GitHub token to keyring: %v", err))
}
return tok, nil
}
// Reset removes the GitHub PAT from the keyring.
func (a *GitHubPATAuth) Reset() error {
if a.kr == nil {
return fmt.Errorf("keyring is unavailable")
}
return a.kr.Delete(ghTokenKey)
}
// EnsureGitHubAuth fulfills the GitHubAuthenticator interface.
func (a *GitHubPATAuth) EnsureGitHubAuth() error {
return EnsureGHSession(RealRunner{})
}
// readSecret reads a secret from stdin without echoing.
func readSecret() (string, error) {
raw, err := term.ReadPassword(int(os.Stdin.Fd()))
fmt.Fprintln(os.Stderr)
if err != nil {
return "", fmt.Errorf("could not read secret: %w", err)
}
return strings.TrimSpace(string(raw)), nil
}