makit 0.0.157 → 0.0.158
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.
- checksums.yaml +4 -4
- data/README.md +41 -41
- data/exe/makit +5 -5
- data/lib/makit/apache.rb +28 -28
- data/lib/makit/auto.rb +48 -48
- data/lib/makit/azure/blob_storage.rb +257 -257
- data/lib/makit/azure/cli.rb +284 -284
- data/lib/makit/cli/base.rb +17 -17
- data/lib/makit/cli/build_commands.rb +500 -500
- data/lib/makit/cli/generators/base_generator.rb +74 -74
- data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
- data/lib/makit/cli/generators/generator_factory.rb +49 -49
- data/lib/makit/cli/generators/node_generator.rb +50 -50
- data/lib/makit/cli/generators/ruby_generator.rb +77 -77
- data/lib/makit/cli/generators/rust_generator.rb +50 -50
- data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
- data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
- data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
- data/lib/makit/cli/generators/templates/ruby/gemspec.rb +41 -41
- data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
- data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
- data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
- data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
- data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
- data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
- data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
- data/lib/makit/cli/main.rb +78 -78
- data/lib/makit/cli/pipeline_commands.rb +311 -311
- data/lib/makit/cli/project_commands.rb +868 -868
- data/lib/makit/cli/repository_commands.rb +661 -661
- data/lib/makit/cli/strategy_commands.rb +207 -207
- data/lib/makit/cli/utility_commands.rb +521 -521
- data/lib/makit/commands/factory.rb +359 -359
- data/lib/makit/commands/middleware/base.rb +73 -73
- data/lib/makit/commands/middleware/cache.rb +248 -248
- data/lib/makit/commands/middleware/command_logger.rb +312 -312
- data/lib/makit/commands/middleware/validator.rb +269 -269
- data/lib/makit/commands/request.rb +316 -316
- data/lib/makit/commands/result.rb +323 -323
- data/lib/makit/commands/runner.rb +386 -386
- data/lib/makit/commands/strategies/base.rb +171 -171
- data/lib/makit/commands/strategies/child_process.rb +162 -162
- data/lib/makit/commands/strategies/factory.rb +136 -136
- data/lib/makit/commands/strategies/synchronous.rb +139 -139
- data/lib/makit/commands.rb +50 -50
- data/lib/makit/configuration/dotnet_project.rb +48 -48
- data/lib/makit/configuration/gitlab_helper.rb +61 -61
- data/lib/makit/configuration/project.rb +292 -292
- data/lib/makit/configuration/rakefile_helper.rb +43 -43
- data/lib/makit/configuration/step.rb +34 -34
- data/lib/makit/configuration/timeout.rb +74 -74
- data/lib/makit/configuration.rb +21 -21
- data/lib/makit/content/default_gitignore.rb +7 -7
- data/lib/makit/content/default_gitignore.txt +225 -225
- data/lib/makit/content/default_rakefile.rb +13 -13
- data/lib/makit/content/gem_rakefile.rb +16 -16
- data/lib/makit/context.rb +1 -1
- data/lib/makit/data.rb +49 -49
- data/lib/makit/directories.rb +170 -170
- data/lib/makit/directory.rb +262 -262
- data/lib/makit/docs/files.rb +89 -89
- data/lib/makit/docs/rake.rb +102 -102
- data/lib/makit/dotnet/cli.rb +69 -69
- data/lib/makit/dotnet/project.rb +217 -217
- data/lib/makit/dotnet/solution.rb +38 -38
- data/lib/makit/dotnet/solution_classlib.rb +239 -239
- data/lib/makit/dotnet/solution_console.rb +264 -264
- data/lib/makit/dotnet/solution_maui.rb +354 -354
- data/lib/makit/dotnet/solution_wasm.rb +275 -275
- data/lib/makit/dotnet/solution_wpf.rb +304 -304
- data/lib/makit/dotnet.rb +102 -102
- data/lib/makit/email.rb +90 -90
- data/lib/makit/environment.rb +142 -142
- data/lib/makit/examples/runner.rb +370 -370
- data/lib/makit/exceptions.rb +45 -45
- data/lib/makit/fileinfo.rb +32 -32
- data/lib/makit/files.rb +43 -43
- data/lib/makit/gems.rb +40 -40
- data/lib/makit/git/cli.rb +78 -54
- data/lib/makit/git/repository.rb +100 -100
- data/lib/makit/git.rb +104 -104
- data/lib/makit/gitlab/pipeline.rb +857 -857
- data/lib/makit/gitlab/pipeline_service_impl.rb +1535 -1535
- data/lib/makit/gitlab_runner.rb +59 -59
- data/lib/makit/humanize.rb +218 -218
- data/lib/makit/indexer.rb +47 -47
- data/lib/makit/io/filesystem.rb +111 -111
- data/lib/makit/io/filesystem_service_impl.rb +337 -337
- data/lib/makit/lint.rb +212 -212
- data/lib/makit/logging/configuration.rb +309 -309
- data/lib/makit/logging/format_registry.rb +84 -84
- data/lib/makit/logging/formatters/base.rb +39 -39
- data/lib/makit/logging/formatters/console_formatter.rb +140 -140
- data/lib/makit/logging/formatters/json_formatter.rb +65 -65
- data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
- data/lib/makit/logging/formatters/text_formatter.rb +64 -64
- data/lib/makit/logging/log_request.rb +119 -119
- data/lib/makit/logging/logger.rb +199 -199
- data/lib/makit/logging/sinks/base.rb +91 -91
- data/lib/makit/logging/sinks/console.rb +72 -72
- data/lib/makit/logging/sinks/file_sink.rb +92 -92
- data/lib/makit/logging/sinks/structured.rb +123 -123
- data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
- data/lib/makit/logging.rb +578 -578
- data/lib/makit/markdown.rb +75 -75
- data/lib/makit/mp/basic_object_mp.rb +17 -17
- data/lib/makit/mp/command_mp.rb +13 -13
- data/lib/makit/mp/command_request.mp.rb +17 -17
- data/lib/makit/mp/project_mp.rb +199 -199
- data/lib/makit/mp/string_mp.rb +205 -205
- data/lib/makit/nuget.rb +74 -74
- data/lib/makit/podman/podman.rb +458 -458
- data/lib/makit/podman/podman_service_impl.rb +1081 -1081
- data/lib/makit/port.rb +32 -32
- data/lib/makit/process.rb +377 -377
- data/lib/makit/protoc.rb +112 -112
- data/lib/makit/rake/cli.rb +196 -196
- data/lib/makit/rake/trace_controller.rb +174 -174
- data/lib/makit/rake.rb +81 -81
- data/lib/makit/ruby/cli.rb +185 -185
- data/lib/makit/ruby.rb +25 -25
- data/lib/makit/rubygems.rb +137 -0
- data/lib/makit/secrets/azure_key_vault.rb +322 -322
- data/lib/makit/secrets/azure_secrets.rb +183 -183
- data/lib/makit/secrets/local_secrets.rb +72 -72
- data/lib/makit/secrets/secrets_manager.rb +105 -105
- data/lib/makit/secrets.rb +16 -16
- data/lib/makit/serializer.rb +130 -130
- data/lib/makit/services/builder.rb +186 -186
- data/lib/makit/services/error_handler.rb +226 -226
- data/lib/makit/services/repository_manager.rb +367 -367
- data/lib/makit/services/validator.rb +112 -112
- data/lib/makit/setup/classlib.rb +101 -101
- data/lib/makit/setup/gem.rb +268 -268
- data/lib/makit/setup/pages.rb +11 -11
- data/lib/makit/setup/razorclasslib.rb +101 -101
- data/lib/makit/setup/runner.rb +54 -54
- data/lib/makit/setup.rb +5 -5
- data/lib/makit/show.rb +110 -110
- data/lib/makit/storage.rb +126 -126
- data/lib/makit/symbols.rb +175 -175
- data/lib/makit/task_info.rb +130 -130
- data/lib/makit/tasks/at_exit.rb +15 -15
- data/lib/makit/tasks/build.rb +22 -22
- data/lib/makit/tasks/bump.rb +7 -7
- data/lib/makit/tasks/clean.rb +13 -13
- data/lib/makit/tasks/configure.rb +10 -10
- data/lib/makit/tasks/format.rb +10 -10
- data/lib/makit/tasks/hook_manager.rb +443 -443
- data/lib/makit/tasks/info.rb +368 -368
- data/lib/makit/tasks/init.rb +49 -49
- data/lib/makit/tasks/integrate.rb +60 -56
- data/lib/makit/tasks/pull_incoming.rb +13 -13
- data/lib/makit/tasks/secrets.rb +7 -7
- data/lib/makit/tasks/setup.rb +16 -16
- data/lib/makit/tasks/sync.rb +14 -17
- data/lib/makit/tasks/tag.rb +27 -27
- data/lib/makit/tasks/task_monkey_patch.rb +81 -81
- data/lib/makit/tasks/test.rb +22 -22
- data/lib/makit/tasks/update.rb +18 -18
- data/lib/makit/tasks/version.rb +6 -6
- data/lib/makit/tasks.rb +24 -24
- data/lib/makit/test_cache.rb +239 -239
- data/lib/makit/tree.rb +37 -37
- data/lib/makit/v1/configuration/project_service_impl.rb +370 -370
- data/lib/makit/v1/git/git_repository_service_impl.rb +295 -295
- data/lib/makit/v1/makit.v1_pb.rb +35 -35
- data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
- data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -572
- data/lib/makit/version.rb +661 -503
- data/lib/makit/version_util.rb +21 -21
- data/lib/makit/wix.rb +95 -95
- data/lib/makit/yaml.rb +29 -29
- data/lib/makit/zip.rb +17 -17
- data/lib/makit copy.rb +44 -44
- data/lib/makit.rb +115 -114
- 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
|
|