mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
56 lines
1.4 KiB
Go
56 lines
1.4 KiB
Go
package audit
|
|
|
|
import (
|
|
"context"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/coderd/database"
|
|
)
|
|
|
|
// Backends can store or send audit logs to arbitrary locations.
|
|
type Backend interface {
|
|
// Decision determines the FilterDecisions that the backend tolerates.
|
|
Decision() FilterDecision
|
|
// Export sends an audit log to the backend.
|
|
Export(ctx context.Context, alog database.AuditLog) error
|
|
}
|
|
|
|
// Exporter exports audit logs to an arbitrary list of backends.
|
|
type Exporter struct {
|
|
filter Filter
|
|
backends []Backend
|
|
}
|
|
|
|
// NewExporter creates an exporter from the given filter and backends.
|
|
func NewExporter(filter Filter, backends ...Backend) *Exporter {
|
|
return &Exporter{
|
|
filter: filter,
|
|
backends: backends,
|
|
}
|
|
}
|
|
|
|
// Export exports and audit log. Before exporting to a backend, it uses the
|
|
// filter to determine if the backend tolerates the audit log. If not, it is
|
|
// dropped.
|
|
func (e *Exporter) Export(ctx context.Context, alog database.AuditLog) error {
|
|
decision, err := e.filter.Check(ctx, alog)
|
|
if err != nil {
|
|
return xerrors.Errorf("filter check: %w", err)
|
|
}
|
|
|
|
for _, backend := range e.backends {
|
|
if decision&backend.Decision() != backend.Decision() {
|
|
continue
|
|
}
|
|
|
|
err = backend.Export(ctx, alog)
|
|
if err != nil {
|
|
// naively return the first error. should probably make this smarter
|
|
// by returning multiple errors.
|
|
return xerrors.Errorf("export audit log to backend: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|