mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: add boundary usage tracking database schema and tracker skeleton (#21670)
feat: add boundary usage telemetry database schema and RBAC
Adds the foundation for tracking boundary usage telemetry across Coder
replicas. This includes:
- Database schema: `boundary_usage_stats` table with per-replica stats
(unique workspaces, unique users, allowed/denied request counts)
- Database queries: upsert stats, get aggregated summary, reset stats,
delete by replica ID
- RBAC: `boundary_usage` resource type with read/update/delete actions,
accessible only via system `BoundaryUsageTracker` subject (not regular
user roles)
- Tracker skeleton + docs: stub implementation in `coderd/boundaryusage/`
The tracker accumulates stats in memory and periodically flushes to the
database. Stats are aggregated across replicas for telemetry reporting,
then reset when a new reporting period begins. The tracker implementation
and plumbing will be done in a subsequent commit/PR.
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Generated
+10
@@ -12467,6 +12467,10 @@ const docTemplate = `{
|
|||||||
"audit_log:*",
|
"audit_log:*",
|
||||||
"audit_log:create",
|
"audit_log:create",
|
||||||
"audit_log:read",
|
"audit_log:read",
|
||||||
|
"boundary_usage:*",
|
||||||
|
"boundary_usage:delete",
|
||||||
|
"boundary_usage:read",
|
||||||
|
"boundary_usage:update",
|
||||||
"coder:all",
|
"coder:all",
|
||||||
"coder:apikeys.manage_self",
|
"coder:apikeys.manage_self",
|
||||||
"coder:application_connect",
|
"coder:application_connect",
|
||||||
@@ -12665,6 +12669,10 @@ const docTemplate = `{
|
|||||||
"APIKeyScopeAuditLogAll",
|
"APIKeyScopeAuditLogAll",
|
||||||
"APIKeyScopeAuditLogCreate",
|
"APIKeyScopeAuditLogCreate",
|
||||||
"APIKeyScopeAuditLogRead",
|
"APIKeyScopeAuditLogRead",
|
||||||
|
"APIKeyScopeBoundaryUsageAll",
|
||||||
|
"APIKeyScopeBoundaryUsageDelete",
|
||||||
|
"APIKeyScopeBoundaryUsageRead",
|
||||||
|
"APIKeyScopeBoundaryUsageUpdate",
|
||||||
"APIKeyScopeCoderAll",
|
"APIKeyScopeCoderAll",
|
||||||
"APIKeyScopeCoderApikeysManageSelf",
|
"APIKeyScopeCoderApikeysManageSelf",
|
||||||
"APIKeyScopeCoderApplicationConnect",
|
"APIKeyScopeCoderApplicationConnect",
|
||||||
@@ -17740,6 +17748,7 @@ const docTemplate = `{
|
|||||||
"assign_org_role",
|
"assign_org_role",
|
||||||
"assign_role",
|
"assign_role",
|
||||||
"audit_log",
|
"audit_log",
|
||||||
|
"boundary_usage",
|
||||||
"connection_log",
|
"connection_log",
|
||||||
"crypto_key",
|
"crypto_key",
|
||||||
"debug_info",
|
"debug_info",
|
||||||
@@ -17784,6 +17793,7 @@ const docTemplate = `{
|
|||||||
"ResourceAssignOrgRole",
|
"ResourceAssignOrgRole",
|
||||||
"ResourceAssignRole",
|
"ResourceAssignRole",
|
||||||
"ResourceAuditLog",
|
"ResourceAuditLog",
|
||||||
|
"ResourceBoundaryUsage",
|
||||||
"ResourceConnectionLog",
|
"ResourceConnectionLog",
|
||||||
"ResourceCryptoKey",
|
"ResourceCryptoKey",
|
||||||
"ResourceDebugInfo",
|
"ResourceDebugInfo",
|
||||||
|
|||||||
Generated
+10
@@ -11105,6 +11105,10 @@
|
|||||||
"audit_log:*",
|
"audit_log:*",
|
||||||
"audit_log:create",
|
"audit_log:create",
|
||||||
"audit_log:read",
|
"audit_log:read",
|
||||||
|
"boundary_usage:*",
|
||||||
|
"boundary_usage:delete",
|
||||||
|
"boundary_usage:read",
|
||||||
|
"boundary_usage:update",
|
||||||
"coder:all",
|
"coder:all",
|
||||||
"coder:apikeys.manage_self",
|
"coder:apikeys.manage_self",
|
||||||
"coder:application_connect",
|
"coder:application_connect",
|
||||||
@@ -11303,6 +11307,10 @@
|
|||||||
"APIKeyScopeAuditLogAll",
|
"APIKeyScopeAuditLogAll",
|
||||||
"APIKeyScopeAuditLogCreate",
|
"APIKeyScopeAuditLogCreate",
|
||||||
"APIKeyScopeAuditLogRead",
|
"APIKeyScopeAuditLogRead",
|
||||||
|
"APIKeyScopeBoundaryUsageAll",
|
||||||
|
"APIKeyScopeBoundaryUsageDelete",
|
||||||
|
"APIKeyScopeBoundaryUsageRead",
|
||||||
|
"APIKeyScopeBoundaryUsageUpdate",
|
||||||
"APIKeyScopeCoderAll",
|
"APIKeyScopeCoderAll",
|
||||||
"APIKeyScopeCoderApikeysManageSelf",
|
"APIKeyScopeCoderApikeysManageSelf",
|
||||||
"APIKeyScopeCoderApplicationConnect",
|
"APIKeyScopeCoderApplicationConnect",
|
||||||
@@ -16182,6 +16190,7 @@
|
|||||||
"assign_org_role",
|
"assign_org_role",
|
||||||
"assign_role",
|
"assign_role",
|
||||||
"audit_log",
|
"audit_log",
|
||||||
|
"boundary_usage",
|
||||||
"connection_log",
|
"connection_log",
|
||||||
"crypto_key",
|
"crypto_key",
|
||||||
"debug_info",
|
"debug_info",
|
||||||
@@ -16226,6 +16235,7 @@
|
|||||||
"ResourceAssignOrgRole",
|
"ResourceAssignOrgRole",
|
||||||
"ResourceAssignRole",
|
"ResourceAssignRole",
|
||||||
"ResourceAuditLog",
|
"ResourceAuditLog",
|
||||||
|
"ResourceBoundaryUsage",
|
||||||
"ResourceConnectionLog",
|
"ResourceConnectionLog",
|
||||||
"ResourceCryptoKey",
|
"ResourceCryptoKey",
|
||||||
"ResourceDebugInfo",
|
"ResourceDebugInfo",
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
// Package boundaryusage tracks workspace boundary usage for telemetry reporting.
|
||||||
|
// The design intent is to track trends and rough usage patterns.
|
||||||
|
//
|
||||||
|
// Each replica does in-memory usage tracking. Boundary usage is inferred at the
|
||||||
|
// control plane when workspace agents call the ReportBoundaryLogs RPC. Accumulated
|
||||||
|
// stats are periodically flushed to a database table keyed by replica ID. Telemetry
|
||||||
|
// aggregates are computed across all replicas when generating snapshots.
|
||||||
|
//
|
||||||
|
// Aggregate Precision:
|
||||||
|
//
|
||||||
|
// The aggregated stats represent approximate usage over roughly the telemetry
|
||||||
|
// snapshot interval, not a precise time window. This imprecision arises because:
|
||||||
|
//
|
||||||
|
// - Each replica flushes independently, so their data covers slightly different
|
||||||
|
// time ranges (varying by up to the flush interval)
|
||||||
|
// - Unflushed in-memory data at snapshot time rolls into the next period
|
||||||
|
// - The snapshot captures "data flushed since last reset" rather than "usage
|
||||||
|
// during exactly the last N minutes"
|
||||||
|
//
|
||||||
|
// We accept this imprecision to keep the architecture simple. Each replica
|
||||||
|
// operates independently and flushes to the database on their own schedule.
|
||||||
|
// This approach also minimizes database load. The table contains at most one
|
||||||
|
// row per replica, so flushes are just upserts, and resets only delete N
|
||||||
|
// rows. There's no accumulation of historical data to clean up. The only
|
||||||
|
// synchronization is a database lock that ensures exactly one replica reports
|
||||||
|
// telemetry per period.
|
||||||
|
//
|
||||||
|
// Known Shortcomings:
|
||||||
|
//
|
||||||
|
// - Unique workspace/user counts may be inflated when the same workspace or
|
||||||
|
// user connects through multiple replicas, as each replica tracks its own
|
||||||
|
// unique set
|
||||||
|
// - Ad-hoc boundary usage in a workspace may not be accounted for e.g. if
|
||||||
|
// the boundary command is invoked directly with the --log-proxy-socket-path
|
||||||
|
// flag set to something other than the Workspace agent server.
|
||||||
|
//
|
||||||
|
// Implementation:
|
||||||
|
//
|
||||||
|
// The Tracker maintains sets of unique workspace IDs and user IDs, plus request
|
||||||
|
// counters. When boundary logs are reported, Track() adds the IDs to the sets
|
||||||
|
// and increments request counters.
|
||||||
|
//
|
||||||
|
// FlushToDB() writes stats to the database, replacing all values with the current
|
||||||
|
// in-memory state. Stats accumulate in memory throughout the telemetry period.
|
||||||
|
//
|
||||||
|
// A new period is detected when the upsert results in an INSERT (meaning
|
||||||
|
// telemetry deleted the replica's row). At that point, all in-memory stats are
|
||||||
|
// reset so they only count usage within the new period.
|
||||||
|
//
|
||||||
|
// Below is a sequence diagram showing the flow of boundary usage tracking.
|
||||||
|
//
|
||||||
|
// ┌───────┐ ┌───────────────┐ ┌──────────┐ ┌────┐ ┌───────────┐
|
||||||
|
// │ Agent │ │BoundaryLogsAPI│ │ Tracker │ │ DB │ │ Telemetry │
|
||||||
|
// └───┬───┘ └───────┬───────┘ └────┬─────┘ └──┬─┘ └─────┬─────┘
|
||||||
|
// │ │ │ │ │
|
||||||
|
// │ ReportBoundaryLogs│ │ │ │
|
||||||
|
// ├──────────────────►│ │ │ │
|
||||||
|
// │ │ Track(...) │ │ │
|
||||||
|
// │ ├────────────────►│ │ │
|
||||||
|
// │ : │ │ │ │
|
||||||
|
// │ : │ │ │ │
|
||||||
|
// │ ReportBoundaryLogs│ │ │ │
|
||||||
|
// ├──────────────────►│ │ │ │
|
||||||
|
// │ │ Track(...) │ │ │
|
||||||
|
// │ ├────────────────►│ │ │
|
||||||
|
// │ │ │ │ │
|
||||||
|
// │ │ │ FlushToDB │ │
|
||||||
|
// │ │ ├────────────►│ │
|
||||||
|
// │ │ │ : │ │
|
||||||
|
// │ │ │ : │ │
|
||||||
|
// │ │ │ FlushToDB │ │
|
||||||
|
// │ │ ├────────────►│ │
|
||||||
|
// │ │ │ │ │
|
||||||
|
// │ │ │ │ Snapshot │
|
||||||
|
// │ │ │ │ interval │
|
||||||
|
// │ │ │ │◄───────────┤
|
||||||
|
// │ │ │ │ Aggregate │
|
||||||
|
// │ │ │ │ & Reset │
|
||||||
|
package boundaryusage
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package boundaryusage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/coder/coder/v2/coderd/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tracker tracks boundary usage for telemetry reporting.
|
||||||
|
//
|
||||||
|
// All stats accumulate in memory throughout a telemetry period and are only
|
||||||
|
// reset when a new period begins.
|
||||||
|
type Tracker struct {
|
||||||
|
mu sync.Mutex //nolint:unused // Will be used when implemented.
|
||||||
|
workspaces map[uuid.UUID]struct{} //nolint:unused // Will be used when implemented.
|
||||||
|
users map[uuid.UUID]struct{} //nolint:unused // Will be used when implemented.
|
||||||
|
allowedRequests int64 //nolint:unused // Will be used when implemented.
|
||||||
|
deniedRequests int64 //nolint:unused // Will be used when implemented.
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTracker creates a new boundary usage tracker.
|
||||||
|
func NewTracker() (*Tracker, error) {
|
||||||
|
return nil, xerrors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track records boundary usage for a workspace.
|
||||||
|
func (*Tracker) Track(_, _ uuid.UUID, _, _ int64) error {
|
||||||
|
return xerrors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlushToDB writes the accumulated stats to the database. All values are
|
||||||
|
// replaced in the database (they represent the current in-memory state). If the
|
||||||
|
// database row was deleted (new telemetry period), all in-memory stats are reset.
|
||||||
|
func (*Tracker) FlushToDB(_ context.Context, _ database.Store, _ uuid.UUID) error {
|
||||||
|
return xerrors.New("not implemented")
|
||||||
|
}
|
||||||
@@ -649,6 +649,25 @@ var (
|
|||||||
}),
|
}),
|
||||||
Scope: rbac.ScopeAll,
|
Scope: rbac.ScopeAll,
|
||||||
}.WithCachedASTValue()
|
}.WithCachedASTValue()
|
||||||
|
|
||||||
|
// Used by the boundary usage tracker to record telemetry statistics.
|
||||||
|
subjectBoundaryUsageTracker = rbac.Subject{
|
||||||
|
Type: rbac.SubjectTypeBoundaryUsageTracker,
|
||||||
|
FriendlyName: "Boundary Usage Tracker",
|
||||||
|
ID: uuid.Nil.String(),
|
||||||
|
Roles: rbac.Roles([]rbac.Role{
|
||||||
|
{
|
||||||
|
Identifier: rbac.RoleIdentifier{Name: "boundary-usage-tracker"},
|
||||||
|
DisplayName: "Boundary Usage Tracker",
|
||||||
|
Site: rbac.Permissions(map[string][]policy.Action{
|
||||||
|
rbac.ResourceBoundaryUsage.Type: rbac.ResourceBoundaryUsage.AvailableActions(),
|
||||||
|
}),
|
||||||
|
User: []rbac.Permission{},
|
||||||
|
ByOrgID: map[string]rbac.OrgPermissions{},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Scope: rbac.ScopeAll,
|
||||||
|
}.WithCachedASTValue()
|
||||||
)
|
)
|
||||||
|
|
||||||
// AsProvisionerd returns a context with an actor that has permissions required
|
// AsProvisionerd returns a context with an actor that has permissions required
|
||||||
@@ -749,6 +768,12 @@ func AsDBPurge(ctx context.Context) context.Context {
|
|||||||
return As(ctx, subjectDBPurge)
|
return As(ctx, subjectDBPurge)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AsBoundaryUsageTracker returns a context with an actor that has permissions
|
||||||
|
// required for the boundary usage tracker to record telemetry statistics.
|
||||||
|
func AsBoundaryUsageTracker(ctx context.Context) context.Context {
|
||||||
|
return As(ctx, subjectBoundaryUsageTracker)
|
||||||
|
}
|
||||||
|
|
||||||
var AsRemoveActor = rbac.Subject{
|
var AsRemoveActor = rbac.Subject{
|
||||||
ID: "remove-actor",
|
ID: "remove-actor",
|
||||||
}
|
}
|
||||||
@@ -1678,6 +1703,13 @@ func (q *querier) DeleteApplicationConnectAPIKeysByUserID(ctx context.Context, u
|
|||||||
return q.db.DeleteApplicationConnectAPIKeysByUserID(ctx, userID)
|
return q.db.DeleteApplicationConnectAPIKeysByUserID(ctx, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *querier) DeleteBoundaryUsageStatsByReplicaID(ctx context.Context, replicaID uuid.UUID) error {
|
||||||
|
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceBoundaryUsage); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return q.db.DeleteBoundaryUsageStatsByReplicaID(ctx, replicaID)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *querier) DeleteCryptoKey(ctx context.Context, arg database.DeleteCryptoKeyParams) (database.CryptoKey, error) {
|
func (q *querier) DeleteCryptoKey(ctx context.Context, arg database.DeleteCryptoKeyParams) (database.CryptoKey, error) {
|
||||||
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceCryptoKey); err != nil {
|
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceCryptoKey); err != nil {
|
||||||
return database.CryptoKey{}, err
|
return database.CryptoKey{}, err
|
||||||
@@ -2239,6 +2271,13 @@ func (q *querier) GetAuthorizationUserRoles(ctx context.Context, userID uuid.UUI
|
|||||||
return q.db.GetAuthorizationUserRoles(ctx, userID)
|
return q.db.GetAuthorizationUserRoles(ctx, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *querier) GetBoundaryUsageSummary(ctx context.Context, maxStalenessMs int64) (database.GetBoundaryUsageSummaryRow, error) {
|
||||||
|
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceBoundaryUsage); err != nil {
|
||||||
|
return database.GetBoundaryUsageSummaryRow{}, err
|
||||||
|
}
|
||||||
|
return q.db.GetBoundaryUsageSummary(ctx, maxStalenessMs)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *querier) GetConnectionLogsOffset(ctx context.Context, arg database.GetConnectionLogsOffsetParams) ([]database.GetConnectionLogsOffsetRow, error) {
|
func (q *querier) GetConnectionLogsOffset(ctx context.Context, arg database.GetConnectionLogsOffsetParams) ([]database.GetConnectionLogsOffsetRow, error) {
|
||||||
// Just like with the audit logs query, shortcut if the user is an owner.
|
// Just like with the audit logs query, shortcut if the user is an owner.
|
||||||
err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceConnectionLog)
|
err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceConnectionLog)
|
||||||
@@ -4852,6 +4891,13 @@ func (q *querier) RemoveUserFromGroups(ctx context.Context, arg database.RemoveU
|
|||||||
return q.db.RemoveUserFromGroups(ctx, arg)
|
return q.db.RemoveUserFromGroups(ctx, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *querier) ResetBoundaryUsageStats(ctx context.Context) error {
|
||||||
|
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceBoundaryUsage); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return q.db.ResetBoundaryUsageStats(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *querier) RevokeDBCryptKey(ctx context.Context, activeKeyDigest string) error {
|
func (q *querier) RevokeDBCryptKey(ctx context.Context, activeKeyDigest string) error {
|
||||||
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil {
|
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -5943,6 +5989,13 @@ func (q *querier) UpsertApplicationName(ctx context.Context, value string) error
|
|||||||
return q.db.UpsertApplicationName(ctx, value)
|
return q.db.UpsertApplicationName(ctx, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *querier) UpsertBoundaryUsageStats(ctx context.Context, arg database.UpsertBoundaryUsageStatsParams) (bool, error) {
|
||||||
|
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceBoundaryUsage); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return q.db.UpsertBoundaryUsageStats(ctx, arg)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *querier) UpsertConnectionLog(ctx context.Context, arg database.UpsertConnectionLogParams) (database.ConnectionLog, error) {
|
func (q *querier) UpsertConnectionLog(ctx context.Context, arg database.UpsertConnectionLogParams) (database.ConnectionLog, error) {
|
||||||
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceConnectionLog); err != nil {
|
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceConnectionLog); err != nil {
|
||||||
return database.ConnectionLog{}, err
|
return database.ConnectionLog{}, err
|
||||||
|
|||||||
@@ -278,6 +278,11 @@ func (s *MethodTestSuite) TestAPIKey() {
|
|||||||
dbm.EXPECT().DeleteApplicationConnectAPIKeysByUserID(gomock.Any(), a.UserID).Return(nil).AnyTimes()
|
dbm.EXPECT().DeleteApplicationConnectAPIKeysByUserID(gomock.Any(), a.UserID).Return(nil).AnyTimes()
|
||||||
check.Args(a.UserID).Asserts(rbac.ResourceApiKey.WithOwner(a.UserID.String()), policy.ActionDelete).Returns()
|
check.Args(a.UserID).Asserts(rbac.ResourceApiKey.WithOwner(a.UserID.String()), policy.ActionDelete).Returns()
|
||||||
}))
|
}))
|
||||||
|
s.Run("DeleteBoundaryUsageStatsByReplicaID", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
||||||
|
replicaID := uuid.New()
|
||||||
|
dbm.EXPECT().DeleteBoundaryUsageStatsByReplicaID(gomock.Any(), replicaID).Return(nil).AnyTimes()
|
||||||
|
check.Args(replicaID).Asserts(rbac.ResourceBoundaryUsage, policy.ActionDelete)
|
||||||
|
}))
|
||||||
s.Run("DeleteExternalAuthLink", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
s.Run("DeleteExternalAuthLink", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||||
a := testutil.Fake(s.T(), faker, database.ExternalAuthLink{})
|
a := testutil.Fake(s.T(), faker, database.ExternalAuthLink{})
|
||||||
dbm.EXPECT().GetExternalAuthLink(gomock.Any(), database.GetExternalAuthLinkParams{ProviderID: a.ProviderID, UserID: a.UserID}).Return(a, nil).AnyTimes()
|
dbm.EXPECT().GetExternalAuthLink(gomock.Any(), database.GetExternalAuthLinkParams{ProviderID: a.ProviderID, UserID: a.UserID}).Return(a, nil).AnyTimes()
|
||||||
@@ -528,6 +533,10 @@ func (s *MethodTestSuite) TestGroup() {
|
|||||||
dbm.EXPECT().RemoveUserFromGroups(gomock.Any(), arg).Return(slice.New(g1.ID, g2.ID), nil).AnyTimes()
|
dbm.EXPECT().RemoveUserFromGroups(gomock.Any(), arg).Return(slice.New(g1.ID, g2.ID), nil).AnyTimes()
|
||||||
check.Args(arg).Asserts(rbac.ResourceSystem, policy.ActionUpdate).Returns(slice.New(g1.ID, g2.ID))
|
check.Args(arg).Asserts(rbac.ResourceSystem, policy.ActionUpdate).Returns(slice.New(g1.ID, g2.ID))
|
||||||
}))
|
}))
|
||||||
|
s.Run("ResetBoundaryUsageStats", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
||||||
|
dbm.EXPECT().ResetBoundaryUsageStats(gomock.Any()).Return(nil).AnyTimes()
|
||||||
|
check.Args().Asserts(rbac.ResourceBoundaryUsage, policy.ActionDelete)
|
||||||
|
}))
|
||||||
|
|
||||||
s.Run("UpdateGroupByID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
s.Run("UpdateGroupByID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||||
g := testutil.Fake(s.T(), faker, database.Group{})
|
g := testutil.Fake(s.T(), faker, database.Group{})
|
||||||
@@ -2972,6 +2981,10 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
|||||||
dbm.EXPECT().GetAuthorizationUserRoles(gomock.Any(), u.ID).Return(database.GetAuthorizationUserRolesRow{}, nil).AnyTimes()
|
dbm.EXPECT().GetAuthorizationUserRoles(gomock.Any(), u.ID).Return(database.GetAuthorizationUserRolesRow{}, nil).AnyTimes()
|
||||||
check.Args(u.ID).Asserts(rbac.ResourceSystem, policy.ActionRead)
|
check.Args(u.ID).Asserts(rbac.ResourceSystem, policy.ActionRead)
|
||||||
}))
|
}))
|
||||||
|
s.Run("GetBoundaryUsageSummary", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
||||||
|
dbm.EXPECT().GetBoundaryUsageSummary(gomock.Any(), int64(1000)).Return(database.GetBoundaryUsageSummaryRow{}, nil).AnyTimes()
|
||||||
|
check.Args(int64(1000)).Asserts(rbac.ResourceBoundaryUsage, policy.ActionRead)
|
||||||
|
}))
|
||||||
s.Run("GetDERPMeshKey", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
s.Run("GetDERPMeshKey", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
||||||
dbm.EXPECT().GetDERPMeshKey(gomock.Any()).Return("testing", nil).AnyTimes()
|
dbm.EXPECT().GetDERPMeshKey(gomock.Any()).Return("testing", nil).AnyTimes()
|
||||||
check.Args().Asserts(rbac.ResourceSystem, policy.ActionRead)
|
check.Args().Asserts(rbac.ResourceSystem, policy.ActionRead)
|
||||||
@@ -3342,6 +3355,11 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
|||||||
dbm.EXPECT().UpsertApplicationName(gomock.Any(), "").Return(nil).AnyTimes()
|
dbm.EXPECT().UpsertApplicationName(gomock.Any(), "").Return(nil).AnyTimes()
|
||||||
check.Args("").Asserts(rbac.ResourceDeploymentConfig, policy.ActionUpdate)
|
check.Args("").Asserts(rbac.ResourceDeploymentConfig, policy.ActionUpdate)
|
||||||
}))
|
}))
|
||||||
|
s.Run("UpsertBoundaryUsageStats", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
||||||
|
arg := database.UpsertBoundaryUsageStatsParams{ReplicaID: uuid.New()}
|
||||||
|
dbm.EXPECT().UpsertBoundaryUsageStats(gomock.Any(), arg).Return(false, nil).AnyTimes()
|
||||||
|
check.Args(arg).Asserts(rbac.ResourceBoundaryUsage, policy.ActionUpdate)
|
||||||
|
}))
|
||||||
s.Run("GetHealthSettings", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
s.Run("GetHealthSettings", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
|
||||||
dbm.EXPECT().GetHealthSettings(gomock.Any()).Return("{}", nil).AnyTimes()
|
dbm.EXPECT().GetHealthSettings(gomock.Any()).Return("{}", nil).AnyTimes()
|
||||||
check.Args().Asserts()
|
check.Args().Asserts()
|
||||||
|
|||||||
@@ -335,6 +335,14 @@ func (m queryMetricsStore) DeleteApplicationConnectAPIKeysByUserID(ctx context.C
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m queryMetricsStore) DeleteBoundaryUsageStatsByReplicaID(ctx context.Context, replicaID uuid.UUID) error {
|
||||||
|
start := time.Now()
|
||||||
|
r0 := m.s.DeleteBoundaryUsageStatsByReplicaID(ctx, replicaID)
|
||||||
|
m.queryLatencies.WithLabelValues("DeleteBoundaryUsageStatsByReplicaID").Observe(time.Since(start).Seconds())
|
||||||
|
m.queryCounts.WithLabelValues(httpmw.ExtractHTTPRoute(ctx), httpmw.ExtractHTTPMethod(ctx), "DeleteBoundaryUsageStatsByReplicaID").Inc()
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
func (m queryMetricsStore) DeleteCryptoKey(ctx context.Context, arg database.DeleteCryptoKeyParams) (database.CryptoKey, error) {
|
func (m queryMetricsStore) DeleteCryptoKey(ctx context.Context, arg database.DeleteCryptoKeyParams) (database.CryptoKey, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
r0, r1 := m.s.DeleteCryptoKey(ctx, arg)
|
r0, r1 := m.s.DeleteCryptoKey(ctx, arg)
|
||||||
@@ -894,6 +902,14 @@ func (m queryMetricsStore) GetAuthorizationUserRoles(ctx context.Context, userID
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m queryMetricsStore) GetBoundaryUsageSummary(ctx context.Context, maxStalenessMs int64) (database.GetBoundaryUsageSummaryRow, error) {
|
||||||
|
start := time.Now()
|
||||||
|
r0, r1 := m.s.GetBoundaryUsageSummary(ctx, maxStalenessMs)
|
||||||
|
m.queryLatencies.WithLabelValues("GetBoundaryUsageSummary").Observe(time.Since(start).Seconds())
|
||||||
|
m.queryCounts.WithLabelValues(httpmw.ExtractHTTPRoute(ctx), httpmw.ExtractHTTPMethod(ctx), "GetBoundaryUsageSummary").Inc()
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
func (m queryMetricsStore) GetConnectionLogsOffset(ctx context.Context, arg database.GetConnectionLogsOffsetParams) ([]database.GetConnectionLogsOffsetRow, error) {
|
func (m queryMetricsStore) GetConnectionLogsOffset(ctx context.Context, arg database.GetConnectionLogsOffsetParams) ([]database.GetConnectionLogsOffsetRow, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
r0, r1 := m.s.GetConnectionLogsOffset(ctx, arg)
|
r0, r1 := m.s.GetConnectionLogsOffset(ctx, arg)
|
||||||
@@ -3318,6 +3334,14 @@ func (m queryMetricsStore) RemoveUserFromGroups(ctx context.Context, arg databas
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m queryMetricsStore) ResetBoundaryUsageStats(ctx context.Context) error {
|
||||||
|
start := time.Now()
|
||||||
|
r0 := m.s.ResetBoundaryUsageStats(ctx)
|
||||||
|
m.queryLatencies.WithLabelValues("ResetBoundaryUsageStats").Observe(time.Since(start).Seconds())
|
||||||
|
m.queryCounts.WithLabelValues(httpmw.ExtractHTTPRoute(ctx), httpmw.ExtractHTTPMethod(ctx), "ResetBoundaryUsageStats").Inc()
|
||||||
|
return r0
|
||||||
|
}
|
||||||
|
|
||||||
func (m queryMetricsStore) RevokeDBCryptKey(ctx context.Context, activeKeyDigest string) error {
|
func (m queryMetricsStore) RevokeDBCryptKey(ctx context.Context, activeKeyDigest string) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
r0 := m.s.RevokeDBCryptKey(ctx, activeKeyDigest)
|
r0 := m.s.RevokeDBCryptKey(ctx, activeKeyDigest)
|
||||||
@@ -4069,6 +4093,14 @@ func (m queryMetricsStore) UpsertApplicationName(ctx context.Context, value stri
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m queryMetricsStore) UpsertBoundaryUsageStats(ctx context.Context, arg database.UpsertBoundaryUsageStatsParams) (bool, error) {
|
||||||
|
start := time.Now()
|
||||||
|
r0, r1 := m.s.UpsertBoundaryUsageStats(ctx, arg)
|
||||||
|
m.queryLatencies.WithLabelValues("UpsertBoundaryUsageStats").Observe(time.Since(start).Seconds())
|
||||||
|
m.queryCounts.WithLabelValues(httpmw.ExtractHTTPRoute(ctx), httpmw.ExtractHTTPMethod(ctx), "UpsertBoundaryUsageStats").Inc()
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
func (m queryMetricsStore) UpsertConnectionLog(ctx context.Context, arg database.UpsertConnectionLogParams) (database.ConnectionLog, error) {
|
func (m queryMetricsStore) UpsertConnectionLog(ctx context.Context, arg database.UpsertConnectionLogParams) (database.ConnectionLog, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
r0, r1 := m.s.UpsertConnectionLog(ctx, arg)
|
r0, r1 := m.s.UpsertConnectionLog(ctx, arg)
|
||||||
|
|||||||
@@ -511,6 +511,20 @@ func (mr *MockStoreMockRecorder) DeleteApplicationConnectAPIKeysByUserID(ctx, us
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplicationConnectAPIKeysByUserID", reflect.TypeOf((*MockStore)(nil).DeleteApplicationConnectAPIKeysByUserID), ctx, userID)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplicationConnectAPIKeysByUserID", reflect.TypeOf((*MockStore)(nil).DeleteApplicationConnectAPIKeysByUserID), ctx, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteBoundaryUsageStatsByReplicaID mocks base method.
|
||||||
|
func (m *MockStore) DeleteBoundaryUsageStatsByReplicaID(ctx context.Context, replicaID uuid.UUID) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "DeleteBoundaryUsageStatsByReplicaID", ctx, replicaID)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBoundaryUsageStatsByReplicaID indicates an expected call of DeleteBoundaryUsageStatsByReplicaID.
|
||||||
|
func (mr *MockStoreMockRecorder) DeleteBoundaryUsageStatsByReplicaID(ctx, replicaID any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteBoundaryUsageStatsByReplicaID", reflect.TypeOf((*MockStore)(nil).DeleteBoundaryUsageStatsByReplicaID), ctx, replicaID)
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteCryptoKey mocks base method.
|
// DeleteCryptoKey mocks base method.
|
||||||
func (m *MockStore) DeleteCryptoKey(ctx context.Context, arg database.DeleteCryptoKeyParams) (database.CryptoKey, error) {
|
func (m *MockStore) DeleteCryptoKey(ctx context.Context, arg database.DeleteCryptoKeyParams) (database.CryptoKey, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@@ -1634,6 +1648,21 @@ func (mr *MockStoreMockRecorder) GetAuthorizedWorkspacesAndAgentsByOwnerID(ctx,
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizedWorkspacesAndAgentsByOwnerID", reflect.TypeOf((*MockStore)(nil).GetAuthorizedWorkspacesAndAgentsByOwnerID), ctx, ownerID, prepared)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizedWorkspacesAndAgentsByOwnerID", reflect.TypeOf((*MockStore)(nil).GetAuthorizedWorkspacesAndAgentsByOwnerID), ctx, ownerID, prepared)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBoundaryUsageSummary mocks base method.
|
||||||
|
func (m *MockStore) GetBoundaryUsageSummary(ctx context.Context, maxStalenessMs int64) (database.GetBoundaryUsageSummaryRow, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetBoundaryUsageSummary", ctx, maxStalenessMs)
|
||||||
|
ret0, _ := ret[0].(database.GetBoundaryUsageSummaryRow)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBoundaryUsageSummary indicates an expected call of GetBoundaryUsageSummary.
|
||||||
|
func (mr *MockStoreMockRecorder) GetBoundaryUsageSummary(ctx, maxStalenessMs any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBoundaryUsageSummary", reflect.TypeOf((*MockStore)(nil).GetBoundaryUsageSummary), ctx, maxStalenessMs)
|
||||||
|
}
|
||||||
|
|
||||||
// GetConnectionLogsOffset mocks base method.
|
// GetConnectionLogsOffset mocks base method.
|
||||||
func (m *MockStore) GetConnectionLogsOffset(ctx context.Context, arg database.GetConnectionLogsOffsetParams) ([]database.GetConnectionLogsOffsetRow, error) {
|
func (m *MockStore) GetConnectionLogsOffset(ctx context.Context, arg database.GetConnectionLogsOffsetParams) ([]database.GetConnectionLogsOffsetRow, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@@ -6249,6 +6278,20 @@ func (mr *MockStoreMockRecorder) RemoveUserFromGroups(ctx, arg any) *gomock.Call
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveUserFromGroups", reflect.TypeOf((*MockStore)(nil).RemoveUserFromGroups), ctx, arg)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveUserFromGroups", reflect.TypeOf((*MockStore)(nil).RemoveUserFromGroups), ctx, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResetBoundaryUsageStats mocks base method.
|
||||||
|
func (m *MockStore) ResetBoundaryUsageStats(ctx context.Context) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "ResetBoundaryUsageStats", ctx)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetBoundaryUsageStats indicates an expected call of ResetBoundaryUsageStats.
|
||||||
|
func (mr *MockStoreMockRecorder) ResetBoundaryUsageStats(ctx any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResetBoundaryUsageStats", reflect.TypeOf((*MockStore)(nil).ResetBoundaryUsageStats), ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// RevokeDBCryptKey mocks base method.
|
// RevokeDBCryptKey mocks base method.
|
||||||
func (m *MockStore) RevokeDBCryptKey(ctx context.Context, activeKeyDigest string) error {
|
func (m *MockStore) RevokeDBCryptKey(ctx context.Context, activeKeyDigest string) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@@ -7603,6 +7646,21 @@ func (mr *MockStoreMockRecorder) UpsertApplicationName(ctx, value any) *gomock.C
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertApplicationName", reflect.TypeOf((*MockStore)(nil).UpsertApplicationName), ctx, value)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertApplicationName", reflect.TypeOf((*MockStore)(nil).UpsertApplicationName), ctx, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpsertBoundaryUsageStats mocks base method.
|
||||||
|
func (m *MockStore) UpsertBoundaryUsageStats(ctx context.Context, arg database.UpsertBoundaryUsageStatsParams) (bool, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "UpsertBoundaryUsageStats", ctx, arg)
|
||||||
|
ret0, _ := ret[0].(bool)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpsertBoundaryUsageStats indicates an expected call of UpsertBoundaryUsageStats.
|
||||||
|
func (mr *MockStoreMockRecorder) UpsertBoundaryUsageStats(ctx, arg any) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertBoundaryUsageStats", reflect.TypeOf((*MockStore)(nil).UpsertBoundaryUsageStats), ctx, arg)
|
||||||
|
}
|
||||||
|
|
||||||
// UpsertConnectionLog mocks base method.
|
// UpsertConnectionLog mocks base method.
|
||||||
func (m *MockStore) UpsertConnectionLog(ctx context.Context, arg database.UpsertConnectionLogParams) (database.ConnectionLog, error) {
|
func (m *MockStore) UpsertConnectionLog(ctx context.Context, arg database.UpsertConnectionLogParams) (database.ConnectionLog, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
|||||||
Generated
+35
-2
@@ -204,7 +204,11 @@ CREATE TYPE api_key_scope AS ENUM (
|
|||||||
'task:delete',
|
'task:delete',
|
||||||
'task:*',
|
'task:*',
|
||||||
'workspace:share',
|
'workspace:share',
|
||||||
'workspace_dormant:share'
|
'workspace_dormant:share',
|
||||||
|
'boundary_usage:*',
|
||||||
|
'boundary_usage:delete',
|
||||||
|
'boundary_usage:read',
|
||||||
|
'boundary_usage:update'
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TYPE app_sharing_level AS ENUM (
|
CREATE TYPE app_sharing_level AS ENUM (
|
||||||
@@ -1111,6 +1115,32 @@ CREATE TABLE audit_logs (
|
|||||||
resource_icon text NOT NULL
|
resource_icon text NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE boundary_usage_stats (
|
||||||
|
replica_id uuid NOT NULL,
|
||||||
|
unique_workspaces_count bigint DEFAULT 0 NOT NULL,
|
||||||
|
unique_users_count bigint DEFAULT 0 NOT NULL,
|
||||||
|
allowed_requests bigint DEFAULT 0 NOT NULL,
|
||||||
|
denied_requests bigint DEFAULT 0 NOT NULL,
|
||||||
|
window_start timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
updated_at timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE boundary_usage_stats IS 'Per-replica boundary usage statistics for telemetry aggregation.';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.replica_id IS 'The unique identifier of the replica reporting stats.';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.unique_workspaces_count IS 'Count of unique workspaces that used boundary on this replica.';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.unique_users_count IS 'Count of unique users that used boundary on this replica.';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.allowed_requests IS 'Total allowed requests through boundary on this replica.';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.denied_requests IS 'Total denied requests through boundary on this replica.';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.window_start IS 'Start of the time window for these stats, set on first flush after reset.';
|
||||||
|
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.updated_at IS 'Timestamp of the last update to this row.';
|
||||||
|
|
||||||
CREATE TABLE connection_logs (
|
CREATE TABLE connection_logs (
|
||||||
id uuid NOT NULL,
|
id uuid NOT NULL,
|
||||||
connect_time timestamp with time zone NOT NULL,
|
connect_time timestamp with time zone NOT NULL,
|
||||||
@@ -2002,7 +2032,7 @@ CREATE TABLE telemetry_items (
|
|||||||
CREATE TABLE telemetry_locks (
|
CREATE TABLE telemetry_locks (
|
||||||
event_type text NOT NULL,
|
event_type text NOT NULL,
|
||||||
period_ending_at timestamp with time zone NOT NULL,
|
period_ending_at timestamp with time zone NOT NULL,
|
||||||
CONSTRAINT telemetry_lock_event_type_constraint CHECK ((event_type = 'aibridge_interceptions_summary'::text))
|
CONSTRAINT telemetry_lock_event_type_constraint CHECK ((event_type = ANY (ARRAY['aibridge_interceptions_summary'::text, 'boundary_usage_summary'::text])))
|
||||||
);
|
);
|
||||||
|
|
||||||
COMMENT ON TABLE telemetry_locks IS 'Telemetry lock tracking table for deduplication of heartbeat events across replicas.';
|
COMMENT ON TABLE telemetry_locks IS 'Telemetry lock tracking table for deduplication of heartbeat events across replicas.';
|
||||||
@@ -2941,6 +2971,9 @@ ALTER TABLE ONLY api_keys
|
|||||||
ALTER TABLE ONLY audit_logs
|
ALTER TABLE ONLY audit_logs
|
||||||
ADD CONSTRAINT audit_logs_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT audit_logs_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY boundary_usage_stats
|
||||||
|
ADD CONSTRAINT boundary_usage_stats_pkey PRIMARY KEY (replica_id);
|
||||||
|
|
||||||
ALTER TABLE ONLY connection_logs
|
ALTER TABLE ONLY connection_logs
|
||||||
ADD CONSTRAINT connection_logs_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT connection_logs_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- Restore the original telemetry_locks event_type constraint.
|
||||||
|
ALTER TABLE telemetry_locks DROP CONSTRAINT telemetry_lock_event_type_constraint;
|
||||||
|
ALTER TABLE telemetry_locks ADD CONSTRAINT telemetry_lock_event_type_constraint
|
||||||
|
CHECK (event_type IN ('aibridge_interceptions_summary'));
|
||||||
|
|
||||||
|
DROP TABLE boundary_usage_stats;
|
||||||
|
|
||||||
|
-- No-op for boundary_usage scopes: keep enum values to avoid dependency churn.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
CREATE TABLE boundary_usage_stats (
|
||||||
|
replica_id UUID PRIMARY KEY,
|
||||||
|
unique_workspaces_count BIGINT NOT NULL DEFAULT 0,
|
||||||
|
unique_users_count BIGINT NOT NULL DEFAULT 0,
|
||||||
|
allowed_requests BIGINT NOT NULL DEFAULT 0,
|
||||||
|
denied_requests BIGINT NOT NULL DEFAULT 0,
|
||||||
|
window_start TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
COMMENT ON TABLE boundary_usage_stats IS 'Per-replica boundary usage statistics for telemetry aggregation.';
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.replica_id IS 'The unique identifier of the replica reporting stats.';
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.unique_workspaces_count IS 'Count of unique workspaces that used boundary on this replica.';
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.unique_users_count IS 'Count of unique users that used boundary on this replica.';
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.allowed_requests IS 'Total allowed requests through boundary on this replica.';
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.denied_requests IS 'Total denied requests through boundary on this replica.';
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.window_start IS 'Start of the time window for these stats, set on first flush after reset.';
|
||||||
|
COMMENT ON COLUMN boundary_usage_stats.updated_at IS 'Timestamp of the last update to this row.';
|
||||||
|
|
||||||
|
-- Add boundary_usage_summary to the telemetry_locks event_type constraint.
|
||||||
|
ALTER TABLE telemetry_locks DROP CONSTRAINT telemetry_lock_event_type_constraint;
|
||||||
|
ALTER TABLE telemetry_locks ADD CONSTRAINT telemetry_lock_event_type_constraint
|
||||||
|
CHECK (event_type IN ('aibridge_interceptions_summary', 'boundary_usage_summary'));
|
||||||
|
|
||||||
|
-- Add boundary_usage scopes for RBAC.
|
||||||
|
ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'boundary_usage:*';
|
||||||
|
ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'boundary_usage:delete';
|
||||||
|
ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'boundary_usage:read';
|
||||||
|
ALTER TYPE api_key_scope ADD VALUE IF NOT EXISTS 'boundary_usage:update';
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
INSERT INTO boundary_usage_stats (replica_id, unique_workspaces_count, unique_users_count, allowed_requests, denied_requests, window_start, updated_at)
|
||||||
|
VALUES ('00000000-0000-0000-0000-000000000001', 10, 5, 100, 20, NOW(), NOW());
|
||||||
@@ -213,6 +213,10 @@ const (
|
|||||||
ApiKeyScopeTask APIKeyScope = "task:*"
|
ApiKeyScopeTask APIKeyScope = "task:*"
|
||||||
ApiKeyScopeWorkspaceShare APIKeyScope = "workspace:share"
|
ApiKeyScopeWorkspaceShare APIKeyScope = "workspace:share"
|
||||||
ApiKeyScopeWorkspaceDormantShare APIKeyScope = "workspace_dormant:share"
|
ApiKeyScopeWorkspaceDormantShare APIKeyScope = "workspace_dormant:share"
|
||||||
|
ApiKeyScopeBoundaryUsage APIKeyScope = "boundary_usage:*"
|
||||||
|
ApiKeyScopeBoundaryUsageDelete APIKeyScope = "boundary_usage:delete"
|
||||||
|
ApiKeyScopeBoundaryUsageRead APIKeyScope = "boundary_usage:read"
|
||||||
|
ApiKeyScopeBoundaryUsageUpdate APIKeyScope = "boundary_usage:update"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *APIKeyScope) Scan(src interface{}) error {
|
func (e *APIKeyScope) Scan(src interface{}) error {
|
||||||
@@ -445,7 +449,11 @@ func (e APIKeyScope) Valid() bool {
|
|||||||
ApiKeyScopeTaskDelete,
|
ApiKeyScopeTaskDelete,
|
||||||
ApiKeyScopeTask,
|
ApiKeyScopeTask,
|
||||||
ApiKeyScopeWorkspaceShare,
|
ApiKeyScopeWorkspaceShare,
|
||||||
ApiKeyScopeWorkspaceDormantShare:
|
ApiKeyScopeWorkspaceDormantShare,
|
||||||
|
ApiKeyScopeBoundaryUsage,
|
||||||
|
ApiKeyScopeBoundaryUsageDelete,
|
||||||
|
ApiKeyScopeBoundaryUsageRead,
|
||||||
|
ApiKeyScopeBoundaryUsageUpdate:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -647,6 +655,10 @@ func AllAPIKeyScopeValues() []APIKeyScope {
|
|||||||
ApiKeyScopeTask,
|
ApiKeyScopeTask,
|
||||||
ApiKeyScopeWorkspaceShare,
|
ApiKeyScopeWorkspaceShare,
|
||||||
ApiKeyScopeWorkspaceDormantShare,
|
ApiKeyScopeWorkspaceDormantShare,
|
||||||
|
ApiKeyScopeBoundaryUsage,
|
||||||
|
ApiKeyScopeBoundaryUsageDelete,
|
||||||
|
ApiKeyScopeBoundaryUsageRead,
|
||||||
|
ApiKeyScopeBoundaryUsageUpdate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3702,6 +3714,24 @@ type AuditLog struct {
|
|||||||
ResourceIcon string `db:"resource_icon" json:"resource_icon"`
|
ResourceIcon string `db:"resource_icon" json:"resource_icon"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Per-replica boundary usage statistics for telemetry aggregation.
|
||||||
|
type BoundaryUsageStat struct {
|
||||||
|
// The unique identifier of the replica reporting stats.
|
||||||
|
ReplicaID uuid.UUID `db:"replica_id" json:"replica_id"`
|
||||||
|
// Count of unique workspaces that used boundary on this replica.
|
||||||
|
UniqueWorkspacesCount int64 `db:"unique_workspaces_count" json:"unique_workspaces_count"`
|
||||||
|
// Count of unique users that used boundary on this replica.
|
||||||
|
UniqueUsersCount int64 `db:"unique_users_count" json:"unique_users_count"`
|
||||||
|
// Total allowed requests through boundary on this replica.
|
||||||
|
AllowedRequests int64 `db:"allowed_requests" json:"allowed_requests"`
|
||||||
|
// Total denied requests through boundary on this replica.
|
||||||
|
DeniedRequests int64 `db:"denied_requests" json:"denied_requests"`
|
||||||
|
// Start of the time window for these stats, set on first flush after reset.
|
||||||
|
WindowStart time.Time `db:"window_start" json:"window_start"`
|
||||||
|
// Timestamp of the last update to this row.
|
||||||
|
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
type ConnectionLog struct {
|
type ConnectionLog struct {
|
||||||
ID uuid.UUID `db:"id" json:"id"`
|
ID uuid.UUID `db:"id" json:"id"`
|
||||||
ConnectTime time.Time `db:"connect_time" json:"connect_time"`
|
ConnectTime time.Time `db:"connect_time" json:"connect_time"`
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ type sqlcQuerier interface {
|
|||||||
// be recreated.
|
// be recreated.
|
||||||
DeleteAllWebpushSubscriptions(ctx context.Context) error
|
DeleteAllWebpushSubscriptions(ctx context.Context) error
|
||||||
DeleteApplicationConnectAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error
|
DeleteApplicationConnectAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error
|
||||||
|
// Deletes boundary usage statistics for a specific replica.
|
||||||
|
DeleteBoundaryUsageStatsByReplicaID(ctx context.Context, replicaID uuid.UUID) error
|
||||||
DeleteCryptoKey(ctx context.Context, arg DeleteCryptoKeyParams) (CryptoKey, error)
|
DeleteCryptoKey(ctx context.Context, arg DeleteCryptoKeyParams) (CryptoKey, error)
|
||||||
DeleteCustomRole(ctx context.Context, arg DeleteCustomRoleParams) error
|
DeleteCustomRole(ctx context.Context, arg DeleteCustomRoleParams) error
|
||||||
DeleteExpiredAPIKeys(ctx context.Context, arg DeleteExpiredAPIKeysParams) (int64, error)
|
DeleteExpiredAPIKeys(ctx context.Context, arg DeleteExpiredAPIKeysParams) (int64, error)
|
||||||
@@ -194,6 +196,10 @@ type sqlcQuerier interface {
|
|||||||
// This function returns roles for authorization purposes. Implied member roles
|
// This function returns roles for authorization purposes. Implied member roles
|
||||||
// are included.
|
// are included.
|
||||||
GetAuthorizationUserRoles(ctx context.Context, userID uuid.UUID) (GetAuthorizationUserRolesRow, error)
|
GetAuthorizationUserRoles(ctx context.Context, userID uuid.UUID) (GetAuthorizationUserRolesRow, error)
|
||||||
|
// Aggregates boundary usage statistics across all replicas. Filters to only
|
||||||
|
// include data where window_start is within the given interval to exclude
|
||||||
|
// stale data.
|
||||||
|
GetBoundaryUsageSummary(ctx context.Context, maxStalenessMs int64) (GetBoundaryUsageSummaryRow, error)
|
||||||
GetConnectionLogsOffset(ctx context.Context, arg GetConnectionLogsOffsetParams) ([]GetConnectionLogsOffsetRow, error)
|
GetConnectionLogsOffset(ctx context.Context, arg GetConnectionLogsOffsetParams) ([]GetConnectionLogsOffsetRow, error)
|
||||||
GetCoordinatorResumeTokenSigningKey(ctx context.Context) (string, error)
|
GetCoordinatorResumeTokenSigningKey(ctx context.Context) (string, error)
|
||||||
GetCryptoKeyByFeatureAndSequence(ctx context.Context, arg GetCryptoKeyByFeatureAndSequenceParams) (CryptoKey, error)
|
GetCryptoKeyByFeatureAndSequence(ctx context.Context, arg GetCryptoKeyByFeatureAndSequenceParams) (CryptoKey, error)
|
||||||
@@ -646,6 +652,9 @@ type sqlcQuerier interface {
|
|||||||
RegisterWorkspaceProxy(ctx context.Context, arg RegisterWorkspaceProxyParams) (WorkspaceProxy, error)
|
RegisterWorkspaceProxy(ctx context.Context, arg RegisterWorkspaceProxyParams) (WorkspaceProxy, error)
|
||||||
RemoveUserFromAllGroups(ctx context.Context, userID uuid.UUID) error
|
RemoveUserFromAllGroups(ctx context.Context, userID uuid.UUID) error
|
||||||
RemoveUserFromGroups(ctx context.Context, arg RemoveUserFromGroupsParams) ([]uuid.UUID, error)
|
RemoveUserFromGroups(ctx context.Context, arg RemoveUserFromGroupsParams) ([]uuid.UUID, error)
|
||||||
|
// Deletes all boundary usage statistics. Called after telemetry reports the
|
||||||
|
// aggregated stats. Each replica will insert a fresh row on its next flush.
|
||||||
|
ResetBoundaryUsageStats(ctx context.Context) error
|
||||||
RevokeDBCryptKey(ctx context.Context, activeKeyDigest string) error
|
RevokeDBCryptKey(ctx context.Context, activeKeyDigest string) error
|
||||||
// Note that this selects from the CTE, not the original table. The CTE is named
|
// Note that this selects from the CTE, not the original table. The CTE is named
|
||||||
// the same as the original table to trick sqlc into reusing the existing struct
|
// the same as the original table to trick sqlc into reusing the existing struct
|
||||||
@@ -753,6 +762,10 @@ type sqlcQuerier interface {
|
|||||||
UpsertAnnouncementBanners(ctx context.Context, value string) error
|
UpsertAnnouncementBanners(ctx context.Context, value string) error
|
||||||
UpsertAppSecurityKey(ctx context.Context, value string) error
|
UpsertAppSecurityKey(ctx context.Context, value string) error
|
||||||
UpsertApplicationName(ctx context.Context, value string) error
|
UpsertApplicationName(ctx context.Context, value string) error
|
||||||
|
// Upserts boundary usage statistics for a replica. All values are replaced with
|
||||||
|
// the current in-memory state. Returns true if this was an insert (new period),
|
||||||
|
// false if update.
|
||||||
|
UpsertBoundaryUsageStats(ctx context.Context, arg UpsertBoundaryUsageStatsParams) (bool, error)
|
||||||
UpsertConnectionLog(ctx context.Context, arg UpsertConnectionLogParams) (ConnectionLog, error)
|
UpsertConnectionLog(ctx context.Context, arg UpsertConnectionLogParams) (ConnectionLog, error)
|
||||||
UpsertCoordinatorResumeTokenSigningKey(ctx context.Context, value string) error
|
UpsertCoordinatorResumeTokenSigningKey(ctx context.Context, value string) error
|
||||||
// The default proxy is implied and not actually stored in the database.
|
// The default proxy is implied and not actually stored in the database.
|
||||||
|
|||||||
@@ -1980,6 +1980,109 @@ func (q *sqlQuerier) InsertAuditLog(ctx context.Context, arg InsertAuditLogParam
|
|||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteBoundaryUsageStatsByReplicaID = `-- name: DeleteBoundaryUsageStatsByReplicaID :exec
|
||||||
|
DELETE FROM boundary_usage_stats WHERE replica_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
// Deletes boundary usage statistics for a specific replica.
|
||||||
|
func (q *sqlQuerier) DeleteBoundaryUsageStatsByReplicaID(ctx context.Context, replicaID uuid.UUID) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, deleteBoundaryUsageStatsByReplicaID, replicaID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBoundaryUsageSummary = `-- name: GetBoundaryUsageSummary :one
|
||||||
|
SELECT
|
||||||
|
COALESCE(SUM(unique_workspaces_count), 0)::bigint AS unique_workspaces,
|
||||||
|
COALESCE(SUM(unique_users_count), 0)::bigint AS unique_users,
|
||||||
|
COALESCE(SUM(allowed_requests), 0)::bigint AS allowed_requests,
|
||||||
|
COALESCE(SUM(denied_requests), 0)::bigint AS denied_requests
|
||||||
|
FROM boundary_usage_stats
|
||||||
|
WHERE window_start >= NOW() - ($1::bigint || ' ms')::interval
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetBoundaryUsageSummaryRow struct {
|
||||||
|
UniqueWorkspaces int64 `db:"unique_workspaces" json:"unique_workspaces"`
|
||||||
|
UniqueUsers int64 `db:"unique_users" json:"unique_users"`
|
||||||
|
AllowedRequests int64 `db:"allowed_requests" json:"allowed_requests"`
|
||||||
|
DeniedRequests int64 `db:"denied_requests" json:"denied_requests"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregates boundary usage statistics across all replicas. Filters to only
|
||||||
|
// include data where window_start is within the given interval to exclude
|
||||||
|
// stale data.
|
||||||
|
func (q *sqlQuerier) GetBoundaryUsageSummary(ctx context.Context, maxStalenessMs int64) (GetBoundaryUsageSummaryRow, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, getBoundaryUsageSummary, maxStalenessMs)
|
||||||
|
var i GetBoundaryUsageSummaryRow
|
||||||
|
err := row.Scan(
|
||||||
|
&i.UniqueWorkspaces,
|
||||||
|
&i.UniqueUsers,
|
||||||
|
&i.AllowedRequests,
|
||||||
|
&i.DeniedRequests,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetBoundaryUsageStats = `-- name: ResetBoundaryUsageStats :exec
|
||||||
|
DELETE FROM boundary_usage_stats
|
||||||
|
`
|
||||||
|
|
||||||
|
// Deletes all boundary usage statistics. Called after telemetry reports the
|
||||||
|
// aggregated stats. Each replica will insert a fresh row on its next flush.
|
||||||
|
func (q *sqlQuerier) ResetBoundaryUsageStats(ctx context.Context) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, resetBoundaryUsageStats)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const upsertBoundaryUsageStats = `-- name: UpsertBoundaryUsageStats :one
|
||||||
|
INSERT INTO boundary_usage_stats (
|
||||||
|
replica_id,
|
||||||
|
unique_workspaces_count,
|
||||||
|
unique_users_count,
|
||||||
|
allowed_requests,
|
||||||
|
denied_requests,
|
||||||
|
window_start,
|
||||||
|
updated_at
|
||||||
|
) VALUES (
|
||||||
|
$1,
|
||||||
|
$2,
|
||||||
|
$3,
|
||||||
|
$4,
|
||||||
|
$5,
|
||||||
|
NOW(),
|
||||||
|
NOW()
|
||||||
|
) ON CONFLICT (replica_id) DO UPDATE SET
|
||||||
|
unique_workspaces_count = EXCLUDED.unique_workspaces_count,
|
||||||
|
unique_users_count = EXCLUDED.unique_users_count,
|
||||||
|
allowed_requests = EXCLUDED.allowed_requests,
|
||||||
|
denied_requests = EXCLUDED.denied_requests,
|
||||||
|
updated_at = NOW()
|
||||||
|
RETURNING (xmax = 0) AS new_period
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpsertBoundaryUsageStatsParams struct {
|
||||||
|
ReplicaID uuid.UUID `db:"replica_id" json:"replica_id"`
|
||||||
|
UniqueWorkspacesCount int64 `db:"unique_workspaces_count" json:"unique_workspaces_count"`
|
||||||
|
UniqueUsersCount int64 `db:"unique_users_count" json:"unique_users_count"`
|
||||||
|
AllowedRequests int64 `db:"allowed_requests" json:"allowed_requests"`
|
||||||
|
DeniedRequests int64 `db:"denied_requests" json:"denied_requests"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upserts boundary usage statistics for a replica. All values are replaced with
|
||||||
|
// the current in-memory state. Returns true if this was an insert (new period),
|
||||||
|
// false if update.
|
||||||
|
func (q *sqlQuerier) UpsertBoundaryUsageStats(ctx context.Context, arg UpsertBoundaryUsageStatsParams) (bool, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, upsertBoundaryUsageStats,
|
||||||
|
arg.ReplicaID,
|
||||||
|
arg.UniqueWorkspacesCount,
|
||||||
|
arg.UniqueUsersCount,
|
||||||
|
arg.AllowedRequests,
|
||||||
|
arg.DeniedRequests,
|
||||||
|
)
|
||||||
|
var new_period bool
|
||||||
|
err := row.Scan(&new_period)
|
||||||
|
return new_period, err
|
||||||
|
}
|
||||||
|
|
||||||
const countConnectionLogs = `-- name: CountConnectionLogs :one
|
const countConnectionLogs = `-- name: CountConnectionLogs :one
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) AS count
|
COUNT(*) AS count
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
-- name: UpsertBoundaryUsageStats :one
|
||||||
|
-- Upserts boundary usage statistics for a replica. All values are replaced with
|
||||||
|
-- the current in-memory state. Returns true if this was an insert (new period),
|
||||||
|
-- false if update.
|
||||||
|
INSERT INTO boundary_usage_stats (
|
||||||
|
replica_id,
|
||||||
|
unique_workspaces_count,
|
||||||
|
unique_users_count,
|
||||||
|
allowed_requests,
|
||||||
|
denied_requests,
|
||||||
|
window_start,
|
||||||
|
updated_at
|
||||||
|
) VALUES (
|
||||||
|
@replica_id,
|
||||||
|
@unique_workspaces_count,
|
||||||
|
@unique_users_count,
|
||||||
|
@allowed_requests,
|
||||||
|
@denied_requests,
|
||||||
|
NOW(),
|
||||||
|
NOW()
|
||||||
|
) ON CONFLICT (replica_id) DO UPDATE SET
|
||||||
|
unique_workspaces_count = EXCLUDED.unique_workspaces_count,
|
||||||
|
unique_users_count = EXCLUDED.unique_users_count,
|
||||||
|
allowed_requests = EXCLUDED.allowed_requests,
|
||||||
|
denied_requests = EXCLUDED.denied_requests,
|
||||||
|
updated_at = NOW()
|
||||||
|
RETURNING (xmax = 0) AS new_period;
|
||||||
|
|
||||||
|
-- name: GetBoundaryUsageSummary :one
|
||||||
|
-- Aggregates boundary usage statistics across all replicas. Filters to only
|
||||||
|
-- include data where window_start is within the given interval to exclude
|
||||||
|
-- stale data.
|
||||||
|
SELECT
|
||||||
|
COALESCE(SUM(unique_workspaces_count), 0)::bigint AS unique_workspaces,
|
||||||
|
COALESCE(SUM(unique_users_count), 0)::bigint AS unique_users,
|
||||||
|
COALESCE(SUM(allowed_requests), 0)::bigint AS allowed_requests,
|
||||||
|
COALESCE(SUM(denied_requests), 0)::bigint AS denied_requests
|
||||||
|
FROM boundary_usage_stats
|
||||||
|
WHERE window_start >= NOW() - (@max_staleness_ms::bigint || ' ms')::interval;
|
||||||
|
|
||||||
|
-- name: ResetBoundaryUsageStats :exec
|
||||||
|
-- Deletes all boundary usage statistics. Called after telemetry reports the
|
||||||
|
-- aggregated stats. Each replica will insert a fresh row on its next flush.
|
||||||
|
DELETE FROM boundary_usage_stats;
|
||||||
|
|
||||||
|
-- name: DeleteBoundaryUsageStatsByReplicaID :exec
|
||||||
|
-- Deletes boundary usage statistics for a specific replica.
|
||||||
|
DELETE FROM boundary_usage_stats WHERE replica_id = @replica_id;
|
||||||
@@ -13,6 +13,7 @@ const (
|
|||||||
UniqueAibridgeUserPromptsPkey UniqueConstraint = "aibridge_user_prompts_pkey" // ALTER TABLE ONLY aibridge_user_prompts ADD CONSTRAINT aibridge_user_prompts_pkey PRIMARY KEY (id);
|
UniqueAibridgeUserPromptsPkey UniqueConstraint = "aibridge_user_prompts_pkey" // ALTER TABLE ONLY aibridge_user_prompts ADD CONSTRAINT aibridge_user_prompts_pkey PRIMARY KEY (id);
|
||||||
UniqueAPIKeysPkey UniqueConstraint = "api_keys_pkey" // ALTER TABLE ONLY api_keys ADD CONSTRAINT api_keys_pkey PRIMARY KEY (id);
|
UniqueAPIKeysPkey UniqueConstraint = "api_keys_pkey" // ALTER TABLE ONLY api_keys ADD CONSTRAINT api_keys_pkey PRIMARY KEY (id);
|
||||||
UniqueAuditLogsPkey UniqueConstraint = "audit_logs_pkey" // ALTER TABLE ONLY audit_logs ADD CONSTRAINT audit_logs_pkey PRIMARY KEY (id);
|
UniqueAuditLogsPkey UniqueConstraint = "audit_logs_pkey" // ALTER TABLE ONLY audit_logs ADD CONSTRAINT audit_logs_pkey PRIMARY KEY (id);
|
||||||
|
UniqueBoundaryUsageStatsPkey UniqueConstraint = "boundary_usage_stats_pkey" // ALTER TABLE ONLY boundary_usage_stats ADD CONSTRAINT boundary_usage_stats_pkey PRIMARY KEY (replica_id);
|
||||||
UniqueConnectionLogsPkey UniqueConstraint = "connection_logs_pkey" // ALTER TABLE ONLY connection_logs ADD CONSTRAINT connection_logs_pkey PRIMARY KEY (id);
|
UniqueConnectionLogsPkey UniqueConstraint = "connection_logs_pkey" // ALTER TABLE ONLY connection_logs ADD CONSTRAINT connection_logs_pkey PRIMARY KEY (id);
|
||||||
UniqueCryptoKeysPkey UniqueConstraint = "crypto_keys_pkey" // ALTER TABLE ONLY crypto_keys ADD CONSTRAINT crypto_keys_pkey PRIMARY KEY (feature, sequence);
|
UniqueCryptoKeysPkey UniqueConstraint = "crypto_keys_pkey" // ALTER TABLE ONLY crypto_keys ADD CONSTRAINT crypto_keys_pkey PRIMARY KEY (feature, sequence);
|
||||||
UniqueCustomRolesUniqueKey UniqueConstraint = "custom_roles_unique_key" // ALTER TABLE ONLY custom_roles ADD CONSTRAINT custom_roles_unique_key UNIQUE (name, organization_id);
|
UniqueCustomRolesUniqueKey UniqueConstraint = "custom_roles_unique_key" // ALTER TABLE ONLY custom_roles ADD CONSTRAINT custom_roles_unique_key UNIQUE (name, organization_id);
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ const (
|
|||||||
SubjectTypeUsagePublisher SubjectType = "usage_publisher"
|
SubjectTypeUsagePublisher SubjectType = "usage_publisher"
|
||||||
SubjectAibridged SubjectType = "aibridged"
|
SubjectAibridged SubjectType = "aibridged"
|
||||||
SubjectTypeDBPurge SubjectType = "dbpurge"
|
SubjectTypeDBPurge SubjectType = "dbpurge"
|
||||||
|
SubjectTypeBoundaryUsageTracker SubjectType = "boundary_usage_tracker"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -63,6 +63,15 @@ var (
|
|||||||
Type: "audit_log",
|
Type: "audit_log",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResourceBoundaryUsage
|
||||||
|
// Valid Actions
|
||||||
|
// - "ActionDelete" :: delete boundary usage statistics
|
||||||
|
// - "ActionRead" :: read boundary usage statistics
|
||||||
|
// - "ActionUpdate" :: upsert boundary usage statistics
|
||||||
|
ResourceBoundaryUsage = Object{
|
||||||
|
Type: "boundary_usage",
|
||||||
|
}
|
||||||
|
|
||||||
// ResourceConnectionLog
|
// ResourceConnectionLog
|
||||||
// Valid Actions
|
// Valid Actions
|
||||||
// - "ActionRead" :: read connection logs
|
// - "ActionRead" :: read connection logs
|
||||||
@@ -417,6 +426,7 @@ func AllResources() []Objecter {
|
|||||||
ResourceAssignOrgRole,
|
ResourceAssignOrgRole,
|
||||||
ResourceAssignRole,
|
ResourceAssignRole,
|
||||||
ResourceAuditLog,
|
ResourceAuditLog,
|
||||||
|
ResourceBoundaryUsage,
|
||||||
ResourceConnectionLog,
|
ResourceConnectionLog,
|
||||||
ResourceCryptoKey,
|
ResourceCryptoKey,
|
||||||
ResourceDebugInfo,
|
ResourceDebugInfo,
|
||||||
|
|||||||
@@ -380,4 +380,11 @@ var RBACPermissions = map[string]PermissionDefinition{
|
|||||||
ActionCreate: "create aibridge interceptions & related records",
|
ActionCreate: "create aibridge interceptions & related records",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"boundary_usage": {
|
||||||
|
Actions: map[Action]ActionDefinition{
|
||||||
|
ActionRead: "read boundary usage statistics",
|
||||||
|
ActionUpdate: "upsert boundary usage statistics",
|
||||||
|
ActionDelete: "delete boundary usage statistics",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
|||||||
// Workspace dormancy and workspace are omitted.
|
// Workspace dormancy and workspace are omitted.
|
||||||
// Workspace is specifically handled based on the opts.NoOwnerWorkspaceExec.
|
// Workspace is specifically handled based on the opts.NoOwnerWorkspaceExec.
|
||||||
// Owners cannot access other users' secrets.
|
// Owners cannot access other users' secrets.
|
||||||
allPermsExcept(ResourceWorkspaceDormant, ResourcePrebuiltWorkspace, ResourceWorkspace, ResourceUserSecret, ResourceUsageEvent),
|
allPermsExcept(ResourceWorkspaceDormant, ResourcePrebuiltWorkspace, ResourceWorkspace, ResourceUserSecret, ResourceUsageEvent, ResourceBoundaryUsage),
|
||||||
// This adds back in the Workspace permissions.
|
// This adds back in the Workspace permissions.
|
||||||
Permissions(map[string][]policy.Action{
|
Permissions(map[string][]policy.Action{
|
||||||
ResourceWorkspace.Type: ownerWorkspaceActions,
|
ResourceWorkspace.Type: ownerWorkspaceActions,
|
||||||
@@ -309,7 +309,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
|||||||
ResourceOauth2App.Type: {policy.ActionRead},
|
ResourceOauth2App.Type: {policy.ActionRead},
|
||||||
ResourceWorkspaceProxy.Type: {policy.ActionRead},
|
ResourceWorkspaceProxy.Type: {policy.ActionRead},
|
||||||
}),
|
}),
|
||||||
User: append(allPermsExcept(ResourceWorkspaceDormant, ResourcePrebuiltWorkspace, ResourceWorkspace, ResourceUser, ResourceOrganizationMember, ResourceOrganizationMember),
|
User: append(allPermsExcept(ResourceWorkspaceDormant, ResourcePrebuiltWorkspace, ResourceWorkspace, ResourceUser, ResourceOrganizationMember, ResourceOrganizationMember, ResourceBoundaryUsage),
|
||||||
Permissions(map[string][]policy.Action{
|
Permissions(map[string][]policy.Action{
|
||||||
// Users cannot do create/update/delete on themselves, but they
|
// Users cannot do create/update/delete on themselves, but they
|
||||||
// can read their own details.
|
// can read their own details.
|
||||||
@@ -433,7 +433,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
|||||||
ByOrgID: map[string]OrgPermissions{
|
ByOrgID: map[string]OrgPermissions{
|
||||||
// Org admins should not have workspace exec perms.
|
// Org admins should not have workspace exec perms.
|
||||||
organizationID.String(): {
|
organizationID.String(): {
|
||||||
Org: append(allPermsExcept(ResourceWorkspace, ResourceWorkspaceDormant, ResourcePrebuiltWorkspace, ResourceAssignRole, ResourceUserSecret), Permissions(map[string][]policy.Action{
|
Org: append(allPermsExcept(ResourceWorkspace, ResourceWorkspaceDormant, ResourcePrebuiltWorkspace, ResourceAssignRole, ResourceUserSecret, ResourceBoundaryUsage), Permissions(map[string][]policy.Action{
|
||||||
ResourceWorkspaceDormant.Type: {policy.ActionRead, policy.ActionDelete, policy.ActionCreate, policy.ActionUpdate, policy.ActionWorkspaceStop, policy.ActionCreateAgent, policy.ActionDeleteAgent},
|
ResourceWorkspaceDormant.Type: {policy.ActionRead, policy.ActionDelete, policy.ActionCreate, policy.ActionUpdate, policy.ActionWorkspaceStop, policy.ActionCreateAgent, policy.ActionDeleteAgent},
|
||||||
ResourceWorkspace.Type: slice.Omit(ResourceWorkspace.AvailableActions(), policy.ActionApplicationConnect, policy.ActionSSH),
|
ResourceWorkspace.Type: slice.Omit(ResourceWorkspace.AvailableActions(), policy.ActionApplicationConnect, policy.ActionSSH),
|
||||||
// PrebuiltWorkspaces are a subset of Workspaces.
|
// PrebuiltWorkspaces are a subset of Workspaces.
|
||||||
|
|||||||
@@ -1003,6 +1003,14 @@ func TestRolePermissions(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "BoundaryUsage",
|
||||||
|
Actions: []policy.Action{policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
|
||||||
|
Resource: rbac.ResourceBoundaryUsage,
|
||||||
|
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||||
|
false: {owner, setOtherOrg, setOrgNotMe, memberMe, templateAdmin, userAdmin},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// We expect every permission to be tested above.
|
// We expect every permission to be tested above.
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ const (
|
|||||||
ScopeAssignRoleUnassign ScopeName = "assign_role:unassign"
|
ScopeAssignRoleUnassign ScopeName = "assign_role:unassign"
|
||||||
ScopeAuditLogCreate ScopeName = "audit_log:create"
|
ScopeAuditLogCreate ScopeName = "audit_log:create"
|
||||||
ScopeAuditLogRead ScopeName = "audit_log:read"
|
ScopeAuditLogRead ScopeName = "audit_log:read"
|
||||||
|
ScopeBoundaryUsageDelete ScopeName = "boundary_usage:delete"
|
||||||
|
ScopeBoundaryUsageRead ScopeName = "boundary_usage:read"
|
||||||
|
ScopeBoundaryUsageUpdate ScopeName = "boundary_usage:update"
|
||||||
ScopeConnectionLogRead ScopeName = "connection_log:read"
|
ScopeConnectionLogRead ScopeName = "connection_log:read"
|
||||||
ScopeConnectionLogUpdate ScopeName = "connection_log:update"
|
ScopeConnectionLogUpdate ScopeName = "connection_log:update"
|
||||||
ScopeCryptoKeyCreate ScopeName = "crypto_key:create"
|
ScopeCryptoKeyCreate ScopeName = "crypto_key:create"
|
||||||
@@ -180,6 +183,9 @@ func (e ScopeName) Valid() bool {
|
|||||||
ScopeAssignRoleUnassign,
|
ScopeAssignRoleUnassign,
|
||||||
ScopeAuditLogCreate,
|
ScopeAuditLogCreate,
|
||||||
ScopeAuditLogRead,
|
ScopeAuditLogRead,
|
||||||
|
ScopeBoundaryUsageDelete,
|
||||||
|
ScopeBoundaryUsageRead,
|
||||||
|
ScopeBoundaryUsageUpdate,
|
||||||
ScopeConnectionLogRead,
|
ScopeConnectionLogRead,
|
||||||
ScopeConnectionLogUpdate,
|
ScopeConnectionLogUpdate,
|
||||||
ScopeCryptoKeyCreate,
|
ScopeCryptoKeyCreate,
|
||||||
@@ -336,6 +342,9 @@ func AllScopeNameValues() []ScopeName {
|
|||||||
ScopeAssignRoleUnassign,
|
ScopeAssignRoleUnassign,
|
||||||
ScopeAuditLogCreate,
|
ScopeAuditLogCreate,
|
||||||
ScopeAuditLogRead,
|
ScopeAuditLogRead,
|
||||||
|
ScopeBoundaryUsageDelete,
|
||||||
|
ScopeBoundaryUsageRead,
|
||||||
|
ScopeBoundaryUsageUpdate,
|
||||||
ScopeConnectionLogRead,
|
ScopeConnectionLogRead,
|
||||||
ScopeConnectionLogUpdate,
|
ScopeConnectionLogUpdate,
|
||||||
ScopeCryptoKeyCreate,
|
ScopeCryptoKeyCreate,
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ const (
|
|||||||
APIKeyScopeAuditLogAll APIKeyScope = "audit_log:*"
|
APIKeyScopeAuditLogAll APIKeyScope = "audit_log:*"
|
||||||
APIKeyScopeAuditLogCreate APIKeyScope = "audit_log:create"
|
APIKeyScopeAuditLogCreate APIKeyScope = "audit_log:create"
|
||||||
APIKeyScopeAuditLogRead APIKeyScope = "audit_log:read"
|
APIKeyScopeAuditLogRead APIKeyScope = "audit_log:read"
|
||||||
|
APIKeyScopeBoundaryUsageAll APIKeyScope = "boundary_usage:*"
|
||||||
|
APIKeyScopeBoundaryUsageDelete APIKeyScope = "boundary_usage:delete"
|
||||||
|
APIKeyScopeBoundaryUsageRead APIKeyScope = "boundary_usage:read"
|
||||||
|
APIKeyScopeBoundaryUsageUpdate APIKeyScope = "boundary_usage:update"
|
||||||
APIKeyScopeCoderAll APIKeyScope = "coder:all"
|
APIKeyScopeCoderAll APIKeyScope = "coder:all"
|
||||||
APIKeyScopeCoderApikeysManageSelf APIKeyScope = "coder:apikeys.manage_self"
|
APIKeyScopeCoderApikeysManageSelf APIKeyScope = "coder:apikeys.manage_self"
|
||||||
APIKeyScopeCoderApplicationConnect APIKeyScope = "coder:application_connect"
|
APIKeyScopeCoderApplicationConnect APIKeyScope = "coder:application_connect"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const (
|
|||||||
ResourceAssignOrgRole RBACResource = "assign_org_role"
|
ResourceAssignOrgRole RBACResource = "assign_org_role"
|
||||||
ResourceAssignRole RBACResource = "assign_role"
|
ResourceAssignRole RBACResource = "assign_role"
|
||||||
ResourceAuditLog RBACResource = "audit_log"
|
ResourceAuditLog RBACResource = "audit_log"
|
||||||
|
ResourceBoundaryUsage RBACResource = "boundary_usage"
|
||||||
ResourceConnectionLog RBACResource = "connection_log"
|
ResourceConnectionLog RBACResource = "connection_log"
|
||||||
ResourceCryptoKey RBACResource = "crypto_key"
|
ResourceCryptoKey RBACResource = "crypto_key"
|
||||||
ResourceDebugInfo RBACResource = "debug_info"
|
ResourceDebugInfo RBACResource = "debug_info"
|
||||||
@@ -79,6 +80,7 @@ var RBACResourceActions = map[RBACResource][]RBACAction{
|
|||||||
ResourceAssignOrgRole: {ActionAssign, ActionCreate, ActionDelete, ActionRead, ActionUnassign, ActionUpdate},
|
ResourceAssignOrgRole: {ActionAssign, ActionCreate, ActionDelete, ActionRead, ActionUnassign, ActionUpdate},
|
||||||
ResourceAssignRole: {ActionAssign, ActionRead, ActionUnassign},
|
ResourceAssignRole: {ActionAssign, ActionRead, ActionUnassign},
|
||||||
ResourceAuditLog: {ActionCreate, ActionRead},
|
ResourceAuditLog: {ActionCreate, ActionRead},
|
||||||
|
ResourceBoundaryUsage: {ActionDelete, ActionRead, ActionUpdate},
|
||||||
ResourceConnectionLog: {ActionRead, ActionUpdate},
|
ResourceConnectionLog: {ActionRead, ActionUpdate},
|
||||||
ResourceCryptoKey: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
ResourceCryptoKey: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||||
ResourceDebugInfo: {ActionRead},
|
ResourceDebugInfo: {ActionRead},
|
||||||
|
|||||||
Generated
+20
-20
@@ -172,10 +172,10 @@ Status Code **200**
|
|||||||
|
|
||||||
#### Enumerated Values
|
#### Enumerated Values
|
||||||
|
|
||||||
| Property | Value(s) |
|
| Property | Value(s) |
|
||||||
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
||||||
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `boundary_usage`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
||||||
|
|
||||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||||
|
|
||||||
@@ -305,10 +305,10 @@ Status Code **200**
|
|||||||
|
|
||||||
#### Enumerated Values
|
#### Enumerated Values
|
||||||
|
|
||||||
| Property | Value(s) |
|
| Property | Value(s) |
|
||||||
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
||||||
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `boundary_usage`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
||||||
|
|
||||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||||
|
|
||||||
@@ -438,10 +438,10 @@ Status Code **200**
|
|||||||
|
|
||||||
#### Enumerated Values
|
#### Enumerated Values
|
||||||
|
|
||||||
| Property | Value(s) |
|
| Property | Value(s) |
|
||||||
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
||||||
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `boundary_usage`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
||||||
|
|
||||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||||
|
|
||||||
@@ -533,10 +533,10 @@ Status Code **200**
|
|||||||
|
|
||||||
#### Enumerated Values
|
#### Enumerated Values
|
||||||
|
|
||||||
| Property | Value(s) |
|
| Property | Value(s) |
|
||||||
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
||||||
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `boundary_usage`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
||||||
|
|
||||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||||
|
|
||||||
@@ -850,9 +850,9 @@ Status Code **200**
|
|||||||
|
|
||||||
#### Enumerated Values
|
#### Enumerated Values
|
||||||
|
|
||||||
| Property | Value(s) |
|
| Property | Value(s) |
|
||||||
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
| `action` | `application_connect`, `assign`, `create`, `create_agent`, `delete`, `delete_agent`, `read`, `read_personal`, `share`, `ssh`, `start`, `stop`, `unassign`, `update`, `update_personal`, `use`, `view_insights` |
|
||||||
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
| `resource_type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `boundary_usage`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
||||||
|
|
||||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||||
|
|||||||
Generated
+6
-6
@@ -862,9 +862,9 @@
|
|||||||
|
|
||||||
#### Enumerated Values
|
#### Enumerated Values
|
||||||
|
|
||||||
| Value(s) |
|
| Value(s) |
|
||||||
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `aibridge_interception:*`, `aibridge_interception:create`, `aibridge_interception:read`, `aibridge_interception:update`, `all`, `api_key:*`, `api_key:create`, `api_key:delete`, `api_key:read`, `api_key:update`, `application_connect`, `assign_org_role:*`, `assign_org_role:assign`, `assign_org_role:create`, `assign_org_role:delete`, `assign_org_role:read`, `assign_org_role:unassign`, `assign_org_role:update`, `assign_role:*`, `assign_role:assign`, `assign_role:read`, `assign_role:unassign`, `audit_log:*`, `audit_log:create`, `audit_log:read`, `coder:all`, `coder:apikeys.manage_self`, `coder:application_connect`, `coder:templates.author`, `coder:templates.build`, `coder:workspaces.access`, `coder:workspaces.create`, `coder:workspaces.delete`, `coder:workspaces.operate`, `connection_log:*`, `connection_log:read`, `connection_log:update`, `crypto_key:*`, `crypto_key:create`, `crypto_key:delete`, `crypto_key:read`, `crypto_key:update`, `debug_info:*`, `debug_info:read`, `deployment_config:*`, `deployment_config:read`, `deployment_config:update`, `deployment_stats:*`, `deployment_stats:read`, `file:*`, `file:create`, `file:read`, `group:*`, `group:create`, `group:delete`, `group:read`, `group:update`, `group_member:*`, `group_member:read`, `idpsync_settings:*`, `idpsync_settings:read`, `idpsync_settings:update`, `inbox_notification:*`, `inbox_notification:create`, `inbox_notification:read`, `inbox_notification:update`, `license:*`, `license:create`, `license:delete`, `license:read`, `notification_message:*`, `notification_message:create`, `notification_message:delete`, `notification_message:read`, `notification_message:update`, `notification_preference:*`, `notification_preference:read`, `notification_preference:update`, `notification_template:*`, `notification_template:read`, `notification_template:update`, `oauth2_app:*`, `oauth2_app:create`, `oauth2_app:delete`, `oauth2_app:read`, `oauth2_app:update`, `oauth2_app_code_token:*`, `oauth2_app_code_token:create`, `oauth2_app_code_token:delete`, `oauth2_app_code_token:read`, `oauth2_app_secret:*`, `oauth2_app_secret:create`, `oauth2_app_secret:delete`, `oauth2_app_secret:read`, `oauth2_app_secret:update`, `organization:*`, `organization:create`, `organization:delete`, `organization:read`, `organization:update`, `organization_member:*`, `organization_member:create`, `organization_member:delete`, `organization_member:read`, `organization_member:update`, `prebuilt_workspace:*`, `prebuilt_workspace:delete`, `prebuilt_workspace:update`, `provisioner_daemon:*`, `provisioner_daemon:create`, `provisioner_daemon:delete`, `provisioner_daemon:read`, `provisioner_daemon:update`, `provisioner_jobs:*`, `provisioner_jobs:create`, `provisioner_jobs:read`, `provisioner_jobs:update`, `replicas:*`, `replicas:read`, `system:*`, `system:create`, `system:delete`, `system:read`, `system:update`, `tailnet_coordinator:*`, `tailnet_coordinator:create`, `tailnet_coordinator:delete`, `tailnet_coordinator:read`, `tailnet_coordinator:update`, `task:*`, `task:create`, `task:delete`, `task:read`, `task:update`, `template:*`, `template:create`, `template:delete`, `template:read`, `template:update`, `template:use`, `template:view_insights`, `usage_event:*`, `usage_event:create`, `usage_event:read`, `usage_event:update`, `user:*`, `user:create`, `user:delete`, `user:read`, `user:read_personal`, `user:update`, `user:update_personal`, `user_secret:*`, `user_secret:create`, `user_secret:delete`, `user_secret:read`, `user_secret:update`, `webpush_subscription:*`, `webpush_subscription:create`, `webpush_subscription:delete`, `webpush_subscription:read`, `workspace:*`, `workspace:application_connect`, `workspace:create`, `workspace:create_agent`, `workspace:delete`, `workspace:delete_agent`, `workspace:read`, `workspace:share`, `workspace:ssh`, `workspace:start`, `workspace:stop`, `workspace:update`, `workspace_agent_devcontainers:*`, `workspace_agent_devcontainers:create`, `workspace_agent_resource_monitor:*`, `workspace_agent_resource_monitor:create`, `workspace_agent_resource_monitor:read`, `workspace_agent_resource_monitor:update`, `workspace_dormant:*`, `workspace_dormant:application_connect`, `workspace_dormant:create`, `workspace_dormant:create_agent`, `workspace_dormant:delete`, `workspace_dormant:delete_agent`, `workspace_dormant:read`, `workspace_dormant:share`, `workspace_dormant:ssh`, `workspace_dormant:start`, `workspace_dormant:stop`, `workspace_dormant:update`, `workspace_proxy:*`, `workspace_proxy:create`, `workspace_proxy:delete`, `workspace_proxy:read`, `workspace_proxy:update` |
|
| `aibridge_interception:*`, `aibridge_interception:create`, `aibridge_interception:read`, `aibridge_interception:update`, `all`, `api_key:*`, `api_key:create`, `api_key:delete`, `api_key:read`, `api_key:update`, `application_connect`, `assign_org_role:*`, `assign_org_role:assign`, `assign_org_role:create`, `assign_org_role:delete`, `assign_org_role:read`, `assign_org_role:unassign`, `assign_org_role:update`, `assign_role:*`, `assign_role:assign`, `assign_role:read`, `assign_role:unassign`, `audit_log:*`, `audit_log:create`, `audit_log:read`, `boundary_usage:*`, `boundary_usage:delete`, `boundary_usage:read`, `boundary_usage:update`, `coder:all`, `coder:apikeys.manage_self`, `coder:application_connect`, `coder:templates.author`, `coder:templates.build`, `coder:workspaces.access`, `coder:workspaces.create`, `coder:workspaces.delete`, `coder:workspaces.operate`, `connection_log:*`, `connection_log:read`, `connection_log:update`, `crypto_key:*`, `crypto_key:create`, `crypto_key:delete`, `crypto_key:read`, `crypto_key:update`, `debug_info:*`, `debug_info:read`, `deployment_config:*`, `deployment_config:read`, `deployment_config:update`, `deployment_stats:*`, `deployment_stats:read`, `file:*`, `file:create`, `file:read`, `group:*`, `group:create`, `group:delete`, `group:read`, `group:update`, `group_member:*`, `group_member:read`, `idpsync_settings:*`, `idpsync_settings:read`, `idpsync_settings:update`, `inbox_notification:*`, `inbox_notification:create`, `inbox_notification:read`, `inbox_notification:update`, `license:*`, `license:create`, `license:delete`, `license:read`, `notification_message:*`, `notification_message:create`, `notification_message:delete`, `notification_message:read`, `notification_message:update`, `notification_preference:*`, `notification_preference:read`, `notification_preference:update`, `notification_template:*`, `notification_template:read`, `notification_template:update`, `oauth2_app:*`, `oauth2_app:create`, `oauth2_app:delete`, `oauth2_app:read`, `oauth2_app:update`, `oauth2_app_code_token:*`, `oauth2_app_code_token:create`, `oauth2_app_code_token:delete`, `oauth2_app_code_token:read`, `oauth2_app_secret:*`, `oauth2_app_secret:create`, `oauth2_app_secret:delete`, `oauth2_app_secret:read`, `oauth2_app_secret:update`, `organization:*`, `organization:create`, `organization:delete`, `organization:read`, `organization:update`, `organization_member:*`, `organization_member:create`, `organization_member:delete`, `organization_member:read`, `organization_member:update`, `prebuilt_workspace:*`, `prebuilt_workspace:delete`, `prebuilt_workspace:update`, `provisioner_daemon:*`, `provisioner_daemon:create`, `provisioner_daemon:delete`, `provisioner_daemon:read`, `provisioner_daemon:update`, `provisioner_jobs:*`, `provisioner_jobs:create`, `provisioner_jobs:read`, `provisioner_jobs:update`, `replicas:*`, `replicas:read`, `system:*`, `system:create`, `system:delete`, `system:read`, `system:update`, `tailnet_coordinator:*`, `tailnet_coordinator:create`, `tailnet_coordinator:delete`, `tailnet_coordinator:read`, `tailnet_coordinator:update`, `task:*`, `task:create`, `task:delete`, `task:read`, `task:update`, `template:*`, `template:create`, `template:delete`, `template:read`, `template:update`, `template:use`, `template:view_insights`, `usage_event:*`, `usage_event:create`, `usage_event:read`, `usage_event:update`, `user:*`, `user:create`, `user:delete`, `user:read`, `user:read_personal`, `user:update`, `user:update_personal`, `user_secret:*`, `user_secret:create`, `user_secret:delete`, `user_secret:read`, `user_secret:update`, `webpush_subscription:*`, `webpush_subscription:create`, `webpush_subscription:delete`, `webpush_subscription:read`, `workspace:*`, `workspace:application_connect`, `workspace:create`, `workspace:create_agent`, `workspace:delete`, `workspace:delete_agent`, `workspace:read`, `workspace:share`, `workspace:ssh`, `workspace:start`, `workspace:stop`, `workspace:update`, `workspace_agent_devcontainers:*`, `workspace_agent_devcontainers:create`, `workspace_agent_resource_monitor:*`, `workspace_agent_resource_monitor:create`, `workspace_agent_resource_monitor:read`, `workspace_agent_resource_monitor:update`, `workspace_dormant:*`, `workspace_dormant:application_connect`, `workspace_dormant:create`, `workspace_dormant:create_agent`, `workspace_dormant:delete`, `workspace_dormant:delete_agent`, `workspace_dormant:read`, `workspace_dormant:share`, `workspace_dormant:ssh`, `workspace_dormant:start`, `workspace_dormant:stop`, `workspace_dormant:update`, `workspace_proxy:*`, `workspace_proxy:create`, `workspace_proxy:delete`, `workspace_proxy:read`, `workspace_proxy:update` |
|
||||||
|
|
||||||
## codersdk.AddLicenseRequest
|
## codersdk.AddLicenseRequest
|
||||||
|
|
||||||
@@ -7060,9 +7060,9 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|
|||||||
|
|
||||||
#### Enumerated Values
|
#### Enumerated Values
|
||||||
|
|
||||||
| Value(s) |
|
| Value(s) |
|
||||||
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
| `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `boundary_usage`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
||||||
|
|
||||||
## codersdk.RateLimitConfig
|
## codersdk.RateLimitConfig
|
||||||
|
|
||||||
|
|||||||
Generated
+5
-5
@@ -810,11 +810,11 @@ Status Code **200**
|
|||||||
|
|
||||||
#### Enumerated Values
|
#### Enumerated Values
|
||||||
|
|
||||||
| Property | Value(s) |
|
| Property | Value(s) |
|
||||||
|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
| `type` | `*`, `aibridge_interception`, `api_key`, `assign_org_role`, `assign_role`, `audit_log`, `boundary_usage`, `connection_log`, `crypto_key`, `debug_info`, `deployment_config`, `deployment_stats`, `file`, `group`, `group_member`, `idpsync_settings`, `inbox_notification`, `license`, `notification_message`, `notification_preference`, `notification_template`, `oauth2_app`, `oauth2_app_code_token`, `oauth2_app_secret`, `organization`, `organization_member`, `prebuilt_workspace`, `provisioner_daemon`, `provisioner_jobs`, `replicas`, `system`, `tailnet_coordinator`, `task`, `template`, `usage_event`, `user`, `user_secret`, `webpush_subscription`, `workspace`, `workspace_agent_devcontainers`, `workspace_agent_resource_monitor`, `workspace_dormant`, `workspace_proxy` |
|
||||||
| `login_type` | `github`, `oidc`, `password`, `token` |
|
| `login_type` | `github`, `oidc`, `password`, `token` |
|
||||||
| `scope` | `all`, `application_connect` |
|
| `scope` | `all`, `application_connect` |
|
||||||
|
|
||||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ export const RBACResourceActions: Partial<
|
|||||||
create: "create new audit log entries",
|
create: "create new audit log entries",
|
||||||
read: "read audit logs",
|
read: "read audit logs",
|
||||||
},
|
},
|
||||||
|
boundary_usage: {
|
||||||
|
delete: "delete boundary usage statistics",
|
||||||
|
read: "read boundary usage statistics",
|
||||||
|
update: "upsert boundary usage statistics",
|
||||||
|
},
|
||||||
connection_log: {
|
connection_log: {
|
||||||
read: "read connection logs",
|
read: "read connection logs",
|
||||||
update: "upsert connection log entries",
|
update: "upsert connection log entries",
|
||||||
|
|||||||
Generated
+10
@@ -189,6 +189,10 @@ export type APIKeyScope =
|
|||||||
| "audit_log:*"
|
| "audit_log:*"
|
||||||
| "audit_log:create"
|
| "audit_log:create"
|
||||||
| "audit_log:read"
|
| "audit_log:read"
|
||||||
|
| "boundary_usage:*"
|
||||||
|
| "boundary_usage:delete"
|
||||||
|
| "boundary_usage:read"
|
||||||
|
| "boundary_usage:update"
|
||||||
| "coder:all"
|
| "coder:all"
|
||||||
| "coder:apikeys.manage_self"
|
| "coder:apikeys.manage_self"
|
||||||
| "coder:application_connect"
|
| "coder:application_connect"
|
||||||
@@ -387,6 +391,10 @@ export const APIKeyScopes: APIKeyScope[] = [
|
|||||||
"audit_log:*",
|
"audit_log:*",
|
||||||
"audit_log:create",
|
"audit_log:create",
|
||||||
"audit_log:read",
|
"audit_log:read",
|
||||||
|
"boundary_usage:*",
|
||||||
|
"boundary_usage:delete",
|
||||||
|
"boundary_usage:read",
|
||||||
|
"boundary_usage:update",
|
||||||
"coder:all",
|
"coder:all",
|
||||||
"coder:apikeys.manage_self",
|
"coder:apikeys.manage_self",
|
||||||
"coder:application_connect",
|
"coder:application_connect",
|
||||||
@@ -4057,6 +4065,7 @@ export type RBACResource =
|
|||||||
| "assign_org_role"
|
| "assign_org_role"
|
||||||
| "assign_role"
|
| "assign_role"
|
||||||
| "audit_log"
|
| "audit_log"
|
||||||
|
| "boundary_usage"
|
||||||
| "connection_log"
|
| "connection_log"
|
||||||
| "crypto_key"
|
| "crypto_key"
|
||||||
| "debug_info"
|
| "debug_info"
|
||||||
@@ -4101,6 +4110,7 @@ export const RBACResources: RBACResource[] = [
|
|||||||
"assign_org_role",
|
"assign_org_role",
|
||||||
"assign_role",
|
"assign_role",
|
||||||
"audit_log",
|
"audit_log",
|
||||||
|
"boundary_usage",
|
||||||
"connection_log",
|
"connection_log",
|
||||||
"crypto_key",
|
"crypto_key",
|
||||||
"debug_info",
|
"debug_info",
|
||||||
|
|||||||
Reference in New Issue
Block a user