Skip to content

Commit b7759e1

Browse files
committed
PR review comments addressed
1 parent 4a2b917 commit b7759e1

File tree

6 files changed

+75
-50
lines changed

6 files changed

+75
-50
lines changed

internal/config/config.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ const (
5050
regexLabelPattern = "^[a-zA-Z0-9]([a-zA-Z0-9-_]{0,254}[a-zA-Z0-9])?$"
5151
)
5252

53+
var domainRegex = regexp.MustCompile(
54+
`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`,
55+
)
56+
5357
var viperInstance = viper.NewWithOptions(viper.KeyDelimiter(KeyDelimiter))
5458

5559
func RegisterRunner(r func(cmd *cobra.Command, args []string)) {
@@ -495,7 +499,7 @@ func registerExternalDataSourceFlags(fs *flag.FlagSet) {
495499
fs.String(
496500
ExternalDataSourceProxyUrlKey,
497501
DefExternalDataSourceProxyUrl,
498-
"Url to the proxy service to fetch the external file.",
502+
"Url to the proxy service for fetching external files.",
499503
)
500504
fs.StringSlice(
501505
ExternalDataSourceAllowDomainsKey,
@@ -651,7 +655,7 @@ func registerClientFlags(fs *flag.FlagSet) {
651655
fs.Duration(
652656
ClientFileDownloadTimeoutKey,
653657
DefClientFileDownloadTimeout,
654-
"Timeout value in seconds, to downloading file for config apply.",
658+
"Timeout value in seconds, for downloading a file during a config apply.",
655659
)
656660

657661
fs.Int(
@@ -1610,8 +1614,9 @@ func validateAllowedDomains(domains []string) error {
16101614
}
16111615

16121616
for _, domain := range domains {
1613-
if strings.ContainsAny(domain, "/\\ ") || domain == "" {
1614-
slog.Error("domain is not specified in allowed_domains")
1617+
// Validating syntax using the RFC-compliant regex
1618+
if !domainRegex.MatchString(domain) || domain == "" {
1619+
slog.Error("domain specified in allowed_domains is invalid", "domain", domain)
16151620
return errors.New("invalid domain found in allowed_domains")
16161621
}
16171622
}

internal/config/config_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,10 +1427,10 @@ func createConfig() *Config {
14271427
},
14281428
ExternalDataSource: &ExternalDataSource{
14291429
ProxyURL: ProxyURL{
1430-
URL: "",
1430+
URL: "http://proxy.example.com",
14311431
},
1432-
AllowedDomains: nil,
1433-
MaxBytes: 0,
1432+
AllowedDomains: []string{"example.com", "api.example.com"},
1433+
MaxBytes: 1048576,
14341434
},
14351435
}
14361436
}
@@ -1638,7 +1638,7 @@ func TestValidateAllowedDomains(t *testing.T) {
16381638

16391639
if tt.wantErr {
16401640
require.Error(t, actualErr, "Expected an error but got nil.")
1641-
assert.Contains(t, logBuffer.String(), "domain is not specified in allowed_domains",
1641+
assert.Contains(t, logBuffer.String(), "domain specified in allowed_domains is invalid",
16421642
"Expected the error log message to be present in the output.")
16431643
} else {
16441644
assert.NoError(t, actualErr, "Did not expect an error but got one: %v", actualErr)

internal/config/defaults.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ const (
118118
DefLibDir = "/var/lib/nginx-agent"
119119

120120
DefExternalDataSourceProxyUrl = ""
121+
// Default allow external data sources up to 100 MB
121122
DefExternalDataSourceMaxBytes = 100 * 1024 * 1024
122123
)
123124

internal/config/testdata/nginx-agent.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,11 @@ collector:
183183
log:
184184
level: "INFO"
185185
path: "/var/log/nginx-agent/opentelemetry-collector-agent.log"
186+
187+
external_data_source:
188+
proxy:
189+
url: "http://proxy.example.com"
190+
allowed_domains:
191+
- example.com
192+
- api.example.com
193+
max_bytes: 1048576

internal/file/file_manager_service.go

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const (
4444
executePerm = 0o111
4545
)
4646

47-
type DownloadHeaders struct {
47+
type DownloadHeader struct {
4848
ETag string
4949
LastModified string
5050
}
@@ -114,28 +114,28 @@ type FileManagerService struct {
114114
// map of files and the actions performed on them during config apply
115115
fileActions map[string]*model.FileCache // key is file path
116116
// map of the files currently on disk, used to determine the file action during config apply
117-
currentFilesOnDisk map[string]*mpi.File // key is file path
118-
previousManifestFiles map[string]*model.ManifestFile
119-
newExternalFileHeaders map[string]DownloadHeaders
120-
manifestFilePath string
121-
rollbackManifest bool
122-
filesMutex sync.RWMutex
117+
currentFilesOnDisk map[string]*mpi.File // key is file path
118+
previousManifestFiles map[string]*model.ManifestFile
119+
externalFileHeaders map[string]DownloadHeader
120+
manifestFilePath string
121+
rollbackManifest bool
122+
filesMutex sync.RWMutex
123123
}
124124

125125
func NewFileManagerService(fileServiceClient mpi.FileServiceClient, agentConfig *config.Config,
126126
manifestLock *sync.RWMutex,
127127
) *FileManagerService {
128128
return &FileManagerService{
129-
agentConfig: agentConfig,
130-
fileOperator: NewFileOperator(manifestLock),
131-
fileServiceOperator: NewFileServiceOperator(agentConfig, fileServiceClient, manifestLock),
132-
fileActions: make(map[string]*model.FileCache),
133-
currentFilesOnDisk: make(map[string]*mpi.File),
134-
previousManifestFiles: make(map[string]*model.ManifestFile),
135-
newExternalFileHeaders: make(map[string]DownloadHeaders),
136-
rollbackManifest: true,
137-
manifestFilePath: agentConfig.LibDir + "/manifest.json",
138-
manifestLock: manifestLock,
129+
agentConfig: agentConfig,
130+
fileOperator: NewFileOperator(manifestLock),
131+
fileServiceOperator: NewFileServiceOperator(agentConfig, fileServiceClient, manifestLock),
132+
fileActions: make(map[string]*model.FileCache),
133+
currentFilesOnDisk: make(map[string]*mpi.File),
134+
previousManifestFiles: make(map[string]*model.ManifestFile),
135+
externalFileHeaders: make(map[string]DownloadHeader),
136+
rollbackManifest: true,
137+
manifestFilePath: agentConfig.LibDir + "/manifest.json",
138+
manifestLock: manifestLock,
139139
}
140140
}
141141

@@ -402,22 +402,30 @@ func (fms *FileManagerService) DetermineFileActions(
402402
slog.DebugContext(ctx, "Skipping unmanaged file updates", "file_name", fileName)
403403
continue
404404
}
405+
406+
// If either the modified file or the current file is an external data source,
407+
// treat this as an ExternalFile and skip the regular Add/Update checks. This
408+
// ensures external files are downloaded/validated every single time.
409+
if modifiedFile.File.GetExternalDataSource() != nil || (ok && currentFile.GetExternalDataSource() != nil) {
410+
modifiedFile.Action = model.ExternalFile
411+
fileDiff[fileName] = modifiedFile
412+
413+
continue
414+
}
415+
405416
// if file doesn't exist in the current files, file has been added
406417
// set file action
407418
if _, statErr := os.Stat(fileName); errors.Is(statErr, os.ErrNotExist) {
408419
modifiedFile.Action = model.Add
409420
fileDiff[fileName] = modifiedFile
410421

422+
continue
411423
// if file currently exists and file hash is different, file has been updated
412424
// copy contents, set file action
413425
} else if ok && modifiedFile.File.GetFileMeta().GetHash() != currentFile.GetFileMeta().GetHash() {
414426
modifiedFile.Action = model.Update
415427
fileDiff[fileName] = modifiedFile
416428
}
417-
if modifiedFile.File.GetExternalDataSource() != nil || currentFile.GetExternalDataSource() != nil {
418-
modifiedFile.Action = model.ExternalFile
419-
fileDiff[fileName] = modifiedFile
420-
}
421429
}
422430

423431
return fileDiff, nil
@@ -615,7 +623,7 @@ func (fms *FileManagerService) downloadUpdatedFilesToTempLocation(ctx context.Co
615623

616624
switch fileAction.Action {
617625
case model.ExternalFile:
618-
return fms.handleExternalFileDownload(errGroupCtx, fileAction, tempFilePath)
626+
return fms.downloadExternalFile(errGroupCtx, fileAction, tempFilePath)
619627
case model.Add, model.Update:
620628
slog.DebugContext(
621629
errGroupCtx,
@@ -819,15 +827,17 @@ func tempBackupFilePath(fileName string) string {
819827
return filepath.Join(filepath.Dir(fileName), tempFileName)
820828
}
821829

822-
func (fms *FileManagerService) handleExternalFileDownload(ctx context.Context, fileAction *model.FileCache,
823-
tempFilePath string,
830+
func (fms *FileManagerService) downloadExternalFile(ctx context.Context, fileAction *model.FileCache,
831+
filePath string,
824832
) error {
825833
location := fileAction.File.GetExternalDataSource().GetLocation()
834+
permission := fileAction.File.GetFileMeta().GetPermissions()
835+
826836
slog.InfoContext(ctx, "Downloading external file from", "location", location)
827837

828838
var contentToWrite []byte
829839
var downloadErr, updateError error
830-
var headers DownloadHeaders
840+
var headers DownloadHeader
831841

832842
contentToWrite, headers, downloadErr = fms.downloadFileContent(ctx, fileAction.File)
833843

@@ -848,9 +858,9 @@ func (fms *FileManagerService) handleExternalFileDownload(ctx context.Context, f
848858
}
849859

850860
fileName := fileAction.File.GetFileMeta().GetName()
851-
fms.newExternalFileHeaders[fileName] = headers
861+
fms.externalFileHeaders[fileName] = headers
852862

853-
updateErr := fms.writeContentToTempFile(ctx, contentToWrite, tempFilePath)
863+
updateErr := fms.writeContentToTempFile(ctx, contentToWrite, filePath, permission)
854864

855865
return updateErr
856866
}
@@ -859,12 +869,13 @@ func (fms *FileManagerService) writeContentToTempFile(
859869
ctx context.Context,
860870
content []byte,
861871
path string,
872+
permission string,
862873
) error {
863874
writeErr := fms.fileOperator.Write(
864875
ctx,
865876
content,
866877
path,
867-
"0600",
878+
permission,
868879
)
869880

870881
if writeErr != nil {
@@ -878,23 +889,23 @@ func (fms *FileManagerService) writeContentToTempFile(
878889
func (fms *FileManagerService) downloadFileContent(
879890
ctx context.Context,
880891
file *mpi.File,
881-
) (content []byte, headers DownloadHeaders, err error) {
892+
) (content []byte, headers DownloadHeader, err error) {
882893
fileName := file.GetFileMeta().GetName()
883894
downloadURL := file.GetExternalDataSource().GetLocation()
884895
externalConfig := fms.agentConfig.ExternalDataSource
885896

886897
if !isDomainAllowed(downloadURL, externalConfig.AllowedDomains) {
887-
return nil, DownloadHeaders{}, fmt.Errorf("download URL %s is not in the allowed domains list", downloadURL)
898+
return nil, DownloadHeader{}, fmt.Errorf("download URL %s is not in the allowed domains list", downloadURL)
888899
}
889900

890901
httpClient, err := fms.setupHTTPClient(ctx, externalConfig.ProxyURL.URL)
891902
if err != nil {
892-
return nil, DownloadHeaders{}, err
903+
return nil, DownloadHeader{}, err
893904
}
894905

895906
req, err := http.NewRequestWithContext(ctx, http.MethodGet, downloadURL, nil)
896907
if err != nil {
897-
return nil, DownloadHeaders{}, fmt.Errorf("failed to create request for %s: %w", downloadURL, err)
908+
return nil, DownloadHeader{}, fmt.Errorf("failed to create request for %s: %w", downloadURL, err)
898909
}
899910

900911
if externalConfig.ProxyURL.URL != "" {
@@ -905,7 +916,7 @@ func (fms *FileManagerService) downloadFileContent(
905916

906917
resp, err := httpClient.Do(req)
907918
if err != nil {
908-
return nil, DownloadHeaders{}, fmt.Errorf("failed to execute download request for %s: %w", downloadURL, err)
919+
return nil, DownloadHeader{}, fmt.Errorf("failed to execute download request for %s: %w", downloadURL, err)
909920
}
910921
defer resp.Body.Close()
911922

@@ -914,10 +925,10 @@ func (fms *FileManagerService) downloadFileContent(
914925
headers.ETag = resp.Header.Get("ETag")
915926
headers.LastModified = resp.Header.Get("Last-Modified")
916927
case http.StatusNotModified:
917-
slog.InfoContext(ctx, "File content unchanged (304 Not Modified)", "file_name", fileName)
918-
return nil, DownloadHeaders{}, nil
928+
slog.DebugContext(ctx, "File content unchanged (304 Not Modified)", "file_name", fileName)
929+
return nil, DownloadHeader{}, nil
919930
default:
920-
return nil, DownloadHeaders{}, fmt.Errorf("download failed with status code %d", resp.StatusCode)
931+
return nil, DownloadHeader{}, fmt.Errorf("download failed with status code %d", resp.StatusCode)
921932
}
922933

923934
reader := io.Reader(resp.Body)
@@ -927,7 +938,7 @@ func (fms *FileManagerService) downloadFileContent(
927938

928939
content, err = io.ReadAll(reader)
929940
if err != nil {
930-
return nil, DownloadHeaders{}, fmt.Errorf("failed to read content from response body: %w", err)
941+
return nil, DownloadHeader{}, fmt.Errorf("failed to read content from response body: %w", err)
931942
}
932943

933944
slog.InfoContext(ctx, "Successfully downloaded file content", "file_name", fileName, "size", len(content))
@@ -947,16 +958,16 @@ func isDomainAllowed(downloadURL string, allowedDomains []string) bool {
947958
return false
948959
}
949960

950-
for _, pattern := range allowedDomains {
951-
if pattern == "" {
961+
for _, domain := range allowedDomains {
962+
if domain == "" {
952963
continue
953964
}
954965

955-
if pattern == hostname {
966+
if domain == hostname {
956967
return true
957968
}
958969

959-
if isWildcardMatch(hostname, pattern) {
970+
if isWildcardMatch(hostname, domain) {
960971
return true
961972
}
962973
}

internal/file/file_manager_service_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1420,7 +1420,7 @@ func TestFileManagerService_downloadExternalFiles_Cases(t *testing.T) {
14201420
require.NoError(t, readErr)
14211421
assert.Equal(t, test.expectContent, b)
14221422

1423-
h, ok := fileManagerService.newExternalFileHeaders[fileName]
1423+
h, ok := fileManagerService.externalFileHeaders[fileName]
14241424
require.True(t, ok)
14251425
assert.Equal(t, test.expectHeaderETag, h.ETag)
14261426
assert.Equal(t, test.expectHeaderLastMod, h.LastModified)

0 commit comments

Comments
 (0)