diff --git a/.gitattributes b/.gitattributes index 6313b56..facfa5b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ * text=auto eol=lf +*.pt linguist-language=Ruby diff --git a/.gitignore b/.gitignore index a246e47..cc56deb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .idea/ .vscode/ +out.json vendor/ version.go version.yml diff --git a/cmd/fpt/ChangeLog.md b/cmd/fpt/ChangeLog.md index a4d0947..424e13d 100644 --- a/cmd/fpt/ChangeLog.md +++ b/cmd/fpt/ChangeLog.md @@ -1,3 +1,10 @@ +v1.1.3 / 2020-06-26 +------------------- +* Fix an incorrect use of `fmt.Printf` without a format to use `fmt.Print` instead +* Handle the `'EOS'` and `"EOS"` forms of [HEREDOC](https://ruby-doc.org/core-2.2.7/doc/syntax/literals_rdoc.html#label-Here+Documents)s when detecting JavaScript `code` blocks in the `fpt script` subcommand +* Actually check if `--result`/`-r` is being passed when executing raw JavaScript with the `fpt script` subcommand +* Handle Policy Template (Ruby) comments correctly when parsing for the `fpt script` subcommand + v1.1.2 / 2020-05-21 ------------------- * Actually check for any updates if `update.check` is set to `true` diff --git a/cmd/fpt/fixtures/get_script1.pt b/cmd/fpt/fixtures/get_script1.pt index 56197aa..6767905 100644 --- a/cmd/fpt/fixtures/get_script1.pt +++ b/cmd/fpt/fixtures/get_script1.pt @@ -58,6 +58,24 @@ RESVAR=otra[0] EOF end +script 'single_quote_heredoc', type: 'javascript' do # there can be a comment here, + result 'output' # here, + parameters 'a', 'b' # here, + code <<-'eos' # here, + var output = 'Single quote HEREDOCs\nare awesome!'; + + console.log(a, b, output); + eos +end # and here + +script 'double_quote_heredoc', type: 'javascript' do + result 'output' + code <<"eos" +var output = 'Double quote HEREDOCs\\nare not that remarkable.'; + +console.log(output); +eos +end policy "filter_check" do validate $filtered_dcs do diff --git a/cmd/fpt/run.go b/cmd/fpt/run.go index 044fbf2..3ef03a6 100644 --- a/cmd/fpt/run.go +++ b/cmd/fpt/run.go @@ -106,7 +106,7 @@ func policyTemplateRun(ctx context.Context, cli policy.Client, file string, runO lastEtag = *log.Etag lastLog = *log.ResponseBody if !noLog { - fmt.Printf(lastLog[lastSize:]) + fmt.Print(lastLog[lastSize:]) } //fmt.Printf("STATUS: %s\n", dump(status)) diff --git a/cmd/fpt/script.go b/cmd/fpt/script.go index c94e0fb..8e6bc5a 100644 --- a/cmd/fpt/script.go +++ b/cmd/fpt/script.go @@ -6,6 +6,7 @@ import ( "fmt" "io/ioutil" "os" + "path/filepath" "regexp" "strconv" "strings" @@ -24,6 +25,11 @@ var ( maxExecTime = 600 * time.Second errHalt = fmt.Errorf("HALT") debuglogDataSize = 10 * 1024 + q = regexp.MustCompile(`\\(.)`) + qw = regexp.MustCompile(`"(.*?[^\\])"|'(.*?[^\\])'`) + scriptStartRe = regexp.MustCompile(`^\s*script\s+['"]([^'"]+)['"],.*do\s*(?:#.*)?$`) + scriptEndRe = regexp.MustCompile(`^\s*end\s*(?:#.*)?$`) + codeStartRe = regexp.MustCompile(`^\s*code\s+('.*|".*|<<-?(?:[A-Za-z_]+|'[A-Za-z_]+'|"[A-Za-z_]+")\s*(?:#.*)?)$`) ) type script struct { @@ -108,6 +114,10 @@ func runScript(ctx context.Context, file, outfile, result, name string, options strings.Join(names, " or ")) } } + } else if result == "" { + return fmt.Errorf("no result variable specified for raw JavaScript, pass --result with the name of the variable to extract") + } else { + name = strings.TrimSuffix(filepath.Base(file), filepath.Ext(file)) } fmt.Printf("Running script %q from %s and writing %s to %s\n", name, file, result, outfile) @@ -355,10 +365,7 @@ func getScripts(src string) []*script { lines := strings.Split(src, "\n") inScript := false inCode := false - qw := regexp.MustCompile(`"(.*?[^\\])"|'(.*?[^\\])'`) - scriptStartRe := regexp.MustCompile(`^\s*script ['"]([^'"]+)['"],.*do\s*$`) - scriptEndRe := regexp.MustCompile(`^\s*end\s*$`) - codeStartRe := regexp.MustCompile(`^\s*code ('.*|".*|<<-?[A-Z_]+\s*)$`) + unescapeCode := true var codeEndRe *regexp.Regexp var codeLine int @@ -395,9 +402,9 @@ func getScripts(src string) []*script { } scripts = append(scripts, &script{ name: name, - code: unquote(strings.Join(codeLines, "\n")), + code: unquote(strings.Join(codeLines, "\n"), unescapeCode), line: codeLine, - result: unquote(result), + result: unquote(result, true), params: params, }) } else if matches := codeStartRe.FindStringSubmatch(line); len(matches) > 0 { @@ -411,7 +418,9 @@ func getScripts(src string) []*script { codeEndRe = regexp.MustCompile(`^(.*?[^\\]")`) codeLines = append(codeLines, matches[1]) } else { - end := strings.TrimPrefix(strings.TrimPrefix(matches[1], "<<"), "-") + identifier := strings.TrimSpace(strings.SplitN(strings.TrimPrefix(strings.TrimPrefix(matches[1], "<<"), "-"), "#", 2)[0]) + unescapeCode = identifier[:1] != "'" + end := strings.Trim(identifier, `'"`) codeEndRe = regexp.MustCompile(`^\s*` + end) codeLine++ } @@ -431,23 +440,24 @@ func getScripts(src string) []*script { } func getKey(lines []string, key string) string { - keyRe := regexp.MustCompile(fmt.Sprintf(`\s*%s\s+(.*)\s*$`, key)) + keyRe := regexp.MustCompile(fmt.Sprintf(`\s*%s\s+([^#]*)(?:#.*)?$`, key)) for _, line := range lines { if matches := keyRe.FindStringSubmatch(line); len(matches) > 0 { - return matches[1] + return strings.TrimSpace(matches[1]) } } return "" } -func unquote(s string) string { - q := regexp.MustCompile(`\\(.)`) +func unquote(s string, unescape bool) string { if strings.HasPrefix(s, "'") { s = s[1 : len(s)-1] } else if strings.HasPrefix(s, `"`) { s = s[1 : len(s)-1] } - s = q.ReplaceAllString(s, "$1") + if unescape { + s = q.ReplaceAllString(s, "$1") + } return s } diff --git a/cmd/fpt/script_test.go b/cmd/fpt/script_test.go index 05431c8..d168e5d 100644 --- a/cmd/fpt/script_test.go +++ b/cmd/fpt/script_test.go @@ -55,6 +55,20 @@ func TestGetScripts(t *testing.T) { params: []string{"otra"}, result: "RESVAR", }, + { + name: "single_quote_heredoc", + code: " var output = 'Single quote HEREDOCs\\nare awesome!';\n\n console.log(a, b, output);", + line: 65, + params: []string{"a", "b"}, + result: "output", + }, + { + name: "double_quote_heredoc", + code: "var output = 'Double quote HEREDOCs\\nare not that remarkable.';\n\nconsole.log(output);", + line: 74, + params: []string{}, + result: "output", + }, }, }, }