diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 89116fd..aaf7ded 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -1,29 +1,30 @@ name: PR on: - pull_request: - types: [opened, reopened, synchronize] + pull_request: + types: [opened, reopened, synchronize] jobs: - soundness: - name: Soundness - uses: apple/swift-nio/.github/workflows/soundness.yml@main - with: - license_header_check_project_name: "SwiftAWSLambdaRuntime" - shell_check_enabled: false - api_breakage_check_container_image: "swift:6.0-noble" - docs_check_container_image: "swift:6.0-noble" + soundness: + name: Soundness + uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main + with: + license_header_check_project_name: "SwiftAWSLambdaRuntime" + shell_check_enabled: false + python_lint_check_enabled: false + api_breakage_check_container_image: "swift:6.0-noble" + docs_check_container_image: "swift:6.0-noble" + format_check_container_image: "swift:6.0-noble" - unit-tests: - name: Unit tests - uses: apple/swift-nio/.github/workflows/unit_tests.yml@main - with: - linux_5_8_enabled: true - linux_5_9_enabled: true - linux_5_10_enabled: true - linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error" - linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error" + unit-tests: + name: Unit tests + uses: apple/swift-nio/.github/workflows/unit_tests.yml@main + with: + linux_5_9_enabled: false + linux_5_10_enabled: false + linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error" + linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error" - swift-6-language-mode: - name: Swift 6 Language Mode - uses: apple/swift-nio/.github/workflows/swift_6_language_mode.yml@main + swift-6-language-mode: + name: Swift 6 Language Mode + uses: apple/swift-nio/.github/workflows/swift_6_language_mode.yml@main diff --git a/Sources/AWSLambdaEvents/AWSRegion.swift b/Sources/AWSLambdaEvents/AWSRegion.swift index 78789ba..3f622cf 100644 --- a/Sources/AWSLambdaEvents/AWSRegion.swift +++ b/Sources/AWSLambdaEvents/AWSRegion.swift @@ -58,7 +58,7 @@ public struct AWSRegion: RawRepresentable, Equatable, Sendable { Self.sa_east_1, Self.me_central_1, Self.me_south_1, - Self.il_central_1 + Self.il_central_1, ] public static var af_south_1: Self { AWSRegion(rawValue: "af-south-1")! } diff --git a/Sources/AWSLambdaEvents/Cloudwatch.swift b/Sources/AWSLambdaEvents/Cloudwatch.swift index 0895b81..c9b509f 100644 --- a/Sources/AWSLambdaEvents/Cloudwatch.swift +++ b/Sources/AWSLambdaEvents/Cloudwatch.swift @@ -140,16 +140,36 @@ public enum CloudwatchDetails { /// https://docs.aws.amazon.com/AmazonS3/latest/userguide/ev-events.html -public typealias CloudWatchS3ObjectCreatedNotificationEvent = CloudwatchEvent -public typealias CloudWatchS3ObjectDeletedNotificationEvent = CloudwatchEvent -public typealias CloudWatchS3ObjectRestoreInitiatedNotificationEvent = CloudwatchEvent -public typealias CloudWatchS3ObjectRestoreCompletedNotificationEvent = CloudwatchEvent -public typealias CloudWatchS3ObjectRestoreExpiredNotificationEvent = CloudwatchEvent -public typealias CloudWatchS3ObjectStorageClassChangedNotificationEvent = CloudwatchEvent -public typealias CloudWatchS3ObjectAccessTierChangedNotificationEvent = CloudwatchEvent -public typealias CloudWatchS3ObjectACLUpdatedNotificationEvent = CloudwatchEvent -public typealias CloudWatchS3ObjectTagsAddedNotificationEvent = CloudwatchEvent -public typealias CloudWatchS3ObjectTagsDeletedNotificationEvent = CloudwatchEvent +public typealias CloudWatchS3ObjectCreatedNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectCreatedNotification +> +public typealias CloudWatchS3ObjectDeletedNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectDeletedNotification +> +public typealias CloudWatchS3ObjectRestoreInitiatedNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectRestoreInitiatedNotification +> +public typealias CloudWatchS3ObjectRestoreCompletedNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectRestoreCompletedNotification +> +public typealias CloudWatchS3ObjectRestoreExpiredNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectRestoreExpiredNotification +> +public typealias CloudWatchS3ObjectStorageClassChangedNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectStorageClassChangedNotification +> +public typealias CloudWatchS3ObjectAccessTierChangedNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectAccessTierChangedNotification +> +public typealias CloudWatchS3ObjectACLUpdatedNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectACLUpdatedNotification +> +public typealias CloudWatchS3ObjectTagsAddedNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectTagsAddedNotification +> +public typealias CloudWatchS3ObjectTagsDeletedNotificationEvent = CloudwatchEvent< + CloudwatchDetails.S3.ObjectTagsDeletedNotification +> extension CloudwatchDetails { public enum S3: Sendable { @@ -185,7 +205,7 @@ extension CloudwatchDetails { public let version: String public let bucket: Bucket - public let object: Object + public let object: Object public let requestId: String public let requester: String public let sourceIpAddress: String @@ -194,7 +214,7 @@ extension CloudwatchDetails { enum CodingKeys: String, CodingKey { case version case bucket - case object + case object case requestId = "request-id" case requester case sourceIpAddress = "source-ip-address" @@ -235,7 +255,7 @@ extension CloudwatchDetails { public let version: String public let bucket: Bucket - public let object: Object + public let object: Object public let requestId: String public let requester: String public let sourceIpAddress: String @@ -245,7 +265,7 @@ extension CloudwatchDetails { enum CodingKeys: String, CodingKey { case version case bucket - case object + case object case requestId = "request-id" case requester case sourceIpAddress = "source-ip-address" @@ -344,7 +364,7 @@ extension CloudwatchDetails { public let object: Object public let requestId: String public let requester: String - @ISO8601Coding + @ISO8601Coding public var restoreExpiryTime: Date public let sourceStorageClass: SourceStorageClass diff --git a/Tests/AWSLambdaEventsTests/CloudwatchTests.swift b/Tests/AWSLambdaEventsTests/CloudwatchTests.swift index 5ebb455..b8beb94 100644 --- a/Tests/AWSLambdaEventsTests/CloudwatchTests.swift +++ b/Tests/AWSLambdaEventsTests/CloudwatchTests.swift @@ -101,110 +101,113 @@ class CloudwatchTests: XCTestCase { XCTAssertEqual(event.detail.instanceId, "0") XCTAssertEqual(event.detail.action, .terminate) } - - func testS3ObjectCreatedEventFromJSON() { - let eventBody = CloudwatchTests.eventBody( - type: CloudwatchDetails.S3.ObjectCreatedNotification.name, - details: "{ \"version\": \"0\", \"bucket\": { \"name\": \"amzn-s3-demo-bucket1\" }, \"object\": { \"key\": \"example-key\", \"size\":5, \"etag\": \"b1946ac92492d2347c6235b4d2611184\", \"version-id\": \"IYV3p45BT0ac8hjHg1houSdS1a.Mro8e\", \"sequencer\": \"617f08299329d189\" }, \"request-id\": \"N4N7GDK58NMKJ12R\", \"requester\": \"123456789012\", \"source-ip-address\": \"1.2.3.4\", \"reason\": \"PutObject\" }" - - ) - let data = eventBody.data(using: .utf8)! - var maybeEvent: CloudWatchS3ObjectCreatedNotificationEvent? - XCTAssertNoThrow( - maybeEvent = try JSONDecoder().decode(CloudWatchS3ObjectCreatedNotificationEvent.self, from: data) - ) - - guard let event = maybeEvent else { - return XCTFail("Expected to have an event") - } - - XCTAssertEqual(event.id, "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c") - XCTAssertEqual(event.source, "aws.events") - XCTAssertEqual(event.accountId, "123456789012") - XCTAssertEqual(event.time, Date(timeIntervalSince1970: 0)) - XCTAssertEqual(event.region, .us_east_1) - XCTAssertEqual(event.resources, ["arn:aws:events:us-east-1:123456789012:rule/ExampleRule"]) - XCTAssertEqual(event.detail.version, "0") - XCTAssertEqual(event.detail.bucket.name, "amzn-s3-demo-bucket1") - XCTAssertEqual(event.detail.object.key, "example-key") - XCTAssertEqual(event.detail.object.size, 5) - XCTAssertEqual(event.detail.object.etag, "b1946ac92492d2347c6235b4d2611184") - XCTAssertEqual(event.detail.object.versionId, "IYV3p45BT0ac8hjHg1houSdS1a.Mro8e") - XCTAssertEqual(event.detail.object.sequencer, "617f08299329d189") - XCTAssertEqual(event.detail.requestId, "N4N7GDK58NMKJ12R") - XCTAssertEqual(event.detail.requester, "123456789012") - XCTAssertEqual(event.detail.sourceIpAddress, "1.2.3.4") - XCTAssertEqual(event.detail.reason, .putObject) - } - - func testS3ObjectDeletedEventFromJSON() { - let eventBody = CloudwatchTests.eventBody( - type: CloudwatchDetails.S3.ObjectDeletedNotification.name, - details: "{ \"version\": \"0\", \"bucket\": { \"name\": \"amzn-s3-demo-bucket1\" }, \"object\": { \"key\": \"example-key\", \"etag\": \"d41d8cd98f00b204e9800998ecf8427e\", \"version-id\": \"1QW9g1Z99LUNbvaaYVpW9xDlOLU.qxgF\", \"sequencer\": \"617f0837b476e463\" }, \"request-id\": \"0BH729840619AG5K\", \"requester\": \"123456789012\", \"source-ip-address\": \"1.2.3.4\", \"reason\": \"DeleteObject\", \"deletion-type\": \"Delete Marker Created\" }" - - ) - let data = eventBody.data(using: .utf8)! - var maybeEvent: CloudWatchS3ObjectDeletedNotificationEvent? - XCTAssertNoThrow( - maybeEvent = try JSONDecoder().decode(CloudWatchS3ObjectDeletedNotificationEvent.self, from: data) - ) - - guard let event = maybeEvent else { - return XCTFail("Expected to have an event") - } - - XCTAssertEqual(event.id, "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c") - XCTAssertEqual(event.source, "aws.events") - XCTAssertEqual(event.accountId, "123456789012") - XCTAssertEqual(event.time, Date(timeIntervalSince1970: 0)) - XCTAssertEqual(event.region, .us_east_1) - XCTAssertEqual(event.resources, ["arn:aws:events:us-east-1:123456789012:rule/ExampleRule"]) - XCTAssertEqual(event.detail.version, "0") - XCTAssertEqual(event.detail.bucket.name, "amzn-s3-demo-bucket1") - XCTAssertEqual(event.detail.object.key, "example-key") - XCTAssertEqual(event.detail.object.etag, "d41d8cd98f00b204e9800998ecf8427e") - XCTAssertEqual(event.detail.object.versionId, "1QW9g1Z99LUNbvaaYVpW9xDlOLU.qxgF") - XCTAssertEqual(event.detail.object.sequencer, "617f0837b476e463") - XCTAssertEqual(event.detail.requestId, "0BH729840619AG5K") - XCTAssertEqual(event.detail.requester, "123456789012") - XCTAssertEqual(event.detail.sourceIpAddress, "1.2.3.4") - XCTAssertEqual(event.detail.reason, .deleteObject) - XCTAssertEqual(event.detail.deletionType, .deleteMarkerCreated) - } - - func testS3ObjectRestoreCompletedEventFromJSON() { - let eventBody = CloudwatchTests.eventBody( - type: CloudwatchDetails.S3.ObjectRestoreCompletedNotification.name, - details: "{ \"version\": \"0\", \"bucket\": { \"name\": \"amzn-s3-demo-bucket1\" }, \"object\": { \"key\": \"example-key\", \"size\": 5, \"etag\": \"b1946ac92492d2347c6235b4d2611184\", \"version-id\": \"KKsjUC1.6gIjqtvhfg5AdMI0eCePIiT3\" }, \"request-id\": \"189F19CB7FB1B6A4\", \"requester\": \"s3.amazonaws.com\", \"restore-expiry-time\": \"2021-11-13T00:00:00Z\", \"source-storage-class\": \"GLACIER\" }" - - ) - let data = eventBody.data(using: .utf8)! - var maybeEvent: CloudWatchS3ObjectRestoreCompletedNotificationEvent? - XCTAssertNoThrow( - maybeEvent = try JSONDecoder().decode(CloudWatchS3ObjectRestoreCompletedNotificationEvent.self, from: data) - ) - - guard let event = maybeEvent else { - return XCTFail("Expected to have an event") - } - - XCTAssertEqual(event.id, "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c") - XCTAssertEqual(event.source, "aws.events") - XCTAssertEqual(event.accountId, "123456789012") - XCTAssertEqual(event.time, Date(timeIntervalSince1970: 0)) - XCTAssertEqual(event.region, .us_east_1) - XCTAssertEqual(event.resources, ["arn:aws:events:us-east-1:123456789012:rule/ExampleRule"]) - XCTAssertEqual(event.detail.version, "0") - XCTAssertEqual(event.detail.bucket.name, "amzn-s3-demo-bucket1") - XCTAssertEqual(event.detail.object.key, "example-key") - XCTAssertEqual(event.detail.object.size, 5) - XCTAssertEqual(event.detail.object.etag, "b1946ac92492d2347c6235b4d2611184") - XCTAssertEqual(event.detail.object.versionId, "KKsjUC1.6gIjqtvhfg5AdMI0eCePIiT3") - XCTAssertEqual(event.detail.requestId, "189F19CB7FB1B6A4") - XCTAssertEqual(event.detail.requester, "s3.amazonaws.com") - XCTAssertEqual(event.detail.restoreExpiryTime.description, "2021-11-13 00:00:00 +0000") - XCTAssertEqual(event.detail.sourceStorageClass, .glacier) - } + + func testS3ObjectCreatedEventFromJSON() { + let eventBody = CloudwatchTests.eventBody( + type: CloudwatchDetails.S3.ObjectCreatedNotification.name, + details: + "{ \"version\": \"0\", \"bucket\": { \"name\": \"amzn-s3-demo-bucket1\" }, \"object\": { \"key\": \"example-key\", \"size\":5, \"etag\": \"b1946ac92492d2347c6235b4d2611184\", \"version-id\": \"IYV3p45BT0ac8hjHg1houSdS1a.Mro8e\", \"sequencer\": \"617f08299329d189\" }, \"request-id\": \"N4N7GDK58NMKJ12R\", \"requester\": \"123456789012\", \"source-ip-address\": \"1.2.3.4\", \"reason\": \"PutObject\" }" + + ) + let data = eventBody.data(using: .utf8)! + var maybeEvent: CloudWatchS3ObjectCreatedNotificationEvent? + XCTAssertNoThrow( + maybeEvent = try JSONDecoder().decode(CloudWatchS3ObjectCreatedNotificationEvent.self, from: data) + ) + + guard let event = maybeEvent else { + return XCTFail("Expected to have an event") + } + + XCTAssertEqual(event.id, "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c") + XCTAssertEqual(event.source, "aws.events") + XCTAssertEqual(event.accountId, "123456789012") + XCTAssertEqual(event.time, Date(timeIntervalSince1970: 0)) + XCTAssertEqual(event.region, .us_east_1) + XCTAssertEqual(event.resources, ["arn:aws:events:us-east-1:123456789012:rule/ExampleRule"]) + XCTAssertEqual(event.detail.version, "0") + XCTAssertEqual(event.detail.bucket.name, "amzn-s3-demo-bucket1") + XCTAssertEqual(event.detail.object.key, "example-key") + XCTAssertEqual(event.detail.object.size, 5) + XCTAssertEqual(event.detail.object.etag, "b1946ac92492d2347c6235b4d2611184") + XCTAssertEqual(event.detail.object.versionId, "IYV3p45BT0ac8hjHg1houSdS1a.Mro8e") + XCTAssertEqual(event.detail.object.sequencer, "617f08299329d189") + XCTAssertEqual(event.detail.requestId, "N4N7GDK58NMKJ12R") + XCTAssertEqual(event.detail.requester, "123456789012") + XCTAssertEqual(event.detail.sourceIpAddress, "1.2.3.4") + XCTAssertEqual(event.detail.reason, .putObject) + } + + func testS3ObjectDeletedEventFromJSON() { + let eventBody = CloudwatchTests.eventBody( + type: CloudwatchDetails.S3.ObjectDeletedNotification.name, + details: + "{ \"version\": \"0\", \"bucket\": { \"name\": \"amzn-s3-demo-bucket1\" }, \"object\": { \"key\": \"example-key\", \"etag\": \"d41d8cd98f00b204e9800998ecf8427e\", \"version-id\": \"1QW9g1Z99LUNbvaaYVpW9xDlOLU.qxgF\", \"sequencer\": \"617f0837b476e463\" }, \"request-id\": \"0BH729840619AG5K\", \"requester\": \"123456789012\", \"source-ip-address\": \"1.2.3.4\", \"reason\": \"DeleteObject\", \"deletion-type\": \"Delete Marker Created\" }" + + ) + let data = eventBody.data(using: .utf8)! + var maybeEvent: CloudWatchS3ObjectDeletedNotificationEvent? + XCTAssertNoThrow( + maybeEvent = try JSONDecoder().decode(CloudWatchS3ObjectDeletedNotificationEvent.self, from: data) + ) + + guard let event = maybeEvent else { + return XCTFail("Expected to have an event") + } + + XCTAssertEqual(event.id, "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c") + XCTAssertEqual(event.source, "aws.events") + XCTAssertEqual(event.accountId, "123456789012") + XCTAssertEqual(event.time, Date(timeIntervalSince1970: 0)) + XCTAssertEqual(event.region, .us_east_1) + XCTAssertEqual(event.resources, ["arn:aws:events:us-east-1:123456789012:rule/ExampleRule"]) + XCTAssertEqual(event.detail.version, "0") + XCTAssertEqual(event.detail.bucket.name, "amzn-s3-demo-bucket1") + XCTAssertEqual(event.detail.object.key, "example-key") + XCTAssertEqual(event.detail.object.etag, "d41d8cd98f00b204e9800998ecf8427e") + XCTAssertEqual(event.detail.object.versionId, "1QW9g1Z99LUNbvaaYVpW9xDlOLU.qxgF") + XCTAssertEqual(event.detail.object.sequencer, "617f0837b476e463") + XCTAssertEqual(event.detail.requestId, "0BH729840619AG5K") + XCTAssertEqual(event.detail.requester, "123456789012") + XCTAssertEqual(event.detail.sourceIpAddress, "1.2.3.4") + XCTAssertEqual(event.detail.reason, .deleteObject) + XCTAssertEqual(event.detail.deletionType, .deleteMarkerCreated) + } + + func testS3ObjectRestoreCompletedEventFromJSON() { + let eventBody = CloudwatchTests.eventBody( + type: CloudwatchDetails.S3.ObjectRestoreCompletedNotification.name, + details: + "{ \"version\": \"0\", \"bucket\": { \"name\": \"amzn-s3-demo-bucket1\" }, \"object\": { \"key\": \"example-key\", \"size\": 5, \"etag\": \"b1946ac92492d2347c6235b4d2611184\", \"version-id\": \"KKsjUC1.6gIjqtvhfg5AdMI0eCePIiT3\" }, \"request-id\": \"189F19CB7FB1B6A4\", \"requester\": \"s3.amazonaws.com\", \"restore-expiry-time\": \"2021-11-13T00:00:00Z\", \"source-storage-class\": \"GLACIER\" }" + + ) + let data = eventBody.data(using: .utf8)! + var maybeEvent: CloudWatchS3ObjectRestoreCompletedNotificationEvent? + XCTAssertNoThrow( + maybeEvent = try JSONDecoder().decode(CloudWatchS3ObjectRestoreCompletedNotificationEvent.self, from: data) + ) + + guard let event = maybeEvent else { + return XCTFail("Expected to have an event") + } + + XCTAssertEqual(event.id, "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c") + XCTAssertEqual(event.source, "aws.events") + XCTAssertEqual(event.accountId, "123456789012") + XCTAssertEqual(event.time, Date(timeIntervalSince1970: 0)) + XCTAssertEqual(event.region, .us_east_1) + XCTAssertEqual(event.resources, ["arn:aws:events:us-east-1:123456789012:rule/ExampleRule"]) + XCTAssertEqual(event.detail.version, "0") + XCTAssertEqual(event.detail.bucket.name, "amzn-s3-demo-bucket1") + XCTAssertEqual(event.detail.object.key, "example-key") + XCTAssertEqual(event.detail.object.size, 5) + XCTAssertEqual(event.detail.object.etag, "b1946ac92492d2347c6235b4d2611184") + XCTAssertEqual(event.detail.object.versionId, "KKsjUC1.6gIjqtvhfg5AdMI0eCePIiT3") + XCTAssertEqual(event.detail.requestId, "189F19CB7FB1B6A4") + XCTAssertEqual(event.detail.requester, "s3.amazonaws.com") + XCTAssertEqual(event.detail.restoreExpiryTime.description, "2021-11-13 00:00:00 +0000") + XCTAssertEqual(event.detail.sourceStorageClass, .glacier) + } func testCustomEventFromJSON() { struct Custom: CloudwatchDetail {