@@ -24,9 +24,9 @@ import (
24
24
"github.com/ossf/package-analysis/internal/log"
25
25
"github.com/ossf/package-analysis/internal/notification"
26
26
"github.com/ossf/package-analysis/internal/pkgmanager"
27
- "github.com/ossf/package-analysis/internal/resultstore"
28
27
"github.com/ossf/package-analysis/internal/sandbox"
29
28
"github.com/ossf/package-analysis/internal/staticanalysis"
29
+ "github.com/ossf/package-analysis/internal/useragent"
30
30
"github.com/ossf/package-analysis/internal/worker"
31
31
"github.com/ossf/package-analysis/pkg/api/pkgecosystem"
32
32
)
@@ -35,20 +35,6 @@ const (
35
35
localPkgPathFmt = "/local/%s"
36
36
)
37
37
38
- // resultBucketPaths holds bucket paths for the different types of results.
39
- type resultBucketPaths struct {
40
- analyzedPkg string
41
- dynamicAnalysis string
42
- executionLog string
43
- fileWrites string
44
- staticAnalysis string
45
- }
46
-
47
- type sandboxImageSpec struct {
48
- tag string
49
- noPull bool
50
- }
51
-
52
38
func copyPackageToLocalFile (ctx context.Context , packagesBucket * blob.Bucket , bucketPath string ) (string , * os.File , error ) {
53
39
if packagesBucket == nil {
54
40
return "" , nil , errors .New ("packages bucket not set" )
@@ -77,29 +63,7 @@ func copyPackageToLocalFile(ctx context.Context, packagesBucket *blob.Bucket, bu
77
63
return fmt .Sprintf (localPkgPathFmt , path .Base (bucketPath )), f , nil
78
64
}
79
65
80
- func makeResultStores (dest resultBucketPaths ) worker.ResultStores {
81
- resultStores := worker.ResultStores {}
82
-
83
- if dest .analyzedPkg != "" {
84
- resultStores .AnalyzedPackage = resultstore .New (dest .analyzedPkg , resultstore .ConstructPath ())
85
- }
86
- if dest .dynamicAnalysis != "" {
87
- resultStores .DynamicAnalysis = resultstore .New (dest .dynamicAnalysis , resultstore .ConstructPath ())
88
- }
89
- if dest .executionLog != "" {
90
- resultStores .ExecutionLog = resultstore .New (dest .executionLog , resultstore .ConstructPath ())
91
- }
92
- if dest .fileWrites != "" {
93
- resultStores .FileWrites = resultstore .New (dest .fileWrites , resultstore .ConstructPath ())
94
- }
95
- if dest .staticAnalysis != "" {
96
- resultStores .StaticAnalysis = resultstore .New (dest .staticAnalysis , resultstore .ConstructPath ())
97
- }
98
-
99
- return resultStores
100
- }
101
-
102
- func handleMessage (ctx context.Context , msg * pubsub.Message , packagesBucket * blob.Bucket , resultStores * worker.ResultStores , imageSpec sandboxImageSpec , notificationTopic * pubsub.Topic ) error {
66
+ func handleMessage (ctx context.Context , msg * pubsub.Message , cfg * config , packagesBucket * blob.Bucket , notificationTopic * pubsub.Topic ) error {
103
67
name := msg .Metadata ["name" ]
104
68
if name == "" {
105
69
slog .WarnContext (ctx , "name is empty" )
@@ -132,7 +96,7 @@ func handleMessage(ctx context.Context, msg *pubsub.Message, packagesBucket *blo
132
96
)
133
97
134
98
localPkgPath := ""
135
- sandboxOpts := []sandbox.Option {sandbox .Tag (imageSpec .tag )}
99
+ sandboxOpts := []sandbox.Option {sandbox .Tag (cfg . imageSpec .tag )}
136
100
137
101
if remotePkgPath != "" {
138
102
tmpPkgPath , pkgFile , err := copyPackageToLocalFile (ctx , packagesBucket , remotePkgPath )
@@ -146,7 +110,7 @@ func handleMessage(ctx context.Context, msg *pubsub.Message, packagesBucket *blo
146
110
sandboxOpts = append (sandboxOpts , sandbox .Volume (pkgFile .Name (), localPkgPath ))
147
111
}
148
112
149
- if imageSpec .noPull {
113
+ if cfg . imageSpec .noPull {
150
114
sandboxOpts = append (sandboxOpts , sandbox .NoPull ())
151
115
}
152
116
@@ -159,19 +123,24 @@ func handleMessage(ctx context.Context, msg *pubsub.Message, packagesBucket *blo
159
123
staticSandboxOpts := append (worker .StaticSandboxOptions (), sandboxOpts ... )
160
124
dynamicSandboxOpts := append (worker .DynamicSandboxOptions (), sandboxOpts ... )
161
125
126
+ // propogate user agent extras to the static analysis sandbox if it is set.
127
+ if cfg .userAgentExtra != "" {
128
+ staticSandboxOpts = append (staticSandboxOpts , sandbox .SetEnv ("OSSF_MALWARE_USER_AGENT_EXTRA" , cfg .userAgentExtra ))
129
+ }
130
+
162
131
// run both dynamic and static analysis regardless of error status of either
163
132
// and return combined error(s) afterwards, if applicable
164
133
staticResults , _ , staticAnalysisErr := worker .RunStaticAnalysis (ctx , pkg , staticSandboxOpts , staticanalysis .All )
165
134
if staticAnalysisErr == nil {
166
- staticAnalysisErr = worker .SaveStaticAnalysisData (ctx , pkg , resultStores , staticResults )
135
+ staticAnalysisErr = worker .SaveStaticAnalysisData (ctx , pkg , cfg . resultStores , staticResults )
167
136
}
168
137
169
138
result , dynamicAnalysisErr := worker .RunDynamicAnalysis (ctx , pkg , dynamicSandboxOpts , "" )
170
139
if dynamicAnalysisErr == nil {
171
- dynamicAnalysisErr = worker .SaveDynamicAnalysisData (ctx , pkg , resultStores , result .Data )
140
+ dynamicAnalysisErr = worker .SaveDynamicAnalysisData (ctx , pkg , cfg . resultStores , result .Data )
172
141
}
173
142
174
- resultStores .AnalyzedPackageSaved = false
143
+ cfg . resultStores .AnalyzedPackageSaved = false
175
144
176
145
// combine errors
177
146
if analysisErr := errors .Join (dynamicAnalysisErr , staticAnalysisErr ); analysisErr != nil {
@@ -187,12 +156,12 @@ func handleMessage(ctx context.Context, msg *pubsub.Message, packagesBucket *blo
187
156
return nil
188
157
}
189
158
190
- func messageLoop (ctx context.Context , subURL , packagesBucket , notificationTopicURL string , imageSpec sandboxImageSpec , resultsBuckets * worker. ResultStores ) error {
191
- sub , err := pubsub .OpenSubscription (ctx , subURL )
159
+ func messageLoop (ctx context.Context , cfg * config ) error {
160
+ sub , err := pubsub .OpenSubscription (ctx , cfg . subURL )
192
161
if err != nil {
193
162
return err
194
163
}
195
- extender , err := pubsubextender .New (ctx , subURL , sub )
164
+ extender , err := pubsubextender .New (ctx , cfg . subURL , sub )
196
165
if err != nil {
197
166
return err
198
167
}
@@ -205,18 +174,18 @@ func messageLoop(ctx context.Context, subURL, packagesBucket, notificationTopicU
205
174
// we pass in a nil notificationTopic object to handleMessage
206
175
// and continue with the analysis with no notifications published
207
176
var notificationTopic * pubsub.Topic
208
- if notificationTopicURL != "" {
209
- notificationTopic , err = pubsub .OpenTopic (ctx , notificationTopicURL )
177
+ if cfg . notificationTopicURL != "" {
178
+ notificationTopic , err = pubsub .OpenTopic (ctx , cfg . notificationTopicURL )
210
179
if err != nil {
211
180
return err
212
181
}
213
182
defer notificationTopic .Shutdown (ctx )
214
183
}
215
184
216
185
var pkgsBkt * blob.Bucket
217
- if packagesBucket != "" {
186
+ if cfg . packagesBucket != "" {
218
187
var err error
219
- pkgsBkt , err = blob .OpenBucket (ctx , packagesBucket )
188
+ pkgsBkt , err = blob .OpenBucket (ctx , cfg . packagesBucket )
220
189
if err != nil {
221
190
return err
222
191
}
@@ -246,7 +215,7 @@ func messageLoop(ctx context.Context, subURL, packagesBucket, notificationTopicU
246
215
return fmt .Errorf ("error starting message ack deadline extender: %w" , err )
247
216
}
248
217
249
- if err := handleMessage (msgCtx , msg , pkgsBkt , resultsBuckets , imageSpec , notificationTopic ); err != nil {
218
+ if err := handleMessage (msgCtx , msg , cfg , pkgsBkt , notificationTopic ); err != nil {
250
219
slog .ErrorContext (msgCtx , "Failed to process message" , "error" , err )
251
220
if err := me .Stop (); err != nil {
252
221
slog .ErrorContext (msgCtx , "Extender failed" , "error" , err )
@@ -267,35 +236,21 @@ func main() {
267
236
log .Initialize (os .Getenv ("LOGGER_ENV" ))
268
237
269
238
ctx := context .Background ()
270
- subURL := os . Getenv ( "OSSMALWARE_WORKER_SUBSCRIPTION" )
271
- packagesBucket := os . Getenv ( "OSSF_MALWARE_ANALYSIS_PACKAGES" )
272
- notificationTopicURL := os . Getenv ( "OSSF_MALWARE_NOTIFICATION_TOPIC" )
273
- enableProfiler := os . Getenv ( "OSSF_MALWARE_ANALYSIS_ENABLE_PROFILER" )
239
+
240
+ cfg := configFromEnv ( )
241
+
242
+ http . DefaultTransport = useragent . DefaultRoundTripper ( http . DefaultTransport , cfg . userAgentExtra )
274
243
275
244
if err := featureflags .Update (os .Getenv ("OSSF_MALWARE_FEATURE_FLAGS" )); err != nil {
276
245
slog .Error ("Failed to parse feature flags" , "error" , err )
277
246
os .Exit (1 )
278
247
}
279
248
280
- resultsBuckets := resultBucketPaths {
281
- analyzedPkg : os .Getenv ("OSSF_MALWARE_ANALYZED_PACKAGES" ),
282
- dynamicAnalysis : os .Getenv ("OSSF_MALWARE_ANALYSIS_RESULTS" ),
283
- executionLog : os .Getenv ("OSSF_MALWARE_ANALYSIS_EXECUTION_LOGS" ),
284
- fileWrites : os .Getenv ("OSSF_MALWARE_ANALYSIS_FILE_WRITE_RESULTS" ),
285
- staticAnalysis : os .Getenv ("OSSF_MALWARE_STATIC_ANALYSIS_RESULTS" ),
286
- }
287
- resultStores := makeResultStores (resultsBuckets )
288
-
289
- imageSpec := sandboxImageSpec {
290
- tag : os .Getenv ("OSSF_SANDBOX_IMAGE_TAG" ),
291
- noPull : os .Getenv ("OSSF_SANDBOX_NOPULL" ) != "" ,
292
- }
293
-
294
249
sandbox .InitNetwork (ctx )
295
250
296
251
// If configured, start a webserver so that Go's pprof can be accessed for
297
252
// debugging and profiling.
298
- if enableProfiler != "" {
253
+ if os . Getenv ( "OSSF_MALWARE_ANALYSIS_ENABLE_PROFILER" ) != "" {
299
254
go func () {
300
255
slog .Info ("Starting profiler" )
301
256
http .ListenAndServe (":6060" , nil )
@@ -304,20 +259,11 @@ func main() {
304
259
305
260
// Log the configuration of the worker at startup so we can observe it.
306
261
slog .InfoContext (ctx , "Starting worker" ,
307
- "subscription" , subURL ,
308
- "package_bucket" , packagesBucket ,
309
- "results_bucket" , resultsBuckets .dynamicAnalysis ,
310
- "static_results_bucket" , resultsBuckets .staticAnalysis ,
311
- "file_write_results_bucket" , resultsBuckets .fileWrites ,
312
- "analyzed_packages_bucket" , resultsBuckets .analyzedPkg ,
313
- "execution_log_bucket" , resultsBuckets .executionLog ,
314
- "image_tag" , imageSpec .tag ,
315
- "image_nopull" , imageSpec .noPull ,
316
- "topic_notification" , notificationTopicURL ,
262
+ "config" , cfg ,
317
263
"feature_flags" , featureflags .State (),
318
264
)
319
265
320
- err := messageLoop (ctx , subURL , packagesBucket , notificationTopicURL , imageSpec , & resultStores )
266
+ err := messageLoop (ctx , cfg )
321
267
if err != nil {
322
268
slog .ErrorContext (ctx , "Error encountered" , "error" , err )
323
269
}
0 commit comments