Skip to content

Commit c2fc60a

Browse files
committed
feat(lambda): convert project to swift
1 parent 4f7f03b commit c2fc60a

File tree

308 files changed

+209
-26044
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

308 files changed

+209
-26044
lines changed

.github/actions/deploy/action.yml

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ inputs:
1313
runs:
1414
using: composite
1515
steps:
16-
- name: Validate environment
17-
shell: bash
18-
run: if [ "${{ inputs.environment }}" != "staging" ] && [ "${{ inputs.environment }}" != "live" ]; then echo "Invalid environment"; exit 1; fi
19-
2016
- name: Setup Terraform
2117
uses: hashicorp/setup-terraform@v3
2218
with:
@@ -56,18 +52,21 @@ runs:
5652
working-directory: terraform
5753
run: terraform validate
5854

59-
- name: Setup version information
55+
- name: Build functions for Lambda
6056
shell: bash
61-
env:
62-
GITHUB_EVENT_NAME: ${{ github.event_name }}
63-
GITHUB_REF_NAME: ${{ github.ref_name }}
6457
run: |
65-
chmod +x scripts/version.sh
66-
./scripts/version.sh info
67-
68-
- name: Build functions
69-
shell: bash
70-
run: swift build -c release
58+
docker run --rm \
59+
--platform linux/amd64 \
60+
-v "${{ github.workspace }}:/workspace" \
61+
-w /workspace \
62+
swift:6.1-amazonlinux2 \
63+
bash -c "swift build -c release --static-swift-stdlib && \
64+
cp .build/release/lambda .build/release/bootstrap && \
65+
chmod 755 .build/release/bootstrap && \
66+
mkdir -p .build/release/authorizer-package && \
67+
cp .build/release/authorizer .build/release/authorizer-package/bootstrap && \
68+
chmod 755 .build/release/authorizer-package/bootstrap"
69+
sudo chown -R $(id -u):$(id -g) .build
7170
7271
- name: Terraform plan
7372
id: plan

.github/actions/install/action.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,12 @@ runs:
1010
- name: Setup Swift
1111
uses: swift-actions/setup-swift@v3
1212
with:
13-
swift-version: "6.2.0"
13+
swift-version: "6.1.0"
1414

1515
- name: Resolve Swift dependencies
1616
shell: bash
1717
run: swift package resolve
1818

19-
# https://github.com/actions/virtual-environments/issues/1187
20-
- name: tune linux network
21-
run: sudo ethtool -K eth0 tx off rx off
22-
shell: bash
23-
2419
- name: 🥟 Setup Bun
2520
uses: oven-sh/setup-bun@v2
2621
with:

.github/workflows/build-prerelease-version.yml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
name: Build pre-release version
22
on:
33
workflow_dispatch:
4-
pull_request:
5-
types: [opened, synchronize, edited, reopened]
4+
# pull_request:
5+
# types: [opened, synchronize, edited, reopened]
66
concurrency:
77
group: ${{ github.workflow }}-${{ github.ref }}
88
cancel-in-progress: true
@@ -27,7 +27,7 @@ permissions: write-all
2727
jobs:
2828
deploy:
2929
name: Deploy to staging
30-
runs-on: macos-latest
30+
runs-on: ubuntu-latest
3131
timeout-minutes: 10
3232
steps:
3333
- name: Checkout repository
@@ -39,17 +39,17 @@ jobs:
3939
- name: Ensure rebased with main
4040
run: ./scripts/ensure-rebased.sh
4141

42-
- name: Install
43-
uses: ./.github/actions/install
42+
# - name: Install
43+
# uses: ./.github/actions/install
4444

45-
- name: Validate
46-
uses: ./.github/actions/validate
45+
# - name: Validate
46+
# uses: ./.github/actions/validate
4747

48-
- name: Changelogs
49-
uses: ./.github/actions/changelog
50-
with:
51-
prerelease: true
52-
publish: false
48+
# - name: Changelogs
49+
# uses: ./.github/actions/changelog
50+
# with:
51+
# prerelease: true
52+
# publish: false
5353

5454
- name: fetch latest commits
5555
run: git fetch && git pull

.github/workflows/deploy-test.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: Build test version
2+
on:
3+
workflow_dispatch:
4+
pull_request:
5+
types: [opened, synchronize, edited, reopened]
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.ref }}
8+
cancel-in-progress: true
9+
env:
10+
TF_VAR_env: test
11+
TF_VAR_env_vars: ${{ secrets.LIVE_ENV_VARS }}
12+
TF_VAR_zone_id: ${{ secrets.LIVE_ZONE_ID }}
13+
TF_VAR_root_domain: lhowsam.com
14+
TF_VAR_sub_domain: nowplaying.lhowsam.com
15+
TF_VAR_private_key: ${{ secrets.STAGING_PRIVATE_KEY }}
16+
TF_VAR_certificate_body: ${{ secrets.STAGING_CERTIFICATE_BODY }}
17+
TF_VAR_certificate_chain: ${{ secrets.STAGING_CERTIFICATE_CHAIN }}
18+
TF_VAR_deployed_by: ${{ github.actor }}
19+
TF_VAR_git_sha: ${{ github.sha }}
20+
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
21+
TURBO_TEAM: luke-h1-project
22+
TF_VAR_api_key: ${{ secrets.STAGING_API_KEY }}
23+
TF_VAR_discord_webhook_url: ${{ secrets.DISCORD_ALERTS_WEBHOOK_URL}}
24+
25+
permissions: write-all
26+
27+
jobs:
28+
deploy:
29+
name: Deploy to staging
30+
runs-on: ubuntu-latest
31+
timeout-minutes: 10
32+
steps:
33+
- name: Checkout repository
34+
uses: actions/checkout@v4
35+
with:
36+
fetch-depth: 0
37+
ref: ${{ github.head_ref }}
38+
39+
- name: Ensure rebased with main
40+
run: ./scripts/ensure-rebased.sh
41+
42+
# - name: Install
43+
# uses: ./.github/actions/install
44+
45+
# - name: Validate
46+
# uses: ./.github/actions/validate
47+
48+
# - name: Changelogs
49+
# uses: ./.github/actions/changelog
50+
# with:
51+
# prerelease: true
52+
# publish: false
53+
54+
- name: fetch latest commits
55+
run: git fetch && git pull
56+
57+
- name: Deploy
58+
uses: ./.github/actions/deploy
59+
with:
60+
environment: ${{ env.TF_VAR_env }}
61+
aws-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
62+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
63+
64+
- name: Get versions
65+
id: lambda-version
66+
run: |
67+
echo "::set-output name=LAMBDA_VERSION::$(./scripts/version.sh get)"
68+
echo "::set-output name=AUTHORIZER_VERSION::$(./scripts/version.sh get)"
69+
70+
- uses: actions/github-script@v7
71+
with:
72+
script: |
73+
github.rest.issues.createComment({
74+
issue_number: context.issue.number,
75+
owner: context.repo.owner,
76+
repo: context.repo.repo,
77+
body: '* [Lambda version](https://nowplaying-${{env.TF_VAR_env}}.lhowsam.com) - `${{ steps.lambda-version.outputs.LAMBDA_VERSION }}`\n* [Authorizer version](https://nowplaying-${{env.TF_VAR_env}}.lhowsam.com) - `${{ steps.lambda-version.outputs.AUTHORIZER_VERSION }}`'
78+
})

.github/workflows/deploy.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ jobs:
4747
- name: Install
4848
uses: ./.github/actions/install
4949

50-
- name: Validate
51-
uses: ./.github/actions/validate
50+
# - name: Validate
51+
# uses: ./.github/actions/validate
5252

53-
- name: Changelogs
54-
uses: ./.github/actions/changelog
53+
# - name: Changelogs
54+
# uses: ./.github/actions/changelog
5555

5656
- name: Deploy
5757
uses: ./.github/actions/deploy

Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version: 6.2
1+
// swift-tools-version: 6.1
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
@@ -15,6 +15,7 @@ let package = Package(
1515
.package(
1616
url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", from: "2.4.0"),
1717
.package(url: "https://github.com/awslabs/swift-aws-lambda-events.git", from: "1.0.0"),
18+
.package(url: "https://github.com/apple/swift-log.git", "1.0.0"..<"1.8.0"),
1819
],
1920
targets: [
2021
.executableTarget(

Sources/authorizer/main.swift

Lines changed: 54 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,32 @@
1-
import AWSLambdaEvents
21
import AWSLambdaRuntime
32
import Foundation
43

4+
// MARK: - Custom Request/Response types for HTTP API v2 Authorizer
5+
6+
struct AuthorizerRequest: Codable {
7+
let version: String?
8+
let type: String?
9+
let routeArn: String?
10+
let routeKey: String?
11+
let rawPath: String?
12+
let rawQueryString: String?
13+
let headers: [String: String]?
14+
let requestContext: RequestContext?
15+
16+
struct RequestContext: Codable {
17+
let http: HTTPContext?
18+
19+
struct HTTPContext: Codable {
20+
let method: String?
21+
let path: String?
22+
}
23+
}
24+
}
25+
26+
struct AuthorizerSimpleResponse: Codable {
27+
let isAuthorized: Bool
28+
}
29+
530
// MARK: - Helper Functions
631

732
/// Gets a header value from the request headers (case-insensitive)
@@ -19,64 +44,35 @@ func getHeaderValue(_ headers: [String: String]?, key: String) -> String? {
1944
return nil
2045
}
2146

22-
/// Generates an IAM policy response for API Gateway
23-
func generatePolicy(
24-
principalId: String,
25-
effect: APIGatewayLambdaAuthorizerPolicyResponse.PolicyDocument.Statement.Effect,
26-
resource: String
27-
) -> APIGatewayLambdaAuthorizerPolicyResponse {
28-
return APIGatewayLambdaAuthorizerPolicyResponse(
29-
principalId: principalId,
30-
policyDocument: .init(statement: [
31-
.init(
32-
action: "execute-api:Invoke",
33-
effect: effect,
34-
resource: resource
35-
)
36-
]),
37-
context: nil
38-
)
39-
}
40-
4147
// MARK: - Lambda Runtime
4248

43-
let authorizerHandler:
44-
(APIGatewayLambdaAuthorizerRequest, LambdaContext) async throws ->
45-
APIGatewayLambdaAuthorizerPolicyResponse = {
46-
(request: APIGatewayLambdaAuthorizerRequest, context: LambdaContext) in
47-
48-
let consumer = getHeaderValue(request.headers, key: "x-consumer")
49-
let validConsumers = ["lhowsam-dev", "lhowsam-prod", "lhowsam-local"]
50-
51-
let apiKey = getHeaderValue(request.headers, key: "x-api-key")
52-
let validKey = ProcessInfo.processInfo.environment["API_KEY"]
53-
54-
let resource = request.routeArn ?? "*"
55-
56-
if apiKey != validKey {
57-
context.logger.info("Deny")
58-
return generatePolicy(
59-
principalId: "user",
60-
effect: .deny,
61-
resource: resource
62-
)
63-
}
64-
65-
if let consumer = consumer, !validConsumers.contains(consumer) {
66-
context.logger.info("Deny")
67-
return generatePolicy(
68-
principalId: "user",
69-
effect: .deny,
70-
resource: resource
71-
)
72-
}
73-
74-
return generatePolicy(
75-
principalId: "user",
76-
effect: .allow,
77-
resource: resource
78-
)
79-
}
49+
let runtime = LambdaRuntime {
50+
(event: AuthorizerRequest, context: LambdaContext) -> AuthorizerSimpleResponse in
51+
52+
context.logger.info("Authorizer invoked")
53+
context.logger.info("Headers: \(String(describing: event.headers))")
54+
context.logger.info("RouteArn: \(String(describing: event.routeArn))")
55+
56+
let consumer = getHeaderValue(event.headers, key: "x-consumer")
57+
let validConsumers = ["lhowsam-dev", "lhowsam-prod", "lhowsam-local"]
58+
59+
let apiKey = getHeaderValue(event.headers, key: "x-api-key")
60+
let validKey = ProcessInfo.processInfo.environment["API_KEY"]
61+
62+
context.logger.info("API Key from header: '\(apiKey ?? "nil")'")
63+
64+
if apiKey != validKey {
65+
context.logger.info("Deny - API key mismatch")
66+
return AuthorizerSimpleResponse(isAuthorized: false)
67+
}
68+
69+
if let consumer = consumer, !validConsumers.contains(consumer) {
70+
context.logger.info("Deny - Invalid consumer: \(consumer)")
71+
return AuthorizerSimpleResponse(isAuthorized: false)
72+
}
73+
74+
context.logger.info("Allow - Authorization successful")
75+
return AuthorizerSimpleResponse(isAuthorized: true)
76+
}
8077

81-
let runtime = LambdaRuntime(body: authorizerHandler)
8278
try await runtime.run()

0 commit comments

Comments
 (0)