Class: Wisco::SettingsStore
- Inherits:
-
Object
- Object
- Wisco::SettingsStore
- 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
-
#connector_path ⇒ Object
readonly
Returns the value of attribute connector_path.
Class Method Summary collapse
-
.detect_structure(data) ⇒ Object
:none, :flat (all top-level values scalar), :nested (all Hash), or :mixed.
-
.set_names(data) ⇒ Object
Names of the named (nested) connection sets — the top-level keys whose value is a Hash.
Instance Method Summary collapse
- #encrypted? ⇒ Boolean
- #encrypted_path ⇒ Object
- #exist? ⇒ Boolean
-
#filename ⇒ Object
Basename for user-facing messages; falls back to the plaintext name when no file exists yet (that is the form
addwould create). -
#form ⇒ Object
:encrypted (settings.yaml.enc present), :plaintext (settings.yaml present), or :none.
-
#initialize(connector_path) ⇒ SettingsStore
constructor
A new instance of SettingsStore.
- #master_key_available? ⇒ Boolean
- #master_key_path ⇒ Object
- #plaintext_path ⇒ Object
-
#read_all ⇒ Object
Reads the entire settings file (all sets) as a plain string-keyed Hash.
- #require_master_key! ⇒ Object
-
#write_all(data, encrypted:) ⇒ Object
Replaces the whole settings file with
data.
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.(connector_path) end |
Instance Attribute Details
#connector_path ⇒ Object (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
49 50 51 |
# File 'lib/wisco/settings_store.rb', line 49 def encrypted? form == :encrypted end |
#encrypted_path ⇒ Object
29 30 31 |
# File 'lib/wisco/settings_store.rb', line 29 def encrypted_path File.join(@connector_path, ENCRYPTED_FILENAME) end |
#exist? ⇒ Boolean
53 54 55 |
# File 'lib/wisco/settings_store.rb', line 53 def exist? form != :none end |
#filename ⇒ Object
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 |
#form ⇒ Object
: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
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_path ⇒ Object
33 34 35 |
# File 'lib/wisco/settings_store.rb', line 33 def master_key_path File.join(@connector_path, MASTER_KEY_FILENAME) end |
#plaintext_path ⇒ Object
25 26 27 |
# File 'lib/wisco/settings_store.rb', line 25 def plaintext_path File.join(@connector_path, PLAINTEXT_FILENAME) end |
#read_all ⇒ Object
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
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 |