@@ -37,8 +37,50 @@ pub const DEFAULT_DOCKER_NETWORK_NAME: &str = "openshell-docker";
3737/// Default domain used for browser-facing sandbox service URLs.
3838pub const DEFAULT_SERVICE_ROUTING_DOMAIN : & str = "openshell.localhost" ;
3939
40- /// Default OCI image for the openshell-sandbox supervisor binary.
41- pub const DEFAULT_SUPERVISOR_IMAGE : & str = "ghcr.io/nvidia/openshell/supervisor:latest" ;
40+ /// Default OCI repository for the supervisor image (no tag).
41+ pub const DEFAULT_SUPERVISOR_IMAGE_REPO : & str = "ghcr.io/nvidia/openshell/supervisor" ;
42+
43+ /// Return the default supervisor image reference with a version-pinned tag.
44+ #[ must_use]
45+ pub fn default_supervisor_image ( ) -> String {
46+ format ! (
47+ "{DEFAULT_SUPERVISOR_IMAGE_REPO}:{}" ,
48+ default_supervisor_image_tag( )
49+ )
50+ }
51+
52+ fn default_supervisor_image_tag ( ) -> String {
53+ resolve_supervisor_image_tag (
54+ option_env ! ( "OPENSHELL_IMAGE_TAG" ) ,
55+ option_env ! ( "IMAGE_TAG" ) ,
56+ env ! ( "CARGO_PKG_VERSION" ) ,
57+ )
58+ }
59+
60+ /// Resolve the supervisor image tag from build-time inputs.
61+ ///
62+ /// Priority: `OPENSHELL_IMAGE_TAG` > `IMAGE_TAG` > `CARGO_PKG_VERSION`.
63+ /// Falls back to `"dev"` when the Cargo version is empty or `"0.0.0"`.
64+ /// Replaces `+` with `-` for OCI tag compatibility.
65+ #[ must_use]
66+ pub fn resolve_supervisor_image_tag (
67+ openshell_image_tag : Option < & str > ,
68+ image_tag : Option < & str > ,
69+ cargo_pkg_version : & str ,
70+ ) -> String {
71+ let tag = openshell_image_tag
72+ . filter ( |tag| !tag. is_empty ( ) )
73+ . or_else ( || image_tag. filter ( |tag| !tag. is_empty ( ) ) )
74+ . unwrap_or_else ( || {
75+ if cargo_pkg_version. is_empty ( ) || cargo_pkg_version == "0.0.0" {
76+ "dev"
77+ } else {
78+ cargo_pkg_version
79+ }
80+ } ) ;
81+
82+ tag. replace ( '+' , "-" )
83+ }
4284
4385/// CDI device identifier for requesting all NVIDIA GPUs.
4486pub const CDI_GPU_DEVICE_ALL : & str = "nvidia.com/gpu=all" ;
@@ -1064,4 +1106,48 @@ mod tests {
10641106 }
10651107 }
10661108 }
1109+
1110+ #[ test]
1111+ fn supervisor_image_tag_prefers_explicit_build_tags ( ) {
1112+ use super :: resolve_supervisor_image_tag;
1113+ assert_eq ! (
1114+ resolve_supervisor_image_tag( Some ( "1.2.3" ) , Some ( "sha" ) , "0.0.0" ) ,
1115+ "1.2.3" ,
1116+ ) ;
1117+ assert_eq ! (
1118+ resolve_supervisor_image_tag( None , Some ( "sha" ) , "0.0.0" ) ,
1119+ "sha" ,
1120+ ) ;
1121+ assert_eq ! ( resolve_supervisor_image_tag( None , None , "1.2.3" ) , "1.2.3" , ) ;
1122+ assert_eq ! (
1123+ resolve_supervisor_image_tag( Some ( "" ) , Some ( "" ) , "0.0.0" ) ,
1124+ "dev" ,
1125+ ) ;
1126+ assert_eq ! (
1127+ resolve_supervisor_image_tag( Some ( "latest" ) , None , "1.2.3" ) ,
1128+ "latest" ,
1129+ ) ;
1130+ }
1131+
1132+ #[ test]
1133+ fn supervisor_image_tag_sanitizes_build_metadata_for_oci ( ) {
1134+ use super :: resolve_supervisor_image_tag;
1135+ assert_eq ! (
1136+ resolve_supervisor_image_tag( None , None , "0.0.37-dev.156+g1d3b741ee" ) ,
1137+ "0.0.37-dev.156-g1d3b741ee" ,
1138+ ) ;
1139+ assert_eq ! (
1140+ resolve_supervisor_image_tag( Some ( "0.0.37-dev.156+g1d3b741ee" ) , None , "0.0.0" ) ,
1141+ "0.0.37-dev.156-g1d3b741ee" ,
1142+ ) ;
1143+ }
1144+
1145+ #[ test]
1146+ fn default_supervisor_image_is_version_pinned ( ) {
1147+ use super :: default_supervisor_image;
1148+ let image = default_supervisor_image ( ) ;
1149+ assert ! ( image. starts_with( "ghcr.io/nvidia/openshell/supervisor:" ) ) ;
1150+ let tag = image. rsplit_once ( ':' ) . unwrap ( ) . 1 ;
1151+ assert ! ( !tag. is_empty( ) ) ;
1152+ }
10671153}
0 commit comments