goherence/internal/lint/rules_shell.go
2026-09-11 10:17:25 +03:00

55 lines
2.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package lint
import (
"strings"
"github.com/vladimir/goherence/internal/parser"
)
// shellToModuleHints — известные паттерны команд, для которых есть
// прямой декларативный модуль. Список расширяется по мере роста
// internal/module/builtin — если добавляешь builtin-модуль, стоит
// сразу подумать, какие shell-паттерны он делает лишними.
var shellToModuleHints = map[string]string{
"apt-get install": "apt",
"apt install": "apt",
"yum install": "rpm_package",
"dnf install": "rpm_package",
"systemctl": "systemd",
"mkdir -p": "file (state=directory)",
"chmod": "file (mode=...)",
"rm -rf": "file (state=absent)",
}
// ShellUsageRule ловит использование shell/command там, где уже есть
// builtin-модуль с тем же эффектом, но идемпотентный по своей природе.
// Единственный способ обойти правило — явная пометка allow_shell: true
// прямо на таске: она остаётся видна в коде плейбука навсегда, так что
// причина обхода на виду у любого, кто читает файл при code review.
type ShellUsageRule struct{}
func (r *ShellUsageRule) Name() string { return "shell-usage" }
func (r *ShellUsageRule) Check(pb *parser.Playbook) []Violation {
var out []Violation
walkTasks(pb, func(loc string, t *parser.Task) {
if t.Module != "shell" && t.Module != "command" {
return
}
if t.AllowShell {
return
}
cmd, _ := t.Args["cmd"].(string)
for pattern, alt := range shellToModuleHints {
if strings.Contains(cmd, pattern) {
out = append(out, Violation{
Rule: r.Name(), Severity: Error, Location: loc,
Message: "используй декларативный модуль " + alt +
" вместо shell/command, либо явно пометь таск allow_shell: true: " + cmd,
})
return // одного совпадения достаточно, не дублируем сообщение
}
}
})
return out
}