-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Add audit logging and DNS management #51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
nfebe
commented
Jan 14, 2026
- Add audit logging system with SQLite storage
- Add middleware for request/response capture
- Add DNS plugins for external providers (Cloudflare, Route53, DigitalOcean, Hetzner)
- Add PowerDNS infrastructure service for self-hosted DNS
- Add API handlers for audit, DNS, and PowerDNS endpoints
- Extend plugin system with DNSPlugin interface
- Add audit logging system with SQLite storage - Add middleware for request/response capture - Add DNS plugins for external providers (Cloudflare, Route53, DigitalOcean, Hetzner) - Add PowerDNS infrastructure service for self-hosted DNS - Add API handlers for audit, DNS, and PowerDNS endpoints - Extend plugin system with DNSPlugin interface Signed-off-by: nfebe <fenn25.fn@gmail.com>
Code Review SummaryThis pull request introduces a comprehensive audit logging system and extends DNS management capabilities by integrating external DNS providers (Cloudflare, AWS Route53, DigitalOcean, Hetzner) and a self-hosted PowerDNS instance. It also updates the Go version in CI workflows to 1.24 and refines dependency management. The changes generally reflect strong engineering practices with a focus on modularity and security. 🚀 Key Improvements
💡 Minor Suggestions
🚨 Critical Issues
|
🔍 Code Review💡 1. **internal/api/server.go** (Lines 860-865) - SECURITYUsing Suggested Code: Current Code: func generateRandomPassword(length int) string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
b := make([]byte, length)
for i := range b {
b[i] = charset[time.Now().UnixNano()%int64(len(charset))]
time.Sleep(time.Nanosecond)
}
return string(b)
}💡 2. **internal/api/server.go** (Lines 2425-2471) - REFACTORModifying YAML content using string replacement and regex can be very brittle and lead to parsing errors or unexpected behavior if the YAML structure deviates slightly from the expected pattern. It's generally safer and more robust to unmarshal the YAML into a Go struct (or Consider using Suggested Code: Current Code: func replaceHardcodedNetwork(content, oldNetwork, newNetwork string) string {
if oldNetwork == newNetwork {
return content
}
lines := strings.Split(content, "\n")
var result []string
inNetworks := false
inServicesNetworks := false
indentLevel := 0
for _, line := range lines {
trimmed := strings.TrimSpace(line)
currentIndent := len(line) - len(strings.TrimLeft(line, " \t"))
if trimmed == "networks:" {
if currentIndent == 0 {
inNetworks = true
indentLevel = currentIndent
} else {
inServicesNetworks = true
indentLevel = currentIndent
}
result = append(result, line)
continue
}
if inNetworks && currentIndent > indentLevel {
if strings.HasPrefix(trimmed, oldNetwork+":") {
line = strings.Replace(line, oldNetwork+":", newNetwork+":", 1)
}
} else if inNetworks && currentIndent <= indentLevel && trimmed != "" {
inNetworks = false
}
if inServicesNetworks && currentIndent > indentLevel {
if trimmed == "- "+oldNetwork {
line = strings.Replace(line, "- "+oldNetwork, "- "+newNetwork, 1)
}
} else if inServicesNetworks && currentIndent <= indentLevel && trimmed != "" {
inServicesNetworks = false
}
result = append(result, line)
}
return strings.Join(result, "\n")
}💡 3. **internal/audit/middleware.go** (Lines 16-19) - REFACTORThese context keys are also defined in Suggested Code: Current Code: const (
ContextKeyActorType = "audit_actor_type"
ContextKeyActorID = "audit_actor_id"
ContextKeyActorName = "audit_actor_name"
ContextKeyAPIKeyPrefix = "audit_api_key_prefix"
)💡 4. **internal/audit/middleware.go** (Lines 139-158) - CLARITYThe Consider a more explicit approach by annotating Gin routes with resource types and ID parameters, or by defining specific patterns for IDs where possible (e.g., only UUIDs or purely numeric IDs if that is consistently the case). Suggested Code: Current Code: func isID(s string) bool {
if s == "" {
return false
}
if uuidRegex.MatchString(s) {
return true
}
if numericRegex.MatchString(s) {
return true
}
if len(s) >= 8 && len(s) <= 64 && !strings.Contains(s, " ") {
alphaNum := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
if alphaNum.MatchString(s) && strings.ContainsAny(s, "0123456789") {
return true
}
}
return false
}💡 5. **internal/auth/middleware.go** (Lines 14-17) - REFACTORThese context keys are also defined in Suggested Code: Current Code: const (
ContextKeyActorType = "audit_actor_type"
ContextKeyActorID = "audit_actor_id"
ContextKeyActorName = "audit_actor_name"
ContextKeyAPIKeyPrefix = "audit_api_key_prefix"
)💡 6. **internal/dns/powerdns.go** (Lines 208-218) - REFACTORThe Consider implementing the SQLite schema creation directly within the Go code using Suggested Code: Current Code: func (m *PowerDNSManager) initializeDatabase(dataDir string) error {
dbPath := filepath.Join(dataDir, "pdns.sqlite3")
if _, err := os.Stat(dbPath); err == nil {
return nil
}
schema := `
PRAGMA foreign_keys = 1;
...
`
absDataDir, err := filepath.Abs(dataDir)
if err != nil {
return fmt.Errorf("failed to get absolute path: %w", err)
}
uid := fmt.Sprintf("%d", os.Getuid())
gid := fmt.Sprintf("%d", os.Getgid())
cmd := exec.Command("docker", "run", "--rm",
"-v", absDataDir+":/data",
"alpine:latest",
"sh", "-c", "apk add --no-cache sqlite > /dev/null 2>&1 && sqlite3 /data/pdns.sqlite3 \""+schema+"\" && chown "+uid+":"+gid+" /data/pdns.sqlite3")
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("database init failed: %s - %w", string(output), err)
}
return nil
}Verdict: APPROVE Posted as a comment because posting a review failed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review complete. See the overview comment for a summary.
|
Looks like there are a few issues preventing this PR from being merged!
If you'd like me to help, just leave a comment, like Feel free to include any additional details that might help me get this PR into a better state. You can manage your notification settings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review complete. See the overview comment for a summary.
Update Go version requirements to match go.mod which now requires Go 1.24.0. Signed-off-by: nfebe <fenn25.fn@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review complete. See the overview comment for a summary.
| for i := range b { | ||
| b[i] = charset[time.Now().UnixNano()%int64(len(charset))] | ||
| time.Sleep(time.Nanosecond) | ||
| b[i] = charset[int(b[i])%len(charset)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The createDatabaseService function is intended to create a Docker Compose service definition for a database. It currently assigns the DefaultProxyNetwork to this database service. This is likely incorrect; it should instead use the DefaultDatabaseNetwork from the configuration to ensure proper isolation and naming for database-specific networks.
| b[i] = charset[int(b[i])%len(charset)] | |
| networkName := s.config.Infrastructure.DefaultDatabaseNetwork |