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
54 changes: 54 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Deploy on LocalStack

on:
push:
paths-ignore:
- 'README.md'
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:

jobs:
sam:
name: Deploy the SAM application
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install lstk
run: |
npm install -g @localstack/lstk
lstk setup aws --force --non-interactive

- name: Install dependencies
run: make install

- name: Start LocalStack
env:
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
run: lstk start

- name: Deploy the SAM application
run: make deploy

- name: Run tests
run: make test

- name: Show LocalStack logs
if: failure()
run: lstk logs | tail -200
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ To setup the infrastructure on LocalStack, run:
make deploy
```

You will be prompted to enter a name for the stack. Use the default options for the prompts and fill `Y` (`Yes`) for the confirmation prompt. The stack will be created and the output will be printed to the console.
This deploys the stack `sam-app` without prompting. Set `STACK_NAME` to use another name, for example `make deploy STACK_NAME=my-stack`. The stack outputs are printed to the console.


After deploying, you can invoke the Lambda function using the following commands:
Expand All @@ -54,3 +54,9 @@ make invoke-deny
make invoke-unauthorized
make invoke-none
```

To check all four cases at once, run:

```sh
make test
```
12 changes: 9 additions & 3 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
export AWS_ACCESS_KEY_ID ?= test
export AWS_SECRET_ACCESS_KEY ?= test
export AWS_DEFAULT_REGION=us-east-1
STACK_NAME ?= sam-app
SHELL := /bin/bash

usage: ## Show this help
Expand All @@ -22,11 +23,11 @@ logs: ## Save the logs in a separate file
install:
npm install --save ulid

deploy: venv
$(VENV_RUN) && lstk sam deploy -g
deploy: venv ## Deploy the SAM application
$(VENV_RUN) && lstk sam deploy --stack-name $(STACK_NAME) --resolve-s3 --capabilities CAPABILITY_IAM --no-confirm-changeset

invoke-url: venv
@$(VENV_RUN) && lstk sam list stack-outputs --stack-name sam-app --output json | jq -r '.[0].OutputValue'
@$(VENV_RUN) && lstk sam list stack-outputs --stack-name $(STACK_NAME) --output json | jq -r '.[0].OutputValue'

invoke-allow:
url=$$(make invoke-url) && \
Expand All @@ -43,3 +44,8 @@ invoke-unauthorized:
invoke-none:
url=$$(make invoke-url) && \
curl $${url} -H "Authorization: none"

test: ## Call the API with each token and check the authorizer's decision
STACK_NAME=$(STACK_NAME) ./test.sh

.PHONY: usage start stop logs install deploy invoke-url invoke-allow invoke-deny invoke-unauthorized invoke-none test
38 changes: 38 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash
# Call the API with each token the Lambda authorizer understands and check
# API Gateway answers the way src/authorizer.js documents it.
set -euo pipefail

STACK_NAME=${STACK_NAME:-sam-app}

URL=$(lstk aws cloudformation describe-stacks --stack-name "$STACK_NAME" \
--query "Stacks[0].Outputs[?OutputKey=='APIGWEndpoint'].OutputValue" --output text)
echo "API: $URL"

failed=0
# expect <description> <status> <body substring> [curl args...]
expect() {
local description=$1 status=$2 substring=$3 response actual
shift 3
response=$(curl -sk -m 30 -w '\n%{http_code}' "$URL" "$@")
actual=${response##*$'\n'}
response=${response%$'\n'*}
if [ "$actual" = "$status" ] && [[ "$response" == *"$substring"* ]]; then
echo "PASS: $description returned $actual"
else
echo "FAIL: $description returned $actual '$response', expected $status with '$substring'"
failed=1
fi
}

expect "token 'allow'" 200 "hello world" -H "Authorization: allow"
expect "token 'deny'" 403 "explicit deny" -H "Authorization: deny"
expect "token 'unauthorized'" 401 "Unauthorized" -H "Authorization: unauthorized"
expect "any other token" 500 "" -H "Authorization: none"
expect "no token" 401 "Unauthorized"

if [ "$failed" != 0 ]; then
echo "Test failed"
exit 1
fi
echo "Test passed: the authorizer allowed and denied requests as expected"
Loading