@ -32,27 +32,56 @@ import (
chart "helm.sh/helm/v4/pkg/chart/v2"
)
// MaxDecompressedChartSize is the maximum size of a chart archive that will be
// decompressed. This is the decompressed size of all the files.
// The default value is 100 MiB.
var MaxDecompressedChartSize int64 = 100 * 1024 * 1024 // Default 100 MiB
var drivePathPattern = regexp . MustCompile ( ` ^[a-zA-Z]:/ ` )
// MaxDecompressedFileSize is the size of the largest file that Helm will attempt to load.
// The size of the file is the decompressed version of it when it is stored in an archive.
var MaxDecompressedFileSize int64 = 5 * 1024 * 1024 // Default 5 MiB
type ChartLoadOptions struct {
MaxDecompressedChartSize int64
MaxDecompressedFileSize int64
}
var drivePathPattern = regexp . MustCompile ( ` ^[a-zA-Z]:/ ` )
// DefaultChartLoadOptions provides the default size limits
var DefaultChartLoadOptions = ChartLoadOptions {
// MaxDecompressedChartSize is the maximum size of a chart archive that will be
// decompressed. This is the decompressed size of all the files.
MaxDecompressedChartSize : 100 * 1024 * 1024 , // 100 MiB
// MaxDecompressedFileSize is the size of the largest file that Helm will attempt to load.
// The size of the file is the decompressed version of it when it is stored in an archive.
MaxDecompressedFileSize : 5 * 1024 * 1024 , // 5 MiB
}
// FileLoader with embedded options
type FileLoader struct {
path string
opts ChartLoadOptions
}
// FileLoader loads a chart from a file
type FileLoader string
// NewFileLoader creates a file loader with custom options
func NewFileLoader ( path string , opts ChartLoadOptions ) FileLoader {
return FileLoader { path : path , opts : opts }
}
// Load loads a chart
// NewDefaultFileLoader creates a file loader with default options
func NewDefaultFileLoader ( path string ) FileLoader {
return FileLoader { path : path , opts : DefaultChartLoadOptions }
}
// Load loads a chart using default options
func ( l FileLoader ) Load ( ) ( * chart . Chart , error ) {
return LoadFile ( string ( l ) )
return LoadFile WithOptions( l . path , DefaultChartLoadOptions )
}
// LoadFile loads from an archive file.
// LoadWithOptions loads a chart using the provided options
func ( l FileLoader ) LoadWithOptions ( ) ( * chart . Chart , error ) {
return LoadFileWithOptions ( l . path , l . opts )
}
// LoadFile load a chart with default options
func LoadFile ( name string ) ( * chart . Chart , error ) {
return LoadFileWithOptions ( name , DefaultChartLoadOptions )
}
// LoadFile loads from an archive file with the provided options
func LoadFileWithOptions ( name string , opts ChartLoadOptions ) ( * chart . Chart , error ) {
if fi , err := os . Stat ( name ) ; err != nil {
return nil , err
} else if fi . IsDir ( ) {
@ -70,7 +99,7 @@ func LoadFile(name string) (*chart.Chart, error) {
return nil , err
}
c , err := LoadArchive ( raw )
c , err := LoadArchive WithOptions ( raw , opts )
if err != nil {
if err == gzip . ErrHeader {
return nil , fmt . Errorf ( "file '%s' does not appear to be a valid chart file (details: %s)" , name , err )
@ -117,8 +146,15 @@ func isGZipApplication(data []byte) bool {
// LoadArchiveFiles reads in files out of an archive into memory. This function
// performs important path security checks and should always be used before
// expanding a tarball
// expanding a tarball . It use default options.
func LoadArchiveFiles ( in io . Reader ) ( [ ] * BufferedFile , error ) {
return LoadArchiveFilesWithOptions ( in , DefaultChartLoadOptions )
}
// LoadArchiveFiles reads in files out of an archive into memory. This function
// performs important path security checks and should always be used before
// expanding a tarball. It uses the provided options.
func LoadArchiveFilesWithOptions ( in io . Reader , opts ChartLoadOptions ) ( [ ] * BufferedFile , error ) {
unzipped , err := gzip . NewReader ( in )
if err != nil {
return nil , err
@ -127,7 +163,7 @@ func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
files := [ ] * BufferedFile { }
tr := tar . NewReader ( unzipped )
remainingSize := MaxDecompressedChartSize
remainingSize := opts. MaxDecompressedChartSize
for {
b := bytes . NewBuffer ( nil )
hd , err := tr . Next ( )
@ -188,11 +224,11 @@ func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
}
if hd . Size > remainingSize {
return nil , fmt . Errorf ( "decompressed chart is larger than the maximum size %d ", MaxDecompressedChartSize )
return nil , fmt . Errorf ( "decompressed chart is larger than the maximum size %d bytes ", opts . MaxDecompressedChartSize )
}
if hd . Size > MaxDecompressedFileSize {
return nil , fmt . Errorf ( "decompressed chart file %q is larger than the maximum file size %d ", hd . Name , MaxDecompressedFileSize )
if hd . Size > opts. MaxDecompressedFileSize {
return nil , fmt . Errorf ( "decompressed chart file %q is larger than the maximum file size %d bytes ", hd . Name , opts . MaxDecompressedFileSize )
}
limitedReader := io . LimitReader ( tr , remainingSize )
@ -208,7 +244,7 @@ func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
// is the one that goes over the limit. It assumes the Size stored in the tar header
// is correct, something many applications do.
if bytesWritten < hd . Size || remainingSize <= 0 {
return nil , fmt . Errorf ( "decompressed chart is larger than the maximum size %d ", MaxDecompressedChartSize )
return nil , fmt . Errorf ( "decompressed chart is larger than the maximum size %d bytes ", opts . MaxDecompressedChartSize )
}
data := bytes . TrimPrefix ( b . Bytes ( ) , utf8bom )
@ -223,9 +259,14 @@ func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
return files , nil
}
// LoadArchive loads from a reader containing a compressed tar archive .
// LoadArchive loads from a reader containing a compressed tar archive with default options
func LoadArchive ( in io . Reader ) ( * chart . Chart , error ) {
files , err := LoadArchiveFiles ( in )
return LoadArchiveWithOptions ( in , DefaultChartLoadOptions )
}
// LoadArchive loads from a reader containing a compressed tar archive with the provided options
func LoadArchiveWithOptions ( in io . Reader , opts ChartLoadOptions ) ( * chart . Chart , error ) {
files , err := LoadArchiveFilesWithOptions ( in , opts )
if err != nil {
return nil , err
}