fix(worker): harden control-plane lifecycle
Все проверки выполнены успешно
CI / test (push) Successful in 2m32s
Docker / Build and publish worker image (push) Successful in 18m17s

- reconnect safely after token rotation and retry leased results
- reject malformed tasks and remove production cluster debug mutation
- validate environment files and require immutable container images

BREAKING CHANGE: Docker install, deploy, and Compose now require an
immutable repository@sha256 image reference.
Этот коммит содержится в:
Gleb Tv
2026-07-19 23:11:43 +03:00
родитель 6937674449
Коммит e987f24903
38 изменённых файлов: 2203 добавлений и 674 удалений

Просмотреть файл

@@ -10,13 +10,17 @@ import (
"path/filepath"
"regexp"
"strings"
"unicode"
)
var dockerImagePattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._/:@-]*$`)
var (
dockerImagePattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._/:-]*@sha256:[a-f0-9]{64}$`)
envKeyPattern = regexp.MustCompile(`^[A-Za-z_][A-Za-z0-9_]*$`)
)
const (
DefaultURL = "https://rsmon.ru"
DefaultImage = "reg.rsxx.ru/rsmon/rsmon-worker:latest"
DefaultImage = ""
binaryPath = "/usr/local/bin/rsmon-worker"
envPath = "/etc/rsmon-worker/worker.env"
unitPath = "/etc/systemd/system/rsmon-worker.service"
@@ -74,7 +78,11 @@ func Install(opts InstallOptions) error {
if err := ValidateURL(opts.URL); err != nil {
return err
}
if opts.EnvFile == "" {
if opts.EnvFile != "" {
if err := ValidateEnvironmentFile(opts.EnvFile); err != nil {
return err
}
} else {
if err := ValidateToken(opts.Token); err != nil {
return err
}
@@ -156,9 +164,50 @@ func ValidateToken(token string) error {
return nil
}
// ValidateEnvironmentFile checks the worker credentials before installation
// changes the binary, systemd unit, or Docker image on the host.
func ValidateEnvironmentFile(path string) error {
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("read worker environment: %w", err)
}
values := make(map[string]string)
seenRequired := make(map[string]bool)
for number, line := range strings.Split(string(data), "\n") {
lineNumber := number + 1
if line == "" || strings.HasPrefix(line, "#") {
continue
}
if strings.ContainsRune(line, '\r') {
return fmt.Errorf("worker environment line %d contains a carriage return", lineNumber)
}
key, value, ok := strings.Cut(line, "=")
if !ok || !envKeyPattern.MatchString(key) {
return fmt.Errorf("worker environment line %d must use KEY=VALUE syntax", lineNumber)
}
if strings.IndexFunc(value, unicode.IsSpace) >= 0 || strings.ContainsAny(value, "$\\\"'") {
return fmt.Errorf("worker environment line %d uses unsupported quoting, interpolation, or whitespace", lineNumber)
}
if key == "RSMON_URL" || key == "RSMON_TOKEN" {
if seenRequired[key] {
return fmt.Errorf("worker environment line %d duplicates %s", lineNumber, key)
}
seenRequired[key] = true
}
values[key] = value
}
if err := ValidateURL(values["RSMON_URL"]); err != nil {
return err
}
if err := ValidateToken(values["RSMON_TOKEN"]); err != nil {
return err
}
return nil
}
func ValidateImage(image string) error {
if !dockerImagePattern.MatchString(image) {
return errors.New("Docker image must be one non-option argument")
return errors.New("Docker image must be an immutable repository@sha256:<64 lowercase hex characters> reference")
}
return nil
}