diff --git a/events/testdata/vpclattice-response.json b/events/testdata/vpclattice-response.json new file mode 100644 index 00000000..d5438dc2 --- /dev/null +++ b/events/testdata/vpclattice-response.json @@ -0,0 +1,10 @@ +{ + "isBase64Encoded": true, + "statusCode": 200, + "statusDescription": "200 OK", + "headers": { + "set-cookie": "cookies", + "content-type": "application/json" + }, + "body": "BODY" +} \ No newline at end of file diff --git a/events/testdata/vpclattice-v1-request.json b/events/testdata/vpclattice-v1-request.json new file mode 100644 index 00000000..b247ced4 --- /dev/null +++ b/events/testdata/vpclattice-v1-request.json @@ -0,0 +1,16 @@ +{ + "raw_path": "/", + "method": "POST", + "headers": { + "accept-encoding": "gzip, br, deflate", + "accept": "application/json", + "content-length": "4", + "content-type": "application/json", + "host": "some-host.vpc-lattice-svcs.us-east-1.on.aws", + "x-forwarded-for": "1.2.3.4,2.3.4.5", + "x-forwarded-port": "443" + }, + "query_string_parameters": {}, + "body": "BODY", + "is_base64_encoded": true +} \ No newline at end of file diff --git a/events/testdata/vpclattice-v2-request.json b/events/testdata/vpclattice-v2-request.json new file mode 100644 index 00000000..f032a92b --- /dev/null +++ b/events/testdata/vpclattice-v2-request.json @@ -0,0 +1,42 @@ +{ + "version": "2.0", + "path": "/", + "method": "POST", + "headers": { + "accept": [ + "application/json" + ], + "x-forwarded-port": [ + "443" + ], + "x-forwarded-for": [ + "1.2.3.4,2.3.4.5" + ], + "host": [ + "some-host.vpc-lattice-svcs.us-east-1.on.aws" + ], + "content-type": [ + "application/json" + ], + "content-length": [ + "4" + ], + "accept-encoding": [ + "gzip, br, deflate" + ] + }, + "body": "BODY", + "requestContext": { + "serviceNetworkArn": "arn:aws:vpc-lattice:us-east-1:12346789012:servicenetwork/sn-0db8ae434454b4422", + "serviceArn": "arn:aws:vpc-lattice:us-east-1:12346789012:service/svc-0db8ae434454b4422", + "targetGroupArn": "arn:aws:vpc-lattice:us-east-1:12346789012:targetgroup/tg-0db8ae434454b4422", + "identity": { + "sourceVpcArn": "arn:aws:ec2:us-east-1:12346789012:vpc/vpc-0db8ae434454b4422", + "type": "AWS_IAM", + "principal": "arn:aws:sts::12346789012:assumed-role/IAM_ROLE/SESSION_NAME", + "sessionName": "SESSION_NAME" + }, + "region": "us-east-1", + "timeEpoch": "1695799509392227" + } +} \ No newline at end of file diff --git a/events/vpclattice.go b/events/vpclattice.go new file mode 100644 index 00000000..b0b6c2b7 --- /dev/null +++ b/events/vpclattice.go @@ -0,0 +1,48 @@ +package events + +// VPCLatticeRequestV1 contains data coming from AWS VPC Lattice +type VPCLatticeRequestV1 struct { + RawPath string `json:"raw_path"` + Method string `json:"method"` + Headers map[string]string `json:"headers"` + QueryStringParameters map[string]string `json:"query_string_parameters"` + Body string `json:"body"` + IsBase64Encoded bool `json:"is_base64_encoded,omitempty"` +} + +// VPCLatticeRequestV2 contains data coming from AWS VPC Lattice +type VPCLatticeRequestV2 struct { + Version string `json:"version"` + Path string `json:"path"` + Method string `json:"method"` + Headers map[string][]string `json:"headers"` + Body string `json:"body"` + RequestContext VpcLatticeRequestContext `json:"requestContext"` +} + +// VpcLatticeRequestContext contains metadata about the incoming request +type VpcLatticeRequestContext struct { + ServiceNetworkArn string `json:"serviceNetworkArn"` + ServiceArn string `json:"serviceArn"` + TargetGroupArn string `json:"targetGroupArn"` + Identity *VpcLatticeRequestIdentity `json:"identity,omitempty"` + Region string `json:"region"` + TimeEpoch string `json:"timeEpoch"` +} + +// VpcLatticeRequestIdentity contains information about the caller +type VpcLatticeRequestIdentity struct { + SourceVpcArn string `json:"sourceVpcArn"` + Type string `json:"type"` + Principal string `json:"principal"` + SessionName string `json:"sessionName"` +} + +// VPCLatticeResponse contains the response to be returned to VPC Lattice +type VPCLatticeResponse struct { + IsBase64Encoded bool `json:"isBase64Encoded,omitempty"` + StatusCode int `json:"statusCode"` + StatusDescription string `json:"statusDescription,omitempty"` + Headers map[string]string `json:"headers"` + Body string `json:"body"` +} diff --git a/events/vpclattice_test.go b/events/vpclattice_test.go new file mode 100644 index 00000000..bc4e201d --- /dev/null +++ b/events/vpclattice_test.go @@ -0,0 +1,86 @@ +package events + +import ( + "encoding/json" + "io/ioutil" + "testing" + + "github.com/aws/aws-lambda-go/events/test" + "github.com/stretchr/testify/assert" +) + +func TestVPCLatticeRequestV1Marshalling(t *testing.T) { + + // read json from file + inputJSON, err := ioutil.ReadFile("./testdata/vpclattice-v1-request.json") + if err != nil { + t.Errorf("could not open test file. details: %v", err) + } + + // de-serialize into Go object + var inputEvent VPCLatticeRequestV1 + if err := json.Unmarshal(inputJSON, &inputEvent); err != nil { + t.Errorf("could not unmarshal event. details: %v", err) + } + + // serialize to json + outputJSON, err := json.Marshal(inputEvent) + if err != nil { + t.Errorf("could not marshal event. details: %v", err) + } + + assert.JSONEq(t, string(inputJSON), string(outputJSON)) +} + +func TestVPCLatticeRequestV1MalformedJson(t *testing.T) { + test.TestMalformedJson(t, VPCLatticeRequestV1{}) +} + +func TestVPCLatticeRequestV2Marshalling(t *testing.T) { + + // read json from file + inputJSON, err := ioutil.ReadFile("./testdata/vpclattice-v2-request.json") + if err != nil { + t.Errorf("could not open test file. details: %v", err) + } + + // de-serialize into Go object + var inputEvent VPCLatticeRequestV2 + if err := json.Unmarshal(inputJSON, &inputEvent); err != nil { + t.Errorf("could not unmarshal event. details: %v", err) + } + + // serialize to json + outputJSON, err := json.Marshal(inputEvent) + if err != nil { + t.Errorf("could not marshal event. details: %v", err) + } + + assert.JSONEq(t, string(inputJSON), string(outputJSON)) +} + +func TestVPCLatticeRequestV2MalformedJson(t *testing.T) { + test.TestMalformedJson(t, VPCLatticeRequestV2{}) +} + +func TestVPCLatticeResponse(t *testing.T) { + // read json from file + inputJSON, err := ioutil.ReadFile("./testdata/vpclattice-response.json") + if err != nil { + t.Errorf("could not open test file. details: %v", err) + } + + // de-serialize into Go object + var inputEvent VPCLatticeResponse + if err := json.Unmarshal(inputJSON, &inputEvent); err != nil { + t.Errorf("could not unmarshal event. details: %v", err) + } + + // serialize to json + outputJSON, err := json.Marshal(inputEvent) + if err != nil { + t.Errorf("could not marshal event. details: %v", err) + } + + assert.JSONEq(t, string(inputJSON), string(outputJSON)) +}