diff --git a/.github/workflows/check-generated-code.yml b/.github/workflows/check-generated-code.yml new file mode 100644 index 000000000..152cf91bc --- /dev/null +++ b/.github/workflows/check-generated-code.yml @@ -0,0 +1,36 @@ +name: Check generated code + +on: + push: + branches: + - main + paths-ignore: + - "**/*.md" + - "LICENSE" + pull_request: + branches: + - main + paths-ignore: + - "**/*.md" + - "LICENSE" + +jobs: + check-generated-code: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - name: Install Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + with: + go-version: 1.24.x + cache: true + - name: Check generated code + run: | + go generate ./... + if [[ $(git status --porcelain) ]]; then + echo "Error: Uncommitted changes found after running 'go generate'. Please commit all generated code." + git diff + exit 1 + else + echo "No changes detected after running 'go generate'." + fi diff --git a/go.sum b/go.sum index f7bb6a723..195ffae7a 100644 --- a/go.sum +++ b/go.sum @@ -14,14 +14,10 @@ github.com/jcchavezs/mergefs v0.1.0 h1:7oteO7Ocl/fnfFMkoVLJxTveCjrsd//UB0j89xmnp github.com/jcchavezs/mergefs v0.1.0/go.mod h1:eRLTrsA+vFwQZ48hj8p8gki/5v9C2bFtHH5Mnn4bcGk= github.com/magefile/mage v1.15.1-0.20241126214340-bdc92f694516 h1:aAO0L0ulox6m/CLRYvJff+jWXYYCKGpEm3os7dM/Z+M= github.com/magefile/mage v1.15.1-0.20241126214340-bdc92f694516/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= -github.com/mccutchen/go-httpbin/v2 v2.18.0 h1:WFU1OELp3nHYLvXct/3nrGVIgxU0X+RJfDPYRBnvicY= -github.com/mccutchen/go-httpbin/v2 v2.18.0/go.mod h1:GBy5I7XwZ4ZLhT3hcq39I4ikwN9x4QUt6EAxNiR8Jus= github.com/mccutchen/go-httpbin/v2 v2.18.1 h1:Zsi6gLCUS/kqZf36BicIbZsO8o0VyO2nSaOv/J8XKlQ= github.com/mccutchen/go-httpbin/v2 v2.18.1/go.mod h1:GBy5I7XwZ4ZLhT3hcq39I4ikwN9x4QUt6EAxNiR8Jus= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= -github.com/petar-dambovaliev/aho-corasick v0.0.0-20240411101913-e07a1f0e8eb4 h1:1Kw2vDBXmjop+LclnzCb/fFy+sgb3gYARwfmoUcQe6o= -github.com/petar-dambovaliev/aho-corasick v0.0.0-20240411101913-e07a1f0e8eb4/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw= github.com/petar-dambovaliev/aho-corasick v0.0.0-20250424160509-463d218d4745 h1:Vpr4VgAizEgEZsaMohpw6JYDP+i9Of9dmdY4ufNP6HI= github.com/petar-dambovaliev/aho-corasick v0.0.0-20250424160509-463d218d4745/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= diff --git a/go.work.sum b/go.work.sum index 8f0ff766f..319bd5c07 100644 --- a/go.work.sum +++ b/go.work.sum @@ -8,13 +8,16 @@ golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= diff --git a/internal/seclang/parser_test.go b/internal/seclang/parser_test.go index fc67bbee3..4e3c6d87d 100644 --- a/internal/seclang/parser_test.go +++ b/internal/seclang/parser_test.go @@ -297,3 +297,549 @@ func BenchmarkParseFromString(b *testing.B) { _ = parser.FromString(parsingRule) } } + +func TestSelect(t *testing.T) { + tests := []struct { + name string + rule string + expectedError bool + }{ + { + name: "ARGS", + rule: `SecRule ARGS:foo "bar" "id:1"`, + expectedError: false, + }, + { + name: "ARGS_COMBINED_SIZE", + rule: `SecRule ARGS_COMBINED_SIZE:foo "bar" "id:1"`, + expectedError: true, + }, + { + name: "ARGS_GET", + rule: `SecRule ARGS_GET:foo "bar" "id:2"`, + expectedError: false, + }, + { + name: "ARGS_GET_NAMES", + rule: `SecRule ARGS_GET_NAMES:foo "bar" "id:3"`, + expectedError: false, + }, + { + name: "ARGS_NAMES", + rule: `SecRule ARGS_NAMES:foo "bar" "id:4"`, + expectedError: false, + }, + { + name: "ARGS_PATH", + rule: `SecRule ARGS_PATH:foo "bar" "id:5"`, + expectedError: false, + }, + { + name: "ARGS_POST", + rule: `SecRule ARGS_POST:foo "bar" "id:6"`, + expectedError: false, + }, + { + name: "ARGS_POST_NAMES", + rule: `SecRule ARGS_POST_NAMES:foo "bar" "id:7"`, + expectedError: false, + }, + { + name: "AUTH_TYPE", + rule: `SecRule AUTH_TYPE:foo "bar" "id:8"`, + expectedError: true, + }, + { + name: "DURATION", + rule: `SecRule DURATION:foo "bar" "id:9"`, + expectedError: true, + }, + { + name: "ENV", + rule: `SecRule ENV:foo "bar" "id:10"`, + expectedError: false, + }, + { + name: "FILES", + rule: `SecRule FILES:foo "bar" "id:11"`, + expectedError: false, + }, + { + name: "FILES_COMBINED_SIZE", + rule: `SecRule FILES_COMBINED_SIZE:foo "bar" "id:12"`, + expectedError: true, + }, + { + name: "FILES_NAMES", + rule: `SecRule FILES_NAMES:foo "bar" "id:13"`, + expectedError: false, + }, + { + name: "FILES_SIZES", + rule: `SecRule FILES_SIZES:foo "bar" "id:14"`, + expectedError: false, + }, + { + name: "FILES_TMPNAMES", + rule: `SecRule FILES_TMPNAMES:foo "bar" "id:15"`, + expectedError: false, + }, + { + name: "FILES_TMP_CONTENT", + rule: `SecRule FILES_TMP_CONTENT:foo "bar" "id:16"`, + expectedError: false, + }, + { + name: "FULL_REQUEST", + rule: `SecRule FULL_REQUEST:foo "bar" "id:17"`, + expectedError: true, + }, + { + name: "FULL_REQUEST_LENGTH", + rule: `SecRule FULL_REQUEST_LENGTH:foo "bar" "id:18"`, + expectedError: true, + }, + { + name: "GEO", + rule: `SecRule GEO:foo "bar" "id:19"`, + expectedError: false, + }, + { + name: "HIGHEST_SEVERITY", + rule: `SecRule HIGHEST_SEVERITY:foo "bar" "id:20"`, + expectedError: true, + }, + { + name: "INBOUND_DATA_ERROR", + rule: `SecRule INBOUND_DATA_ERROR:foo "bar" "id:21"`, + expectedError: true, + }, + { + name: "IP", + rule: `SecRule IP:foo "bar" "id:22"`, + expectedError: true, + }, + { + name: "JSON", + rule: `SecRule JSON:foo "bar" "id:23"`, + expectedError: false, + }, + { + name: "MATCHED_VAR", + rule: `SecRule MATCHED_VAR:foo "bar" "id:24"`, + expectedError: true, + }, + { + name: "MATCHED_VARS", + rule: `SecRule MATCHED_VARS:foo "bar" "id:25"`, + expectedError: false, + }, + { + name: "MATCHED_VARS_NAMES", + rule: `SecRule MATCHED_VARS_NAMES:foo "bar" "id:26"`, + expectedError: false, + }, + { + name: "MATCHED_VAR_NAME", + rule: `SecRule MATCHED_VAR_NAME:foo "bar" "id:27"`, + expectedError: true, + }, + { + name: "MULTIPART_BOUNDARY_QUOTED", + rule: `SecRule MULTIPART_BOUNDARY_QUOTED:foo "bar" "id:28"`, + expectedError: true, + }, + { + name: "MULTIPART_BOUNDARY_WHITESPACE", + rule: `SecRule MULTIPART_BOUNDARY_WHITESPACE:foo "bar" "id:29"`, + expectedError: true, + }, + { + name: "MULTIPART_CRLF_LF_LINES", + rule: `SecRule MULTIPART_CRLF_LF_LINES:foo "bar" "id:30"`, + expectedError: true, + }, + { + name: "MULTIPART_DATA_AFTER", + rule: `SecRule MULTIPART_DATA_AFTER:foo "bar" "id:31"`, + expectedError: true, + }, + { + name: "MULTIPART_DATA_BEFORE", + rule: `SecRule MULTIPART_DATA_BEFORE:foo "bar" "id:32"`, + expectedError: true, + }, + { + name: "MULTIPART_FILENAME", + rule: `SecRule MULTIPART_FILENAME:foo "bar" "id:33"`, + expectedError: false, + }, + { + name: "MULTIPART_FILE_LIMIT_EXCEEDED", + rule: `SecRule MULTIPART_FILE_LIMIT_EXCEEDED:foo "bar" "id:34"`, + expectedError: true, + }, + { + name: "MULTIPART_HEADER_FOLDING", + rule: `SecRule MULTIPART_HEADER_FOLDING:foo "bar" "id:35"`, + expectedError: true, + }, + { + name: "MULTIPART_INVALID_HEADER_FOLDING", + rule: `SecRule MULTIPART_INVALID_HEADER_FOLDING:foo "bar" "id:36"`, + expectedError: true, + }, + { + name: "MULTIPART_INVALID_PART", + rule: `SecRule MULTIPART_INVALID_PART:foo "bar" "id:37"`, + expectedError: true, + }, + { + name: "MULTIPART_INVALID_QUOTING", + rule: `SecRule MULTIPART_INVALID_QUOTING:foo "bar" "id:38"`, + expectedError: true, + }, + { + name: "MULTIPART_LF_LINE", + rule: `SecRule MULTIPART_LF_LINE:foo "bar" "id:39"`, + expectedError: true, + }, + { + name: "MULTIPART_MISSING_SEMICOLON", + rule: `SecRule MULTIPART_MISSING_SEMICOLON:foo "bar" "id:40"`, + expectedError: true, + }, + { + name: "MULTIPART_NAME", + rule: `SecRule MULTIPART_NAME:foo "bar" "id:41"`, + expectedError: false, + }, + { + name: "MULTIPART_PART_HEADERS", + rule: `SecRule MULTIPART_PART_HEADERS:foo "bar" "id:42"`, + expectedError: false, + }, + { + name: "MULTIPART_STRICT_ERROR", + rule: `SecRule MULTIPART_STRICT_ERROR:foo "bar" "id:43"`, + expectedError: true, + }, + { + name: "MULTIPART_UNMATCHED_BOUNDARY", + rule: `SecRule MULTIPART_UNMATCHED_BOUNDARY:foo "bar" "id:44"`, + expectedError: true, + }, + { + name: "OUTBOUND_DATA_ERROR", + rule: `SecRule OUTBOUND_DATA_ERROR:foo "bar" "id:45"`, + expectedError: true, + }, + { + name: "PATH_INFO", + rule: `SecRule PATH_INFO:foo "bar" "id:46"`, + expectedError: true, + }, + { + name: "QUERY_STRING", + rule: `SecRule QUERY_STRING:foo "bar" "id:47"`, + expectedError: true, + }, + { + name: "REMOTE_ADDR", + rule: `SecRule REMOTE_ADDR:foo "bar" "id:48"`, + expectedError: true, + }, + { + name: "REMOTE_HOST", + rule: `SecRule REMOTE_HOST:foo "bar" "id:49"`, + expectedError: true, + }, + { + name: "REMOTE_PORT", + rule: `SecRule REMOTE_PORT:foo "bar" "id:50"`, + expectedError: true, + }, + { + name: "REQBODY_ERROR", + rule: `SecRule REQBODY_ERROR:foo "bar" "id:51"`, + expectedError: true, + }, + { + name: "REQBODY_ERROR_MSG", + rule: `SecRule REQBODY_ERROR_MSG:foo "bar" "id:52"`, + expectedError: true, + }, + { + name: "REQBODY_PROCESSOR", + rule: `SecRule REQBODY_PROCESSOR:foo "bar" "id:53"`, + expectedError: true, + }, + { + name: "REQBODY_PROCESSOR_ERROR", + rule: `SecRule REQBODY_PROCESSOR_ERROR:foo "bar" "id:54"`, + expectedError: true, + }, + { + name: "REQBODY_PROCESSOR_ERROR_MSG", + rule: `SecRule REQBODY_PROCESSOR_ERROR_MSG:foo "bar" "id:55"`, + expectedError: true, + }, + { + name: "REQUEST_BASENAME", + rule: `SecRule REQUEST_BASENAME:foo "bar" "id:56"`, + expectedError: true, + }, + { + name: "REQUEST_BODY", + rule: `SecRule REQUEST_BODY:foo "bar" "id:57"`, + expectedError: true, + }, + { + name: "REQUEST_BODY_LENGTH", + rule: `SecRule REQUEST_BODY_LENGTH:foo "bar" "id:58"`, + expectedError: true, + }, + { + name: "REQUEST_COOKIES", + rule: `SecRule REQUEST_COOKIES:foo "bar" "id:59"`, + expectedError: false, + }, + { + name: "REQUEST_COOKIES_NAMES", + rule: `SecRule REQUEST_COOKIES_NAMES:foo "bar" "id:60"`, + expectedError: false, + }, + { + name: "REQUEST_FILENAME", + rule: `SecRule REQUEST_FILENAME:foo "bar" "id:61"`, + expectedError: true, + }, + { + name: "REQUEST_HEADERS", + rule: `SecRule REQUEST_HEADERS:foo "bar" "id:62"`, + expectedError: false, + }, + { + name: "REQUEST_HEADERS_NAMES", + rule: `SecRule REQUEST_HEADERS_NAMES:foo "bar" "id:63"`, + expectedError: false, + }, + { + name: "REQUEST_LINE", + rule: `SecRule REQUEST_LINE:foo "bar" "id:64"`, + expectedError: true, + }, + { + name: "REQUEST_METHOD", + rule: `SecRule REQUEST_METHOD:foo "bar" "id:65"`, + expectedError: true, + }, + { + name: "REQUEST_PROTOCOL", + rule: `SecRule REQUEST_PROTOCOL:foo "bar" "id:66"`, + expectedError: true, + }, + { + name: "REQUEST_URI", + rule: `SecRule REQUEST_URI:foo "bar" "id:67"`, + expectedError: true, + }, + { + name: "REQUEST_URI_RAW", + rule: `SecRule REQUEST_URI_RAW:foo "bar" "id:68"`, + expectedError: true, + }, + { + name: "REQUEST_XML", + rule: `SecRule REQUEST_XML:foo "bar" "id:69"`, + expectedError: false, + }, + { + name: "RESPONSE_ARGS", + rule: `SecRule RESPONSE_ARGS:foo "bar" "id:70"`, + expectedError: false, + }, + { + name: "RESPONSE_BODY", + rule: `SecRule RESPONSE_BODY:foo "bar" "id:71"`, + expectedError: true, + }, + { + name: "RESPONSE_CONTENT_LENGTH", + rule: `SecRule RESPONSE_CONTENT_LENGTH:foo "bar" "id:72"`, + expectedError: true, + }, + { + name: "RESPONSE_CONTENT_TYPE", + rule: `SecRule RESPONSE_CONTENT_TYPE:foo "bar" "id:73"`, + expectedError: true, + }, + { + name: "RESPONSE_HEADERS", + rule: `SecRule RESPONSE_HEADERS:foo "bar" "id:74"`, + expectedError: false, + }, + { + name: "RESPONSE_HEADERS_NAMES", + rule: `SecRule RESPONSE_HEADERS_NAMES:foo "bar" "id:75"`, + expectedError: false, + }, + { + name: "RESPONSE_PROTOCOL", + rule: `SecRule RESPONSE_PROTOCOL:foo "bar" "id:76"`, + expectedError: true, + }, + { + name: "RESPONSE_STATUS", + rule: `SecRule RESPONSE_STATUS:foo "bar" "id:77"`, + expectedError: true, + }, + { + name: "RESPONSE_XML", + rule: `SecRule RESPONSE_XML:foo "bar" "id:78"`, + expectedError: false, + }, + { + name: "RES_BODY_ERROR", + rule: `SecRule RES_BODY_ERROR:foo "bar" "id:79"`, + expectedError: true, + }, + { + name: "RES_BODY_ERROR_MSG", + rule: `SecRule RES_BODY_ERROR_MSG:foo "bar" "id:80"`, + expectedError: true, + }, + { + name: "RES_BODY_PROCESSOR", + rule: `SecRule RES_BODY_PROCESSOR:foo "bar" "id:81"`, + expectedError: true, + }, + { + name: "RES_BODY_PROCESSOR_ERROR", + rule: `SecRule RES_BODY_PROCESSOR_ERROR:foo "bar" "id:82"`, + expectedError: true, + }, + { + name: "RES_BODY_PROCESSOR_ERROR_MSG", + rule: `SecRule RES_BODY_PROCESSOR_ERROR_MSG:foo "bar" "id:83"`, + expectedError: true, + }, + { + name: "RULE", + rule: `SecRule RULE:foo "bar" "id:84"`, + expectedError: false, + }, + { + name: "SERVER_ADDR", + rule: `SecRule SERVER_ADDR:foo "bar" "id:85"`, + expectedError: true, + }, + { + name: "SERVER_NAME", + rule: `SecRule SERVER_NAME:foo "bar" "id:86"`, + expectedError: true, + }, + { + name: "SERVER_PORT", + rule: `SecRule SERVER_PORT:foo "bar" "id:87"`, + expectedError: true, + }, + { + name: "SESSIONID", + rule: `SecRule SESSIONID:foo "bar" "id:88"`, + expectedError: true, + }, + { + name: "STATUS_LINE", + rule: `SecRule STATUS_LINE:foo "bar" "id:89"`, + expectedError: true, + }, + { + name: "TIME", + rule: `SecRule TIME:foo "bar" "id:90"`, + expectedError: true, + }, + { + name: "TIME_DAY", + rule: `SecRule TIME_DAY:foo "bar" "id:91"`, + expectedError: true, + }, + { + name: "TIME_EPOCH", + rule: `SecRule TIME_EPOCH:foo "bar" "id:92"`, + expectedError: true, + }, + { + name: "TIME_HOUR", + rule: `SecRule TIME_HOUR:foo "bar" "id:93"`, + expectedError: true, + }, + { + name: "TIME_MIN", + rule: `SecRule TIME_MIN:foo "bar" "id:94"`, + expectedError: true, + }, + { + name: "TIME_MON", + rule: `SecRule TIME_MON:foo "bar" "id:95"`, + expectedError: true, + }, + { + name: "TIME_SEC", + rule: `SecRule TIME_SEC:foo "bar" "id:96"`, + expectedError: true, + }, + { + name: "TIME_WDAY", + rule: `SecRule TIME_WDAY:foo "bar" "id:97"`, + expectedError: true, + }, + { + name: "TIME_YEAR", + rule: `SecRule TIME_YEAR:foo "bar" "id:98"`, + expectedError: true, + }, + { + name: "TX", + rule: `SecRule TX:foo "bar" "id:99"`, + expectedError: false, + }, + { + name: "UNIQUE_ID", + rule: `SecRule UNIQUE_ID:foo "bar" "id:100"`, + expectedError: true, + }, + { + name: "UNKNOWN", + rule: `SecRule UNKNOWN:foo "bar" "id:101"`, + expectedError: true, + }, + { + name: "URLENCODED_ERROR", + rule: `SecRule URLENCODED_ERROR:foo "bar" "id:102"`, + expectedError: true, + }, + { + name: "USERID", + rule: `SecRule USERID:foo "bar" "id:103"`, + expectedError: true, + }, + { + name: "XML", + rule: `SecRule XML:foo "bar" "id:104"`, + expectedError: false, + }, + } + + waf := coraza.NewWAF() + p := NewParser(waf) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := p.FromString(tt.rule) + if (err != nil) != tt.expectedError { + t.Errorf("FromString() error = %v, expectedError %v", err, tt.expectedError) + } + }) + } +} diff --git a/internal/variables/variablesmap.gen.go b/internal/variables/variablesmap.gen.go index fba7f99d0..d1bad5831 100644 --- a/internal/variables/variablesmap.gen.go +++ b/internal/variables/variablesmap.gen.go @@ -243,18 +243,32 @@ func (v RuleVariable) CanBeSelected() bool { return true case ArgsPost: return true + case ArgsPath: + return true + case FilesSizes: + return true case FilesNames: return true + case FilesTmpContent: + return true + case MultipartFilename: + return true + case MultipartName: + return true case MatchedVarsNames: return true case MatchedVars: return true + case Files: + return true case RequestCookies: return true case RequestHeaders: return true case ResponseHeaders: return true + case Geo: + return true case RequestCookiesNames: return true case FilesTmpNames: @@ -267,6 +281,8 @@ func (v RuleVariable) CanBeSelected() bool { return true case TX: return true + case Rule: + return true case JSON: return true case Env: