package config import ( "strings" "unicode" "tug/internal/platform/userbasekeys" ) const ( reasonConfigKnownHostsUnused = "set only when remote is an ssh:// URL" reasonBranch = "must be a branch name without \"..\", \"//\", a leading or trailing \"/\", spaces, control characters or any of ~^:?*[\\, and not HEAD" ) func (v *validator) configGit(g *rawConfigGit) *ConfigGit { if g == nil { g = &rawConfigGit{} } remoteValid := v.required("config.git.remote", g.Remote) && v.remote("config.git.remote", g.Remote) if v.required("config.git.branch", g.Branch) { v.branch("config.git.branch", g.Branch) } if v.required("config.git.allowed_signers", g.AllowedSigners) { v.absolutePath("config.git.allowed_signers", g.AllowedSigners) } switch { case !remoteValid: case v.idx.has("config.git.known_hosts") && !usesSSH(g.Remote): v.add("config.git.known_hosts", reasonConfigKnownHostsUnused) case v.idx.has("config.git.known_hosts"): v.absolutePath("config.git.known_hosts", g.KnownHosts) case usesSSH(g.Remote): v.add("config.git.known_hosts", reasonRequired) } return &ConfigGit{Remote: g.Remote, Branch: g.Branch, AllowedSigners: g.AllowedSigners, KnownHosts: g.KnownHosts} } func (v *validator) branch(key, value string) { ok := value != "HEAD" && !strings.Contains(value, "..") && !strings.Contains(value, "//") && !strings.HasPrefix(value, "/") && !strings.HasSuffix(value, "/") && !strings.ContainsAny(value, "~^:?*[\\") for _, r := range value { if unicode.IsControl(r) || unicode.IsSpace(r) { ok = false } } if !ok { v.add(key, reasonBranch) } } func (g *ConfigGit) SSH() bool { return usesSSH(g.Remote) } func checkConfigSecrets(file string, vars map[string]secretLine, s Secrets) []Problem { if s.ConfigDeployKey.isZero() { return nil } if _, err := userbasekeys.ParseSigner(s.ConfigDeployKey.Bytes()); err != nil { return []Problem{{File: file, Line: vars[nameConfigRepoKey].line, Key: nameConfigRepoKey, Reason: keyFileReason(err)}} } return nil }