@@ -2,8 +2,246 @@ package check_template
2
2
3
3
import (
4
4
"context"
5
+ "database/sql"
6
+ "fmt"
7
+ "regexp"
8
+ "strings"
5
9
)
6
10
11
+ type optionsStruct struct {
12
+ // Database is the name of the database to connect to
13
+ Database string `compscore:"database"`
14
+
15
+ // Table is the name of the table to check
16
+ Table string `compscore:"table"`
17
+
18
+ // Field is the name of the field to check
19
+ Field string `compscore:"field"`
20
+
21
+ // Check if a database connection can be made
22
+ Connect bool `compscore:"connect"`
23
+
24
+ // Check if a table exists
25
+ TableExists bool `compscore:"table_exists"`
26
+
27
+ // Check if any row exists in table
28
+ RowExists bool `compscore:"row_exists"`
29
+
30
+ // Check if a field of row matches regex in
31
+ RegexMatch bool `compscore:"regex_match"`
32
+
33
+ // Check if a field of row matches substring
34
+ SubstringMatch bool `compscore:"substring_match"`
35
+
36
+ // Check if a field of row matches exact string
37
+ Match bool `compscore:"match"`
38
+ }
39
+
40
+ func (o * optionsStruct ) Unmarshal (options map [string ]interface {}) {
41
+ databaseInterface , ok := options ["database" ]
42
+ if ok {
43
+ database , ok := databaseInterface .(string )
44
+ if ok {
45
+ o .Database = database
46
+ }
47
+ }
48
+
49
+ tableInterface , ok := options ["table" ]
50
+ if ok {
51
+ table , ok := tableInterface .(string )
52
+ if ok {
53
+ o .Table = table
54
+ }
55
+ }
56
+
57
+ fieldInterface , ok := options ["field" ]
58
+ if ok {
59
+ field , ok := fieldInterface .(string )
60
+ if ok {
61
+ o .Field = field
62
+ }
63
+ }
64
+
65
+ connectInterface , ok := options ["connect" ]
66
+ if ok {
67
+ connect , ok := connectInterface .(bool )
68
+ if ok {
69
+ o .Connect = connect
70
+ }
71
+ }
72
+
73
+ tableExistsInterface , ok := options ["table_exists" ]
74
+ if ok {
75
+ tableExists , ok := tableExistsInterface .(bool )
76
+ if ok {
77
+ o .TableExists = tableExists
78
+ }
79
+ }
80
+
81
+ rowExistsInterface , ok := options ["row_exists" ]
82
+ if ok {
83
+ rowExists , ok := rowExistsInterface .(bool )
84
+ if ok {
85
+ o .RowExists = rowExists
86
+ }
87
+ }
88
+
89
+ regexMatchInterface , ok := options ["regex_match" ]
90
+ if ok {
91
+ regexMatch , ok := regexMatchInterface .(bool )
92
+ if ok {
93
+ o .RegexMatch = regexMatch
94
+ }
95
+ }
96
+
97
+ substringMatchInterface , ok := options ["substring_match" ]
98
+ if ok {
99
+ substringMatch , ok := substringMatchInterface .(bool )
100
+ if ok {
101
+ o .SubstringMatch = substringMatch
102
+ }
103
+ }
104
+
105
+ matchInterface , ok := options ["match" ]
106
+ if ok {
107
+ match , ok := matchInterface .(bool )
108
+ if ok {
109
+ o .Match = match
110
+ }
111
+ }
112
+ }
113
+
7
114
func Run (ctx context.Context , target string , command string , expectedOutput string , username string , password string , options map [string ]interface {}) (bool , string ) {
115
+ optionsStruct := optionsStruct {}
116
+ optionsStruct .Unmarshal (options )
117
+
118
+ conn , err := sql .Open (
119
+ "mysql" ,
120
+ fmt .Sprintf (
121
+ "%s:%s@tcp(%s)/%s" ,
122
+ username ,
123
+ password ,
124
+ target ,
125
+ optionsStruct .Database ,
126
+ ),
127
+ )
128
+ if err != nil {
129
+ return false , err .Error ()
130
+ }
131
+ defer conn .Close ()
132
+
133
+ conn .SetConnMaxIdleTime (- 1 )
134
+ conn .SetMaxOpenConns (1 )
135
+
136
+ // Check if connection can be made
137
+ if optionsStruct .Connect {
138
+ err = conn .Ping ()
139
+ if err != nil {
140
+ return false , err .Error ()
141
+ }
142
+ }
143
+
144
+ // Check if table exists
145
+ if optionsStruct .TableExists {
146
+ query , err := conn .Prepare ("SHOW TABLES LIKE ?" )
147
+ if err != nil {
148
+ return false , err .Error ()
149
+ }
150
+ defer query .Close ()
151
+
152
+ rows , err := query .Query (optionsStruct .Table )
153
+ if err != nil {
154
+ return false , err .Error ()
155
+ }
156
+
157
+ if ! rows .Next () {
158
+ return false , fmt .Sprintf ("table does not exist: \" %s\" " , optionsStruct .Table )
159
+ }
160
+ }
161
+
162
+ // Check if row exists
163
+ if optionsStruct .RowExists {
164
+ query , err := conn .Prepare ("SELECT * FROM ? LIMIT 1" )
165
+ if err != nil {
166
+ return false , err .Error ()
167
+ }
168
+ defer query .Close ()
169
+
170
+ rows , err := query .Query (optionsStruct .Table )
171
+ if err != nil {
172
+ return false , err .Error ()
173
+ }
174
+
175
+ if ! rows .Next () {
176
+ return false , fmt .Sprintf ("table is empty: \" %s\" " , optionsStruct .Table )
177
+ }
178
+ }
179
+
180
+ // Check if field matches regex
181
+ if optionsStruct .RegexMatch {
182
+ regexp , err := regexp .Compile (expectedOutput )
183
+ if err != nil {
184
+ return false , err .Error ()
185
+ }
186
+
187
+ query , err := conn .Prepare ("SELECT ? FROM ? LIMIT 1" )
188
+ if err != nil {
189
+ return false , err .Error ()
190
+ }
191
+ defer query .Close ()
192
+
193
+ rows , err := query .Query (optionsStruct .Field , optionsStruct .Table )
194
+ if err != nil {
195
+ return false , err .Error ()
196
+ }
197
+
198
+ if ! rows .Next () {
199
+ return false , fmt .Sprintf ("table is empty: \" %s\" " , optionsStruct .Table )
200
+ }
201
+
202
+ var field string
203
+ err = rows .Scan (& field )
204
+ if err != nil {
205
+ return false , err .Error ()
206
+ }
207
+
208
+ if ! regexp .MatchString (field ) {
209
+ return false , fmt .Sprintf ("field does not match regex: \" %s\" " , expectedOutput )
210
+ }
211
+ }
212
+
213
+ // Check if field matches substring or contains substring
214
+ if optionsStruct .SubstringMatch || optionsStruct .Match {
215
+ query , err := conn .Prepare ("SELECT ? FROM ? LIMIT 1" )
216
+ if err != nil {
217
+ return false , err .Error ()
218
+ }
219
+ defer query .Close ()
220
+
221
+ rows , err := query .Query (optionsStruct .Field , optionsStruct .Table )
222
+ if err != nil {
223
+ return false , err .Error ()
224
+ }
225
+
226
+ if ! rows .Next () {
227
+ return false , fmt .Sprintf ("table is empty: \" %s\" " , optionsStruct .Table )
228
+ }
229
+
230
+ var field string
231
+ err = rows .Scan (& field )
232
+ if err != nil {
233
+ return false , err .Error ()
234
+ }
235
+
236
+ if optionsStruct .Match && field != expectedOutput {
237
+ return false , fmt .Sprintf ("field does not match string: \" %s\" " , expectedOutput )
238
+ }
239
+
240
+ if optionsStruct .SubstringMatch && ! strings .Contains (field , expectedOutput ) {
241
+ return false , fmt .Sprintf ("field does not contain substring: \" %s\" " , expectedOutput )
242
+ }
243
+
244
+ }
245
+
8
246
return true , ""
9
247
}
0 commit comments