mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: show audit logs for forgot password flow (#15181)
Fixes https://github.com/coder/coder/issues/15150 Audit logs for requesting a password reset, and a user updating their password, now show up in the audit log.
This commit is contained in:
Generated
+4
-2
@@ -9116,7 +9116,8 @@ const docTemplate = `{
|
|||||||
"stop",
|
"stop",
|
||||||
"login",
|
"login",
|
||||||
"logout",
|
"logout",
|
||||||
"register"
|
"register",
|
||||||
|
"request_password_reset"
|
||||||
],
|
],
|
||||||
"x-enum-varnames": [
|
"x-enum-varnames": [
|
||||||
"AuditActionCreate",
|
"AuditActionCreate",
|
||||||
@@ -9126,7 +9127,8 @@ const docTemplate = `{
|
|||||||
"AuditActionStop",
|
"AuditActionStop",
|
||||||
"AuditActionLogin",
|
"AuditActionLogin",
|
||||||
"AuditActionLogout",
|
"AuditActionLogout",
|
||||||
"AuditActionRegister"
|
"AuditActionRegister",
|
||||||
|
"AuditActionRequestPasswordReset"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"codersdk.AuditDiff": {
|
"codersdk.AuditDiff": {
|
||||||
|
|||||||
Generated
+4
-2
@@ -8090,7 +8090,8 @@
|
|||||||
"stop",
|
"stop",
|
||||||
"login",
|
"login",
|
||||||
"logout",
|
"logout",
|
||||||
"register"
|
"register",
|
||||||
|
"request_password_reset"
|
||||||
],
|
],
|
||||||
"x-enum-varnames": [
|
"x-enum-varnames": [
|
||||||
"AuditActionCreate",
|
"AuditActionCreate",
|
||||||
@@ -8100,7 +8101,8 @@
|
|||||||
"AuditActionStop",
|
"AuditActionStop",
|
||||||
"AuditActionLogin",
|
"AuditActionLogin",
|
||||||
"AuditActionLogout",
|
"AuditActionLogout",
|
||||||
"AuditActionRegister"
|
"AuditActionRegister",
|
||||||
|
"AuditActionRequestPasswordReset"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"codersdk.AuditDiff": {
|
"codersdk.AuditDiff": {
|
||||||
|
|||||||
+14
-3
@@ -274,8 +274,15 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
|
|||||||
|
|
||||||
func auditLogDescription(alog database.GetAuditLogsOffsetRow) string {
|
func auditLogDescription(alog database.GetAuditLogsOffsetRow) string {
|
||||||
b := strings.Builder{}
|
b := strings.Builder{}
|
||||||
|
|
||||||
// NOTE: WriteString always returns a nil error, so we never check it
|
// NOTE: WriteString always returns a nil error, so we never check it
|
||||||
_, _ = b.WriteString("{user} ")
|
|
||||||
|
// Requesting a password reset can be performed by anyone that knows the email
|
||||||
|
// of a user so saying the user performed this action might be slightly misleading.
|
||||||
|
if alog.AuditLog.Action != database.AuditActionRequestPasswordReset {
|
||||||
|
_, _ = b.WriteString("{user} ")
|
||||||
|
}
|
||||||
|
|
||||||
if alog.AuditLog.StatusCode >= 400 {
|
if alog.AuditLog.StatusCode >= 400 {
|
||||||
_, _ = b.WriteString("unsuccessfully attempted to ")
|
_, _ = b.WriteString("unsuccessfully attempted to ")
|
||||||
_, _ = b.WriteString(string(alog.AuditLog.Action))
|
_, _ = b.WriteString(string(alog.AuditLog.Action))
|
||||||
@@ -298,8 +305,12 @@ func auditLogDescription(alog database.GetAuditLogsOffsetRow) string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = b.WriteString(" ")
|
if alog.AuditLog.Action == database.AuditActionRequestPasswordReset {
|
||||||
_, _ = b.WriteString(codersdk.ResourceType(alog.AuditLog.ResourceType).FriendlyString())
|
_, _ = b.WriteString(" for")
|
||||||
|
} else {
|
||||||
|
_, _ = b.WriteString(" ")
|
||||||
|
_, _ = b.WriteString(codersdk.ResourceType(alog.AuditLog.ResourceType).FriendlyString())
|
||||||
|
}
|
||||||
|
|
||||||
if alog.AuditLog.ResourceType == database.ResourceTypeConvertLogin {
|
if alog.AuditLog.ResourceType == database.ResourceTypeConvertLogin {
|
||||||
_, _ = b.WriteString(" to")
|
_, _ = b.WriteString(" to")
|
||||||
|
|||||||
Generated
+2
-1
@@ -19,7 +19,8 @@ CREATE TYPE audit_action AS ENUM (
|
|||||||
'stop',
|
'stop',
|
||||||
'login',
|
'login',
|
||||||
'logout',
|
'logout',
|
||||||
'register'
|
'register',
|
||||||
|
'request_password_reset'
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TYPE automatic_updates AS ENUM (
|
CREATE TYPE automatic_updates AS ENUM (
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- It's not possible to drop enum values from enum types, so the UP has "IF NOT
|
||||||
|
-- EXISTS".
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TYPE audit_action
|
||||||
|
ADD VALUE IF NOT EXISTS 'request_password_reset';
|
||||||
@@ -138,14 +138,15 @@ func AllAppSharingLevelValues() []AppSharingLevel {
|
|||||||
type AuditAction string
|
type AuditAction string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AuditActionCreate AuditAction = "create"
|
AuditActionCreate AuditAction = "create"
|
||||||
AuditActionWrite AuditAction = "write"
|
AuditActionWrite AuditAction = "write"
|
||||||
AuditActionDelete AuditAction = "delete"
|
AuditActionDelete AuditAction = "delete"
|
||||||
AuditActionStart AuditAction = "start"
|
AuditActionStart AuditAction = "start"
|
||||||
AuditActionStop AuditAction = "stop"
|
AuditActionStop AuditAction = "stop"
|
||||||
AuditActionLogin AuditAction = "login"
|
AuditActionLogin AuditAction = "login"
|
||||||
AuditActionLogout AuditAction = "logout"
|
AuditActionLogout AuditAction = "logout"
|
||||||
AuditActionRegister AuditAction = "register"
|
AuditActionRegister AuditAction = "register"
|
||||||
|
AuditActionRequestPasswordReset AuditAction = "request_password_reset"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *AuditAction) Scan(src interface{}) error {
|
func (e *AuditAction) Scan(src interface{}) error {
|
||||||
@@ -192,7 +193,8 @@ func (e AuditAction) Valid() bool {
|
|||||||
AuditActionStop,
|
AuditActionStop,
|
||||||
AuditActionLogin,
|
AuditActionLogin,
|
||||||
AuditActionLogout,
|
AuditActionLogout,
|
||||||
AuditActionRegister:
|
AuditActionRegister,
|
||||||
|
AuditActionRequestPasswordReset:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -208,6 +210,7 @@ func AllAuditActionValues() []AuditAction {
|
|||||||
AuditActionLogin,
|
AuditActionLogin,
|
||||||
AuditActionLogout,
|
AuditActionLogout,
|
||||||
AuditActionRegister,
|
AuditActionRegister,
|
||||||
|
AuditActionRequestPasswordReset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -220,7 +220,7 @@ func (api *API) postRequestOneTimePasscode(rw http.ResponseWriter, r *http.Reque
|
|||||||
Audit: *auditor,
|
Audit: *auditor,
|
||||||
Log: api.Logger,
|
Log: api.Logger,
|
||||||
Request: r,
|
Request: r,
|
||||||
Action: database.AuditActionWrite,
|
Action: database.AuditActionRequestPasswordReset,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
defer commitAudit()
|
defer commitAudit()
|
||||||
@@ -253,6 +253,7 @@ func (api *API) postRequestOneTimePasscode(rw http.ResponseWriter, r *http.Reque
|
|||||||
}
|
}
|
||||||
// We continue if err == sql.ErrNoRows to help prevent a timing-based attack.
|
// We continue if err == sql.ErrNoRows to help prevent a timing-based attack.
|
||||||
aReq.Old = user
|
aReq.Old = user
|
||||||
|
aReq.UserID = user.ID
|
||||||
|
|
||||||
passcode := uuid.New()
|
passcode := uuid.New()
|
||||||
passcodeExpiresAt := dbtime.Now().Add(api.OneTimePasscodeValidityPeriod)
|
passcodeExpiresAt := dbtime.Now().Add(api.OneTimePasscodeValidityPeriod)
|
||||||
@@ -365,6 +366,7 @@ func (api *API) postChangePasswordWithOneTimePasscode(rw http.ResponseWriter, r
|
|||||||
}
|
}
|
||||||
// We continue if err == sql.ErrNoRows to help prevent a timing-based attack.
|
// We continue if err == sql.ErrNoRows to help prevent a timing-based attack.
|
||||||
aReq.Old = user
|
aReq.Old = user
|
||||||
|
aReq.UserID = user.ID
|
||||||
|
|
||||||
equal, err := userpassword.Compare(string(user.HashedOneTimePasscode), req.OneTimePasscode)
|
equal, err := userpassword.Compare(string(user.HashedOneTimePasscode), req.OneTimePasscode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+11
-8
@@ -86,14 +86,15 @@ func (r ResourceType) FriendlyString() string {
|
|||||||
type AuditAction string
|
type AuditAction string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AuditActionCreate AuditAction = "create"
|
AuditActionCreate AuditAction = "create"
|
||||||
AuditActionWrite AuditAction = "write"
|
AuditActionWrite AuditAction = "write"
|
||||||
AuditActionDelete AuditAction = "delete"
|
AuditActionDelete AuditAction = "delete"
|
||||||
AuditActionStart AuditAction = "start"
|
AuditActionStart AuditAction = "start"
|
||||||
AuditActionStop AuditAction = "stop"
|
AuditActionStop AuditAction = "stop"
|
||||||
AuditActionLogin AuditAction = "login"
|
AuditActionLogin AuditAction = "login"
|
||||||
AuditActionLogout AuditAction = "logout"
|
AuditActionLogout AuditAction = "logout"
|
||||||
AuditActionRegister AuditAction = "register"
|
AuditActionRegister AuditAction = "register"
|
||||||
|
AuditActionRequestPasswordReset AuditAction = "request_password_reset"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a AuditAction) Friendly() string {
|
func (a AuditAction) Friendly() string {
|
||||||
@@ -114,6 +115,8 @@ func (a AuditAction) Friendly() string {
|
|||||||
return "logged out"
|
return "logged out"
|
||||||
case AuditActionRegister:
|
case AuditActionRegister:
|
||||||
return "registered"
|
return "registered"
|
||||||
|
case AuditActionRequestPasswordReset:
|
||||||
|
return "password reset requested"
|
||||||
default:
|
default:
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ We track the following resources:
|
|||||||
| Organization<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_default</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr></tbody></table> |
|
| Organization<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_default</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr></tbody></table> |
|
||||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||||
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>true</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>must_reset_password</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>theme_preference</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>must_reset_password</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>theme_preference</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||||
| Workspace<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
| Workspace<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||||
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
|
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>provisioner_state</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
|
||||||
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody><tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
||||||
|
|||||||
Generated
+11
-10
@@ -513,16 +513,17 @@
|
|||||||
|
|
||||||
#### Enumerated Values
|
#### Enumerated Values
|
||||||
|
|
||||||
| Value |
|
| Value |
|
||||||
| ---------- |
|
| ------------------------ |
|
||||||
| `create` |
|
| `create` |
|
||||||
| `write` |
|
| `write` |
|
||||||
| `delete` |
|
| `delete` |
|
||||||
| `start` |
|
| `start` |
|
||||||
| `stop` |
|
| `stop` |
|
||||||
| `login` |
|
| `login` |
|
||||||
| `logout` |
|
| `logout` |
|
||||||
| `register` |
|
| `register` |
|
||||||
|
| `request_password_reset` |
|
||||||
|
|
||||||
## codersdk.AuditDiff
|
## codersdk.AuditDiff
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ var auditableResourcesTypes = map[any]map[string]Action{
|
|||||||
"theme_preference": ActionIgnore,
|
"theme_preference": ActionIgnore,
|
||||||
"name": ActionTrack,
|
"name": ActionTrack,
|
||||||
"github_com_user_id": ActionIgnore,
|
"github_com_user_id": ActionIgnore,
|
||||||
"hashed_one_time_passcode": ActionSecret, // Do not expose a user's one time passcode.
|
"hashed_one_time_passcode": ActionIgnore,
|
||||||
"one_time_passcode_expires_at": ActionTrack,
|
"one_time_passcode_expires_at": ActionTrack,
|
||||||
"must_reset_password": ActionTrack,
|
"must_reset_password": ActionTrack,
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+2
-2
@@ -2098,8 +2098,8 @@ export type AgentSubsystem = "envbox" | "envbuilder" | "exectrace"
|
|||||||
export const AgentSubsystems: AgentSubsystem[] = ["envbox", "envbuilder", "exectrace"]
|
export const AgentSubsystems: AgentSubsystem[] = ["envbox", "envbuilder", "exectrace"]
|
||||||
|
|
||||||
// From codersdk/audit.go
|
// From codersdk/audit.go
|
||||||
export type AuditAction = "create" | "delete" | "login" | "logout" | "register" | "start" | "stop" | "write"
|
export type AuditAction = "create" | "delete" | "login" | "logout" | "register" | "request_password_reset" | "start" | "stop" | "write"
|
||||||
export const AuditActions: AuditAction[] = ["create", "delete", "login", "logout", "register", "start", "stop", "write"]
|
export const AuditActions: AuditAction[] = ["create", "delete", "login", "logout", "register", "request_password_reset", "start", "stop", "write"]
|
||||||
|
|
||||||
// From codersdk/workspaces.go
|
// From codersdk/workspaces.go
|
||||||
export type AutomaticUpdates = "always" | "never"
|
export type AutomaticUpdates = "always" | "never"
|
||||||
|
|||||||
+7
@@ -1,6 +1,7 @@
|
|||||||
import type { Meta, StoryObj } from "@storybook/react";
|
import type { Meta, StoryObj } from "@storybook/react";
|
||||||
import {
|
import {
|
||||||
MockAuditLog,
|
MockAuditLog,
|
||||||
|
MockAuditLogRequestPasswordReset,
|
||||||
MockAuditLogSuccessfulLogin,
|
MockAuditLogSuccessfulLogin,
|
||||||
MockAuditLogUnsuccessfulLoginKnownUser,
|
MockAuditLogUnsuccessfulLoginKnownUser,
|
||||||
MockAuditLogWithWorkspaceBuild,
|
MockAuditLogWithWorkspaceBuild,
|
||||||
@@ -57,6 +58,12 @@ export const UnsuccessfulLoginForUnknownUser: Story = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const RequestPasswordReset: Story = {
|
||||||
|
args: {
|
||||||
|
auditLog: MockAuditLogRequestPasswordReset,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const CreateUser: Story = {
|
export const CreateUser: Story = {
|
||||||
args: {
|
args: {
|
||||||
auditLog: {
|
auditLog: {
|
||||||
|
|||||||
@@ -9,6 +9,14 @@ const getDiffValue = (value: unknown): string => {
|
|||||||
return `"${value}"`;
|
return `"${value}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isTimeObject(value)) {
|
||||||
|
if (!value.Valid) {
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Date(value.Time).toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
const values = value.map((v) => getDiffValue(v));
|
const values = value.map((v) => getDiffValue(v));
|
||||||
return `[${values.join(", ")}]`;
|
return `[${values.join(", ")}]`;
|
||||||
@@ -21,6 +29,19 @@ const getDiffValue = (value: unknown): string => {
|
|||||||
return String(value);
|
return String(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isTimeObject = (
|
||||||
|
value: unknown,
|
||||||
|
): value is { Time: string; Valid: boolean } => {
|
||||||
|
return (
|
||||||
|
value !== null &&
|
||||||
|
typeof value === "object" &&
|
||||||
|
"Time" in value &&
|
||||||
|
typeof value.Time === "string" &&
|
||||||
|
"Valid" in value &&
|
||||||
|
typeof value.Valid === "boolean"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
interface AuditLogDiffProps {
|
interface AuditLogDiffProps {
|
||||||
diff: AuditDiff;
|
diff: AuditDiff;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
MockAuditLog,
|
MockAuditLog,
|
||||||
MockAuditLog2,
|
MockAuditLog2,
|
||||||
MockAuditLogGitSSH,
|
MockAuditLogGitSSH,
|
||||||
|
MockAuditLogRequestPasswordReset,
|
||||||
MockAuditLogWithDeletedResource,
|
MockAuditLogWithDeletedResource,
|
||||||
MockAuditLogWithWorkspaceBuild,
|
MockAuditLogWithWorkspaceBuild,
|
||||||
MockUser,
|
MockUser,
|
||||||
@@ -122,6 +123,12 @@ export const WithOrganization: Story = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const WithDateDiffValue: Story = {
|
||||||
|
args: {
|
||||||
|
auditLog: MockAuditLogRequestPasswordReset,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const NoUserAgent: Story = {
|
export const NoUserAgent: Story = {
|
||||||
args: {
|
args: {
|
||||||
auditLog: {
|
auditLog: {
|
||||||
|
|||||||
@@ -2600,6 +2600,32 @@ export const MockAuditLogUnsuccessfulLoginKnownUser: TypesGen.AuditLog = {
|
|||||||
status_code: 401,
|
status_code: 401,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const MockAuditLogRequestPasswordReset: TypesGen.AuditLog = {
|
||||||
|
...MockAuditLog,
|
||||||
|
resource_type: "user",
|
||||||
|
resource_target: "member",
|
||||||
|
action: "request_password_reset",
|
||||||
|
description: "password reset requested for {target}",
|
||||||
|
diff: {
|
||||||
|
hashed_password: {
|
||||||
|
old: "",
|
||||||
|
new: "",
|
||||||
|
secret: true,
|
||||||
|
},
|
||||||
|
one_time_passcode_expires_at: {
|
||||||
|
old: {
|
||||||
|
Time: "0001-01-01T00:00:00Z",
|
||||||
|
Valid: false,
|
||||||
|
},
|
||||||
|
new: {
|
||||||
|
Time: "2024-10-22T09:03:23.961702Z",
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
secret: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const MockWorkspaceQuota: TypesGen.WorkspaceQuota = {
|
export const MockWorkspaceQuota: TypesGen.WorkspaceQuota = {
|
||||||
credits_consumed: 0,
|
credits_consumed: 0,
|
||||||
budget: 100,
|
budget: 100,
|
||||||
|
|||||||
Reference in New Issue
Block a user