You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

metadata.go 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright 2022 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package helm
  4. import (
  5. "archive/tar"
  6. "compress/gzip"
  7. "io"
  8. "strings"
  9. "code.gitea.io/gitea/modules/util"
  10. "code.gitea.io/gitea/modules/validation"
  11. "github.com/hashicorp/go-version"
  12. "gopkg.in/yaml.v3"
  13. )
  14. var (
  15. // ErrMissingChartFile indicates a missing Chart.yaml file
  16. ErrMissingChartFile = util.NewInvalidArgumentErrorf("Chart.yaml file is missing")
  17. // ErrInvalidName indicates an invalid package name
  18. ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid")
  19. // ErrInvalidVersion indicates an invalid package version
  20. ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid")
  21. // ErrInvalidChart indicates an invalid chart
  22. ErrInvalidChart = util.NewInvalidArgumentErrorf("chart is invalid")
  23. )
  24. // Metadata for a Chart file. This models the structure of a Chart.yaml file.
  25. type Metadata struct {
  26. APIVersion string `json:"api_version" yaml:"apiVersion"`
  27. Type string `json:"type,omitempty" yaml:"type,omitempty"`
  28. Name string `json:"name" yaml:"name"`
  29. Version string `json:"version" yaml:"version"`
  30. AppVersion string `json:"app_version,omitempty" yaml:"appVersion,omitempty"`
  31. Home string `json:"home,omitempty" yaml:"home,omitempty"`
  32. Sources []string `json:"sources,omitempty" yaml:"sources,omitempty"`
  33. Description string `json:"description,omitempty" yaml:"description,omitempty"`
  34. Keywords []string `json:"keywords,omitempty" yaml:"keywords,omitempty"`
  35. Maintainers []*Maintainer `json:"maintainers,omitempty" yaml:"maintainers,omitempty"`
  36. Icon string `json:"icon,omitempty" yaml:"icon,omitempty"`
  37. Condition string `json:"condition,omitempty" yaml:"condition,omitempty"`
  38. Tags string `json:"tags,omitempty" yaml:"tags,omitempty"`
  39. Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
  40. Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
  41. KubeVersion string `json:"kube_version,omitempty" yaml:"kubeVersion,omitempty"`
  42. Dependencies []*Dependency `json:"dependencies,omitempty" yaml:"dependencies,omitempty"`
  43. }
  44. type Maintainer struct {
  45. Name string `json:"name,omitempty" yaml:"name,omitempty"`
  46. Email string `json:"email,omitempty" yaml:"email,omitempty"`
  47. URL string `json:"url,omitempty" yaml:"url,omitempty"`
  48. }
  49. type Dependency struct {
  50. Name string `json:"name" yaml:"name"`
  51. Version string `json:"version,omitempty" yaml:"version,omitempty"`
  52. Repository string `json:"repository" yaml:"repository"`
  53. Condition string `json:"condition,omitempty" yaml:"condition,omitempty"`
  54. Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
  55. Enabled bool `json:"enabled,omitempty" yaml:"enabled,omitempty"`
  56. ImportValues []any `json:"import_values,omitempty" yaml:"import-values,omitempty"`
  57. Alias string `json:"alias,omitempty" yaml:"alias,omitempty"`
  58. }
  59. // ParseChartArchive parses the metadata of a Helm archive
  60. func ParseChartArchive(r io.Reader) (*Metadata, error) {
  61. gzr, err := gzip.NewReader(r)
  62. if err != nil {
  63. return nil, err
  64. }
  65. defer gzr.Close()
  66. tr := tar.NewReader(gzr)
  67. for {
  68. hd, err := tr.Next()
  69. if err == io.EOF {
  70. break
  71. }
  72. if err != nil {
  73. return nil, err
  74. }
  75. if hd.Typeflag != tar.TypeReg {
  76. continue
  77. }
  78. if hd.FileInfo().Name() == "Chart.yaml" {
  79. if strings.Count(hd.Name, "/") != 1 {
  80. continue
  81. }
  82. return ParseChartFile(tr)
  83. }
  84. }
  85. return nil, ErrMissingChartFile
  86. }
  87. // ParseChartFile parses a Chart.yaml file to retrieve the metadata of a Helm chart
  88. func ParseChartFile(r io.Reader) (*Metadata, error) {
  89. var metadata *Metadata
  90. if err := yaml.NewDecoder(r).Decode(&metadata); err != nil {
  91. return nil, err
  92. }
  93. if metadata.APIVersion == "" {
  94. return nil, ErrInvalidChart
  95. }
  96. if metadata.Type != "" && metadata.Type != "application" && metadata.Type != "library" {
  97. return nil, ErrInvalidChart
  98. }
  99. if metadata.Name == "" {
  100. return nil, ErrInvalidName
  101. }
  102. if _, err := version.NewSemver(metadata.Version); err != nil {
  103. return nil, ErrInvalidVersion
  104. }
  105. if !validation.IsValidURL(metadata.Home) {
  106. metadata.Home = ""
  107. }
  108. return metadata, nil
  109. }