-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat(piipolicy): add policy-based automatic PII detection and dynamic… #3506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,192 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Copyright 2026 Google LLC | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // you may not use this file except in compliance with the License. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // You may obtain a copy of the License at | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Unless required by applicable law or agreed to in writing, software | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // See the License for the specific language governing permissions and | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // limitations under the License. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package piipolicy | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "context" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "encoding/json" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "regexp" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "strings" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ApplyPolicy evaluates the PII policy against the provided data given the user's claims. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func ApplyPolicy(ctx context.Context, config Config, claims map[string]any, data any) (any, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(config.Rules) == 0 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return data, nil // Nothing to do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Determine the user's tier based on the claim | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tier := "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if config.TierClaim != "" && claims != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if val, ok := claims[config.TierClaim]; ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if strVal, ok := val.(string); ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tier = strVal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| switch v := data.(type) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case string: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return applyToString(v, config.Rules, tier) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case map[string]any: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return applyToMap(ctx, config, claims, tier, v) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case []map[string]any: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return applyToMapSlice(ctx, config, claims, tier, v) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case []any: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var out []any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, el := range v { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res, err := ApplyPolicy(ctx, config, claims, el) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out = append(out, res) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return out, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+57
to
+58
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correctness & Efficiency: Prevent Type Mutation of PrimitivesCurrently, any primitive type other than
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Attempt to convert struct to map/slice using JSON | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bytes, err := json.Marshal(data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var parsed any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err := json.Unmarshal(bytes, &parsed); err == nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Prevent infinite loop if type doesn't change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if fmt.Sprintf("%T", parsed) != fmt.Sprintf("%T", data) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ApplyPolicy(ctx, config, claims, parsed) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Unsupported type, return as is | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return data, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func getActionForRule(rule Rule, tier string) Action { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if action, ok := rule.Actions[tier]; ok && tier != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return action | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if action, ok := rule.Actions["default"]; ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return action | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fallback secure default | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return MaskFull | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func applyToString(data string, rules []Rule, tier string) (string, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result := data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, rule := range rules { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if rule.Pattern == "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue // Column-based rule, skip for unstructured text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| action := getActionForRule(rule, tier) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if action == Unmask { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| re, err := regexp.Compile(rule.Pattern) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "", fmt.Errorf("invalid pattern in rule %q: %w", rule.Name, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+97
to
+100
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Performance: Use Cached RegexUse the newly introduced
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = re.ReplaceAllStringFunc(result, func(match string) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return applyActionToString(action, match) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return result, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func applyToMapSlice(ctx context.Context, config Config, claims map[string]any, tier string, data []map[string]any) ([]map[string]any, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| var out []map[string]any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, m := range data { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res, err := applyToMap(ctx, config, claims, tier, m) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out = append(out, res) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return out, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func applyToMap(ctx context.Context, config Config, claims map[string]any, tier string, data map[string]any) (map[string]any, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out := make(map[string]any, len(data)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for k, v := range data { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| res, err := ApplyPolicy(ctx, config, claims, v) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out[k] = res | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, rule := range config.Rules { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if rule.Column == "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Try applying pattern if value is a string, even in structured data | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if rule.Pattern != "" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for k, v := range out { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if strVal, ok := v.(string); ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| action := getActionForRule(rule, tier) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if action == Unmask { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| re, err := regexp.Compile(rule.Pattern) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("invalid pattern in rule %q: %w", rule.Name, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out[k] = re.ReplaceAllStringFunc(strVal, func(match string) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return applyActionToString(action, match) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+134
to
+151
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Performance: Hoist Action Check and Regex CompilationIn
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Exact column match | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if val, exists := out[rule.Column]; exists { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| action := getActionForRule(rule, tier) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if action == Unmask { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if action == DenyField { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out[rule.Column] = "[DENIED]" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Apply masking | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if strVal, ok := val.(string); ok { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out[rule.Column] = applyActionToString(action, strVal) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Non-string value masked entirely | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out[rule.Column] = "***" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return out, nil | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func applyActionToString(action Action, val string) string { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| switch action { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case MaskFull: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return strings.Repeat("*", len(val)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case MaskPartial: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(val) <= 2 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return strings.Repeat("*", len(val)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| visibleLen := len(val) / 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return val[:visibleLen] + strings.Repeat("*", len(val)-visibleLen) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case DenyField: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return "[DENIED]" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return val // Unmask or unknown | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Deeven-Seru marked this conversation as resolved.
Comment on lines
+177
to
+192
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correctness: Handle Multi-Byte UTF-8 Characters CorrectlyIn Go, Additionally, slicing a string using byte indices (
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Performance & Correctness: Thread-Safe Regex Cache
Regex compilation via
regexp.Compileis an expensive operation. Currently, regexes are compiled on the fly during every string evaluation. Introducing a thread-safe cache usingsync.Mapavoids redundant compilation and significantly improves performance, especially when processing large datasets.