Skip to content

Commit

Permalink
Add template validation
Browse files Browse the repository at this point in the history
  • Loading branch information
aharpervc committed Oct 3, 2023
1 parent 844e766 commit 76fbb9d
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 2 deletions.
3 changes: 2 additions & 1 deletion bin/consult
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env ruby

require_relative '../lib/consult/cli'
require 'bundler/setup'
require 'consult/cli'

cli = Consult::CLI.instance
cli.parse
Expand Down
1 change: 1 addition & 0 deletions consult.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Gem::Specification.new do |spec|

spec.add_dependency 'diplomat', '~> 2.6'
spec.add_dependency 'vault', '>= 0.10.0', '< 1.0.0'
spec.add_dependency 'dry-validation', '<= 1.9.0'

spec.add_development_dependency 'bundler'
spec.add_development_dependency 'guard'
Expand Down
7 changes: 7 additions & 0 deletions lib/consult.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ def render!
active_templates.each(&:render)
end

def validate_templates
active_templates do |t|
t.validate
puts "#{t.name}: #{t.validation.errors}"
end
end

# Map more conventional `token` parameter to Diplomat's `acl_token` configuration.
# Additionally, we support ~/.consul-token, similar to Vault's support for ~/.vault-token
def consul_token
Expand Down
1 change: 1 addition & 0 deletions lib/consult/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def parse(args = ARGV)
end

def render
Consult.validate_templates
Consult.render!
end

Expand Down
7 changes: 6 additions & 1 deletion lib/consult/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'fileutils'
require_relative 'template_functions'
require_relative 'template_schema'
require_relative '../support/hash_extensions'

module Consult
Expand All @@ -24,7 +25,7 @@ def render(save: true)
end

# Attempt to render
renderer = ERB.new(contents, nil, '-')
renderer = ERB.new(contents, trim_mode: '-')
result = renderer.result(binding)

puts "Consult: Rendering #{name}" + (save ? " to #{dest}" : "...") if verbose?
Expand Down Expand Up @@ -76,6 +77,10 @@ def ordered_locations
@config.keys & LOCATIONS
end

def validate
@validation = TemplateSchema.new.call(@config)
end

private

# Concatenate all the source templates together, in the order provided
Expand Down
30 changes: 30 additions & 0 deletions lib/consult/template_schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string-literal: true

require 'dry-validation'

class TemplateSchema < Dry::Validation::Contract
schema do
# Output destination is required
required(:dest).value(:string)

# At least one of path/paths/consul_key/consul_keys is required
optional(:path).value(:string)
optional(:paths).value(:array)
optional(:consul_key).value(:string)
optional(:consul_keys).value(:array)

# Other configuration
optional(:ttl).value(:integer)
optional(:vars).value(:hash)
end

rule(:path, :paths, :consul_key, :consul_keys) do
unless key?(:path) || key?(:paths) || key?(:consul_key) || key?(:consul_keys)
base.failure("A template source must be specified. Please provide one or more of: path, paths, consul_key, consul_keys")
end
end

rule(:ttl) do
key.failure "A TTL is strongly recommended to avoid rendering templates too often, especially in multi-process environments." if value.to_i == 0
end
end
3 changes: 3 additions & 0 deletions spec/support/config/consult.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ shared:
path: x/y/z.txt
dest: rendered/nope/skip_missing_template

missing_source:
dest: rendered/nowhere.txt

test:
vars:
test_env_override: some value
Expand Down

0 comments on commit 76fbb9d

Please sign in to comment.