@@ -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
125125func 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(
878889func (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 }
0 commit comments