@@ -2,6 +2,9 @@ use serde::{Deserialize, Serialize};
22use std:: path:: Path ;
33use tracing:: { debug, info} ;
44
5+ const STATUS_PANEL_CAPABILITY : & str = "status_panel" ;
6+ const NPM_CREDENTIAL_SOURCE_VAULT : & str = "npm_credential_source=vault" ;
7+
58#[ derive( Debug , Serialize ) ]
69pub struct RegistrationRequest {
710 pub purchase_token : String ,
@@ -40,6 +43,7 @@ pub struct LinkAgentRequest {
4043 pub session_token : String ,
4144 pub deployment_id : String ,
4245 pub server_fingerprint : ServerFingerprint ,
46+ pub capabilities : Vec < String > ,
4347}
4448
4549#[ derive( Debug , Serialize ) ]
@@ -120,6 +124,54 @@ pub fn collect_fingerprint() -> ServerFingerprint {
120124 }
121125}
122126
127+ pub async fn collect_capabilities ( default_compose_agent_enabled : bool ) -> Vec < String > {
128+ let compose_agent = std:: env:: var ( "COMPOSE_AGENT_ENABLED" )
129+ . ok ( )
130+ . and_then ( |value| value. parse :: < bool > ( ) . ok ( ) )
131+ . unwrap_or ( default_compose_agent_enabled) ;
132+
133+ let mut features = vec ! [
134+ STATUS_PANEL_CAPABILITY . to_string( ) ,
135+ "monitoring" . to_string( ) ,
136+ NPM_CREDENTIAL_SOURCE_VAULT . to_string( ) ,
137+ ] ;
138+
139+ if cfg ! ( feature = "docker" ) {
140+ features. push ( "docker" . to_string ( ) ) ;
141+ features. push ( "compose" . to_string ( ) ) ;
142+ features. push ( "logs" . to_string ( ) ) ;
143+ features. push ( "restart" . to_string ( ) ) ;
144+ }
145+
146+ if compose_agent {
147+ features. push ( "compose_agent" . to_string ( ) ) ;
148+ }
149+
150+ #[ cfg( feature = "docker" ) ]
151+ {
152+ if crate :: commands:: stacker:: detect_kata_runtime ( ) . await {
153+ features. push ( "kata" . to_string ( ) ) ;
154+ }
155+ }
156+
157+ features
158+ }
159+
160+ fn marketplace_registration_url ( dashboard_url : & str ) -> String {
161+ format ! (
162+ "{}/api/v1/marketplace/agents/register" ,
163+ dashboard_url. trim_end_matches( '/' )
164+ )
165+ }
166+
167+ fn agent_link_url ( stacker_url : & str ) -> String {
168+ format ! ( "{}/api/v1/agent/link" , stacker_url. trim_end_matches( '/' ) )
169+ }
170+
171+ fn agent_login_url ( stacker_url : & str ) -> String {
172+ format ! ( "{}/api/v1/agent/login" , stacker_url. trim_end_matches( '/' ) )
173+ }
174+
123175/// Register this agent with the Stacker Server using a purchase token.
124176pub async fn register_with_stacker (
125177 dashboard_url : & str ,
@@ -142,7 +194,7 @@ pub async fn register_with_stacker(
142194 stack_id : stack_id. to_string ( ) ,
143195 } ;
144196
145- let url = format ! ( "{}/api/v1/agents/register" , dashboard_url) ;
197+ let url = marketplace_registration_url ( dashboard_url) ;
146198 info ! ( url = %url, stack_id = %stack_id, "sending registration request to Stacker" ) ;
147199
148200 let client = reqwest:: Client :: new ( ) ;
@@ -193,7 +245,7 @@ pub async fn login_to_stacker(
193245 password : password. to_string ( ) ,
194246 } ;
195247
196- let url = format ! ( "{}/api/v1/auth/login" , stacker_url) ;
248+ let url = agent_login_url ( stacker_url) ;
197249 info ! ( url = %url, email = %email, "sending login request to Stacker" ) ;
198250
199251 let client = reqwest:: Client :: new ( ) ;
@@ -219,8 +271,10 @@ pub async fn link_agent_to_deployment(
219271 stacker_url : & str ,
220272 session_token : & str ,
221273 deployment_id : & str ,
274+ default_compose_agent_enabled : bool ,
222275) -> Result < RegistrationResponse , Box < dyn std:: error:: Error > > {
223276 let fingerprint = collect_fingerprint ( ) ;
277+ let capabilities = collect_capabilities ( default_compose_agent_enabled) . await ;
224278 debug ! (
225279 hostname = %fingerprint. hostname,
226280 deployment_id = %deployment_id,
@@ -231,9 +285,10 @@ pub async fn link_agent_to_deployment(
231285 session_token : session_token. to_string ( ) ,
232286 deployment_id : deployment_id. to_string ( ) ,
233287 server_fingerprint : fingerprint,
288+ capabilities,
234289 } ;
235290
236- let url = format ! ( "{}/api/v1/agents/link" , stacker_url) ;
291+ let url = agent_link_url ( stacker_url) ;
237292 info ! ( url = %url, deployment_id = %deployment_id, "sending link request to Stacker" ) ;
238293
239294 let client = reqwest:: Client :: new ( ) ;
@@ -286,4 +341,39 @@ mod tests {
286341 assert_eq ! ( parsed[ "deployment_hash" ] , "hash-abc" ) ;
287342 assert_eq ! ( parsed[ "dashboard_url" ] , "https://stacker.try.direct" ) ;
288343 }
344+
345+ #[ test]
346+ fn marketplace_registration_url_uses_marketplace_scope ( ) {
347+ assert_eq ! (
348+ marketplace_registration_url( "https://stacker.try.direct/" ) ,
349+ "https://stacker.try.direct/api/v1/marketplace/agents/register"
350+ ) ;
351+ }
352+
353+ #[ test]
354+ fn agent_link_url_uses_singular_agent_scope ( ) {
355+ assert_eq ! (
356+ agent_link_url( "https://stacker.try.direct/" ) ,
357+ "https://stacker.try.direct/api/v1/agent/link"
358+ ) ;
359+ }
360+
361+ #[ test]
362+ fn agent_login_url_uses_agent_scope ( ) {
363+ assert_eq ! (
364+ agent_login_url( "https://stacker.try.direct/" ) ,
365+ "https://stacker.try.direct/api/v1/agent/login"
366+ ) ;
367+ }
368+
369+ #[ tokio:: test]
370+ async fn collect_capabilities_includes_vault_proxy_marker ( ) {
371+ let capabilities = collect_capabilities ( false ) . await ;
372+ assert ! ( capabilities
373+ . iter( )
374+ . any( |cap| cap == STATUS_PANEL_CAPABILITY ) ) ;
375+ assert ! ( capabilities
376+ . iter( )
377+ . any( |cap| cap == NPM_CREDENTIAL_SOURCE_VAULT ) ) ;
378+ }
289379}
0 commit comments