Skip to content

Commit 6b92a77

Browse files
committed
Introduce -textproto flag to allow testing string conversion into required proto.
1 parent 7ea6e65 commit 6b92a77

8 files changed

Lines changed: 334 additions & 52 deletions

File tree

MODULE.bazel

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ bazel_dep(
3434
version = "0.39.1",
3535
repo_name = "bazel_gazelle",
3636
)
37+
bazel_dep(
38+
name = "rules_proto",
39+
version = "7.0.2",
40+
)
41+
42+
bazel_dep(
43+
name = "rules_proto_grpc",
44+
version = "5.0.1",
45+
)
46+
47+
bazel_dep(
48+
name = "protobuf",
49+
version = "29.0",
50+
repo_name = "com_google_protobuf",
51+
)
3752

3853
go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
3954
go_deps.gazelle_override(

MODULE.bazel.lock

Lines changed: 143 additions & 50 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/rulescli.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const textFmtHeader = `# proto-file: github.com/google/cel-spec/proto/checked.pr
3737
type options struct {
3838
expr, file, test string
3939
outputFormat, version string
40+
textproto string
4041
verbose bool
4142
}
4243

@@ -46,12 +47,13 @@ func (o *options) registerFlags(fs *flag.FlagSet) {
4647
fs.StringVar(&o.file, "file", "", "File containing CEL expressions representing the Cloud Armor rule")
4748
fs.StringVar(&o.outputFormat, "output_format", "", "output format (textproto, binarypb)")
4849
fs.StringVar(&o.version, "version", "VCurrent", "valid versions (VCurrent, VNext)")
50+
fs.StringVar(&o.textproto, "textproto", "", "File containing the VendorRulesetCollection ruleset textproto")
4951
fs.BoolVar(&o.verbose, "verbose", false, "Enable verbose logging")
5052
}
5153

5254
func (o *options) validate() error {
53-
if o.expr == "" && o.file == "" && o.test == "" {
54-
return fmt.Errorf("either -expr=<expression> or -file=<file> or -test=<test_suite_file> is required")
55+
if o.expr == "" && o.file == "" && o.test == "" && o.textproto == "" {
56+
return fmt.Errorf("either -expr=<expression> or -file=<file> or -test=<test_suite_file> or -textproto=<textproto_file> is required")
5557
}
5658
if o.expr != "" && o.outputFormat != "" &&
5759
o.outputFormat != "textproto" && o.outputFormat != "binarypb" {
@@ -160,6 +162,25 @@ func (r *rules) newProgram(ast *cel.Ast) cel.Program {
160162
return prg
161163
}
162164

165+
func processVendorRuleset(filename string, verbose bool) error {
166+
verboseLog(verbose, "Reading vendor ruleset file: %s", filename)
167+
content, err := os.ReadFile(filename)
168+
169+
if err != nil {
170+
fmt.Fprintf(os.Stderr, "failed to read vendor ruleset file: %v\n", err)
171+
}
172+
173+
err = cloudarmor.ParseVendorRuleset(content)
174+
175+
if err != nil {
176+
fmt.Fprintf(os.Stderr, "failed to parse vendor ruleset file as VendorRulesetCollection: %v\n", err)
177+
return err
178+
}
179+
180+
verboseLog(verbose, "Successfully validated vendor ruleset")
181+
return nil
182+
}
183+
163184
func main() {
164185
var opts options
165186
opts.registerFlags(flag.CommandLine)
@@ -178,6 +199,14 @@ func main() {
178199

179200
r := newRules(opts.version)
180201

202+
if opts.textproto != "" {
203+
if err := processVendorRuleset(opts.textproto, opts.verbose); err != nil {
204+
fmt.Fprintf(os.Stderr, "failed to process vendor ruleset: %v\n", err)
205+
os.Exit(1)
206+
}
207+
os.Exit(0)
208+
}
209+
181210
if opts.expr != "" {
182211
ast, ok := r.newAST(opts.expr)
183212
if ok {

pkg/cloudarmor/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ go_library(
1313
importpath = "github.com/cel-expr/cloud-armor-rules/pkg/cloudarmor",
1414
visibility = ["//visibility:public"],
1515
deps = [
16+
"//pkg/cloudarmor/proto:vendor_ruleset_collection_go_proto",
17+
"@org_golang_google_protobuf//encoding/prototext",
1618
"@com_github_google_cel_go//cel:go_default_library",
1719
"@com_github_google_cel_go//common/ast:go_default_library",
1820
"@com_github_google_cel_go//common/env:go_default_library",

pkg/cloudarmor/cloudarmor.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ import (
3434
"github.com/google/cel-go/common/overloads"
3535
"github.com/google/cel-go/common/types"
3636
"github.com/google/cel-go/common/types/ref"
37+
"google.golang.org/protobuf/encoding/prototext"
3738
"gopkg.in/yaml.v3"
39+
40+
pb "github.com/cel-expr/cloud-armor-rules/pkg/cloudarmor/proto"
3841
)
3942

4043
const (
@@ -413,3 +416,16 @@ func utf8ToUnicodeString(str string) ref.Val {
413416
}
414417
return types.String(sb.String())
415418
}
419+
420+
func ParseVendorRuleset(content []byte) error {
421+
422+
var rulesetCollection pb.VendorRulesetCollection
423+
424+
// Unmarshal the text-formatted content into the struct.
425+
err := prototext.Unmarshal(content, &rulesetCollection)
426+
if err != nil {
427+
return fmt.Errorf("failed to unmarshal VendorRulesetCollection: %w", err)
428+
}
429+
430+
return nil
431+
}

pkg/cloudarmor/proto/BUILD.bazel

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
2+
load("@rules_proto//proto:defs.bzl", "proto_library")
3+
4+
licenses(["notice"]) # Apache 2.0
5+
6+
proto_library(
7+
name = "vendor_ruleset_collection_proto",
8+
srcs = ["vendor_ruleset_collection.proto"],
9+
visibility = ["//visibility:public"],
10+
deps = ["@com_google_protobuf//:timestamp_proto"],
11+
)
12+
13+
go_proto_library(
14+
name = "vendor_ruleset_collection_go_proto",
15+
importpath = "github.com/cel-expr/cloud-armor-rules/pkg/cloudarmor/proto",
16+
proto = ":vendor_ruleset_collection_proto",
17+
visibility = ["//visibility:public"],
18+
)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
syntax = "proto3";
2+
3+
package proto;
4+
5+
option go_package = "github.com/cel-expr/cloud-armor-rules/pkg/cloudarmor/proto";
6+
7+
import "google/protobuf/timestamp.proto";
8+
9+
// Vendor ruleset collection initially provided by Vendor
10+
// This represents the initial set of data provided by the Vendor.
11+
// For further details, please refer to shared(Google and Imperva) design doc:
12+
// go/imperva-google-mgdrules-integration
13+
message VendorRulesetCollection {
14+
// Next ID: 4
15+
// Unique ID associated with the ruleset collection
16+
string uuid = 1;
17+
18+
// Metadata shared across Rulesets
19+
message RulesetMetadata {
20+
// Next ID: 6
21+
// ruleset creation date
22+
google.protobuf.Timestamp creation_date = 1;
23+
24+
// ruleset modification date
25+
google.protobuf.Timestamp updation_date = 2;
26+
27+
// Name of the owner of the rulesets, e.g. Imperva
28+
string owner = 3;
29+
30+
// A description of the ruleset's purpose
31+
string description = 4;
32+
33+
// Encryption key identifier
34+
string encryptionkey_id = 5;
35+
}
36+
37+
// Metadata for the ruleset
38+
RulesetMetadata ruleset_metadata = 2;
39+
40+
// Collection of vendor rulesets
41+
repeated VendorRuleSet rule_sets = 3;
42+
}
43+
44+
// Vendor rulesets containing rules for specific category, e.g. sqli, xss
45+
message VendorRuleSet {
46+
// Next ID: 7
47+
// Name of the ruleset provided by Vendor
48+
string name = 1;
49+
50+
// Version of the ruleset provided by Vendor, if any.
51+
string version = 2;
52+
53+
// Category of the ruleset, e.g. SQLi, XSS
54+
string category = 3;
55+
56+
// ChangeLog for the ruleset
57+
message ChangeLog {
58+
// This will be used to surface changelog information through
59+
// documentation
60+
string description = 1;
61+
62+
// this determines whether the ruleset description should be public
63+
// e.g. Included in the release notes
64+
bool always_public = 2;
65+
66+
// this is set if it should be included in a CVE release
67+
bool use_for_cve = 3;
68+
}
69+
70+
// Release notes corresponding to the rulesets
71+
ChangeLog change_log = 4;
72+
73+
// Transformations should be applied sequentially to the input request
74+
// before evaluating CEL Expression
75+
// Rule shall be evaluated only once all the transformations were applied.
76+
repeated string transformations = 5;
77+
78+
// Rule from the Vendor ruleset.
79+
// It would only exist in the initial set of rules provided by the Vendor.
80+
message VendorRule {
81+
// Next ID: 7
82+
// Unique ID associated with each rule
83+
// For incremental updates, the rule ID remains unchanged but follows a
84+
// versioning format. Example: id191190.0 to id191190.1
85+
string id = 1;
86+
87+
// CEL expression
88+
// Defines the rule logic in CEL string format using Cloud Armor (CA)
89+
// attributes.
90+
string cel_expression = 2;
91+
92+
// Array of Key value pairs of tags and additional info associated
93+
// with the tag separated by ':'
94+
repeated string tags = 3;
95+
96+
// Curl commands that would generate the matching expression for rule
97+
repeated string e2e_test_command = 4;
98+
99+
// This field is reserved for the initial version of the ruleset
100+
// defined by the Vendor.
101+
reserved 5;
102+
103+
// By default, it would be false.
104+
// If true, the rule shall only be evaluated if enabled by customers.
105+
bool opt_in = 6;
106+
}
107+
// collection of rules under the ruleset
108+
repeated VendorRule rules = 6;
109+
}

rulescli

10.9 MB
Binary file not shown.

0 commit comments

Comments
 (0)