@@ -4,6 +4,10 @@ import (
4
4
"context"
5
5
"fmt"
6
6
7
+ "golang.org/x/xerrors"
8
+
9
+ "github.com/google/uuid"
10
+
7
11
"github.com/coder/coder/v2/codersdk"
8
12
"github.com/coder/xray/jfrog"
9
13
@@ -23,10 +27,11 @@ type K8sReporter struct {
23
27
Namespace string
24
28
CoderClient CoderClient
25
29
Logger slog.Logger
26
- JFrogClient * jfrog.Client
30
+ JFrogClient jfrog.Client
31
+ ResultsChan chan codersdk.JFrogXrayScan
27
32
28
33
// Unexported fields are initialized on calls to Init.
29
- podInformer cache. SharedIndexInformer
34
+ factory informers. SharedInformerFactory
30
35
}
31
36
32
37
type WorkspaceAgent struct {
@@ -35,14 +40,14 @@ type WorkspaceAgent struct {
35
40
}
36
41
37
42
func (k * K8sReporter ) Init (ctx context.Context ) error {
38
- podFactory : = informers .NewSharedInformerFactoryWithOptions (k .Client , 0 , informers .WithNamespace (k .Namespace ), informers .WithTweakListOptions (func (lo * v1.ListOptions ) {
43
+ k . factory = informers .NewSharedInformerFactoryWithOptions (k .Client , 0 , informers .WithNamespace (k .Namespace ), informers .WithTweakListOptions (func (lo * v1.ListOptions ) {
39
44
lo .FieldSelector = k .FieldSelector
40
45
lo .LabelSelector = k .LabelSelector
41
46
}))
42
47
43
- k . podInformer = podFactory .Core ().V1 ().Pods ().Informer ()
48
+ podInformer := k . factory .Core ().V1 ().Pods ().Informer ()
44
49
45
- _ , err := k . podInformer .AddEventHandler (cache.ResourceEventHandlerFuncs {
50
+ _ , err := podInformer .AddEventHandler (cache.ResourceEventHandlerFuncs {
46
51
AddFunc : func (obj interface {}) {
47
52
pod , ok := obj .(* corev1.Pod )
48
53
if ! ok {
@@ -53,63 +58,72 @@ func (k *K8sReporter) Init(ctx context.Context) error {
53
58
log := k .Logger .With (
54
59
slog .F ("pod_name" , pod .Name ),
55
60
)
56
- var isWorkspace bool
57
61
for _ , container := range pod .Spec .Containers {
58
- var agentToken string
59
- for _ , env := range container .Env {
60
- if env .Name != "CODER_AGENT_TOKEN" {
61
- continue
62
- }
63
- isWorkspace = true
64
- agentToken = env .Value
65
- break
66
- }
67
- if agentToken == "" {
68
- continue
69
- }
70
-
71
62
log = log .With (
72
63
slog .F ("container_name" , container .Name ),
73
64
slog .F ("container_image" , container .Image ),
74
65
)
75
66
76
- image , err := jfrog .ParseImage (container .Image )
77
- if err != nil {
78
- log .Error (ctx , "parse image" , slog .Error (err ))
79
- return
80
- }
67
+ scan , err := func () (codersdk.JFrogXrayScan , error ) {
68
+ var agentToken string
69
+ for _ , env := range container .Env {
70
+ if env .Name != "CODER_AGENT_TOKEN" {
71
+ continue
72
+ }
73
+ agentToken = env .Value
74
+ break
75
+ }
76
+ if agentToken == "" {
77
+ return codersdk.JFrogXrayScan {}, nil
78
+ }
81
79
82
- scan , err := k .JFrogClient .ScanResults (image )
83
- if err != nil {
84
- log .Error (ctx , "fetch scan results" , slog .Error (err ))
85
- return
86
- }
80
+ image , err := jfrog .ParseImage (container .Image )
81
+ if err != nil {
82
+ return codersdk.JFrogXrayScan {}, xerrors .Errorf ("parse image: %w" , err )
83
+ }
87
84
88
- manifest , err := k .CoderClient .AgentManifest (ctx , agentToken )
89
- if err != nil {
90
- log .Error (ctx , "Get agent manifest" , slog .Error (err ))
91
- return
92
- }
85
+ scan , err := k .JFrogClient .ScanResults (image )
86
+ if err != nil {
87
+ return codersdk.JFrogXrayScan {}, xerrors .Errorf ("fetch scan results: %w" , err )
88
+ }
93
89
94
- log = log .With (
95
- slog .F ("workspace_id" , manifest .WorkspaceID ),
96
- slog .F ("agent_id" , manifest .AgentID ),
97
- slog .F ("workspace_name" , manifest .WorkspaceName ),
98
- )
90
+ manifest , err := k .CoderClient .AgentManifest (ctx , agentToken )
91
+ if err != nil {
92
+ return codersdk.JFrogXrayScan {}, xerrors .Errorf ("agent manifest: %w" , err )
93
+ }
99
94
100
- err = k .CoderClient .PostJFrogXrayScan (ctx , codersdk.JFrogXrayScan {
101
- WorkspaceID : manifest .WorkspaceID ,
102
- AgentID : manifest .AgentID ,
103
- Critical : scan .SecurityIssues .Critical ,
104
- High : scan .SecurityIssues .High ,
105
- })
95
+ log = log .With (
96
+ slog .F ("workspace_id" , manifest .WorkspaceID ),
97
+ slog .F ("agent_id" , manifest .AgentID ),
98
+ slog .F ("workspace_name" , manifest .WorkspaceName ),
99
+ )
100
+
101
+ req := codersdk.JFrogXrayScan {
102
+ WorkspaceID : manifest .WorkspaceID ,
103
+ AgentID : manifest .AgentID ,
104
+ Critical : scan .SecurityIssues .Critical ,
105
+ High : scan .SecurityIssues .High ,
106
+ }
107
+ err = k .CoderClient .PostJFrogXrayScan (ctx , req )
108
+ if err != nil {
109
+ return codersdk.JFrogXrayScan {}, xerrors .Errorf ("post xray scan: %w" , err )
110
+ }
111
+
112
+ return req , nil
113
+ }()
106
114
if err != nil {
107
- log .Error (ctx , "post xray results" , slog .Error (err ))
108
- return
115
+ log .Error (ctx , "scan agent" , slog .Error (err ))
116
+ break
117
+ }
118
+ if scan .AgentID != uuid .Nil {
119
+ log .Info (ctx , "uploaded agent results!" , slog .F ("pod_name" , pod .Name ), slog .F ("namespace" , pod .Namespace ))
120
+ if k .ResultsChan != nil {
121
+ // This should only be populated during tests
122
+ // so it's ok to assume an unbuffered channel is
123
+ // going to block until read.
124
+ k .ResultsChan <- scan
125
+ }
109
126
}
110
- }
111
- if isWorkspace {
112
- log .Info (ctx , "uploaded workspace results!" , slog .F ("pod_name" , pod .Name ), slog .F ("namespace" , pod .Namespace ))
113
127
}
114
128
},
115
129
})
@@ -120,5 +134,5 @@ func (k *K8sReporter) Init(ctx context.Context) error {
120
134
}
121
135
122
136
func (k * K8sReporter ) Start (stop chan struct {}) {
123
- k .podInformer . Run (stop )
137
+ k .factory . Start (stop )
124
138
}
0 commit comments