mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add support for workspace app audit (#16801)
This change adds support for workspace app auditing. To avoid audit log spam, we introduce the concept of app audit sessions. An audit session is unique per workspace app, user, ip, user agent and http status code. The sessions are stored in a separate table from audit logs to allow use-case specific optimizations. Sessions are ephemeral and the table does not function as a log. The logic for auditing is placed in the DBTokenProvider for workspace apps so that wsproxies are included. This is the final change affecting the API fo #15139. Updates #15139
This commit is contained in:
@@ -93,7 +93,7 @@ func (a *MockAuditor) Contains(t testing.TB, expected database.AuditLog) bool {
|
||||
t.Logf("audit log %d: expected UserID %s, got %s", idx+1, expected.UserID, al.UserID)
|
||||
continue
|
||||
}
|
||||
if expected.OrganizationID != uuid.Nil && al.UserID != expected.UserID {
|
||||
if expected.OrganizationID != uuid.Nil && al.OrganizationID != expected.OrganizationID {
|
||||
t.Logf("audit log %d: expected OrganizationID %s, got %s", idx+1, expected.OrganizationID, al.OrganizationID)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ type BackgroundAuditParams[T Auditable] struct {
|
||||
Action database.AuditAction
|
||||
OrganizationID uuid.UUID
|
||||
IP string
|
||||
UserAgent string
|
||||
// todo: this should automatically marshal an interface{} instead of accepting a raw message.
|
||||
AdditionalFields json.RawMessage
|
||||
|
||||
@@ -422,7 +423,7 @@ func InitRequest[T Auditable](w http.ResponseWriter, p *RequestParams) (*Request
|
||||
action = req.Action
|
||||
}
|
||||
|
||||
ip := parseIP(p.Request.RemoteAddr)
|
||||
ip := ParseIP(p.Request.RemoteAddr)
|
||||
auditLog := database.AuditLog{
|
||||
ID: uuid.New(),
|
||||
Time: dbtime.Now(),
|
||||
@@ -453,7 +454,7 @@ func InitRequest[T Auditable](w http.ResponseWriter, p *RequestParams) (*Request
|
||||
// BackgroundAudit creates an audit log for a background event.
|
||||
// The audit log is committed upon invocation.
|
||||
func BackgroundAudit[T Auditable](ctx context.Context, p *BackgroundAuditParams[T]) {
|
||||
ip := parseIP(p.IP)
|
||||
ip := ParseIP(p.IP)
|
||||
|
||||
diff := Diff(p.Audit, p.Old, p.New)
|
||||
var err error
|
||||
@@ -479,7 +480,7 @@ func BackgroundAudit[T Auditable](ctx context.Context, p *BackgroundAuditParams[
|
||||
UserID: p.UserID,
|
||||
OrganizationID: requireOrgID[T](ctx, p.OrganizationID, p.Log),
|
||||
Ip: ip,
|
||||
UserAgent: sql.NullString{},
|
||||
UserAgent: sql.NullString{Valid: p.UserAgent != "", String: p.UserAgent},
|
||||
ResourceType: either(p.Old, p.New, ResourceType[T], p.Action),
|
||||
ResourceID: either(p.Old, p.New, ResourceID[T], p.Action),
|
||||
ResourceTarget: either(p.Old, p.New, ResourceTarget[T], p.Action),
|
||||
@@ -566,7 +567,7 @@ func either[T Auditable, R any](old, new T, fn func(T) R, auditAction database.A
|
||||
panic("both old and new are nil")
|
||||
}
|
||||
|
||||
func parseIP(ipStr string) pqtype.Inet {
|
||||
func ParseIP(ipStr string) pqtype.Inet {
|
||||
ip := net.ParseIP(ipStr)
|
||||
ipNet := net.IPNet{}
|
||||
if ip != nil {
|
||||
|
||||
Reference in New Issue
Block a user