belt 0.2.8 → 0.2.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ad9e95cd921b5bf91ffd28544086a895e49ce04a59e4a6b62d64cb9b1ec7bd1
4
- data.tar.gz: 7e8795bcfc4e7941f5bd6b426a509ada6dd8d931c39b2af777e0725e8a78e021
3
+ metadata.gz: 37cf283dc30b43f875f8600eb4b00e46b5782f374d3be306d0c5adaec7e9024a
4
+ data.tar.gz: 1153f552cef87426f91afcf28647065017b77a09bdd9347241366ed9cc455b76
5
5
  SHA512:
6
- metadata.gz: d228ac8ae6a440aa17c56b5ab16e48ebda349666b5b22d08456d5c99df4a66f47461031d48d049f81cd8c9d6253d9aa410e8ffa25a45998296ec5c3af524a651
7
- data.tar.gz: 943b4993668f4c3be7ede7ff7dda63f7e4682906af122632fba1fe3ef66b257ee3970d93383dfe7fbd8df1d88a4852f1cbdaca37f2beac8db26ad0c995d75230
6
+ metadata.gz: 4cafc0f29e0148e74950e9fe0898e74632f2563980f60ffece7bfbb58ec7187ec30f928a0958dff9d9832fe79b21e8a87e512f26c4cddfa58c1f243776cea5eb
7
+ data.tar.gz: 7850fc8e4c5921646c25f77f67fdfcae663e148ec597b514b095b637733b0e55f34182e8c64ea52f2294ed687b3a24f7b6a56462b30df07811a01ffae23da952
@@ -14,7 +14,7 @@ module Belt
14
14
  @infra_dir = infra_dir
15
15
  @app_name = app_name
16
16
  @timestamp = Time.now.strftime('%Y%m%d-%H%M%S')
17
- @backup_bucket = "#{@app_name}-backups-#{@env}"
17
+ @backup_bucket = sanitize_bucket_name("#{@app_name}-backups-#{@env}")
18
18
  @errors = []
19
19
  @summary = []
20
20
  end
@@ -41,6 +41,8 @@ module Belt
41
41
 
42
42
  puts " 📦 Creating backup bucket: #{@backup_bucket}"
43
43
 
44
+ errors_before = @errors.size
45
+
44
46
  run_aws('s3', 'mb', "s3://#{@backup_bucket}", '--region', detect_region)
45
47
 
46
48
  # Enable versioning
@@ -54,7 +56,11 @@ module Belt
54
56
  '--public-access-block-configuration',
55
57
  'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true')
56
58
 
57
- puts ' ✅ Backup bucket created and secured'
59
+ if @errors.size > errors_before
60
+ puts ' ⚠️ Backup bucket creation failed (see warnings below)'
61
+ else
62
+ puts ' ✅ Backup bucket created and secured'
63
+ end
58
64
  end
59
65
 
60
66
  # ─── DynamoDB ────────────────────────────────────────────────────
@@ -153,11 +159,11 @@ module Belt
153
159
 
154
160
  def export_cognito_users(pool_id)
155
161
  all_users = []
156
- pagination_token = nil
162
+ next_token = nil
157
163
 
158
164
  loop do
159
- args = ['aws', 'cognito-idp', 'list-users', '--user-pool-id', pool_id, '--max-results', '60']
160
- args += ['--pagination-token', pagination_token] if pagination_token
165
+ args = ['aws', 'cognito-idp', 'list-users', '--user-pool-id', pool_id, '--max-items', '60']
166
+ args += ['--starting-token', next_token] if next_token
161
167
 
162
168
  output, status = Open3.capture2(*args)
163
169
  break unless status.success?
@@ -165,8 +171,8 @@ module Belt
165
171
  data = JSON.parse(output)
166
172
  all_users.concat(data['Users'] || [])
167
173
 
168
- pagination_token = data['PaginationToken']
169
- break if pagination_token.nil? || pagination_token.empty?
174
+ next_token = data['NextToken']
175
+ break if next_token.nil? || next_token.empty?
170
176
 
171
177
  puts ' Fetching next page of users...'
172
178
  end
@@ -327,69 +333,41 @@ module Belt
327
333
  end
328
334
  end
329
335
 
330
- # ─── Terraform Output Resolution ─────────────────────────────────
336
+ # ─── Table Discovery ──────────────────────────────────────────────
331
337
 
332
338
  def resolve_table_names
333
- @resolve_table_names ||= fetch_table_names_from_terraform
339
+ @resolve_table_names ||= discover_tables_from_aws
334
340
  end
335
341
 
336
- def fetch_table_names_from_terraform
337
- env_dir = File.join(@infra_dir, @env)
338
- return [] unless Dir.exist?(env_dir)
339
-
340
- Dir.chdir(env_dir) do
341
- names = try_terraform_table_output
342
- return names if names
342
+ def discover_tables_from_aws
343
+ # List all DynamoDB tables matching the app-env prefix directly from AWS.
344
+ # This is the source of truth — no Terraform output maintenance required.
345
+ prefix = "#{@app_name}-#{@env}-"
346
+ sanitized_prefix = sanitize_bucket_name(prefix)
343
347
 
344
- fetch_table_names_from_all_outputs
345
- end
346
- end
347
-
348
- def try_terraform_table_output
349
- output, status = Open3.capture2('terraform', 'output', '-json', 'dynamodb_table_names')
350
- return nil unless status.success?
351
-
352
- names = begin
353
- JSON.parse(output)
354
- rescue StandardError
355
- nil
348
+ output, status = Open3.capture2('aws', 'dynamodb', 'list-tables', '--output', 'json')
349
+ unless status.success?
350
+ @errors << 'Failed to list DynamoDB tables from AWS'
351
+ return []
356
352
  end
357
- names.is_a?(Array) && names.any? ? Array(names) : nil
358
- end
359
-
360
- def fetch_table_names_from_all_outputs
361
- output, status = Open3.capture2('terraform', 'output', '-json')
362
- return [] unless status.success?
363
353
 
364
- all_outputs = begin
365
- JSON.parse(output)
354
+ all_tables = begin
355
+ JSON.parse(output)['TableNames'] || []
366
356
  rescue StandardError
367
- {}
368
- end
369
-
370
- # Look for dynamodb_table_names in output
371
- if all_outputs['dynamodb_table_names']
372
- val = all_outputs['dynamodb_table_names']['value']
373
- return Array(val) if val
357
+ []
374
358
  end
375
359
 
376
- # Try to find any output that looks like table names
377
- all_outputs.each do |key, data|
378
- next unless key.include?('table')
379
-
380
- val = data['value']
381
- return Array(val) if val.is_a?(Array) && val.any?
382
- end
383
-
384
- []
360
+ all_tables.select { |t| t.start_with?(prefix) || t.start_with?(sanitized_prefix) }
385
361
  end
386
362
 
363
+ # ─── Terraform Output Resolution ─────────────────────────────────
364
+
387
365
  def resolve_cognito_pool_id
388
366
  env_dir = File.join(@infra_dir, @env)
389
367
  return nil unless Dir.exist?(env_dir)
390
368
 
391
369
  Dir.chdir(env_dir) do
392
- output, status = Open3.capture2('terraform', 'output', '-json', 'user_pool_id')
370
+ output, status = Open3.capture2('terraform', 'output', '-json', 'user_pool_id', err: File::NULL)
393
371
  if status.success?
394
372
  val = begin
395
373
  JSON.parse(output)
@@ -400,7 +378,7 @@ module Belt
400
378
  end
401
379
 
402
380
  # Fallback: search all outputs
403
- output, status = Open3.capture2('terraform', 'output', '-json')
381
+ output, status = Open3.capture2('terraform', 'output', '-json', err: File::NULL)
404
382
  if status.success?
405
383
  all_outputs = begin
406
384
  JSON.parse(output)
@@ -477,6 +455,11 @@ module Belt
477
455
 
478
456
  # ─── Helpers ─────────────────────────────────────────────────────
479
457
 
458
+ def sanitize_bucket_name(name)
459
+ # S3 bucket names must be DNS-compliant: lowercase, hyphens, no underscores
460
+ name.tr('_', '-').downcase.gsub(/[^a-z0-9\-.]/, '-').gsub(/-{2,}/, '-')
461
+ end
462
+
480
463
  def short_table_name(table_name)
481
464
  table_name.sub(/\A#{Regexp.escape(@app_name)}-#{Regexp.escape(@env)}-/, '')
482
465
  end
data/lib/belt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Belt
4
- VERSION = '0.2.8'
4
+ VERSION = '0.2.9'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: belt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 0.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stowzilla