11package polylint
22
33import (
4+ "context"
45 "crypto/sha256"
6+ "encoding/json"
57 "fmt"
68 "io"
79 "log"
@@ -13,6 +15,7 @@ import (
1315 "strings"
1416
1517 "github.com/dop251/goja"
18+ extism "github.com/extism/go-sdk"
1619 "github.com/spf13/viper"
1720 "golang.org/x/mod/semver"
1821 "gopkg.in/yaml.v2"
@@ -41,7 +44,7 @@ func extractIgnoresFromLine(line string, lineNo int, f *FileReport) error {
4144 f .Ignores = append (f .Ignores , Ignore {Scope : pathScope , SourceLineNo : lineNo , LineNo : 0 , Id : ignore })
4245 }
4346 } else {
44- fmt . Printf ("WARNING: directive for polylint not recognized on line %d %s %s\n " , lineNo , directive , ignoresStr )
47+ logz . Warnf ("WARNING: directive for polylint not recognized on line %d %s %s\n " , lineNo , directive , ignoresStr )
4548 return nil
4649 }
4750 }
@@ -98,24 +101,27 @@ func LoadConfigFile(content string) (ConfigFile, error) {
98101 var config ConfigFile
99102 err := yaml .Unmarshal ([]byte (content ), & rawConfig )
100103 if err != nil {
101- fmt . Printf ("Error unmarshalling YAML: %v" , err )
104+ logz . Errorf ("Error unmarshalling YAML: %v" , err )
102105 return ConfigFile {}, err
103106 }
104107
105108 if ! strings .HasPrefix (rawConfig .Version , "v" ) {
106- fmt . Printf ("Error: config file version must start with a 'v' but was %s\n " , rawConfig .Version )
109+ logz . Errorf ("Error: config file version must start with a 'v' but was %s\n " , rawConfig .Version )
107110 panic ("Invalid version due to semver incompatibility" )
108111 }
109112
110113 if ! semver .IsValid (rawConfig .Version ) {
111- fmt . Printf ("Error: Config version %s is newer than binary version %s\n " , rawConfig .Version , viper .GetString ("binary_version" ))
112- fmt . Println (semver .IsValid (rawConfig .Version ))
114+ logz . Errorf ("Error: Config version %s is newer than binary version %s\n " , rawConfig .Version , viper .GetString ("binary_version" ))
115+ logz . Errorln (semver .IsValid (rawConfig .Version ))
113116 panic ("Invalid version due to semver incompatibility" )
114117 }
115118
116119 // If version file is too new for binary version
117120 if semver .Compare (rawConfig .Version , viper .GetString ("binary_version" )) == 1 {
118- fmt .Printf ("Warning: config file version %s is newer than binary version %s\n " , rawConfig .Version , viper .GetString ("binary_version" ))
121+ _ = 1
122+ // TODO: determine how to handle version for version check when not set in tests
123+ // Ignore for now until we can control the output
124+ //logz.Warnf("Warning: config file version %s is newer than binary version %s\n", rawConfig.Version, viper.GetString("binary_version"))
119125 }
120126
121127 config .Version = rawConfig .Version
@@ -285,6 +291,8 @@ func BuildLineFn(f RawFn) RuleFunc {
285291 return buildLineFnBuiltin (f )
286292 case "js" :
287293 return buildJsFn (f )
294+ case "wasm" :
295+ return buildWasmFn (f )
288296 default :
289297 panic (fmt .Sprintf ("unknown type %s" , f .Type ))
290298 }
@@ -296,6 +304,8 @@ func BuildFileScopeFn(f RawFn) RuleFunc {
296304 return BuildFileFnBuiltin (f )
297305 case "js" :
298306 return BuildFileFnJs (f )
307+ case "wasm" :
308+ return buildWasmFn (f )
299309 default :
300310 panic (fmt .Sprintf ("unknown type %s" , f .Type ))
301311 }
@@ -340,6 +350,8 @@ func BuildPathScopeFn(f RawFn) RuleFunc {
340350 return BuildPathFnBuiltin (f )
341351 case "js" :
342352 return BuildPathFnJs (f )
353+ case "wasm" :
354+ return buildWasmFn (f )
343355 default :
344356 panic (fmt .Sprintf ("unknown type %s" , f .Type ))
345357 }
@@ -394,6 +406,80 @@ func buildJsFn(f RawFn) RuleFunc {
394406 return fn
395407}
396408
409+ func buildWasmFn (f RawFn ) RuleFunc {
410+ hash , err := f .GetMetadataHash ()
411+ if err != nil {
412+ logz .Warnf ("Warning: cannot find metadata hash for %s\n " , f .Body )
413+ }
414+ var content []byte
415+
416+ // TODO: handle null case of hash
417+ if hash != "" {
418+ content , err = f .GetWASMFromCache (hash )
419+ }
420+ if err != nil {
421+ if strings .HasPrefix (f .Body , "http" ) {
422+ content , err = f .GetWASMFromUrl (f .Body )
423+ } else {
424+ content , err = f .GetWASMFromPath (f .Body )
425+ }
426+ }
427+ if err != nil {
428+ panic (err )
429+ }
430+
431+ ok := f .CheckWASMHash (content , hash )
432+ if ! ok && hash != "" {
433+ logz .Errorf ("hash mismatch for %s" , f .Body )
434+ }
435+ f .WriteWASMToCache (content )
436+
437+ var location []extism.Wasm
438+ location = append (location , extism.WasmData {
439+ Data : content ,
440+ Hash : hash ,
441+ })
442+
443+ manifest := extism.Manifest {
444+ Wasm : location ,
445+ }
446+
447+ ctx := context .Background ()
448+ config := extism.PluginConfig {
449+ EnableWasi : true ,
450+ }
451+
452+ plugin , err := extism .NewPlugin (ctx , manifest , config , []extism.HostFunction {})
453+ if err != nil {
454+ logz .Errorf ("Failed to initialize plugin: %v\n " , err )
455+ os .Exit (1 )
456+ }
457+
458+ return func (path string , idx int , line string ) bool {
459+ args := RuleFuncArgs {path , idx , line }
460+ b , err := json .Marshal (& args )
461+ if err != nil {
462+ panic (err )
463+ }
464+
465+ exit , bytes , err := plugin .CallWithContext (ctx , f .Name , b )
466+ if err != nil {
467+ logz .Errorln (err )
468+ os .Exit (int (exit ))
469+ }
470+ var result RuleFuncResult
471+ json .Unmarshal (bytes , & result )
472+
473+ return result .Value
474+ }
475+ }
476+
477+ type RuleFuncArgs [3 ]interface {}
478+
479+ type RuleFuncResult struct {
480+ Value bool
481+ }
482+
397483func ProcessFile (content string , path string , cfg ConfigFile ) (FileReport , error ) {
398484 f := FileReport {
399485 Path : path ,
@@ -405,7 +491,7 @@ func ProcessFile(content string, path string, cfg ConfigFile) (FileReport, error
405491 for idx , line := range lines {
406492 err := processLine (line , idx , & f )
407493 if err != nil {
408- fmt . Printf ("ERROR: %s\n " , err )
494+ logz . Errorf ("ERROR: %s\n " , err )
409495 return FileReport {}, err
410496 }
411497 }
0 commit comments