Skip to content

Commit

Permalink
Fixed issue with JS plugins running async.
Browse files Browse the repository at this point in the history
Also bumped version of libopenapi to take advantage of the new reduced memory use.
  • Loading branch information
daveshanley committed Oct 24, 2024
1 parent 1562583 commit 7bbf99c
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 15 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.23.0

require (
github.com/alecthomas/chroma v0.10.0
github.com/dop251/goja v0.0.0-20241009100908-5f46f2705ca3
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd
github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc
github.com/dustin/go-humanize v1.0.1
github.com/fsnotify/fsnotify v1.7.0
Expand All @@ -13,7 +13,7 @@ require (
github.com/json-iterator/go v1.1.12
github.com/mitchellh/mapstructure v1.5.0
github.com/pb33f/doctor v0.0.14
github.com/pb33f/libopenapi v0.18.4
github.com/pb33f/libopenapi v0.18.5
github.com/pb33f/libopenapi-validator v0.2.0
github.com/pterm/pterm v0.12.79
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yA
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dop251/goja v0.0.0-20241009100908-5f46f2705ca3 h1:MXsAuToxwsTn5BEEYm2DheqIiC4jWGmkEJ1uy+KFhvQ=
github.com/dop251/goja v0.0.0-20241009100908-5f46f2705ca3/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd h1:QMSNEh9uQkDjyPwu/J541GgSH+4hw+0skJDIj9HJ3mE=
github.com/dop251/goja v0.0.0-20241024094426-79f3a7efcdbd/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc h1:MKYt39yZJi0Z9xEeRmDX2L4ocE0ETKcHKw6MVL3R+co=
github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc/go.mod h1:VULptt4Q/fNzQUJlqY/GP3qHyU7ZH46mFkBZe0ZTokU=
github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
Expand Down Expand Up @@ -162,6 +164,7 @@ github.com/pb33f/doctor v0.0.14 h1:Yei7f6Ksuc9RBjN3umiCEI8zN7ti3s5aveTT3sLi8Ts=
github.com/pb33f/doctor v0.0.14/go.mod h1:1afDRJqurrftgMfRDbf1jWPoOyvdAsaK8+GHD8MiTLI=
github.com/pb33f/libopenapi v0.18.4 h1:b39Spb8CY0jzormHkB2+U/UtaKegicHHJRY7c9PlTDQ=
github.com/pb33f/libopenapi v0.18.4/go.mod h1:9ap4lXBHgxGyFwxtOfa+B1C3IQ0rvnqteqjJvJ11oiQ=
github.com/pb33f/libopenapi v0.18.5/go.mod h1:9ap4lXBHgxGyFwxtOfa+B1C3IQ0rvnqteqjJvJ11oiQ=
github.com/pb33f/libopenapi-validator v0.2.0 h1:bixMgyHXRenN60L8927GtsWM8AE/p3fGvQdn6ZkgNHM=
github.com/pb33f/libopenapi-validator v0.2.0/go.mod h1:DpluvEfTfDwfqTN2sgvTH14dPbzKDtE/vYQgcx3iNMs=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
Expand Down
40 changes: 27 additions & 13 deletions plugin/javascript/js_plugin.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
// Copyright 2023-2004 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT

package javascript
Expand All @@ -12,6 +12,7 @@ import (
"github.com/dop251/goja_nodejs/require"
"github.com/mitchellh/mapstructure"
"gopkg.in/yaml.v3"
"sync"
)

type CoreFunction func(input any, context model.RuleFunctionContext) []model.RuleFunctionResult
Expand All @@ -31,14 +32,11 @@ type JSRuleFunction struct {
scriptParsed bool
runtime *goja.Runtime
coreFunctions map[string]interface{}
l sync.Mutex
}

func NewJSRuleFunction(ruleName, script string) JSEnabledRuleFunction {
rt := goja.New()
rt.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
reg := new(require.Registry)
reg.Enable(rt)
console.Enable(rt)
rt := BuildVM()

return &JSRuleFunction{
ruleName: ruleName,
Expand Down Expand Up @@ -113,14 +111,19 @@ func (j *JSRuleFunction) CheckScript() error {

func (j *JSRuleFunction) RunRule(nodes []*yaml.Node, context model.RuleFunctionContext) []model.RuleFunctionResult {

// rule need their own runtime because these functions run async, the same runtime will become polluted.
rt := BuildVM()

var results []model.RuleFunctionResult
var runtimeErr error

for _, node := range nodes {

var enc interface{}
_ = node.Decode(&enc)

runtimeErr := j.runtime.Set("context", context)
j.l.Lock()
runtimeErr = rt.Set("context", context) // prevent any run time issues.
j.l.Unlock()
if runtimeErr != nil {
return []model.RuleFunctionResult{
{
Expand All @@ -134,9 +137,11 @@ func (j *JSRuleFunction) RunRule(nodes []*yaml.Node, context model.RuleFunctionC
}
}

_, runtimeErr = rt.RunString(j.script)

// register core functions
for name, function := range j.coreFunctions {
coreErr := j.runtime.Set(fmt.Sprintf("vacuum_%s", name), function)
coreErr := rt.Set(fmt.Sprintf("vacuum_%s", name), function)
if coreErr != nil {
return []model.RuleFunctionResult{
{
Expand All @@ -151,12 +156,12 @@ func (j *JSRuleFunction) RunRule(nodes []*yaml.Node, context model.RuleFunctionC
}
}

runRule, ok := goja.AssertFunction(j.runtime.Get("runRule"))
runRule, ok := goja.AssertFunction(rt.Get("runRule"))
if !ok {
return []model.RuleFunctionResult{
{
Message: fmt.Sprintf("'runRule' is not defined as a JavaScript function: '%s': %s ",
j.ruleName, runtimeErr.Error()),
Message: fmt.Sprintf("'runRule' is not defined as a JavaScript function: '%s'",
j.ruleName),
StartNode: node,
EndNode: node,
Path: fmt.Sprint(context.Given),
Expand All @@ -167,7 +172,7 @@ func (j *JSRuleFunction) RunRule(nodes []*yaml.Node, context model.RuleFunctionC
var functionResults []model.RuleFunctionResult

// run JS rule!
runtimeValue := j.runtime.ToValue(enc)
runtimeValue := rt.ToValue(enc)
ruleOutput, rErr := runRule(goja.Undefined(), runtimeValue)
if rErr != nil {
if jserr, okE := rErr.(*goja.Exception); okE {
Expand Down Expand Up @@ -219,3 +224,12 @@ func (j *JSRuleFunction) RunRule(nodes []*yaml.Node, context model.RuleFunctionC
}
return results
}

func BuildVM() *goja.Runtime {
rt := goja.New()
rt.SetFieldNameMapper(goja.TagFieldNameMapper("json", true))
reg := new(require.Registry)
reg.Enable(rt)
console.Enable(rt)
return rt
}

0 comments on commit 7bbf99c

Please sign in to comment.