Skip to content

Commit

Permalink
#48 Add ability to generate secrets only for select environments
Browse files Browse the repository at this point in the history
  • Loading branch information
rogerluan authored Nov 16, 2023
2 parents d521a9a + 9de2612 commit ee3e79f
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 1 deletion.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ Usage: `--flavor loremipsum`
Passing a flavor option will change the env var lookup mechanism. Flavors are useful, for instance, when generating secrets for white-label projects.
### `--include-environments`
Usage: `--include-environments dev,staging,prod`
Passing an `--include-environments` option will change the env var lookup mechanism. This option is useful when you want to generate secrets for specific environments only, and skip the verification that checks whether all keys from all environments are present. You might want to use this option to only build debug environments locally (and thus only require debug env vars), and only build staging and production environments in CI (and thus only expose prod env vars to your CI).
Defaults to `nil`, which means all your environments will be used. When passing multiple values, separate them with commas and no spaces.
#### Example
Let's load a flavor called `snowflakes` and load a secret called `MySecretAPIKey`:
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ task default: %i[spec rubocop]

desc "Generates Swift source code and run its unit tests."
task :test_swift do
sh("ARKANA_RUNNING_CI_INTEGRATION_TESTS=true bin/arkana --config-filepath spec/fixtures/swift-tests.yml --dotenv-filepath spec/fixtures/.env.fruitloops")
sh("ARKANA_RUNNING_CI_INTEGRATION_TESTS=true bin/arkana --config-filepath spec/fixtures/swift-tests.yml --dotenv-filepath spec/fixtures/.env.fruitloops --include-environments dev,staging")
Dir.chdir("tests/MySecrets") do
sh("swift test")
end
Expand Down
1 change: 1 addition & 0 deletions lib/arkana/config_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module ConfigParser
def self.parse(arguments)
yaml = YAML.load_file(arguments.config_filepath)
config = Config.new(yaml)
config.include_environments(arguments.include_environments)
config.current_flavor = arguments.flavor
config.dotenv_filepath = arguments.dotenv_filepath
UI.warn("Dotenv file was specified but couldn't be found at '#{config.dotenv_filepath}'") if config.dotenv_filepath && !File.exist?(config.dotenv_filepath)
Expand Down
6 changes: 6 additions & 0 deletions lib/arkana/models/arguments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ class Arguments
attr_reader :dotenv_filepath
# @returns [string]
attr_reader :flavor
# @returns [Array<string>]
attr_reader :include_environments

def initialize
# Default values
@config_filepath = ".arkana.yml"
@dotenv_filepath = ".env" if File.exist?(".env")
@flavor = nil
@include_environments = nil

OptionParser.new do |opt|
opt.on("-c", "--config-filepath /path/to/your/.arkana.yml", "Path to your config file. Defaults to '.arkana.yml'") do |o|
Expand All @@ -27,6 +30,9 @@ def initialize
opt.on("-f", "--flavor FrostedFlakes", "Flavors are useful, for instance, when generating secrets for white-label projects. See the README for more information") do |o|
@flavor = o
end
opt.on("-i", "--include-environments debug,release", "Optionally pass the environments that you want Arkana to generate secrets for. Useful if you only want to build a certain environment, e.g. just Debug in local machines, while only building Staging and Release in CI. Separate the keys using a comma, without spaces. When ommitted, Arkana generate secrets for all environments.") do |o|
@include_environments = o.split(",")
end
end.parse!
end
end
6 changes: 6 additions & 0 deletions lib/arkana/models/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,10 @@ def environment_keys
def all_keys
global_secrets + environment_keys
end

def include_environments(environments)
return unless environments

@environments = @environments.select { |e| environments.map(&:downcase).include?(e.downcase) }
end
end
21 changes: 21 additions & 0 deletions spec/arkana_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,26 @@
described_class.run(arguments)
end
end

context "when only a subset of environments is included" do
before do
ARGV.replace([
"--config-filepath",
config_filepath,
"--include-environments",
"debug,release,debugPlusMore",
])

config.all_keys.each do |key|
allow(ENV).to receive(:[]).with(key).and_return("lorem ipsum")
end
allow(ENV).to receive(:[]).with("ServiceKeyReleasePlusMore").and_return(nil)
allow(ENV).to receive(:[]).with("ServerReleasePlusMore").and_return(nil)
end

it "does not error out when it cant find a missing env var that wasnt included in the list of environments" do
expect { described_class.run(arguments) }.not_to raise_error
end
end
end
end
19 changes: 19 additions & 0 deletions spec/config_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,24 @@
end
end
end

describe "#include_environments" do
describe "when include_environments is specified" do
let(:include_environments) { %w[debug debugPlusMore] }

before { ARGV << "--include-environments" << include_environments.join(",") }

it "includes the environments specified, case insensitive" do
expect(subject.environments.map(&:downcase)).to match_array(include_environments.map(&:downcase))
end
end

describe "when include_environments is not specified" do
it "includes all environments" do
all_environments = %w[debug release debugPlusMore ReleasePlusMore]
expect(subject.environments.map(&:downcase)).to match_array(all_environments.map(&:downcase))
end
end
end
end
end
4 changes: 4 additions & 0 deletions spec/fixtures/.env.fruitloops
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ SecretWithDollarSignNotEscapedAndSingleQuoteKey = 'real_$lim_shady'
SecretWithDollarSignNotEscapedAndDoubleQuotesKey = "real_$lim_shady"
SecretWithDollarSignNotEscapedAndNoQuotesKey = real_$lim_shady
SecretWithWeirdCharactersKey = "` ~ ! @ # % ^ & * ( ) _ - + = { [ } } | : ; ' < , > . ? /"
ServiceKeyDev = "this dev key is secret"
ServerDev = "dev.example.com"
ServiceKeyStaging = "this staging key is secret"
ServerStaging = "staging.example.com"
7 changes: 7 additions & 0 deletions spec/fixtures/swift-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ global_secrets:
- SecretWithDollarSignNotEscapedAndDoubleQuotesKey
- SecretWithDollarSignNotEscapedAndNoQuotesKey
- SecretWithWeirdCharactersKey
environments:
- dev
- staging
- prod
environment_secrets:
- ServiceKey
- Server
18 changes: 18 additions & 0 deletions spec/models/arguments_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,22 @@
end
end
end

describe "#environments" do
context "when the option is ommitted in ARGV" do
it "defaults to nil" do
expect(subject.include_environments).to be_nil
end
end

context "when the option is passed in ARGV" do
let(:expected_environments) { %w[first_env second_env] }

before { ARGV.replace(["--include-environments", expected_environments.join(",")]) }

it "returns the environments passed as an array, not as a comma-separated string" do
expect(subject.include_environments).to eq expected_environments
end
end
end
end
45 changes: 45 additions & 0 deletions spec/models/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@
expect(subject.dotenv_filepath).to be_nil
end
end

context "when all_keys is empty" do
subject { described_class.new({}) }

it "raises an error" do
expect { SwiftCodeGenerator.generate(template_arguments: template_arguments, config: config) }.to raise_error(StandardError)
end
end
end

describe `#environment_keys` do
Expand Down Expand Up @@ -85,6 +93,43 @@
end
end

describe ".include_environments" do
context "when nil is passed" do
it "includes all environments declared in the yaml file" do
subject.include_environments(nil)
expect(subject.environments).to match_array %w[Debug Release DebugPlusMore ReleasePlusMore]
end
end

context "when 1 environment is passed" do
it "onlies that environment in the environments" do
subject.include_environments(["DebugPlusMore"])
expect(subject.environments).to match_array %w[DebugPlusMore]
end
end

context "when all environments are passed" do
it "onlies that environment in the environments" do
subject.include_environments(%w[Debug Release DebugPlusMore ReleasePlusMore])
expect(subject.environments).to match_array %w[Debug Release DebugPlusMore ReleasePlusMore]
end
end

context "when an empty array is passed" do
it "causes the subject's environments to become empty" do
subject.include_environments([])
expect(subject.environments).to be_empty
end
end

context "when a string that is not an environment is passed" do
it "ignores that string and consider the other elements of the array passed, if any" do
subject.include_environments(["I double dare you"])
expect(subject.environments).to be_empty
end
end
end

describe `#all_keys` do
it "is not empty" do
expect(subject.all_keys).not_to be_empty
Expand Down

0 comments on commit ee3e79f

Please sign in to comment.