Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Impose a 127 character limit on the Lambda function handler when the package type is set to zip #1812

Merged
merged 3 commits into from
Sep 23, 2024
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
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, class name or method name to stay within the character limit.",
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
Loading