Skip to content

Commit

Permalink
Merge pull request #94 from tristanmorgan/gen_test_creds
Browse files Browse the repository at this point in the history
Generate fake creds for testing.
  • Loading branch information
tristanmorgan authored Feb 3, 2025
2 parents 8879a39 + 1775164 commit 09e806a
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 20 deletions.
1 change: 1 addition & 0 deletions i18n/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ en:
notoken: 'Do not use saved token.'
noremote: 'Do not validate with remote api.'
path: 'The service PATH to open.'
test: 'Generate test credentials.'
browser: 'Specify an alternative browser.'
secret: 'AWS account secret.'
unset: 'Unset environment variables.'
Expand Down
18 changes: 18 additions & 0 deletions lib/awskeyring/awsapi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'aws-sdk-iam'
require 'cgi'
require 'json'
require 'securerandom'

# Awskeyring Module,
# gives you an interface to access keychains and items.
Expand Down Expand Up @@ -180,6 +181,23 @@ def self.get_credentials_from_file(account:)
}
end

# Generate test credentials for AWS
#
# @return [Hash] with the new credentials
# key The aws_access_key_id
# secret The aws_secret_access_key
# expiry expiry time
def self.gen_test_credentials(account:)
{
account: account,
key: "AKIA#{Array.new(16) { [*'A'..'Z', *'2'..'7'].sample }.join}",
secret: SecureRandom.base64(30),
token: nil,
expiry: nil,
role: nil
}
end

# Retrieves an AWS Console login url
#
# @param [String] key The aws_access_key_id
Expand Down
46 changes: 31 additions & 15 deletions lib/awskeyring_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,15 @@ def list_role
desc 'env ACCOUNT', I18n.t('env_desc')
method_option :force, type: :boolean, aliases: '-f', desc: I18n.t('method_option.force'), default: false
method_option 'no-token', type: :boolean, aliases: '-n', desc: I18n.t('method_option.notoken'), default: false
method_option :test, type: :boolean, aliases: '-t', desc: I18n.t('method_option.test'), default: false
method_option :unset, type: :boolean, aliases: '-u', desc: I18n.t('method_option.unset'), default: false
# Print Env vars
def env(account = nil)
if options[:unset]
if options[:test]
account ||= 'fakeaccount'
cred = Awskeyring::Awsapi.gen_test_credentials(account: account)
put_env_string(cred)
elsif options[:unset]
put_env_string(account: nil, key: nil, secret: nil, token: nil)
else
output_safe(options[:force])
Expand All @@ -129,21 +134,32 @@ def env(account = nil)
desc 'json ACCOUNT', I18n.t('json_desc')
method_option :force, type: :boolean, aliases: '-f', desc: I18n.t('method_option.force'), default: false
method_option 'no-token', type: :boolean, aliases: '-n', desc: I18n.t('method_option.notoken'), default: false
method_option :test, type: :boolean, aliases: '-t', desc: I18n.t('method_option.test'), default: false
# Print JSON for use with credential_process
def json(account) # rubocop:disable Metrics/AbcSize
output_safe(options[:force])
account = ask_check(
existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_exists),
limited_to: Awskeyring.list_account_names
)
cred = age_check_and_get(account: account, no_token: options['no-token'])
expiry = Time.at(cred[:expiry]) unless cred[:expiry].nil?
puts Awskeyring::Awsapi.get_cred_json(
key: cred[:key],
secret: cred[:secret],
token: cred[:token],
expiry: (expiry || (Time.new + Awskeyring::Awsapi::ONE_HOUR)).iso8601
)
def json(account) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
if options[:test]
cred = Awskeyring::Awsapi.gen_test_credentials(account: account)
puts Awskeyring::Awsapi.get_cred_json(
key: cred[:key],
secret: cred[:secret],
token: cred[:token],
expiry: (Time.new + Awskeyring::Awsapi::TWELVE_HOUR).iso8601
)
else
output_safe(options[:force])
account = ask_check(
existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_exists),
limited_to: Awskeyring.list_account_names
)
cred = age_check_and_get(account: account, no_token: options['no-token'])
expiry = Time.at(cred[:expiry]) unless cred[:expiry].nil?
puts Awskeyring::Awsapi.get_cred_json(
key: cred[:key],
secret: cred[:secret],
token: cred[:token],
expiry: (expiry || (Time.new + Awskeyring::Awsapi::ONE_HOUR)).iso8601
)
end
end

desc 'import ACCOUNT', I18n.t('import_desc')
Expand Down
10 changes: 8 additions & 2 deletions man/awskeyring.5
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "AWSKEYRING" "5" "June 2024" "" ""
.TH "AWSKEYRING" "5" "January 2025" "" ""
.
.SH "NAME"
\fBAwskeyring\fR \- is a small tool to manage AWS account keys in the macOS Keychain
Expand Down Expand Up @@ -95,7 +95,10 @@ Outputs bourne shell environment exports for an ACCOUNT
\-n, \-\-no\-token: Do not use saved token\.
.
.br
\-u, \-\-unset, \-\-no\-unset: Unset environment variables\.
\-t, \-\-test: Generate test credentials\.
.
.br
\-u, \-\-unset: Unset environment variables\.
.
.TP
exec ACCOUNT command\.\.\.:
Expand Down Expand Up @@ -153,6 +156,9 @@ Outputs AWS CLI compatible JSON for an ACCOUNT
.br
\-n, \-\-no\-token: Do not use saved token\.
.
.br
\-t, \-\-test: Generate test credentials\.
.
.TP
list:
.
Expand Down
6 changes: 4 additions & 2 deletions man/awskeyring.5.ronn
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ The commands are as follows:

-f, --force: Force output to a tty.<br>
-n, --no-token: Do not use saved token.<br>
-u, --unset, --no-unset: Unset environment variables.
-t, --test: Generate test credentials.<br>
-u, --unset: Unset environment variables.

* exec ACCOUNT command...:

Expand Down Expand Up @@ -80,7 +81,8 @@ The commands are as follows:
Outputs AWS CLI compatible JSON for an ACCOUNT<br>

-f, --force: Force output to a tty.<br>
-n, --no-token: Do not use saved token.
-n, --no-token: Do not use saved token.<br>
-t, --test: Generate test credentials.

* list:

Expand Down
6 changes: 6 additions & 0 deletions spec/lib/awskeyring/awsapi_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -536,5 +536,11 @@
it 'calls get_account_id with an invalid token' do
expect(awsapi.get_account_id(key: key)).to eq('000000000000')
end

it 'generates test credentials' do
creds = awsapi.gen_test_credentials(account: 'testaccount')
expect { Awskeyring::Validate.access_key(creds[:key]) }.not_to raise_error
expect { Awskeyring::Validate.secret_access_key(creds[:secret]) }.not_to raise_error
end
end
end
14 changes: 13 additions & 1 deletion spec/lib/awskeyring_command_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
ENV['COMP_POINT'] = ENV['COMP_LINE'].size.to_s
allow(ARGF).to receive(:argv).and_return(['awskeyring', '--', 'test'])
expect { described_class.start(%w[autocomplete test]) }
.to output(/--force\n--no-token\n--unset/).to_stdout
.to output(/--force\n--no-token\n--test\n--unset/).to_stdout
ENV['COMP_LINE'] = nil
end

Expand Down Expand Up @@ -245,6 +245,12 @@
)).to_stdout
expect(Awskeyring).not_to have_received(:get_valid_creds)
end

it 'export a fake AWS Access key' do
expect { described_class.start(%w[env test --test]) }
.to output(/export AWS_DEFAULT_REGION="us-east-1"/).to_stdout
expect(Awskeyring).not_to have_received(:get_valid_creds)
end
end

context 'when there is an account, a role and a session token' do
Expand Down Expand Up @@ -350,6 +356,12 @@
expect(Awskeyring).to have_received(:get_valid_creds).with(account: 'test', no_token: false)
end

it 'provides a test account via JSON' do
expect { described_class.start(%w[json test --test]) }
.to output(/ "Version": 1,/).to_stdout
expect(Awskeyring).not_to have_received(:get_valid_creds).with(account: 'test', no_token: false)
end

it 'runs an external command' do
ENV['BUNDLER_ORIG_TEST_ENV'] = 'BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL'
ENV['TEST_ENV'] = 'CHANGED'
Expand Down

0 comments on commit 09e806a

Please sign in to comment.