45 lines
2.1 KiB
Go
45 lines
2.1 KiB
Go
package lint
|
||
|
||
import (
|
||
"regexp"
|
||
|
||
"github.com/vladimir/goherence/internal/parser"
|
||
)
|
||
|
||
// WhenGrammarRule разрешает в `when` только чистые предикаты:
|
||
// сравнения (==, !=, <, >, <=, >=), логику (and, or, not) и обращения
|
||
// к переменным. Вызов функций (sprig или любых других) в when запрещён —
|
||
// это первый и самый частый путь протащить в условие вычисление с
|
||
// побочным эффектом (случайные числа, текущее время, счётчики).
|
||
//
|
||
// Реализация первой версии — не полноценный парсер выражений, а
|
||
// консервативный regex-фильтр: ищем характерный синтаксис вызова функции
|
||
// `имя(...)` и паттерн `| filterName` (пайп — тоже вызов функции в Go-шаблонах).
|
||
// Ложные срабатывания возможны и это осознанный компромисс: лучше
|
||
// требовать явный allow_shell-подобный обход, чем пропустить реальный вызов.
|
||
type WhenGrammarRule struct{}
|
||
|
||
func (r *WhenGrammarRule) Name() string { return "when-grammar" }
|
||
|
||
var (
|
||
funcCallPattern = regexp.MustCompile(`[a-zA-Z_][a-zA-Z0-9_]*\s*\(`)
|
||
pipePattern = regexp.MustCompile(`\|\s*[a-zA-Z_]`)
|
||
)
|
||
|
||
func (r *WhenGrammarRule) Check(pb *parser.Playbook) []Violation {
|
||
var out []Violation
|
||
walkTasks(pb, func(loc string, t *parser.Task) {
|
||
if t.When == "" {
|
||
return
|
||
}
|
||
if funcCallPattern.MatchString(t.When) || pipePattern.MatchString(t.When) {
|
||
out = append(out, Violation{
|
||
Rule: r.Name(), Severity: Error, Location: loc,
|
||
Message: "when-выражение должно быть чистым предикатом " +
|
||
"(сравнения / and / or / not над переменными), вызовы функций и " +
|
||
"фильтры (|) внутри when запрещены: " + t.When,
|
||
})
|
||
}
|
||
})
|
||
return out
|
||
}
|