Module: Legion::CLI::ConfigImport

Defined in:
lib/legion/cli/config_import.rb

Constant Summary collapse

SETTINGS_DIR =
File.expand_path('~/.legionio/settings')
BOOTSTRAPPED_FILE =
'bootstrapped_settings.json'
SUBSYSTEM_KEYS =
%i[
  microsoft_teams rbac api logging gaia extensions
  llm data cache_local cache transport crypt role
].freeze

Class Method Summary collapse

Class Method Details

.deep_merge(base, overlay) ⇒ Object



95
96
97
98
99
100
101
102
103
# File 'lib/legion/cli/config_import.rb', line 95

def deep_merge(base, overlay)
  base.merge(overlay) do |_key, old_val, new_val|
    if old_val.is_a?(Hash) && new_val.is_a?(Hash)
      deep_merge(old_val, new_val)
    else
      new_val
    end
  end
end

.fetch_http(url) ⇒ Object

Raises:



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/legion/cli/config_import.rb', line 32

def fetch_http(url)
  uri = URI.parse(url)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = uri.scheme == 'https'
  http.open_timeout = 10
  http.read_timeout = 10
  request = Net::HTTP::Get.new(uri)
  response = http.request(request)
  raise CLI::Error, "HTTP #{response.code}: #{response.message}" unless response.is_a?(Net::HTTPSuccess)

  response.body
end

.fetch_source(source) ⇒ Object



22
23
24
25
26
27
28
29
30
# File 'lib/legion/cli/config_import.rb', line 22

def fetch_source(source)
  if source.match?(%r{\Ahttps?://})
    fetch_http(source)
  else
    raise CLI::Error, "File not found: #{source}" unless File.exist?(source)

    File.read(source)
  end
end

.parse_payload(body) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/legion/cli/config_import.rb', line 45

def parse_payload(body)
  parsed = ::JSON.parse(body, symbolize_names: true)
  raise CLI::Error, 'Config must be a JSON object' unless parsed.is_a?(Hash)

  parsed
rescue ::JSON::ParserError
  begin
    decoded = Base64.decode64(body)
    parsed = ::JSON.parse(decoded, symbolize_names: true)
    raise CLI::Error, 'Config must be a JSON object' unless parsed.is_a?(Hash)

    parsed
  rescue ::JSON::ParserError
    raise CLI::Error, 'Source is not valid JSON or base64-encoded JSON'
  end
end

.summary(config) ⇒ Object



105
106
107
108
109
# File 'lib/legion/cli/config_import.rb', line 105

def summary(config)
  sections = config.keys.map(&:to_s)
  vault_clusters = config.dig(:crypt, :vault, :clusters)&.keys&.map(&:to_s) || []
  { sections: sections, vault_clusters: vault_clusters }
end

.write_config(config, force: false) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/legion/cli/config_import.rb', line 62

def write_config(config, force: false)
  FileUtils.mkdir_p(SETTINGS_DIR)
  written = []
  remainder = config.dup

  SUBSYSTEM_KEYS.each do |key|
    next unless remainder.key?(key)

    subsystem_data = remainder.delete(key)
    path = File.join(SETTINGS_DIR, "#{key}.json")
    to_write = { key => subsystem_data }
    if File.exist?(path) && !force
      existing = ::JSON.parse(File.read(path), symbolize_names: true)
      existing_subsystem = existing[key]
      to_write = { key => deep_merge(existing_subsystem, subsystem_data) } if existing_subsystem.is_a?(Hash) && subsystem_data.is_a?(Hash)
    end
    File.write(path, "#{::JSON.pretty_generate(to_write)}\n")
    written << path
  end

  unless remainder.empty?
    path = File.join(SETTINGS_DIR, BOOTSTRAPPED_FILE)
    if File.exist?(path) && !force
      existing = ::JSON.parse(File.read(path), symbolize_names: true)
      remainder = deep_merge(existing, remainder)
    end
    File.write(path, "#{::JSON.pretty_generate(remainder)}\n")
    written << path
  end

  written
end