talos
115 строк · 2.7 Кб
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5package extensions6
7import (8"fmt"9"io/fs"10"os"11"path/filepath"12"strings"13
14"github.com/blang/semver/v4"15
16"github.com/siderolabs/talos/pkg/machinery/version"17)
18
19// Validate the extension: compatibility, contents, etc.
20func (ext *Extension) Validate() error {21if err := ext.validateConstraints(); err != nil {22return err23}24
25return ext.validateContents()26}
27
28func (ext *Extension) validateConstraints() error {29constraint := ext.Manifest.Metadata.Compatibility.Talos.Version30
31if constraint != "" {32talosVersion, err := semver.ParseTolerant(version.Tag)33if err != nil {34return err35}36
37versionConstraint, err := semver.ParseRange(trim(constraint))38if err != nil {39return fmt.Errorf("error parsing Talos version constraint: %w", err)40}41
42if !versionConstraint(coreVersion(talosVersion)) {43return fmt.Errorf("version constraint %s can't be satisfied with Talos version %s", constraint, talosVersion)44}45}46
47return nil48}
49
50// trim removes 'v' symbol anywhere in string if it's located before the number.
51func trim(constraint string) string {52for i := 0; i < len(constraint); i++ {53if constraint[i] == 'v' && i+1 < len(constraint) && constraint[i+1] >= '0' && constraint[i+1] <= '9' {54constraint = constraint[:i] + constraint[i+1:]55}56}57
58return constraint59}
60
61func coreVersion(talosVersion semver.Version) semver.Version {62return semver.Version{63Major: talosVersion.Major,64Minor: talosVersion.Minor,65Patch: talosVersion.Patch,66}67}
68
69//nolint:gocyclo
70func (ext *Extension) validateContents() error {71return filepath.WalkDir(ext.rootfsPath, func(path string, d fs.DirEntry, err error) error {72if err != nil {73return err74}75
76itemPath, err := filepath.Rel(ext.rootfsPath, path)77if err != nil {78return err79}80
81itemPath = filepath.Join("/", itemPath)82
83// check for -------w-84if d.Type().Perm()&0o002 > 0 {85return fmt.Errorf("world-writeable files are not allowed: %q", itemPath)86}87
88// no special files89if !d.IsDir() && !d.Type().IsRegular() && d.Type().Type() != os.ModeSymlink {90return fmt.Errorf("special files are not allowed: %q", itemPath)91}92
93// regular file: check for file path being whitelisted94if !d.IsDir() {95allowed := false96
97for _, allowedPath := range AllowedPaths {98if strings.HasPrefix(itemPath, allowedPath) {99_, err = filepath.Rel(allowedPath, itemPath)100if err == nil {101allowed = true102
103break104}105}106}107
108if !allowed {109return fmt.Errorf("path %q is not allowed in extensions", itemPath)110}111}112
113return nil114})115}
116