Skip to content

Commit 8feceb5

Browse files
committed
seclog: review improvements
1 parent a2956c6 commit 8feceb5

4 files changed

Lines changed: 36 additions & 40 deletions

File tree

seclog/nop.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type nopLogger struct{}
2525
// Ensure [nopLogger] implements [SecurityLogger].
2626
var _ SecurityLogger = (*nopLogger)(nil)
2727

28+
// NewNopLogger returns a [SecurityLogger] that silently discards all events.
2829
func NewNopLogger() SecurityLogger {
2930
return nopLogger{}
3031
}

seclog/seclog.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ import (
2727
"github.com/snapcore/snapd/logger"
2828
)
2929

30+
// unknown is the placeholder for empty fields in descriptions.
31+
const unknown = "<unknown>"
32+
3033
// Level is the importance or severity of a log event.
3134
// The higher the level, the more severe the event.
3235
type Level int
@@ -40,9 +43,7 @@ const (
4043
LevelCritical Level = 5
4144
)
4245

43-
// String returns a name for the level. If the level has a name, then that name
44-
// in uppercase is returned. Otherwise, a string of the form "UKNOWN(<number>)"
45-
// is returned.
46+
// String returns a name for the level.
4647
func (l Level) String() string {
4748
switch l {
4849
case LevelDebug:
@@ -61,9 +62,6 @@ func (l Level) String() string {
6162
}
6263

6364
// SnapdUser represents the identity of a user for security log events.
64-
// The slog output schema is defined by [SnapdUser.LogValue], which
65-
// renders Expiration as "never" for zero values instead of emitting a
66-
// zero-value datetime.
6765
type SnapdUser struct {
6866
ID int64 `json:"snapd-user-id"`
6967
StoreUserName string `json:"store-user-name"`
@@ -73,10 +71,8 @@ type SnapdUser struct {
7371

7472
// String returns a colon-separated description of the user in the form
7573
// "<ID>:<StoreUserEmail>:<StoreUserName>". Fields that are unset use
76-
// "unknown" as a placeholder. A zero ID is treated as unset.
74+
// "<unknown>" as a placeholder. A zero ID means unset.
7775
func (u SnapdUser) String() string {
78-
const unknown = "unknown"
79-
8076
id := unknown
8177
if u.ID != 0 {
8278
id = fmt.Sprintf("%d", u.ID)
@@ -115,8 +111,6 @@ type Reason struct {
115111
// "<Code>:<Message>". Fields that are unset use "unknown" as a
116112
// placeholder.
117113
func (r Reason) String() string {
118-
const unknown = "unknown"
119-
120114
code := unknown
121115
if r.Code != "" {
122116
code = r.Code
@@ -156,7 +150,8 @@ type SecurityLogger interface {
156150

157151
var (
158152
globalLogger SecurityLogger = NewNopLogger()
159-
lock sync.Mutex
153+
// lock guards globalLogger reads and writes.
154+
lock sync.Mutex
160155
)
161156

162157
// Setup activates the security logger, replacing any previously
@@ -172,10 +167,11 @@ func Setup(l SecurityLogger) {
172167

173168
// LogLoggerEnabled logs that the security logger has been enabled.
174169
func LogLoggerEnabled() {
170+
logger.Noticef("security logger enabled")
171+
175172
lock.Lock()
176173
defer lock.Unlock()
177174

178-
logger.Noticef("security logger enabled")
179175
globalLogger.LogAny(
180176
Event{Category: "SYS", Name: "sys_logging_enabled", Level: LevelInfo},
181177
"Security logging enabled",
@@ -184,10 +180,11 @@ func LogLoggerEnabled() {
184180

185181
// LogLoggerDisabled logs that the security logger has been disabled.
186182
func LogLoggerDisabled() {
183+
logger.Noticef("security logger disabled")
184+
187185
lock.Lock()
188186
defer lock.Unlock()
189187

190-
logger.Noticef("security logger disabled")
191188
globalLogger.LogAny(
192189
Event{Category: "SYS", Name: "sys_logging_disabled", Level: LevelCritical},
193190
"Security logging disabled",

seclog/seclog_test.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (s *SecLogSuite) SetUpTest(c *C) {
4646
// No cleanup of the global logger is needed: every suite that
4747
// uses seclog calls Setup in its own SetUpTest, replacing any
4848
// leftover logger from a previous suite.
49-
seclog.Setup(seclogtest.NewMockSecurityLogger(s.buf))
49+
seclog.Setup(seclogtest.MockSecurityLogger(s.buf))
5050
}
5151

5252
func (s *SecLogSuite) TearDownTest(c *C) {
@@ -76,8 +76,6 @@ func (s *SecLogSuite) TestString(c *C) {
7676
"UNKNOWN(7)",
7777
}
7878

79-
c.Assert(len(levels), Equals, len(expected))
80-
8179
obtained := make([]string, 0, len(levels))
8280

8381
for _, level := range levels {
@@ -93,17 +91,17 @@ func (s *SecLogSuite) TestSnapdUserString(c *C) {
9391
ID: 42, StoreUserEmail: "a@b.com", StoreUserName: "jdoe",
9492
}.String(), Equals, "42:a@b.com:jdoe")
9593

96-
// All fields zero/empty — all "unknown".
97-
c.Check(seclog.SnapdUser{}.String(), Equals, "unknown:unknown:unknown")
94+
// All fields zero/empty — all "<unknown>".
95+
c.Check(seclog.SnapdUser{}.String(), Equals, "<unknown>:<unknown>:<unknown>")
9896

9997
// Only ID set.
100-
c.Check(seclog.SnapdUser{ID: 7}.String(), Equals, "7:unknown:unknown")
98+
c.Check(seclog.SnapdUser{ID: 7}.String(), Equals, "7:<unknown>:<unknown>")
10199

102100
// Only email set.
103-
c.Check(seclog.SnapdUser{StoreUserEmail: "x@y.z"}.String(), Equals, "unknown:x@y.z:unknown")
101+
c.Check(seclog.SnapdUser{StoreUserEmail: "x@y.z"}.String(), Equals, "<unknown>:x@y.z:<unknown>")
104102

105103
// Only username set.
106-
c.Check(seclog.SnapdUser{StoreUserName: "root"}.String(), Equals, "unknown:unknown:root")
104+
c.Check(seclog.SnapdUser{StoreUserName: "root"}.String(), Equals, "<unknown>:<unknown>:root")
107105
}
108106

109107
func (s *SecLogSuite) TestReasonString(c *C) {
@@ -112,14 +110,14 @@ func (s *SecLogSuite) TestReasonString(c *C) {
112110
Code: seclog.ReasonInvalidCredentials, Message: "bad password",
113111
}.String(), Equals, "invalid-credentials:bad password")
114112

115-
// Both fields empty — all "unknown".
116-
c.Check(seclog.Reason{}.String(), Equals, "unknown:unknown")
113+
// Both fields empty — all "<unknown>".
114+
c.Check(seclog.Reason{}.String(), Equals, "<unknown>:<unknown>")
117115

118116
// Only code set.
119-
c.Check(seclog.Reason{Code: seclog.ReasonInternal}.String(), Equals, "internal:unknown")
117+
c.Check(seclog.Reason{Code: seclog.ReasonInternal}.String(), Equals, "internal:<unknown>")
120118

121119
// Only message set.
122-
c.Check(seclog.Reason{Message: "something broke"}.String(), Equals, "unknown:something broke")
120+
c.Check(seclog.Reason{Message: "something broke"}.String(), Equals, "<unknown>:something broke")
123121
}
124122

125123
func (s *SecLogSuite) TestSetupSuccess(c *C) {
@@ -134,7 +132,7 @@ func (s *SecLogSuite) TestSetupReplacesExistingLogger(c *C) {
134132

135133
// Replace with a second logger.
136134
secondBuf := &bytes.Buffer{}
137-
seclog.Setup(seclogtest.NewMockSecurityLogger(secondBuf))
135+
seclog.Setup(seclogtest.MockSecurityLogger(secondBuf))
138136

139137
// New events go to the second logger, not the first.
140138
s.buf.Reset()

seclog/seclogtest/seclogtest.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,39 +29,39 @@ import (
2929
"github.com/snapcore/snapd/seclog"
3030
)
3131

32-
// MockSecurityLogger implements seclog.SecurityLogger and writes event
32+
// mockLogger implements seclog.SecurityLogger and writes event
3333
// names plus key identifying data to a buffer. This lets tests verify
3434
// that the right events are emitted without depending on slog or JSON.
35-
type MockSecurityLogger struct {
35+
type mockLogger struct {
3636
buf *bytes.Buffer
3737
}
3838

39-
// Ensure MockSecurityLogger implements seclog.SecurityLogger.
40-
var _ seclog.SecurityLogger = (*MockSecurityLogger)(nil)
39+
// Ensure mockLogger implements seclog.SecurityLogger.
40+
var _ seclog.SecurityLogger = (*mockLogger)(nil)
4141

42-
// NewMockSecurityLogger returns a MockSecurityLogger that writes to the
42+
// MockSecurityLogger returns a [seclog.SecurityLogger] that writes to the
4343
// given buffer.
44-
func NewMockSecurityLogger(buf *bytes.Buffer) *MockSecurityLogger {
45-
return &MockSecurityLogger{buf: buf}
44+
func MockSecurityLogger(buf *bytes.Buffer) seclog.SecurityLogger {
45+
return &mockLogger{buf: buf}
4646
}
4747

4848
// LogAny implements [seclog.SecurityLogger.LogAny].
49-
func (m *MockSecurityLogger) LogAny(event seclog.Event, description string, attrs ...seclog.Attr) {
49+
func (m *mockLogger) LogAny(event seclog.Event, description string, attrs ...seclog.Attr) {
5050
fmt.Fprintf(m.buf, "%s %s", event.Name, description)
5151
for _, a := range attrs {
5252
fmt.Fprintf(m.buf, " [%s=%#v]", a.Key, a.Value)
5353
}
5454
fmt.Fprintln(m.buf)
5555
}
5656

57-
// NewMockSlogLogger returns a buffer and a constructor function matching the
57+
// MockSlogLogger returns a buffer and a constructor function matching the
5858
// seclog.NewSlogLogger signature. The constructor ignores its arguments and
59-
// returns a MockSecurityLogger backed by the buffer. This is intended for
59+
// returns a mockLogger backed by the buffer. This is intended for
6060
// mocking the newSlogLogger variable in tests.
61-
func NewMockSlogLogger() (*bytes.Buffer, func(io.Writer, string, seclog.Level) seclog.SecurityLogger) {
61+
func MockSlogLogger() (*bytes.Buffer, func(io.Writer, string, seclog.Level) seclog.SecurityLogger) {
6262
buf := &bytes.Buffer{}
63-
fn := func(_ io.Writer, _ string, _ seclog.Level) seclog.SecurityLogger {
64-
return NewMockSecurityLogger(buf)
63+
fn := func(io.Writer, string, seclog.Level) seclog.SecurityLogger {
64+
return MockSecurityLogger(buf)
6565
}
6666
return buf, fn
6767
}

0 commit comments

Comments
 (0)