@@ -33,6 +33,7 @@ type BuildParams struct {
3333 WorkdirMount string
3434 BuildArgs []string
3535 BuildArgsFile string
36+ Envs []string
3637 ContainerfileJsonOutput string
3738 ExtraArgs []string
3839}
@@ -158,6 +159,10 @@ func runBuildWithOutput(container *TestRunnerContainer, buildParams BuildParams)
158159 if buildParams .BuildArgsFile != "" {
159160 args = append (args , "--build-args-file" , buildParams .BuildArgsFile )
160161 }
162+ if len (buildParams .Envs ) > 0 {
163+ args = append (args , "--envs" )
164+ args = append (args , buildParams .Envs ... )
165+ }
161166 if buildParams .ContainerfileJsonOutput != "" {
162167 args = append (args , "--containerfile-json-output" , buildParams .ContainerfileJsonOutput )
163168 }
@@ -201,25 +206,37 @@ func writeContainerfile(contextDir, content string) {
201206 Expect (err ).ToNot (HaveOccurred ())
202207}
203208
204- func getImageLabels (container * TestRunnerContainer , imageRef string ) map [string ]string {
209+ type containerImageMeta struct {
210+ labels map [string ]string
211+ envs map [string ]string
212+ }
213+
214+ func getImageMeta (container * TestRunnerContainer , imageRef string ) containerImageMeta {
205215 stdout , _ , err := container .ExecuteCommandWithOutput ("buildah" , "inspect" , imageRef )
206216 Expect (err ).ToNot (HaveOccurred ())
207217
208218 var inspect struct {
209219 OCIv1 struct {
210220 Config struct {
211221 Labels map [string ]string
222+ Env []string
212223 } `json:"config"`
213224 }
214225 }
215226
216227 err = json .Unmarshal ([]byte (stdout ), & inspect )
217228 Expect (err ).ToNot (HaveOccurred ())
218229
219- return inspect .OCIv1 .Config .Labels
230+ envs := make (map [string ]string , len (inspect .OCIv1 .Config .Env ))
231+ for _ , env := range inspect .OCIv1 .Config .Env {
232+ key , value , _ := strings .Cut (env , "=" )
233+ envs [key ] = value
234+ }
235+
236+ return containerImageMeta {labels : inspect .OCIv1 .Config .Labels , envs : envs }
220237}
221238
222- func getContainerfileLabels (container * TestRunnerContainer , containerfileJsonPath string ) map [ string ] string {
239+ func getContainerfileMeta (container * TestRunnerContainer , containerfileJsonPath string ) containerImageMeta {
223240 containerfileJSON , err := container .GetFileContent (containerfileJsonPath )
224241 Expect (err ).ToNot (HaveOccurred ())
225242
@@ -232,8 +249,12 @@ func getContainerfileLabels(container *TestRunnerContainer, containerfileJsonPat
232249 Commands []struct {
233250 Name string
234251 Labels []struct {
235- Key string
236- Value string
252+ Key string
253+ Value string
254+ }
255+ Env []struct {
256+ Key string
257+ Value string
237258 }
238259 }
239260 }
@@ -243,14 +264,18 @@ func getContainerfileLabels(container *TestRunnerContainer, containerfileJsonPat
243264 Expect (err ).ToNot (HaveOccurred ())
244265
245266 labels := make (map [string ]string )
267+ envs := make (map [string ]string )
268+
246269 for _ , cmd := range containerfile .Stages [0 ].Commands {
247- if strings .ToLower (cmd .Name ) == "label" {
248- for _ , label := range cmd .Labels {
249- labels [label .Key ] = label .Value
250- }
270+ for _ , label := range cmd .Labels {
271+ labels [label .Key ] = label .Value
272+ }
273+ for _ , env := range cmd .Env {
274+ envs [env .Key ] = env .Value
251275 }
252276 }
253- return labels
277+
278+ return containerImageMeta {labels : labels , envs : envs }
254279}
255280
256281func formatAsKeyValuePairs (m map [string ]string ) []string {
@@ -562,12 +587,15 @@ LABEL test.label="build-args-test"
562587 "undefined-buildarg=" ,
563588 }
564589
590+ imageMeta := getImageMeta (container , outputRef )
591+ containerfileMeta := getContainerfileMeta (container , containerfileJsonPath )
592+
565593 // Verify image labels
566- imageLabels := formatAsKeyValuePairs (getImageLabels ( container , outputRef ) )
594+ imageLabels := formatAsKeyValuePairs (imageMeta . labels )
567595 Expect (imageLabels ).To (ContainElements (expectedLabels ))
568596
569597 // Verify the parsed Containerfile has the same label values
570- containerfileLabels := formatAsKeyValuePairs (getContainerfileLabels ( container , containerfileJsonPath ) )
598+ containerfileLabels := formatAsKeyValuePairs (containerfileMeta . labels )
571599 Expect (containerfileLabels ).To (ContainElements (expectedLabels ))
572600 })
573601
@@ -614,8 +642,8 @@ LABEL test.label="platform-build-args-test"
614642 Expect (err ).ToNot (HaveOccurred ())
615643
616644 // Verify platform values match between the parsed Containerfile and the actual image
617- imageLabels := getImageLabels (container , outputRef )
618- containerfileLabels := getContainerfileLabels (container , containerfileJsonPath )
645+ imageLabels := getImageMeta (container , outputRef ). labels
646+ containerfileLabels := getContainerfileMeta (container , containerfileJsonPath ). labels
619647
620648 labelsToCheck := []string {
621649 "TARGETPLATFORM" ,
@@ -698,4 +726,75 @@ LABEL test.label="platform-build-args-test"
698726 ]
699727}` ))
700728 })
729+
730+ t .Run ("WithEnvs" , func (t * testing.T ) {
731+ contextDir := setupTestContext (t )
732+
733+ writeContainerfile (contextDir , `
734+ FROM scratch
735+
736+ LABEL foo=$FOO
737+ LABEL bar=$BAR
738+
739+ LABEL test.label="envs-test"
740+ ` )
741+
742+ outputRef := "localhost/test-image-envs:" + GenerateUniqueTag (t )
743+ // Also verify that envs are handled properly for Containerfile parsing
744+ containerfileJsonPath := "/workspace/parsed-containerfile.json"
745+
746+ buildParams := BuildParams {
747+ Context : contextDir ,
748+ OutputRef : outputRef ,
749+ Push : false ,
750+ Envs : []string {
751+ "FOO=foo-value" ,
752+ "BAR=bar-value" ,
753+ // Corner cases to verify that dockerfile-json and buildah handle them the same way
754+ // Should be an env var without a name (causes an error when starting the container)
755+ "=noname" ,
756+ // Should be an empty string
757+ "NOVALUE=" ,
758+ // Shouldn't be set at all
759+ "NOSUCHENV" ,
760+ },
761+ ContainerfileJsonOutput : containerfileJsonPath ,
762+ }
763+
764+ container := setupBuildContainerWithCleanup (t , buildParams , nil )
765+
766+ err := runBuild (container , buildParams )
767+ Expect (err ).ToNot (HaveOccurred ())
768+
769+ expectedEnvs := []string {
770+ "FOO=foo-value" ,
771+ "BAR=bar-value" ,
772+ "=noname" ,
773+ "NOVALUE=" ,
774+ }
775+ expectedLabels := []string {
776+ "foo=foo-value" ,
777+ "bar=bar-value" ,
778+ }
779+
780+ imageMeta := getImageMeta (container , outputRef )
781+ containerfileMeta := getContainerfileMeta (container , containerfileJsonPath )
782+
783+ // Verify envs
784+ imageEnvs := formatAsKeyValuePairs (imageMeta .envs )
785+ Expect (imageEnvs ).To (ContainElements (expectedEnvs ))
786+
787+ containerfileEnvs := formatAsKeyValuePairs (containerfileMeta .envs )
788+ Expect (containerfileEnvs ).To (ContainElements (expectedEnvs ))
789+
790+ Expect (imageMeta .envs ).ToNot (HaveKey ("NOSUCHENV" ))
791+ Expect (containerfileMeta .envs ).ToNot (HaveKey ("NOSUCHENV" ))
792+
793+ // Verify labels
794+ imageLabels := formatAsKeyValuePairs (imageMeta .labels )
795+ Expect (imageLabels ).To (ContainElements (expectedLabels ))
796+
797+ containerfileLabels := formatAsKeyValuePairs (containerfileMeta .labels )
798+ Expect (containerfileLabels ).To (ContainElements (expectedLabels ))
799+ })
701800}
0 commit comments