makit 0.0.164 → 0.0.166

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -41
  3. data/exe/makit +5 -5
  4. data/lib/makit/apache.rb +28 -28
  5. data/lib/makit/auto.rb +48 -48
  6. data/lib/makit/azure/blob_storage.rb +257 -257
  7. data/lib/makit/azure/cli.rb +284 -284
  8. data/lib/makit/azure-pipelines.rb +139 -0
  9. data/lib/makit/cli/base.rb +17 -17
  10. data/lib/makit/cli/build_commands.rb +500 -500
  11. data/lib/makit/cli/generators/base_generator.rb +74 -74
  12. data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
  13. data/lib/makit/cli/generators/generator_factory.rb +49 -49
  14. data/lib/makit/cli/generators/node_generator.rb +50 -50
  15. data/lib/makit/cli/generators/ruby_generator.rb +77 -77
  16. data/lib/makit/cli/generators/rust_generator.rb +50 -50
  17. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
  18. data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
  19. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
  20. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +41 -41
  21. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
  22. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
  23. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
  24. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
  25. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
  26. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
  27. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
  28. data/lib/makit/cli/main.rb +78 -78
  29. data/lib/makit/cli/pipeline_commands.rb +311 -311
  30. data/lib/makit/cli/project_commands.rb +868 -868
  31. data/lib/makit/cli/repository_commands.rb +661 -661
  32. data/lib/makit/cli/strategy_commands.rb +207 -207
  33. data/lib/makit/cli/utility_commands.rb +521 -521
  34. data/lib/makit/commands/factory.rb +359 -359
  35. data/lib/makit/commands/middleware/base.rb +73 -73
  36. data/lib/makit/commands/middleware/cache.rb +248 -248
  37. data/lib/makit/commands/middleware/command_logger.rb +312 -312
  38. data/lib/makit/commands/middleware/validator.rb +269 -269
  39. data/lib/makit/commands/request.rb +316 -316
  40. data/lib/makit/commands/result.rb +323 -323
  41. data/lib/makit/commands/runner.rb +386 -386
  42. data/lib/makit/commands/strategies/base.rb +171 -171
  43. data/lib/makit/commands/strategies/child_process.rb +162 -162
  44. data/lib/makit/commands/strategies/factory.rb +136 -136
  45. data/lib/makit/commands/strategies/synchronous.rb +139 -139
  46. data/lib/makit/commands.rb +50 -50
  47. data/lib/makit/configuration/dotnet_project.rb +48 -48
  48. data/lib/makit/configuration/gitlab_helper.rb +61 -61
  49. data/lib/makit/configuration/project.rb +292 -292
  50. data/lib/makit/configuration/rakefile_helper.rb +43 -43
  51. data/lib/makit/configuration/step.rb +34 -34
  52. data/lib/makit/configuration/timeout.rb +74 -74
  53. data/lib/makit/configuration.rb +21 -21
  54. data/lib/makit/content/default_gitignore.rb +7 -7
  55. data/lib/makit/content/default_gitignore.txt +225 -225
  56. data/lib/makit/content/default_rakefile.rb +13 -13
  57. data/lib/makit/content/gem_rakefile.rb +16 -16
  58. data/lib/makit/context.rb +1 -1
  59. data/lib/makit/data.rb +49 -49
  60. data/lib/makit/directories.rb +170 -170
  61. data/lib/makit/directory.rb +262 -262
  62. data/lib/makit/docs/files.rb +89 -89
  63. data/lib/makit/docs/rake.rb +102 -102
  64. data/lib/makit/dotnet/cli.rb +224 -224
  65. data/lib/makit/dotnet/project.rb +217 -217
  66. data/lib/makit/dotnet/solution.rb +38 -38
  67. data/lib/makit/dotnet/solution_classlib.rb +239 -239
  68. data/lib/makit/dotnet/solution_console.rb +264 -264
  69. data/lib/makit/dotnet/solution_maui.rb +354 -354
  70. data/lib/makit/dotnet/solution_wasm.rb +275 -275
  71. data/lib/makit/dotnet/solution_wpf.rb +304 -304
  72. data/lib/makit/dotnet.rb +110 -110
  73. data/lib/makit/email.rb +90 -90
  74. data/lib/makit/environment.rb +142 -142
  75. data/lib/makit/examples/runner.rb +370 -370
  76. data/lib/makit/exceptions.rb +45 -45
  77. data/lib/makit/fileinfo.rb +32 -32
  78. data/lib/makit/files.rb +43 -43
  79. data/lib/makit/gems.rb +49 -49
  80. data/lib/makit/git/cli.rb +103 -103
  81. data/lib/makit/git/repository.rb +100 -100
  82. data/lib/makit/git.rb +104 -104
  83. data/lib/makit/gitlab/pipeline.rb +857 -857
  84. data/lib/makit/gitlab/pipeline_service_impl.rb +1535 -1535
  85. data/lib/makit/gitlab_runner.rb +59 -59
  86. data/lib/makit/humanize.rb +218 -218
  87. data/lib/makit/indexer.rb +47 -47
  88. data/lib/makit/io/filesystem.rb +111 -111
  89. data/lib/makit/io/filesystem_service_impl.rb +337 -337
  90. data/lib/makit/lint.rb +212 -212
  91. data/lib/makit/logging/configuration.rb +309 -309
  92. data/lib/makit/logging/format_registry.rb +84 -84
  93. data/lib/makit/logging/formatters/base.rb +39 -39
  94. data/lib/makit/logging/formatters/console_formatter.rb +140 -140
  95. data/lib/makit/logging/formatters/json_formatter.rb +65 -65
  96. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
  97. data/lib/makit/logging/formatters/text_formatter.rb +64 -64
  98. data/lib/makit/logging/log_request.rb +119 -119
  99. data/lib/makit/logging/logger.rb +199 -199
  100. data/lib/makit/logging/sinks/base.rb +91 -91
  101. data/lib/makit/logging/sinks/console.rb +72 -72
  102. data/lib/makit/logging/sinks/file_sink.rb +92 -92
  103. data/lib/makit/logging/sinks/structured.rb +123 -123
  104. data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
  105. data/lib/makit/logging.rb +578 -578
  106. data/lib/makit/markdown.rb +75 -75
  107. data/lib/makit/mp/basic_object_mp.rb +17 -17
  108. data/lib/makit/mp/command_mp.rb +13 -13
  109. data/lib/makit/mp/command_request.mp.rb +17 -17
  110. data/lib/makit/mp/project_mp.rb +199 -199
  111. data/lib/makit/mp/string_mp.rb +205 -205
  112. data/lib/makit/nuget.rb +454 -454
  113. data/lib/makit/podman/podman.rb +458 -458
  114. data/lib/makit/podman/podman_service_impl.rb +1081 -1081
  115. data/lib/makit/port.rb +32 -32
  116. data/lib/makit/process.rb +377 -377
  117. data/lib/makit/protoc.rb +112 -112
  118. data/lib/makit/rake/cli.rb +196 -196
  119. data/lib/makit/rake/trace_controller.rb +174 -174
  120. data/lib/makit/rake.rb +81 -81
  121. data/lib/makit/ruby/cli.rb +185 -185
  122. data/lib/makit/ruby.rb +25 -25
  123. data/lib/makit/rubygems.rb +137 -137
  124. data/lib/makit/secrets/azure_key_vault.rb +322 -322
  125. data/lib/makit/secrets/azure_secrets.rb +221 -183
  126. data/lib/makit/secrets/local_secrets.rb +72 -72
  127. data/lib/makit/secrets/secrets_manager.rb +105 -105
  128. data/lib/makit/secrets.rb +96 -16
  129. data/lib/makit/serializer.rb +130 -130
  130. data/lib/makit/services/builder.rb +186 -186
  131. data/lib/makit/services/error_handler.rb +226 -226
  132. data/lib/makit/services/repository_manager.rb +367 -367
  133. data/lib/makit/services/validator.rb +112 -112
  134. data/lib/makit/setup/classlib.rb +101 -101
  135. data/lib/makit/setup/gem.rb +268 -268
  136. data/lib/makit/setup/pages.rb +11 -11
  137. data/lib/makit/setup/razorclasslib.rb +101 -101
  138. data/lib/makit/setup/runner.rb +54 -54
  139. data/lib/makit/setup.rb +5 -5
  140. data/lib/makit/show.rb +110 -110
  141. data/lib/makit/storage.rb +126 -126
  142. data/lib/makit/symbols.rb +175 -175
  143. data/lib/makit/task_info.rb +130 -130
  144. data/lib/makit/tasks/at_exit.rb +15 -15
  145. data/lib/makit/tasks/build.rb +22 -22
  146. data/lib/makit/tasks/bump.rb +7 -7
  147. data/lib/makit/tasks/clean.rb +13 -13
  148. data/lib/makit/tasks/configure.rb +10 -10
  149. data/lib/makit/tasks/format.rb +10 -10
  150. data/lib/makit/tasks/hook_manager.rb +443 -443
  151. data/lib/makit/tasks/info.rb +368 -368
  152. data/lib/makit/tasks/init.rb +49 -49
  153. data/lib/makit/tasks/integrate.rb +60 -60
  154. data/lib/makit/tasks/pull_incoming.rb +13 -13
  155. data/lib/makit/tasks/secrets.rb +7 -7
  156. data/lib/makit/tasks/setup.rb +16 -16
  157. data/lib/makit/tasks/sync.rb +14 -14
  158. data/lib/makit/tasks/tag.rb +27 -27
  159. data/lib/makit/tasks/task_monkey_patch.rb +81 -81
  160. data/lib/makit/tasks/test.rb +22 -22
  161. data/lib/makit/tasks/update.rb +21 -21
  162. data/lib/makit/tasks/version.rb +6 -6
  163. data/lib/makit/tasks.rb +24 -24
  164. data/lib/makit/test_cache.rb +239 -239
  165. data/lib/makit/tree.rb +37 -37
  166. data/lib/makit/v1/configuration/project_service_impl.rb +370 -370
  167. data/lib/makit/v1/git/git_repository_service_impl.rb +295 -295
  168. data/lib/makit/v1/makit.v1_pb.rb +35 -35
  169. data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
  170. data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -572
  171. data/lib/makit/version.rb +661 -661
  172. data/lib/makit/version_util.rb +21 -21
  173. data/lib/makit/wix.rb +95 -95
  174. data/lib/makit/yaml.rb +29 -29
  175. data/lib/makit/zip.rb +17 -17
  176. data/lib/makit copy.rb +44 -44
  177. data/lib/makit.rb +120 -119
  178. metadata +3 -2
@@ -1,323 +1,323 @@
1
-
2
-
3
- module Makit
4
- module Secrets
5
- # Azure Key Vault operations
6
- class AzureKeyVault
7
- # Required environment variables
8
- REQUIRED_VARS = [
9
- "AZURE_STORAGE_ACCOUNT",
10
- "AZURE_STORAGE_ACCOUNT_KEY",
11
- ].freeze
12
-
13
- # Optional environment variables
14
- OPTIONAL_VARS = [
15
- "AZURE_CDN_RESOURCE_GROUP",
16
- "AZURE_CDN_PROFILE_NAME",
17
- "AZURE_CDN_ENDPOINT_NAME",
18
- "GITLAB_NUGET_TOKEN",
19
- "GITLAB_USERNAME",
20
- ].freeze
21
-
22
- # All environment variablesazure_key_vault.r
23
- ALL_VARS = (REQUIRED_VARS + OPTIONAL_VARS).freeze
24
-
25
- # Check if kvenv is available
26
- def self.kvenv_available?
27
- system("which kvenv > /dev/null 2>&1")
28
- end
29
-
30
- # Check if Azure CLI is authenticated
31
- def self.azure_cli_authenticated?
32
- return false unless system("which az > /dev/null 2>&1")
33
- system("az account show > /dev/null 2>&1")
34
- end
35
-
36
- # Get Azure Key Vault name from environment or use default
37
- def self.keyvault_name
38
- ENV["AZURE_KEYVAULT_NAME"] || "louparslow-secrets"
39
- end
40
-
41
- # Get secret name from environment or auto-generate from GIT_REMOTE_URL
42
- def self.secret_name
43
- return ENV["AZURE_SECRET_NAME"] if ENV["AZURE_SECRET_NAME"] && !ENV["AZURE_SECRET_NAME"].empty?
44
-
45
- # Auto-generate from GIT_REMOTE_URL
46
- git_remote_url = get_git_remote_url
47
- if git_remote_url && !git_remote_url.empty?
48
- generate_secret_name_from_url(git_remote_url)
49
- else
50
- "portal-secrets" # Fallback default
51
- end
52
- end
53
-
54
- # Get GIT_REMOTE_URL from various sources
55
- def self.get_git_remote_url
56
- # Try constant first
57
- return GIT_REMOTE_URL if defined?(GIT_REMOTE_URL) && !GIT_REMOTE_URL.nil? && !GIT_REMOTE_URL.empty?
58
-
59
- # Try Git module
60
- if defined?(Makit::Git) && Makit::Git.git_repo?
61
- url = Makit::Git.get_remote_url
62
- return url if url && !url.empty?
63
- end
64
-
65
- # Try project configuration
66
- if defined?(Makit::Configuration::Project)
67
- project = Makit::Configuration::Project.default
68
- url = project.git_remote_url
69
- return url if url && !url.nil? && !url.empty?
70
- end
71
-
72
- nil
73
- end
74
-
75
- # Generate a valid Azure Key Vault secret name from a Git remote URL
76
- # Azure Key Vault secret names must be 1-127 characters, alphanumeric and hyphens only,
77
- # cannot start or end with hyphen, and cannot have consecutive hyphens
78
- def self.generate_secret_name_from_url(url)
79
- # Remove protocol (http://, https://, git@)
80
- name = url.gsub(/^https?:\/\//, "").gsub(/^git@/, "")
81
-
82
- # Remove .git suffix if present
83
- name = name.gsub(/\.git$/, "")
84
-
85
- # Replace invalid characters with hyphens
86
- name = name.gsub(/[^a-zA-Z0-9\-]/, "-")
87
-
88
- # Remove consecutive hyphens
89
- name = name.gsub(/-+/, "-")
90
-
91
- # Remove leading/trailing hyphens
92
- name = name.gsub(/^-+|-+$/, "")
93
-
94
- # Ensure it starts with a letter or number (Azure requirement)
95
- name = "secret-#{name}" if name.empty? || name.match(/^[^a-zA-Z0-9]/)
96
-
97
- # Truncate to 127 characters (Azure Key Vault limit)
98
- name = name[0, 127]
99
-
100
- # Remove trailing hyphen if truncation created one
101
- name = name.gsub(/-+$/, "")
102
-
103
- # Ensure it's not empty
104
- name = "git-secrets" if name.empty?
105
-
106
- name
107
- end
108
-
109
- # Get secret prefix from environment
110
- def self.secret_prefix
111
- ENV["AZURE_SECRET_PREFIX"]
112
- end
113
-
114
- # Setup method: Attempt to initialize environment variables
115
- def self.setup
116
- puts "Setting up secrets...".colorize(:blue)
117
-
118
- # Check if required variables are already set
119
- missing_required = REQUIRED_VARS.select { |var| ENV[var].nil? || ENV[var].empty? }
120
-
121
- if missing_required.empty?
122
- puts " All required environment variables are already set".colorize(:green)
123
- return true
124
- end
125
-
126
- puts " Missing required variables: #{missing_required.join(", ")}".colorize(:yellow)
127
- puts " Attempting to load from Azure Key Vault...".colorize(:yellow)
128
-
129
- # Try to load from Azure Key Vault
130
- if load(keyvault_name: nil, secret_name: nil)
131
- # Verify again after loading
132
- still_missing = REQUIRED_VARS.select { |var| ENV[var].nil? || ENV[var].empty? }
133
- if still_missing.empty?
134
- puts " Successfully loaded all required secrets".colorize(:green)
135
- return true
136
- else
137
- puts " Warning: Still missing required variables: #{still_missing.join(", ")}".colorize(:yellow)
138
- return false
139
- end
140
- else
141
- puts " Could not load secrets from Azure Key Vault".colorize(:yellow)
142
- puts " Please set environment variables manually or configure Azure Key Vault access".colorize(:yellow)
143
- return false
144
- end
145
- end
146
-
147
- # Verify that expected environment variables are set
148
- def self.verify(warn_only: true)
149
- issues = []
150
- warnings = []
151
-
152
- # Check required variables
153
- REQUIRED_VARS.each do |var|
154
- if ENV[var].nil? || ENV[var].empty?
155
- issues << "Required variable '#{var}' is not set"
156
- end
157
- end
158
-
159
- # Check optional variables (only warn)
160
- OPTIONAL_VARS.each do |var|
161
- if ENV[var].nil? || ENV[var].empty?
162
- warnings << "Optional variable '#{var}' is not set"
163
- end
164
- end
165
-
166
- # Report issues
167
- if issues.any?
168
- if warn_only
169
- issues.each { |issue| puts " ⚠️ #{issue}".colorize(:yellow) }
170
- else
171
- issues.each { |issue| puts " ❌ #{issue}".colorize(:red) }
172
- end
173
- end
174
-
175
- if warnings.any?
176
- warnings.each { |warning| puts " ℹ️ #{warning}".colorize(:cyan) }
177
- end
178
-
179
- if issues.empty? && warnings.empty?
180
- puts " ✅ All environment variables are set".colorize(:green)
181
- return true
182
- elsif issues.empty?
183
- puts " ✅ All required environment variables are set".colorize(:green)
184
- return true
185
- else
186
- return false
187
- end
188
- end
189
-
190
- # Get status of all environment variables
191
- def self.status
192
- puts "Environment Variables Status:".colorize(:blue)
193
- puts ""
194
-
195
- puts "Required Variables:".colorize(:cyan)
196
- REQUIRED_VARS.each do |var|
197
- status = ENV[var].nil? || ENV[var].empty? ? "❌ Not set" : "✅ Set"
198
- color = ENV[var].nil? || ENV[var].empty? ? :red : :green
199
- puts " #{var}: #{status}".colorize(color)
200
- end
201
-
202
- puts ""
203
- puts "Optional Variables:".colorize(:cyan)
204
- OPTIONAL_VARS.each do |var|
205
- status = ENV[var].nil? || ENV[var].empty? ? "⚪ Not set" : "✅ Set"
206
- color = ENV[var].nil? || ENV[var].empty? ? :yellow : :green
207
- puts " #{var}: #{status}".colorize(color)
208
- end
209
- end
210
-
211
- # Load secrets from Azure Key Vault using kvenv
212
- # @param keyvault_name [String, nil] The Azure Key Vault name (defaults to ENV["AZURE_KEYVAULT_NAME"] or "louparslow-secrets")
213
- # @param secret_name [String, nil] The secret name in Key Vault (defaults to ENV["AZURE_SECRET_NAME"] or "portal-secrets")
214
- # @return [Boolean] true if secrets were loaded successfully, false otherwise
215
- def self.load(keyvault_name: nil, secret_name: nil)
216
- # Use provided parameters or fall back to defaults
217
- kv_name = keyvault_name || self.keyvault_name
218
- sec_name = secret_name || self.secret_name
219
-
220
- unless kvenv_available?
221
- puts " Warning: kvenv not installed, secrets will not be loaded".colorize(:yellow)
222
- return false
223
- end
224
-
225
- # Check if Azure CLI is authenticated (kvenv can use this)
226
- unless azure_cli_authenticated?
227
- puts " Warning: Azure CLI not authenticated, run 'az login' first".colorize(:yellow)
228
- return false
229
- end
230
-
231
- cache_file = "/tmp/kvenv-#{sec_name}.json"
232
-
233
- # Build kvenv command
234
- cmd_parts = [
235
- "kvenv cache",
236
- "--azure",
237
- "--azure-keyvault-name #{kv_name}",
238
- ]
239
-
240
- if secret_prefix
241
- cmd_parts << "--secret-prefix #{secret_prefix}"
242
- else
243
- cmd_parts << "--secret-name #{sec_name}"
244
- end
245
-
246
- cmd_parts << "--output #{cache_file}"
247
-
248
- # Run kvenv to cache secrets
249
- puts " Loading secrets from Key Vault: #{kv_name}, Secret: #{sec_name}".colorize(:cyan)
250
- success = system(cmd_parts.join(" "))
251
- return false unless success
252
- return false unless File.exist?(cache_file)
253
-
254
- # Load secrets from cache file
255
- begin
256
- require "json"
257
- secrets = JSON.parse(File.read(cache_file))
258
-
259
- # Set environment variables (don't override existing ones)
260
- loaded_count = 0
261
- secrets.each do |key, value|
262
- unless ENV[key]
263
- ENV[key] = value
264
- loaded_count += 1
265
- end
266
- end
267
-
268
- puts " Loaded #{loaded_count} secrets from Azure Key Vault (#{secrets.keys.count} total in secret)".colorize(:green)
269
- true
270
- rescue => e
271
- puts " Warning: Could not parse secrets from cache: #{e.message}".colorize(:yellow)
272
- false
273
- end
274
- end
275
-
276
- # Set a secret in Azure Key Vault
277
- # @param secret_name [String] The name of the secret to set
278
- # @param secret_value [String] The value of the secret
279
- # @param keyvault_name [String, nil] The Azure Key Vault name (defaults to ENV["AZURE_KEYVAULT_NAME"] or "louparslow-secrets")
280
- # @return [Boolean] true if secret was set successfully, false otherwise
281
- def self.set(secret_name, secret_value, keyvault_name: nil)
282
- # Use provided parameter or fall back to default
283
- kv_name = keyvault_name || self.keyvault_name
284
-
285
- if secret_name.nil? || secret_name.empty?
286
- raise "Secret name is required"
287
- end
288
-
289
- if secret_value.nil? || secret_value.empty?
290
- raise "Secret value is required"
291
- end
292
-
293
- unless azure_cli_authenticated?
294
- raise "Azure CLI is not authenticated. Run 'az login' first"
295
- end
296
-
297
- puts " Setting secret '#{secret_name}' in Key Vault: #{kv_name}".colorize(:cyan)
298
-
299
- # Build Azure CLI command
300
- cmd = [
301
- "az keyvault secret set",
302
- "--vault-name '#{kv_name}'",
303
- "--name '#{secret_name}'",
304
- "--value '#{secret_value}'",
305
- "2>&1",
306
- ].join(" ")
307
-
308
- output = `#{cmd}`
309
- exit_code = $?.exitstatus
310
-
311
- if exit_code != 0
312
- puts " Error: Failed to set secret".colorize(:red)
313
- puts " #{output}".colorize(:red)
314
- return false
315
- end
316
-
317
- puts " Successfully set secret '#{secret_name}' in Key Vault".colorize(:green)
318
- true
319
- end
320
- end
321
- end
322
- end
1
+
2
+
3
+ module Makit
4
+ module Secrets
5
+ # Azure Key Vault operations
6
+ class AzureKeyVault
7
+ # Required environment variables
8
+ REQUIRED_VARS = [
9
+ "AZURE_STORAGE_ACCOUNT",
10
+ "AZURE_STORAGE_ACCOUNT_KEY",
11
+ ].freeze
12
+
13
+ # Optional environment variables
14
+ OPTIONAL_VARS = [
15
+ "AZURE_CDN_RESOURCE_GROUP",
16
+ "AZURE_CDN_PROFILE_NAME",
17
+ "AZURE_CDN_ENDPOINT_NAME",
18
+ "GITLAB_NUGET_TOKEN",
19
+ "GITLAB_USERNAME",
20
+ ].freeze
21
+
22
+ # All environment variablesazure_key_vault.r
23
+ ALL_VARS = (REQUIRED_VARS + OPTIONAL_VARS).freeze
24
+
25
+ # Check if kvenv is available
26
+ def self.kvenv_available?
27
+ system("which kvenv > /dev/null 2>&1")
28
+ end
29
+
30
+ # Check if Azure CLI is authenticated
31
+ def self.azure_cli_authenticated?
32
+ return false unless system("which az > /dev/null 2>&1")
33
+ system("az account show > /dev/null 2>&1")
34
+ end
35
+
36
+ # Get Azure Key Vault name from environment or use default
37
+ def self.keyvault_name
38
+ ENV["AZURE_KEYVAULT_NAME"] || "louparslow-secrets"
39
+ end
40
+
41
+ # Get secret name from environment or auto-generate from GIT_REMOTE_URL
42
+ def self.secret_name
43
+ return ENV["AZURE_SECRET_NAME"] if ENV["AZURE_SECRET_NAME"] && !ENV["AZURE_SECRET_NAME"].empty?
44
+
45
+ # Auto-generate from GIT_REMOTE_URL
46
+ git_remote_url = get_git_remote_url
47
+ if git_remote_url && !git_remote_url.empty?
48
+ generate_secret_name_from_url(git_remote_url)
49
+ else
50
+ "portal-secrets" # Fallback default
51
+ end
52
+ end
53
+
54
+ # Get GIT_REMOTE_URL from various sources
55
+ def self.get_git_remote_url
56
+ # Try constant first
57
+ return GIT_REMOTE_URL if defined?(GIT_REMOTE_URL) && !GIT_REMOTE_URL.nil? && !GIT_REMOTE_URL.empty?
58
+
59
+ # Try Git module
60
+ if defined?(Makit::Git) && Makit::Git.git_repo?
61
+ url = Makit::Git.get_remote_url
62
+ return url if url && !url.empty?
63
+ end
64
+
65
+ # Try project configuration
66
+ if defined?(Makit::Configuration::Project)
67
+ project = Makit::Configuration::Project.default
68
+ url = project.git_remote_url
69
+ return url if url && !url.nil? && !url.empty?
70
+ end
71
+
72
+ nil
73
+ end
74
+
75
+ # Generate a valid Azure Key Vault secret name from a Git remote URL
76
+ # Azure Key Vault secret names must be 1-127 characters, alphanumeric and hyphens only,
77
+ # cannot start or end with hyphen, and cannot have consecutive hyphens
78
+ def self.generate_secret_name_from_url(url)
79
+ # Remove protocol (http://, https://, git@)
80
+ name = url.gsub(/^https?:\/\//, "").gsub(/^git@/, "")
81
+
82
+ # Remove .git suffix if present
83
+ name = name.gsub(/\.git$/, "")
84
+
85
+ # Replace invalid characters with hyphens
86
+ name = name.gsub(/[^a-zA-Z0-9\-]/, "-")
87
+
88
+ # Remove consecutive hyphens
89
+ name = name.gsub(/-+/, "-")
90
+
91
+ # Remove leading/trailing hyphens
92
+ name = name.gsub(/^-+|-+$/, "")
93
+
94
+ # Ensure it starts with a letter or number (Azure requirement)
95
+ name = "secret-#{name}" if name.empty? || name.match(/^[^a-zA-Z0-9]/)
96
+
97
+ # Truncate to 127 characters (Azure Key Vault limit)
98
+ name = name[0, 127]
99
+
100
+ # Remove trailing hyphen if truncation created one
101
+ name = name.gsub(/-+$/, "")
102
+
103
+ # Ensure it's not empty
104
+ name = "git-secrets" if name.empty?
105
+
106
+ name
107
+ end
108
+
109
+ # Get secret prefix from environment
110
+ def self.secret_prefix
111
+ ENV["AZURE_SECRET_PREFIX"]
112
+ end
113
+
114
+ # Setup method: Attempt to initialize environment variables
115
+ def self.setup
116
+ puts "Setting up secrets...".colorize(:blue)
117
+
118
+ # Check if required variables are already set
119
+ missing_required = REQUIRED_VARS.select { |var| ENV[var].nil? || ENV[var].empty? }
120
+
121
+ if missing_required.empty?
122
+ puts " All required environment variables are already set".colorize(:green)
123
+ return true
124
+ end
125
+
126
+ puts " Missing required variables: #{missing_required.join(", ")}".colorize(:yellow)
127
+ puts " Attempting to load from Azure Key Vault...".colorize(:yellow)
128
+
129
+ # Try to load from Azure Key Vault
130
+ if load(keyvault_name: nil, secret_name: nil)
131
+ # Verify again after loading
132
+ still_missing = REQUIRED_VARS.select { |var| ENV[var].nil? || ENV[var].empty? }
133
+ if still_missing.empty?
134
+ puts " Successfully loaded all required secrets".colorize(:green)
135
+ return true
136
+ else
137
+ puts " Warning: Still missing required variables: #{still_missing.join(", ")}".colorize(:yellow)
138
+ return false
139
+ end
140
+ else
141
+ puts " Could not load secrets from Azure Key Vault".colorize(:yellow)
142
+ puts " Please set environment variables manually or configure Azure Key Vault access".colorize(:yellow)
143
+ return false
144
+ end
145
+ end
146
+
147
+ # Verify that expected environment variables are set
148
+ def self.verify(warn_only: true)
149
+ issues = []
150
+ warnings = []
151
+
152
+ # Check required variables
153
+ REQUIRED_VARS.each do |var|
154
+ if ENV[var].nil? || ENV[var].empty?
155
+ issues << "Required variable '#{var}' is not set"
156
+ end
157
+ end
158
+
159
+ # Check optional variables (only warn)
160
+ OPTIONAL_VARS.each do |var|
161
+ if ENV[var].nil? || ENV[var].empty?
162
+ warnings << "Optional variable '#{var}' is not set"
163
+ end
164
+ end
165
+
166
+ # Report issues
167
+ if issues.any?
168
+ if warn_only
169
+ issues.each { |issue| puts " ⚠️ #{issue}".colorize(:yellow) }
170
+ else
171
+ issues.each { |issue| puts " ❌ #{issue}".colorize(:red) }
172
+ end
173
+ end
174
+
175
+ if warnings.any?
176
+ warnings.each { |warning| puts " ℹ️ #{warning}".colorize(:cyan) }
177
+ end
178
+
179
+ if issues.empty? && warnings.empty?
180
+ puts " ✅ All environment variables are set".colorize(:green)
181
+ return true
182
+ elsif issues.empty?
183
+ puts " ✅ All required environment variables are set".colorize(:green)
184
+ return true
185
+ else
186
+ return false
187
+ end
188
+ end
189
+
190
+ # Get status of all environment variables
191
+ def self.status
192
+ puts "Environment Variables Status:".colorize(:blue)
193
+ puts ""
194
+
195
+ puts "Required Variables:".colorize(:cyan)
196
+ REQUIRED_VARS.each do |var|
197
+ status = ENV[var].nil? || ENV[var].empty? ? "❌ Not set" : "✅ Set"
198
+ color = ENV[var].nil? || ENV[var].empty? ? :red : :green
199
+ puts " #{var}: #{status}".colorize(color)
200
+ end
201
+
202
+ puts ""
203
+ puts "Optional Variables:".colorize(:cyan)
204
+ OPTIONAL_VARS.each do |var|
205
+ status = ENV[var].nil? || ENV[var].empty? ? "⚪ Not set" : "✅ Set"
206
+ color = ENV[var].nil? || ENV[var].empty? ? :yellow : :green
207
+ puts " #{var}: #{status}".colorize(color)
208
+ end
209
+ end
210
+
211
+ # Load secrets from Azure Key Vault using kvenv
212
+ # @param keyvault_name [String, nil] The Azure Key Vault name (defaults to ENV["AZURE_KEYVAULT_NAME"] or "louparslow-secrets")
213
+ # @param secret_name [String, nil] The secret name in Key Vault (defaults to ENV["AZURE_SECRET_NAME"] or "portal-secrets")
214
+ # @return [Boolean] true if secrets were loaded successfully, false otherwise
215
+ def self.load(keyvault_name: nil, secret_name: nil)
216
+ # Use provided parameters or fall back to defaults
217
+ kv_name = keyvault_name || self.keyvault_name
218
+ sec_name = secret_name || self.secret_name
219
+
220
+ unless kvenv_available?
221
+ puts " Warning: kvenv not installed, secrets will not be loaded".colorize(:yellow)
222
+ return false
223
+ end
224
+
225
+ # Check if Azure CLI is authenticated (kvenv can use this)
226
+ unless azure_cli_authenticated?
227
+ puts " Warning: Azure CLI not authenticated, run 'az login' first".colorize(:yellow)
228
+ return false
229
+ end
230
+
231
+ cache_file = "/tmp/kvenv-#{sec_name}.json"
232
+
233
+ # Build kvenv command
234
+ cmd_parts = [
235
+ "kvenv cache",
236
+ "--azure",
237
+ "--azure-keyvault-name #{kv_name}",
238
+ ]
239
+
240
+ if secret_prefix
241
+ cmd_parts << "--secret-prefix #{secret_prefix}"
242
+ else
243
+ cmd_parts << "--secret-name #{sec_name}"
244
+ end
245
+
246
+ cmd_parts << "--output #{cache_file}"
247
+
248
+ # Run kvenv to cache secrets
249
+ puts " Loading secrets from Key Vault: #{kv_name}, Secret: #{sec_name}".colorize(:cyan)
250
+ success = system(cmd_parts.join(" "))
251
+ return false unless success
252
+ return false unless File.exist?(cache_file)
253
+
254
+ # Load secrets from cache file
255
+ begin
256
+ require "json"
257
+ secrets = JSON.parse(File.read(cache_file))
258
+
259
+ # Set environment variables (don't override existing ones)
260
+ loaded_count = 0
261
+ secrets.each do |key, value|
262
+ unless ENV[key]
263
+ ENV[key] = value
264
+ loaded_count += 1
265
+ end
266
+ end
267
+
268
+ puts " Loaded #{loaded_count} secrets from Azure Key Vault (#{secrets.keys.count} total in secret)".colorize(:green)
269
+ true
270
+ rescue => e
271
+ puts " Warning: Could not parse secrets from cache: #{e.message}".colorize(:yellow)
272
+ false
273
+ end
274
+ end
275
+
276
+ # Set a secret in Azure Key Vault
277
+ # @param secret_name [String] The name of the secret to set
278
+ # @param secret_value [String] The value of the secret
279
+ # @param keyvault_name [String, nil] The Azure Key Vault name (defaults to ENV["AZURE_KEYVAULT_NAME"] or "louparslow-secrets")
280
+ # @return [Boolean] true if secret was set successfully, false otherwise
281
+ def self.set(secret_name, secret_value, keyvault_name: nil)
282
+ # Use provided parameter or fall back to default
283
+ kv_name = keyvault_name || self.keyvault_name
284
+
285
+ if secret_name.nil? || secret_name.empty?
286
+ raise "Secret name is required"
287
+ end
288
+
289
+ if secret_value.nil? || secret_value.empty?
290
+ raise "Secret value is required"
291
+ end
292
+
293
+ unless azure_cli_authenticated?
294
+ raise "Azure CLI is not authenticated. Run 'az login' first"
295
+ end
296
+
297
+ puts " Setting secret '#{secret_name}' in Key Vault: #{kv_name}".colorize(:cyan)
298
+
299
+ # Build Azure CLI command
300
+ cmd = [
301
+ "az keyvault secret set",
302
+ "--vault-name '#{kv_name}'",
303
+ "--name '#{secret_name}'",
304
+ "--value '#{secret_value}'",
305
+ "2>&1",
306
+ ].join(" ")
307
+
308
+ output = `#{cmd}`
309
+ exit_code = $?.exitstatus
310
+
311
+ if exit_code != 0
312
+ puts " Error: Failed to set secret".colorize(:red)
313
+ puts " #{output}".colorize(:red)
314
+ return false
315
+ end
316
+
317
+ puts " Successfully set secret '#{secret_name}' in Key Vault".colorize(:green)
318
+ true
319
+ end
320
+ end
321
+ end
322
+ end
323
323