-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy pathuser_secrets.sql
More file actions
135 lines (127 loc) · 5.04 KB
/
Copy pathuser_secrets.sql
File metadata and controls
135 lines (127 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
-- name: GetUserSecretByUserIDAndName :one
SELECT *
FROM user_secrets
WHERE user_id = @user_id AND name = @name;
-- name: GetUserSecretByID :one
SELECT *
FROM user_secrets
WHERE id = @id;
-- name: GetUserSecretByUserIDAndNameForUpdate :one
SELECT *
FROM user_secrets
WHERE user_id = @user_id AND name = @name
FOR UPDATE;
-- name: ListUserSecrets :many
-- Returns metadata only (no value or value_key_id) for the
-- REST API list and get endpoints.
SELECT
id, user_id, name, description,
env_name, file_path, enabled,
created_at, updated_at
FROM user_secrets
WHERE user_id = @user_id
ORDER BY name ASC;
-- name: ListUserSecretsWithValues :many
-- Returns all columns including the secret value. Used by the
-- provisioner (build-time injection) and the agent manifest
-- (runtime injection).
SELECT *
FROM user_secrets
WHERE user_id = @user_id
ORDER BY name ASC;
-- name: CreateUserSecret :one
INSERT INTO user_secrets (
id,
user_id,
name,
description,
value,
value_key_id,
env_name,
file_path,
enabled
) VALUES (
@id,
@user_id,
@name,
@description,
@value,
@value_key_id,
@env_name,
@file_path,
@enabled
) RETURNING *;
-- name: UpdateUserSecretByUserIDAndName :one
UPDATE user_secrets
SET
value = CASE WHEN @update_value::bool THEN @value ELSE value END,
value_key_id = CASE WHEN @update_value::bool THEN @value_key_id ELSE value_key_id END,
description = CASE WHEN @update_description::bool THEN @description ELSE description END,
env_name = CASE WHEN @update_env_name::bool THEN @env_name ELSE env_name END,
file_path = CASE WHEN @update_file_path::bool THEN @file_path ELSE file_path END,
enabled = CASE WHEN @update_enabled::bool THEN @enabled ELSE enabled END,
updated_at = CURRENT_TIMESTAMP
WHERE user_id = @user_id AND name = @name
RETURNING *;
-- name: DeleteUserSecretByUserIDAndName :one
DELETE FROM user_secrets
WHERE user_id = @user_id AND name = @name
RETURNING *;
-- name: GetUserSecretsTelemetrySummary :one
-- Returns deployment-wide aggregates for the telemetry snapshot.
--
-- The denominator for both user-level counts and the per-user
-- distribution is active non-system users. Specifically:
--
-- * deleted = false: Coder soft-deletes by flipping users.deleted
-- rather than removing rows. The delete_deleted_user_resources()
-- trigger now removes their user_secrets, but soft-deleted users
-- are still excluded here so they don't dilute the percentile
-- distribution as zero-secret entries.
-- * status = 'active': dormant users (no recent activity) and
-- suspended users (explicitly disabled) cannot use secrets, so
-- they shouldn't dilute the percentile distribution as
-- zero-secret entries.
-- * is_system = false: internal subjects like the prebuilds user
-- never use secrets in the normal flow.
--
-- Status transitions move users in and out of this denominator, so a
-- snapshot's UsersWithSecrets can drop without any secret being
-- deleted.
--
-- The percentile distribution is computed across all active non-system
-- users, including those with zero secrets, so the percentiles reflect
-- deployment-wide adoption rather than only the power-user subset.
-- percentile_disc returns an actual integer count from the underlying
-- values rather than interpolating between rows.
WITH active_users AS (
SELECT id AS user_id
FROM users
WHERE deleted = false
AND is_system = false
AND status = 'active'::user_status
),
per_user AS (
SELECT au.user_id, COUNT(us.id)::bigint AS n
FROM active_users au
LEFT JOIN user_secrets us ON us.user_id = au.user_id
GROUP BY au.user_id
),
secrets_filtered AS (
SELECT us.env_name, us.file_path
FROM user_secrets us
JOIN active_users au ON au.user_id = us.user_id
)
SELECT
COUNT(*) FILTER (WHERE n > 0)::bigint AS users_with_secrets,
(SELECT COUNT(*) FROM secrets_filtered)::bigint AS total_secrets,
(SELECT COUNT(*) FROM secrets_filtered WHERE env_name != '' AND file_path = '' )::bigint AS env_name_only,
(SELECT COUNT(*) FROM secrets_filtered WHERE env_name = '' AND file_path != '')::bigint AS file_path_only,
(SELECT COUNT(*) FROM secrets_filtered WHERE env_name != '' AND file_path != '')::bigint AS both,
(SELECT COUNT(*) FROM secrets_filtered WHERE env_name = '' AND file_path = '' )::bigint AS neither,
COALESCE(MAX(n), 0)::bigint AS secrets_per_user_max,
COALESCE(percentile_disc(0.25) WITHIN GROUP (ORDER BY n), 0)::bigint AS secrets_per_user_p25,
COALESCE(percentile_disc(0.50) WITHIN GROUP (ORDER BY n), 0)::bigint AS secrets_per_user_p50,
COALESCE(percentile_disc(0.75) WITHIN GROUP (ORDER BY n), 0)::bigint AS secrets_per_user_p75,
COALESCE(percentile_disc(0.90) WITHIN GROUP (ORDER BY n), 0)::bigint AS secrets_per_user_p90
FROM per_user;