-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
144 lines (116 loc) · 3.3 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package main
import (
"flag"
"fmt"
"log"
"os"
"strings"
color "github.com/TwiN/go-color"
)
func main() {
const unsafeKeyword = "not safe"
const notSecure = "not secure"
version := "0.2.0"
ver := flag.Bool("version", false, "print version and exit")
porcelain := flag.Bool("porcelain", false, "do not do the plumbing after the analysis")
porcelainShort := flag.Bool("p", false, "do not do the plumbing after the analysis (shorthand)")
flag.Parse()
isPorcelain := *porcelain || *porcelainShort
if *ver {
fmt.Println(version)
os.Exit(0)
}
client, ctx, err := initOpenAI()
if err != nil {
log.Fatalf("Error: %v", err)
}
// NOTE: All logs go to STDERR so we can output the original script to STDOUT
errLog := log.New(os.Stderr, "", log.Lmsgprefix)
printWarning(errLog)
isPipe, err := isInputFromPipe()
if err != nil {
log.Fatalf("Error: %v", err)
}
if !isPipe {
errLog.Fatal("Error: Expected input from pipe, but none was detected!")
}
script, err := readFromPipe()
if err != nil {
log.Fatalf("Error: %v", err)
}
if len(script) == 0 {
log.Fatalf("Error: the script appears to be empty!")
}
chunks, err := sliceTextIntoChunks(script)
if err != nil {
log.Fatalf("Error: %v", err)
}
output := ""
securityAudit := ""
for i, chunk := range chunks {
listPrompt := makeListPrompt(chunk)
securityPrompt := makeSecurityPrompt(chunk)
// Ask GPT-3 to make a list of bullet pints about chunk actions
resp, err := requestCompletion(client, ctx, listPrompt)
if err != nil {
errLog.Fatalf("Failed to request completion: %v", err)
}
output += "\n" + resp
// Ask GPT-3 to make a security audit of a chunk
resp, err = requestCompletion(client, ctx, securityPrompt)
if err != nil {
errLog.Fatalf("Failed to request completion: %v", err)
}
securityAudit += resp + "\n"
// If it's the last chunk, then ask GPT-3 to make a summary
if i == len(chunks)-1 {
output = removeEmptyLines(output)
output = fixBulletPoints(output)
conclusionPrompt := makeConclusionPrompt(output, securityAudit)
resp, err = requestCompletion(client, ctx, conclusionPrompt)
if err != nil {
errLog.Fatalf("Failed to request completion: %v", err)
}
if len(resp) == 0 {
continue
}
resp = removeAnswerPrefix(resp)
if strings.Contains(resp, unsafeKeyword) || strings.Contains(resp, notSecure) {
resp = color.InRed(resp)
} else {
resp = color.InGreen(resp)
}
output += "\n\n" + strings.TrimSpace(resp)
}
}
// Print the actions list
errLog.Println(output)
// If no plumbing is needed, then exit
if isPorcelain {
return
}
// Ask the user if they want to pipe the original script to the next command
confirm, err := askForConfirmation(errLog, "Do you want to redirect this script to STDOUT then? [y/N]: ")
if err != nil {
errLog.Printf("Failed to get confirmation: %v", err)
return
}
if confirm {
errLog.Println(
color.InBold(
color.InYellowOverBlack("WARNING: If you redirect it to sh/bash it will execute the script on your machine!"),
),
)
confirmAgain, err := askForConfirmation(
errLog,
"Are you ABSOLUTELY positive that you want to pipe this script to the next command!? [y/N]: ",
)
if err != nil {
errLog.Printf("Failed to get confirmation: %v", err)
return
}
if confirmAgain {
fmt.Println(script)
}
}
}