Skip to content

Commit

Permalink
adding validation around binary types (#235)
Browse files Browse the repository at this point in the history
* adding validation around binary types

---------

Signed-off-by: Jordan Rash <[email protected]>
  • Loading branch information
jordan-rash authored May 22, 2024
1 parent 3d24832 commit 467469a
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 18 deletions.
57 changes: 57 additions & 0 deletions nex/bin_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import (
"fmt"
"os"
"slices"
)

func validateBinary(inFile string) (string, string, error) {
f, err := os.Open(inFile)
if err != nil {
return "", "", err
}

buf := make([]byte, 150)
_, err = f.Read(buf)
if err != nil {
return "", "", err
}

err = f.Close()
if err != nil {
return "", "", err
}

switch {
case slices.Equal(buf[:4], []byte{0x7f, 0x45, 0x4c, 0x46}):
switch {
case slices.Equal(buf[17:19], []byte{0x00, 0x3e}):
return "linux", "amd64", nil
case slices.Equal(buf[17:19], []byte{0x00, 0xb7}):
return "linux", "arm64", nil
default:
return "", "", fmt.Errorf("unsupported elf file type")
}
case slices.Equal(buf[:2], []byte{0x4d, 0x5a}):
switch {
case slices.Equal(buf[132:134], []byte{0x64, 0x86}):
return "windows", "amd64", nil
case slices.Equal(buf[132:134], []byte{0x64, 0xaa}):
return "windows", "arm64", nil
default:
return "", "", fmt.Errorf("unsupported windows file type")
}
case slices.Equal(buf[:4], []byte{0xcf, 0xfa, 0xed, 0xfe}):
switch {
case slices.Equal(buf[4:5], []byte{0x07}):
return "darwin", "amd64", nil
case slices.Equal(buf[4:5], []byte{0x0c}):
return "darwin", "arm64", nil
default:
return "", "", fmt.Errorf("unsupported darwin file type")
}
default:
return "", "", fmt.Errorf("unsupported binary file type")
}
}
34 changes: 16 additions & 18 deletions nex/devrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ func init() {
// Attempts to "deploy a file" by finding a suitable target and publishing the workload to an ad-hoc created bucket
// and using default issuer and publisher keys stored in ~/.nex. This should be as easy as typing "nex devrun ./amazingapp env1=foo env2=bar"
func RunDevWorkload(ctx context.Context, logger *slog.Logger) error {
if RunOpts.WorkloadType == "elf" || RunOpts.WorkloadType == "native" {
os, arch, err := validateBinary(DevRunOpts.Filename)
if err != nil {
logger.Error("failed to validate binary", slog.Any("err", err))
}
logger.Debug("Binary validation complete", slog.String("os", os), slog.String("arch", arch))
}

nc, err := models.GenerateConnectionFromOpts(Opts, logger)
if err != nil {
return err
Expand Down Expand Up @@ -77,12 +85,12 @@ func RunDevWorkload(ctx context.Context, logger *slog.Logger) error {
}

targetPublicXkey := info.PublicXKey
workloadUrl, workloadName, workloadType, err := uploadWorkload(nc, *DevRunOpts)
workloadUrl, workloadName, err := uploadWorkload(nc, *DevRunOpts)
if err != nil {
return err
}

if workloadType == "v8" && len(RunOpts.TriggerSubjects) == 0 {
if RunOpts.WorkloadType == "v8" && len(RunOpts.TriggerSubjects) == 0 {
return errors.New("cannot start a function-type workload without specifying at least one trigger subject")
}

Expand Down Expand Up @@ -117,7 +125,7 @@ func RunDevWorkload(ctx context.Context, logger *slog.Logger) error {
controlapi.TargetPublicXKey(targetPublicXkey),
controlapi.TriggerSubjects(RunOpts.TriggerSubjects),
controlapi.WorkloadName(workloadName),
controlapi.WorkloadType(workloadType),
controlapi.WorkloadType(RunOpts.WorkloadType),
controlapi.Checksum("abc12345TODOmakethisreal"),
controlapi.WorkloadDescription("Workload published in devmode"),
)
Expand Down Expand Up @@ -156,7 +164,7 @@ func listNodes(nodeClient *controlapi.Client) ([]controlapi.PingResponse, error)
return candidates, nil
}

func uploadWorkload(nc *nats.Conn, devOpts models.DevRunOptions) (string, string, string, error) {
func uploadWorkload(nc *nats.Conn, devOpts models.DevRunOptions) (string, string, error) {
js, err := nc.JetStream()
if err != nil {
panic(err)
Expand All @@ -174,32 +182,22 @@ func uploadWorkload(nc *nats.Conn, devOpts models.DevRunOptions) (string, string
MaxBytes: int64(maxBytes),
})
if err != nil {
return "", "", "", err
return "", "", err
}
}
bytes, err := os.ReadFile(devOpts.Filename)
if err != nil {
return "", "", "", err
return "", "", err
}
key := filepath.Base(devOpts.Filename)
key = strings.ReplaceAll(key, ".", "")

_, err = bucket.PutBytes(key, bytes)
if err != nil {
return "", "", "", err
}

var workloadType string
switch strings.Replace(filepath.Ext(devOpts.Filename), ".", "", 1) {
case fileExtensionJS:
workloadType = agentapi.NexExecutionProviderV8
case fileExtensionWasm:
workloadType = agentapi.NexExecutionProviderWasm
default:
workloadType = defaultWorkloadType
return "", "", err
}

return fmt.Sprintf("nats://%s/%s", objectStoreName, key), key, workloadType, nil
return fmt.Sprintf("nats://%s/%s", objectStoreName, key), key, nil
}

func readOrGenerateIssuer() (nkeys.KeyPair, error) {
Expand Down
1 change: 1 addition & 0 deletions nex/nex.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ func init() {
yeet.Flag("trigger_subject", "Trigger subjects to register for subsequent workload execution, if supported by the workload type").StringsVar(&RunOpts.TriggerSubjects)
yeet.Flag("stop", "Indicates whether to stop pre-existing workloads during launch. Disable with caution").Default("true").BoolVar(&DevRunOpts.AutoStop)
yeet.Flag("bucketmaxbytes", "Overrides the default max bytes if the dev object store bucket is created").UintVar(&DevRunOpts.DevBucketMaxBytes)
yeet.Flag("type", "Type of workload").Default("elf").EnumVar(&RunOpts.WorkloadType, "elf", "v8", "wasm")

stop.Arg("id", "Public key of the target node on which to stop the workload").Required().StringVar(&StopOpts.TargetNode)
stop.Arg("workload_id", "Unique ID of the workload to be stopped").Required().StringVar(&StopOpts.WorkloadId)
Expand Down

0 comments on commit 467469a

Please sign in to comment.