@@ -12,7 +12,7 @@ import { FeaturesConfig, getContainerFeaturesBaseDockerFile, getFeatureInstallWr
1212import { readLocalFile } from '../spec-utils/pfs' ;
1313import { includeAllConfiguredFeatures } from '../spec-utils/product' ;
1414import { createFeaturesTempFolder , DockerResolverParameters , getCacheFolder , getFolderImageName , getEmptyContextFolder , SubstitutedConfig } from './utils' ;
15- import { isEarlierVersion , parseVersion } from '../spec-common/commonUtils' ;
15+ import { isEarlierVersion , parseVersion , runCommandNoPty } from '../spec-common/commonUtils' ;
1616import { getDevcontainerMetadata , getDevcontainerMetadataLabel , getImageBuildInfoFromImage , ImageBuildInfo , ImageMetadataEntry , imageMetadataLabel , MergedDevContainerConfig } from './imageMetadata' ;
1717import { supportsBuildContexts } from './dockerfileUtils' ;
1818import { ContainerError } from '../spec-common/errors' ;
@@ -92,6 +92,10 @@ export async function extendImage(params: DockerResolverParameters, config: Subs
9292 for ( const buildContext in featureBuildInfo . buildKitContexts ) {
9393 args . push ( '--build-context' , `${ buildContext } =${ featureBuildInfo . buildKitContexts [ buildContext ] } ` ) ;
9494 }
95+
96+ for ( const securityOpt of featureBuildInfo . securityOpts ) {
97+ args . push ( '--security-opt' , securityOpt ) ;
98+ }
9599 } else {
96100 // Not using buildx
97101 args . push (
@@ -186,6 +190,7 @@ export interface ImageBuildOptions {
186190 dockerfilePrefixContent : string ;
187191 buildArgs : Record < string , string > ;
188192 buildKitContexts : Record < string , string > ;
193+ securityOpts : string [ ] ;
189194}
190195
191196function getImageBuildOptions ( params : DockerResolverParameters , config : SubstitutedConfig < DevContainerConfig > , dstFolder : string , baseName : string , imageBuildInfo : ImageBuildInfo ) : ImageBuildOptions {
@@ -204,6 +209,7 @@ ${getDevcontainerMetadataLabel(getDevcontainerMetadata(imageBuildInfo.metadata,
204209 _DEV_CONTAINERS_BASE_IMAGE : baseName ,
205210 } as Record < string , string > ,
206211 buildKitContexts : { } as Record < string , string > ,
212+ securityOpts : [ ] ,
207213 } ;
208214}
209215
@@ -234,7 +240,7 @@ async function getFeaturesBuildOptions(params: DockerResolverParameters, devCont
234240 const minRequiredVersion = [ 0 , 8 , 0 ] ;
235241 const useBuildKitBuildContexts = buildKitVersionParsed ? ! isEarlierVersion ( buildKitVersionParsed , minRequiredVersion ) : false ;
236242 const buildContentImageName = 'dev_container_feature_content_temp' ;
237- const isBuildah = ! ! params . buildKitVersion ?. versionString . toLowerCase ( ) . includes ( 'buildah' ) ;
243+ const disableSELinuxLabels = useBuildKitBuildContexts && await isUsingSELinuxLabels ( params ) ;
238244
239245 const omitPropertyOverride = params . common . skipPersistingCustomizationsFromFeatures ? [ 'customizations' ] : [ ] ;
240246 const imageMetadata = getDevcontainerMetadata ( imageBuildInfo . metadata , devContainerConfig , featuresConfig , omitPropertyOverride , getOmitDevcontainerPropertyOverride ( params . common ) ) ;
@@ -251,7 +257,7 @@ async function getFeaturesBuildOptions(params: DockerResolverParameters, devCont
251257 const contentSourceRootPath = useBuildKitBuildContexts ? '.' : '/tmp/build-features/' ;
252258 const dockerfile = getContainerFeaturesBaseDockerFile ( contentSourceRootPath )
253259 . replace ( '#{nonBuildKitFeatureContentFallback}' , useBuildKitBuildContexts ? '' : `FROM ${ buildContentImageName } as dev_containers_feature_content_source` )
254- . replace ( '#{featureLayer}' , getFeatureLayers ( featuresConfig , containerUser , remoteUser , isBuildah , useBuildKitBuildContexts , contentSourceRootPath ) )
260+ . replace ( '#{featureLayer}' , getFeatureLayers ( featuresConfig , containerUser , remoteUser , useBuildKitBuildContexts , contentSourceRootPath ) )
255261 . replace ( '#{containerEnv}' , generateContainerEnvsV1 ( featuresConfig ) )
256262 . replace ( '#{devcontainerMetadata}' , getDevcontainerMetadataLabel ( imageMetadata ) )
257263 . replace ( '#{containerEnvMetadata}' , generateContainerEnvs ( devContainerConfig . config . containerEnv , true ) )
@@ -343,9 +349,32 @@ ARG _DEV_CONTAINERS_BASE_IMAGE=placeholder
343349 _DEV_CONTAINERS_FEATURE_CONTENT_SOURCE : buildContentImageName ,
344350 } ,
345351 buildKitContexts : useBuildKitBuildContexts ? { dev_containers_feature_content_source : dstFolder } : { } ,
352+ securityOpts : disableSELinuxLabels ? [ 'label=disable' ] : [ ] ,
346353 } ;
347354}
348355
356+ async function isUsingSELinuxLabels ( params : DockerResolverParameters ) : Promise < boolean > {
357+ try {
358+ const { common } = params ;
359+ const { cliHost, output } = common ;
360+ return params . isPodman && cliHost . platform === 'linux'
361+ && ( await runCommandNoPty ( {
362+ exec : cliHost . exec ,
363+ cmd : 'getenforce' ,
364+ output,
365+ print : true ,
366+ } ) ) . stdout . toString ( ) . trim ( ) !== 'Disabled'
367+ && ( await dockerCLI ( {
368+ ...toExecParameters ( params ) ,
369+ print : true ,
370+ } , 'info' , '-f' , '{{.Host.Security.SELinuxEnabled}}' ) ) . stdout . toString ( ) . trim ( ) === 'true' ;
371+ } catch {
372+ // If we can't run the commands, assume SELinux is not enabled.
373+ return false ;
374+
375+ }
376+ }
377+
349378export function findContainerUsers ( imageMetadata : SubstitutedConfig < ImageMetadataEntry [ ] > , composeServiceUser : string | undefined , imageUser : string ) {
350379 const reversed = imageMetadata . config . slice ( ) . reverse ( ) ;
351380 const containerUser = reversed . find ( entry => entry . containerUser ) ?. containerUser || composeServiceUser || imageUser ;
0 commit comments