diff --git a/reposerver/apiclient/repository.go b/reposerver/apiclient/repository.go new file mode 100644 index 0000000000..20516c2988 --- /dev/null +++ b/reposerver/apiclient/repository.go @@ -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 +} diff --git a/reposerver/apiclient/repository.pb.go b/reposerver/apiclient/repository.pb.go index 1df220224d..332950efd0 100644 --- a/reposerver/apiclient/repository.pb.go +++ b/reposerver/apiclient/repository.pb.go @@ -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:]) diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 39c7178299..f28f0d4bfd 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -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 } diff --git a/reposerver/repository/repository.proto b/reposerver/repository/repository.proto index d5b32ee62a..5c979759c6 100644 --- a/reposerver/repository/repository.proto +++ b/reposerver/repository/repository.proto @@ -102,6 +102,7 @@ message RepoServerAppDetailsQuery { bool noRevisionCache = 7; string trackingMethod = 8; map enabledSourceTypes = 9; + github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmOptions helmOptions = 10; } // RepoAppDetailsResponse application details diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go index 62d66d51d3..0764a21765 100644 --- a/reposerver/repository/repository_test.go +++ b/reposerver/repository/repository_test.go @@ -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) diff --git a/server/application/application.go b/server/application/application.go index fdc220132b..25343e8e75 100644 --- a/server/application/application.go +++ b/server/application/application.go @@ -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 { diff --git a/server/repository/repository.go b/server/repository/repository.go index 8340f81c3a..15a6af7484 100644 --- a/server/repository/repository.go +++ b/server/repository/repository.go @@ -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, }) } diff --git a/util/argo/argo.go b/util/argo/argo.go index ce15ab41b6..a84dc04a82 100644 --- a/util/argo/argo.go +++ b/util/argo/argo.go @@ -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{ diff --git a/util/argo/argo_test.go b/util/argo/argo_test.go index 795d38956e..7ce6dcfca7 100644 --- a/util/argo/argo_test.go +++ b/util/argo/argo_test.go @@ -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) diff --git a/util/helm/cmd.go b/util/helm/cmd.go index 471db33bdb..51c2c51c41 100644 --- a/util/helm/cmd.go +++ b/util/helm/cmd.go @@ -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) diff --git a/util/helm/helm.go b/util/helm/helm.go index 1b35f33831..0c3a3a184e 100644 --- a/util/helm/helm.go +++ b/util/helm/helm.go @@ -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") { diff --git a/util/helm/helm_test.go b/util/helm/helm_test.go index 00a7d6389f..acccffe6f4 100644 --- a/util/helm/helm_test.go +++ b/util/helm/helm_test.go @@ -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"] diff --git a/util/io/path/resolved.go b/util/io/path/resolved.go new file mode 100644 index 0000000000..0343a379f0 --- /dev/null +++ b/util/io/path/resolved.go @@ -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 +} diff --git a/util/io/path/resolved_test.go b/util/io/path/resolved_test.go new file mode 100644 index 0000000000..fc95833778 --- /dev/null +++ b/util/io/path/resolved_test.go @@ -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)) + }) +} diff --git a/reposerver/repository/testdata/symlinks/bam b/util/io/path/testdata/bam similarity index 100% rename from reposerver/repository/testdata/symlinks/bam rename to util/io/path/testdata/bam diff --git a/reposerver/repository/testdata/symlinks/bar b/util/io/path/testdata/bar similarity index 100% rename from reposerver/repository/testdata/symlinks/bar rename to util/io/path/testdata/bar diff --git a/reposerver/repository/testdata/symlinks/baz b/util/io/path/testdata/baz similarity index 100% rename from reposerver/repository/testdata/symlinks/baz rename to util/io/path/testdata/baz diff --git a/reposerver/repository/testdata/symlinks/foo b/util/io/path/testdata/foo similarity index 100% rename from reposerver/repository/testdata/symlinks/foo rename to util/io/path/testdata/foo diff --git a/util/notification/argocd/service.go b/util/notification/argocd/service.go index 3a224bcf23..5dafd4bf74 100644 --- a/util/notification/argocd/service.go +++ b/util/notification/argocd/service.go @@ -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