@eduardbar/drift 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gga +50 -0
- package/.github/actions/drift-review/README.md +60 -0
- package/.github/actions/drift-review/action.yml +131 -0
- package/.github/actions/drift-scan/README.md +28 -32
- package/.github/actions/drift-scan/action.yml +78 -14
- package/.github/workflows/review-pr.yml +34 -41
- package/AGENTS.md +75 -251
- package/CHANGELOG.md +28 -0
- package/README.md +148 -41
- package/dist/benchmark.d.ts +1 -1
- package/dist/benchmark.js +71 -52
- package/dist/cli.js +243 -8
- package/dist/config.js +16 -2
- package/dist/diff.js +42 -50
- package/dist/doctor.d.ts +5 -0
- package/dist/doctor.js +133 -0
- package/dist/format.d.ts +17 -0
- package/dist/format.js +45 -0
- package/dist/guard-types.d.ts +57 -0
- package/dist/guard-types.js +2 -0
- package/dist/guard.d.ts +14 -0
- package/dist/guard.js +239 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.js +4 -1
- package/dist/init.d.ts +15 -0
- package/dist/init.js +273 -0
- package/dist/map-cycles.d.ts +2 -0
- package/dist/map-cycles.js +34 -0
- package/dist/map-svg.d.ts +19 -0
- package/dist/map-svg.js +97 -0
- package/dist/map.js +78 -138
- package/dist/metrics.js +70 -55
- package/dist/output-metadata.d.ts +13 -0
- package/dist/output-metadata.js +17 -0
- package/dist/plugins-capabilities.d.ts +4 -0
- package/dist/plugins-capabilities.js +21 -0
- package/dist/plugins-messages.d.ts +10 -0
- package/dist/plugins-messages.js +16 -0
- package/dist/plugins-rules.d.ts +9 -0
- package/dist/plugins-rules.js +137 -0
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +45 -142
- package/dist/reporter-constants.d.ts +16 -0
- package/dist/reporter-constants.js +39 -0
- package/dist/reporter.d.ts +3 -3
- package/dist/reporter.js +35 -55
- package/dist/review.d.ts +2 -1
- package/dist/review.js +2 -1
- package/dist/rules/phase3-configurable.js +23 -15
- package/dist/saas/constants.d.ts +15 -0
- package/dist/saas/constants.js +48 -0
- package/dist/saas/dashboard.d.ts +8 -0
- package/dist/saas/dashboard.js +132 -0
- package/dist/saas/errors.d.ts +19 -0
- package/dist/saas/errors.js +37 -0
- package/dist/saas/helpers.d.ts +21 -0
- package/dist/saas/helpers.js +110 -0
- package/dist/saas/ingest.d.ts +3 -0
- package/dist/saas/ingest.js +249 -0
- package/dist/saas/organization.d.ts +5 -0
- package/dist/saas/organization.js +82 -0
- package/dist/saas/plan-change.d.ts +10 -0
- package/dist/saas/plan-change.js +15 -0
- package/dist/saas/store.d.ts +21 -0
- package/dist/saas/store.js +159 -0
- package/dist/saas/types.d.ts +191 -0
- package/dist/saas/types.js +2 -0
- package/dist/saas.d.ts +8 -218
- package/dist/saas.js +7 -761
- package/dist/sarif.d.ts +74 -0
- package/dist/sarif.js +122 -0
- package/dist/trust-advanced.d.ts +14 -0
- package/dist/trust-advanced.js +65 -0
- package/dist/trust-kpi-fs.d.ts +3 -0
- package/dist/trust-kpi-fs.js +141 -0
- package/dist/trust-kpi-parse.d.ts +7 -0
- package/dist/trust-kpi-parse.js +186 -0
- package/dist/trust-kpi-types.d.ts +16 -0
- package/dist/trust-kpi-types.js +2 -0
- package/dist/trust-kpi.d.ts +1 -3
- package/dist/trust-kpi.js +6 -266
- package/dist/trust-policy.d.ts +32 -0
- package/dist/trust-policy.js +160 -0
- package/dist/trust-render.d.ts +9 -0
- package/dist/trust-render.js +54 -0
- package/dist/trust-scoring.d.ts +9 -0
- package/dist/trust-scoring.js +208 -0
- package/dist/trust.d.ts +4 -32
- package/dist/trust.js +29 -432
- package/dist/types/app.d.ts +30 -0
- package/dist/types/app.js +2 -0
- package/dist/types/config.d.ts +25 -0
- package/dist/types/config.js +2 -0
- package/dist/types/core.d.ts +100 -0
- package/dist/types/core.js +2 -0
- package/dist/types/diff.d.ts +55 -0
- package/dist/types/diff.js +2 -0
- package/dist/types/plugin.d.ts +41 -0
- package/dist/types/plugin.js +2 -0
- package/dist/types/trust.d.ts +120 -0
- package/dist/types/trust.js +2 -0
- package/dist/types.d.ts +8 -365
- package/docs/release-notes-draft.md +40 -0
- package/docs/rules-catalog.md +49 -0
- package/docs/trust-core-release-checklist.md +37 -5
- package/package.json +3 -2
- package/packages/vscode-drift/src/code-actions.ts +1 -1
- package/schemas/drift-ai-output.v1.json +162 -0
- package/schemas/drift-report.v1.json +151 -0
- package/schemas/drift-trust.v1.json +131 -0
- package/scripts/smoke-repo.mjs +394 -0
- package/src/benchmark.ts +75 -53
- package/src/cli.ts +285 -13
- package/src/config.ts +19 -2
- package/src/diff.ts +57 -48
- package/src/doctor.ts +173 -0
- package/src/format.ts +81 -0
- package/src/guard-types.ts +64 -0
- package/src/guard.ts +324 -0
- package/src/index.ts +35 -0
- package/src/init.ts +298 -0
- package/src/map-cycles.ts +38 -0
- package/src/map-svg.ts +124 -0
- package/src/map.ts +111 -142
- package/src/metrics.ts +78 -59
- package/src/output-metadata.ts +30 -0
- package/src/plugins-capabilities.ts +36 -0
- package/src/plugins-messages.ts +35 -0
- package/src/plugins-rules.ts +296 -0
- package/src/plugins.ts +76 -283
- package/src/reporter-constants.ts +46 -0
- package/src/reporter.ts +64 -65
- package/src/review.ts +4 -2
- package/src/rules/phase3-configurable.ts +39 -26
- package/src/saas/constants.ts +56 -0
- package/src/saas/dashboard.ts +172 -0
- package/src/saas/errors.ts +45 -0
- package/src/saas/helpers.ts +140 -0
- package/src/saas/ingest.ts +278 -0
- package/src/saas/organization.ts +99 -0
- package/src/saas/plan-change.ts +19 -0
- package/src/saas/store.ts +172 -0
- package/src/saas/types.ts +216 -0
- package/src/saas.ts +49 -1031
- package/src/sarif.ts +232 -0
- package/src/trust-advanced.ts +99 -0
- package/src/trust-kpi-fs.ts +169 -0
- package/src/trust-kpi-parse.ts +219 -0
- package/src/trust-kpi-types.ts +19 -0
- package/src/trust-kpi.ts +8 -316
- package/src/trust-policy.ts +246 -0
- package/src/trust-render.ts +61 -0
- package/src/trust-scoring.ts +231 -0
- package/src/trust.ts +62 -576
- package/src/types/app.ts +30 -0
- package/src/types/config.ts +27 -0
- package/src/types/core.ts +105 -0
- package/src/types/diff.ts +61 -0
- package/src/types/plugin.ts +46 -0
- package/src/types/trust.ts +134 -0
- package/src/types.ts +78 -409
- package/tests/cli-sarif.test.ts +92 -0
- package/tests/format.test.ts +157 -0
- package/tests/new-features.test.ts +10 -2
- package/tests/phase1-init-doctor-guard.test.ts +199 -0
- package/tests/sarif.test.ts +160 -0
- package/tests/trust-kpi.test.ts +31 -4
- package/tests/trust.test.ts +18 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, resolve } from 'node:path'
|
|
3
|
+
import type { SaasEffectiveLimits, SaasOperation, SaasPermissionContext, SaasPermissionResult, SaasPlan, SaasPolicyOverrides, SaasRole, SaasStore, SaasWorkspace } from './types.js'
|
|
4
|
+
import { DEFAULT_ORGANIZATION_ID, REQUIRED_ROLE_BY_OPERATION, ROLE_PRIORITY, STORE_VERSION } from './constants.js'
|
|
5
|
+
import { SaasActorRequiredError, SaasPermissionError } from './errors.js'
|
|
6
|
+
import { hasRoleAtLeast, membershipKey, mergePolicy, normalizePlan, resolveSaasPolicy } from './helpers.js'
|
|
7
|
+
|
|
8
|
+
const HOURS_PER_DAY = 24
|
|
9
|
+
const MINUTES_PER_HOUR = 60
|
|
10
|
+
const SECONDS_PER_MINUTE = 60
|
|
11
|
+
const MILLISECONDS_PER_SECOND = 1000
|
|
12
|
+
|
|
13
|
+
export function defaultSaasStorePath(root = '.'): string {
|
|
14
|
+
return resolve(root, '.drift-cloud', 'store.json')
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createEmptyStore(policy?: SaasPolicyOverrides): SaasStore {
|
|
18
|
+
return {
|
|
19
|
+
version: STORE_VERSION,
|
|
20
|
+
policy: resolveSaasPolicy(policy),
|
|
21
|
+
users: {},
|
|
22
|
+
organizations: {},
|
|
23
|
+
workspaces: {},
|
|
24
|
+
memberships: {},
|
|
25
|
+
repos: {},
|
|
26
|
+
snapshots: [],
|
|
27
|
+
planChanges: [],
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ensureStoreFile(storeFile: string, policy?: SaasPolicyOverrides): void {
|
|
32
|
+
const dir = dirname(storeFile)
|
|
33
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
|
|
34
|
+
if (!existsSync(storeFile)) {
|
|
35
|
+
const initial = createEmptyStore(policy)
|
|
36
|
+
writeFileSync(storeFile, JSON.stringify(initial, null, 2), 'utf8')
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function applyStoreEntityDefaults(store: SaasStore): void {
|
|
41
|
+
for (const workspace of Object.values(store.workspaces)) {
|
|
42
|
+
if (!workspace.organizationId) workspace.organizationId = DEFAULT_ORGANIZATION_ID
|
|
43
|
+
}
|
|
44
|
+
for (const repo of Object.values(store.repos)) {
|
|
45
|
+
if (!repo.organizationId) repo.organizationId = DEFAULT_ORGANIZATION_ID
|
|
46
|
+
}
|
|
47
|
+
for (const snapshot of store.snapshots) {
|
|
48
|
+
if (!snapshot.organizationId) snapshot.organizationId = DEFAULT_ORGANIZATION_ID
|
|
49
|
+
if (!snapshot.plan) snapshot.plan = 'free'
|
|
50
|
+
if (!snapshot.role) snapshot.role = 'member'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function ensureOrganizationFromWorkspace(store: SaasStore, workspace: SaasWorkspace): void {
|
|
55
|
+
const orgId = workspace.organizationId
|
|
56
|
+
const existingOrg = store.organizations[orgId]
|
|
57
|
+
|
|
58
|
+
if (!existingOrg) {
|
|
59
|
+
store.organizations[orgId] = {
|
|
60
|
+
id: orgId,
|
|
61
|
+
plan: 'free',
|
|
62
|
+
createdAt: workspace.createdAt,
|
|
63
|
+
lastSeenAt: workspace.lastSeenAt,
|
|
64
|
+
workspaceIds: [workspace.id],
|
|
65
|
+
}
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!existingOrg.workspaceIds.includes(workspace.id)) existingOrg.workspaceIds.push(workspace.id)
|
|
70
|
+
if (workspace.lastSeenAt > existingOrg.lastSeenAt) existingOrg.lastSeenAt = workspace.lastSeenAt
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function hydrateOrganizationsFromWorkspaces(store: SaasStore): void {
|
|
74
|
+
for (const workspace of Object.values(store.workspaces)) {
|
|
75
|
+
ensureOrganizationFromWorkspace(store, workspace)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function applyRetentionPolicy(store: SaasStore): void {
|
|
80
|
+
const millisecondsPerDay = HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND
|
|
81
|
+
const cutoff = Date.now() - store.policy.retentionDays * millisecondsPerDay
|
|
82
|
+
store.snapshots = store.snapshots.filter((snapshot) => new Date(snapshot.createdAt).getTime() >= cutoff)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function saveStore(storeFile: string, store: SaasStore): void {
|
|
86
|
+
writeFileSync(storeFile, JSON.stringify(store, null, 2), 'utf8')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function loadStoreInternal(storeFile: string, policy?: SaasPolicyOverrides): SaasStore {
|
|
90
|
+
ensureStoreFile(storeFile, policy)
|
|
91
|
+
const raw = readFileSync(storeFile, 'utf8')
|
|
92
|
+
const parsed = JSON.parse(raw) as Partial<SaasStore>
|
|
93
|
+
|
|
94
|
+
const merged = createEmptyStore(parsed.policy)
|
|
95
|
+
merged.version = parsed.version ?? STORE_VERSION
|
|
96
|
+
merged.users = parsed.users ?? {}
|
|
97
|
+
merged.organizations = parsed.organizations ?? {}
|
|
98
|
+
merged.workspaces = parsed.workspaces ?? {}
|
|
99
|
+
merged.memberships = parsed.memberships ?? {}
|
|
100
|
+
merged.repos = parsed.repos ?? {}
|
|
101
|
+
merged.snapshots = parsed.snapshots ?? []
|
|
102
|
+
merged.planChanges = parsed.planChanges ?? []
|
|
103
|
+
merged.policy = mergePolicy(policy, merged.policy)
|
|
104
|
+
|
|
105
|
+
applyStoreEntityDefaults(merged)
|
|
106
|
+
hydrateOrganizationsFromWorkspaces(merged)
|
|
107
|
+
applyRetentionPolicy(merged)
|
|
108
|
+
|
|
109
|
+
return merged
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function resolveActorRole(store: SaasStore, organizationId: string, actorUserId: string, workspaceId?: string): SaasRole | undefined {
|
|
113
|
+
if (workspaceId) {
|
|
114
|
+
const scopedMembershipId = membershipKey(organizationId, workspaceId, actorUserId)
|
|
115
|
+
return store.memberships[scopedMembershipId]?.role
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let highestRole: SaasRole | undefined
|
|
119
|
+
for (const membership of Object.values(store.memberships)) {
|
|
120
|
+
if (membership.organizationId !== organizationId) continue
|
|
121
|
+
if (membership.userId !== actorUserId) continue
|
|
122
|
+
if (!highestRole || ROLE_PRIORITY[membership.role] > ROLE_PRIORITY[highestRole]) highestRole = membership.role
|
|
123
|
+
if (highestRole === 'owner') break
|
|
124
|
+
}
|
|
125
|
+
return highestRole
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function assertPermissionInStore(store: SaasStore, context: SaasPermissionContext): SaasPermissionResult {
|
|
129
|
+
const requiredRole = REQUIRED_ROLE_BY_OPERATION[context.operation]
|
|
130
|
+
if (!context.actorUserId) {
|
|
131
|
+
if (store.policy.strictActorEnforcement) throw new SaasActorRequiredError(context)
|
|
132
|
+
return { requiredRole }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const actorRole = resolveActorRole(store, context.organizationId, context.actorUserId, context.workspaceId)
|
|
136
|
+
if (!hasRoleAtLeast(actorRole, requiredRole)) {
|
|
137
|
+
throw new SaasPermissionError(context, requiredRole, actorRole)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return { requiredRole, actorRole }
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function getRequiredRoleForOperation(operation: SaasOperation): SaasRole {
|
|
144
|
+
return REQUIRED_ROLE_BY_OPERATION[operation]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function assertSaasPermission(
|
|
148
|
+
context: SaasPermissionContext & { storeFile?: string; policy?: SaasPolicyOverrides },
|
|
149
|
+
): SaasPermissionResult {
|
|
150
|
+
const storeFile = resolve(context.storeFile ?? defaultSaasStorePath())
|
|
151
|
+
const store = loadStoreInternal(storeFile, context.policy)
|
|
152
|
+
return assertPermissionInStore(store, context)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function getSaasEffectiveLimits(input: { plan: SaasPlan; policy?: SaasPolicyOverrides }): SaasEffectiveLimits {
|
|
156
|
+
const policy = resolveSaasPolicy(input.policy)
|
|
157
|
+
const plan = normalizePlan(input.plan)
|
|
158
|
+
return {
|
|
159
|
+
plan,
|
|
160
|
+
maxWorkspaces: policy.maxWorkspacesPerOrganizationByPlan[plan],
|
|
161
|
+
maxReposPerWorkspace: policy.maxReposPerWorkspace,
|
|
162
|
+
maxRunsPerWorkspacePerMonth: policy.maxRunsPerWorkspacePerMonth,
|
|
163
|
+
retentionDays: policy.retentionDays,
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function getOrganizationEffectiveLimits(options: { organizationId: string; storeFile?: string; policy?: SaasPolicyOverrides }): SaasEffectiveLimits {
|
|
168
|
+
const storeFile = resolve(options.storeFile ?? defaultSaasStorePath())
|
|
169
|
+
const store = loadStoreInternal(storeFile, options.policy)
|
|
170
|
+
const plan = normalizePlan(store.organizations[options.organizationId]?.plan)
|
|
171
|
+
return getSaasEffectiveLimits({ plan, policy: store.policy })
|
|
172
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import type { DriftConfig, DriftReport } from '../types.js'
|
|
2
|
+
|
|
3
|
+
export interface SaasPolicy {
|
|
4
|
+
freeUserThreshold: number
|
|
5
|
+
maxRunsPerWorkspacePerMonth: number
|
|
6
|
+
maxReposPerWorkspace: number
|
|
7
|
+
retentionDays: number
|
|
8
|
+
strictActorEnforcement: boolean
|
|
9
|
+
maxWorkspacesPerOrganizationByPlan: Record<SaasPlan, number>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type SaasRole = 'owner' | 'member' | 'viewer'
|
|
13
|
+
export type SaasPlan = 'free' | 'sponsor' | 'team' | 'business'
|
|
14
|
+
|
|
15
|
+
export interface SaasUser {
|
|
16
|
+
id: string
|
|
17
|
+
createdAt: string
|
|
18
|
+
lastSeenAt: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface SaasOrganization {
|
|
22
|
+
id: string
|
|
23
|
+
plan: SaasPlan
|
|
24
|
+
createdAt: string
|
|
25
|
+
lastSeenAt: string
|
|
26
|
+
workspaceIds: string[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SaasWorkspace {
|
|
30
|
+
id: string
|
|
31
|
+
organizationId: string
|
|
32
|
+
createdAt: string
|
|
33
|
+
lastSeenAt: string
|
|
34
|
+
userIds: string[]
|
|
35
|
+
repoIds: string[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface SaasRepo {
|
|
39
|
+
id: string
|
|
40
|
+
organizationId: string
|
|
41
|
+
workspaceId: string
|
|
42
|
+
name: string
|
|
43
|
+
createdAt: string
|
|
44
|
+
lastSeenAt: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface SaasMembership {
|
|
48
|
+
id: string
|
|
49
|
+
organizationId: string
|
|
50
|
+
workspaceId: string
|
|
51
|
+
userId: string
|
|
52
|
+
role: SaasRole
|
|
53
|
+
createdAt: string
|
|
54
|
+
lastSeenAt: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface SaasPlanChange {
|
|
58
|
+
id: string
|
|
59
|
+
organizationId: string
|
|
60
|
+
fromPlan: SaasPlan
|
|
61
|
+
toPlan: SaasPlan
|
|
62
|
+
changedAt: string
|
|
63
|
+
changedByUserId: string
|
|
64
|
+
reason?: string
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface SaasSnapshot {
|
|
68
|
+
id: string
|
|
69
|
+
createdAt: string
|
|
70
|
+
scannedAt: string
|
|
71
|
+
organizationId: string
|
|
72
|
+
workspaceId: string
|
|
73
|
+
userId: string
|
|
74
|
+
role: SaasRole
|
|
75
|
+
plan: SaasPlan
|
|
76
|
+
repoId: string
|
|
77
|
+
repoName: string
|
|
78
|
+
targetPath: string
|
|
79
|
+
totalScore: number
|
|
80
|
+
totalIssues: number
|
|
81
|
+
totalFiles: number
|
|
82
|
+
summary: {
|
|
83
|
+
errors: number
|
|
84
|
+
warnings: number
|
|
85
|
+
infos: number
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface SaasStore {
|
|
90
|
+
version: number
|
|
91
|
+
policy: SaasPolicy
|
|
92
|
+
users: Record<string, SaasUser>
|
|
93
|
+
organizations: Record<string, SaasOrganization>
|
|
94
|
+
workspaces: Record<string, SaasWorkspace>
|
|
95
|
+
memberships: Record<string, SaasMembership>
|
|
96
|
+
repos: Record<string, SaasRepo>
|
|
97
|
+
snapshots: SaasSnapshot[]
|
|
98
|
+
planChanges: SaasPlanChange[]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type SaasOperation = 'snapshot:write' | 'snapshot:read' | 'summary:read' | 'billing:write' | 'billing:read'
|
|
102
|
+
|
|
103
|
+
export interface SaasPermissionContext {
|
|
104
|
+
operation: SaasOperation
|
|
105
|
+
organizationId: string
|
|
106
|
+
workspaceId?: string
|
|
107
|
+
actorUserId?: string
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface SaasPermissionResult {
|
|
111
|
+
actorRole?: SaasRole
|
|
112
|
+
requiredRole: SaasRole
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface SaasEffectiveLimits {
|
|
116
|
+
plan: SaasPlan
|
|
117
|
+
maxWorkspaces: number
|
|
118
|
+
maxReposPerWorkspace: number
|
|
119
|
+
maxRunsPerWorkspacePerMonth: number
|
|
120
|
+
retentionDays: number
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface SaasOrganizationUsageSnapshot {
|
|
124
|
+
organizationId: string
|
|
125
|
+
plan: SaasPlan
|
|
126
|
+
capturedAt: string
|
|
127
|
+
workspaceCount: number
|
|
128
|
+
repoCount: number
|
|
129
|
+
runCount: number
|
|
130
|
+
runCountThisMonth: number
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface ChangeOrganizationPlanOptions {
|
|
134
|
+
organizationId: string
|
|
135
|
+
actorUserId: string
|
|
136
|
+
newPlan: SaasPlan
|
|
137
|
+
reason?: string
|
|
138
|
+
storeFile?: string
|
|
139
|
+
policy?: SaasPolicyOverrides
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface SaasUsageQueryOptions {
|
|
143
|
+
organizationId: string
|
|
144
|
+
month?: string
|
|
145
|
+
storeFile?: string
|
|
146
|
+
policy?: SaasPolicyOverrides
|
|
147
|
+
actorUserId?: string
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface SaasPlanChangeQueryOptions {
|
|
151
|
+
organizationId: string
|
|
152
|
+
storeFile?: string
|
|
153
|
+
policy?: SaasPolicyOverrides
|
|
154
|
+
actorUserId?: string
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface SaasSummary {
|
|
158
|
+
policy: SaasPolicy
|
|
159
|
+
usersRegistered: number
|
|
160
|
+
workspacesActive: number
|
|
161
|
+
reposActive: number
|
|
162
|
+
runsPerMonth: Record<string, number>
|
|
163
|
+
totalSnapshots: number
|
|
164
|
+
phase: 'free' | 'paid'
|
|
165
|
+
thresholdReached: boolean
|
|
166
|
+
freeUsersRemaining: number
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface SaasPolicyOverrides {
|
|
170
|
+
freeUserThreshold?: number
|
|
171
|
+
maxRunsPerWorkspacePerMonth?: number
|
|
172
|
+
maxReposPerWorkspace?: number
|
|
173
|
+
retentionDays?: number
|
|
174
|
+
strictActorEnforcement?: boolean
|
|
175
|
+
maxWorkspacesPerOrganizationByPlan?: Partial<Record<SaasPlan, number>>
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface SaasQueryOptions {
|
|
179
|
+
storeFile?: string
|
|
180
|
+
policy?: SaasPolicyOverrides
|
|
181
|
+
organizationId?: string
|
|
182
|
+
workspaceId?: string
|
|
183
|
+
actorUserId?: string
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface IngestOptions {
|
|
187
|
+
organizationId?: string
|
|
188
|
+
workspaceId: string
|
|
189
|
+
userId: string
|
|
190
|
+
role?: SaasRole
|
|
191
|
+
plan?: SaasPlan
|
|
192
|
+
repoName?: string
|
|
193
|
+
actorUserId?: string
|
|
194
|
+
storeFile?: string
|
|
195
|
+
policy?: SaasPolicyOverrides
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface ScopedIdentity {
|
|
199
|
+
organizationId: string
|
|
200
|
+
workspaceId: string
|
|
201
|
+
workspaceKey: string
|
|
202
|
+
repoName: string
|
|
203
|
+
repoId: string
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface IngestMutationContext {
|
|
207
|
+
store: SaasStore
|
|
208
|
+
scoped: ScopedIdentity
|
|
209
|
+
options: IngestOptions
|
|
210
|
+
nowIso: string
|
|
211
|
+
requestedPlan: SaasPlan
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export type SaasPolicyInput = SaasPolicyOverrides | DriftConfig['saas'] | undefined
|
|
215
|
+
|
|
216
|
+
export type DriftReportInput = DriftReport
|