77package config
88
99import (
10+ "context"
1011 "encoding/json"
1112 "fmt"
1213 "io"
@@ -56,15 +57,15 @@ type Operations struct {
5657}
5758
5859// Apply applies the operations to the root.
59- func (o * Operations ) Apply (rootPath string ) error {
60+ func (o * Operations ) Apply (ctx context. Context , rootPath string ) error {
6061 root , err := os .OpenRoot (rootPath )
6162 if err != nil {
6263 return err
6364 }
6465 defer root .Close ()
6566 for _ , operation := range o .FileOperations {
6667 // TODO (go.1.25): we won't need rootPath in 1.25
67- err := operation .apply (root , rootPath )
68+ err := operation .apply (ctx , root , rootPath )
6869 if err != nil {
6970 return err
7071 }
@@ -80,8 +81,9 @@ type FileOperation struct {
8081 Patch json.RawMessage `json:"patch,omitempty"`
8182}
8283
83- func (a * FileOperation ) apply (root * os.Root , rootPath string ) error {
84- if ! configNameAllowed (a .FilePath ) {
84+ func (a * FileOperation ) apply (ctx context.Context , root * os.Root , rootPath string ) error {
85+ spec := getConfigFileSpec (a .FilePath )
86+ if spec == nil {
8587 return fmt .Errorf ("modifying config file %s is not allowed" , a .FilePath )
8688 }
8789 path := strings .TrimPrefix (a .FilePath , "/" )
@@ -149,9 +151,19 @@ func (a *FileOperation) apply(root *os.Root, rootPath string) error {
149151 if err != nil {
150152 return err
151153 }
152- return err
154+ // Set proper ownership and permissions for the file
155+ fullPath := filepath .Join (rootPath , path )
156+ if err := setFileOwnershipAndPermissions (ctx , fullPath , spec ); err != nil {
157+ return err
158+ }
159+ return nil
153160 case FileOperationCopy :
154161 // TODO(go.1.25): os.Root.MkdirAll and os.Root.WriteFile are only available starting go 1.25
162+ destSpec := getConfigFileSpec (a .DestinationPath )
163+ if destSpec == nil {
164+ return fmt .Errorf ("modifying config file %s is not allowed" , a .DestinationPath )
165+ }
166+
155167 err := ensureDir (root , destinationPath )
156168 if err != nil {
157169 return err
@@ -179,9 +191,20 @@ func (a *FileOperation) apply(root *os.Root, rootPath string) error {
179191 if err != nil {
180192 return err
181193 }
194+
195+ // Set proper ownership and permissions for the destination file
196+ fullDestPath := filepath .Join (rootPath , destinationPath )
197+ if err := setFileOwnershipAndPermissions (ctx , fullDestPath , destSpec ); err != nil {
198+ return err
199+ }
182200 return nil
183201 case FileOperationMove :
184202 // TODO(go.1.25): os.Root.Rename is only available starting go 1.25 so we'll use it instead
203+ destSpec := getConfigFileSpec (a .DestinationPath )
204+ if destSpec == nil {
205+ return fmt .Errorf ("modifying config file %s is not allowed" , a .DestinationPath )
206+ }
207+
185208 err := ensureDir (root , destinationPath )
186209 if err != nil {
187210 return err
@@ -214,6 +237,12 @@ func (a *FileOperation) apply(root *os.Root, rootPath string) error {
214237 if err != nil {
215238 return err
216239 }
240+
241+ // Set proper ownership and permissions for the destination file
242+ fullDestPath := filepath .Join (rootPath , destinationPath )
243+ if err := setFileOwnershipAndPermissions (ctx , fullDestPath , destSpec ); err != nil {
244+ return err
245+ }
217246 return nil
218247 case FileOperationDelete :
219248 err := root .Remove (path )
@@ -275,39 +304,70 @@ func ensureDir(root *os.Root, filePath string) error {
275304 return nil
276305}
277306
307+ // configFileSpec specifies a config file pattern, its ownership, and permissions.
308+ type configFileSpec struct {
309+ pattern string
310+ owner string
311+ group string
312+ mode os.FileMode
313+ }
314+
278315var (
279- allowedConfigFiles = []string {
280- "/datadog.yaml" ,
281- "/otel-config.yaml" ,
282- "/security-agent.yaml" ,
283- "/system-probe.yaml" ,
284- "/application_monitoring.yaml" ,
285- "/conf.d/*.yaml" ,
286- "/conf.d/*.d/*.yaml" ,
316+ allowedConfigFiles = []configFileSpec {
317+ { pattern : "/datadog.yaml" , owner : "dd-agent" , group : "dd-agent" , mode : 0640 } ,
318+ { pattern : "/otel-config.yaml" , owner : "dd-agent" , group : "dd-agent" , mode : 0640 } ,
319+ { pattern : "/security-agent.yaml" , owner : "root" , group : "root" , mode : 0640 } ,
320+ { pattern : "/system-probe.yaml" , owner : "root" , group : "root" , mode : 0640 } ,
321+ { pattern : "/application_monitoring.yaml" , owner : "root" , group : "root" , mode : 0644 } ,
322+ { pattern : "/conf.d/*.yaml" , owner : "dd-agent" , group : "dd-agent" , mode : 0640 } ,
323+ { pattern : "/conf.d/*.d/*.yaml" , owner : "dd-agent" , group : "dd-agent" , mode : 0640 } ,
287324 }
288325
289326 legacyPathPrefix = filepath .Join ("managed" , "datadog-agent" , "stable" )
290327)
291328
292- func configNameAllowed (file string ) bool {
293- // Normalize path to use forward slashes for consistent matching on all platforms
329+ func getConfigFileSpec (file string ) * configFileSpec {
294330 normalizedFile := filepath .ToSlash (file )
295331
296- // Matching everything under the legacy /managed directory
332+ // Fallback for legacy files under the /managed directory
297333 if strings .HasPrefix (normalizedFile , "/managed" ) {
298- return true
334+ filename := filepath .Base (normalizedFile )
335+
336+ for _ , spec := range allowedConfigFiles {
337+ // Skip patterns with nested paths (e.g., /conf.d/*.yaml)
338+ if strings .Count (spec .pattern , "/" ) > 1 {
339+ continue
340+ }
341+
342+ // Extract just the filename from the pattern
343+ patternFilename := filepath .Base (spec .pattern )
344+ match , err := filepath .Match (patternFilename , filename )
345+ if err != nil {
346+ continue
347+ }
348+ if match {
349+ // Return a copy with the original pattern set to the full managed path
350+ return & configFileSpec {
351+ pattern : normalizedFile ,
352+ owner : spec .owner ,
353+ group : spec .group ,
354+ mode : spec .mode ,
355+ }
356+ }
357+ }
358+ return & configFileSpec {pattern : normalizedFile , owner : "dd-agent" , group : "dd-agent" , mode : 0640 }
299359 }
300360
301- for _ , allowedFile := range allowedConfigFiles {
302- match , err := filepath .Match (allowedFile , normalizedFile )
361+ for _ , spec := range allowedConfigFiles {
362+ match , err := filepath .Match (spec . pattern , normalizedFile )
303363 if err != nil {
304- return false
364+ continue
305365 }
306366 if match {
307- return true
367+ return & spec
308368 }
309369 }
310- return false
370+ return nil
311371}
312372
313373func buildOperationsFromLegacyInstaller (rootPath string ) []FileOperation {
0 commit comments