Skip to content

Commit

Permalink
fix: Impose a 127 character limit on the Lambda function handler when…
Browse files Browse the repository at this point in the history
… the package type is set to zip

Addresses #1642
  • Loading branch information
96malhar committed Sep 19, 2024
1 parent cdaef1c commit dff351c
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
; Shipped analyzer releases
; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

## Release 1.5.1
### New Rules

Rule ID | Category | Severity | Notes
--------|----------|----------|-------
AWSLambda0118 | AWSLambdaCSharpGenerator | Error | Maximum Handler Length Exceeded

## Release 1.5.0
### New Rules

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,5 +138,12 @@ public static class DiagnosticDescriptors
category: "AWSLambdaCSharpGenerator",
DiagnosticSeverity.Error,
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor MaximumHandlerLengthExceeded = new DiagnosticDescriptor(id: "AWSLambda0118",
title: "Maximum Handler Length Exceeded",
messageFormat: "The handler string '{0}' exceeds the maximum length of 127 characters. Please trim down your project namespace to stay within the character limit. Alternatively, you can switch to an image based deployment by setting the 'PackageType' to 'Image' to avoid the handler length restriction.",
category: "AWSLambdaCSharpGenerator",
DiagnosticSeverity.Error,
isEnabledByDefault: true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ internal static bool ValidateFunction(GeneratorExecutionContext context, IMethod
diagnostics.Add(Diagnostic.Create(DiagnosticDescriptors.InvalidResourceName, methodLocation));
}

// Check the handler length does not exceed 127 characters when the package type is set to zip
// The official AWS docs state a 128 character limit on the Lambda handler. However, there is an open issue where the last character is stripped off
// when the handler is exactly 128 characters long. Hence, we are enforcing a 127 character limit.
// https://github.com/aws/aws-lambda-dotnet/issues/1642
if (lambdaFunctionModel.PackageType == LambdaPackageType.Zip && lambdaFunctionModel.Handler.Length > 127)
{
diagnostics.Add(Diagnostic.Create(DiagnosticDescriptors.MaximumHandlerLengthExceeded, methodLocation, lambdaFunctionModel.Handler));
}

// Check for Serializer attribute
if (!lambdaMethodSymbol.ContainingAssembly.HasAttribute(context, TypeFullNames.LambdaSerializerAttribute))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,18 @@
}
},
"Properties": {
"Runtime": "dotnet6",
"CodeUri": ".",
"MemorySize": 512,
"Timeout": 30,
"Policies": [
"AWSLambdaBasicExecutionRole"
],
"PackageType": "Zip",
"Handler": "TestProject::TestServerlessApp.SQSEventExamples.ValidSQSEvents_ProcessMessages_Generated::ProcessMessages",
"PackageType": "Image",
"ImageUri": ".",
"ImageConfig": {
"Command": [
"TestProject::TestServerlessApp.SQSEventExamples.ValidSQSEvents_ProcessMessages_Generated::ProcessMessages"
]
},
"Events": {
"queue1": {
"Type": "SQS",
Expand Down Expand Up @@ -109,15 +112,18 @@
}
},
"Properties": {
"Runtime": "dotnet6",
"CodeUri": ".",
"MemorySize": 512,
"Timeout": 30,
"Policies": [
"AWSLambdaBasicExecutionRole"
],
"PackageType": "Zip",
"Handler": "TestProject::TestServerlessApp.SQSEventExamples.ValidSQSEvents_ProcessMessagesWithBatchFailureReporting_Generated::ProcessMessagesWithBatchFailureReporting",
"PackageType": "Image",
"ImageUri": ".",
"ImageConfig": {
"Command": [
"TestProject::TestServerlessApp.SQSEventExamples.ValidSQSEvents_ProcessMessagesWithBatchFailureReporting_Generated::ProcessMessagesWithBatchFailureReporting"
]
},
"Events": {
"queue3": {
"Type": "SQS",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,31 @@ public async Task VerifyValidSQSEvents()
}.RunAsync();
}

[Fact]
public async Task ExceededMaximumHandlerLength()
{
await new VerifyCS.Test
{
TestState =
{
Sources =
{
(Path.Combine("TestServerlessApp", "PlaceholderClass.cs"), await File.ReadAllTextAsync(Path.Combine("TestServerlessApp", "PlaceholderClass.cs"))),
(Path.Combine("TestServerlessApp", "ExceededMaximumHandlerLength.cs"), await File.ReadAllTextAsync(Path.Combine("TestServerlessApp", "ExceededMaximumHandlerLength.cs.error"))),
(Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"), await File.ReadAllTextAsync(Path.Combine("Amazon.Lambda.Annotations", "LambdaFunctionAttribute.cs"))),
(Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"), await File.ReadAllTextAsync(Path.Combine("TestServerlessApp", "AssemblyAttributes.cs"))),
},
ExpectedDiagnostics =
{
DiagnosticResult
.CompilerError("AWSLambda0118")
.WithSpan($"TestServerlessApp{Path.DirectorySeparatorChar}ExceededMaximumHandlerLength.cs", 9, 9, 13, 10)
.WithArguments("TestProject::TestServerlessApp.ExceededMaximumHandlerLength_SayHelloXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX_Generated::SayHelloXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
},
}
}.RunAsync();
}

public void Dispose()
{
File.Delete(Path.Combine("TestServerlessApp", "serverless.template"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using Amazon.Lambda.Annotations;

namespace TestServerlessApp
{
public class ExceededMaximumHandlerLength
{
// This fails because generated handler is longer than 127 characters
[LambdaFunction]
public string SayHelloXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX()
{
return "Hello, World!";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,72 +12,72 @@ namespace TestServerlessApp.SQSEventExamples

public class InvalidSQSEvents
{
[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("@testQueue", BatchSize = 0, MaximumBatchingWindowInSeconds = 302, MaximumConcurrency = 1)]
public void ProcessMessageWithInvalidSQSEventAttributes(SQSEvent evnt)
{
Console.WriteLine($"Event processed: {evnt}");
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("@testQueue")]
public void ProcessMessageWithInvalidParameters(SQSEvent evnt, bool invalidParameter1, int invalidParameter2)
{
Console.WriteLine($"Event processed: {evnt}");
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("@testQueue")]
public bool ProcessMessageWithInvalidReturnType(SQSEvent evnt)
{
Console.WriteLine($"Event processed: {evnt}");
return true;
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[RestApi(LambdaHttpMethod.Get, "/")]
[SQSEvent("@testQueue")]
public void ProcessMessageWithMultipleEventTypes(SQSEvent evnt)
{
Console.WriteLine($"Event processed: {evnt}");
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("test-queue")]
public void ProcessMessageWithInvalidQueueArn(SQSEvent evnt)
{
Console.WriteLine($"Event processed: {evnt}");
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("@testQueue", ResourceName = "sqs-event-source")]
public void ProcessMessageWithInvalidResourceName(SQSEvent evnt)
{
Console.WriteLine($"Event processed: {evnt}");
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("@testQueue", ResourceName = "")]
public void ProcessMessageWithEmptyResourceName(SQSEvent evnt)
{
Console.WriteLine($"Event processed: {evnt}");
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("@testQueue", BatchSize = 100)]
public void ProcessMessageWithMaximumBatchingWindowInSecondsNotSpecified(SQSEvent evnt)
{
Console.WriteLine($"Event processed: {evnt}");
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("@testQueue", BatchSize = 100, MaximumBatchingWindowInSeconds = 0)]
public void ProcessMessageWithMaximumBatchingWindowInSecondsLessThanOne(SQSEvent evnt)
{
Console.WriteLine($"Event processed: {evnt}");
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("arn:aws:sqs:us-east-2:444455556666:test-queue.fifo", BatchSize = 100, MaximumBatchingWindowInSeconds = 5)]
public void ProcessMessageWithFifoQueue(SQSEvent evnt)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace TestServerlessApp.SQSEventExamples

public class ValidSQSEvents
{
[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("arn:aws:sqs:us-east-2:444455556666:queue1", BatchSize = 50, MaximumBatchingWindowInSeconds = 2, MaximumConcurrency = 30, Filters = "My-Filter-1; My-Filter-2")]
[SQSEvent("arn:aws:sqs:us-east-2:444455556666:queue2", MaximumBatchingWindowInSeconds = 5, Enabled = false)]
[SQSEvent("arn:aws:sqs:us-east-2:444455556666:my-queue")]
Expand All @@ -22,7 +22,7 @@ namespace TestServerlessApp.SQSEventExamples
Console.WriteLine($"Event processed: {evnt}");
}

[LambdaFunction]
[LambdaFunction(PackageType = LambdaPackageType.Image)]
[SQSEvent("arn:aws:sqs:us-east-2:444455556666:queue3")]
public async Task<SQSBatchResponse> ProcessMessagesWithBatchFailureReporting(SQSEvent evnt)
{
Expand Down
12 changes: 6 additions & 6 deletions Libraries/test/TestServerlessApp/serverless.template
Original file line number Diff line number Diff line change
Expand Up @@ -913,12 +913,6 @@
"TestQueueEvent": {
"Type": "SQS",
"Properties": {
"Queue": {
"Fn::GetAtt": [
"TestQueue",
"Arn"
]
},
"BatchSize": 50,
"FilterCriteria": {
"Filters": [
Expand All @@ -933,6 +927,12 @@
"MaximumBatchingWindowInSeconds": 5,
"ScalingConfig": {
"MaximumConcurrency": 5
},
"Queue": {
"Fn::GetAtt": [
"TestQueue",
"Arn"
]
}
}
}
Expand Down

0 comments on commit dff351c

Please sign in to comment.