diff --git a/pkg/checker/checker.go b/pkg/checker/checker.go new file mode 100644 index 00000000..4fcb5624 --- /dev/null +++ b/pkg/checker/checker.go @@ -0,0 +1,98 @@ +package checker + +import ( + "fmt" + "regexp" + + "github.com/hashicorp/go-version" + pkg "kcl-lang.io/kpm/pkg/package" +) + +// Checker defines an interface for KclPkg dependencies checkers. +type Checker interface { + Check(pkg.KclPkg) error +} + +type DepChecker struct { + checkers []Checker +} + +// NewDepChecker creates a new DepChecker with provided checkers. +func NewDepChecker(checkers ...Checker) *DepChecker { + return &DepChecker{checkers: checkers} +} + +// Check runs all individual checks for a kclPkg. +func (c *DepChecker) Check(kclPkg pkg.KclPkg) error { + for _, checker := range c.checkers { + if err := checker.Check(kclPkg); err != nil { + return err + } + } + return nil +} + +// IdentChecker validates the dependencies name in kclPkg. +type IdentChecker struct{} + +func (c *IdentChecker) Check(kclPkg pkg.KclPkg) error { + for _, key := range kclPkg.Dependencies.Deps.Keys() { + dep, _ := kclPkg.Dependencies.Deps.Get(key) + if !isValidDependencyName(dep.Name) { + return fmt.Errorf("invalid dependency name: %s", dep.Name) + } + } + return nil +} + +// VersionChecker validates the dependencies version in kclPkg. +type VersionChecker struct{} + +func (c *VersionChecker) Check(kclPkg pkg.KclPkg) error { + for _, key := range kclPkg.Dependencies.Deps.Keys() { + dep, _ := kclPkg.Dependencies.Deps.Get(key) + if !isValidDependencyVersion(dep.Version) { + return fmt.Errorf("invalid dependency version: %s for %s", dep.Version, dep.Name) + } + } + return nil +} + +// SumChecker validates the dependencies checksum in kclPkg. +type SumChecker struct{} + +func (c *SumChecker) Check(kclPkg pkg.KclPkg) error { + if kclPkg.NoSumCheck { + return nil + } + for _, key := range kclPkg.Dependencies.Deps.Keys() { + dep, _ := kclPkg.Dependencies.Deps.Get(key) + trustedSum, err := getTrustedSum(dep) + if err != nil { + return fmt.Errorf("failed to get checksum from trusted source: %w", err) + } + if dep.Sum != trustedSum { + return fmt.Errorf("checksum verification failed for '%s': expected '%s', got '%s'", dep.Name, trustedSum, dep.Sum) + } + } + return nil +} + +// isValidDependencyName reports whether the name of the dependency is appropriate. +func isValidDependencyName(name string) bool { + validNamePattern := `^[a-zA-Z][a-zA-Z_\-\.]*[a-zA-Z]$` + regex := regexp.MustCompile(validNamePattern) + return regex.MatchString(name) +} + +// isValidDependencyVersion reports whether v is a valid semantic version string. +func isValidDependencyVersion(v string) bool { + _, err := version.NewVersion(v) + return err == nil +} + +// Placeholder for getTrustedSum function +func getTrustedSum(dep pkg.Dependency) (string, error) { + // Need to be implemented to get the trusted checksum. + return "", nil +}