-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient_agent.go
More file actions
119 lines (104 loc) · 3.65 KB
/
client_agent.go
File metadata and controls
119 lines (104 loc) · 3.65 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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package shush
import (
"fmt"
"os"
"os/exec"
"strings"
"time"
)
// Ping checks if an agent is running at the given socket path.
func Ping(socketPath string) error {
return PingWithCapability(socketPath, ResolveCapability(nil))
}
// PingWithCapability checks if an agent is running with the provided capability.
func PingWithCapability(socketPath, capability string) error {
client := &Client{SocketPath: socketPath, Capability: capability}
_, err := client.do(request{Action: actionPing})
return err
}
// Stop requests the agent to shut down.
func Stop(socketPath string) error {
return StopWithCapability(socketPath, ResolveCapability(nil))
}
// StopWithCapability requests the agent to shut down with the provided capability.
func StopWithCapability(socketPath, capability string) error {
client := &Client{SocketPath: socketPath, Capability: capability}
_, err := client.do(request{Action: actionStop})
return err
}
// ClearAll removes all cached secrets and tokens from the agent.
func ClearAll(socketPath string) error {
client := &Client{SocketPath: socketPath, Capability: ResolveCapability(nil)}
if _, err := client.do(request{Action: actionClear}); err != nil {
return err
}
_, err := client.do(request{Action: actionClearToken})
return err
}
// ClearPrefix removes all cached secrets whose keys start with the prefix.
func ClearPrefix(socketPath, prefix string) error {
client := &Client{SocketPath: socketPath, Capability: ResolveCapability(nil)}
return client.ClearPrefix(prefix)
}
// ClearByKeyPattern removes all cached secrets matching the glob pattern.
func ClearByKeyPattern(socketPath, pattern string) error {
client := &Client{SocketPath: socketPath, Capability: ResolveCapability(nil)}
return client.ClearByKeyPattern(pattern)
}
// StartProcess starts an agent server in a background process.
// serveArgs specifies the full command and arguments (the socket path is appended).
// If serveArgs is nil, defaults to [os.Executable(), "serve", "--socket"].
func StartProcess(socketPath string, serveArgs []string) error {
return StartProcessWithCapability(socketPath, serveArgs, ResolveCapability(nil))
}
// StartProcessWithCapability starts an agent and configures capability protection.
func StartProcessWithCapability(socketPath string, serveArgs []string, capability string) error {
return startProcess(socketPath, serveArgs, capability)
}
func startProcess(socketPath string, serveArgs []string, capability string) error {
capability = strings.TrimSpace(capability)
if err := PingWithCapability(socketPath, capability); err == nil {
return nil
} else if isCapabilityAuthError(err) {
return err
}
if len(serveArgs) == 0 {
exePath, err := os.Executable()
if err != nil {
return fmt.Errorf("resolve executable path: %w", err)
}
serveArgs = []string{exePath, "serve", "--socket"}
}
args := append(serveArgs[1:], socketPath)
cmd := exec.Command(serveArgs[0], args...)
cmd.Stdin = nil
cmd.Stdout = nil
cmd.Stderr = nil
if capability != "" {
cmd.Env = withCapabilityEnv(os.Environ(), capability)
}
if err := cmd.Start(); err != nil {
return fmt.Errorf("start agent process: %w", err)
}
_ = cmd.Process.Release()
var lastErr error
for i := 0; i < 40; i++ {
time.Sleep(25 * time.Millisecond)
lastErr = PingWithCapability(socketPath, capability)
if lastErr == nil {
return nil
}
}
return fmt.Errorf("wait for agent startup: %w", lastErr)
}
func withCapabilityEnv(env []string, capability string) []string {
keyPrefix := EnvCapability + "="
out := make([]string, 0, len(env)+1)
for _, kv := range env {
if !strings.HasPrefix(kv, keyPrefix) {
out = append(out, kv)
}
}
out = append(out, keyPrefix+capability)
return out
}