mirror of
https://github.com/larksuite/cli.git
synced 2026-07-07 00:55:53 +08:00
204 lines
4.6 KiB
Go
204 lines
4.6 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package semantic
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
|
|
"github.com/larksuite/cli/internal/qualitygate/facts"
|
|
)
|
|
|
|
type FactScope struct {
|
|
FactKind string
|
|
Domain string
|
|
Changed bool
|
|
Source string
|
|
SourceFile string
|
|
Line int
|
|
CommandPath string
|
|
}
|
|
|
|
func scopesForFinding(f facts.Facts, finding Finding) ([]FactScope, bool) {
|
|
scopes := make([]FactScope, 0, len(finding.Evidence))
|
|
for _, ev := range finding.Evidence {
|
|
kind, idx, ok := parseEvidence(ev)
|
|
if !ok || !evidenceExists(f, kind, idx) {
|
|
return nil, false
|
|
}
|
|
scope, ok := factScope(f, kind, idx)
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
scopes = append(scopes, scope)
|
|
}
|
|
return scopes, true
|
|
}
|
|
|
|
func factScope(f facts.Facts, kind string, idx int) (FactScope, bool) {
|
|
switch kind {
|
|
case "commands":
|
|
item := f.Commands[idx]
|
|
return FactScope{
|
|
FactKind: "command",
|
|
Domain: item.Domain,
|
|
Changed: item.Changed,
|
|
Source: item.Source,
|
|
CommandPath: item.Path,
|
|
}, true
|
|
case "skills":
|
|
item := f.Skills[idx]
|
|
return FactScope{
|
|
FactKind: "skill",
|
|
Domain: item.Domain,
|
|
Changed: item.Changed,
|
|
Source: item.Source,
|
|
SourceFile: item.SourceFile,
|
|
Line: item.Line,
|
|
CommandPath: item.CommandPath,
|
|
}, true
|
|
case "errors":
|
|
item := f.Errors[idx]
|
|
commandPath := item.CommandPath
|
|
if commandPath == "" {
|
|
commandPath = item.Command
|
|
}
|
|
return FactScope{
|
|
FactKind: "error",
|
|
Domain: item.Domain,
|
|
Changed: item.Changed,
|
|
Source: item.Source,
|
|
SourceFile: item.File,
|
|
Line: item.Line,
|
|
CommandPath: commandPath,
|
|
}, true
|
|
case "outputs":
|
|
item := f.Outputs[idx]
|
|
return FactScope{
|
|
FactKind: "output",
|
|
Domain: item.Domain,
|
|
Changed: item.Changed,
|
|
Source: item.Source,
|
|
CommandPath: item.Command,
|
|
}, true
|
|
default:
|
|
return FactScope{}, false
|
|
}
|
|
}
|
|
|
|
func matchingRolloutGroups(policy Policy, finding Finding, scopes []FactScope) []string {
|
|
var matched []string
|
|
for _, group := range policy.RolloutGroups {
|
|
if group.Enforcement != "blocking" || !containsString(group.Categories, finding.Category) {
|
|
continue
|
|
}
|
|
allMatch := true
|
|
for _, scope := range scopes {
|
|
if !scopeMatches(group.Scope, scope) {
|
|
allMatch = false
|
|
break
|
|
}
|
|
}
|
|
if allMatch {
|
|
matched = append(matched, group.ID)
|
|
}
|
|
}
|
|
return matched
|
|
}
|
|
|
|
func scopeMatches(selector ScopeSelector, scope FactScope) bool {
|
|
if selector.ChangedOnly && !scope.Changed {
|
|
return false
|
|
}
|
|
if len(selector.Domains) > 0 && !containsString(selector.Domains, scope.Domain) {
|
|
return false
|
|
}
|
|
if len(selector.FactKinds) > 0 && !containsString(selector.FactKinds, scope.FactKind) {
|
|
return false
|
|
}
|
|
if len(selector.Sources) > 0 && (scope.Source == "" || !containsString(selector.Sources, scope.Source)) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (w Waivers) MatchFinding(category string, scopes []FactScope) (string, []string, bool) {
|
|
if len(scopes) == 0 || len(w.Items) == 0 {
|
|
return "", nil, false
|
|
}
|
|
common := map[string][]string{}
|
|
for i, scope := range scopes {
|
|
matches := map[string][]string{}
|
|
for _, item := range w.Items {
|
|
if !waiverMatchesScope(item, category, scope) {
|
|
continue
|
|
}
|
|
matches[item.ID] = append(matches[item.ID], waiverKey(item))
|
|
}
|
|
if len(matches) == 0 {
|
|
return "", nil, false
|
|
}
|
|
if i == 0 {
|
|
common = matches
|
|
continue
|
|
}
|
|
for id, keys := range common {
|
|
next, ok := matches[id]
|
|
if !ok {
|
|
delete(common, id)
|
|
continue
|
|
}
|
|
common[id] = append(keys, next...)
|
|
}
|
|
}
|
|
ids := make([]string, 0, len(common))
|
|
for id := range common {
|
|
ids = append(ids, id)
|
|
}
|
|
sort.Strings(ids)
|
|
for _, id := range ids {
|
|
keys := common[id]
|
|
return id, keys, true
|
|
}
|
|
return "", nil, false
|
|
}
|
|
|
|
func waiverMatchesScope(item Waiver, category string, scope FactScope) bool {
|
|
if item.Category != category || item.FactKind != scope.FactKind {
|
|
return false
|
|
}
|
|
if item.SourceFile != "" && item.SourceFile != scope.SourceFile {
|
|
return false
|
|
}
|
|
if item.Line != 0 && item.Line != scope.Line {
|
|
return false
|
|
}
|
|
if item.CommandPath != "" && item.CommandPath != scope.CommandPath {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func waiverKey(item Waiver) string {
|
|
return fmt.Sprintf("%s:%s:%s:%s:%d:%s", item.ID, item.Category, item.FactKind, item.SourceFile, item.Line, item.CommandPath)
|
|
}
|
|
|
|
func containsString(values []string, want string) bool {
|
|
for _, value := range values {
|
|
if value == want {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func allowedFactKind(kind string) bool {
|
|
switch kind {
|
|
case "skill", "command", "error", "output":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|