Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

chore: add lambda platform config validation - add tests #3193

Merged
merged 4 commits into from
Apr 13, 2022
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
3 changes: 3 additions & 0 deletions .changelog/3193.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
plugin/aws-lambda: Add platform config validation.
```
41 changes: 38 additions & 3 deletions builtin/aws/lambda/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/aws/aws-sdk-go/service/elbv2"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/lambda"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/waypoint/builtin/aws/ecr"
"github.com/hashicorp/waypoint/builtin/aws/utils"
Expand All @@ -38,10 +39,44 @@ type Platform struct {
// ConfigSet is called after a configuration has been decoded
// we can use this to validate the config
func (p *Platform) ConfigSet(config interface{}) error {
_, ok := config.(*Config)
c, ok := config.(*Config)
if !ok {
// this should never happen
return fmt.Errorf("Invalid configuration, expected *lambda.Config, got %s", reflect.TypeOf(config))
return fmt.Errorf("Invalid configuration, expected *lambda.Config, got %q", reflect.TypeOf(config))
}

// validate architecture
if c.Architecture != "" {
architectures := make([]interface{}, len(lambda.Architecture_Values()))

for i, ca := range lambda.Architecture_Values() {
architectures[i] = ca
}

var validArchitectures []string
for _, arch := range lambda.Architecture_Values() {
validArchitectures = append(validArchitectures, fmt.Sprintf("%q", arch))
}

if err := utils.Error(validation.ValidateStruct(c,
validation.Field(&c.Architecture,
validation.In(architectures...).Error(fmt.Sprintf("Unsupported function architecture %q. Must be one of [%s], or left blank", c.Architecture, strings.Join(validArchitectures, ", "))),
),
)); err != nil {
return err
}
}

// validate timeout - max is 900 (15 minutes)
if c.Timeout != 0 {
if err := utils.Error(validation.ValidateStruct(c,
validation.Field(&c.Timeout,
validation.Min(0).Error("Timeout must not be negative"),
validation.Max(900).Error("Timeout must be less than or equal to 15 minutes"),
),
)); err != nil {
return err
}
}

return nil
Expand Down Expand Up @@ -822,7 +857,7 @@ type Config struct {
Memory int `hcl:"memory,optional"`

// The number of seconds to wait for a function to complete it's work.
// Defaults to 256
// Defaults to 60
Timeout int `hcl:"timeout,optional"`

// The instruction set architecture that the function supports.
Expand Down
63 changes: 32 additions & 31 deletions builtin/aws/lambda/platform_test.go
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
package lambda

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"
)

// Just to validate that the key armoring works properly
func TestKeys(t *testing.T) {
hostkey, err := rsa.GenerateKey(rand.Reader, 4096)
require.NoError(t, err)

hoststr := base64.StdEncoding.EncodeToString(x509.MarshalPKCS1PrivateKey(hostkey))

hostbytes, err := base64.StdEncoding.DecodeString(hoststr)
require.NoError(t, err)

hkey, err := x509.ParsePKCS1PrivateKey(hostbytes)
require.NoError(t, err)

assert.True(t, hostkey.Equal(hkey))

userstr := base64.StdEncoding.EncodeToString(x509.MarshalPKCS1PublicKey(&hostkey.PublicKey))

userbytes, err := base64.StdEncoding.DecodeString(userstr)
require.NoError(t, err)

userKey, err := x509.ParsePKCS1PublicKey(userbytes)
require.NoError(t, err)

_, err = ssh.NewPublicKey(userKey)
require.NoError(t, err)
func TestPlatformConfig(t *testing.T) {
t.Run("empty is fine", func(t *testing.T) {
var p Platform
cfg := &Config{}
require.NoError(t, p.ConfigSet(cfg))
})

t.Run("disallows unsupported architecture", func(t *testing.T) {
var p Platform
cfg := &Config{
Architecture: "foobar",
}

require.EqualError(t, p.ConfigSet(cfg), "rpc error: code = InvalidArgument desc = Architecture: Unsupported function architecture \"foobar\". Must be one of [\"x86_64\", \"arm64\"], or left blank.")
})

t.Run("disallows invalid timeout", func(t *testing.T) {
var p Platform
{
cfg := &Config{
Timeout: 901,
}
require.EqualError(t, p.ConfigSet(cfg), "rpc error: code = InvalidArgument desc = Timeout: Timeout must be less than or equal to 15 minutes.")
}

{
cfg := &Config{
Timeout: -1,
}
require.EqualError(t, p.ConfigSet(cfg), "rpc error: code = InvalidArgument desc = Timeout: Timeout must not be negative.")
}
})
}