1+ require 'uri'
2+
13module VCAP ::CloudController
24 class BuildpackLifecycleDataMessage < BaseMessage
35 register_allowed_keys %i[ buildpacks stack credentials ]
@@ -19,6 +21,7 @@ class BuildpackLifecycleDataMessage < BaseMessage
1921
2022 validate :buildpacks_content
2123 validate :credentials_content
24+ validate :custom_stack_requires_custom_buildpack
2225
2326 def buildpacks_content
2427 return unless buildpacks . is_a? ( Array )
@@ -40,7 +43,44 @@ def buildpacks_content
4043 def credentials_content
4144 return unless credentials . is_a? ( Hash )
4245
43- errors . add ( :credentials , 'credentials value must be a hash' ) if credentials . any? { |_ , v | !v . is_a? ( Hash ) }
46+ credentials . each do |registry , creds |
47+ unless creds . is_a? ( Hash )
48+ errors . add ( :credentials , "for registry '#{ registry } ' must be a hash" )
49+ next
50+ end
51+
52+ has_username = creds . key? ( 'username' ) || creds . key? ( :username )
53+ has_password = creds . key? ( 'password' ) || creds . key? ( :password )
54+ errors . add ( :base , "credentials for #{ registry } must include 'username' and 'password'" ) unless has_username && has_password
55+ end
56+ end
57+
58+ def custom_stack_requires_custom_buildpack
59+ return unless stack . is_a? ( String ) && is_custom_stack? ( stack )
60+ return unless FeatureFlag . enabled? ( :diego_custom_stacks )
61+ return unless buildpacks . is_a? ( Array )
62+
63+ buildpacks . each do |buildpack_name |
64+ # If buildpack is a URL, it's custom
65+ next if buildpack_name &.match? ( URI ::DEFAULT_PARSER . make_regexp )
66+
67+ # Check if it's a system buildpack
68+ system_buildpack = Buildpack . find ( name : buildpack_name )
69+ if system_buildpack
70+ errors . add ( :base , 'Buildpack must be a custom buildpack when using a custom stack' )
71+ break
72+ end
73+ end
74+ end
75+
76+ private
77+
78+ def is_custom_stack? ( stack_name )
79+ # Check for various container registry URL formats
80+ return true if stack_name . include? ( 'docker://' )
81+ return true if stack_name . match? ( %r{^https?://} ) # Any https/http URL
82+ return true if stack_name . include? ( '.' ) # Any string with a dot (likely a registry)
83+ false
4484 end
4585 end
4686end
0 commit comments