@@ -26,18 +26,12 @@ import (
2626
2727// Normalize compose project by moving deprecated attributes to their canonical position and injecting implicit defaults
2828func Normalize (dict map [string ]any , env types.Mapping ) (map [string ]any , error ) {
29- dict [ "networks" ] = normalizeNetworks (dict )
29+ normalizeNetworks (dict )
3030
3131 if d , ok := dict ["services" ]; ok {
3232 services := d .(map [string ]any )
3333 for name , s := range services {
3434 service := s .(map [string ]any )
35- _ , hasNetworks := service ["networks" ]
36- _ , hasNetworkMode := service ["network_mode" ]
37- if ! hasNetworks && ! hasNetworkMode {
38- // Service without explicit network attachment are implicitly exposed on default network
39- service ["networks" ] = map [string ]any {"default" : nil }
40- }
4135
4236 if service ["pull_policy" ] == types .PullPolicyIfNotPresent {
4337 service ["pull_policy" ] = types .PullPolicyMissing
@@ -137,18 +131,51 @@ func Normalize(dict map[string]any, env types.Mapping) (map[string]any, error) {
137131 return dict , nil
138132}
139133
140- func normalizeNetworks (dict map [string ]any ) map [ string ] any {
134+ func normalizeNetworks (dict map [string ]any ) {
141135 var networks map [string ]any
142136 if n , ok := dict ["networks" ]; ok {
143137 networks = n .(map [string ]any )
144138 } else {
145139 networks = map [string ]any {}
146140 }
147- if _ , ok := networks ["default" ]; ! ok {
141+
142+ // implicit `default` network must be introduced only if actually used by some service
143+ usesDefaultNetwork := false
144+
145+ if s , ok := dict ["services" ]; ok {
146+ services := s .(map [string ]any )
147+ for name , se := range services {
148+ service := se .(map [string ]any )
149+ if _ , ok := service ["network_mode" ]; ok {
150+ continue
151+ }
152+ if n , ok := service ["networks" ]; ! ok {
153+ // If none explicitly declared, service is connected to default network
154+ service ["networks" ] = map [string ]any {"default" : nil }
155+ usesDefaultNetwork = true
156+ } else {
157+ net := n .(map [string ]any )
158+ if len (net ) == 0 {
159+ // networks section declared but empty (corner case)
160+ service ["networks" ] = map [string ]any {"default" : nil }
161+ usesDefaultNetwork = true
162+ } else if _ , ok := net ["default" ]; ok {
163+ usesDefaultNetwork = true
164+ }
165+ }
166+ services [name ] = service
167+ }
168+ dict ["services" ] = services
169+ }
170+
171+ if _ , ok := networks ["default" ]; ! ok && usesDefaultNetwork {
148172 // If not declared explicitly, Compose model involves an implicit "default" network
149173 networks ["default" ] = nil
150174 }
151- return networks
175+
176+ if len (networks ) > 0 {
177+ dict ["networks" ] = networks
178+ }
152179}
153180
154181func resolve (a any , fn func (s string ) (string , bool )) (any , bool ) {
0 commit comments