AWS code-library documentation change
Summary
Added Swift SDK code example demonstrating SNS/SQS integration with FIFO topics, message filtering, deduplication, and queue policy configuration
Security assessment
The change adds documentation about secure queue policy configuration (IAM policy restricting SQS access to SNS topic) and message filtering. While security-related features are demonstrated, there's no evidence of addressing a specific vulnerability or security incident.
Diff
diff --git a/code-library/latest/ug/sns_example_sqs_Scenario_TopicsAndQueues_section.md b/code-library/latest/ug/sns_example_sqs_Scenario_TopicsAndQueues_section.md index b79ca844d..8663c3438 100644 --- a//code-library/latest/ug/sns_example_sqs_Scenario_TopicsAndQueues_section.md +++ b//code-library/latest/ug/sns_example_sqs_Scenario_TopicsAndQueues_section.md @@ -4068,0 +4069,734 @@ There's more on GitHub. Find the complete example and learn how to set up and ru +Swift + + +**SDK for Swift** + + +###### Note + +There's more on GitHub. Find the complete example and learn how to set up and run in the [AWS Code Examples Repository](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/swift/example_code/sqs/scenario#code-examples). + + + import ArgumentParser + import AWSClientRuntime + import AWSSNS + import AWSSQS + import Foundation + + struct ExampleCommand: ParsableCommand { + @Option(help: "Name of the Amazon Region to use") + var region = "us-east-1" + + static var configuration = CommandConfiguration( + commandName: "queue-scenario", + abstract: """ + This example interactively demonstrates how to use Amazon Simple + Notification Service (Amazon SNS) and Amazon Simple Queue Service + (Amazon SQS) together to publish and receive messages using queues. + """, + discussion: """ + Supports filtering using a "tone" attribute. + """ + ) + + /// Prompt for an input string. Only non-empty strings are allowed. + /// + /// - Parameter prompt: The prompt to display. + /// + /// - Returns: The string input by the user. + func stringRequest(prompt: String) -> String { + var str: String? + + while str == nil { + print(prompt, terminator: "") + str = readLine() + + if str != nil && str?.count == 0 { + str = nil + } + } + + return str! + } + + /// Ask a yes/no question. + /// + /// - Parameter prompt: A prompt string to print. + /// + /// - Returns: `true` if the user answered "Y", otherwise `false`. + func yesNoRequest(prompt: String) -> Bool { + while true { + let answer = stringRequest(prompt: prompt).lowercased() + if answer == "y" || answer == "n" { + return answer == "y" + } + } + } + + /// Display a menu of options then request a selection. + /// + /// - Parameters: + /// - prompt: A prompt string to display before the menu. + /// - options: An array of strings giving the menu options. + /// + /// - Returns: The index number of the selected option or 0 if no item was + /// selected. + func menuRequest(prompt: String, options: [String]) -> Int { + let numOptions = options.count + + if numOptions == 0 { + return 0 + } + + print(prompt) + + for (index, value) in options.enumerated() { + print("(\(index)) \(value)") + } + + repeat { + print("Enter your selection (0 - \(numOptions-1)): ", terminator: "") + if let answer = readLine() { + guard let answer = Int(answer) else { + print("Please enter the number matching your selection.") + continue + } + + if answer >= 0 && answer < numOptions { + return answer + } else { + print("Please enter the number matching your selection.") + } + } + } while true + } + + /// Ask the user too press RETURN. Accepts any input but ignores it. + /// + /// - Parameter prompt: The text prompt to display. + func returnRequest(prompt: String) { + print(prompt, terminator: "") + _ = readLine() + } + + var attrValues = [ + "<none>", + "cheerful", + "funny", + "serious", + "sincere" + ] + + /// Ask the user to choose one of the attribute values to use as a filter. + /// + /// - Parameters: + /// - message: A message to display before the menu of values. + /// - attrValues: An array of strings giving the values to choose from. + /// + /// - Returns: The string corresponding to the selected option. + func askForFilter(message: String, attrValues: [String]) -> String? { + print(message) + for (index, value) in attrValues.enumerated() { + print(" [\(index)] \(value)") + } + + var answer: Int? + repeat { + answer = Int(stringRequest(prompt: "Select an value for the 'tone' attribute or 0 to end: ")) + } while answer == nil || answer! < 0 || answer! > attrValues.count + 1 + + if answer == 0 { + return nil + } + return attrValues[answer!] + } + + /// Prompts the user for filter terms and constructs the attribute + /// record that specifies them. + /// + /// - Returns: A mapping of "FilterPolicy" to a JSON string representing + /// the user-defined filter. + func buildFilterAttributes() -> [String:String] { + var attr: [String:String] = [:] + var filterString = "" + + var first = true + + while let ans = askForFilter(message: "Choose a value to apply to the 'tone' attribute.", + attrValues: attrValues) { + if !first { + filterString += "," + } + first = false + + filterString += "\"\(ans)\"" + } + + let filterJSON = "{ \"tone\": [\(filterString)]}" + attr["FilterPolicy"] = filterJSON + + return attr + } + /// Create a queue, returning its URL string. + /// + /// - Parameters: + /// - prompt: A prompt to ask for the queue name. + /// - isFIFO: Whether or not to create a FIFO queue. + /// + /// - Returns: The URL of the queue. + func createQueue(prompt: String, sqsClient: SQSClient, isFIFO: Bool) async throws -> String? { + repeat { + var queueName = stringRequest(prompt: prompt) + var attributes: [String: String] = [:] + + if isFIFO { + queueName += ".fifo" + attributes["FifoQueue"] = "true" + } + + do { + let output = try await sqsClient.createQueue( + input: CreateQueueInput( + attributes: attributes, + queueName: queueName + ) + )