168 lines
3.6 KiB
Go
168 lines
3.6 KiB
Go
// ©AngelaMos | 2026
|
|
// registry.go
|
|
|
|
package rules
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/CarterPerez-dev/portia/pkg/types"
|
|
)
|
|
|
|
type Registry struct {
|
|
rules map[string]*types.Rule
|
|
disabled map[string]bool
|
|
}
|
|
|
|
func NewRegistry() *Registry {
|
|
return &Registry{
|
|
rules: make(map[string]*types.Rule),
|
|
disabled: make(map[string]bool),
|
|
}
|
|
}
|
|
|
|
func (r *Registry) Register(rule *types.Rule) {
|
|
if _, exists := r.rules[rule.ID]; exists {
|
|
panic(fmt.Sprintf(
|
|
"duplicate rule ID: %s", rule.ID,
|
|
))
|
|
}
|
|
r.rules[rule.ID] = rule
|
|
}
|
|
|
|
func (r *Registry) Get(
|
|
id string,
|
|
) (*types.Rule, bool) {
|
|
rule, ok := r.rules[id]
|
|
if !ok || r.disabled[id] {
|
|
return nil, false
|
|
}
|
|
return rule, true
|
|
}
|
|
|
|
func (r *Registry) All() []*types.Rule {
|
|
result := make([]*types.Rule, 0, len(r.rules))
|
|
for _, rule := range r.rules {
|
|
if !r.disabled[rule.ID] {
|
|
result = append(result, rule)
|
|
}
|
|
}
|
|
sort.Slice(result, func(i, j int) bool {
|
|
return result[i].ID < result[j].ID
|
|
})
|
|
return result
|
|
}
|
|
|
|
func (r *Registry) Disable(ids ...string) {
|
|
for _, id := range ids {
|
|
r.disabled[id] = true
|
|
}
|
|
}
|
|
|
|
func (r *Registry) MatchKeywords(
|
|
content string,
|
|
) []*types.Rule {
|
|
lower := strings.ToLower(content)
|
|
var matched []*types.Rule
|
|
|
|
for _, rule := range r.rules {
|
|
if r.disabled[rule.ID] {
|
|
continue
|
|
}
|
|
for _, kw := range rule.Keywords {
|
|
if strings.Contains(lower, strings.ToLower(kw)) {
|
|
matched = append(matched, rule)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return matched
|
|
}
|
|
|
|
func (r *Registry) Len() int {
|
|
count := 0
|
|
for id := range r.rules {
|
|
if !r.disabled[id] {
|
|
count++
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
func (r *Registry) Replace(rule *types.Rule) {
|
|
r.rules[rule.ID] = rule
|
|
}
|
|
|
|
var GlobalPathAllowlist = []*regexp.Regexp{
|
|
regexp.MustCompile(
|
|
`go\.(?:mod|sum|work(?:\.sum)?)$`,
|
|
),
|
|
regexp.MustCompile(
|
|
`(?:^|/)(?:package-lock\.json|pnpm-lock\.yaml|` +
|
|
`yarn\.lock|npm-shrinkwrap\.json|deno\.lock|` +
|
|
`Cargo\.lock|composer\.lock|Gemfile\.lock|` +
|
|
`poetry\.lock|Pipfile\.lock|mix\.lock|` +
|
|
`pubspec\.lock|Podfile\.lock|flake\.lock|` +
|
|
`bun\.lockb)$`,
|
|
),
|
|
regexp.MustCompile(`(?:^|/)node_modules/`),
|
|
regexp.MustCompile(`(?:^|/)vendor/`),
|
|
regexp.MustCompile(`(?:^|/)\.git/`),
|
|
regexp.MustCompile(`(?:^|/)\.svn/`),
|
|
regexp.MustCompile(`(?:^|/)\.hg/`),
|
|
regexp.MustCompile(
|
|
`(?:^|/)(?:__pycache__|\.venv|venv|\.tox|` +
|
|
`\.mypy_cache|\.pytest_cache|\.ruff_cache|` +
|
|
`\.eggs|.*\.egg-info)/`,
|
|
),
|
|
regexp.MustCompile(
|
|
`(?:^|/)(?:\.next|\.nuxt|\.svelte-kit|` +
|
|
`\.terraform|\.gradle|\.mvn|\.bundle|` +
|
|
`Pods|coverage|\.nyc_output)/`,
|
|
),
|
|
regexp.MustCompile(
|
|
`(?:^|/)(?:target|build|dist|out)/`,
|
|
),
|
|
regexp.MustCompile(
|
|
`\.min\.(?:js|css)(?:\.map)?$`,
|
|
),
|
|
regexp.MustCompile(
|
|
`\.(?:png|jpg|jpeg|gif|ico|svg|woff2?|ttf|eot|otf|` +
|
|
`mp[34]|avi|mkv|mov|zip|tar|gz|rar|7z|pdf|exe|` +
|
|
`dll|so|dylib)$`,
|
|
),
|
|
regexp.MustCompile(`dist-info/`),
|
|
}
|
|
|
|
var GlobalValueAllowlist = []*regexp.Regexp{
|
|
regexp.MustCompile(
|
|
`(?i)^(?:example|test|dummy|fake|placeholder|` +
|
|
`sample|your[-_]?(?:api[-_]?key|token|` +
|
|
`secret|password))`,
|
|
),
|
|
regexp.MustCompile(`^x{4,}$`),
|
|
regexp.MustCompile(`^\*{4,}$`),
|
|
regexp.MustCompile(`^\$\{.+\}$`),
|
|
regexp.MustCompile(`^\{\{.+\}\}$`),
|
|
regexp.MustCompile(`^<[A-Z_]{2,}>$`),
|
|
regexp.MustCompile(`^0{8,}$`),
|
|
regexp.MustCompile(
|
|
`^(?:1{8,}|2{8,}|3{8,}|4{8,}|5{8,}|6{8,}|7{8,}|8{8,}|9{8,})$`,
|
|
),
|
|
regexp.MustCompile(
|
|
`(?i)^(?:none|null|nil|undefined|true|false|` +
|
|
`TODO|FIXME|CHANGEME|INSERT|REPLACE|` +
|
|
`REDACTED|N/A|TBD|REMOVED|MASKED|` +
|
|
`changeit|s3cr3t|p@ssw0rd|admin123)$`,
|
|
),
|
|
regexp.MustCompile(
|
|
`(?i)^(?:dGVzdA==|cGFzc3dvcmQ=|YWRtaW4=)$`,
|
|
),
|
|
regexp.MustCompile(
|
|
`(?i)^(?:PUT_YOUR_|ENTER_YOUR_|ADD_YOUR_)`,
|
|
),
|
|
}
|