- Notifications
You must be signed in to change notification settings - Fork1k
feat: add support for workspace app audit#16801
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
d235001
b18740c
4dfb4fb
7d7922c
19ca904
30bb732
94ddbbe
bef7614
d13d3c0
9a3a4c8
1f4e95b
bda2d12
93784b9
e38ba0f
5f0c141
ae06fe4
cf1180e
623ad6f
c91024e
9608da1
5bb42c2
14a1740
4426bcf
2c1536e
c070d74
8a61541
7279b9a
4ff41d4
c723b95
217a0d3
336c7b8
8d7a763
0f162b1
22ea58c
119cf03
16ae577
9003ae0
c1ae295
1ee8441
5b3b122
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -282,10 +282,14 @@ func auditLogDescription(alog database.GetAuditLogsOffsetRow) string { | ||
_, _ = b.WriteString("{user} ") | ||
} | ||
switch { | ||
case alog.AuditLog.StatusCode == int32(http.StatusSeeOther): | ||
_, _ = b.WriteString("was redirected attempting to ") | ||
_, _ = b.WriteString(string(alog.AuditLog.Action)) | ||
case alog.AuditLog.StatusCode >= 400: | ||
_, _ = b.WriteString("unsuccessfully attempted to ") | ||
_, _ = b.WriteString(string(alog.AuditLog.Action)) | ||
default: | ||
Comment on lines +285 to +292 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. 👍 | ||
_, _ = b.WriteString(codersdk.AuditAction(alog.AuditLog.Action).Friendly()) | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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.OrganizationID != expected.OrganizationID { | ||
johnstcn marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
t.Logf("audit log %d: expected OrganizationID %s, got %s", idx+1, expected.OrganizationID, al.OrganizationID) | ||
continue | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
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) | ||
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{Valid: p.UserAgent != "", String: p.UserAgent}, | ||
mafredri marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
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") | ||
} | ||
funcParseIP(ipStr string) pqtype.Inet { | ||
ip := net.ParseIP(ipStr) | ||
ipNet := net.IPNet{} | ||
if ip != nil { | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -226,6 +226,10 @@ type Options struct { | ||
UpdateAgentMetrics func(ctx context.Context, labels prometheusmetrics.AgentMetricLabels, metrics []*agentproto.Stats_Metric) | ||
StatsBatcher workspacestats.Batcher | ||
// WorkspaceAppAuditSessionTimeout allows changing the timeout for audit | ||
// sessions. Raising or lowering this value will directly affect the write | ||
// load of the audit log table. This is used for testing. Default 1 hour. | ||
WorkspaceAppAuditSessionTimeout time.Duration | ||
mafredri marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
WorkspaceAppsStatsCollectorOptions workspaceapps.StatsCollectorOptions | ||
// This janky function is used in telemetry to parse fields out of the raw | ||
@@ -534,16 +538,6 @@ func New(options *Options) *API { | ||
Authorizer: options.Authorizer, | ||
Logger: options.Logger, | ||
}, | ||
metricsCache: metricsCache, | ||
Auditor: atomic.Pointer[audit.Auditor]{}, | ||
TailnetCoordinator: atomic.Pointer[tailnet.Coordinator]{}, | ||
@@ -561,6 +555,18 @@ func New(options *Options) *API { | ||
), | ||
dbRolluper: options.DatabaseRolluper, | ||
} | ||
api.WorkspaceAppsProvider = workspaceapps.NewDBTokenProvider( | ||
options.Logger.Named("workspaceapps"), | ||
options.AccessURL, | ||
options.Authorizer, | ||
&api.Auditor, | ||
options.Database, | ||
options.DeploymentValues, | ||
oauthConfigs, | ||
options.AgentInactiveDisconnectTimeout, | ||
options.WorkspaceAppAuditSessionTimeout, | ||
options.AppSigningKeyCache, | ||
) | ||
f := appearance.NewDefaultFetcher(api.DeploymentValues.DocsURL.String()) | ||
api.AppearanceFetcher.Store(&f) | ||
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.
Uh oh!
There was an error while loading.Please reload this page.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
DROP TABLE workspace_app_audit_sessions; |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.