Skip to content

Commit 83c591a

Browse files
authored
feat(middleware-bucket-endpoint): add object lambda support (#2143)
* fix(middleware-bucket-endpoint): bugfixing the s3 endpoint parser * fix(middleware-bucket-endpoint): add tests * fix: remove latent debugger * feat: add robust tests to object lambda * fix: adding object lambda to service validation * fix: fixing error messages in tests
1 parent 105c9b7 commit 83c591a

File tree

3 files changed

+222
-7
lines changed

3 files changed

+222
-7
lines changed

packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts

Lines changed: 207 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ describe("bucketHostname", () => {
393393
[
394394
{
395395
bucketArn: "arn:aws:sqs:us-west-2:123456789012:someresource",
396-
message: "Expect 's3' or 's3-outposts' in ARN service component",
396+
message: "Expect 's3' or 's3-outposts' or 's3-object-lambda' in ARN service component",
397397
},
398398
{
399399
bucketArn: "arn:aws:s3:us-west-2:123456789012:bucket_name:mybucket",
@@ -713,4 +713,210 @@ describe("bucketHostname", () => {
713713
expect(signingService).toBe("s3-outposts");
714714
});
715715
});
716+
717+
describe("from Object Lamdba ARN", () => {
718+
describe("populates access point endpoint from ARN", () => {
719+
it("should use the proper endpoint", () => {
720+
const region = "eu-west-1";
721+
const expectedEndpoint = "js-sdk-ap-name-123456789012.s3-object-lambda.eu-west-1.amazonaws.com";
722+
["arn:aws:s3-object-lambda:eu-west-1:123456789012:accesspoint/js-sdk-ap-name"].forEach((outpostArn) => {
723+
const { bucketEndpoint, hostname } = bucketHostname({
724+
bucketName: parseArn(outpostArn),
725+
baseHostname: "s3.eu-west-1.amazonaws.com",
726+
isCustomEndpoint: false,
727+
clientRegion: region,
728+
});
729+
expect(bucketEndpoint).toBe(true);
730+
expect(hostname).toBe(expectedEndpoint);
731+
});
732+
});
733+
});
734+
735+
it("should not be able to use accelerate", () => {
736+
try {
737+
bucketHostname({
738+
bucketName: parseArn("arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner"),
739+
baseHostname: "s3.us-west-2.amazonaws.com",
740+
isCustomEndpoint: false,
741+
clientRegion: "us-west-2",
742+
accelerateEndpoint: true,
743+
});
744+
// should never get here
745+
expect.assertions(1);
746+
} catch (e) {
747+
// should throw since these are error cases
748+
expect(1).toEqual(1);
749+
}
750+
});
751+
752+
it("should not be able to use dualstack", () => {
753+
try {
754+
bucketHostname({
755+
bucketName: parseArn("arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner"),
756+
baseHostname: "s3.us-west-2.amazonaws.com",
757+
isCustomEndpoint: false,
758+
clientRegion: "us-west-2",
759+
dualstackEndpoint: true,
760+
});
761+
// should never get here
762+
expect.assertions(1);
763+
} catch (e) {
764+
// should throw since these are error cases
765+
expect(1).toEqual(1);
766+
}
767+
});
768+
769+
it("should support a custom endpoint", () => {
770+
const { hostname } = bucketHostname({
771+
bucketName: parseArn("arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner"),
772+
baseHostname: "my-endpoint.com",
773+
isCustomEndpoint: true,
774+
clientRegion: "us-west-2",
775+
});
776+
expect(hostname).toEqual("mybanner-123456789012.s3-object-lambda.us-west-2.my-endpoint.com");
777+
});
778+
779+
describe("object lambda general test cases", () => {
780+
it("should match expectations in valid configurations", () => {
781+
const validLambdaExpectations: [string, string, boolean, string][] = [
782+
[
783+
"arn:aws:s3-object-lambda:us-west-2:1123456789012:accesspoint/mybanner",
784+
"us-west-2",
785+
false,
786+
"mybanner-1123456789012.s3-object-lambda.us-west-2.amazonaws.com",
787+
],
788+
[
789+
"arn:aws:s3-object-lambda:us-west-2:2123456789012:accesspoint:mybanner",
790+
"us-west-2",
791+
false,
792+
"mybanner-2123456789012.s3-object-lambda.us-west-2.amazonaws.com",
793+
],
794+
[
795+
"arn:aws:s3-object-lambda:us-east-1:3123456789012:accesspoint/mybanner",
796+
"us-west-2",
797+
true,
798+
"mybanner-3123456789012.s3-object-lambda.us-east-1.amazonaws.com",
799+
],
800+
[
801+
"arn:aws:s3-object-lambda:us-east-1:4123456789012:accesspoint/mybanner",
802+
"s3-external-1",
803+
true,
804+
"mybanner-4123456789012.s3-object-lambda.us-east-1.amazonaws.com",
805+
],
806+
[
807+
"arn:aws:s3-object-lambda:us-east-1:5123456789012:accesspoint/mybanner",
808+
"aws-global",
809+
true,
810+
"mybanner-5123456789012.s3-object-lambda.us-east-1.amazonaws.com",
811+
],
812+
];
813+
validLambdaExpectations.forEach((lambdaArn) => {
814+
const arn = lambdaArn[0];
815+
const region = lambdaArn[1];
816+
const useArnRegion = lambdaArn[2];
817+
const exoectedEndpoint = lambdaArn[3];
818+
const { bucketEndpoint, hostname } = bucketHostname({
819+
bucketName: parseArn(arn),
820+
baseHostname: `s3.${region}.amazonaws.com`,
821+
isCustomEndpoint: false,
822+
clientRegion: region,
823+
useArnRegion: useArnRegion,
824+
});
825+
expect(bucketEndpoint).toBe(true);
826+
expect(hostname).toBe(exoectedEndpoint);
827+
});
828+
});
829+
830+
it("should match not work with invalid configurations", () => {
831+
const invalidLambdaConfigurations: [string, string, boolean, string][] = [
832+
[
833+
"arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner",
834+
"us-west-2",
835+
false,
836+
"Invalid configuration, cross region Access Point ARN",
837+
],
838+
[
839+
"arn:aws-cn:s3-object-lambda:cn-north-1:123456789012:accesspoint/mybanner",
840+
"us-west-2",
841+
true,
842+
"Invalid configuration, cross partition Access Point ARN",
843+
],
844+
[
845+
"arn:aws:sqs:us-west-2:123456789012:someresource",
846+
"us-west-2",
847+
false,
848+
"Invalid ARN not S3 Access Point ARN",
849+
],
850+
[
851+
"arn:aws:s3-object-lambda:us-west-2:123456789012:bucket_name:mybucket",
852+
"us-west-2",
853+
false,
854+
"Invalid ARN not S3 Access Point ARN",
855+
],
856+
[
857+
"arn:aws:s3-object-lambda::123456789012:accesspoint/mybanner",
858+
"us-west-2",
859+
false,
860+
"Invalid ARN, missing region",
861+
],
862+
[
863+
"arn:aws:s3-object-lambda:us-west-2::accesspoint/mybanner",
864+
"us-west-2",
865+
false,
866+
"Invalid ARN, missing account-id",
867+
],
868+
[
869+
"arn:aws:s3-object-lambda:us-west-2:123.45678.9012:accesspoint:mybucket",
870+
"us-west-2",
871+
false,
872+
"Invalid ARN, account-id contains invalid character, ..",
873+
],
874+
[
875+
"arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint",
876+
"us-west-2",
877+
false,
878+
"Invalid ARN, missing Access Point name",
879+
],
880+
[
881+
"arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:*",
882+
"us-west-2",
883+
false,
884+
"Invalid ARN, Access Point Name contains invalid character, *",
885+
],
886+
[
887+
"arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:my.bucket",
888+
"us-west-2",
889+
false,
890+
"Invalid ARN, Access Point Name contains invalid character, .",
891+
],
892+
[
893+
"arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:mybucket:object:foo",
894+
"us-west-2",
895+
false,
896+
"Invalid ARN, Access Point ARN contains sub resources",
897+
],
898+
];
899+
900+
invalidLambdaConfigurations.forEach((lambdaArn) => {
901+
const arn = lambdaArn[0];
902+
const region = lambdaArn[1];
903+
const useArnRegion = lambdaArn[2];
904+
try {
905+
bucketHostname({
906+
bucketName: parseArn(arn),
907+
baseHostname: "s3.us-west-2.amazonaws.com",
908+
isCustomEndpoint: false,
909+
clientRegion: region,
910+
useArnRegion: useArnRegion,
911+
});
912+
// should never get here
913+
expect.assertions(1);
914+
} catch (e) {
915+
// should throw since these are error cases
916+
expect(1).toEqual(1);
917+
}
918+
});
919+
});
920+
});
921+
});
716922
});

packages/middleware-bucket-endpoint/src/bucketHostname.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,26 @@ const getEndpointFromArn = (options: ArnHostnameParams & { isCustomEndpoint: boo
6868
validateAccountId(accountId);
6969
validateRegion(region, { useArnRegion, clientRegion, clientSigningRegion });
7070
const { accesspointName, outpostId } = getArnResources(resource);
71-
validateDNSHostLabel(`${accesspointName}-${accountId}`, { tlsCompatible });
71+
const DNSHostLabel = `${accesspointName}-${accountId}`;
72+
validateDNSHostLabel(DNSHostLabel, { tlsCompatible });
7273

7374
const endpointRegion = useArnRegion ? region : clientRegion;
7475
const signingRegion = useArnRegion ? region : clientSigningRegion;
75-
if (outpostId) {
76+
if (service === "s3-object-lambda") {
77+
validateNoDualstack(dualstackEndpoint);
78+
return {
79+
bucketEndpoint: true,
80+
hostname: `${DNSHostLabel}.${service}.${endpointRegion}.${hostnameSuffix}`,
81+
signingRegion,
82+
signingService: service,
83+
};
84+
} else if (outpostId) {
7685
// if this is an Outpost ARN
7786
validateOutpostService(service);
7887
validateDNSHostLabel(outpostId, { tlsCompatible });
7988
validateNoDualstack(dualstackEndpoint);
8089
validateNoFIPS(endpointRegion);
81-
const hostnamePrefix = `${accesspointName}-${accountId}.${outpostId}`;
90+
const hostnamePrefix = `${DNSHostLabel}.${outpostId}`;
8291
return {
8392
bucketEndpoint: true,
8493
hostname: `${hostnamePrefix}${isCustomEndpoint ? "" : `.s3-outposts.${endpointRegion}`}.${hostnameSuffix}`,
@@ -88,7 +97,7 @@ const getEndpointFromArn = (options: ArnHostnameParams & { isCustomEndpoint: boo
8897
}
8998
// construct endpoint from Accesspoint ARN
9099
validateS3Service(service);
91-
const hostnamePrefix = `${accesspointName}-${accountId}`;
100+
const hostnamePrefix = `${DNSHostLabel}`;
92101
return {
93102
bucketEndpoint: true,
94103
hostname: `${hostnamePrefix}${

packages/middleware-bucket-endpoint/src/bucketHostnameUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ export const validateArnEndpointOptions = (options: {
8787
};
8888

8989
export const validateService = (service: string) => {
90-
if (service !== "s3" && service !== "s3-outposts") {
91-
throw new Error("Expect 's3' or 's3-outposts' in ARN service component");
90+
if (service !== "s3" && service !== "s3-outposts" && service !== "s3-object-lambda") {
91+
throw new Error("Expect 's3' or 's3-outposts' or 's3-object-lambda' in ARN service component");
9292
}
9393
};
9494

0 commit comments

Comments
 (0)