From ec2b6ab2734cf1defda4c5eefc206bc6bbceec92 Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Wed, 10 Dec 2025 16:15:37 +0100 Subject: [PATCH] privileged logs: Handle unsearchable directories (#43747) In any directory in the path of a configured log file does not have executable (search) permissions, it does not get tailed even with privileged logs enabled since a stat(2) call from the file launcher fails and the logs agent never gets to the point where it calls into system-probe. Fix this by having that stat(2) call too fallback to system-probe if privileged logs is enabled. https://datadoghq.atlassian.net/browse/DSCVR-288 Unit and E2E tests have been modified to test this case. Co-authored-by: vincent.whitchurch (cherry picked from commit d81746c60fffaf5ef00426aa12f11531e761ff68) (Manually fixed conflict in pkg/logs/launchers/file/launcher_test.go due to "Replace uses of `fmt.Sprintf` and `fmt.Errorf` with better alternatives (#43413) not being present on 7.74.x) --- pkg/logs/internal/util/opener/open_linux.go | 5 ++ pkg/logs/internal/util/opener/open_other.go | 5 ++ .../file/launcher_privileged_logs_test.go | 52 ++++++++++++-- pkg/logs/launchers/file/launcher_test.go | 50 ++++++++----- .../launchers/file/provider/file_provider.go | 3 +- pkg/privileged-logs/client/open.go | 52 +++++++++++--- pkg/privileged-logs/client/open_other.go | 5 ++ pkg/privileged-logs/test/handler.go | 22 ++++++ .../test/privileged_logs_test.go | 71 ++++++++++++++++--- .../testdata/provision/python/server.py | 18 +++-- 10 files changed, 237 insertions(+), 46 deletions(-) diff --git a/pkg/logs/internal/util/opener/open_linux.go b/pkg/logs/internal/util/opener/open_linux.go index 31743c2c70504a..c2a8a33a27e84a 100644 --- a/pkg/logs/internal/util/opener/open_linux.go +++ b/pkg/logs/internal/util/opener/open_linux.go @@ -16,3 +16,8 @@ import ( func OpenLogFile(path string) (*os.File, error) { return privilegedlogsclient.Open(path) } + +// StatLogFile stats a log file with the privileged logs client +func StatLogFile(path string) (os.FileInfo, error) { + return privilegedlogsclient.Stat(path) +} diff --git a/pkg/logs/internal/util/opener/open_other.go b/pkg/logs/internal/util/opener/open_other.go index 14e182c2b3ca32..f02132778cc258 100644 --- a/pkg/logs/internal/util/opener/open_other.go +++ b/pkg/logs/internal/util/opener/open_other.go @@ -18,3 +18,8 @@ import ( func OpenLogFile(path string) (*os.File, error) { return filesystem.OpenShared(path) } + +// StatLogFile stats a log file +func StatLogFile(path string) (os.FileInfo, error) { + return os.Stat(path) +} diff --git a/pkg/logs/launchers/file/launcher_privileged_logs_test.go b/pkg/logs/launchers/file/launcher_privileged_logs_test.go index 5f100a17985e9e..5d8ed0b7b50b0f 100644 --- a/pkg/logs/launchers/file/launcher_privileged_logs_test.go +++ b/pkg/logs/launchers/file/launcher_privileged_logs_test.go @@ -9,6 +9,8 @@ package file import ( + "os" + "path/filepath" "testing" "github.com/stretchr/testify/require" @@ -19,15 +21,33 @@ import ( ) type PrivilegedLogsTestSetupStrategy struct { - tempDirs [2]string + searchableTempDirs [2]string + unsearchableTempDirs [2]string } func (s *PrivilegedLogsTestSetupStrategy) Setup(t *testing.T) TestSetupResult { handler := privilegedlogstest.Setup(t, func() { - s.tempDirs = [2]string{} + s.searchableTempDirs = [2]string{} + s.unsearchableTempDirs = [2]string{} for i := 0; i < 2; i++ { testDir := t.TempDir() - s.tempDirs[i] = testDir + + s.searchableTempDirs[i] = testDir + + // Use a subdirectory without execute permissions so that the + // unprivileged user can't even stat(2) the file. + subdir := filepath.Join(testDir, "subdir") + err := os.Mkdir(subdir, 0) + require.NoError(t, err) + + s.unsearchableTempDirs[i] = subdir + + // Restore permissions after the test so that the cleanup of the + // temporary directories doesn't fail. + t.Cleanup(func() { + err := os.Chmod(subdir, 0755) + require.NoError(t, err) + }) } }) @@ -41,7 +61,24 @@ func (s *PrivilegedLogsTestSetupStrategy) Setup(t *testing.T) TestSetupResult { systemProbeConfig.SetWithoutSource("privileged_logs.enabled", true) systemProbeConfig.SetWithoutSource("system_probe_config.sysprobe_socket", handler.SocketPath) - return TestSetupResult{TestDirs: s.tempDirs[:]} + return TestSetupResult{TestDirs: s.unsearchableTempDirs[:], TestOps: TestOps{ + create: func(name string) (*os.File, error) { + var file *os.File + err := privilegedlogstest.WithParentPermFixup(t, name, func() error { + var err error + file, err = os.Create(name) + return err + }) + return file, err + }, rename: func(oldPath, newPath string) error { + return privilegedlogstest.WithParentPermFixup(t, newPath, func() error { + return os.Rename(oldPath, newPath) + }) + }, remove: func(name string) error { + return privilegedlogstest.WithParentPermFixup(t, name, func() error { + return os.Remove(name) + }) + }}} } type PrivilegedLogsLauncherTestSuite struct { @@ -125,10 +162,13 @@ type privilegedLogsTestSetup struct { // setupPrivilegedLogsTest sets up the privileged logs test environment func setupPrivilegedLogsTest(t *testing.T) *privilegedLogsTestSetup { strategy := &PrivilegedLogsTestSetupStrategy{} - result := strategy.Setup(t) + strategy.Setup(t) return &privilegedLogsTestSetup{ - tempDirs: [2]string{result.TestDirs[0], result.TestDirs[1]}, + // Use the searchable temp dirs since several of the non-suite tests use + // wildcard patterns which do not work with non-searchable directories + // since the logs agent is unable to scan the directory for files. + tempDirs: [2]string{strategy.searchableTempDirs[0], strategy.searchableTempDirs[1]}, } } diff --git a/pkg/logs/launchers/file/launcher_test.go b/pkg/logs/launchers/file/launcher_test.go index 5cdeb74bb6bf0e..ed70bff75e09f8 100644 --- a/pkg/logs/launchers/file/launcher_test.go +++ b/pkg/logs/launchers/file/launcher_test.go @@ -41,7 +41,12 @@ import ( type RegularTestSetupStrategy struct{} func (s *RegularTestSetupStrategy) Setup(t *testing.T) TestSetupResult { - return TestSetupResult{TestDirs: []string{t.TempDir(), t.TempDir()}} + return TestSetupResult{TestDirs: []string{t.TempDir(), t.TempDir()}, + TestOps: TestOps{ + create: os.Create, + rename: os.Rename, + remove: os.Remove, + }} } type LauncherTestSuite struct { @@ -110,8 +115,15 @@ type TestSetupStrategy interface { Setup(t *testing.T) TestSetupResult } +type TestOps struct { + create func(name string) (*os.File, error) + rename func(oldPath, newPath string) error + remove func(name string) error +} + type TestSetupResult struct { TestDirs []string + TestOps TestOps } type BaseLauncherTestSuite struct { @@ -132,6 +144,8 @@ type BaseLauncherTestSuite struct { setupStrategy TestSetupStrategy setupResult TestSetupResult + + ops TestOps } const DefaultFileLimit = 100 @@ -190,13 +204,15 @@ func (suite *BaseLauncherTestSuite) SetupTest() { var err error suite.testDir = suite.setupResult.TestDirs[0] + suite.ops = suite.setupResult.TestOps + suite.testPath = fmt.Sprintf("%s/launcher.log", suite.testDir) suite.testRotatedPath = fmt.Sprintf("%s.1", suite.testPath) - f, err := os.Create(suite.testPath) + f, err := suite.ops.create(suite.testPath) suite.Nil(err) suite.testFile = f - f, err = os.Create(suite.testRotatedPath) + f, err = suite.ops.create(suite.testRotatedPath) suite.Nil(err) suite.testRotatedFile = f @@ -263,8 +279,9 @@ func (suite *BaseLauncherTestSuite) TestLauncherScanWithLogRotation() { suite.Equal("hello world", string(msg.GetContent())) tailer, _ = s.tailers.Get(getScanKey(suite.testPath, suite.source)) - os.Rename(suite.testPath, suite.testRotatedPath) - f, err := os.Create(suite.testPath) + err = suite.ops.rename(suite.testPath, suite.testRotatedPath) + suite.Nil(err) + f, err := suite.ops.create(suite.testPath) suite.Nil(err) s.resolveActiveTailers(suite.s.fileProvider.FilesToTail(context.Background(), suite.s.validatePodContainerID, suite.s.activeSources, suite.s.registry)) newTailer, _ = s.tailers.Get(getScanKey(suite.testPath, suite.source)) @@ -333,8 +350,9 @@ func (suite *BaseLauncherTestSuite) TestLauncherScanWithLogRotationAndChecksum_R s.registry.(*auditorMock.Registry).SetFingerprint(fingerprint) // Rotate file - os.Rename(suite.testPath, suite.testRotatedPath) - f, err := os.Create(suite.testPath) + err = suite.ops.rename(suite.testPath, suite.testRotatedPath) + suite.Nil(err) + f, err := suite.ops.create(suite.testPath) suite.Nil(err) // Write different content @@ -457,13 +475,13 @@ func (suite *BaseLauncherTestSuite) TestLauncherScanWithFileRemovedAndCreated() var err error // remove file - err = os.Remove(suite.testPath) + err = suite.ops.remove(suite.testPath) suite.Nil(err) s.resolveActiveTailers(suite.s.fileProvider.FilesToTail(context.Background(), suite.s.validatePodContainerID, suite.s.activeSources, suite.s.registry)) suite.Equal(tailerLen-1, s.tailers.Count()) // create file - _, err = os.Create(suite.testPath) + _, err = suite.ops.create(suite.testPath) suite.Nil(err) s.resolveActiveTailers(suite.s.fileProvider.FilesToTail(context.Background(), suite.s.validatePodContainerID, suite.s.activeSources, suite.s.registry)) suite.Equal(tailerLen, s.tailers.Count()) @@ -1260,11 +1278,11 @@ func (suite *BaseLauncherTestSuite) TestLauncherDoesNotCreateTailerForRotatedUnd // Simulate file rotation: move current file to .1 and create a new empty file rotatedPath := suite.testPath + ".1" - err = os.Rename(suite.testPath, rotatedPath) + err = suite.ops.rename(suite.testPath, rotatedPath) suite.Nil(err) // Create a new file that is undersized (empty, which results in fingerprint = 0) - newFile, err := os.Create(suite.testPath) + newFile, err := suite.ops.create(suite.testPath) suite.Nil(err) newFile.Close() @@ -1328,10 +1346,10 @@ func (suite *BaseLauncherTestSuite) TestRotatedTailersNotStoppedDuringScan() { // Rotate the file rotatedPath := suite.testPath + ".1" - err = os.Rename(suite.testPath, rotatedPath) + err = suite.ops.rename(suite.testPath, rotatedPath) suite.Nil(err) - newFile, err := os.Create(suite.testPath) + newFile, err := suite.ops.create(suite.testPath) suite.Nil(err) _, err = newFile.WriteString("new content\n") suite.Nil(err) @@ -1398,11 +1416,11 @@ func (suite *BaseLauncherTestSuite) TestRestartTailerAfterFileRotationRemovesTai // Simulate rotation rotatedPath := suite.testPath + ".1" - err = os.Rename(suite.testPath, rotatedPath) + err = suite.ops.rename(suite.testPath, rotatedPath) suite.Nil(err) // Create new file - newFile, err := os.Create(suite.testPath) + newFile, err := suite.ops.create(suite.testPath) suite.Nil(err) _, err = newFile.WriteString("line2\n") suite.Nil(err) @@ -1477,7 +1495,7 @@ func (suite *LauncherTestSuite) TestTailerReceivesConfigWhenDisabled() { defer status.Clear() // Create file with content - f, err := os.Create(suite.testPath) + f, err := suite.ops.create(suite.testPath) suite.Nil(err) _, err = f.WriteString("test data\n") suite.Nil(err) diff --git a/pkg/logs/launchers/file/provider/file_provider.go b/pkg/logs/launchers/file/provider/file_provider.go index c92fee250aed7a..13d9a6b35ac9ce 100644 --- a/pkg/logs/launchers/file/provider/file_provider.go +++ b/pkg/logs/launchers/file/provider/file_provider.go @@ -17,6 +17,7 @@ import ( "time" auditor "github.com/DataDog/datadog-agent/comp/logs/auditor/def" + "github.com/DataDog/datadog-agent/pkg/logs/internal/util/opener" "github.com/DataDog/datadog-agent/pkg/logs/sources" "github.com/DataDog/datadog-agent/pkg/logs/status" tailer "github.com/DataDog/datadog-agent/pkg/logs/tailers/file" @@ -267,7 +268,7 @@ func (p *FileProvider) FilesToTail(ctx context.Context, validatePodContainerID b // with ordering defined by 'wildcardOrder' func (p *FileProvider) CollectFiles(source *sources.LogSource) ([]*tailer.File, error) { path := source.Config.Path - _, err := os.Stat(path) + _, err := opener.StatLogFile(path) switch { case err == nil: return []*tailer.File{ diff --git a/pkg/privileged-logs/client/open.go b/pkg/privileged-logs/client/open.go index 4e6d6962e564aa..5bea4e34c81c4e 100644 --- a/pkg/privileged-logs/client/open.go +++ b/pkg/privileged-logs/client/open.go @@ -111,6 +111,24 @@ func OpenPrivileged(socketPath string, filePath string) (*os.File, error) { return nil, fmt.Errorf("no file descriptor received") } +func maybeOpenPrivileged(path string, originalError error) (*os.File, error) { + enabled := pkgconfigsetup.SystemProbe().GetBool("privileged_logs.enabled") + if !enabled { + return nil, originalError + } + + log.Debugf("Permission denied, opening file with system-probe: %v", path) + + socketPath := pkgconfigsetup.SystemProbe().GetString("system_probe_config.sysprobe_socket") + file, spErr := OpenPrivileged(socketPath, path) + log.Tracef("Opened file with system-probe: %v, err: %v", path, spErr) + if spErr != nil { + return nil, fmt.Errorf("failed to open file with system-probe: %w, original error: %w", spErr, originalError) + } + + return file, nil +} + // Open attempts to open a file, and if it fails due to permissions, it opens // the file using system-probe if the privileged logs module is available. func Open(path string) (*os.File, error) { @@ -119,19 +137,33 @@ func Open(path string) (*os.File, error) { return file, err } - enabled := pkgconfigsetup.SystemProbe().GetBool("privileged_logs.enabled") - if !enabled { - return file, err + file, err = maybeOpenPrivileged(path, err) + if err != nil { + return nil, err } - log.Debugf("Permission denied, opening file with system-probe: %v", path) + return file, nil +} - socketPath := pkgconfigsetup.SystemProbe().GetString("system_probe_config.sysprobe_socket") - fd, spErr := OpenPrivileged(socketPath, path) - log.Tracef("Opened file with system-probe: %v, err: %v", path, spErr) - if spErr != nil { - return file, fmt.Errorf("failed to open file with system-probe: %w, original error: %w", spErr, err) +// Stat attempts to stat a file, and if it fails due to permissions, it opens +// the file using system-probe if the privileged logs module is available and +// stats the opened file. +func Stat(path string) (os.FileInfo, error) { + info, err := os.Stat(path) + if err == nil || !errors.Is(err, os.ErrPermission) { + return info, err + } + + file, err := maybeOpenPrivileged(path, err) + if err != nil { + return nil, err + } + defer file.Close() + + info, err = file.Stat() + if err != nil { + return nil, err } - return fd, nil + return info, nil } diff --git a/pkg/privileged-logs/client/open_other.go b/pkg/privileged-logs/client/open_other.go index 99111cf376c02b..458323f4ddbb44 100644 --- a/pkg/privileged-logs/client/open_other.go +++ b/pkg/privileged-logs/client/open_other.go @@ -16,3 +16,8 @@ import ( func Open(path string) (*os.File, error) { return os.Open(path) } + +// Stat provides a fallback for non-Linux platforms where the privileged logs module is not available. +func Stat(path string) (os.FileInfo, error) { + return os.Stat(path) +} diff --git a/pkg/privileged-logs/test/handler.go b/pkg/privileged-logs/test/handler.go index de1a5360a94869..19f19646fa654d 100644 --- a/pkg/privileged-logs/test/handler.go +++ b/pkg/privileged-logs/test/handler.go @@ -130,6 +130,28 @@ func Setup(t *testing.T, callback func()) *Handler { return handler } +// WithParentPermFixup ensures that the parent directory of the given path has +// execute permissions before operations that manipulate the log files from the +// tests. This is necessary to ensure that the tests can manipulate the log +// files even when the parent directory does not have search permissions. +func WithParentPermFixup(t *testing.T, path string, op func() error) error { + parent := filepath.Dir(path) + err := os.Chmod(parent, 0755) + require.NoError(t, err) + + opErr := op() + + err = os.Chmod(parent, 0) + require.NoError(t, err) + + t.Cleanup(func() { + err := os.Chmod(parent, 0755) + require.NoError(t, err) + }) + + return opErr +} + func setupTestServer(t *testing.T) *Handler { cfg := &sysconfigtypes.Config{} deps := module.FactoryDependencies{} diff --git a/pkg/privileged-logs/test/privileged_logs_test.go b/pkg/privileged-logs/test/privileged_logs_test.go index c06f992ce32991..9693b1e60eaf96 100644 --- a/pkg/privileged-logs/test/privileged_logs_test.go +++ b/pkg/privileged-logs/test/privileged_logs_test.go @@ -25,7 +25,20 @@ import ( func createTestFile(t *testing.T, dir, filename, content string) string { filePath := filepath.Join(dir, filename) - err := os.WriteFile(filePath, []byte(content), 0000) + WithParentPermFixup(t, filePath, func() error { + err := os.WriteFile(filePath, []byte(content), 0000) + require.NoError(t, err) + t.Cleanup(func() { + os.Remove(filePath) + }) + return err + }) + return filePath +} + +func createAccessibleTestFile(t *testing.T, dir, filename, content string) string { + filePath := filepath.Join(dir, filename) + err := os.WriteFile(filePath, []byte(content), 0644) require.NoError(t, err) t.Cleanup(func() { os.Remove(filePath) @@ -66,6 +79,20 @@ func assertClientOpenContent(t *testing.T, filePath, expectedContent string) { assert.Equal(t, expectedContent, string(data)) } +func assertClientStatInfo(t *testing.T, filePath string, expectedSize int64) { + info, err := client.Stat(filePath) + require.NoError(t, err) + require.NotNil(t, info) + assert.Equal(t, expectedSize, info.Size()) +} + +func assertClientStatError(t *testing.T, filePath, expectedErrorMsg string) { + info, err := client.Stat(filePath) + require.Error(t, err) + assert.Nil(t, info) + assert.Contains(t, err.Error(), expectedErrorMsg) +} + func assertOpenPrivilegedError(t *testing.T, socketPath, filePath, expectedErrorMsg string) { file, err := client.OpenPrivileged(socketPath, filePath) require.Error(t, err) @@ -75,13 +102,22 @@ func assertOpenPrivilegedError(t *testing.T, socketPath, filePath, expectedError type PrivilegedLogsSuite struct { suite.Suite - handler *Handler - tempDir string + handler *Handler + searchableTmpDir string + tempDir string } func (s *PrivilegedLogsSuite) SetupSuite() { s.handler = Setup(s.T(), func() { - s.tempDir = s.T().TempDir() + s.searchableTmpDir = s.T().TempDir() + + unsearchableDir := filepath.Join(s.searchableTmpDir, "unsearchable") + err := os.Mkdir(unsearchableDir, 0000) + require.NoError(s.T(), err) + s.T().Cleanup(func() { + os.Remove(unsearchableDir) + }) + s.tempDir = unsearchableDir }) } @@ -114,7 +150,9 @@ func (s *PrivilegedLogsSuite) TestPrivilegedLogsModule_Symlink() { realLogFile := createTestFile(s.T(), s.tempDir, "real.log", testContent) symlinkPath := filepath.Join(s.tempDir, "fake.log") - err := os.Symlink(realLogFile, symlinkPath) + err := WithParentPermFixup(s.T(), symlinkPath, func() error { + return os.Symlink(realLogFile, symlinkPath) + }) require.NoError(s.T(), err) assertOpenPrivilegedContent(s.T(), s.handler.SocketPath, symlinkPath, testContent) @@ -124,7 +162,9 @@ func (s *PrivilegedLogsSuite) TestPrivilegedLogsModule_SymlinkToNonLogFile() { nonLogFile := createTestFile(s.T(), s.tempDir, "secret_nonlog.txt", "secret content") symlinkPath := filepath.Join(s.tempDir, "fake_nonlog.log") - err := os.Symlink(nonLogFile, symlinkPath) + err := WithParentPermFixup(s.T(), symlinkPath, func() error { + return os.Symlink(nonLogFile, symlinkPath) + }) require.NoError(s.T(), err) assertOpenPrivilegedError(s.T(), s.handler.SocketPath, symlinkPath, "non-log file not allowed") @@ -146,6 +186,7 @@ func (s *PrivilegedLogsSuite) TestPrivilegedLogsModule_OpenFallback() { setupSystemProbeConfig(s.T(), s.handler.SocketPath, true) assertClientOpenContent(s.T(), upperLogFile, testContent) + assertClientStatInfo(s.T(), upperLogFile, int64(len(testContent))) } func (s *PrivilegedLogsSuite) TestPrivilegedLogsModule_OpenFallbackError() { @@ -155,6 +196,7 @@ func (s *PrivilegedLogsSuite) TestPrivilegedLogsModule_OpenFallbackError() { setupSystemProbeConfig(s.T(), s.handler.SocketPath, true) assertClientOpenError(s.T(), upperLogFile, "non-log file not allowed") + assertClientStatError(s.T(), upperLogFile, "non-log file not allowed") } func TestPrivilegedLogsSuite(t *testing.T) { @@ -170,12 +212,13 @@ func TestPrivilegedLogsModule_Close(t *testing.T) { func (s *PrivilegedLogsSuite) TestOpen_SuccessfulNormalOpen() { testContent := "Hello, privileged logs transfer!" - testFile := createTestFile(s.T(), s.tempDir, "test.log", testContent) + testFile := createAccessibleTestFile(s.T(), s.searchableTmpDir, "test.log", testContent) - // Force the file to be accesssible from the non-privileged user + // Force the file to be accessible from the non-privileged user require.NoError(s.T(), os.Chmod(testFile, 0644)) assertClientOpenContent(s.T(), testFile, testContent) + assertClientStatInfo(s.T(), testFile, int64(len(testContent))) } func (s *PrivilegedLogsSuite) TestOpen_PermissionErrorWithModuleDisabled() { @@ -184,6 +227,7 @@ func (s *PrivilegedLogsSuite) TestOpen_PermissionErrorWithModuleDisabled() { setupSystemProbeConfig(s.T(), s.handler.SocketPath, false) assertClientOpenError(s.T(), testFile, "permission denied") + assertClientStatError(s.T(), testFile, "permission denied") } func (s *PrivilegedLogsSuite) TestOpen_PermissionErrorWithModuleFailure() { @@ -197,6 +241,12 @@ func (s *PrivilegedLogsSuite) TestOpen_PermissionErrorWithModuleFailure() { assert.Nil(t, file) assert.Contains(t, err.Error(), "failed to open file with system-probe") assert.Contains(t, err.Error(), "permission denied") + + stat, err := client.Stat(testFile) + require.Error(t, err) + assert.Nil(t, stat) + assert.Contains(t, err.Error(), "failed to open file with system-probe") + assert.Contains(t, err.Error(), "permission denied") } func (s *PrivilegedLogsSuite) TestOpen_NonPermissionError() { @@ -205,4 +255,9 @@ func (s *PrivilegedLogsSuite) TestOpen_NonPermissionError() { require.Error(t, err) assert.Nil(t, file) assert.NotContains(t, err.Error(), "system-probe") + + stat, err := client.Stat("/nonexistent/file.log") + require.Error(t, err) + assert.Nil(t, stat) + assert.NotContains(t, err.Error(), "system-probe") } diff --git a/test/new-e2e/tests/discovery/testdata/provision/python/server.py b/test/new-e2e/tests/discovery/testdata/provision/python/server.py index 8bae588e5f650f..081217738e43f0 100644 --- a/test/new-e2e/tests/discovery/testdata/provision/python/server.py +++ b/test/new-e2e/tests/discovery/testdata/provision/python/server.py @@ -34,16 +34,24 @@ def run(): server = HTTPServer(addr, Handler) dd_service = os.getenv("DD_SERVICE", "python") - mode = 0o666 - if dd_service == "python-restricted-dd": - # Write-only log file to trigger permission errors from discovery - mode = 0o222 + pid = os.getpid() + logpath = f'/tmp/{dd_service}-{pid}' + logfile = f'{logpath}/foo.log' + restricted = dd_service == "python-restricted-dd" - logfile = f'/tmp/{dd_service}-{os.getpid()}.log' + os.makedirs(logpath, exist_ok=True) + + # Write-only log file to trigger permission errors from discovery + mode = 0o222 if restricted else 0o666 fd = os.open(logfile, os.O_CREAT | os.O_WRONLY | os.O_APPEND, mode) file = os.fdopen(fd, "a") + if restricted: + # Test that privileged logs can open the file even when the directory is + # not searchable. + os.chmod(logpath, 0o0) + logging.basicConfig( level=logging.INFO, format='%(message)s',