Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/style.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: Style Checks

on: pull_request

permissions:
contents: read
pull-requests: write

jobs:
rubocop:
name: runner / rubocop
Expand All @@ -13,7 +17,7 @@ jobs:
- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2.2
ruby-version: 3.4.1

- name: rubocop
uses: reviewdog/action-rubocop@b6d5e953a5fc0bf3ab65254e77730ea2174d6d6d #v2.22.0
Expand Down
50 changes: 50 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Tests

on: pull_request

permissions:
contents: read
pull-requests: write

jobs:
rspec:
name: rspec tests
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v6

- name: Install Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.4.1
bundler-cache: true

- name: Run rspec tests
run: |
bundle exec rspec

- name: Upload coverage results
uses: actions/upload-artifact@v4
with:
include-hidden-files: 'true'
name: coverage-results
path: coverage
retention-days: 5

coverage:
needs: rspec
runs-on: ubuntu-latest
steps:
- name: Download coverage results
uses: actions/download-artifact@v4
with:
name: coverage-results
path: coverage

- name: Simplecov Report
uses: aki77/simplecov-report-action@7fd5fa551dd583dd437a11c640b2a1cf23d6cdaa
with:
token: ${{ secrets.GITHUB_TOKEN }}
failedThreshold: 70
resultPath: coverage/.last_run.json
3 changes: 3 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--require spec_helper
--format documentation
--color
3 changes: 2 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
AllCops:
DisplayCopNames: true
TargetRubyVersion: 3.2
TargetRubyVersion: 3.4
StyleGuideBaseURL: https://github.com/rewindio/ruby-style-configs/
NewCops: enable
Exclude:
- .git/**/*
- bin/**/*
- lambda_layer/**/*
- tmp/**/*
- vendor/**/*

Expand Down
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.2
3.4.1
5 changes: 4 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ gem 'logger-colors', '~>1.0'
gem 'octokit', '~> 8.0'
gem 'retriable', '~> 3.1'

group :development do
group :development, :test do
gem 'aws-sdk-ssm', '~> 1.0'
gem 'rspec', '~> 3.13'
gem 'rubocop'
gem 'simplecov', require: false
end
113 changes: 82 additions & 31 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,62 +1,113 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
base64 (0.2.0)
addressable (2.8.8)
public_suffix (>= 2.0.2, < 8.0)
ast (2.4.3)
aws-eventstream (1.4.0)
aws-partitions (1.1210.0)
aws-sdk-core (3.241.4)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
bigdecimal
jmespath (~> 1, >= 1.6.1)
logger
aws-sdk-ssm (1.210.0)
aws-sdk-core (~> 3, >= 3.241.4)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.12.1)
aws-eventstream (~> 1, >= 1.0.2)
base64 (0.3.0)
bigdecimal (4.0.1)
diff-lcs (1.6.2)
docile (1.4.1)
dotenv (2.8.1)
faraday (2.7.11)
faraday (2.14.0)
faraday-net_http (>= 2.0, < 3.5)
json
logger
faraday-net_http (3.4.2)
net-http (~> 0.5)
jmespath (1.6.2)
json (2.18.0)
language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
logger (1.7.0)
logger-colors (1.1.0)
logger
net-http (0.9.1)
uri (>= 0.11.1)
octokit (8.1.0)
base64
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.2)
json (2.6.3)
language_server-protocol (3.17.0.3)
logger-colors (1.0.0)
octokit (8.0.0)
faraday (>= 1, < 3)
sawyer (~> 0.9)
parallel (1.23.0)
parser (3.2.2.4)
parallel (1.27.0)
parser (3.3.10.1)
ast (~> 2.4.1)
racc
public_suffix (5.0.4)
racc (1.7.3)
prism (1.9.0)
public_suffix (7.0.2)
racc (1.8.1)
rainbow (3.1.1)
regexp_parser (2.8.2)
regexp_parser (2.11.3)
retriable (3.1.2)
rexml (3.4.2)
rubocop (1.57.2)
rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.6)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.7)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.6)
rubocop (1.84.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.2.2.4)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.28.1, < 2.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.49.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.30.0)
parser (>= 3.2.1.0)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.49.0)
parser (>= 3.3.7.2)
prism (~> 1.7)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
sawyer (0.9.2)
sawyer (0.9.3)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
unicode-display_width (2.5.0)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-html (0.13.2)
simplecov_json_formatter (0.1.4)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.2.0)
uri (1.1.1)

PLATFORMS
ruby
x86_64-linux

DEPENDENCIES
aws-sdk-ssm (~> 1.0)
dotenv (~> 2.8)
logger-colors (~> 1.0)
octokit (~> 8.0)
retriable (~> 3.1)
rspec (~> 3.13)
rubocop
simplecov

BUNDLED WITH
2.4.22
2.4.10
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ To read more about how GitHub's search syntax works, see [understanding the sear

### Execution

This requires [ruby](https://www.ruby-lang.org/en/documentation/installation/) to be installed on your machine. It was tested on `Ruby 3.2.2`. Other versions may work.
This requires [ruby](https://www.ruby-lang.org/en/documentation/installation/) to be installed on your machine. It was tested on `Ruby 3.4.1`. Other versions may work.

```shell
bundler install
Expand Down
6 changes: 3 additions & 3 deletions lambda_layer/Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# SAM does not package ruby layers correctly
# AWS Lambda has a GEM_PATH of:
# /var/task/vendor/bundle/ruby/3.2.0:/opt/ruby/gems/3.2.0
# but the layer is zipped up as: /opt/ruby/3.2.0/gems
# /var/task/vendor/bundle/ruby/3.4.0:/opt/ruby/gems/3.4.0
# but the layer is zipped up as: /opt/ruby/3.4.0/gems
#
# See: https://github.com/aws/aws-lambda-builders/issues/177
# and: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/building-custom-runtimes.html

RUBY_VERSION = 3.2.0
RUBY_VERSION = 3.4.0

mkfile_path := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))

Expand Down
120 changes: 120 additions & 0 deletions spec/lambda_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# frozen_string_literal: true

require 'json'
require 'aws-sdk-ssm'

# Stub the SSM client before loading lambda.rb to prevent AWS connection attempts
SSM_CLIENT_DOUBLE = Aws::SSM::Client.new(stub_responses: true)

# Temporarily replace SSM::Client.new to return our stubbed client
original_new = Aws::SSM::Client.method(:new)
Aws::SSM::Client.define_singleton_method(:new) { |**_| SSM_CLIENT_DOUBLE }

# Load the lambda file
lambda_file = File.expand_path('../src/lambda.rb', __dir__)
load lambda_file

# Restore original behavior
Aws::SSM::Client.define_singleton_method(:new, original_new)

RSpec.describe 'Lambda functions' do
let(:ssm_client) { instance_double(Aws::SSM::Client) }

before do
stub_const('SSM_CLIENT', ssm_client)
end

describe '#get_ssm_parameter' do
it 'retrieves a parameter with decryption enabled' do
parameter_response = instance_double(
Aws::SSM::Types::GetParameterResult,
parameter: instance_double(Aws::SSM::Types::Parameter, value: 'secret-value')
)

expect(ssm_client).to receive(:get_parameter).with(
name: '/test/parameter',
with_decryption: true
).and_return(parameter_response)

result = get_ssm_parameter('/test/parameter')
expect(result).to eq(parameter_response)
end
end

describe '#update_ssm_parameter' do
it 'updates a parameter with overwrite enabled' do
expect(ssm_client).to receive(:put_parameter).with(
name: '/test/parameter',
overwrite: true,
value: 'new-value'
)

update_ssm_parameter('/test/parameter', 'new-value')
end
end

describe '#github_token_from_ssm' do
before do
allow(ENV).to receive(:fetch).with('GITHUB_TOKEN_SSM_PATH', nil).and_return('/github/token/path')
end

it 'returns the GitHub token from SSM' do
parameter_response = instance_double(
Aws::SSM::Types::GetParameterResult,
parameter: instance_double(Aws::SSM::Types::Parameter, value: 'ghp_test_token')
)

expect(ssm_client).to receive(:get_parameter).with(
name: '/github/token/path',
with_decryption: true
).and_return(parameter_response)

expect(github_token_from_ssm).to eq('ghp_test_token')
end
end

describe '#last_time_checked_from_ssm' do
before do
allow(ENV).to receive(:fetch).with('LAST_TIME_CHECKED_SSM_PATH', nil).and_return('/last/checked/path')
end

context 'when parameter has a valid timestamp' do
it 'returns the stored timestamp' do
stored_time = '2025-01-15T10:30:00.000+00:00'
parameter_response = instance_double(
Aws::SSM::Types::GetParameterResult,
parameter: instance_double(Aws::SSM::Types::Parameter, value: stored_time)
)

expect(ssm_client).to receive(:get_parameter).with(
name: '/last/checked/path',
with_decryption: true
).and_return(parameter_response)

expect(last_time_checked_from_ssm).to eq(stored_time)
end
end

context 'when parameter value is "null"' do
it 'returns a timestamp from 1 day ago' do
parameter_response = instance_double(
Aws::SSM::Types::GetParameterResult,
parameter: instance_double(Aws::SSM::Types::Parameter, value: 'null')
)

expect(ssm_client).to receive(:get_parameter).with(
name: '/last/checked/path',
with_decryption: true
).and_return(parameter_response)

frozen_time = DateTime.new(2025, 1, 28, 12, 0, 0)
allow(DateTime).to receive(:now).and_return(frozen_time)

result = last_time_checked_from_ssm
expected_time = (frozen_time - 1).iso8601(3)

expect(result).to eq(expected_time)
end
end
end
end
Loading
Loading