Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions providers-sdk/v1/testutils/testdata/arch.json
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,93 @@
}
}
},
{
"Resource": "file",
"ID": "/etc/rsyslog.conf",
"Fields": {
"content": {
"type": "\u0007",
"value": "# /etc/rsyslog.conf\n# rsyslog configuration file\n\n$ModLoad imuxsock\n$ModLoad imklog\n\n# Use traditional timestamp format\n$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat\n\n# Set the default permissions for all log files.\n$FileOwner root\n$FileGroup adm\n$FileCreateMode 0640\n$DirCreateMode 0755\n$Umask 0022\n\n# Log anything (except mail) of level info or higher\n*.info;mail.none;authpriv.none;cron.none /var/log/messages\n\n# The authpriv file has restricted access.\nauthpriv.* /var/log/secure\n\n# Log all the mail messages in one place.\nmail.* -/var/log/maillog\n\n# Log cron stuff\ncron.* /var/log/cron\n\n# Everybody gets emergency messages\n*.emerg :omusrmsg:*\n\n# Include all config files in /etc/rsyslog.d/\n$IncludeConfig /etc/rsyslog.d/*.conf\n"
},
"exists": {
"type": "\u0004",
"value": true
},
"path": {
"type": "\u0007",
"value": "/etc/rsyslog.conf"
},
"permissions": {
"type": "\u001bfile.permissions",
"value": {
"Name": "file.permissions",
"ID": "-rw-r--r--"
}
},
"size": {
"type": "\u0005",
"value": 700
}
}
},
{
"Resource": "file",
"ID": "/etc/rsyslog.d",
"Fields": {
"exists": {
"type": "\u0004",
"value": true
},
"path": {
"type": "\u0007",
"value": "/etc/rsyslog.d"
}
}
},
{
"Resource": "file",
"ID": "/etc/rsyslog.d/50-default.conf",
"Fields": {
"content": {
"type": "\u0007",
"value": "# Default rules for rsyslog.\n\n# Log kernel messages to the console.\nkern.* /var/log/kern.log\n\n# Log authentication messages.\nauth,authpriv.* /var/log/auth.log\n\n# First some standard log files. Log by facility.\nuser.* -/var/log/user.log\ndaemon.* -/var/log/daemon.log\n"
},
"exists": {
"type": "\u0004",
"value": true
},
"path": {
"type": "\u0007",
"value": "/etc/rsyslog.d/50-default.conf"
},
"permissions": {
"type": "\u001bfile.permissions",
"value": {
"Name": "file.permissions",
"ID": "-rw-r--r--"
}
},
"size": {
"type": "\u0005",
"value": 300
}
}
},
{
"Resource": "files.find",
"ID": "/etc/rsyslog.d -xdev type=file permissions=0",
"Fields": {
"list": {
"type": "\u0019\u001bfile",
"value": [
{
"Name": "file",
"ID": "/etc/rsyslog.d/50-default.conf"
}
]
}
}
},
{
"Resource": "file",
"ID": "/etc/ssl/cert.pem",
Expand Down
23 changes: 21 additions & 2 deletions providers/os/resources/rsyslog.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,27 @@ import (
"go.mondoo.com/mql/v13/checksums"
"go.mondoo.com/mql/v13/llx"
"go.mondoo.com/mql/v13/providers-sdk/v1/resources"
"go.mondoo.com/mql/v13/providers/os/connection/shared"
)

const defaultRsyslogConf = "/etc/rsyslog.conf"
// rsyslogConfPaths maps platform names to their rsyslog.conf location.
// BSD variants install rsyslog via package managers to non-default prefixes.
var rsyslogConfPaths = map[string]string{
"freebsd": "/usr/local/etc/rsyslog.conf",
"dragonflybsd": "/usr/local/etc/rsyslog.conf",
"openbsd": "/usr/local/etc/rsyslog.conf",
"netbsd": "/usr/pkg/etc/rsyslog.conf",
}

func rsyslogConfPath(conn shared.Connection) string {
asset := conn.Asset()
if asset != nil && asset.Platform != nil {
if p, ok := rsyslogConfPaths[asset.Platform.Name]; ok {
return p
}
}
return "/etc/rsyslog.conf"
}

func (s *mqlRsyslogConf) id() (string, error) {
files := s.GetFiles()
Expand All @@ -30,7 +48,8 @@ func (s *mqlRsyslogConf) id() (string, error) {
}

func (s *mqlRsyslogConf) path() (string, error) {
return defaultRsyslogConf, nil
conn := s.MqlRuntime.Connection.(shared.Connection)
return rsyslogConfPath(conn), nil
}

func (s *mqlRsyslogConf) files(path string) ([]any, error) {
Expand Down
40 changes: 40 additions & 0 deletions providers/os/resources/rsyslog_internal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package resources

import (
"testing"

"github.com/stretchr/testify/assert"
"go.mondoo.com/mql/v13/providers-sdk/v1/inventory"
)

func TestRsyslogConfPath(t *testing.T) {
tests := []struct {
platform string
expected string
}{
{"freebsd", "/usr/local/etc/rsyslog.conf"},
{"dragonflybsd", "/usr/local/etc/rsyslog.conf"},
{"openbsd", "/usr/local/etc/rsyslog.conf"},
{"netbsd", "/usr/pkg/etc/rsyslog.conf"},
{"debian", "/etc/rsyslog.conf"},
{"ubuntu", "/etc/rsyslog.conf"},
{"redhat", "/etc/rsyslog.conf"},
{"macos", "/etc/rsyslog.conf"},
{"aix", "/etc/rsyslog.conf"},
{"solaris", "/etc/rsyslog.conf"},
}

for _, tt := range tests {
t.Run(tt.platform, func(t *testing.T) {
assert.Equal(t, tt.expected, rsyslogConfPath(connWithPlatform(tt.platform)))
})
}

t.Run("nil platform", func(t *testing.T) {
conn := &mockConn{asset: &inventory.Asset{}}
assert.Equal(t, "/etc/rsyslog.conf", rsyslogConfPath(conn))
})
Comment on lines +36 to +39
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 suggestion — You test nil Platform but not nil Asset. Consider adding a case with &mockConn{asset: nil} to cover the asset != nil guard in rsyslogConfPath.

}
68 changes: 68 additions & 0 deletions providers/os/resources/rsyslog_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package resources_test

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestResource_RsyslogConf(t *testing.T) {
t.Run("files includes main conf and .d fragments", func(t *testing.T) {
res := x.TestQuery(t, "rsyslog.conf.files.length")
require.NotEmpty(t, res)
require.NoError(t, res[0].Data.Error)
assert.Equal(t, int64(2), res[0].Data.Value)
})

t.Run("content aggregates all files", func(t *testing.T) {
res := x.TestQuery(t, "rsyslog.conf.content")
require.NotEmpty(t, res)
require.NoError(t, res[0].Data.Error)
content := res[0].Data.Value.(string)
// Main conf content
assert.Contains(t, content, "$ModLoad imuxsock")
// Fragment content from rsyslog.d/50-default.conf
assert.Contains(t, content, "kern.* /var/log/kern.log")
})

t.Run("settings strips comments and blanks", func(t *testing.T) {
res := x.TestQuery(t, "rsyslog.conf.settings")
require.NotEmpty(t, res)
require.NoError(t, res[0].Data.Error)
settings := res[0].Data.Value.([]any)
assert.Greater(t, len(settings), 0)
// Verify comment-only and blank lines are excluded
for _, s := range settings {
line := s.(string)
assert.NotEmpty(t, line)
assert.NotEqual(t, "#", string(line[0]), "settings should not contain comment lines")
}
})

t.Run("settings contains expected directives", func(t *testing.T) {
res := x.TestQuery(t, "rsyslog.conf.settings")
require.NotEmpty(t, res)
require.NoError(t, res[0].Data.Error)
settings := res[0].Data.Value.([]any)
// Check for a known directive from the main conf
found := false
for _, s := range settings {
if s.(string) == "$ModLoad imuxsock" {
found = true
break
}
}
assert.True(t, found, "settings should contain '$ModLoad imuxsock'")
})

t.Run("path returns default", func(t *testing.T) {
res := x.TestQuery(t, "rsyslog.conf.path")
require.NotEmpty(t, res)
require.NoError(t, res[0].Data.Error)
assert.Equal(t, "/etc/rsyslog.conf", res[0].Data.Value)
})
}
Loading