Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
104bf21
feat: add user_secrets table
evgeniy-scherbina Aug 4, 2025
b677273
feat: add SQL queries
evgeniy-scherbina Aug 4, 2025
a826dd3
feat: add DBAuthz wrappers and UserSecret resource type
evgeniy-scherbina Aug 5, 2025
540f2e2
feat: add DBAuthz tests
evgeniy-scherbina Aug 5, 2025
363173c
test: fix role-permissions test
evgeniy-scherbina Aug 5, 2025
e152648
test: fix migration test
evgeniy-scherbina Aug 5, 2025
49ac807
fix: change user-secret permissions
evgeniy-scherbina Aug 5, 2025
85b4f4c
fix: add unit-tests for sql queries
evgeniy-scherbina Aug 6, 2025
3f04a15
test: improve unit-tests for sql queries
evgeniy-scherbina Aug 6, 2025
d7605f6
refactor: use table-test approach for secrets-authz test
evgeniy-scherbina Aug 6, 2025
b55be78
refactor: minor refactor in tests
evgeniy-scherbina Aug 6, 2025
3090d52
fix: formatting
evgeniy-scherbina Aug 6, 2025
789a5eb
fix: formatting
evgeniy-scherbina Aug 6, 2025
12b6c2e
ci: run make gen and make fmt
evgeniy-scherbina Aug 6, 2025
317708b
refactor: CR's fixes
evgeniy-scherbina Aug 7, 2025
72faf7a
Update coderd/database/dbauthz/dbauthz.go
evgeniy-scherbina Aug 7, 2025
a715310
Update coderd/database/dbauthz/dbauthz.go
evgeniy-scherbina Aug 7, 2025
8ea3cda
refactor: CR's fixes
evgeniy-scherbina Aug 7, 2025
b21f07c
refactor: CR's fixes
evgeniy-scherbina Aug 7, 2025
0f47bae
refactor: CR's fixes
evgeniy-scherbina Aug 7, 2025
1d6f2fa
refactor: CR's fixes
evgeniy-scherbina Aug 7, 2025
b24599c
Merge remote-tracking branch 'origin/main' into yevhenii/secrets-db-s…
evgeniy-scherbina Aug 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: add DBAuthz tests
  • Loading branch information
evgeniy-scherbina committed Aug 5, 2025
commit 540f2e2e81d331257f10bd555c89d5b02b1335a7
70 changes: 35 additions & 35 deletions coderd/database/dbauthz/dbauthz.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,9 @@ func As(ctx context.Context, actor rbac.Subject) context.Context {
// running the insertFunc. The insertFunc is expected to return the object that
// was inserted.
func insert[
ObjectType any,
ArgumentType any,
Insert func(ctx context.Context, arg ArgumentType) (ObjectType, error),
ObjectType any,
ArgumentType any,
Insert func(ctx context.Context, arg ArgumentType) (ObjectType, error),
](
logger slog.Logger,
authorizer rbac.Authorizer,
Expand All @@ -625,9 +625,9 @@ Insert func(ctx context.Context, arg ArgumentType) (ObjectType, error),
}

func insertWithAction[
ObjectType any,
ArgumentType any,
Insert func(ctx context.Context, arg ArgumentType) (ObjectType, error),
ObjectType any,
ArgumentType any,
Insert func(ctx context.Context, arg ArgumentType) (ObjectType, error),
](
logger slog.Logger,
authorizer rbac.Authorizer,
Expand All @@ -654,10 +654,10 @@ Insert func(ctx context.Context, arg ArgumentType) (ObjectType, error),
}

func deleteQ[
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
Delete func(ctx context.Context, arg ArgumentType) error,
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
Delete func(ctx context.Context, arg ArgumentType) error,
](
logger slog.Logger,
authorizer rbac.Authorizer,
Expand All @@ -669,10 +669,10 @@ Delete func(ctx context.Context, arg ArgumentType) error,
}

func updateWithReturn[
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
UpdateQuery func(ctx context.Context, arg ArgumentType) (ObjectType, error),
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
UpdateQuery func(ctx context.Context, arg ArgumentType) (ObjectType, error),
](
logger slog.Logger,
authorizer rbac.Authorizer,
Expand All @@ -683,10 +683,10 @@ UpdateQuery func(ctx context.Context, arg ArgumentType) (ObjectType, error),
}

func update[
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
Exec func(ctx context.Context, arg ArgumentType) error,
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
Exec func(ctx context.Context, arg ArgumentType) error,
](
logger slog.Logger,
authorizer rbac.Authorizer,
Expand All @@ -704,9 +704,9 @@ Exec func(ctx context.Context, arg ArgumentType) error,
// user cannot read the resource. This is because the resource details are
// required to run a proper authorization check.
func fetchWithAction[
ArgumentType any,
ObjectType rbac.Objecter,
DatabaseFunc func(ctx context.Context, arg ArgumentType) (ObjectType, error),
ArgumentType any,
ObjectType rbac.Objecter,
DatabaseFunc func(ctx context.Context, arg ArgumentType) (ObjectType, error),
](
logger slog.Logger,
authorizer rbac.Authorizer,
Expand Down Expand Up @@ -737,9 +737,9 @@ DatabaseFunc func(ctx context.Context, arg ArgumentType) (ObjectType, error),
}

func fetch[
ArgumentType any,
ObjectType rbac.Objecter,
DatabaseFunc func(ctx context.Context, arg ArgumentType) (ObjectType, error),
ArgumentType any,
ObjectType rbac.Objecter,
DatabaseFunc func(ctx context.Context, arg ArgumentType) (ObjectType, error),
](
logger slog.Logger,
authorizer rbac.Authorizer,
Expand All @@ -752,10 +752,10 @@ DatabaseFunc func(ctx context.Context, arg ArgumentType) (ObjectType, error),
// from SQL 'exec' functions which only return an error.
// See fetchAndQuery for more information.
func fetchAndExec[
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
Exec func(ctx context.Context, arg ArgumentType) error,
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
Exec func(ctx context.Context, arg ArgumentType) error,
](
logger slog.Logger,
authorizer rbac.Authorizer,
Expand All @@ -778,10 +778,10 @@ Exec func(ctx context.Context, arg ArgumentType) error,
// **before** the query runs. The returns from the fetch are only used to
// assert rbac. The final return of this function comes from the Query function.
func fetchAndQuery[
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
Query func(ctx context.Context, arg ArgumentType) (ObjectType, error),
ObjectType rbac.Objecter,
ArgumentType any,
Fetch func(ctx context.Context, arg ArgumentType) (ObjectType, error),
Query func(ctx context.Context, arg ArgumentType) (ObjectType, error),
](
logger slog.Logger,
authorizer rbac.Authorizer,
Expand Down Expand Up @@ -815,9 +815,9 @@ Query func(ctx context.Context, arg ArgumentType) (ObjectType, error),
// fetchWithPostFilter is like fetch, but works with lists of objects.
// SQL filters are much more optimal.
func fetchWithPostFilter[
ArgumentType any,
ObjectType rbac.Objecter,
DatabaseFunc func(ctx context.Context, arg ArgumentType) ([]ObjectType, error),
ArgumentType any,
ObjectType rbac.Objecter,
DatabaseFunc func(ctx context.Context, arg ArgumentType) ([]ObjectType, error),
](
authorizer rbac.Authorizer,
action policy.Action,
Expand Down
61 changes: 61 additions & 0 deletions coderd/database/dbauthz/dbauthz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5877,3 +5877,64 @@ func (s *MethodTestSuite) TestAuthorizePrebuiltWorkspace() {
}).Asserts(w, policy.ActionUpdate, w.AsPrebuild(), policy.ActionUpdate)
}))
}

func (s *MethodTestSuite) TestUserSecrets() {
s.Run("GetUserSecretByUserIDAndName", s.Subtest(func(db database.Store, check *expects) {
user := dbgen.User(s.T(), db, database.User{})
userSecret := dbgen.UserSecret(s.T(), db, database.CreateUserSecretParams{
UserID: user.ID,
})
arg := database.GetUserSecretByUserIDAndNameParams{
UserID: user.ID,
Name: userSecret.Name,
}
check.Args(arg).
Asserts(rbac.ResourceUserSecret.WithOwner(arg.UserID.String()), policy.ActionRead).
Returns(userSecret)
}))
s.Run("GetUserSecret", s.Subtest(func(db database.Store, check *expects) {
user := dbgen.User(s.T(), db, database.User{})
userSecret := dbgen.UserSecret(s.T(), db, database.CreateUserSecretParams{
UserID: user.ID,
})
check.Args(userSecret.ID).
Asserts(rbac.ResourceUserSecret.WithOwner(user.ID.String()), policy.ActionRead).
Returns(userSecret)
}))
s.Run("ListUserSecrets", s.Subtest(func(db database.Store, check *expects) {
user := dbgen.User(s.T(), db, database.User{})
userSecret := dbgen.UserSecret(s.T(), db, database.CreateUserSecretParams{
UserID: user.ID,
})
check.Args(user.ID).
Asserts(rbac.ResourceUserSecret.WithOwner(user.ID.String()), policy.ActionRead).
Returns([]database.UserSecret{userSecret})
}))
s.Run("CreateUserSecret", s.Subtest(func(db database.Store, check *expects) {
user := dbgen.User(s.T(), db, database.User{})
arg := database.CreateUserSecretParams{
UserID: user.ID,
}
check.Args(arg).
Asserts(rbac.ResourceUserSecret.WithOwner(arg.UserID.String()), policy.ActionCreate)
}))
s.Run("UpdateUserSecret", s.Subtest(func(db database.Store, check *expects) {
user := dbgen.User(s.T(), db, database.User{})
userSecret := dbgen.UserSecret(s.T(), db, database.CreateUserSecretParams{
UserID: user.ID,
})
arg := database.UpdateUserSecretParams{
ID: userSecret.ID,
}
check.Args(arg).
Asserts(rbac.ResourceUserSecret.WithOwner(user.ID.String()), policy.ActionUpdate)
}))
s.Run("DeleteUserSecret", s.Subtest(func(db database.Store, check *expects) {
user := dbgen.User(s.T(), db, database.User{})
userSecret := dbgen.UserSecret(s.T(), db, database.CreateUserSecretParams{
UserID: user.ID,
})
check.Args(userSecret.ID).
Asserts(rbac.ResourceUserSecret.WithOwner(user.ID.String()), policy.ActionDelete)
}))
}
14 changes: 14 additions & 0 deletions coderd/database/dbgen/dbgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -1422,6 +1422,20 @@ func PresetParameter(t testing.TB, db database.Store, seed database.InsertPreset
return parameters
}

func UserSecret(t testing.TB, db database.Store, seed database.CreateUserSecretParams) database.UserSecret {
userSecret, err := db.CreateUserSecret(genCtx, database.CreateUserSecretParams{
ID: takeFirst(seed.ID, uuid.New()),
UserID: takeFirst(seed.UserID, uuid.New()),
Name: takeFirst(seed.Name, "secret-name"),
Description: takeFirst(seed.Description, "secret description"),
Value: takeFirst(seed.Value, "secret value"),
EnvName: takeFirst(seed.EnvName, "SECRET_ENV_NAME"),
FilePath: takeFirst(seed.FilePath, "~/secret/file/path"),
})
require.NoError(t, err, "failed to insert user secret")
return userSecret
}

func ClaimPrebuild(t testing.TB, db database.Store, newUserID uuid.UUID, newName string, presetID uuid.UUID) database.ClaimPrebuiltWorkspaceRow {
claimedWorkspace, err := db.ClaimPrebuiltWorkspace(genCtx, database.ClaimPrebuiltWorkspaceParams{
NewUserID: newUserID,
Expand Down
5 changes: 4 additions & 1 deletion coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion coderd/database/queries/user_secrets.sql
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ ORDER BY name ASC;

-- name: CreateUserSecret :one
INSERT INTO user_secrets (
id,
user_id,
name,
description,
value,
env_name,
file_path
) VALUES (
$1, $2, $3, $4, $5, $6
$1, $2, $3, $4, $5, $6, $7
) RETURNING *;

-- name: UpdateUserSecret :one
Expand Down
Loading