fix: prevent file traversal using helm file values param and application details api (#8606)

* fix: prevent file traversal using helm file values param and application details api

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

* apply reviewer notes: move resolve.go into separate package; use uuid to generate random file

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
This commit is contained in:
Alexander Matyushentsev 2022-02-24 12:58:38 -08:00 committed by GitHub
parent c7da148978
commit 76eddafd1c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 600 additions and 464 deletions

View file

@ -0,0 +1,15 @@
package apiclient
func (q *ManifestRequest) GetValuesFileSchemes() []string {
if q.HelmOptions == nil {
return nil
}
return q.HelmOptions.ValuesFileSchemes
}
func (q *RepoServerAppDetailsQuery) GetValuesFileSchemes() []string {
if q.HelmOptions == nil {
return nil
}
return q.HelmOptions.ValuesFileSchemes
}

View file

@ -750,6 +750,7 @@ type RepoServerAppDetailsQuery struct {
NoRevisionCache bool `protobuf:"varint,7,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"`
TrackingMethod string `protobuf:"bytes,8,opt,name=trackingMethod,proto3" json:"trackingMethod,omitempty"`
EnabledSourceTypes map[string]bool `protobuf:"bytes,9,rep,name=enabledSourceTypes,proto3" json:"enabledSourceTypes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
HelmOptions *v1alpha1.HelmOptions `protobuf:"bytes,10,opt,name=helmOptions,proto3" json:"helmOptions,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -851,6 +852,13 @@ func (m *RepoServerAppDetailsQuery) GetEnabledSourceTypes() map[string]bool {
return nil
}
func (m *RepoServerAppDetailsQuery) GetHelmOptions() *v1alpha1.HelmOptions {
if m != nil {
return m.HelmOptions
}
return nil
}
// RepoAppDetailsResponse application details
type RepoAppDetailsResponse struct {
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
@ -1541,107 +1549,107 @@ func init() {
}
var fileDescriptor_dd8723cfcc820480 = []byte{
// 1594 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xdd, 0x6f, 0xdb, 0xb6,
0x16, 0x8f, 0x6c, 0x27, 0xb1, 0x8f, 0xdb, 0xc4, 0x61, 0xbf, 0x74, 0x75, 0xd3, 0x20, 0xd5, 0xc5,
0x2d, 0x72, 0x6f, 0x5b, 0x19, 0x4d, 0x8b, 0xad, 0x68, 0xb1, 0x01, 0x59, 0x9a, 0xa6, 0x43, 0x9a,
0x26, 0x53, 0xba, 0x01, 0xdb, 0x8a, 0x15, 0x8c, 0xcc, 0xc8, 0x9c, 0x6d, 0x89, 0x15, 0x65, 0x0f,
0x2e, 0xb0, 0x87, 0x3d, 0xed, 0x7d, 0xc0, 0xf6, 0xaf, 0xec, 0x71, 0x4f, 0xfb, 0x78, 0xdc, 0x9f,
0x30, 0x74, 0xff, 0xc5, 0x9e, 0x06, 0x52, 0x5f, 0xb4, 0x2c, 0xa7, 0x1d, 0x9c, 0xa6, 0x2f, 0x36,
0x79, 0x78, 0xbe, 0x79, 0x78, 0xf8, 0xa3, 0xe0, 0x6a, 0x40, 0x98, 0xcf, 0x49, 0x30, 0x20, 0x41,
0x53, 0x0e, 0x69, 0xe8, 0x07, 0x43, 0x65, 0x68, 0xb1, 0xc0, 0x0f, 0x7d, 0x04, 0x19, 0xc5, 0x38,
0xef, 0xfa, 0xae, 0x2f, 0xc9, 0x4d, 0x31, 0x8a, 0x38, 0x8c, 0x65, 0xd7, 0xf7, 0xdd, 0x2e, 0x69,
0x62, 0x46, 0x9b, 0xd8, 0xf3, 0xfc, 0x10, 0x87, 0xd4, 0xf7, 0x78, 0xbc, 0x6a, 0x76, 0xee, 0x70,
0x8b, 0xfa, 0x72, 0xd5, 0xf1, 0x03, 0xd2, 0x1c, 0xdc, 0x6c, 0xba, 0xc4, 0x23, 0x01, 0x0e, 0x49,
0x2b, 0xe6, 0x79, 0xe4, 0xd2, 0xb0, 0xdd, 0x3f, 0xb4, 0x1c, 0xbf, 0xd7, 0xc4, 0x81, 0x34, 0xf1,
0xa5, 0x1c, 0xdc, 0x70, 0x5a, 0xcd, 0xc1, 0x7a, 0x93, 0x75, 0x5c, 0x21, 0xcf, 0x9b, 0x98, 0xb1,
0x2e, 0x75, 0xa4, 0xfe, 0xe6, 0xe0, 0x26, 0xee, 0xb2, 0x36, 0x1e, 0xd3, 0x66, 0x7e, 0x07, 0xb0,
0xb8, 0x8b, 0x3d, 0x7a, 0x44, 0x78, 0x68, 0x93, 0xe7, 0x7d, 0xc2, 0x43, 0xf4, 0x14, 0x2a, 0x22,
0x0e, 0x5d, 0x5b, 0xd5, 0xd6, 0xea, 0xeb, 0x0f, 0xad, 0xcc, 0xa0, 0x95, 0x18, 0x94, 0x83, 0x67,
0x4e, 0xcb, 0x1a, 0xac, 0x5b, 0xac, 0xe3, 0x5a, 0xc2, 0xa0, 0xa5, 0x18, 0xb4, 0x12, 0x83, 0x96,
0x9d, 0x66, 0xc4, 0x96, 0x5a, 0x91, 0x01, 0xd5, 0x80, 0x0c, 0x28, 0xa7, 0xbe, 0xa7, 0x97, 0x56,
0xb5, 0xb5, 0x9a, 0x9d, 0xce, 0x91, 0x0e, 0xf3, 0x9e, 0xbf, 0x89, 0x9d, 0x36, 0xd1, 0xcb, 0xab,
0xda, 0x5a, 0xd5, 0x4e, 0xa6, 0x68, 0x15, 0xea, 0x98, 0xb1, 0x47, 0xf8, 0x90, 0x74, 0x77, 0xc8,
0x50, 0xaf, 0x48, 0x41, 0x95, 0x24, 0x64, 0x31, 0x63, 0x8f, 0x71, 0x8f, 0xe8, 0xb3, 0x72, 0x35,
0x99, 0xa2, 0x65, 0xa8, 0x79, 0xb8, 0x47, 0x38, 0xc3, 0x0e, 0xd1, 0xab, 0x72, 0x2d, 0x23, 0xa0,
0xaf, 0x61, 0x49, 0x71, 0xfc, 0xc0, 0xef, 0x07, 0x0e, 0xd1, 0x41, 0x86, 0xbe, 0x37, 0x5d, 0xe8,
0x1b, 0x79, 0xb5, 0xf6, 0xb8, 0x25, 0xf4, 0x05, 0xcc, 0xca, 0xa2, 0xd1, 0xeb, 0xab, 0xe5, 0x13,
0xcd, 0x76, 0xa4, 0x16, 0x79, 0x30, 0xcf, 0xba, 0x7d, 0x97, 0x7a, 0x5c, 0x3f, 0x23, 0x2d, 0x3c,
0x99, 0xce, 0xc2, 0xa6, 0xef, 0x1d, 0x51, 0x77, 0x17, 0x7b, 0xd8, 0x25, 0x3d, 0xe2, 0x85, 0xfb,
0x52, 0xb9, 0x9d, 0x18, 0x41, 0x2f, 0xa0, 0xd1, 0xe9, 0xf3, 0xd0, 0xef, 0xd1, 0x17, 0x64, 0x8f,
0xc9, 0xe2, 0xd6, 0xcf, 0xca, 0x6c, 0x3e, 0x9e, 0xce, 0xf0, 0x4e, 0x4e, 0xab, 0x3d, 0x66, 0x47,
0x14, 0x49, 0xa7, 0x7f, 0x48, 0x3e, 0x21, 0x81, 0xac, 0xae, 0x85, 0xa8, 0x48, 0x14, 0x52, 0x54,
0x46, 0x34, 0x9e, 0x71, 0x7d, 0x71, 0xb5, 0x1c, 0x95, 0x51, 0x4a, 0x42, 0x6b, 0xb0, 0x38, 0x20,
0x01, 0x3d, 0x1a, 0x1e, 0x50, 0xd7, 0xc3, 0x61, 0x3f, 0x20, 0x7a, 0x43, 0x96, 0x62, 0x9e, 0x8c,
0x7a, 0x70, 0xb6, 0x4d, 0xba, 0x3d, 0x91, 0xf2, 0xcd, 0x80, 0xb4, 0xb8, 0xbe, 0x24, 0xf3, 0xbb,
0x3d, 0xfd, 0x0e, 0x4a, 0x75, 0xf6, 0xa8, 0x76, 0xe1, 0x98, 0xe7, 0xdb, 0xf1, 0x49, 0x89, 0xce,
0x08, 0x8a, 0x1c, 0xcb, 0x91, 0xd1, 0x55, 0x58, 0x08, 0x03, 0xec, 0x74, 0xa8, 0xe7, 0xee, 0x92,
0xb0, 0xed, 0xb7, 0xf4, 0x73, 0x32, 0x13, 0x39, 0x2a, 0x72, 0x00, 0x11, 0x0f, 0x1f, 0x76, 0x49,
0x2b, 0xaa, 0xc5, 0x27, 0x43, 0x46, 0xb8, 0x7e, 0x5e, 0x46, 0x71, 0xcb, 0x52, 0x9a, 0x5b, 0xae,
0x41, 0x58, 0x5b, 0x63, 0x52, 0x5b, 0x5e, 0x18, 0x0c, 0xed, 0x02, 0x75, 0xa8, 0x03, 0x75, 0x11,
0x47, 0x52, 0x0a, 0x17, 0x64, 0x29, 0x7c, 0x38, 0x5d, 0x8e, 0x1e, 0x66, 0x0a, 0x6d, 0x55, 0xbb,
0xb1, 0x05, 0x97, 0x26, 0xf8, 0x86, 0x1a, 0x50, 0xee, 0x90, 0xa1, 0xec, 0x69, 0x35, 0x5b, 0x0c,
0xd1, 0x79, 0x98, 0x1d, 0xe0, 0x6e, 0x9f, 0xc8, 0x2e, 0x54, 0xb5, 0xa3, 0xc9, 0xdd, 0xd2, 0x1d,
0xcd, 0xec, 0xc3, 0x85, 0x27, 0x32, 0xdc, 0xf4, 0x30, 0x9d, 0x46, 0x67, 0x34, 0x1f, 0xc2, 0xc5,
0xbc, 0x59, 0xce, 0x7c, 0x8f, 0x13, 0x64, 0x01, 0x92, 0xd5, 0x47, 0x49, 0x2b, 0x5b, 0x95, 0x5e,
0x54, 0xed, 0x82, 0x15, 0xf3, 0x9b, 0x12, 0x5c, 0xb4, 0x09, 0xf7, 0xbb, 0x03, 0x92, 0x94, 0xc6,
0xe9, 0x34, 0xf7, 0xcf, 0xa1, 0x8c, 0x19, 0x93, 0x19, 0x9d, 0x7a, 0x97, 0x95, 0xf6, 0x69, 0x0b,
0xad, 0xe8, 0x3a, 0x2c, 0xe1, 0xde, 0x21, 0x75, 0xfb, 0x7e, 0x9f, 0x27, 0x61, 0xc9, 0x7b, 0xa2,
0x66, 0x8f, 0x2f, 0x98, 0x0e, 0x5c, 0x1a, 0x4b, 0x41, 0x9c, 0x4e, 0xf5, 0x0a, 0xd2, 0x72, 0x57,
0x50, 0xa1, 0x91, 0xd2, 0x24, 0x23, 0xbf, 0x68, 0xd0, 0xc8, 0x4e, 0x47, 0xac, 0x7e, 0x19, 0x6a,
0xbd, 0x98, 0xc6, 0x75, 0x4d, 0xb6, 0x98, 0x8c, 0x30, 0x7a, 0x1b, 0x95, 0xf2, 0xb7, 0xd1, 0x45,
0x98, 0x8b, 0x70, 0x46, 0x1c, 0x58, 0x3c, 0x1b, 0x71, 0xb9, 0x92, 0x73, 0x79, 0x05, 0x80, 0xa7,
0xe5, 0xae, 0xcf, 0xc9, 0x55, 0x85, 0x82, 0x4c, 0x38, 0x13, 0xf5, 0x2e, 0x9b, 0xf0, 0x7e, 0x37,
0xd4, 0xe7, 0x25, 0xc7, 0x08, 0xcd, 0xf4, 0x61, 0xf1, 0x11, 0x15, 0x31, 0x1c, 0xf1, 0xd3, 0x29,
0xf6, 0x77, 0xa0, 0x22, 0x8c, 0x89, 0xc0, 0x0e, 0x03, 0xec, 0x39, 0x6d, 0x92, 0xe4, 0x2a, 0x9d,
0x23, 0x04, 0x95, 0x10, 0xbb, 0x5c, 0x2f, 0x49, 0xba, 0x1c, 0x9b, 0x3f, 0x96, 0x22, 0x4f, 0x37,
0x18, 0xe3, 0x6f, 0x1f, 0xb0, 0x14, 0xb7, 0xd0, 0xf2, 0x78, 0x0b, 0xcd, 0xb9, 0xfc, 0x4f, 0x5a,
0xe8, 0xc9, 0x75, 0xb5, 0xf9, 0x0d, 0xc6, 0x84, 0x23, 0xe8, 0x26, 0x54, 0x30, 0x63, 0x51, 0xc2,
0xeb, 0xeb, 0x97, 0x55, 0x47, 0x63, 0x16, 0xf1, 0x1f, 0xbb, 0x24, 0x59, 0x8d, 0x77, 0xa1, 0x96,
0x92, 0x5e, 0x65, 0xb6, 0xa6, 0x9a, 0xfd, 0x6b, 0x16, 0xfe, 0x25, 0x72, 0x7a, 0x20, 0x0b, 0x79,
0x83, 0xb1, 0xfb, 0x24, 0xc4, 0xb4, 0xcb, 0x3f, 0xea, 0x93, 0x60, 0xf8, 0x86, 0xb7, 0xce, 0x85,
0xb9, 0xe8, 0x1c, 0xc4, 0x1d, 0xe9, 0xc4, 0x01, 0x5d, 0xac, 0x3e, 0x43, 0x71, 0xe5, 0x37, 0x83,
0xe2, 0x8a, 0x50, 0x55, 0xe5, 0x94, 0x50, 0xd5, 0x64, 0x60, 0xad, 0xc0, 0xf5, 0xb9, 0x51, 0xb8,
0x5e, 0x00, 0x56, 0xe6, 0x5f, 0x17, 0xac, 0x54, 0x0b, 0xc1, 0x4a, 0xaf, 0xf0, 0xa4, 0xd5, 0x64,
0xba, 0xdf, 0x53, 0x0b, 0x78, 0x62, 0xad, 0xbd, 0x8d, 0x33, 0xf7, 0xad, 0xbc, 0x88, 0x99, 0x9f,
0xb9, 0x92, 0xde, 0x12, 0xa2, 0xb9, 0x89, 0x7e, 0x1d, 0xe9, 0x91, 0x63, 0x74, 0x1b, 0xe6, 0x3b,
0xdc, 0xf7, 0x3c, 0x12, 0xc6, 0x05, 0x6b, 0xa8, 0x91, 0xed, 0x44, 0x4b, 0x1b, 0x8c, 0x1d, 0x30,
0xe2, 0xd8, 0x09, 0x2b, 0xba, 0x06, 0x15, 0x01, 0x82, 0xe4, 0x8d, 0x51, 0x5f, 0xbf, 0xa4, 0x8a,
0x08, 0xa4, 0x94, 0xf0, 0x4b, 0x26, 0x74, 0x17, 0x6a, 0xe9, 0x0e, 0xc7, 0x25, 0xb4, 0x3c, 0x62,
0x24, 0x59, 0x4c, 0xc4, 0x32, 0x76, 0x21, 0xdb, 0xa2, 0x01, 0x71, 0x24, 0xfa, 0x98, 0x1d, 0x97,
0xbd, 0x9f, 0x2c, 0xa6, 0xb2, 0x29, 0xbb, 0xf9, 0xb3, 0x06, 0x57, 0xb2, 0xad, 0x49, 0x6a, 0x60,
0x97, 0x84, 0xb8, 0x85, 0x43, 0xfc, 0xf6, 0x3b, 0xf9, 0x55, 0x58, 0x70, 0xda, 0xc4, 0xe9, 0x64,
0xb0, 0x3f, 0x7a, 0x81, 0xe6, 0xa8, 0xe6, 0xaf, 0x25, 0x58, 0x18, 0xdd, 0x08, 0xb1, 0x93, 0xe2,
0x02, 0x4f, 0x76, 0x52, 0x8c, 0xd1, 0x3e, 0x9c, 0x21, 0xde, 0x80, 0x06, 0xbe, 0x27, 0x1e, 0x49,
0x49, 0x5f, 0xb8, 0x3e, 0x79, 0x3b, 0xad, 0x2d, 0x85, 0x3d, 0xaa, 0xcb, 0x11, 0x0d, 0xc8, 0x03,
0x60, 0x38, 0xc0, 0x3d, 0x12, 0x92, 0x40, 0x1c, 0xfe, 0xf2, 0x09, 0x1c, 0xfe, 0xc8, 0x83, 0xfd,
0x44, 0xad, 0xad, 0x58, 0x30, 0x9e, 0xc1, 0xd2, 0x98, 0x4b, 0x05, 0xb5, 0x7f, 0x5b, 0xad, 0xfd,
0xfa, 0xfa, 0x4a, 0x41, 0x84, 0x8a, 0x1a, 0xf5, 0x6c, 0xfc, 0x54, 0x82, 0xba, 0x52, 0x9f, 0x85,
0x69, 0x5c, 0x01, 0x90, 0x02, 0x0f, 0x68, 0x37, 0xbe, 0x57, 0x6b, 0xb6, 0x42, 0x41, 0x9d, 0x82,
0xa4, 0xec, 0x4c, 0xff, 0xb8, 0x28, 0xcc, 0x88, 0xc0, 0x66, 0xd2, 0x34, 0x8f, 0xfb, 0x60, 0x3c,
0x43, 0x5f, 0xc1, 0xc2, 0x11, 0xed, 0x92, 0xfd, 0xcc, 0x91, 0x39, 0xe9, 0xc8, 0xde, 0xf4, 0x8e,
0x3c, 0x50, 0xf5, 0xda, 0x39, 0x33, 0xe6, 0xff, 0xa1, 0x91, 0x3f, 0xae, 0xc2, 0x49, 0xda, 0xc3,
0x6e, 0x9a, 0xad, 0x78, 0x66, 0x7e, 0xaf, 0x01, 0x1a, 0xdf, 0x8f, 0x49, 0x49, 0xef, 0xdc, 0xe1,
0xc9, 0x2b, 0x3a, 0x3a, 0x28, 0x0a, 0x05, 0xed, 0x40, 0xbd, 0x45, 0x78, 0x48, 0x3d, 0xe9, 0x70,
0xdc, 0x44, 0xfe, 0x77, 0xfc, 0xc6, 0xdf, 0xcf, 0x04, 0x6c, 0x55, 0xda, 0xfc, 0x18, 0x2e, 0x1f,
0xcb, 0xad, 0x20, 0x62, 0x6d, 0x04, 0x11, 0x1f, 0x8b, 0xa3, 0x4d, 0x04, 0x8d, 0x7c, 0x37, 0x32,
0x9f, 0xc3, 0x92, 0xc8, 0xe9, 0x66, 0x1b, 0x07, 0xe1, 0x29, 0xa1, 0xdc, 0x7b, 0x50, 0x4b, 0x4d,
0x16, 0xe6, 0xda, 0x80, 0xea, 0x20, 0xf9, 0x1a, 0x11, 0xc1, 0xdc, 0x74, 0x6e, 0x6e, 0x00, 0x52,
0xfd, 0x8d, 0xef, 0x8d, 0x6b, 0x30, 0x4b, 0x43, 0xd2, 0x4b, 0xc0, 0xdb, 0x85, 0x7c, 0xbb, 0x97,
0xec, 0x76, 0xc4, 0xb3, 0xfe, 0xe7, 0x2c, 0x2c, 0x65, 0x5d, 0x57, 0xfc, 0x52, 0x87, 0xa0, 0x3d,
0x68, 0x6c, 0xc7, 0xdf, 0x01, 0x93, 0xc7, 0x0b, 0xfa, 0xf7, 0x31, 0x0f, 0x7e, 0x63, 0xb9, 0x78,
0x31, 0xf2, 0xc8, 0x9c, 0x41, 0x9f, 0xc2, 0xc2, 0xe8, 0xcb, 0x15, 0x5d, 0x51, 0x25, 0x0a, 0x1f,
0xd3, 0x86, 0x79, 0x1c, 0x4b, 0xaa, 0xfa, 0x29, 0x2c, 0xe6, 0x9e, 0x71, 0xc8, 0x1c, 0xbd, 0xee,
0x8b, 0x9e, 0xb9, 0xc6, 0x7f, 0x8e, 0xe5, 0x49, 0xb5, 0xdf, 0x83, 0x6a, 0xf2, 0xec, 0x19, 0xcd,
0x40, 0xee, 0x31, 0x64, 0x34, 0x46, 0xf5, 0x1d, 0x71, 0x73, 0x06, 0xbd, 0x1f, 0x09, 0x0b, 0x58,
0x3c, 0x2e, 0xac, 0x80, 0x7d, 0xe3, 0x5c, 0x01, 0xc0, 0x96, 0xa1, 0x9d, 0xdd, 0x96, 0xfd, 0x3f,
0x86, 0x06, 0xe8, 0xbf, 0xaf, 0x85, 0x63, 0x0c, 0x33, 0xcf, 0x36, 0x8e, 0x2e, 0xcc, 0x19, 0xf4,
0x83, 0x06, 0xe7, 0xb6, 0x49, 0x98, 0xbf, 0x69, 0xd1, 0x8d, 0x62, 0x23, 0x13, 0x6e, 0x64, 0xe3,
0xf1, 0xb4, 0x27, 0x62, 0x54, 0xad, 0x39, 0x83, 0xf6, 0x65, 0xd8, 0x59, 0x65, 0xa3, 0xcb, 0x85,
0x25, 0x9c, 0x66, 0x6f, 0x65, 0xd2, 0x72, 0x12, 0xea, 0x07, 0x1b, 0xbf, 0xbd, 0x5c, 0xd1, 0x7e,
0x7f, 0xb9, 0xa2, 0xfd, 0xf1, 0x72, 0x45, 0xfb, 0xec, 0xd6, 0x2b, 0x3e, 0x90, 0x2b, 0xdf, 0xf2,
0x31, 0xa3, 0x4e, 0x97, 0x12, 0x2f, 0x3c, 0x9c, 0x93, 0x9f, 0xc3, 0x6f, 0xfd, 0x1d, 0x00, 0x00,
0xff, 0xff, 0x01, 0x70, 0xee, 0x21, 0xea, 0x17, 0x00, 0x00,
// 1597 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0xcd, 0x6f, 0x1b, 0x45,
0x14, 0xcf, 0xda, 0x4e, 0x62, 0x3f, 0xb7, 0x89, 0x33, 0xfd, 0x5a, 0x96, 0x34, 0x4a, 0x17, 0x51,
0x05, 0xda, 0xae, 0xd5, 0xb4, 0x82, 0xaa, 0x15, 0x48, 0x21, 0x4d, 0x53, 0x94, 0xa6, 0x09, 0x9b,
0x82, 0x04, 0x54, 0x54, 0x93, 0xf5, 0x64, 0x3d, 0xd8, 0xde, 0x9d, 0xee, 0xac, 0x8d, 0x52, 0x89,
0x03, 0x27, 0xee, 0x48, 0xf0, 0xaf, 0x70, 0xe4, 0xc4, 0xc7, 0x91, 0x3f, 0x01, 0x95, 0x03, 0xff,
0x06, 0x9a, 0xd9, 0xaf, 0xf1, 0x7a, 0x9d, 0x16, 0x39, 0x4d, 0xc5, 0x25, 0x99, 0x79, 0xf3, 0xbe,
0xe7, 0xcd, 0x9b, 0xdf, 0xac, 0xe1, 0x72, 0x40, 0x98, 0xcf, 0x49, 0x30, 0x20, 0x41, 0x53, 0x0e,
0x69, 0xe8, 0x07, 0x87, 0xca, 0xd0, 0x62, 0x81, 0x1f, 0xfa, 0x08, 0x32, 0x8a, 0x71, 0xd6, 0xf5,
0x5d, 0x5f, 0x92, 0x9b, 0x62, 0x14, 0x71, 0x18, 0x8b, 0xae, 0xef, 0xbb, 0x5d, 0xd2, 0xc4, 0x8c,
0x36, 0xb1, 0xe7, 0xf9, 0x21, 0x0e, 0xa9, 0xef, 0xf1, 0x78, 0xd5, 0xec, 0xdc, 0xe2, 0x16, 0xf5,
0xe5, 0xaa, 0xe3, 0x07, 0xa4, 0x39, 0xb8, 0xde, 0x74, 0x89, 0x47, 0x02, 0x1c, 0x92, 0x56, 0xcc,
0xf3, 0xc0, 0xa5, 0x61, 0xbb, 0xbf, 0x6f, 0x39, 0x7e, 0xaf, 0x89, 0x03, 0x69, 0xe2, 0x6b, 0x39,
0xb8, 0xe6, 0xb4, 0x9a, 0x83, 0xd5, 0x26, 0xeb, 0xb8, 0x42, 0x9e, 0x37, 0x31, 0x63, 0x5d, 0xea,
0x48, 0xfd, 0xcd, 0xc1, 0x75, 0xdc, 0x65, 0x6d, 0x3c, 0xa2, 0xcd, 0xfc, 0x01, 0x60, 0x7e, 0x1b,
0x7b, 0xf4, 0x80, 0xf0, 0xd0, 0x26, 0x4f, 0xfb, 0x84, 0x87, 0xe8, 0x31, 0x54, 0x44, 0x1c, 0xba,
0xb6, 0xac, 0xad, 0xd4, 0x57, 0xef, 0x5b, 0x99, 0x41, 0x2b, 0x31, 0x28, 0x07, 0x4f, 0x9c, 0x96,
0x35, 0x58, 0xb5, 0x58, 0xc7, 0xb5, 0x84, 0x41, 0x4b, 0x31, 0x68, 0x25, 0x06, 0x2d, 0x3b, 0xcd,
0x88, 0x2d, 0xb5, 0x22, 0x03, 0xaa, 0x01, 0x19, 0x50, 0x4e, 0x7d, 0x4f, 0x2f, 0x2d, 0x6b, 0x2b,
0x35, 0x3b, 0x9d, 0x23, 0x1d, 0x66, 0x3d, 0x7f, 0x1d, 0x3b, 0x6d, 0xa2, 0x97, 0x97, 0xb5, 0x95,
0xaa, 0x9d, 0x4c, 0xd1, 0x32, 0xd4, 0x31, 0x63, 0x0f, 0xf0, 0x3e, 0xe9, 0x6e, 0x91, 0x43, 0xbd,
0x22, 0x05, 0x55, 0x92, 0x90, 0xc5, 0x8c, 0x3d, 0xc4, 0x3d, 0xa2, 0x4f, 0xcb, 0xd5, 0x64, 0x8a,
0x16, 0xa1, 0xe6, 0xe1, 0x1e, 0xe1, 0x0c, 0x3b, 0x44, 0xaf, 0xca, 0xb5, 0x8c, 0x80, 0xbe, 0x85,
0x05, 0xc5, 0xf1, 0x3d, 0xbf, 0x1f, 0x38, 0x44, 0x07, 0x19, 0xfa, 0xce, 0x64, 0xa1, 0xaf, 0xe5,
0xd5, 0xda, 0xa3, 0x96, 0xd0, 0x57, 0x30, 0x2d, 0x8b, 0x46, 0xaf, 0x2f, 0x97, 0x8f, 0x35, 0xdb,
0x91, 0x5a, 0xe4, 0xc1, 0x2c, 0xeb, 0xf6, 0x5d, 0xea, 0x71, 0xfd, 0x94, 0xb4, 0xf0, 0x68, 0x32,
0x0b, 0xeb, 0xbe, 0x77, 0x40, 0xdd, 0x6d, 0xec, 0x61, 0x97, 0xf4, 0x88, 0x17, 0xee, 0x4a, 0xe5,
0x76, 0x62, 0x04, 0x3d, 0x83, 0x46, 0xa7, 0xcf, 0x43, 0xbf, 0x47, 0x9f, 0x91, 0x1d, 0x26, 0x8b,
0x5b, 0x3f, 0x2d, 0xb3, 0xf9, 0x70, 0x32, 0xc3, 0x5b, 0x39, 0xad, 0xf6, 0x88, 0x1d, 0x51, 0x24,
0x9d, 0xfe, 0x3e, 0xf9, 0x8c, 0x04, 0xb2, 0xba, 0xe6, 0xa2, 0x22, 0x51, 0x48, 0x51, 0x19, 0xd1,
0x78, 0xc6, 0xf5, 0xf9, 0xe5, 0x72, 0x54, 0x46, 0x29, 0x09, 0xad, 0xc0, 0xfc, 0x80, 0x04, 0xf4,
0xe0, 0x70, 0x8f, 0xba, 0x1e, 0x0e, 0xfb, 0x01, 0xd1, 0x1b, 0xb2, 0x14, 0xf3, 0x64, 0xd4, 0x83,
0xd3, 0x6d, 0xd2, 0xed, 0x89, 0x94, 0xaf, 0x07, 0xa4, 0xc5, 0xf5, 0x05, 0x99, 0xdf, 0xcd, 0xc9,
0x77, 0x50, 0xaa, 0xb3, 0x87, 0xb5, 0x0b, 0xc7, 0x3c, 0xdf, 0x8e, 0x4f, 0x4a, 0x74, 0x46, 0x50,
0xe4, 0x58, 0x8e, 0x8c, 0x2e, 0xc3, 0x5c, 0x18, 0x60, 0xa7, 0x43, 0x3d, 0x77, 0x9b, 0x84, 0x6d,
0xbf, 0xa5, 0x9f, 0x91, 0x99, 0xc8, 0x51, 0x91, 0x03, 0x88, 0x78, 0x78, 0xbf, 0x4b, 0x5a, 0x51,
0x2d, 0x3e, 0x3a, 0x64, 0x84, 0xeb, 0x67, 0x65, 0x14, 0x37, 0x2c, 0xa5, 0xb9, 0xe5, 0x1a, 0x84,
0xb5, 0x31, 0x22, 0xb5, 0xe1, 0x85, 0xc1, 0xa1, 0x5d, 0xa0, 0x0e, 0x75, 0xa0, 0x2e, 0xe2, 0x48,
0x4a, 0xe1, 0x9c, 0x2c, 0x85, 0x8f, 0x27, 0xcb, 0xd1, 0xfd, 0x4c, 0xa1, 0xad, 0x6a, 0x37, 0x36,
0xe0, 0xc2, 0x18, 0xdf, 0x50, 0x03, 0xca, 0x1d, 0x72, 0x28, 0x7b, 0x5a, 0xcd, 0x16, 0x43, 0x74,
0x16, 0xa6, 0x07, 0xb8, 0xdb, 0x27, 0xb2, 0x0b, 0x55, 0xed, 0x68, 0x72, 0xbb, 0x74, 0x4b, 0x33,
0xfb, 0x70, 0xee, 0x91, 0x0c, 0x37, 0x3d, 0x4c, 0x27, 0xd1, 0x19, 0xcd, 0xfb, 0x70, 0x3e, 0x6f,
0x96, 0x33, 0xdf, 0xe3, 0x04, 0x59, 0x80, 0x64, 0xf5, 0x51, 0xd2, 0xca, 0x56, 0xa5, 0x17, 0x55,
0xbb, 0x60, 0xc5, 0xfc, 0xae, 0x04, 0xe7, 0x6d, 0xc2, 0xfd, 0xee, 0x80, 0x24, 0xa5, 0x71, 0x32,
0xcd, 0xfd, 0x4b, 0x28, 0x63, 0xc6, 0x64, 0x46, 0x27, 0xde, 0x65, 0xa5, 0x7d, 0xda, 0x42, 0x2b,
0xba, 0x0a, 0x0b, 0xb8, 0xb7, 0x4f, 0xdd, 0xbe, 0xdf, 0xe7, 0x49, 0x58, 0xf2, 0x9e, 0xa8, 0xd9,
0xa3, 0x0b, 0xa6, 0x03, 0x17, 0x46, 0x52, 0x10, 0xa7, 0x53, 0xbd, 0x82, 0xb4, 0xdc, 0x15, 0x54,
0x68, 0xa4, 0x34, 0xce, 0xc8, 0x6f, 0x1a, 0x34, 0xb2, 0xd3, 0x11, 0xab, 0x5f, 0x84, 0x5a, 0x2f,
0xa6, 0x71, 0x5d, 0x93, 0x2d, 0x26, 0x23, 0x0c, 0xdf, 0x46, 0xa5, 0xfc, 0x6d, 0x74, 0x1e, 0x66,
0x22, 0x9c, 0x11, 0x07, 0x16, 0xcf, 0x86, 0x5c, 0xae, 0xe4, 0x5c, 0x5e, 0x02, 0xe0, 0x69, 0xb9,
0xeb, 0x33, 0x72, 0x55, 0xa1, 0x20, 0x13, 0x4e, 0x45, 0xbd, 0xcb, 0x26, 0xbc, 0xdf, 0x0d, 0xf5,
0x59, 0xc9, 0x31, 0x44, 0x33, 0x7d, 0x98, 0x7f, 0x40, 0x45, 0x0c, 0x07, 0xfc, 0x64, 0x8a, 0xfd,
0x3d, 0xa8, 0x08, 0x63, 0x22, 0xb0, 0xfd, 0x00, 0x7b, 0x4e, 0x9b, 0x24, 0xb9, 0x4a, 0xe7, 0x08,
0x41, 0x25, 0xc4, 0x2e, 0xd7, 0x4b, 0x92, 0x2e, 0xc7, 0xe6, 0xcf, 0xa5, 0xc8, 0xd3, 0x35, 0xc6,
0xf8, 0xeb, 0x07, 0x2c, 0xc5, 0x2d, 0xb4, 0x3c, 0xda, 0x42, 0x73, 0x2e, 0xff, 0x97, 0x16, 0x7a,
0x7c, 0x5d, 0x6d, 0x76, 0x8d, 0x31, 0xe1, 0x08, 0xba, 0x0e, 0x15, 0xcc, 0x58, 0x94, 0xf0, 0xfa,
0xea, 0x45, 0xd5, 0xd1, 0x98, 0x45, 0xfc, 0x8f, 0x5d, 0x92, 0xac, 0xc6, 0xfb, 0x50, 0x4b, 0x49,
0x2f, 0x32, 0x5b, 0x53, 0xcd, 0xfe, 0x33, 0x03, 0x6f, 0x88, 0x9c, 0xee, 0xc9, 0x42, 0x5e, 0x63,
0xec, 0x2e, 0x09, 0x31, 0xed, 0xf2, 0x4f, 0xfa, 0x24, 0x38, 0x7c, 0xc5, 0x5b, 0xe7, 0xc2, 0x4c,
0x74, 0x0e, 0xe2, 0x8e, 0x74, 0xec, 0x80, 0x2e, 0x56, 0x9f, 0xa1, 0xb8, 0xf2, 0xab, 0x41, 0x71,
0x45, 0xa8, 0xaa, 0x72, 0x42, 0xa8, 0x6a, 0x3c, 0xb0, 0x56, 0xe0, 0xfa, 0xcc, 0x30, 0x5c, 0x2f,
0x00, 0x2b, 0xb3, 0x2f, 0x0b, 0x56, 0xaa, 0x85, 0x60, 0xa5, 0x57, 0x78, 0xd2, 0x6a, 0x32, 0xdd,
0x1f, 0xa8, 0x05, 0x3c, 0xb6, 0xd6, 0x26, 0x81, 0x2d, 0xf0, 0x7f, 0x80, 0x2d, 0xdf, 0xcb, 0x5b,
0x9f, 0xf9, 0x59, 0xdc, 0xe9, 0x95, 0x24, 0x3a, 0xa9, 0xb8, 0x1c, 0x22, 0x3d, 0x72, 0x8c, 0x6e,
0xc2, 0x6c, 0x87, 0xfb, 0x9e, 0x47, 0xc2, 0xf8, 0x74, 0x18, 0x6a, 0x1a, 0xb7, 0xa2, 0xa5, 0x35,
0xc6, 0xf6, 0x18, 0x71, 0xec, 0x84, 0x15, 0x5d, 0x81, 0x8a, 0x70, 0x5d, 0x5e, 0x4f, 0xf5, 0xd5,
0x0b, 0xaa, 0x88, 0x88, 0x2f, 0xe1, 0x97, 0x4c, 0xe8, 0x36, 0xd4, 0xd2, 0x72, 0x8a, 0xeb, 0x75,
0x71, 0xc8, 0x48, 0xb2, 0x98, 0x88, 0x65, 0xec, 0x42, 0xb6, 0x45, 0x03, 0xe2, 0x48, 0xa8, 0x33,
0x3d, 0x2a, 0x7b, 0x37, 0x59, 0x4c, 0x65, 0x53, 0x76, 0xf3, 0x57, 0x0d, 0x2e, 0x65, 0x75, 0x90,
0x14, 0xdc, 0x36, 0x09, 0x71, 0x0b, 0x87, 0xf8, 0xf5, 0x5f, 0x1b, 0x97, 0x61, 0xce, 0x69, 0x13,
0xa7, 0x93, 0xbd, 0x31, 0xa2, 0xe7, 0x6e, 0x8e, 0x6a, 0xfe, 0x5e, 0x82, 0xb9, 0xe1, 0x8d, 0x10,
0x3b, 0x29, 0xd0, 0x42, 0xb2, 0x93, 0x62, 0x8c, 0x76, 0xe1, 0x14, 0xf1, 0x06, 0x34, 0xf0, 0x3d,
0xf1, 0x22, 0x4b, 0x9a, 0xd0, 0xd5, 0xf1, 0xdb, 0x69, 0x6d, 0x28, 0xec, 0xd1, 0x21, 0x18, 0xd2,
0x80, 0x3c, 0x00, 0x86, 0x03, 0xdc, 0x23, 0x21, 0x09, 0x44, 0xa7, 0x29, 0x1f, 0x43, 0xa7, 0x89,
0x3c, 0xd8, 0x4d, 0xd4, 0xda, 0x8a, 0x05, 0xe3, 0x09, 0x2c, 0x8c, 0xb8, 0x54, 0x50, 0xfb, 0x37,
0xd5, 0xda, 0xaf, 0xaf, 0x2e, 0x15, 0x44, 0xa8, 0xa8, 0x51, 0xcf, 0xc6, 0x2f, 0x25, 0xa8, 0x2b,
0xf5, 0x59, 0x98, 0xc6, 0x25, 0x00, 0x29, 0x70, 0x8f, 0x76, 0xe3, 0x4b, 0xbc, 0x66, 0x2b, 0x14,
0xd4, 0x29, 0x48, 0xca, 0xd6, 0xe4, 0x2d, 0xa1, 0x30, 0x23, 0x02, 0x08, 0x4a, 0xd3, 0x3c, 0x6e,
0xba, 0xf1, 0x0c, 0x7d, 0x03, 0x73, 0x07, 0xb4, 0x4b, 0x76, 0x33, 0x47, 0x66, 0xa4, 0x23, 0x3b,
0x93, 0x3b, 0x72, 0x4f, 0xd5, 0x6b, 0xe7, 0xcc, 0x98, 0xef, 0x42, 0x23, 0x7f, 0x5c, 0x85, 0x93,
0xb4, 0x87, 0xdd, 0x34, 0x5b, 0xf1, 0xcc, 0xfc, 0x51, 0x03, 0x34, 0xba, 0x1f, 0xe3, 0x92, 0xde,
0xb9, 0xc5, 0x93, 0x27, 0x7b, 0x74, 0x50, 0x14, 0x0a, 0xda, 0x82, 0x7a, 0x8b, 0xf0, 0x90, 0x7a,
0xd2, 0xe1, 0xb8, 0x89, 0xbc, 0x73, 0xf4, 0xc6, 0xdf, 0xcd, 0x04, 0x6c, 0x55, 0xda, 0xfc, 0x14,
0x2e, 0x1e, 0xc9, 0xad, 0xc0, 0x6f, 0x6d, 0x08, 0x7e, 0x1f, 0x09, 0xda, 0x4d, 0x04, 0x8d, 0x7c,
0x37, 0x32, 0x9f, 0xc2, 0x82, 0xc8, 0xe9, 0x7a, 0x1b, 0x07, 0xe1, 0x09, 0x41, 0xea, 0x3b, 0x50,
0x4b, 0x4d, 0x16, 0xe6, 0xda, 0x80, 0xea, 0x20, 0xf9, 0xf4, 0x11, 0x61, 0xea, 0x74, 0x6e, 0xae,
0x01, 0x52, 0xfd, 0x8d, 0xef, 0x8d, 0x2b, 0x30, 0x4d, 0x43, 0xd2, 0x4b, 0x90, 0xe2, 0xb9, 0x7c,
0xbb, 0x97, 0xec, 0x76, 0xc4, 0xb3, 0xfa, 0xf7, 0x34, 0x2c, 0x64, 0x5d, 0x57, 0xfc, 0xa5, 0x0e,
0x41, 0x3b, 0xd0, 0xd8, 0x8c, 0x3f, 0x3a, 0x26, 0x2f, 0x25, 0xf4, 0xe6, 0x11, 0x5f, 0x17, 0x8c,
0xc5, 0xe2, 0xc5, 0xc8, 0x23, 0x73, 0x0a, 0x7d, 0x0e, 0x73, 0xc3, 0xcf, 0x64, 0x74, 0x49, 0x95,
0x28, 0x7c, 0xb9, 0x1b, 0xe6, 0x51, 0x2c, 0xa9, 0xea, 0xc7, 0x30, 0x9f, 0x7b, 0x33, 0x22, 0x73,
0x18, 0x5b, 0x14, 0xbd, 0xa9, 0x8d, 0xb7, 0x8e, 0xe4, 0x49, 0xb5, 0xdf, 0x81, 0x6a, 0xf2, 0xc6,
0x1a, 0xce, 0x40, 0xee, 0xe5, 0x65, 0x34, 0x86, 0xf5, 0x1d, 0x70, 0x73, 0x0a, 0x7d, 0x18, 0x09,
0x0b, 0x0c, 0x3e, 0x2a, 0xac, 0xbc, 0x2c, 0x8c, 0x33, 0x05, 0x68, 0x5e, 0x86, 0x76, 0x7a, 0x53,
0xf6, 0xff, 0x18, 0x1a, 0xa0, 0xb7, 0x5f, 0x0a, 0x34, 0x19, 0x66, 0x9e, 0x6d, 0x14, 0x5d, 0x98,
0x53, 0xe8, 0x27, 0x0d, 0xce, 0x6c, 0x92, 0x30, 0x7f, 0xd3, 0xa2, 0x6b, 0xc5, 0x46, 0xc6, 0xdc,
0xc8, 0xc6, 0xc3, 0x49, 0x4f, 0xc4, 0xb0, 0x5a, 0x73, 0x0a, 0xed, 0xca, 0xb0, 0xb3, 0xca, 0x46,
0x17, 0x0b, 0x4b, 0x38, 0xcd, 0xde, 0xd2, 0xb8, 0xe5, 0x24, 0xd4, 0x8f, 0xd6, 0xfe, 0x78, 0xbe,
0xa4, 0xfd, 0xf9, 0x7c, 0x49, 0xfb, 0xeb, 0xf9, 0x92, 0xf6, 0xc5, 0x8d, 0x17, 0x7c, 0x8d, 0x57,
0x7e, 0x38, 0xc0, 0x8c, 0x3a, 0x5d, 0x4a, 0xbc, 0x70, 0x7f, 0x46, 0x7e, 0x7b, 0xbf, 0xf1, 0x6f,
0x00, 0x00, 0x00, 0xff, 0xff, 0x30, 0x2a, 0x03, 0x20, 0x57, 0x18, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -2692,6 +2700,18 @@ func (m *RepoServerAppDetailsQuery) MarshalToSizedBuffer(dAtA []byte) (int, erro
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.HelmOptions != nil {
{
size, err := m.HelmOptions.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintRepository(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x52
}
if len(m.EnabledSourceTypes) > 0 {
for k := range m.EnabledSourceTypes {
v := m.EnabledSourceTypes[k]
@ -3722,6 +3742,10 @@ func (m *RepoServerAppDetailsQuery) Size() (n int) {
n += mapEntrySize + 1 + sovRepository(uint64(mapEntrySize))
}
}
if m.HelmOptions != nil {
l = m.HelmOptions.Size()
n += 1 + l + sovRepository(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@ -6363,6 +6387,42 @@ func (m *RepoServerAppDetailsQuery) Unmarshal(dAtA []byte) error {
}
m.EnabledSourceTypes[mapkey] = mapvalue
iNdEx = postIndex
case 10:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field HelmOptions", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRepository
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthRepository
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthRepository
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.HelmOptions == nil {
m.HelmOptions = &v1alpha1.HelmOptions{}
}
if err := m.HelmOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRepository(dAtA[iNdEx:])

View file

@ -27,6 +27,7 @@ import (
"github.com/ghodss/yaml"
gogit "github.com/go-git/go-git/v5"
"github.com/google/go-jsonnet"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/semaphore"
"google.golang.org/grpc/codes"
@ -52,6 +53,7 @@ import (
"github.com/argoproj/argo-cd/v2/util/grpc"
"github.com/argoproj/argo-cd/v2/util/helm"
"github.com/argoproj/argo-cd/v2/util/io"
pathutil "github.com/argoproj/argo-cd/v2/util/io/path"
"github.com/argoproj/argo-cd/v2/util/ksonnet"
"github.com/argoproj/argo-cd/v2/util/kustomize"
"github.com/argoproj/argo-cd/v2/util/text"
@ -606,153 +608,6 @@ func runHelmBuild(appPath string, h helm.Helm) error {
return ioutil.WriteFile(markerFile, []byte("marker"), 0644)
}
// resolveSymbolicLinkRecursive resolves the symlink path recursively to its
// canonical path on the file system, with a maximum nesting level of maxDepth.
// If path is not a symlink, returns the verbatim copy of path and err of nil.
func resolveSymbolicLinkRecursive(path string, maxDepth int) (string, error) {
resolved, err := os.Readlink(path)
if err != nil {
// path is not a symbolic link
_, ok := err.(*os.PathError)
if ok {
return path, nil
}
// Other error has occured
return "", err
}
if maxDepth == 0 {
return "", fmt.Errorf("maximum nesting level reached")
}
// If we resolved to a relative symlink, make sure we use the absolute
// path for further resolving
if !strings.HasPrefix(resolved, "/") {
basePath := filepath.Dir(path)
resolved = filepath.Join(basePath, resolved)
}
return resolveSymbolicLinkRecursive(resolved, maxDepth-1)
}
// isURLSchemeAllowed returns true if the protocol scheme is in the list of
// allowed URL schemes.
func isURLSchemeAllowed(scheme string, allowed []string) bool {
isAllowed := false
if len(allowed) > 0 {
for _, s := range allowed {
if strings.EqualFold(scheme, s) {
isAllowed = true
break
}
}
}
// Empty scheme means local file
return isAllowed && scheme != ""
}
// resolveHelmValueFilePath will inspect and resolve a path to a Helm value
// file, and make sure that its final path is within the boundaries of the
// path specified in repoRoot.
//
// appPath is the path we're operating in, e.g. where a Helm chart was unpacked
// to. repoRoot is the path to the root of the repository.
//
// If either appPath or repoRoot is relative, it will be treated as relative
// to the current working directory.
//
// valueFile is the path to a value file, relative to appPath. If valueFile is
// specified as an absolute path (i.e. leading slash), it will be treated as
// relative to the repoRoot. In case valueFile is a symlink in the extracted
// chart, it will be resolved recursively and the decision of whether it is in
// the boundary of repoRoot will be made using the final resolved path.
// valueFile can also be a remote URL with a protocol scheme as prefix,
// in which case the scheme must be included in the list of allowed schemes
// specified by allowedURLSchemes.
//
// Will return an error if either valueFile is outside the boundaries of the
// repoRoot, valueFile is an URL with a forbidden protocol scheme or if
// valueFile is a recursive symlink nested too deep. May return errors for
// other reasons as well.
//
// resolvedPath will hold the absolute, resolved path for valueFile on success
// or set to the empty string on failure.
//
// isRemote will be set to true if valueFile is an URL using an allowed
// protocol scheme, or to false if it resolved to a local file.
func resolveHelmValueFilePath(appPath, repoRoot, valueFile string, allowedURLSchemes []string) (resolvedPath string, isRemote bool, err error) {
// We do not provide the path in the error message, because it will be
// returned to the user and could be used for information gathering.
// Instead, we log the concrete error details.
resolveFailure := func(path string, err error) error {
log.Errorf("failed to resolve path '%s': %v", path, err)
return fmt.Errorf("internal error: failed to resolve path. Check logs for more details")
}
// A value file can be specified as an URL to a remote resource.
// We only allow certain URL schemes for remote value files.
url, err := url.Parse(valueFile)
if err == nil {
// If scheme is empty, it means we parsed a path only
if url.Scheme != "" {
if isURLSchemeAllowed(url.Scheme, allowedURLSchemes) {
return valueFile, true, nil
} else {
return "", false, fmt.Errorf("the URL scheme '%s' is not allowed", url.Scheme)
}
}
}
// Ensure that our repository root is absolute
absRepoPath, err := filepath.Abs(repoRoot)
if err != nil {
return "", false, resolveFailure(repoRoot, err)
}
// If the path to the file is relative, join it with the current working directory (appPath)
// Otherwise, join it with the repository's root
path := valueFile
if !filepath.IsAbs(path) {
absWorkDir, err := filepath.Abs(appPath)
if err != nil {
return "", false, resolveFailure(repoRoot, err)
}
path = filepath.Join(absWorkDir, path)
} else {
path = filepath.Join(absRepoPath, path)
}
// Ensure any symbolic link is resolved before we
delinkedPath, err := resolveSymbolicLinkRecursive(path, 10)
if err != nil {
return "", false, resolveFailure(path, err)
}
path = delinkedPath
// Resolve the joined path to an absolute path
path, err = filepath.Abs(path)
if err != nil {
return "", false, resolveFailure(path, err)
}
// Ensure our root path has a trailing slash, otherwise the following check
// would return true if root is /foo and path would be /foo2
requiredRootPath := absRepoPath
if !strings.HasSuffix(requiredRootPath, "/") {
requiredRootPath += "/"
}
// Make sure that the resolved path to values file is within the repository's root path
if !strings.HasPrefix(path, requiredRootPath) {
return "", false, fmt.Errorf("value file '%s' resolved to outside repository root", valueFile)
}
return path, false, nil
}
func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclient.ManifestRequest, isLocal bool) ([]*unstructured.Unstructured, error) {
concurrencyAllowed := isConcurrencyAllowed(appPath)
if !concurrencyAllowed {
@ -767,7 +622,7 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
APIVersions: q.ApiVersions,
Set: map[string]string{},
SetString: map[string]string{},
SetFile: map[string]string{},
SetFile: map[string]pathutil.ResolvedFilePath{},
}
appHelm := q.ApplicationSource.Helm
@ -784,17 +639,13 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
for _, val := range appHelm.ValueFiles {
// This will resolve val to an absolute path (or an URL)
var protocols []string
if q.HelmOptions != nil {
protocols = q.HelmOptions.ValuesFileSchemes
}
path, isRemote, err := resolveHelmValueFilePath(appPath, repoRoot, val, protocols)
path, isRemote, err := pathutil.ResolveFilePath(appPath, repoRoot, val, q.GetValuesFileSchemes())
if err != nil {
return nil, err
}
if !isRemote {
_, err = os.Stat(path)
_, err = os.Stat(string(path))
if os.IsNotExist(err) {
if appHelm.IgnoreMissingValueFiles {
log.Debugf(" %s values file does not exist", path)
@ -807,18 +658,17 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
}
if appHelm.Values != "" {
file, err := ioutil.TempFile("", "values-*.yaml")
rand, err := uuid.NewRandom()
if err != nil {
return nil, err
}
p := file.Name()
p := path.Join(os.TempDir(), rand.String())
defer func() { _ = os.RemoveAll(p) }()
err = ioutil.WriteFile(p, []byte(appHelm.Values), 0644)
if err != nil {
return nil, err
}
defer file.Close()
templateOpts.Values = append(templateOpts.Values, p)
templateOpts.Values = append(templateOpts.Values, pathutil.ResolvedFilePath(p))
}
for _, p := range appHelm.Parameters {
@ -829,7 +679,11 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
}
}
for _, p := range appHelm.FileParameters {
templateOpts.SetFile[p.Name] = p.Path
resolvedPath, _, err := pathutil.ResolveFilePath(appPath, repoRoot, env.Envsubst(p.Path), q.GetValuesFileSchemes())
if err != nil {
return nil, err
}
templateOpts.SetFile[p.Name] = resolvedPath
}
passCredentials = appHelm.PassCredentials
templateOpts.SkipCrds = appHelm.SkipCrds
@ -843,9 +697,6 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
for i, j := range templateOpts.SetString {
templateOpts.SetString[i] = env.Envsubst(j)
}
for i, j := range templateOpts.SetFile {
templateOpts.SetFile[i] = env.Envsubst(j)
}
repos, err := getHelmDependencyRepos(appPath)
if err != nil {
@ -1285,11 +1136,11 @@ func makeJsonnetVm(appPath string, repoRoot string, sourceJsonnet v1alpha1.Appli
// Jsonnet Imports relative to the repository path
jpaths := []string{appPath}
for _, p := range sourceJsonnet.Libs {
jpath := path.Join(repoRoot, p)
if !strings.HasPrefix(jpath, repoRoot) {
return nil, status.Errorf(codes.FailedPrecondition, "%s: referenced library points outside the repository", p)
jpath, _, err := pathutil.ResolveFilePath(appPath, repoRoot, p, nil)
if err != nil {
return nil, err
}
jpaths = append(jpaths, jpath)
jpaths = append(jpaths, string(jpath))
}
vm.Importer(&jsonnet.FileImporter{
@ -1467,7 +1318,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD
return err
}
case v1alpha1.ApplicationSourceTypeHelm:
if err := populateHelmAppDetails(res, opContext.appPath, q); err != nil {
if err := populateHelmAppDetails(res, opContext.appPath, repoRoot, q); err != nil {
return err
}
case v1alpha1.ApplicationSourceTypeKustomize:
@ -1529,7 +1380,7 @@ func populateKsonnetAppDetails(res *apiclient.RepoAppDetailsResponse, appPath st
return nil
}
func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath string, q *apiclient.RepoServerAppDetailsQuery) error {
func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath string, repoRoot string, q *apiclient.RepoServerAppDetailsQuery) error {
var selectedValueFiles []string
if q.Source.Helm != nil {
@ -1563,7 +1414,16 @@ func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath strin
if err := loadFileIntoIfExists(filepath.Join(appPath, "values.yaml"), &res.Helm.Values); err != nil {
return err
}
params, err := h.GetParameters(selectedValueFiles)
var resolvedSelectedValueFiles []pathutil.ResolvedFilePath
// drop not allowed values files
for _, file := range selectedValueFiles {
if resolvedFile, _, err := pathutil.ResolveFilePath(appPath, repoRoot, file, q.GetValuesFileSchemes()); err == nil {
resolvedSelectedValueFiles = append(resolvedSelectedValueFiles, resolvedFile)
} else {
log.Debugf("Values file %s is not allowed: %v", file, err)
}
}
params, err := h.GetParameters(resolvedSelectedValueFiles)
if err != nil {
return err
}

View file

@ -102,6 +102,7 @@ message RepoServerAppDetailsQuery {
bool noRevisionCache = 7;
string trackingMethod = 8;
map<string, bool> enabledSourceTypes = 9;
github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmOptions helmOptions = 10;
}
// RepoAppDetailsResponse application details

View file

@ -254,7 +254,7 @@ func TestGenerateJsonnetManifestInDir(t *testing.T) {
Jsonnet: argoappv1.ApplicationSourceJsonnet{
ExtVars: []argoappv1.JsonnetVar{{Name: "extVarString", Value: "extVarString"}, {Name: "extVarCode", Value: "\"extVarCode\"", Code: true}},
TLAs: []argoappv1.JsonnetVar{{Name: "tlaString", Value: "tlaString"}, {Name: "tlaCode", Value: "\"tlaCode\"", Code: true}},
Libs: []string{"testdata/jsonnet/vendor"},
Libs: []string{"./vendor"},
},
},
},
@ -264,6 +264,25 @@ func TestGenerateJsonnetManifestInDir(t *testing.T) {
assert.Equal(t, 2, len(res1.Manifests))
}
func TestGenerateJsonnetLibOutside(t *testing.T) {
service := newService(".")
q := apiclient.ManifestRequest{
Repo: &argoappv1.Repository{},
ApplicationSource: &argoappv1.ApplicationSource{
Path: "./testdata/jsonnet",
Directory: &argoappv1.ApplicationSourceDirectory{
Jsonnet: argoappv1.ApplicationSourceJsonnet{
Libs: []string{"../../../testdata/jsonnet/vendor"},
},
},
},
}
_, err := service.GenerateManifest(context.Background(), &q)
require.Error(t, err)
require.Contains(t, err.Error(), "value file '../../../testdata/jsonnet/vendor' resolved to outside repository root")
}
func TestGenerateKsonnetManifest(t *testing.T) {
service := newService("../..")
@ -913,9 +932,7 @@ func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) {
})
}
// The requested file parameter (`/tmp/external-secret.txt`) is outside the app path
// (`./util/helm/testdata/redis`), and outside the repo directory. It is used as a means
// of providing direct content to a helm chart via a specific key.
// File parameter should not allow traversal outside of the repository root
func TestGenerateHelmWithAbsoluteFileParameter(t *testing.T) {
service := newService("../..")
@ -937,16 +954,14 @@ func TestGenerateHelmWithAbsoluteFileParameter(t *testing.T) {
Helm: &argoappv1.ApplicationSourceHelm{
ValueFiles: []string{"values-production.yaml"},
Values: `cluster: {slaveCount: 2}`,
FileParameters: []argoappv1.HelmFileParameter{
argoappv1.HelmFileParameter{
Name: "passwordContent",
Path: externalSecretPath,
},
},
FileParameters: []argoappv1.HelmFileParameter{{
Name: "passwordContent",
Path: externalSecretPath,
}},
},
},
})
assert.NoError(t, err)
assert.Error(t, err)
}
// The requested file parameter (`../external/external-secret.txt`) is outside the app path
@ -1738,177 +1753,6 @@ func TestResolveRevisionNegativeScenarios(t *testing.T) {
}
func Test_resolveSymlinkRecursive(t *testing.T) {
testsDir, err := filepath.Abs("./testdata/symlinks")
if err != nil {
panic(err)
}
t.Run("Resolve non-symlink", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/foo", 2)
assert.NoError(t, err)
assert.Equal(t, testsDir+"/foo", r)
})
t.Run("Successfully resolve symlink", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/bar", 2)
assert.NoError(t, err)
assert.Equal(t, testsDir+"/foo", r)
})
t.Run("Do not allow symlink at all", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/bar", 0)
assert.Error(t, err)
assert.Equal(t, "", r)
})
t.Run("Error because too nested symlink", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/bam", 2)
assert.Error(t, err)
assert.Equal(t, "", r)
})
t.Run("No such file or directory", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/foobar", 2)
assert.NoError(t, err)
assert.Equal(t, testsDir+"/foobar", r)
})
}
func Test_isURLSchemeAllowed(t *testing.T) {
type testdata struct {
name string
scheme string
allowed []string
expected bool
}
var tts []testdata = []testdata{
{
name: "Allowed scheme matches",
scheme: "http",
allowed: []string{"http", "https"},
expected: true,
},
{
name: "Allowed scheme matches only partially",
scheme: "http",
allowed: []string{"https"},
expected: false,
},
{
name: "Scheme is not allowed",
scheme: "file",
allowed: []string{"http", "https"},
expected: false,
},
{
name: "Empty scheme with valid allowances is forbidden",
scheme: "",
allowed: []string{"http", "https"},
expected: false,
},
{
name: "Empty scheme with empty allowances is forbidden",
scheme: "",
allowed: []string{},
expected: false,
},
{
name: "Some scheme with empty allowances is forbidden",
scheme: "file",
allowed: []string{},
expected: false,
},
}
for _, tt := range tts {
t.Run(tt.name, func(t *testing.T) {
r := isURLSchemeAllowed(tt.scheme, tt.allowed)
assert.Equal(t, tt.expected, r)
})
}
}
var allowedHelmRemoteProtocols = []string{"http", "https"}
func Test_resolveHelmValueFilePath(t *testing.T) {
t.Run("Resolve normal relative path into absolute path", func(t *testing.T) {
p, remote, err := resolveHelmValueFilePath("/foo/bar", "/foo", "baz/bim.yaml", allowedHelmRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, "/foo/bar/baz/bim.yaml", p)
})
t.Run("Resolve normal relative path into absolute path", func(t *testing.T) {
p, remote, err := resolveHelmValueFilePath("/foo/bar", "/foo", "baz/../../bim.yaml", allowedHelmRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, "/foo/bim.yaml", p)
})
t.Run("Error on path resolving outside repository root", func(t *testing.T) {
p, remote, err := resolveHelmValueFilePath("/foo/bar", "/foo", "baz/../../../bim.yaml", allowedHelmRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", p)
})
t.Run("Return verbatim URL", func(t *testing.T) {
url := "https://some.where/foo,yaml"
p, remote, err := resolveHelmValueFilePath("/foo/bar", "/foo", url, allowedHelmRemoteProtocols)
assert.NoError(t, err)
assert.True(t, remote)
assert.Equal(t, url, p)
})
t.Run("URL scheme not allowed", func(t *testing.T) {
url := "file:///some.where/foo,yaml"
p, remote, err := resolveHelmValueFilePath("/foo/bar", "/foo", url, allowedHelmRemoteProtocols)
assert.Error(t, err)
assert.False(t, remote)
assert.Equal(t, "", p)
})
t.Run("Implicit URL by absolute path", func(t *testing.T) {
p, remote, err := resolveHelmValueFilePath("/foo/bar", "/foo", "/baz.yaml", allowedHelmRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, "/foo/baz.yaml", p)
})
t.Run("Relative app path", func(t *testing.T) {
p, remote, err := resolveHelmValueFilePath(".", "/foo", "/baz.yaml", allowedHelmRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, "/foo/baz.yaml", p)
})
t.Run("Relative repo path", func(t *testing.T) {
c, err := os.Getwd()
require.NoError(t, err)
p, remote, err := resolveHelmValueFilePath(".", ".", "baz.yaml", allowedHelmRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, c+"/baz.yaml", p)
})
t.Run("Overlapping root prefix without trailing slash", func(t *testing.T) {
p, remote, err := resolveHelmValueFilePath(".", "/foo", "../foo2/baz.yaml", allowedHelmRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", p)
})
t.Run("Overlapping root prefix with trailing slash", func(t *testing.T) {
p, remote, err := resolveHelmValueFilePath(".", "/foo/", "../foo2/baz.yaml", allowedHelmRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", p)
})
t.Run("Garbage input as values file", func(t *testing.T) {
p, remote, err := resolveHelmValueFilePath(".", "/foo/", "kfdj\\ks&&&321209.,---e32908923%$§!\"", allowedHelmRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", p)
})
t.Run("NUL-byte path input as values file", func(t *testing.T) {
p, remote, err := resolveHelmValueFilePath(".", "/foo/", "\000", allowedHelmRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", p)
})
}
func TestDirectoryPermissionInitializer(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)

View file

@ -431,6 +431,7 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app
NoCache: true,
TrackingMethod: string(argoutil.GetTrackingMethod(s.settingsMgr)),
EnabledSourceTypes: enabledSourceTypes,
HelmOptions: helmOptions,
})
return err
}); err != nil {

View file

@ -332,11 +332,16 @@ func (s *Server) GetAppDetails(ctx context.Context, q *repositorypkg.RepoAppDeta
if err != nil {
return nil, err
}
helmOptions, err := s.settings.GetHelmSettings()
if err != nil {
return nil, err
}
return repoClient.GetAppDetails(ctx, &apiclient.RepoServerAppDetailsQuery{
Repo: repo,
Source: q.Source,
Repos: helmRepos,
KustomizeOptions: kustomizeOptions,
HelmOptions: helmOptions,
AppName: q.AppName,
})
}

View file

@ -252,6 +252,7 @@ func ValidateRepo(
// don't use case during application change to make sure to fetch latest git/helm revisions
NoRevisionCache: true,
TrackingMethod: string(GetTrackingMethod(settingsMgr)),
HelmOptions: helmOptions,
})
if err != nil {
conditions = append(conditions, argoappv1.ApplicationCondition{

View file

@ -268,6 +268,7 @@ func TestValidateRepo(t *testing.T) {
Source: &app.Spec.Source,
Repos: helmRepos,
KustomizeOptions: kustomizeOptions,
HelmOptions: &argoappv1.HelmOptions{ValuesFileSchemes: []string{"https", "http"}},
NoRevisionCache: true,
}).Return(&apiclient.RepoAppDetailsResponse{}, nil)

View file

@ -11,6 +11,7 @@ import (
executil "github.com/argoproj/argo-cd/v2/util/exec"
"github.com/argoproj/argo-cd/v2/util/io"
pathutil "github.com/argoproj/argo-cd/v2/util/io/path"
"github.com/argoproj/argo-cd/v2/util/proxy"
)
@ -286,8 +287,8 @@ type TemplateOpts struct {
APIVersions []string
Set map[string]string
SetString map[string]string
SetFile map[string]string
Values []string
SetFile map[string]pathutil.ResolvedFilePath
Values []pathutil.ResolvedFilePath
SkipCrds bool
}
@ -323,10 +324,10 @@ func (c *Cmd) template(chartPath string, opts *TemplateOpts) (string, error) {
args = append(args, "--set-string", key+"="+cleanSetParameters(val))
}
for key, val := range opts.SetFile {
args = append(args, "--set-file", key+"="+cleanSetParameters(val))
args = append(args, "--set-file", key+"="+cleanSetParameters(string(val)))
}
for _, val := range opts.Values {
args = append(args, "--values", val)
args = append(args, "--values", string(val))
}
for _, v := range opts.APIVersions {
args = append(args, "--api-versions", v)

View file

@ -13,6 +13,7 @@ import (
"github.com/argoproj/argo-cd/v2/util/config"
executil "github.com/argoproj/argo-cd/v2/util/exec"
pathutil "github.com/argoproj/argo-cd/v2/util/io/path"
)
type HelmRepository struct {
@ -27,7 +28,7 @@ type Helm interface {
// Template returns a list of unstructured objects from a `helm template` command
Template(opts *TemplateOpts) (string, error)
// GetParameters returns a list of chart parameters taking into account values in provided YAML files.
GetParameters(valuesFiles []string) (map[string]string, error)
GetParameters(valuesFiles []pathutil.ResolvedFilePath) (map[string]string, error)
// DependencyBuild runs `helm dependency build` to download a chart's dependencies
DependencyBuild() error
// Init runs `helm init --client-only`
@ -129,13 +130,14 @@ func Version(shortForm bool) (string, error) {
return strings.TrimSpace(version), nil
}
func (h *helm) GetParameters(valuesFiles []string) (map[string]string, error) {
func (h *helm) GetParameters(valuesFiles []pathutil.ResolvedFilePath) (map[string]string, error) {
out, err := h.cmd.inspectValues(".")
if err != nil {
return nil, err
}
values := []string{out}
for _, file := range valuesFiles {
for i := range valuesFiles {
file := string(valuesFiles[i])
var fileValues []byte
parsedURL, err := url.ParseRequestURI(file)
if err == nil && (parsedURL.Scheme == "http" || parsedURL.Scheme == "https") {

View file

@ -5,8 +5,9 @@ import (
"os"
"testing"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/argoproj/argo-cd/v2/util/io/path"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1"
apiv1 "k8s.io/api/core/v1"
@ -56,7 +57,7 @@ func TestHelmTemplateValues(t *testing.T) {
assert.NoError(t, err)
opts := TemplateOpts{
Name: "test",
Values: []string{"values-production.yaml"},
Values: []path.ResolvedFilePath{"values-production.yaml"},
}
objs, err := template(h, &opts)
assert.Nil(t, err)
@ -75,7 +76,7 @@ func TestHelmTemplateValues(t *testing.T) {
func TestHelmGetParams(t *testing.T) {
h, err := NewHelmApp("./testdata/redis", nil, false, "", "", false)
assert.NoError(t, err)
params, err := h.GetParameters([]string{})
params, err := h.GetParameters(nil)
assert.Nil(t, err)
slaveCountParam := params["cluster.slaveCount"]
@ -85,7 +86,7 @@ func TestHelmGetParams(t *testing.T) {
func TestHelmGetParamsValueFiles(t *testing.T) {
h, err := NewHelmApp("./testdata/redis", nil, false, "", "", false)
assert.NoError(t, err)
params, err := h.GetParameters([]string{"values-production.yaml"})
params, err := h.GetParameters([]path.ResolvedFilePath{"values-production.yaml"})
assert.Nil(t, err)
slaveCountParam := params["cluster.slaveCount"]
@ -95,7 +96,7 @@ func TestHelmGetParamsValueFiles(t *testing.T) {
func TestHelmGetParamsValueFilesThatExist(t *testing.T) {
h, err := NewHelmApp("./testdata/redis", nil, false, "", "", false)
assert.NoError(t, err)
params, err := h.GetParameters([]string{"values-missing.yaml", "values-production.yaml"})
params, err := h.GetParameters([]path.ResolvedFilePath{"values-missing.yaml", "values-production.yaml"})
assert.Nil(t, err)
slaveCountParam := params["cluster.slaveCount"]

158
util/io/path/resolved.go Normal file
View file

@ -0,0 +1,158 @@
package path
import (
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
log "github.com/sirupsen/logrus"
)
// ResolvedFilePath represents a resolved file path and intended to prevent unintentional use of not verified file path.
type ResolvedFilePath string
// resolveSymbolicLinkRecursive resolves the symlink path recursively to its
// canonical path on the file system, with a maximum nesting level of maxDepth.
// If path is not a symlink, returns the verbatim copy of path and err of nil.
func resolveSymbolicLinkRecursive(path string, maxDepth int) (string, error) {
resolved, err := os.Readlink(path)
if err != nil {
// path is not a symbolic link
_, ok := err.(*os.PathError)
if ok {
return path, nil
}
// Other error has occured
return "", err
}
if maxDepth == 0 {
return "", fmt.Errorf("maximum nesting level reached")
}
// If we resolved to a relative symlink, make sure we use the absolute
// path for further resolving
if !strings.HasPrefix(resolved, "/") {
basePath := filepath.Dir(path)
resolved = filepath.Join(basePath, resolved)
}
return resolveSymbolicLinkRecursive(resolved, maxDepth-1)
}
// isURLSchemeAllowed returns true if the protocol scheme is in the list of
// allowed URL schemes.
func isURLSchemeAllowed(scheme string, allowed []string) bool {
isAllowed := false
if len(allowed) > 0 {
for _, s := range allowed {
if strings.EqualFold(scheme, s) {
isAllowed = true
break
}
}
}
// Empty scheme means local file
return isAllowed && scheme != ""
}
// ResolveFilePath will inspect and resolve given file, and make sure that its final path is within the boundaries of
// the path specified in repoRoot.
//
// appPath is the path we're operating in, e.g. where a Helm chart was unpacked
// to. repoRoot is the path to the root of the repository.
//
// If either appPath or repoRoot is relative, it will be treated as relative
// to the current working directory.
//
// valueFile is the path to a value file, relative to appPath. If valueFile is
// specified as an absolute path (i.e. leading slash), it will be treated as
// relative to the repoRoot. In case valueFile is a symlink in the extracted
// chart, it will be resolved recursively and the decision of whether it is in
// the boundary of repoRoot will be made using the final resolved path.
// valueFile can also be a remote URL with a protocol scheme as prefix,
// in which case the scheme must be included in the list of allowed schemes
// specified by allowedURLSchemes.
//
// Will return an error if either valueFile is outside the boundaries of the
// repoRoot, valueFile is an URL with a forbidden protocol scheme or if
// valueFile is a recursive symlink nested too deep. May return errors for
// other reasons as well.
//
// resolvedPath will hold the absolute, resolved path for valueFile on success
// or set to the empty string on failure.
//
// isRemote will be set to true if valueFile is an URL using an allowed
// protocol scheme, or to false if it resolved to a local file.
func ResolveFilePath(appPath, repoRoot, valueFile string, allowedURLSchemes []string) (resolvedPath ResolvedFilePath, isRemote bool, err error) {
// We do not provide the path in the error message, because it will be
// returned to the user and could be used for information gathering.
// Instead, we log the concrete error details.
resolveFailure := func(path string, err error) error {
log.Errorf("failed to resolve path '%s': %v", path, err)
return fmt.Errorf("internal error: failed to resolve path. Check logs for more details")
}
// A value file can be specified as an URL to a remote resource.
// We only allow certain URL schemes for remote value files.
url, err := url.Parse(valueFile)
if err == nil {
// If scheme is empty, it means we parsed a path only
if url.Scheme != "" {
if isURLSchemeAllowed(url.Scheme, allowedURLSchemes) {
return ResolvedFilePath(valueFile), true, nil
} else {
return "", false, fmt.Errorf("the URL scheme '%s' is not allowed", url.Scheme)
}
}
}
// Ensure that our repository root is absolute
absRepoPath, err := filepath.Abs(repoRoot)
if err != nil {
return "", false, resolveFailure(repoRoot, err)
}
// If the path to the file is relative, join it with the current working directory (appPath)
// Otherwise, join it with the repository's root
path := valueFile
if !filepath.IsAbs(path) {
absWorkDir, err := filepath.Abs(appPath)
if err != nil {
return "", false, resolveFailure(repoRoot, err)
}
path = filepath.Join(absWorkDir, path)
} else {
path = filepath.Join(absRepoPath, path)
}
// Ensure any symbolic link is resolved before we
delinkedPath, err := resolveSymbolicLinkRecursive(path, 10)
if err != nil {
return "", false, resolveFailure(path, err)
}
path = delinkedPath
// Resolve the joined path to an absolute path
path, err = filepath.Abs(path)
if err != nil {
return "", false, resolveFailure(path, err)
}
// Ensure our root path has a trailing slash, otherwise the following check
// would return true if root is /foo and path would be /foo2
requiredRootPath := absRepoPath
if !strings.HasSuffix(requiredRootPath, "/") {
requiredRootPath += "/"
}
// Make sure that the resolved path to values file is within the repository's root path
if !strings.HasPrefix(path, requiredRootPath) {
return "", false, fmt.Errorf("value file '%s' resolved to outside repository root", valueFile)
}
return ResolvedFilePath(path), false, nil
}

View file

@ -0,0 +1,181 @@
package path
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_resolveSymlinkRecursive(t *testing.T) {
testsDir, err := filepath.Abs("./testdata")
if err != nil {
panic(err)
}
t.Run("Resolve non-symlink", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/foo", 2)
assert.NoError(t, err)
assert.Equal(t, testsDir+"/foo", r)
})
t.Run("Successfully resolve symlink", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/bar", 2)
assert.NoError(t, err)
assert.Equal(t, testsDir+"/foo", r)
})
t.Run("Do not allow symlink at all", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/bar", 0)
assert.Error(t, err)
assert.Equal(t, "", r)
})
t.Run("Error because too nested symlink", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/bam", 2)
assert.Error(t, err)
assert.Equal(t, "", r)
})
t.Run("No such file or directory", func(t *testing.T) {
r, err := resolveSymbolicLinkRecursive(testsDir+"/foobar", 2)
assert.NoError(t, err)
assert.Equal(t, testsDir+"/foobar", r)
})
}
func Test_isURLSchemeAllowed(t *testing.T) {
type testdata struct {
name string
scheme string
allowed []string
expected bool
}
var tts []testdata = []testdata{
{
name: "Allowed scheme matches",
scheme: "http",
allowed: []string{"http", "https"},
expected: true,
},
{
name: "Allowed scheme matches only partially",
scheme: "http",
allowed: []string{"https"},
expected: false,
},
{
name: "Scheme is not allowed",
scheme: "file",
allowed: []string{"http", "https"},
expected: false,
},
{
name: "Empty scheme with valid allowances is forbidden",
scheme: "",
allowed: []string{"http", "https"},
expected: false,
},
{
name: "Empty scheme with empty allowances is forbidden",
scheme: "",
allowed: []string{},
expected: false,
},
{
name: "Some scheme with empty allowances is forbidden",
scheme: "file",
allowed: []string{},
expected: false,
},
}
for _, tt := range tts {
t.Run(tt.name, func(t *testing.T) {
r := isURLSchemeAllowed(tt.scheme, tt.allowed)
assert.Equal(t, tt.expected, r)
})
}
}
var allowedRemoteProtocols = []string{"http", "https"}
func Test_resolveFilePath(t *testing.T) {
t.Run("Resolve normal relative path into absolute path", func(t *testing.T) {
p, remote, err := ResolveFilePath("/foo/bar", "/foo", "baz/bim.yaml", allowedRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, "/foo/bar/baz/bim.yaml", string(p))
})
t.Run("Resolve normal relative path into absolute path", func(t *testing.T) {
p, remote, err := ResolveFilePath("/foo/bar", "/foo", "baz/../../bim.yaml", allowedRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, "/foo/bim.yaml", string(p))
})
t.Run("Error on path resolving outside repository root", func(t *testing.T) {
p, remote, err := ResolveFilePath("/foo/bar", "/foo", "baz/../../../bim.yaml", allowedRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", string(p))
})
t.Run("Return verbatim URL", func(t *testing.T) {
url := "https://some.where/foo,yaml"
p, remote, err := ResolveFilePath("/foo/bar", "/foo", url, allowedRemoteProtocols)
assert.NoError(t, err)
assert.True(t, remote)
assert.Equal(t, url, string(p))
})
t.Run("URL scheme not allowed", func(t *testing.T) {
url := "file:///some.where/foo,yaml"
p, remote, err := ResolveFilePath("/foo/bar", "/foo", url, allowedRemoteProtocols)
assert.Error(t, err)
assert.False(t, remote)
assert.Equal(t, "", string(p))
})
t.Run("Implicit URL by absolute path", func(t *testing.T) {
p, remote, err := ResolveFilePath("/foo/bar", "/foo", "/baz.yaml", allowedRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, "/foo/baz.yaml", string(p))
})
t.Run("Relative app path", func(t *testing.T) {
p, remote, err := ResolveFilePath(".", "/foo", "/baz.yaml", allowedRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, "/foo/baz.yaml", string(p))
})
t.Run("Relative repo path", func(t *testing.T) {
c, err := os.Getwd()
require.NoError(t, err)
p, remote, err := ResolveFilePath(".", ".", "baz.yaml", allowedRemoteProtocols)
assert.NoError(t, err)
assert.False(t, remote)
assert.Equal(t, c+"/baz.yaml", string(p))
})
t.Run("Overlapping root prefix without trailing slash", func(t *testing.T) {
p, remote, err := ResolveFilePath(".", "/foo", "../foo2/baz.yaml", allowedRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", string(p))
})
t.Run("Overlapping root prefix with trailing slash", func(t *testing.T) {
p, remote, err := ResolveFilePath(".", "/foo/", "../foo2/baz.yaml", allowedRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", string(p))
})
t.Run("Garbage input as values file", func(t *testing.T) {
p, remote, err := ResolveFilePath(".", "/foo/", "kfdj\\ks&&&321209.,---e32908923%$§!\"", allowedRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", string(p))
})
t.Run("NUL-byte path input as values file", func(t *testing.T) {
p, remote, err := ResolveFilePath(".", "/foo/", "\000", allowedRemoteProtocols)
assert.Error(t, err)
assert.Contains(t, err.Error(), "outside repository root")
assert.False(t, remote)
assert.Equal(t, "", string(p))
})
}

View file

@ -110,11 +110,16 @@ func (svc *argoCDService) GetAppDetails(ctx context.Context, appSource *v1alpha1
if err != nil {
return nil, err
}
helmOptions, err := svc.settingsMgr.GetHelmSettings()
if err != nil {
return nil, err
}
appDetail, err := svc.repoServerClient.GetAppDetails(ctx, &apiclient.RepoServerAppDetailsQuery{
Repo: repo,
Source: appSource,
Repos: helmRepos,
KustomizeOptions: kustomizeOptions,
HelmOptions: helmOptions,
})
if err != nil {
return nil, err