Class: Wisco::SettingsStore

Inherits:
Object
  • Object
show all
Defined in:
lib/wisco/settings_store.rb

Overview

Read/write wrapper over the Workato SDK settings file (settings.yaml / settings.yaml.enc) living in a connector directory. Handles encrypted vs plaintext auto-detection, master-key resolution, and flat-vs-nested connection-set detection. See doc-specs/wisco-10-settings.md.

Defined Under Namespace

Classes: MissingKeyError

Constant Summary collapse

PLAINTEXT_FILENAME =
'settings.yaml'.freeze
ENCRYPTED_FILENAME =
'settings.yaml.enc'.freeze
MASTER_KEY_FILENAME =
'master.key'.freeze
MASTER_KEY_ENV =
'WORKATO_CONNECTOR_MASTER_KEY'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connector_path) ⇒ SettingsStore

Returns a new instance of SettingsStore.



21
22
23
# File 'lib/wisco/settings_store.rb', line 21

def initialize(connector_path)
  @connector_path = File.expand_path(connector_path)
end

Instance Attribute Details

#connector_pathObject (readonly)

Returns the value of attribute connector_path.



19
20
21
# File 'lib/wisco/settings_store.rb', line 19

def connector_path
  @connector_path
end

Class Method Details

.detect_structure(data) ⇒ Object

:none, :flat (all top-level values scalar), :nested (all Hash), or :mixed.



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/wisco/settings_store.rb', line 112

def self.detect_structure(data)
  return :none if data.nil? || data.empty?

  values = data.values
  if values.all? { |v| v.is_a?(Hash) }
    :nested
  elsif values.none? { |v| v.is_a?(Hash) }
    :flat
  else
    :mixed
  end
end

.set_names(data) ⇒ Object

Names of the named (nested) connection sets — the top-level keys whose value is a Hash. Empty for flat/none files.



127
128
129
130
131
# File 'lib/wisco/settings_store.rb', line 127

def self.set_names(data)
  return [] if data.nil?

  data.select { |_k, v| v.is_a?(Hash) }.keys
end

Instance Method Details

#encrypted?Boolean

Returns:

  • (Boolean)


49
50
51
# File 'lib/wisco/settings_store.rb', line 49

def encrypted?
  form == :encrypted
end

#encrypted_pathObject



29
30
31
# File 'lib/wisco/settings_store.rb', line 29

def encrypted_path
  File.join(@connector_path, ENCRYPTED_FILENAME)
end

#exist?Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/wisco/settings_store.rb', line 53

def exist?
  form != :none
end

#filenameObject

Basename for user-facing messages; falls back to the plaintext name when no file exists yet (that is the form add would create).



59
60
61
# File 'lib/wisco/settings_store.rb', line 59

def filename
  encrypted? ? ENCRYPTED_FILENAME : PLAINTEXT_FILENAME
end

#formObject

:encrypted (settings.yaml.enc present), :plaintext (settings.yaml present), or :none. Encrypted takes precedence when both exist.



39
40
41
42
43
44
45
46
47
# File 'lib/wisco/settings_store.rb', line 39

def form
  if File.exist?(encrypted_path)
    :encrypted
  elsif File.exist?(plaintext_path)
    :plaintext
  else
    :none
  end
end

#master_key_available?Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/wisco/settings_store.rb', line 63

def master_key_available?
  !ENV[MASTER_KEY_ENV].to_s.strip.empty? || File.exist?(master_key_path)
end

#master_key_pathObject



33
34
35
# File 'lib/wisco/settings_store.rb', line 33

def master_key_path
  File.join(@connector_path, MASTER_KEY_FILENAME)
end

#plaintext_pathObject



25
26
27
# File 'lib/wisco/settings_store.rb', line 25

def plaintext_path
  File.join(@connector_path, PLAINTEXT_FILENAME)
end

#read_allObject

Reads the entire settings file (all sets) as a plain string-keyed Hash. Returns {} when no file exists. Raises MissingKeyError if the file is encrypted and no master key is available.



70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/wisco/settings_store.rb', line 70

def read_all
  case form
  when :none
    {}
  when :plaintext
    parsed = YAML.safe_load(File.read(plaintext_path), permitted_classes: [::Symbol])
    parsed.is_a?(Hash) ? parsed : {}
  when :encrypted
    require_master_key!
    raw = Workato::Connector::Sdk::Settings.from_encrypted_file(encrypted_path, master_key_path)
    raw.respond_to?(:to_hash) ? raw.to_hash : {}
  end
end

#require_master_key!Object

Raises:



103
104
105
106
107
108
109
# File 'lib/wisco/settings_store.rb', line 103

def require_master_key!
  return if master_key_available?

  raise MissingKeyError,
        "#{ENCRYPTED_FILENAME} is encrypted but no master key was found.\n" \
        "       Set #{MASTER_KEY_ENV} or provide a #{MASTER_KEY_FILENAME} file in #{@connector_path}."
end

#write_all(data, encrypted:) ⇒ Object

Replaces the whole settings file with data. When encrypted: is true the content is encrypted with the resolved master key; otherwise a plaintext settings.yaml is written. Rewriting wholesale (rather than the SDK's merge-only #update) is what lets add migrate a flat file to nested form.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/wisco/settings_store.rb', line 88

def write_all(data, encrypted:)
  if encrypted
    require_master_key!
    config = ActiveSupport::EncryptedConfiguration.new(
      config_path:          encrypted_path,
      key_path:             master_key_path,
      env_key:              MASTER_KEY_ENV,
      raise_if_missing_key: true
    )
    config.write(YAML.dump(data))
  else
    File.write(plaintext_path, YAML.dump(data))
  end
end