Added support for additional validation rules in custom detector (#4413)

* Added support for additional validation rules in custom detector

* refactored the approach to support validations for each regex in config

* resolved comments
This commit is contained in:
Kashif Khan
2025-08-26 16:19:24 +05:00
committed by GitHub
parent bb899f20dc
commit 15bc3e59af
9 changed files with 850 additions and 44 deletions
+4
View File
@@ -11,6 +11,10 @@ detectors:
regex: regex:
secret: |- secret: |-
(?i)[\w.-]{0,50}?(?:access|auth|(?-i:[Aa]pi|API)|credential|creds|key|passw(?:or)?d|secret|token)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([\w.=-]{10,150}|[a-z0-9][a-z0-9+/]{11,}={0,3})(?:[\x60'"\s;]|\\[nr]|$) (?i)[\w.-]{0,50}?(?:access|auth|(?-i:[Aa]pi|API)|credential|creds|key|passw(?:or)?d|secret|token)(?:[ \t\w.-]{0,20})[\s'"]{0,3}(?:=|>|:{1,3}=|\|\||:|=>|\?=|,)[\x60'"\s=]{0,5}([\w.=-]{10,150}|[a-z0-9][a-z0-9+/]{11,}={0,3})(?:[\x60'"\s;]|\\[nr]|$)
validations:
secret: # name of the regex to apply these validations to
contains_digit: true
contains_special_char: true
entropy: 3.5 entropy: 3.5
# exclude_regexes_capture: # exclude_regexes_capture:
# - |- # - |-
+7
View File
@@ -43,6 +43,13 @@ This guide will walk you through setting up a custom detector in TruffleHog to i
- **`exclude_regexes_match`**: This parameter enables you to define regex patterns to exclude entire matches from being reported as secrets. This applies to the entire matched string, not just the token. - **`exclude_regexes_match`**: This parameter enables you to define regex patterns to exclude entire matches from being reported as secrets. This applies to the entire matched string, not just the token.
- **`entropy`**: This parameter is used to assess the randomness of detected strings. High entropy often indicates that a string is a potential secret, such as an API key or password, due to its complexity and unpredictability. It helps in filtering false-positives. While an entropy threshold of `3` can be a starting point, it's essential to adjust this value based on your project's specific requirements and the nature of the data you have. - **`entropy`**: This parameter is used to assess the randomness of detected strings. High entropy often indicates that a string is a potential secret, such as an API key or password, due to its complexity and unpredictability. It helps in filtering false-positives. While an entropy threshold of `3` can be a starting point, it's essential to adjust this value based on your project's specific requirements and the nature of the data you have.
- **`exclude_words`**: This parameter allows you to specify a list of words that, if present in a detected string, will cause TruffleHog to ignore that string. This is a substring match and does not enforce word boundaries. It applies only to the token. - **`exclude_words`**: This parameter allows you to specify a list of words that, if present in a detected string, will cause TruffleHog to ignore that string. This is a substring match and does not enforce word boundaries. It applies only to the token.
- **`validations`**: This parameter lets you define extra validation rules for each regex specified in the regex option. These rules address limitations of Go's RE2 engine, such as the lack of lookahead support, and are applied after a regex match to help reduce false positives.
Available validation options:
- **`contains_digit`**: Ensures the match contains at least one numeric digit (0-9). Useful for API keys or tokens that must include numbers.
- **`contains_lowercase`**: Ensures the match contains at least one lowercase letter (a-z). Common requirement for passwords and mixed-case tokens.
- **`contains_uppercase`**: Ensures the match contains at least one uppercase letter (A-Z). Helps validate tokens that follow mixed-case conventions.
- **`contains_special_char`**: Ensures the match contains at least one special character from the set `!@#$%^&*()_+-=[]{}|;:,.<>?`. Useful for complex passwords or encoded tokens.
[Here](/examples/generic_with_filters.yml) is an example of a custom detector using these parameters. [Here](/examples/generic_with_filters.yml) is an example of a custom detector using these parameters.
+21 -1
View File
@@ -116,7 +116,7 @@ func (c *CustomRegexWebhook) FromData(ctx context.Context, verify bool, data []b
MatchLoop: MatchLoop:
for _, match := range matches { for _, match := range matches {
for _, values := range match { for key, values := range match {
// attempt to use capture group // attempt to use capture group
secret := values[0] secret := values[0]
if len(values) > 1 { if len(values) > 1 {
@@ -150,6 +150,26 @@ MatchLoop:
continue MatchLoop continue MatchLoop
} }
} }
if validations := c.GetValidations(); validations != nil {
validationRules := []struct {
enabled bool
validator func(string) bool
}{
{validations[key].GetContainsDigit(), ContainsDigit},
{validations[key].GetContainsLowercase(), ContainsLowercase},
{validations[key].GetContainsUppercase(), ContainsUppercase},
{validations[key].GetContainsSpecialChar(), ContainsSpecialChar},
}
for _, rule := range validationRules {
if rule.enabled && !rule.validator(secret) {
// skip this match if a validation rule is enabled but missing from the secret
continue MatchLoop
}
}
}
} }
g.Go(func() error { g.Go(func() error {
@@ -4,9 +4,13 @@ import (
"context" "context"
"testing" "testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/custom_detectorspb" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/custom_detectorspb"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
"github.com/trufflesecurity/trufflehog/v3/pkg/protoyaml" "github.com/trufflesecurity/trufflehog/v3/pkg/protoyaml"
) )
@@ -227,6 +231,334 @@ func TestDetectorPrimarySecret(t *testing.T) {
assert.Equal(t, "secret_YI7C90ACY1_yy", results[0].GetPrimarySecretValue()) assert.Equal(t, "secret_YI7C90ACY1_yy", results[0].GetPrimarySecretValue())
} }
func TestDetectorValidations(t *testing.T) {
type args struct {
CustomRegex *custom_detectorspb.CustomRegex
Data string
}
tests := []struct {
name string
input args
want []detectors.Result
}{
{
name: "custom validation - contains digit",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsDigit: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MyStr0ngP@ssword!
End of file`,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_CustomRegex,
DetectorName: "test",
Verified: false,
Raw: []byte("MyStr0ngP@ssword!"),
},
},
},
{
name: "custom validation - does not contains digit",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsDigit: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MyStrongPassword!
End of file`,
},
want: nil,
},
{
name: "custom validation - contains lowercase",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsLowercase: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MyStrongPassword!
End of file`,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_CustomRegex,
DetectorName: "test",
Verified: false,
Raw: []byte("MyStrongPassword!"),
},
},
},
{
name: "custom validation - does not contains lowercase",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsLowercase: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MYSTRONGPASSWORD!
End of file`,
},
want: nil,
},
{
name: "custom validation - contains uppercase",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsUppercase: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MyStrongPassword!
End of file`,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_CustomRegex,
DetectorName: "test",
Verified: false,
Raw: []byte("MyStrongPassword!"),
},
},
},
{
name: "custom validation - does not contains uppercase",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsUppercase: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: mystrongpassword!
End of file`,
},
want: nil,
},
{
name: "custom validation - contains special character",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsSpecialChar: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MyStr@ngP@ssword!
End of file`,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_CustomRegex,
DetectorName: "test",
Verified: false,
Raw: []byte("MyStr@ngP@ssword!"),
},
},
},
{
name: "custom validation - does not contains special character",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsSpecialChar: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MyStrongPassword
End of file`,
},
want: nil,
},
{
name: "custom validation - contains uppercase and special characters",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsUppercase: true,
ContainsSpecialChar: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MyStrongP@ssword
End of file`,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_CustomRegex,
DetectorName: "test",
Verified: false,
Raw: []byte("MyStrongP@ssword"),
},
},
},
{
name: "custom validation - contains uppercase but does not contain special characters",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsUppercase: true,
ContainsSpecialChar: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MyStrongPassword
End of file`,
},
want: nil,
},
{
name: "custom validation - wrong regex name in validations",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password"},
Regex: map[string]string{"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"wrong": {
ContainsUppercase: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: mystrongp@ssword
End of file`,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_CustomRegex,
DetectorName: "test",
Verified: false,
Raw: []byte("mystrongp@ssword"),
},
},
},
{
name: "custom validation - multiple regex validations",
input: args{
CustomRegex: &custom_detectorspb.CustomRegex{
Name: "test",
Keywords: []string{"password", "api_key"},
Regex: map[string]string{
"password": `([A-Za-z0-9!@#$%^&*()_+=\-]{12,})`,
"api_key": `([a-f0-9_-]{32})`,
},
Validations: map[string]*custom_detectorspb.ValidationConfig{
"password": {
ContainsUppercase: true,
ContainsSpecialChar: true,
},
"api_key": {
ContainsSpecialChar: true,
},
},
},
Data: `This is custom example
This file has a random text and maybe a secret
Password: MyStrongP@ssword
API_Key: c392c9837d69b44c764cbf260b-e6184 // should be detected
API_Key: c392c9837d69b44c764cbf260be6184 // should be filtered by validation
End of file`,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_CustomRegex,
DetectorName: "test",
Verified: false,
Raw: []byte("MyStrongP@sswordc392c9837d69b44c764cbf260b-e6184"),
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
detector, err := NewWebhookCustomRegex(tt.input.CustomRegex)
assert.NoError(t, err)
results, err := detector.FromData(context.Background(), false, []byte(tt.input.Data))
assert.NoError(t, err)
ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "ExtraData", "verificationError", "primarySecret")
if diff := cmp.Diff(results, tt.want, ignoreOpts); diff != "" {
t.Errorf("CustomDetector.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
}
})
}
}
func BenchmarkProductIndices(b *testing.B) { func BenchmarkProductIndices(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_ = productIndices(3, 2, 6) _ = productIndices(3, 2, 6)
+44
View File
@@ -107,3 +107,47 @@ func ValidateRegexVars(regex map[string]string, body ...string) error {
} }
return nil return nil
} }
// === Custom Validations ===
// ContainsDigit checks if string contains at least one digit
func ContainsDigit(s string) bool {
for i := 0; i < len(s); i++ {
char := s[i]
if char >= '0' && char <= '9' {
return true
}
}
return false
}
// ContainsLowercase checks if string contains at least one lowercase letter
func ContainsLowercase(s string) bool {
for i := 0; i < len(s); i++ {
char := s[i]
if char >= 'a' && char <= 'z' {
return true
}
}
return false
}
// ContainsUppercase checks if string contains at least one uppercase letter
func ContainsUppercase(s string) bool {
for i := 0; i < len(s); i++ {
char := s[i]
if char >= 'A' && char <= 'Z' {
return true
}
}
return false
}
// ContainsSpecialChar checks if string contains at least one special character
func ContainsSpecialChar(s string) bool {
specialChars := "!@#$%^&*()_+-=[]{}|;:,.<>?"
return strings.ContainsAny(s, specialChars)
}
+119 -1
View File
@@ -1,6 +1,8 @@
package custom_detectors package custom_detectors
import "testing" import (
"testing"
)
func TestCustomDetectorsKeywordValidation(t *testing.T) { func TestCustomDetectorsKeywordValidation(t *testing.T) {
tests := []struct { tests := []struct {
@@ -232,3 +234,119 @@ func TestCustomDetectorsVerifyRegexVarsValidation(t *testing.T) {
}) })
} }
} }
func TestContainsDigit(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "contains digit",
args: args{s: "lzscqf&60M"},
want: true,
},
{
name: "does not contains digit",
args: args{s: "ZlDQOdaM*vsT"},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ContainsDigit(tt.args.s); got != tt.want {
t.Errorf("ContainsDigit() = %v, want %v", got, tt.want)
}
})
}
}
func TestContainsLowercase(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "contains lower case",
args: args{s: "g0AJBHdnhRG2"},
want: true,
},
{
name: "does not contains lower case",
args: args{s: "V7T#MEA6@+TN"},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ContainsLowercase(tt.args.s); got != tt.want {
t.Errorf("ContainsDigit() = %v, want %v", got, tt.want)
}
})
}
}
func TestContainsUppercase(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "contains upper case",
args: args{s: "G1sKkJeKlSQf"},
want: true,
},
{
name: "does not contains upper case",
args: args{s: "pq6-14ydz1@d"},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ContainsUppercase(tt.args.s); got != tt.want {
t.Errorf("ContainsDigit() = %v, want %v", got, tt.want)
}
})
}
}
func TestContainsSpecialChar(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "contains upper case",
args: args{s: "HP$gE7s=do0B"},
want: true,
},
{
name: "does not contains upper case",
args: args{s: "w9gvBYctrSjB"},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ContainsSpecialChar(tt.args.s); got != tt.want {
t.Errorf("ContainsDigit() = %v, want %v", got, tt.want)
}
})
}
}
+161 -42
View File
@@ -73,16 +73,17 @@ type CustomRegex struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Keywords []string `protobuf:"bytes,2,rep,name=keywords,proto3" json:"keywords,omitempty"` Keywords []string `protobuf:"bytes,2,rep,name=keywords,proto3" json:"keywords,omitempty"`
Regex map[string]string `protobuf:"bytes,3,rep,name=regex,proto3" json:"regex,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Regex map[string]string `protobuf:"bytes,3,rep,name=regex,proto3" json:"regex,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Verify []*VerifierConfig `protobuf:"bytes,4,rep,name=verify,proto3" json:"verify,omitempty"` Verify []*VerifierConfig `protobuf:"bytes,4,rep,name=verify,proto3" json:"verify,omitempty"`
Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"`
ExcludeRegexesCapture []string `protobuf:"bytes,6,rep,name=exclude_regexes_capture,json=excludeRegexesCapture,proto3" json:"exclude_regexes_capture,omitempty"` ExcludeRegexesCapture []string `protobuf:"bytes,6,rep,name=exclude_regexes_capture,json=excludeRegexesCapture,proto3" json:"exclude_regexes_capture,omitempty"`
ExcludeWords []string `protobuf:"bytes,7,rep,name=exclude_words,json=excludeWords,proto3" json:"exclude_words,omitempty"` ExcludeWords []string `protobuf:"bytes,7,rep,name=exclude_words,json=excludeWords,proto3" json:"exclude_words,omitempty"`
Entropy float32 `protobuf:"fixed32,8,opt,name=entropy,proto3" json:"entropy,omitempty"` Entropy float32 `protobuf:"fixed32,8,opt,name=entropy,proto3" json:"entropy,omitempty"`
ExcludeRegexesMatch []string `protobuf:"bytes,9,rep,name=exclude_regexes_match,json=excludeRegexesMatch,proto3" json:"exclude_regexes_match,omitempty"` ExcludeRegexesMatch []string `protobuf:"bytes,9,rep,name=exclude_regexes_match,json=excludeRegexesMatch,proto3" json:"exclude_regexes_match,omitempty"`
PrimaryRegexName string `protobuf:"bytes,10,opt,name=primary_regex_name,json=primaryRegexName,proto3" json:"primary_regex_name,omitempty"` PrimaryRegexName string `protobuf:"bytes,10,opt,name=primary_regex_name,json=primaryRegexName,proto3" json:"primary_regex_name,omitempty"`
Validations map[string]*ValidationConfig `protobuf:"bytes,11,rep,name=validations,proto3" json:"validations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
} }
func (x *CustomRegex) Reset() { func (x *CustomRegex) Reset() {
@@ -187,6 +188,13 @@ func (x *CustomRegex) GetPrimaryRegexName() string {
return "" return ""
} }
func (x *CustomRegex) GetValidations() map[string]*ValidationConfig {
if x != nil {
return x.Validations
}
return nil
}
type VerifierConfig struct { type VerifierConfig struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -258,6 +266,77 @@ func (x *VerifierConfig) GetSuccessRanges() []string {
return nil return nil
} }
type ValidationConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ContainsDigit bool `protobuf:"varint,1,opt,name=contains_digit,json=containsDigit,proto3" json:"contains_digit,omitempty"`
ContainsLowercase bool `protobuf:"varint,2,opt,name=contains_lowercase,json=containsLowercase,proto3" json:"contains_lowercase,omitempty"`
ContainsUppercase bool `protobuf:"varint,3,opt,name=contains_uppercase,json=containsUppercase,proto3" json:"contains_uppercase,omitempty"`
ContainsSpecialChar bool `protobuf:"varint,4,opt,name=contains_special_char,json=containsSpecialChar,proto3" json:"contains_special_char,omitempty"`
}
func (x *ValidationConfig) Reset() {
*x = ValidationConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_custom_detectors_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ValidationConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ValidationConfig) ProtoMessage() {}
func (x *ValidationConfig) ProtoReflect() protoreflect.Message {
mi := &file_custom_detectors_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ValidationConfig.ProtoReflect.Descriptor instead.
func (*ValidationConfig) Descriptor() ([]byte, []int) {
return file_custom_detectors_proto_rawDescGZIP(), []int{3}
}
func (x *ValidationConfig) GetContainsDigit() bool {
if x != nil {
return x.ContainsDigit
}
return false
}
func (x *ValidationConfig) GetContainsLowercase() bool {
if x != nil {
return x.ContainsLowercase
}
return false
}
func (x *ValidationConfig) GetContainsUppercase() bool {
if x != nil {
return x.ContainsUppercase
}
return false
}
func (x *ValidationConfig) GetContainsSpecialChar() bool {
if x != nil {
return x.ContainsSpecialChar
}
return false
}
var File_custom_detectors_proto protoreflect.FileDescriptor var File_custom_detectors_proto protoreflect.FileDescriptor
var file_custom_detectors_proto_rawDesc = []byte{ var file_custom_detectors_proto_rawDesc = []byte{
@@ -270,7 +349,7 @@ var file_custom_detectors_proto_rawDesc = []byte{
0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x75, 0x73, 0x74,
0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x2e, 0x43, 0x75, 0x73,
0x74, 0x6f, 0x6d, 0x52, 0x65, 0x67, 0x65, 0x78, 0x52, 0x09, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x67, 0x65, 0x78, 0x52, 0x09, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74,
0x6f, 0x72, 0x73, 0x22, 0xec, 0x03, 0x0a, 0x0b, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x6f, 0x72, 0x73, 0x22, 0xa2, 0x05, 0x0a, 0x0b, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65,
0x67, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x67, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6b, 0x65, 0x79, 0x77, 0x6f,
0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6b, 0x65, 0x79, 0x77, 0x6f,
@@ -297,25 +376,49 @@ var file_custom_detectors_proto_rawDesc = []byte{
0x67, 0x65, 0x78, 0x65, 0x73, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x67, 0x65, 0x78, 0x65, 0x73, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72,
0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x52,
0x65, 0x67, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0x38, 0x0a, 0x0a, 0x52, 0x65, 0x67, 0x65, 0x65, 0x67, 0x65, 0x78, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x69,
0x78, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e,
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x67, 0x65, 0x78, 0x2e, 0x56, 0x61, 0x6c,
0x38, 0x01, 0x22, 0x8e, 0x01, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x72, 0x43, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x76,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x52, 0x65,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x67, 0x65, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
0x6e, 0x73, 0x61, 0x66, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x6e, 0x73, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x61, 0x66, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x62, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69,
0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
0x0d, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x04, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x05, 0x76, 0x61,
0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x61, 0x6e, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x75, 0x73, 0x74,
0x67, 0x65, 0x73, 0x42, 0x44, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x2e, 0x56, 0x61, 0x6c,
0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x76,
0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8e, 0x01, 0x0a, 0x0e, 0x56, 0x65, 0x72,
0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x64, 0x65, 0x69, 0x66, 0x69, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x24, 0x0a, 0x08, 0x65,
0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa,
0x33, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x6e, 0x73, 0x61, 0x66, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x08, 0x52, 0x06, 0x75, 0x6e, 0x73, 0x61, 0x66, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64,
0x65, 0x72, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x61,
0x6e, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x75, 0x63, 0x63,
0x65, 0x73, 0x73, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0xcb, 0x01, 0x0a, 0x10, 0x56, 0x61,
0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x25,
0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x5f, 0x64, 0x69, 0x67, 0x69, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73,
0x44, 0x69, 0x67, 0x69, 0x74, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x73, 0x5f, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x08, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x4c, 0x6f, 0x77, 0x65, 0x72,
0x63, 0x61, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73,
0x5f, 0x75, 0x70, 0x70, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
0x52, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x55, 0x70, 0x70, 0x65, 0x72, 0x63,
0x61, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x5f,
0x73, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x72, 0x18, 0x04, 0x20, 0x01,
0x28, 0x08, 0x52, 0x13, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x53, 0x70, 0x65, 0x63,
0x69, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x72, 0x42, 0x44, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, 0x65, 0x63,
0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67,
0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f,
0x6d, 0x5f, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -330,22 +433,26 @@ func file_custom_detectors_proto_rawDescGZIP() []byte {
return file_custom_detectors_proto_rawDescData return file_custom_detectors_proto_rawDescData
} }
var file_custom_detectors_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_custom_detectors_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_custom_detectors_proto_goTypes = []interface{}{ var file_custom_detectors_proto_goTypes = []interface{}{
(*CustomDetectors)(nil), // 0: custom_detectors.CustomDetectors (*CustomDetectors)(nil), // 0: custom_detectors.CustomDetectors
(*CustomRegex)(nil), // 1: custom_detectors.CustomRegex (*CustomRegex)(nil), // 1: custom_detectors.CustomRegex
(*VerifierConfig)(nil), // 2: custom_detectors.VerifierConfig (*VerifierConfig)(nil), // 2: custom_detectors.VerifierConfig
nil, // 3: custom_detectors.CustomRegex.RegexEntry (*ValidationConfig)(nil), // 3: custom_detectors.ValidationConfig
nil, // 4: custom_detectors.CustomRegex.RegexEntry
nil, // 5: custom_detectors.CustomRegex.ValidationsEntry
} }
var file_custom_detectors_proto_depIdxs = []int32{ var file_custom_detectors_proto_depIdxs = []int32{
1, // 0: custom_detectors.CustomDetectors.detectors:type_name -> custom_detectors.CustomRegex 1, // 0: custom_detectors.CustomDetectors.detectors:type_name -> custom_detectors.CustomRegex
3, // 1: custom_detectors.CustomRegex.regex:type_name -> custom_detectors.CustomRegex.RegexEntry 4, // 1: custom_detectors.CustomRegex.regex:type_name -> custom_detectors.CustomRegex.RegexEntry
2, // 2: custom_detectors.CustomRegex.verify:type_name -> custom_detectors.VerifierConfig 2, // 2: custom_detectors.CustomRegex.verify:type_name -> custom_detectors.VerifierConfig
3, // [3:3] is the sub-list for method output_type 5, // 3: custom_detectors.CustomRegex.validations:type_name -> custom_detectors.CustomRegex.ValidationsEntry
3, // [3:3] is the sub-list for method input_type 3, // 4: custom_detectors.CustomRegex.ValidationsEntry.value:type_name -> custom_detectors.ValidationConfig
3, // [3:3] is the sub-list for extension type_name 5, // [5:5] is the sub-list for method output_type
3, // [3:3] is the sub-list for extension extendee 5, // [5:5] is the sub-list for method input_type
0, // [0:3] is the sub-list for field type_name 5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
} }
func init() { file_custom_detectors_proto_init() } func init() { file_custom_detectors_proto_init() }
@@ -390,6 +497,18 @@ func file_custom_detectors_proto_init() {
return nil return nil
} }
} }
file_custom_detectors_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ValidationConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
} }
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
@@ -397,7 +516,7 @@ func file_custom_detectors_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_custom_detectors_proto_rawDesc, RawDescriptor: file_custom_detectors_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 4, NumMessages: 6,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },
@@ -235,6 +235,52 @@ func (m *CustomRegex) validate(all bool) error {
// no validation rules for PrimaryRegexName // no validation rules for PrimaryRegexName
{
sorted_keys := make([]string, len(m.GetValidations()))
i := 0
for key := range m.GetValidations() {
sorted_keys[i] = key
i++
}
sort.Slice(sorted_keys, func(i, j int) bool { return sorted_keys[i] < sorted_keys[j] })
for _, key := range sorted_keys {
val := m.GetValidations()[key]
_ = val
// no validation rules for Validations[key]
if all {
switch v := interface{}(val).(type) {
case interface{ ValidateAll() error }:
if err := v.ValidateAll(); err != nil {
errors = append(errors, CustomRegexValidationError{
field: fmt.Sprintf("Validations[%v]", key),
reason: "embedded message failed validation",
cause: err,
})
}
case interface{ Validate() error }:
if err := v.Validate(); err != nil {
errors = append(errors, CustomRegexValidationError{
field: fmt.Sprintf("Validations[%v]", key),
reason: "embedded message failed validation",
cause: err,
})
}
}
} else if v, ok := interface{}(val).(interface{ Validate() error }); ok {
if err := v.Validate(); err != nil {
return CustomRegexValidationError{
field: fmt.Sprintf("Validations[%v]", key),
reason: "embedded message failed validation",
cause: err,
}
}
}
}
}
if len(errors) > 0 { if len(errors) > 0 {
return CustomRegexMultiError(errors) return CustomRegexMultiError(errors)
} }
@@ -425,3 +471,111 @@ var _ interface {
Cause() error Cause() error
ErrorName() string ErrorName() string
} = VerifierConfigValidationError{} } = VerifierConfigValidationError{}
// Validate checks the field values on ValidationConfig with the rules defined
// in the proto definition for this message. If any rules are violated, the
// first error encountered is returned, or nil if there are no violations.
func (m *ValidationConfig) Validate() error {
return m.validate(false)
}
// ValidateAll checks the field values on ValidationConfig with the rules
// defined in the proto definition for this message. If any rules are
// violated, the result is a list of violation errors wrapped in
// ValidationConfigMultiError, or nil if none found.
func (m *ValidationConfig) ValidateAll() error {
return m.validate(true)
}
func (m *ValidationConfig) validate(all bool) error {
if m == nil {
return nil
}
var errors []error
// no validation rules for ContainsDigit
// no validation rules for ContainsLowercase
// no validation rules for ContainsUppercase
// no validation rules for ContainsSpecialChar
if len(errors) > 0 {
return ValidationConfigMultiError(errors)
}
return nil
}
// ValidationConfigMultiError is an error wrapping multiple validation errors
// returned by ValidationConfig.ValidateAll() if the designated constraints
// aren't met.
type ValidationConfigMultiError []error
// Error returns a concatenation of all the error messages it wraps.
func (m ValidationConfigMultiError) Error() string {
var msgs []string
for _, err := range m {
msgs = append(msgs, err.Error())
}
return strings.Join(msgs, "; ")
}
// AllErrors returns a list of validation violation errors.
func (m ValidationConfigMultiError) AllErrors() []error { return m }
// ValidationConfigValidationError is the validation error returned by
// ValidationConfig.Validate if the designated constraints aren't met.
type ValidationConfigValidationError struct {
field string
reason string
cause error
key bool
}
// Field function returns field value.
func (e ValidationConfigValidationError) Field() string { return e.field }
// Reason function returns reason value.
func (e ValidationConfigValidationError) Reason() string { return e.reason }
// Cause function returns cause value.
func (e ValidationConfigValidationError) Cause() error { return e.cause }
// Key function returns key value.
func (e ValidationConfigValidationError) Key() bool { return e.key }
// ErrorName returns error name.
func (e ValidationConfigValidationError) ErrorName() string { return "ValidationConfigValidationError" }
// Error satisfies the builtin error interface
func (e ValidationConfigValidationError) Error() string {
cause := ""
if e.cause != nil {
cause = fmt.Sprintf(" | caused by: %v", e.cause)
}
key := ""
if e.key {
key = "key for "
}
return fmt.Sprintf(
"invalid %sValidationConfig.%s: %s%s",
key,
e.field,
e.reason,
cause)
}
var _ error = ValidationConfigValidationError{}
var _ interface {
Field() string
Reason() string
Key() bool
Cause() error
ErrorName() string
} = ValidationConfigValidationError{}
+8
View File
@@ -21,6 +21,7 @@ message CustomRegex {
float entropy = 8; float entropy = 8;
repeated string exclude_regexes_match = 9; repeated string exclude_regexes_match = 9;
string primary_regex_name = 10; string primary_regex_name = 10;
map<string, ValidationConfig> validations = 11;
} }
@@ -30,3 +31,10 @@ message VerifierConfig {
repeated string headers = 3; repeated string headers = 3;
repeated string successRanges = 4; repeated string successRanges = 4;
} }
message ValidationConfig {
bool contains_digit = 1;
bool contains_lowercase = 2;
bool contains_uppercase = 3;
bool contains_special_char = 4;
}