@@ -147,7 +147,11 @@ pub struct ExploitIntelligenceArgs {
147147 pub exploit_intelligence_url : Option < String > ,
148148
149149 /// Base URL of the Exploit Intelligence web UI for deep-linking to reports.
150- #[ arg( long, env = "EXPLOIT_INTELLIGENCE_UI_URL" ) ]
150+ #[ arg(
151+ long,
152+ env = "EXPLOIT_INTELLIGENCE_UI_URL" ,
153+ requires = "exploit_intelligence_url"
154+ ) ]
151155 pub exploit_intelligence_ui_url : Option < String > ,
152156
153157 /// Polling interval for EI analysis completion (humantime, e.g. "30s").
@@ -245,21 +249,24 @@ pub struct EiOidcArguments {
245249 #[ arg(
246250 id = "ei_oidc_client_id" ,
247251 long = "ei-oidc-client-id" ,
248- env = "EXPLOIT_INTELLIGENCE_OIDC_CLIENT_ID"
252+ env = "EXPLOIT_INTELLIGENCE_OIDC_CLIENT_ID" ,
253+ requires_all = [ "ei_oidc_client_secret" , "ei_oidc_issuer_url" ]
249254 ) ]
250255 pub client_id : Option < String > ,
251256
252257 #[ arg(
253258 id = "ei_oidc_client_secret" ,
254259 long = "ei-oidc-client-secret" ,
255- env = "EXPLOIT_INTELLIGENCE_OIDC_CLIENT_SECRET"
260+ env = "EXPLOIT_INTELLIGENCE_OIDC_CLIENT_SECRET" ,
261+ requires_all = [ "ei_oidc_client_id" , "ei_oidc_issuer_url" ]
256262 ) ]
257263 pub client_secret : Option < String > ,
258264
259265 #[ arg(
260266 id = "ei_oidc_issuer_url" ,
261267 long = "ei-oidc-issuer-url" ,
262- env = "EXPLOIT_INTELLIGENCE_OIDC_ISSUER_URL"
268+ env = "EXPLOIT_INTELLIGENCE_OIDC_ISSUER_URL" ,
269+ requires_all = [ "ei_oidc_client_id" , "ei_oidc_client_secret" ]
263270 ) ]
264271 pub issuer_url : Option < String > ,
265272
@@ -282,28 +289,19 @@ pub struct EiOidcArguments {
282289
283290impl EiOidcArguments {
284291 fn into_config ( self ) -> Option < trustify_auth:: client:: OpenIdTokenProviderConfig > {
285- match ( self . client_id , self . client_secret , self . issuer_url ) {
286- ( Some ( client_id) , Some ( client_secret) , Some ( issuer_url) ) => {
287- Some ( trustify_auth:: client:: OpenIdTokenProviderConfig {
288- client_id,
289- client_secret,
290- issuer_url,
291- refresh_before : self . refresh_before ,
292- tls_insecure : self . tls_insecure ,
293- } )
294- }
295- ( None , None , None ) => None ,
296- _ => {
297- log:: warn!(
298- "Incomplete EI OIDC configuration: all three of \
299- EXPLOIT_INTELLIGENCE_OIDC_CLIENT_ID, \
300- EXPLOIT_INTELLIGENCE_OIDC_CLIENT_SECRET, and \
301- EXPLOIT_INTELLIGENCE_OIDC_ISSUER_URL must be set together. \
302- Falling back to static token or no auth."
303- ) ;
304- None
305- }
306- }
292+ // clap's `requires_all` guarantees all three are present or all absent.
293+ let ( Some ( client_id) , Some ( client_secret) , Some ( issuer_url) ) =
294+ ( self . client_id , self . client_secret , self . issuer_url )
295+ else {
296+ return None ;
297+ } ;
298+ Some ( trustify_auth:: client:: OpenIdTokenProviderConfig {
299+ client_id,
300+ client_secret,
301+ issuer_url,
302+ refresh_before : self . refresh_before ,
303+ tls_insecure : self . tls_insecure ,
304+ } )
307305 }
308306}
309307
@@ -504,44 +502,9 @@ impl InitData {
504502 async fn run ( mut self ) -> anyhow:: Result < ( ) > {
505503 let ui = Arc :: new ( UiResources :: new ( & self . ui ) ?) ;
506504
507- // Create shared Graph and ExploitIntelligenceService before any
508- // closures so the same instances are reused by both the API
509- // endpoints and the background worker.
510505 let graph = Graph :: new ( ) ;
511506 let ei_service = ExploitIntelligenceService :: new ( self . ei_config . take ( ) ) ?;
512-
513- // Build the EI worker task before the HTTP server captures `self`.
514- let ei_worker_task = if let Some ( rt) = ei_service. runtime ( ) {
515- if !self . read_only {
516- let worker_poll_interval = rt. config . worker_poll_interval ;
517- let worker_service = ei_service. clone ( ) ;
518- let ingestor_for_worker = trustify_module_ingestor:: service:: IngestorService :: new (
519- graph. clone ( ) ,
520- self . storage . clone ( ) ,
521- Some ( self . analysis . clone ( ) ) ,
522- ) ;
523- let db_rw = self . db_rw . clone ( ) ;
524- let db_ro = self . db_ro . clone ( ) ;
525-
526- Some (
527- async move {
528- run_worker (
529- worker_service,
530- ingestor_for_worker,
531- db_rw,
532- db_ro,
533- worker_poll_interval,
534- )
535- . await
536- }
537- . boxed_local ( ) ,
538- )
539- } else {
540- None
541- }
542- } else {
543- None
544- } ;
507+ let ei_worker_task = build_ei_worker_task ( & ei_service, & graph, & self , self . read_only ) ;
545508
546509 let http = {
547510 HttpServerBuilder :: try_from ( self . http ) ?
@@ -574,9 +537,7 @@ impl InitData {
574537 #[ allow( unused_mut) ]
575538 let mut tasks = vec ! [ http] ;
576539
577- if let Some ( worker) = ei_worker_task {
578- tasks. push ( worker) ;
579- }
540+ tasks. extend ( ei_worker_task) ;
580541
581542 // track the embedded OIDC server task
582543 #[ cfg( feature = "garage-door" ) ]
@@ -598,6 +559,35 @@ impl InitData {
598559 }
599560}
600561
562+ type Task = futures:: future:: LocalBoxFuture < ' static , anyhow:: Result < ( ) > > ;
563+
564+ fn build_ei_worker_task (
565+ ei_service : & ExploitIntelligenceService ,
566+ graph : & Graph ,
567+ init : & InitData ,
568+ read_only : bool ,
569+ ) -> Option < Task > {
570+ let rt = ei_service. runtime ( ) ?;
571+ if read_only {
572+ return None ;
573+ }
574+ let worker_poll_interval = rt. config . worker_poll_interval ;
575+ let worker_service = ei_service. clone ( ) ;
576+ let ingestor = trustify_module_ingestor:: service:: IngestorService :: new (
577+ graph. clone ( ) ,
578+ init. storage . clone ( ) ,
579+ Some ( init. analysis . clone ( ) ) ,
580+ ) ;
581+ let db_rw = init. db_rw . clone ( ) ;
582+ let db_ro = init. db_ro . clone ( ) ;
583+ Some (
584+ async move {
585+ run_worker ( worker_service, ingestor, db_rw, db_ro, worker_poll_interval) . await
586+ }
587+ . boxed_local ( ) ,
588+ )
589+ }
590+
601591pub fn default_openapi_info ( ) -> Info {
602592 let mut info = Info :: new ( "Trustify" , env ! ( "CARGO_PKG_VERSION" ) ) ;
603593 info. description = Some ( "Software Supply-Chain Security API" . into ( ) ) ;
0 commit comments