ING-2050: Ensure user passwords - #389
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends user-management propagation checks by enabling EnsureUser to wait for a password change to propagate to all nodes, using the server-provided password_change_date as an opaque marker captured via UpsertUser.
Changes:
- Change
UpsertUserto return anUpsertUserResultcontaining a baselinePreviousPasswordChangedmarker when a password is updated. - Add
PasswordChangedMarkerand plumb an optionalSincePasswordChangedmarker throughEnsureUser/EnsureUserHelperto wait for propagation. - Add a dino-based integration test covering ensure semantics for create, password change, and delete.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| mgmtcomponent.go | Updates component UpsertUser signature and wires SincePasswordChanged into EnsureUser. |
| agent_ops.go | Updates Agent.UpsertUser signature to return UpsertUserResult. |
| cbmgmtx/mgmt.go | Implements pre-write probe for password_change_date, returns UpsertUserResult, and swaps UserJson.PasswordChanged to the marker type. |
| cbmgmtx/passwordchangedmarker.go | Introduces the opaque PasswordChangedMarker type and comparison logic. |
| cbmgmtx/ensureuserhelper.go | Adds optional propagation waiting by comparing password_change_date markers during polling. |
| cbmgmtx/ensureuserhelper_int_test.go | Adds a dino integration test for EnsureUser propagation behavior. |
| cbmgmtx/mgmt_int_test.go | Updates existing integration tests for new UpsertUser return signature. |
| cbauthx/cbauth_int_test.go | Updates integration tests for new UpsertUser return signature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
65203fc to
694d550
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Suppressed comments (2)
cbmgmtx/passwordchangedmarker.go:56
- NewPasswordChangedMarkerForTest is an exported, production-build symbol even though it is described as test-only, and it is currently unused in the repo. This weakens the stated goal of keeping PasswordChangedMarker opaque (production callers can construct arbitrary markers) and adds surface area to the public API.
// NewPasswordChangedMarkerForTest constructs a PasswordChangedMarker from an
// arbitrary time.Time. This exists only to support testing code that needs to
// fabricate markers, and must not be used to construct a marker from a
// caller's local clock in production code paths (use a value obtained from
// GetUser or UpsertUser instead).
func NewPasswordChangedMarkerForTest(t time.Time) PasswordChangedMarker {
return PasswordChangedMarker{t: t}
}
cbmgmtx/ensureuserhelper_int_test.go:162
- The test creates a user group but never deletes it. Unlike the other dino integration tests (bucket/manifest/index) which clean up resources, this can leave persistent RBAC groups behind on the cluster across runs and slowly pollute the test environment.
err := mgmt.UpsertUserGroup(ctx, &cbmgmtx.UpsertUserGroupOptions{
GroupName: testGroupName,
Roles: []string{"ro_admin"},
})
require.NoError(t, err)
d44610b to
7c98db9
Compare
|
@droid review |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (2)
cbmgmtx/mgmt.go:1387
- The comment on PreviousPasswordChanged overstates the guarantee: the marker is captured by a separate GetUser request before the PUT, so it is not necessarily the value from “immediately before this call took effect” under concurrent updates. Rewording avoids implying a stronger ordering guarantee than the API can provide.
// PreviousPasswordChanged holds the user's PasswordChangedMarker from
// immediately before this call took effect.
PreviousPasswordChanged *PasswordChangedMarker
cbmgmtx/ensureuserhelper_int_test.go:163
- This integration test creates a user group (testGroupName) but never deletes it, which can pollute a shared dino cluster and make repeated runs noisier over time. Add cleanup to remove the group after the test completes.
testGroupName := "testgroup-" + uuid.NewString()[:6]
err := mgmt.UpsertUserGroup(ctx, &cbmgmtx.UpsertUserGroupOptions{
GroupName: testGroupName,
Roles: []string{"ro_admin"},
})
| actualUserRoles = append(actualUserRoles, encodeRole(role.RoleJson)) | ||
| } | ||
|
|
||
| return stringSetsEqual(actualUserRoles, want) |
There was a problem hiding this comment.
It seems odd that we're string matching these? Would we be better translating the RoleJson and RoleWithOriginsJson into a proper type?
There was a problem hiding this comment.
Good point, if we got a malformed role then the string match would fail and we'd poll forever. I changed it so that we decode the string array into the appropriate JSON and compare that.
cf09045 to
7bfa486
Compare
Summary
Adds the ability for
EnsureUserto confirm a changes to existing user settings (password, roles or groups) have propagated to all nodes.Design notes
EnsureUseracceptsWantSettingsthat describe the desired groups and roles, as well asPasswordChangeda time that the User's password must have changed at or after for the EnsureUser call to return.PasswordChangedMarkeran opaque type that would prevent users passing any time into EnsureUser. After consideration the extra complexity was not worth the protection of giving an arbitrary time.