support policies, closes #12
This commit is contained in:
parent
37093adeab
commit
7e44d75f68
|
@ -0,0 +1,18 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"within.website/olin/policy"
|
||||
)
|
||||
|
||||
func ValidatePolicy(pol policy.Policy) error {
|
||||
var err error
|
||||
|
||||
if pol.RamPageLimit > 2048 {
|
||||
err = multierror.Append(err, fmt.Errorf("ram page limit is %d, which is over the limit of 2048", pol.RamPageLimit))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
|
@ -3,12 +3,13 @@ package internal
|
|||
import "github.com/rogpeppe/go-internal/txtar"
|
||||
|
||||
// Topic name for wasmcloud -> executor communication
|
||||
const TopicName = "wasmcloud-to-executor-09d7e475-71ac-4bdd-be37-050af7a81c58"
|
||||
const TopicName = "exec"
|
||||
|
||||
type ExecRequest struct {
|
||||
WASMCID string `json:"wasmcid"`
|
||||
Name string `json:"name"`
|
||||
Data []byte `json:"data"`
|
||||
Policy []byte `json:"policy"`
|
||||
ABI ABI `json:"abi"`
|
||||
Env map[string]string `json:"env"`
|
||||
UUID string `json:"uuid"`
|
||||
|
|
|
@ -9,5 +9,6 @@ const (
|
|||
|
||||
type Handler struct {
|
||||
WASM []byte `json:"wasm"`
|
||||
Policy []byte `json:"policy"`
|
||||
ABI string `json:"abi"`
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/rogpeppe/go-internal/txtar"
|
||||
"tulpa.dev/within/wasmcloud/cmd/internal"
|
||||
"tulpa.dev/within/wasmcloud/executor"
|
||||
"within.website/olin/policy"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -136,8 +137,17 @@ func waitForNewWASM(ctx context.Context, wg *sync.WaitGroup, sh *shell.Shell, nc
|
|||
LogSink: logBuf,
|
||||
}
|
||||
|
||||
pol, err := policy.Parse(er.Name+".policy", er.Policy)
|
||||
if err != nil {
|
||||
log.Printf("can't get policy: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
c.Policy = &pol
|
||||
|
||||
result, err := executor.Run(c)
|
||||
if err != nil {
|
||||
fmt.Fprintln(logBuf, "can't run binary:", err)
|
||||
log.Printf("can't run binary: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,11 @@ import (
|
|||
|
||||
"github.com/google/subcommands"
|
||||
"tulpa.dev/within/wasmcloud/cmd/internal"
|
||||
"within.website/olin/policy"
|
||||
)
|
||||
|
||||
type handlerCreateCmd struct {
|
||||
abi string
|
||||
abi, policyFile string
|
||||
}
|
||||
|
||||
func (handlerCreateCmd) Name() string { return "create" }
|
||||
|
@ -38,6 +39,7 @@ Flags:
|
|||
|
||||
func (h *handlerCreateCmd) SetFlags(fs *flag.FlagSet) {
|
||||
fs.StringVar(&h.abi, "abi", "cwa", "WebAssembly ABI to use for the handler")
|
||||
fs.StringVar(&h.policyFile, "policy", "", "if set, use this policy file for the handler")
|
||||
}
|
||||
|
||||
func (h handlerCreateCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||
|
@ -57,6 +59,25 @@ func (h handlerCreateCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...in
|
|||
WASM: data,
|
||||
}
|
||||
|
||||
if h.policyFile != "" {
|
||||
data, err := ioutil.ReadFile(h.policyFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
pol, err := policy.Parse(h.policyFile, data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = internal.ValidatePolicy(pol)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
hdlr.Policy = data
|
||||
}
|
||||
|
||||
bodyData, _ := json.Marshal(hdlr)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, *apiServer+"/api/handler/create", bytes.NewBuffer(bodyData))
|
||||
if err != nil {
|
||||
|
|
|
@ -15,10 +15,11 @@ import (
|
|||
|
||||
"github.com/google/subcommands"
|
||||
"tulpa.dev/within/wasmcloud/cmd/internal"
|
||||
"within.website/olin/policy"
|
||||
)
|
||||
|
||||
type handlerUpdateCmd struct {
|
||||
abi string
|
||||
abi, policyFile string
|
||||
}
|
||||
|
||||
func (handlerUpdateCmd) Name() string { return "update" }
|
||||
|
@ -36,6 +37,7 @@ Flags:
|
|||
|
||||
func (h *handlerUpdateCmd) SetFlags(fs *flag.FlagSet) {
|
||||
fs.StringVar(&h.abi, "abi", "cwa", "WebAssembly ABI to use for the handler")
|
||||
fs.StringVar(&h.policyFile, "policy", "", "if set, use this policy file for the handler")
|
||||
}
|
||||
|
||||
func (h handlerUpdateCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||
|
@ -56,6 +58,25 @@ func (h handlerUpdateCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...in
|
|||
WASM: data,
|
||||
}
|
||||
|
||||
if h.policyFile != "" {
|
||||
data, err := ioutil.ReadFile(h.policyFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
pol, err := policy.Parse(h.policyFile, data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = internal.ValidatePolicy(pol)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
hdlr.Policy = data
|
||||
}
|
||||
|
||||
bodyData, _ := json.Marshal(hdlr)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, *apiServer+"/api/handler/update?name="+hname, bytes.NewBuffer(bodyData))
|
||||
if err != nil {
|
||||
|
|
|
@ -17,12 +17,12 @@ import (
|
|||
"github.com/perlin-network/life/exec"
|
||||
"github.com/rogpeppe/go-internal/txtar"
|
||||
"tulpa.dev/within/wasmcloud/executor"
|
||||
"within.website/olin/policy"
|
||||
)
|
||||
|
||||
type runCmd struct {
|
||||
funcName, abi string
|
||||
gasLimit uint64
|
||||
ramLimit int
|
||||
policyFile string
|
||||
}
|
||||
|
||||
func (runCmd) Name() string { return "run" }
|
||||
|
@ -33,7 +33,6 @@ func (runCmd) Usage() string {
|
|||
return `wasmcloud run [options] <file.wasm>
|
||||
|
||||
$ wasmcloud run olinfetch.wasm
|
||||
$ wasmcloud run -abi dagger -func-name dagger_main hello_dagger.wasm
|
||||
|
||||
Run a given webassembly binary and return the output.
|
||||
|
||||
|
@ -47,8 +46,7 @@ Flags:
|
|||
func (r *runCmd) SetFlags(fs *flag.FlagSet) {
|
||||
fs.StringVar(&r.funcName, "func-name", "_start", "entrypoint function to call")
|
||||
fs.StringVar(&r.abi, "abi", "cwa", "ABI to use")
|
||||
fs.Uint64Var(&r.gasLimit, "gas-limit", 1048576, "number of wasm instructions per execution")
|
||||
fs.IntVar(&r.ramLimit, "ram-limit", 128, "number of wasm pages that can be used")
|
||||
fs.StringVar(&r.policyFile, "policy", "", "if set, the policy file to use")
|
||||
}
|
||||
|
||||
func (r runCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||
|
@ -86,9 +84,7 @@ func (r runCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{})
|
|||
var stdin bytes.Buffer
|
||||
c := executor.Config{
|
||||
VMConfig: exec.VMConfig{
|
||||
GasLimit: r.gasLimit,
|
||||
ReturnOnGasLimitExceeded: true,
|
||||
MaxMemoryPages: r.ramLimit,
|
||||
},
|
||||
|
||||
Name: filepath.Base(fname),
|
||||
|
@ -101,6 +97,22 @@ func (r runCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{})
|
|||
LogSink: logBuf,
|
||||
}
|
||||
|
||||
if r.policyFile != "" {
|
||||
data, err := ioutil.ReadFile(r.policyFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
pol, err := policy.Parse(r.policyFile, data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
c.VMConfig.MaxMemoryPages = int(pol.RamPageLimit)
|
||||
c.VMConfig.GasLimit = uint64(pol.GasLimit)
|
||||
c.Policy = &pol
|
||||
}
|
||||
|
||||
result, err := executor.Run(c)
|
||||
if err != nil {
|
||||
log.Printf("can't run binary: %v", err)
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"within.website/ln"
|
||||
"within.website/ln/opname"
|
||||
"within.website/olin/namegen"
|
||||
"within.website/olin/policy"
|
||||
)
|
||||
|
||||
func deleteHandler(w http.ResponseWriter, r *http.Request, u *User) {
|
||||
|
@ -72,6 +73,15 @@ func updateHandler(w http.ResponseWriter, r *http.Request, u *User) {
|
|||
return
|
||||
}
|
||||
|
||||
if len(uHdlr.Policy) != 0 {
|
||||
err = validatePolicy(name, uHdlr.Policy)
|
||||
if err != nil {
|
||||
ln.Error(ctx, err)
|
||||
http.Error(w, "policy validation failure", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cid, err := uploadHandler(uHdlr)
|
||||
if err != nil {
|
||||
ln.Error(ctx, err)
|
||||
|
@ -79,6 +89,7 @@ func updateHandler(w http.ResponseWriter, r *http.Request, u *User) {
|
|||
return
|
||||
}
|
||||
|
||||
hdlr.Policy = uHdlr.Policy
|
||||
hdlr.Path = cid
|
||||
if err := db.Save(&hdlr).Error; err != nil {
|
||||
ln.Error(ctx, err)
|
||||
|
@ -89,6 +100,15 @@ func updateHandler(w http.ResponseWriter, r *http.Request, u *User) {
|
|||
json.NewEncoder(w).Encode(hdlr)
|
||||
}
|
||||
|
||||
func validatePolicy(name string, data []byte) error {
|
||||
pol, err := policy.Parse(name+".policy", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return internal.ValidatePolicy(pol)
|
||||
}
|
||||
|
||||
func uploadHandler(hdlr internal.Handler) (string, error) {
|
||||
sh := shell.NewShell(*ipfsURL)
|
||||
|
||||
|
@ -135,6 +155,19 @@ func createHandler(w http.ResponseWriter, r *http.Request, u *User) {
|
|||
return
|
||||
}
|
||||
|
||||
n := namegen.Next()
|
||||
|
||||
if len(hdlr.Policy) == 0 {
|
||||
hdlr.Policy = []byte(defaultPolicy)
|
||||
}
|
||||
|
||||
err = validatePolicy(n, hdlr.Policy)
|
||||
if err != nil {
|
||||
ln.Error(ctx, err)
|
||||
http.Error(w, "policy validation failure", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
cid, err := uploadHandler(hdlr)
|
||||
if err != nil {
|
||||
ln.Error(ctx, err)
|
||||
|
@ -142,12 +175,12 @@ func createHandler(w http.ResponseWriter, r *http.Request, u *User) {
|
|||
return
|
||||
}
|
||||
|
||||
n := namegen.Next()
|
||||
h := Handler{
|
||||
Name: n,
|
||||
User: *u,
|
||||
UserID: u.ID,
|
||||
Path: cid,
|
||||
Policy: hdlr.Policy,
|
||||
}
|
||||
|
||||
if err := db.Save(&h).Error; err != nil {
|
||||
|
|
|
@ -24,6 +24,7 @@ func runHandler(ctx context.Context, hdlr Handler, timeout time.Duration, messag
|
|||
"MAGIC_CONCH": "yes",
|
||||
},
|
||||
UUID: execID,
|
||||
Policy: hdlr.Policy,
|
||||
}
|
||||
|
||||
encData, err := json.Marshal(er)
|
||||
|
|
|
@ -37,6 +37,7 @@ type Handler struct {
|
|||
gorm.Model
|
||||
Name string `gorm:"unique;not null"`
|
||||
Path string
|
||||
Policy []byte
|
||||
UserID uint `json:"-"`
|
||||
User User `json:"-"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package main
|
||||
|
||||
const defaultPolicy = `## The default policy
|
||||
|
||||
allow (
|
||||
^null://$
|
||||
^random://$
|
||||
^zero://$
|
||||
^https://xena.greedo.xeserv.us/files/hello_olin.txt$
|
||||
)
|
||||
|
||||
ram-page-limit 128
|
||||
gas-limit 1048576
|
||||
`
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/perlin-network/life/exec"
|
||||
"github.com/rogpeppe/go-internal/txtar"
|
||||
"within.website/olin/abi/cwa"
|
||||
"within.website/olin/policy"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -24,6 +25,7 @@ var (
|
|||
type Config struct {
|
||||
exec.VMConfig
|
||||
|
||||
Policy *policy.Policy
|
||||
Name string
|
||||
FuncName string
|
||||
Env map[string]string
|
||||
|
@ -77,7 +79,8 @@ func Run(c Config) (*Result, error) {
|
|||
p.Stdout = c.Stdout
|
||||
p.Stderr = c.Stderr
|
||||
p.Logger = log.New(io.MultiWriter(c.LogSink, os.Stdout), c.Name+" ", log.LstdFlags)
|
||||
p.HC.Transport = WasmcloudBrandingTransport(c.Name, p.HC.Transport)
|
||||
p.HC.Transport = WasmcloudBrandingTransport(c.Name, http.DefaultTransport)
|
||||
p.Policy = c.Policy
|
||||
|
||||
gp := &compiler.SimpleGasPolicy{GasPerInstruction: 1}
|
||||
vm, err := exec.NewVirtualMachine(c.Binary, c.VMConfig, p, gp)
|
||||
|
@ -92,9 +95,13 @@ func Run(c Config) (*Result, error) {
|
|||
|
||||
pagesBefore := len(vm.Memory) / 65536
|
||||
begin := time.Now()
|
||||
ret, err := vm.Run(main)
|
||||
ret, err := vm.RunWithGasLimit(main, int(c.Policy.GasLimit))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
vm.PrintStackTrace()
|
||||
return &Result{
|
||||
Status: -2,
|
||||
StartTime: begin,
|
||||
}, err
|
||||
}
|
||||
dur := time.Since(begin)
|
||||
|
||||
|
|
3
go.mod
3
go.mod
|
@ -11,8 +11,10 @@ require (
|
|||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/mux v1.7.3
|
||||
github.com/gosuri/uitable v0.0.4
|
||||
github.com/hashicorp/go-multierror v1.0.0
|
||||
github.com/ipfs/go-ipfs-api v0.0.2
|
||||
github.com/jinzhu/gorm v1.9.11
|
||||
github.com/kr/pretty v0.1.0
|
||||
github.com/lib/pq v1.1.1
|
||||
github.com/manifoldco/promptui v0.6.0
|
||||
github.com/mattn/go-sqlite3 v2.0.1+incompatible
|
||||
|
@ -20,6 +22,7 @@ require (
|
|||
github.com/nats-io/nats.go v1.9.1
|
||||
github.com/perlin-network/life v0.0.0-20191203030451-05c0e0f7eaea
|
||||
github.com/rogpeppe/go-internal v1.5.0
|
||||
github.com/rogpeppe/gohack v1.0.2 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392
|
||||
within.website/ln v0.7.0
|
||||
within.website/olin v0.4.1-0.20191214133128-bde4927fad6b
|
||||
|
|
6
go.sum
6
go.sum
|
@ -143,7 +143,9 @@ github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyF
|
|||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
|
@ -299,8 +301,11 @@ github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R
|
|||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rogpeppe/go-internal v1.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.5.0 h1:Usqs0/lDK/NqTkvrmKSwA/3XkZAs7ZAW/eLeQ2MVBTw=
|
||||
github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/gohack v1.0.2 h1:lYiGLFzvZC3RvzeE4GoUV3nTecDxTpVusVsQY4nAXGc=
|
||||
github.com/rogpeppe/gohack v1.0.2/go.mod h1:DE8wqaJRPvHU0fden5cSYy7ar2dTbbccPT/eeOYcbcE=
|
||||
github.com/sendgrid/rest v2.4.1+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
|
@ -434,6 +439,7 @@ gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20171010053543-63abe20a23e2/go.mo
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
|
|
Loading…
Reference in New Issue