diff --git a/TODO.md b/TODO.md index 74bab07b0..26df2a8fb 100644 --- a/TODO.md +++ b/TODO.md @@ -40,7 +40,7 @@ - use more secure crypto, can we stop using sha1 or is required for aws? - centralise random gen ids, all scattered - make runinstances nats naming be consistent with others - ec2.RunInstances -- split up utils.go, eg conversions can have their own file +- split up utils.go ### Issues to investigate diff --git a/hive/gateway/ec2.go b/hive/gateway/ec2.go index 498cc1a1b..4cf48744f 100644 --- a/hive/gateway/ec2.go +++ b/hive/gateway/ec2.go @@ -180,7 +180,7 @@ func (gw *GatewayConfig) EC2_Request(ctx *fiber.Ctx) error { action := queryArgs["Action"] handler, ok := ec2Actions[action] if !ok { - return errors.New("InvalidAction") + return errors.New(awserrors.ErrorInvalidAction) } if gw.NATSConn == nil && !ec2LocalActions[action] { diff --git a/hive/gateway/ec2/image/DescribeImages.go b/hive/gateway/ec2/image/DescribeImages.go index 6a6f0423a..28d819cf6 100644 --- a/hive/gateway/ec2/image/DescribeImages.go +++ b/hive/gateway/ec2/image/DescribeImages.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" handlers_ec2_image "github.com/mulgadc/hive/hive/handlers/ec2/image" "github.com/nats-io/nats.go" ) @@ -18,7 +19,7 @@ func ValidateDescribeImagesInput(input *ec2.DescribeImagesInput) (err error) { if input.ImageIds != nil { for _, imageId := range input.ImageIds { if imageId != nil && !strings.HasPrefix(*imageId, "ami-") { - return errors.New("InvalidAMIID.Malformed") + return errors.New(awserrors.ErrorInvalidAMIIDMalformed) } } } diff --git a/hive/gateway/ec2/image/DescribeImages_test.go b/hive/gateway/ec2/image/DescribeImages_test.go index 82ecc8303..b7f2f994d 100644 --- a/hive/gateway/ec2/image/DescribeImages_test.go +++ b/hive/gateway/ec2/image/DescribeImages_test.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" "github.com/stretchr/testify/assert" ) @@ -30,7 +31,7 @@ func TestValidateDescribeImagesInput(t *testing.T) { input: &ec2.DescribeImagesInput{ ImageIds: []*string{aws.String("invalid-id")}, }, - want: errors.New("InvalidAMIID.Malformed"), + want: errors.New(awserrors.ErrorInvalidAMIIDMalformed), }, { name: "ValidInput", diff --git a/hive/gateway/ec2/instance/RunInstances.go b/hive/gateway/ec2/instance/RunInstances.go index 47b95603e..d28c92b16 100644 --- a/hive/gateway/ec2/instance/RunInstances.go +++ b/hive/gateway/ec2/instance/RunInstances.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" handlers_ec2_instance "github.com/mulgadc/hive/hive/handlers/ec2/instance" "github.com/nats-io/nats.go" ) @@ -15,36 +16,36 @@ type RunInstancesResponse struct { func ValidateRunInstancesInput(input *ec2.RunInstancesInput) (err error) { if input == nil { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } if input.MinCount == nil { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } if *input.MinCount == 0 { - return errors.New("InvalidParameterValue") + return errors.New(awserrors.ErrorInvalidParameterValue) } if *input.MaxCount == 0 { - return errors.New("InvalidParameterValue") + return errors.New(awserrors.ErrorInvalidParameterValue) } // Additional validation from EC2 spec if *input.MinCount > *input.MaxCount { - return errors.New("InvalidParameterValue") + return errors.New(awserrors.ErrorInvalidParameterValue) } if input.ImageId == nil || *input.ImageId == "" { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } if input.InstanceType == nil || *input.InstanceType == "" { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } if !strings.HasPrefix(*input.ImageId, "ami-") { - return errors.New("InvalidAMIID.Malformed") + return errors.New(awserrors.ErrorInvalidAMIIDMalformed) } diff --git a/hive/gateway/ec2/instance/RunInstances_test.go b/hive/gateway/ec2/instance/RunInstances_test.go index 3016ed65a..d3dd5c917 100644 --- a/hive/gateway/ec2/instance/RunInstances_test.go +++ b/hive/gateway/ec2/instance/RunInstances_test.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" "github.com/stretchr/testify/assert" ) @@ -41,7 +42,7 @@ func TestParseRunInstances(t *testing.T) { SecurityGroupIds: defaults.SecurityGroupIds, SubnetId: defaults.SubnetId, }, - want: errors.New("InvalidParameterValue"), + want: errors.New(awserrors.ErrorInvalidParameterValue), }, { @@ -55,7 +56,7 @@ func TestParseRunInstances(t *testing.T) { SecurityGroupIds: defaults.SecurityGroupIds, SubnetId: defaults.SubnetId, }, - want: errors.New("InvalidParameterValue"), + want: errors.New(awserrors.ErrorInvalidParameterValue), }, { @@ -69,7 +70,7 @@ func TestParseRunInstances(t *testing.T) { SecurityGroupIds: defaults.SecurityGroupIds, SubnetId: defaults.SubnetId, }, - want: errors.New("InvalidParameterValue"), + want: errors.New(awserrors.ErrorInvalidParameterValue), }, { @@ -83,7 +84,7 @@ func TestParseRunInstances(t *testing.T) { SecurityGroupIds: defaults.SecurityGroupIds, SubnetId: defaults.SubnetId, }, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { @@ -97,7 +98,7 @@ func TestParseRunInstances(t *testing.T) { SecurityGroupIds: defaults.SecurityGroupIds, SubnetId: defaults.SubnetId, }, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { @@ -111,7 +112,7 @@ func TestParseRunInstances(t *testing.T) { SecurityGroupIds: defaults.SecurityGroupIds, SubnetId: defaults.SubnetId, }, - want: errors.New("InvalidAMIID.Malformed"), + want: errors.New(awserrors.ErrorInvalidAMIIDMalformed), }, // Successful test diff --git a/hive/gateway/ec2/key/CreateKeyPair.go b/hive/gateway/ec2/key/CreateKeyPair.go index 24e281710..e71029077 100644 --- a/hive/gateway/ec2/key/CreateKeyPair.go +++ b/hive/gateway/ec2/key/CreateKeyPair.go @@ -5,17 +5,18 @@ import ( "log/slog" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" handlers_ec2_key "github.com/mulgadc/hive/hive/handlers/ec2/key" "github.com/nats-io/nats.go" ) func ValidateCreateKeyPairInput(input *ec2.CreateKeyPairInput) (err error) { if input == nil { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } if input.KeyName == nil || *input.KeyName == "" { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } return diff --git a/hive/gateway/ec2/key/CreateKeyPair_test.go b/hive/gateway/ec2/key/CreateKeyPair_test.go index d93992859..aea99c22f 100644 --- a/hive/gateway/ec2/key/CreateKeyPair_test.go +++ b/hive/gateway/ec2/key/CreateKeyPair_test.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" ) func TestValidateCreateKeyPairInput(t *testing.T) { @@ -17,14 +18,14 @@ func TestValidateCreateKeyPairInput(t *testing.T) { { name: "NilInput", input: nil, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { name: "MissingKeyName", input: &ec2.CreateKeyPairInput{ KeyName: aws.String(""), }, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { name: "ValidInput", diff --git a/hive/gateway/ec2/key/DeleteKeyPair.go b/hive/gateway/ec2/key/DeleteKeyPair.go index b85bdb764..3f7566c17 100644 --- a/hive/gateway/ec2/key/DeleteKeyPair.go +++ b/hive/gateway/ec2/key/DeleteKeyPair.go @@ -5,18 +5,19 @@ import ( "log/slog" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" handlers_ec2_key "github.com/mulgadc/hive/hive/handlers/ec2/key" "github.com/nats-io/nats.go" ) func ValidateDeleteKeyPairInput(input *ec2.DeleteKeyPairInput) (err error) { if input == nil { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } // At least one of KeyName or KeyPairId must be provided if (input.KeyName == nil || *input.KeyName == "") && (input.KeyPairId == nil || *input.KeyPairId == "") { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } return diff --git a/hive/gateway/ec2/key/DeleteKeyPair_test.go b/hive/gateway/ec2/key/DeleteKeyPair_test.go index 9f6aef9bd..9281508d8 100644 --- a/hive/gateway/ec2/key/DeleteKeyPair_test.go +++ b/hive/gateway/ec2/key/DeleteKeyPair_test.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" ) func TestValidateDeleteKeyPairInput(t *testing.T) { @@ -17,7 +18,7 @@ func TestValidateDeleteKeyPairInput(t *testing.T) { { name: "NilInput", input: nil, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { name: "MissingBothKeyNameAndKeyPairId", @@ -25,7 +26,7 @@ func TestValidateDeleteKeyPairInput(t *testing.T) { KeyName: aws.String(""), KeyPairId: aws.String(""), }, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { name: "ValidInputWithKeyName", diff --git a/hive/gateway/ec2/key/ImportKeyPair.go b/hive/gateway/ec2/key/ImportKeyPair.go index 786fee26f..91c8cb304 100644 --- a/hive/gateway/ec2/key/ImportKeyPair.go +++ b/hive/gateway/ec2/key/ImportKeyPair.go @@ -4,21 +4,22 @@ import ( "errors" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" handlers_ec2_key "github.com/mulgadc/hive/hive/handlers/ec2/key" "github.com/nats-io/nats.go" ) func ValidateImportKeyPairInput(input *ec2.ImportKeyPairInput) (err error) { if input == nil { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } if input.KeyName == nil || *input.KeyName == "" { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } if len(input.PublicKeyMaterial) == 0 { - return errors.New("MissingParameter") + return errors.New(awserrors.ErrorMissingParameter) } return diff --git a/hive/gateway/ec2/key/ImportKeyPair_test.go b/hive/gateway/ec2/key/ImportKeyPair_test.go index fbf155ada..b172d9466 100644 --- a/hive/gateway/ec2/key/ImportKeyPair_test.go +++ b/hive/gateway/ec2/key/ImportKeyPair_test.go @@ -6,6 +6,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" "github.com/stretchr/testify/assert" ) @@ -18,21 +19,21 @@ func TestValidateImportKeyPairInput(t *testing.T) { { name: "NilInput", input: nil, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { name: "MissingKeyName", input: &ec2.ImportKeyPairInput{ PublicKeyMaterial: []byte("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ..."), }, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { name: "MissingPublicKeyMaterial", input: &ec2.ImportKeyPairInput{ KeyName: aws.String("test-key"), }, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { name: "EmptyPublicKeyMaterial", @@ -40,7 +41,7 @@ func TestValidateImportKeyPairInput(t *testing.T) { KeyName: aws.String("test-key"), PublicKeyMaterial: []byte{}, }, - want: errors.New("MissingParameter"), + want: errors.New(awserrors.ErrorMissingParameter), }, { name: "ValidInput", diff --git a/hive/gateway/ec2/volume/DescribeVolumes.go b/hive/gateway/ec2/volume/DescribeVolumes.go index 66fb44aaf..4805c4c35 100644 --- a/hive/gateway/ec2/volume/DescribeVolumes.go +++ b/hive/gateway/ec2/volume/DescribeVolumes.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" handlers_ec2_volume "github.com/mulgadc/hive/hive/handlers/ec2/volume" "github.com/nats-io/nats.go" ) @@ -19,7 +20,7 @@ func ValidateDescribeVolumesInput(input *ec2.DescribeVolumesInput) error { if input.VolumeIds != nil { for _, volumeId := range input.VolumeIds { if volumeId != nil && !strings.HasPrefix(*volumeId, "vol-") { - return errors.New("InvalidVolume.Malformed") + return errors.New(awserrors.ErrorInvalidVolumeIDMalformed) } } } diff --git a/hive/gateway/ec2/volume/DescribeVolumes_test.go b/hive/gateway/ec2/volume/DescribeVolumes_test.go index abff51610..bcf3b9c71 100644 --- a/hive/gateway/ec2/volume/DescribeVolumes_test.go +++ b/hive/gateway/ec2/volume/DescribeVolumes_test.go @@ -49,7 +49,7 @@ func TestValidateDescribeVolumesInput(t *testing.T) { VolumeIds: []*string{aws.String("invalid-id")}, }, wantErr: true, - errMsg: "InvalidVolume.Malformed", + errMsg: "InvalidVolumeID.Malformed", }, { name: "InvalidVolumeId_WrongPrefix", @@ -57,7 +57,7 @@ func TestValidateDescribeVolumesInput(t *testing.T) { VolumeIds: []*string{aws.String("ami-0123456789abcdef0")}, }, wantErr: true, - errMsg: "InvalidVolume.Malformed", + errMsg: "InvalidVolumeID.Malformed", }, { name: "InvalidVolumeId_EmptyString", @@ -65,7 +65,7 @@ func TestValidateDescribeVolumesInput(t *testing.T) { VolumeIds: []*string{aws.String("")}, }, wantErr: true, - errMsg: "InvalidVolume.Malformed", + errMsg: "InvalidVolumeID.Malformed", }, { name: "MixedValidAndInvalid", @@ -76,7 +76,7 @@ func TestValidateDescribeVolumesInput(t *testing.T) { }, }, wantErr: true, - errMsg: "InvalidVolume.Malformed", + errMsg: "InvalidVolumeID.Malformed", }, { name: "NilVolumeIdInList", diff --git a/hive/gateway/ec2/volume/ModifyVolume.go b/hive/gateway/ec2/volume/ModifyVolume.go index 518d3f5aa..6152efad0 100644 --- a/hive/gateway/ec2/volume/ModifyVolume.go +++ b/hive/gateway/ec2/volume/ModifyVolume.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/mulgadc/hive/hive/awserrors" handlers_ec2_volume "github.com/mulgadc/hive/hive/handlers/ec2/volume" "github.com/nats-io/nats.go" ) @@ -12,15 +13,15 @@ import ( // ValidateModifyVolumeInput validates the input parameters func ValidateModifyVolumeInput(input *ec2.ModifyVolumeInput) error { if input == nil { - return errors.New("InvalidParameterValue") + return errors.New(awserrors.ErrorInvalidParameterValue) } if input.VolumeId == nil || !strings.HasPrefix(*input.VolumeId, "vol-") { - return errors.New("InvalidVolumeID.Malformed") + return errors.New(awserrors.ErrorInvalidVolumeIDMalformed) } if input.Size != nil && *input.Size <= 0 { - return errors.New("InvalidParameterValue") + return errors.New(awserrors.ErrorInvalidParameterValue) } return nil diff --git a/hive/gateway/gateway.go b/hive/gateway/gateway.go index 6aa178a17..e39d89e40 100644 --- a/hive/gateway/gateway.go +++ b/hive/gateway/gateway.go @@ -143,7 +143,7 @@ func (gw *GatewayConfig) Request(ctx *fiber.Ctx) error { case "iam": err = gw.IAM_Request(ctx) default: - err = errors.New("UnsupportedOperation") + err = errors.New(awserrors.ErrorUnsupportedOperation) } if err != nil { @@ -164,7 +164,7 @@ func (gw *GatewayConfig) GetService(ctx *fiber.Ctx) (string, error) { } if !supportedServices[svc] { slog.Debug("Unsupported service", "service", svc) - return "", errors.New("UnsupportedOperation") + return "", errors.New(awserrors.ErrorUnsupportedOperation) } return svc, nil } @@ -186,7 +186,7 @@ func (gw *GatewayConfig) ErrorHandler(ctx *fiber.Ctx, err error) error { // Check if the error lookup exists if _, exists := awserrors.ErrorLookup[err.Error()]; !exists { slog.Warn("Unknown error code", "error", err.Error()) - err = errors.New("InternalError") + err = errors.New(awserrors.ErrorInternalError) } errorMsg = awserrors.ErrorLookup[err.Error()] @@ -254,7 +254,7 @@ func ParseArgsToStruct(input *any, args map[string]string) (err error) { err = awsec2query.QueryParamsToStruct(args, input) if err != nil { - return errors.New("InvalidParameter") + return errors.New(awserrors.ErrorInvalidParameter) } return nil diff --git a/hive/handlers/ec2/account/service_impl.go b/hive/handlers/ec2/account/service_impl.go index 86b50e26b..2ca479454 100644 --- a/hive/handlers/ec2/account/service_impl.go +++ b/hive/handlers/ec2/account/service_impl.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/mulgadc/hive/hive/config" + "github.com/mulgadc/hive/hive/utils" "github.com/nats-io/nats.go" ) @@ -62,7 +63,7 @@ func NewAccountSettingsServiceImplWithNATS(cfg *config.Config, natsConn *nats.Co func getOrCreateKVBucket(js nats.JetStreamContext, bucketName string, history int) (nats.KeyValue, error) { kv, err := js.CreateKeyValue(&nats.KeyValueConfig{ Bucket: bucketName, - History: uint8(history), + History: utils.SafeIntToUint8(history), }) if err != nil { kv, err = js.KeyValue(bucketName) diff --git a/hive/handlers/ec2/key/service_impl.go b/hive/handlers/ec2/key/service_impl.go index ce34cf456..0499104f1 100644 --- a/hive/handlers/ec2/key/service_impl.go +++ b/hive/handlers/ec2/key/service_impl.go @@ -101,7 +101,7 @@ func (s *KeyServiceImpl) CreateKeyPair(input *ec2.CreateKeyPairInput) (*ec2.Crea case "ed25519": keyType = "ed25519" default: - return nil, errors.New("InvalidParameterValue") + return nil, errors.New(awserrors.ErrorInvalidParameterValue) } } diff --git a/hive/utils/conversion.go b/hive/utils/conversion.go new file mode 100644 index 000000000..02f3f40e9 --- /dev/null +++ b/hive/utils/conversion.go @@ -0,0 +1,38 @@ +package utils + +import "math" + +// SafeInt64ToUint64 converts int64 to uint64, returning 0 if negative +func SafeInt64ToUint64(v int64) uint64 { + if v < 0 { + return 0 + } + return uint64(v) +} + +// SafeIntToUint8 converts int to uint8, clamping to [0, 255] +func SafeIntToUint8(v int) uint8 { + if v < 0 { + return 0 + } + if v > math.MaxUint8 { + return math.MaxUint8 + } + return uint8(v) +} + +// SafeIntToUint64 converts int to uint64, returning 0 if negative +func SafeIntToUint64(v int) uint64 { + if v < 0 { + return 0 + } + return uint64(v) +} + +// SafeUint64ToInt64 converts uint64 to int64, capping at math.MaxInt64 +func SafeUint64ToInt64(v uint64) int64 { + if v > math.MaxInt64 { + return math.MaxInt64 + } + return int64(v) +} diff --git a/hive/utils/utils.go b/hive/utils/utils.go index 57e4dd67b..b6066b301 100644 --- a/hive/utils/utils.go +++ b/hive/utils/utils.go @@ -11,7 +11,6 @@ import ( "fmt" "io" "log/slog" - "math" "net/http" "os" "os/exec" @@ -30,6 +29,7 @@ import ( "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/s3" + "github.com/mulgadc/hive/hive/awserrors" "github.com/mulgadc/hive/hive/config" "github.com/pterm/pterm" "golang.org/x/net/http2" @@ -39,41 +39,6 @@ import ( var ErrQCOWDetected = errors.New("qcow format detected") -// SafeInt64ToUint64 converts int64 to uint64, returning 0 if negative -func SafeInt64ToUint64(v int64) uint64 { - if v < 0 { - return 0 - } - return uint64(v) -} - -// SafeIntToUint8 converts int to uint8, clamping to [0, 255] -func SafeIntToUint8(v int) uint8 { - if v < 0 { - return 0 - } - if v > math.MaxUint8 { - return math.MaxUint8 - } - return uint8(v) -} - -// SafeIntToUint64 converts int to uint64, returning 0 if negative -func SafeIntToUint64(v int) uint64 { - if v < 0 { - return 0 - } - return uint64(v) -} - -// SafeUint64ToInt64 converts uint64 to int64, capping at math.MaxInt64 -func SafeUint64ToInt64(v uint64) int64 { - if v > math.MaxInt64 { - return math.MaxInt64 - } - return int64(v) -} - type Images struct { Name string `json:"name"` Description string `json:"description"` @@ -618,8 +583,7 @@ func ValidateKeyPairName(name string) error { char == '.' if !valid { - // Import needed: github.com/mulgadc/hive/hive/awserrors - return fmt.Errorf("InvalidKeyPair.Format") + return errors.New(awserrors.ErrorInvalidKeyPairFormat) } }