Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding validation around binary types #235

Merged
merged 3 commits into from
May 22, 2024
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
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
Loading