Compare commits

..

6 Commits

Author SHA1 Message Date
dependabot[bot] 251ec3ef66 build(deps): bump github/codeql-action from 3 to 4 (#497)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3 to 4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-27 15:45:40 -07:00
dependabot[bot] cf78b04400 build(deps): bump actions/setup-go from 4 to 7 (#496)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 7.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-27 15:40:11 -07:00
dependabot[bot] 0479c455fb build(deps): bump actions/checkout from 4 to 7 (#495)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-27 15:34:51 -07:00
Chris F Ravenscroft 156e917697 fix: route library log output through the logger (#491)
customWriter is the sink for log output from libraries that emit
unstructured text. With structured logging enabled it bypassed the
logger and hand-rolled JSON straight to os.Stderr, which had two
consequences.

It escaped only double quotes, so backslashes and control characters
were emitted raw. A Windows path produced "path C:\Users\x", where \U
is not a valid JSON escape, and a message containing a newline split
one record across two lines. Anything parsing these logs saw malformed
records.

It also wrote to stderr regardless of where the logger pointed, so
library messages could not follow the logger to another sink.

zerolog already emits the same fields with correct escaping, so the
branch is removed and everything goes through e.logr. Output is
byte-identical for plain text and quoted strings.


Claude-Session: https://claude.ai/code/session_014L5EoqGWsuZWr8fCVM6izP

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 17:05:16 -07:00
lordwelch 7832f9e94d Do not output on stderr if syslog is enabled (#479) 2026-09-13 17:04:15 -07:00
Chris F Ravenscroft e8951481c8 ci: add actions/stale workflow (#490)
Marks issues and pull requests stale after 60 days of inactivity and
closes them 14 days later. Any comment clears the stale label and
restarts the clock, so active discussions are never swept up.

Exempts pinned, security, blocked, help wanted and good first issue, and
anything assigned to a milestone. Runs oldest-first so the real backlog
is handled before recent items.


Claude-Session: https://claude.ai/code/session_014L5EoqGWsuZWr8fCVM6izP

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 16:19:12 -07:00
5 changed files with 74 additions and 27 deletions
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
go-version: [1.25.x] go-version: [1.25.x]
steps: steps:
- name: Install Go - name: Install Go
uses: actions/setup-go@v4 uses: actions/setup-go@v7
with: with:
go-version: ${{ matrix.go-version }} go-version: ${{ matrix.go-version }}
- name: Updating packages database - name: Updating packages database
@@ -21,7 +21,7 @@ jobs:
- name: Install CLI Dependencies - name: Install CLI Dependencies
run: sudo apt-get install -y ldap-utils oathtool libpam0g-dev run: sudo apt-get install -y ldap-utils oathtool libpam0g-dev
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v7
- name: Fetch Go dependencies - name: Fetch Go dependencies
working-directory: ./v2 working-directory: ./v2
run: go get -t -v ./... run: go get -t -v ./...
+4 -4
View File
@@ -24,18 +24,18 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v7
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v4
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
queries: +security-and-quality queries: +security-and-quality
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v3 uses: github/codeql-action/autobuild@v4
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3 uses: github/codeql-action/analyze@v4
with: with:
category: "/language:${{ matrix.language }}" category: "/language:${{ matrix.language }}"
+6 -12
View File
@@ -44,12 +44,11 @@ func InitLogging(reqdebug bool, reqsyslog bool, reqstructlog bool) zerolog.Logge
var logr zerolog.Logger var logr zerolog.Logger
if reqsyslog { if reqsyslog {
s, err := syslog.New(syslog.LOG_INFO, "glauth") s, err := syslog.New(syslog.LOG_INFO, "glauth")
if err != nil { if err == nil {
logr = zerolog.New(zerolog.SyslogLevelWriter(s)).Level(level).With().Timestamp().Logger()
} else {
fmt.Println("Unable to write to syslog: ignoring...") fmt.Println("Unable to write to syslog: ignoring...")
reqsyslog = false reqsyslog = false
} else {
writers := zerolog.MultiLevelWriter(mainWriter, zerolog.SyslogLevelWriter(s))
logr = zerolog.New(writers).Level(level).With().Timestamp().Logger()
} }
} }
@@ -57,14 +56,13 @@ func InitLogging(reqdebug bool, reqsyslog bool, reqstructlog bool) zerolog.Logge
logr = zerolog.New(mainWriter).Level(level).With().Timestamp().Logger() logr = zerolog.New(mainWriter).Level(level).With().Timestamp().Logger()
} }
log.SetOutput(customWriter{logr: logr, structlog: reqstructlog}) log.SetOutput(customWriter{logr: logr})
return logr return logr
} }
type customWriter struct { type customWriter struct {
logr zerolog.Logger logr zerolog.Logger
structlog bool
} }
func (e customWriter) Write(p []byte) (int, error) { func (e customWriter) Write(p []byte) (int, error) {
@@ -76,10 +74,6 @@ func (e customWriter) Write(p []byte) (int, error) {
if msg == "" { if msg == "" {
msg = strings.TrimSpace(string(p)) msg = strings.TrimSpace(string(p))
} }
if e.structlog { e.logr.Info().Msg(msg)
fmt.Fprintf(os.Stderr, "{\"level\":\"info\",\"time\":\"%s\",\"message\":\"%s\"}\n", time.Now().Format(time.RFC1123Z), strings.Replace(strings.TrimSpace(msg), `"`, `\"`, -1))
} else {
e.logr.Info().Msg(msg)
}
return len(p), nil return len(p), nil
} }
+59
View File
@@ -0,0 +1,59 @@
package logging
import (
"bytes"
"encoding/json"
"strings"
"testing"
"github.com/rs/zerolog"
)
// customWriter adapts log output from libraries that emit unstructured text.
// Everything it receives must go through the logger, so that it lands wherever
// the logger points - notably syslog only, when syslog is enabled.
func TestCustomWriterEmitsValidJSONThroughTheLogger(t *testing.T) {
for _, tc := range []struct {
name string
in string
want string
}{
{"plain", "something happened", "something happened"},
{"quotes", `bind for "cn=foo"`, `bind for "cn=foo"`},
{"backslashes", `path C:\Users\x`, `path C:\Users\x`},
{"control characters", "tab\there\nand a newline", "tab\there\nand a newline"},
{
"library timestamp prefix is stripped",
"2026/09/13 16:50:54 connection closed",
"connection closed",
},
} {
t.Run(tc.name, func(t *testing.T) {
var buf bytes.Buffer
w := customWriter{logr: zerolog.New(&buf).With().Timestamp().Logger()}
if _, err := w.Write([]byte(tc.in)); err != nil {
t.Fatalf("Write: %v", err)
}
// One record, one line: an unescaped newline would split this.
if got := strings.Count(strings.TrimRight(buf.String(), "\n"), "\n"); got != 0 {
t.Fatalf("expected a single log line, got %d extra newlines in %q", got, buf.String())
}
var record struct {
Level string `json:"level"`
Message string `json:"message"`
}
if err := json.Unmarshal(buf.Bytes(), &record); err != nil {
t.Fatalf("emitted invalid JSON (%v): %s", err, buf.String())
}
if record.Message != tc.want {
t.Errorf("message = %q, want %q", record.Message, tc.want)
}
if record.Level != "info" {
t.Errorf("level = %q, want %q", record.Level, "info")
}
})
}
}
+3 -9
View File
@@ -4,7 +4,6 @@
package logging package logging
import ( import (
"fmt"
"io" "io"
"log" "log"
"os" "os"
@@ -42,14 +41,13 @@ func InitLogging(reqdebug bool, reqsyslog bool, reqstructlog bool) zerolog.Logge
logr := zerolog.New(mainWriter).Level(level).With().Timestamp().Logger() logr := zerolog.New(mainWriter).Level(level).With().Timestamp().Logger()
log.SetOutput(customWriter{logr: logr, structlog: reqstructlog}) log.SetOutput(customWriter{logr: logr})
return logr return logr
} }
type customWriter struct { type customWriter struct {
logr zerolog.Logger logr zerolog.Logger
structlog bool
} }
func (e customWriter) Write(p []byte) (int, error) { func (e customWriter) Write(p []byte) (int, error) {
@@ -61,10 +59,6 @@ func (e customWriter) Write(p []byte) (int, error) {
if msg == "" { if msg == "" {
msg = strings.TrimSpace(string(p)) msg = strings.TrimSpace(string(p))
} }
if e.structlog { e.logr.Info().Msg(msg)
fmt.Fprintf(os.Stderr, "{\"level\":\"info\",\"time\":\"%s\",\"message\":\"%s\"}\n", time.Now().Format(time.RFC1123Z), strings.Replace(strings.TrimSpace(msg), `"`, `\"`, -1))
} else {
e.logr.Info().Msg(msg)
}
return len(p), nil return len(p), nil
} }