...

Source file src/helm.sh/helm/v3/pkg/chart/metadata.go

Documentation: helm.sh/helm/v3/pkg/chart

     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  	"path/filepath"
    20  	"strings"
    21  	"unicode"
    22  
    23  	"github.com/Masterminds/semver/v3"
    24  )
    25  
    26  // Maintainer describes a Chart maintainer.
    27  type Maintainer struct {
    28  	// Name is a user name or organization name
    29  	Name string `json:"name,omitempty"`
    30  	// Email is an optional email address to contact the named maintainer
    31  	Email string `json:"email,omitempty"`
    32  	// URL is an optional URL to an address for the named maintainer
    33  	URL string `json:"url,omitempty"`
    34  }
    35  
    36  // Validate checks valid data and sanitizes string characters.
    37  func (m *Maintainer) Validate() error {
    38  	if m == nil {
    39  		return ValidationError("maintainers must not contain empty or null nodes")
    40  	}
    41  	m.Name = sanitizeString(m.Name)
    42  	m.Email = sanitizeString(m.Email)
    43  	m.URL = sanitizeString(m.URL)
    44  	return nil
    45  }
    46  
    47  // Metadata for a Chart file. This models the structure of a Chart.yaml file.
    48  type Metadata struct {
    49  	// The name of the chart. Required.
    50  	Name string `json:"name,omitempty"`
    51  	// The URL to a relevant project page, git repo, or contact person
    52  	Home string `json:"home,omitempty"`
    53  	// Source is the URL to the source code of this chart
    54  	Sources []string `json:"sources,omitempty"`
    55  	// A SemVer 2 conformant version string of the chart. Required.
    56  	Version string `json:"version,omitempty"`
    57  	// A one-sentence description of the chart
    58  	Description string `json:"description,omitempty"`
    59  	// A list of string keywords
    60  	Keywords []string `json:"keywords,omitempty"`
    61  	// A list of name and URL/email address combinations for the maintainer(s)
    62  	Maintainers []*Maintainer `json:"maintainers,omitempty"`
    63  	// The URL to an icon file.
    64  	Icon string `json:"icon,omitempty"`
    65  	// The API Version of this chart. Required.
    66  	APIVersion string `json:"apiVersion,omitempty"`
    67  	// The condition to check to enable chart
    68  	Condition string `json:"condition,omitempty"`
    69  	// The tags to check to enable chart
    70  	Tags string `json:"tags,omitempty"`
    71  	// The version of the application enclosed inside of this chart.
    72  	AppVersion string `json:"appVersion,omitempty"`
    73  	// Whether or not this chart is deprecated
    74  	Deprecated bool `json:"deprecated,omitempty"`
    75  	// Annotations are additional mappings uninterpreted by Helm,
    76  	// made available for inspection by other applications.
    77  	Annotations map[string]string `json:"annotations,omitempty"`
    78  	// KubeVersion is a SemVer constraint specifying the version of Kubernetes required.
    79  	KubeVersion string `json:"kubeVersion,omitempty"`
    80  	// Dependencies are a list of dependencies for a chart.
    81  	Dependencies []*Dependency `json:"dependencies,omitempty"`
    82  	// Specifies the chart type: application or library
    83  	Type string `json:"type,omitempty"`
    84  }
    85  
    86  // Validate checks the metadata for known issues and sanitizes string
    87  // characters.
    88  func (md *Metadata) Validate() error {
    89  	if md == nil {
    90  		return ValidationError("chart.metadata is required")
    91  	}
    92  
    93  	md.Name = sanitizeString(md.Name)
    94  	md.Description = sanitizeString(md.Description)
    95  	md.Home = sanitizeString(md.Home)
    96  	md.Icon = sanitizeString(md.Icon)
    97  	md.Condition = sanitizeString(md.Condition)
    98  	md.Tags = sanitizeString(md.Tags)
    99  	md.AppVersion = sanitizeString(md.AppVersion)
   100  	md.KubeVersion = sanitizeString(md.KubeVersion)
   101  	for i := range md.Sources {
   102  		md.Sources[i] = sanitizeString(md.Sources[i])
   103  	}
   104  	for i := range md.Keywords {
   105  		md.Keywords[i] = sanitizeString(md.Keywords[i])
   106  	}
   107  
   108  	if md.APIVersion == "" {
   109  		return ValidationError("chart.metadata.apiVersion is required")
   110  	}
   111  	if md.Name == "" {
   112  		return ValidationError("chart.metadata.name is required")
   113  	}
   114  
   115  	if md.Name != filepath.Base(md.Name) {
   116  		return ValidationErrorf("chart.metadata.name %q is invalid", md.Name)
   117  	}
   118  
   119  	if md.Version == "" {
   120  		return ValidationError("chart.metadata.version is required")
   121  	}
   122  	if !isValidSemver(md.Version) {
   123  		return ValidationErrorf("chart.metadata.version %q is invalid", md.Version)
   124  	}
   125  	if !isValidChartType(md.Type) {
   126  		return ValidationError("chart.metadata.type must be application or library")
   127  	}
   128  
   129  	for _, m := range md.Maintainers {
   130  		if err := m.Validate(); err != nil {
   131  			return err
   132  		}
   133  	}
   134  
   135  	// Aliases need to be validated here to make sure that the alias name does
   136  	// not contain any illegal characters.
   137  	dependencies := map[string]*Dependency{}
   138  	for _, dependency := range md.Dependencies {
   139  		if err := dependency.Validate(); err != nil {
   140  			return err
   141  		}
   142  		key := dependency.Name
   143  		if dependency.Alias != "" {
   144  			key = dependency.Alias
   145  		}
   146  		if dependencies[key] != nil {
   147  			return ValidationErrorf("more than one dependency with name or alias %q", key)
   148  		}
   149  		dependencies[key] = dependency
   150  	}
   151  	return nil
   152  }
   153  
   154  func isValidChartType(in string) bool {
   155  	switch in {
   156  	case "", "application", "library":
   157  		return true
   158  	}
   159  	return false
   160  }
   161  
   162  func isValidSemver(v string) bool {
   163  	_, err := semver.NewVersion(v)
   164  	return err == nil
   165  }
   166  
   167  // sanitizeString normalize spaces and removes non-printable characters.
   168  func sanitizeString(str string) string {
   169  	return strings.Map(func(r rune) rune {
   170  		if unicode.IsSpace(r) {
   171  			return ' '
   172  		}
   173  		if unicode.IsPrint(r) {
   174  			return r
   175  		}
   176  		return -1
   177  	}, str)
   178  }
   179  

View as plain text