github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/chart/metadata.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package chart
    17  
    18  import (
    19  	"strings"
    20  	"unicode"
    21  
    22  	"github.com/Masterminds/semver/v3"
    23  )
    24  
    25  // Maintainer describes a Chart maintainer.
    26  type Maintainer struct {
    27  	// Name is a user name or organization name
    28  	Name string `json:"name,omitempty"`
    29  	// Email is an optional email address to contact the named maintainer
    30  	Email string `json:"email,omitempty"`
    31  	// URL is an optional URL to an address for the named maintainer
    32  	URL string `json:"url,omitempty"`
    33  }
    34  
    35  // Validate checks valid data and sanitizes string characters.
    36  func (m *Maintainer) Validate() error {
    37  	if m == nil {
    38  		return ValidationError("maintainer cannot be an empty list")
    39  	}
    40  	m.Name = sanitizeString(m.Name)
    41  	m.Email = sanitizeString(m.Email)
    42  	m.URL = sanitizeString(m.URL)
    43  	return nil
    44  }
    45  
    46  // Metadata for a Chart file. This models the structure of a Chart.yaml file.
    47  type Metadata struct {
    48  	// The name of the chart. Required.
    49  	Name string `json:"name,omitempty"`
    50  	// The URL to a relevant project page, git repo, or contact person
    51  	Home string `json:"home,omitempty"`
    52  	// Source is the URL to the source code of this chart
    53  	Sources []string `json:"sources,omitempty"`
    54  	// A SemVer 2 conformant version string of the chart. Required.
    55  	Version string `json:"version,omitempty"`
    56  	// A one-sentence description of the chart
    57  	Description string `json:"description,omitempty"`
    58  	// A list of string keywords
    59  	Keywords []string `json:"keywords,omitempty"`
    60  	// A list of name and URL/email address combinations for the maintainer(s)
    61  	Maintainers []*Maintainer `json:"maintainers,omitempty"`
    62  	// The URL to an icon file.
    63  	Icon string `json:"icon,omitempty"`
    64  	// The API Version of this chart. Required.
    65  	APIVersion string `json:"apiVersion,omitempty"`
    66  	// The condition to check to enable chart
    67  	Condition string `json:"condition,omitempty"`
    68  	// The tags to check to enable chart
    69  	Tags string `json:"tags,omitempty"`
    70  	// The version of the application enclosed inside of this chart.
    71  	AppVersion string `json:"appVersion,omitempty"`
    72  	// Whether or not this chart is deprecated
    73  	Deprecated bool `json:"deprecated,omitempty"`
    74  	// Annotations are additional mappings uninterpreted by Helm,
    75  	// made available for inspection by other applications.
    76  	Annotations map[string]string `json:"annotations,omitempty"`
    77  	// KubeVersion is a SemVer constraint specifying the version of Kubernetes required.
    78  	KubeVersion string `json:"kubeVersion,omitempty"`
    79  	// Dependencies are a list of dependencies for a chart.
    80  	Dependencies []*Dependency `json:"dependencies,omitempty"`
    81  	// Specifies the chart type: application or library
    82  	Type string `json:"type,omitempty"`
    83  }
    84  
    85  // Validate checks the metadata for known issues and sanitizes string
    86  // characters.
    87  func (md *Metadata) Validate() error {
    88  	if md == nil {
    89  		return ValidationError("chart.metadata is required")
    90  	}
    91  
    92  	md.Name = sanitizeString(md.Name)
    93  	md.Description = sanitizeString(md.Description)
    94  	md.Home = sanitizeString(md.Home)
    95  	md.Icon = sanitizeString(md.Icon)
    96  	md.Condition = sanitizeString(md.Condition)
    97  	md.Tags = sanitizeString(md.Tags)
    98  	md.AppVersion = sanitizeString(md.AppVersion)
    99  	md.KubeVersion = sanitizeString(md.KubeVersion)
   100  	for i := range md.Sources {
   101  		md.Sources[i] = sanitizeString(md.Sources[i])
   102  	}
   103  	for i := range md.Keywords {
   104  		md.Keywords[i] = sanitizeString(md.Keywords[i])
   105  	}
   106  
   107  	if md.APIVersion == "" {
   108  		return ValidationError("chart.metadata.apiVersion is required")
   109  	}
   110  	if md.Name == "" {
   111  		return ValidationError("chart.metadata.name is required")
   112  	}
   113  	if md.Version == "" {
   114  		return ValidationError("chart.metadata.version is required")
   115  	}
   116  	if !isValidSemver(md.Version) {
   117  		return ValidationErrorf("chart.metadata.version %q is invalid", md.Version)
   118  	}
   119  	if !isValidChartType(md.Type) {
   120  		return ValidationError("chart.metadata.type must be application or library")
   121  	}
   122  
   123  	for _, m := range md.Maintainers {
   124  		if err := m.Validate(); err != nil {
   125  			return err
   126  		}
   127  	}
   128  
   129  	// Aliases need to be validated here to make sure that the alias name does
   130  	// not contain any illegal characters.
   131  	for _, dependency := range md.Dependencies {
   132  		if err := dependency.Validate(); err != nil {
   133  			return err
   134  		}
   135  	}
   136  	return nil
   137  }
   138  
   139  func isValidChartType(in string) bool {
   140  	switch in {
   141  	case "", "application", "library":
   142  		return true
   143  	}
   144  	return false
   145  }
   146  
   147  func isValidSemver(v string) bool {
   148  	_, err := semver.NewVersion(v)
   149  	return err == nil
   150  }
   151  
   152  // sanitizeString normalize spaces and removes non-printable characters.
   153  func sanitizeString(str string) string {
   154  	return strings.Map(func(r rune) rune {
   155  		if unicode.IsSpace(r) {
   156  			return ' '
   157  		}
   158  		if unicode.IsPrint(r) {
   159  			return r
   160  		}
   161  		return -1
   162  	}, str)
   163  }