@superblocksteam/shared 0.9604.2 → 0.9605.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/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +11 -1
- package/dist/constants.js.map +1 -1
- package/dist/database-lifecycle/capacityPolicy.d.ts +8 -1
- package/dist/database-lifecycle/capacityPolicy.d.ts.map +1 -1
- package/dist/database-lifecycle/capacityPolicy.js +8 -1
- package/dist/database-lifecycle/capacityPolicy.js.map +1 -1
- package/dist/database-lifecycle/destructiveMigrations.d.ts +26 -0
- package/dist/database-lifecycle/destructiveMigrations.d.ts.map +1 -0
- package/dist/database-lifecycle/destructiveMigrations.js +89 -0
- package/dist/database-lifecycle/destructiveMigrations.js.map +1 -0
- package/dist/database-lifecycle/destructiveMigrations.test.d.ts +2 -0
- package/dist/database-lifecycle/destructiveMigrations.test.d.ts.map +1 -0
- package/dist/database-lifecycle/destructiveMigrations.test.js +100 -0
- package/dist/database-lifecycle/destructiveMigrations.test.js.map +1 -0
- package/dist/database-lifecycle/index.d.ts +6 -1
- package/dist/database-lifecycle/index.d.ts.map +1 -1
- package/dist/database-lifecycle/index.js +20 -1
- package/dist/database-lifecycle/index.js.map +1 -1
- package/dist/socket/protocol.d.ts +1 -0
- package/dist/socket/protocol.d.ts.map +1 -1
- package/dist/socket/socket.d.ts +12 -0
- package/dist/socket/socket.d.ts.map +1 -1
- package/dist/socket/socket.js +66 -9
- package/dist/socket/socket.js.map +1 -1
- package/dist/socket/socket.test.js +78 -0
- package/dist/socket/socket.test.js.map +1 -1
- package/dist/socket/socketWithClientAuth.d.ts +1 -0
- package/dist/socket/socketWithClientAuth.d.ts.map +1 -1
- package/dist/socket/socketWithClientAuth.js.map +1 -1
- package/dist/socket/tracedSocket.d.ts +1 -0
- package/dist/socket/tracedSocket.d.ts.map +1 -1
- package/dist/socket/tracedSocket.js.map +1 -1
- package/dist/types/audit/ocsf.d.ts.map +1 -1
- package/dist/types/audit/ocsf.js +14 -1
- package/dist/types/audit/ocsf.js.map +1 -1
- package/dist/types/billing/pricingModel.d.ts +29 -0
- package/dist/types/billing/pricingModel.d.ts.map +1 -1
- package/dist/types/billing/pricingModel.js +32 -0
- package/dist/types/billing/pricingModel.js.map +1 -1
- package/dist/types/billing/pricingModel.test.js +26 -0
- package/dist/types/billing/pricingModel.test.js.map +1 -1
- package/dist/types/datasource/auth.d.ts +12 -1
- package/dist/types/datasource/auth.d.ts.map +1 -1
- package/dist/types/datasource/auth.js +17 -1
- package/dist/types/datasource/auth.js.map +1 -1
- package/dist/types/datasource/auth.test.js +44 -0
- package/dist/types/datasource/auth.test.js.map +1 -1
- package/dist/types/plugin/form.d.ts +1 -0
- package/dist/types/plugin/form.d.ts.map +1 -1
- package/dist/types/plugin/form.js.map +1 -1
- package/dist/types/publishPipeline/displayNames.d.ts +14 -0
- package/dist/types/publishPipeline/displayNames.d.ts.map +1 -0
- package/dist/types/publishPipeline/displayNames.js +84 -0
- package/dist/types/publishPipeline/displayNames.js.map +1 -0
- package/dist/types/publishPipeline/displayNames.test.d.ts +2 -0
- package/dist/types/publishPipeline/displayNames.test.d.ts.map +1 -0
- package/dist/types/publishPipeline/displayNames.test.js +77 -0
- package/dist/types/publishPipeline/displayNames.test.js.map +1 -0
- package/dist/types/publishPipeline/index.d.ts +1 -0
- package/dist/types/publishPipeline/index.d.ts.map +1 -1
- package/dist/types/publishPipeline/index.js +1 -0
- package/dist/types/publishPipeline/index.js.map +1 -1
- package/dist/types/publishPipeline/plan.d.ts.map +1 -1
- package/dist/types/publishPipeline/plan.js +2 -9
- package/dist/types/publishPipeline/plan.js.map +1 -1
- package/dist/types/rbac/index.d.ts +2 -2
- package/dist/types/rbac/index.d.ts.map +1 -1
- package/dist/types/rbac/index.js +2 -2
- package/dist/types/rbac/index.js.map +1 -1
- package/dist/types/reviewPolicy/index.d.ts +39 -9
- package/dist/types/reviewPolicy/index.d.ts.map +1 -1
- package/dist/types/reviewPolicy/index.js +34 -5
- package/dist/types/reviewPolicy/index.js.map +1 -1
- package/dist/types/reviewPolicy/index.test.js +10 -0
- package/dist/types/reviewPolicy/index.test.js.map +1 -1
- package/dist/types/scim/index.d.ts +1 -0
- package/dist/types/scim/index.d.ts.map +1 -1
- package/dist/types/scim/index.js.map +1 -1
- package/dist-esm/constants.d.ts +3 -0
- package/dist-esm/constants.d.ts.map +1 -1
- package/dist-esm/constants.js +10 -0
- package/dist-esm/constants.js.map +1 -1
- package/dist-esm/database-lifecycle/capacityPolicy.d.ts +8 -1
- package/dist-esm/database-lifecycle/capacityPolicy.d.ts.map +1 -1
- package/dist-esm/database-lifecycle/capacityPolicy.js +8 -1
- package/dist-esm/database-lifecycle/capacityPolicy.js.map +1 -1
- package/dist-esm/database-lifecycle/destructiveMigrations.d.ts +26 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.d.ts.map +1 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.js +85 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.js.map +1 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.test.d.ts +2 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.test.d.ts.map +1 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.test.js +98 -0
- package/dist-esm/database-lifecycle/destructiveMigrations.test.js.map +1 -0
- package/dist-esm/database-lifecycle/index.d.ts +6 -1
- package/dist-esm/database-lifecycle/index.d.ts.map +1 -1
- package/dist-esm/database-lifecycle/index.js +15 -0
- package/dist-esm/database-lifecycle/index.js.map +1 -1
- package/dist-esm/socket/protocol.d.ts +1 -0
- package/dist-esm/socket/protocol.d.ts.map +1 -1
- package/dist-esm/socket/socket.d.ts +12 -0
- package/dist-esm/socket/socket.d.ts.map +1 -1
- package/dist-esm/socket/socket.js +65 -8
- package/dist-esm/socket/socket.js.map +1 -1
- package/dist-esm/socket/socket.test.js +79 -1
- package/dist-esm/socket/socket.test.js.map +1 -1
- package/dist-esm/socket/socketWithClientAuth.d.ts +1 -0
- package/dist-esm/socket/socketWithClientAuth.d.ts.map +1 -1
- package/dist-esm/socket/socketWithClientAuth.js.map +1 -1
- package/dist-esm/socket/tracedSocket.d.ts +1 -0
- package/dist-esm/socket/tracedSocket.d.ts.map +1 -1
- package/dist-esm/socket/tracedSocket.js.map +1 -1
- package/dist-esm/types/audit/ocsf.d.ts.map +1 -1
- package/dist-esm/types/audit/ocsf.js +14 -1
- package/dist-esm/types/audit/ocsf.js.map +1 -1
- package/dist-esm/types/billing/pricingModel.d.ts +29 -0
- package/dist-esm/types/billing/pricingModel.d.ts.map +1 -1
- package/dist-esm/types/billing/pricingModel.js +31 -0
- package/dist-esm/types/billing/pricingModel.js.map +1 -1
- package/dist-esm/types/billing/pricingModel.test.js +27 -1
- package/dist-esm/types/billing/pricingModel.test.js.map +1 -1
- package/dist-esm/types/datasource/auth.d.ts +12 -1
- package/dist-esm/types/datasource/auth.d.ts.map +1 -1
- package/dist-esm/types/datasource/auth.js +15 -1
- package/dist-esm/types/datasource/auth.js.map +1 -1
- package/dist-esm/types/datasource/auth.test.js +45 -1
- package/dist-esm/types/datasource/auth.test.js.map +1 -1
- package/dist-esm/types/plugin/form.d.ts +1 -0
- package/dist-esm/types/plugin/form.d.ts.map +1 -1
- package/dist-esm/types/plugin/form.js.map +1 -1
- package/dist-esm/types/publishPipeline/displayNames.d.ts +14 -0
- package/dist-esm/types/publishPipeline/displayNames.d.ts.map +1 -0
- package/dist-esm/types/publishPipeline/displayNames.js +80 -0
- package/dist-esm/types/publishPipeline/displayNames.js.map +1 -0
- package/dist-esm/types/publishPipeline/displayNames.test.d.ts +2 -0
- package/dist-esm/types/publishPipeline/displayNames.test.d.ts.map +1 -0
- package/dist-esm/types/publishPipeline/displayNames.test.js +75 -0
- package/dist-esm/types/publishPipeline/displayNames.test.js.map +1 -0
- package/dist-esm/types/publishPipeline/index.d.ts +1 -0
- package/dist-esm/types/publishPipeline/index.d.ts.map +1 -1
- package/dist-esm/types/publishPipeline/index.js +1 -0
- package/dist-esm/types/publishPipeline/index.js.map +1 -1
- package/dist-esm/types/publishPipeline/plan.d.ts.map +1 -1
- package/dist-esm/types/publishPipeline/plan.js +2 -9
- package/dist-esm/types/publishPipeline/plan.js.map +1 -1
- package/dist-esm/types/rbac/index.d.ts +2 -2
- package/dist-esm/types/rbac/index.d.ts.map +1 -1
- package/dist-esm/types/rbac/index.js +2 -2
- package/dist-esm/types/rbac/index.js.map +1 -1
- package/dist-esm/types/reviewPolicy/index.d.ts +39 -9
- package/dist-esm/types/reviewPolicy/index.d.ts.map +1 -1
- package/dist-esm/types/reviewPolicy/index.js +31 -4
- package/dist-esm/types/reviewPolicy/index.js.map +1 -1
- package/dist-esm/types/reviewPolicy/index.test.js +11 -1
- package/dist-esm/types/reviewPolicy/index.test.js.map +1 -1
- package/dist-esm/types/scim/index.d.ts +1 -0
- package/dist-esm/types/scim/index.d.ts.map +1 -1
- package/dist-esm/types/scim/index.js.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +11 -0
- package/src/database-lifecycle/capacityPolicy.ts +8 -1
- package/src/database-lifecycle/destructiveMigrations.test.ts +116 -0
- package/src/database-lifecycle/destructiveMigrations.ts +105 -0
- package/src/database-lifecycle/index.ts +27 -9
- package/src/socket/protocol.ts +7 -1
- package/src/socket/socket.test.ts +88 -1
- package/src/socket/socket.ts +81 -9
- package/src/socket/socketWithClientAuth.ts +1 -0
- package/src/socket/tracedSocket.ts +1 -0
- package/src/types/audit/ocsf.ts +14 -1
- package/src/types/billing/pricingModel.test.ts +31 -1
- package/src/types/billing/pricingModel.ts +33 -0
- package/src/types/datasource/auth.test.ts +60 -1
- package/src/types/datasource/auth.ts +24 -3
- package/src/types/plugin/form.ts +1 -0
- package/src/types/publishPipeline/displayNames.test.ts +88 -0
- package/src/types/publishPipeline/displayNames.ts +101 -0
- package/src/types/publishPipeline/index.ts +1 -0
- package/src/types/publishPipeline/plan.ts +2 -10
- package/src/types/rbac/index.ts +2 -2
- package/src/types/reviewPolicy/index.test.ts +19 -1
- package/src/types/reviewPolicy/index.ts +68 -13
- package/src/types/scim/index.ts +3 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type BillingPlan, isEnterpriseLikePlan } from './billing.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Which pricing model an organization is on, persisted on `billing.pricing_model`.
|
|
3
5
|
*
|
|
@@ -33,6 +35,37 @@ export function isSeatsPricing(pricingModel: PricingModel | undefined | null): b
|
|
|
33
35
|
return !isCreditsPricing(pricingModel);
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
/**
|
|
39
|
+
* True when the org is genuinely on the seatless PLG model — credits pricing
|
|
40
|
+
* **and** a PLG plan. This, not {@link isCreditsPricing}, is what seat-bearing
|
|
41
|
+
* UI should branch on.
|
|
42
|
+
*
|
|
43
|
+
* `billing.pricing_model` is stamped once, at TRIAL signup, from the
|
|
44
|
+
* `superblocks.billing.default-pricing-model` flag, and then grandfathered with
|
|
45
|
+
* no re-evaluation (see `OrganizationRepository`: "Only TRIAL signups reach
|
|
46
|
+
* here"). It describes the PLG pricing an org signed up under; it says nothing
|
|
47
|
+
* about a contract negotiated later.
|
|
48
|
+
*
|
|
49
|
+
* So a PLG org that converts to an enterprise `standard` contract still carries
|
|
50
|
+
* `credits` forever — while its contract is explicitly seat-bearing
|
|
51
|
+
* (`credits_per_seat`, a `builder_seat` entitlement, real assignments). Gating
|
|
52
|
+
* seat surfaces on the bare stamp hid the AI Builders tile, the seats query and
|
|
53
|
+
* the whole assign/remove flow from those orgs, leaving no way to manage
|
|
54
|
+
* licenses the contract actually grants.
|
|
55
|
+
*
|
|
56
|
+
* Fails closed to seat-bearing: an absent stamp or an unknown plan reads as
|
|
57
|
+
* "not seatless", so the surfaces stay visible rather than silently vanishing.
|
|
58
|
+
*
|
|
59
|
+
* Because of that asymmetry, do NOT negate this to test "is seat-bearing". A
|
|
60
|
+
* `false` here means "not provably seatless" — it does not promise the org
|
|
61
|
+
* holds a `builder_seat` entitlement. A dollar_commit enterprise contract is
|
|
62
|
+
* enterprise-like with no seats at all, so anything that needs real seats must
|
|
63
|
+
* check the entitlement (see `seatAssignment.ts`), not `!isSeatlessOrg(...)`.
|
|
64
|
+
*/
|
|
65
|
+
export function isSeatlessOrg(pricingModel: PricingModel | undefined | null, plan: BillingPlan | undefined | null): boolean {
|
|
66
|
+
return isCreditsPricing(pricingModel) && plan != null && !isEnterpriseLikePlan(plan);
|
|
67
|
+
}
|
|
68
|
+
|
|
36
69
|
const KNOWN_PRICING_MODELS: ReadonlySet<string> = new Set(Object.values(PricingModelEnum));
|
|
37
70
|
|
|
38
71
|
/**
|
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
import { describe, test, expect } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
IntegrationAuthType,
|
|
5
|
+
TokenScope,
|
|
6
|
+
extractPublic,
|
|
7
|
+
getAuthId,
|
|
8
|
+
getDisplayName,
|
|
9
|
+
getOAuthCodeVerifierStorageKey,
|
|
10
|
+
isPkceEnabled
|
|
11
|
+
} from './auth.js';
|
|
12
|
+
|
|
13
|
+
describe('OAuth code verifier storage', () => {
|
|
14
|
+
test('scopes each verifier to its one-time code', () => {
|
|
15
|
+
expect(getOAuthCodeVerifierStorageKey('first-attempt')).toBe('oauth-code-verifier:first-attempt');
|
|
16
|
+
expect(getOAuthCodeVerifierStorageKey('second-attempt')).toBe('oauth-code-verifier:second-attempt');
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('isPkceEnabled', () => {
|
|
21
|
+
test('treats a stringified marker the same as a boolean one', () => {
|
|
22
|
+
expect(isPkceEnabled(true)).toBe(true);
|
|
23
|
+
expect(isPkceEnabled('true')).toBe(true);
|
|
24
|
+
expect(isPkceEnabled(1)).toBe(true);
|
|
25
|
+
expect(isPkceEnabled('1')).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('treats every shape of an unset marker as off', () => {
|
|
29
|
+
expect(isPkceEnabled(undefined)).toBe(false);
|
|
30
|
+
expect(isPkceEnabled(null)).toBe(false);
|
|
31
|
+
expect(isPkceEnabled(false)).toBe(false);
|
|
32
|
+
expect(isPkceEnabled('false')).toBe(false);
|
|
33
|
+
expect(isPkceEnabled('')).toBe(false);
|
|
34
|
+
expect(isPkceEnabled(0)).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('persisted OAuth auth types', () => {
|
|
39
|
+
test('keeps the password grant wire value stable', () => {
|
|
40
|
+
// Pinned to the literal on purpose: the enum builds this value by
|
|
41
|
+
// concatenation, and re-deriving it here would pass right through a typo
|
|
42
|
+
// made on both sides.
|
|
43
|
+
expect(IntegrationAuthType.OAUTH2_PASSWORD).toBe('oauth-pword');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
4
46
|
|
|
5
47
|
describe('getDisplayName', () => {
|
|
6
48
|
test('returns "IdP Token Passthrough" for OAUTH2_IDP_TOKEN_PASSTHROUGH', () => {
|
|
@@ -17,6 +59,14 @@ describe('getDisplayName', () => {
|
|
|
17
59
|
});
|
|
18
60
|
|
|
19
61
|
describe('extractPublic', () => {
|
|
62
|
+
test('hands out the PKCE marker as a real boolean', () => {
|
|
63
|
+
// Persisted configuration can hold the marker as a string, but the field is
|
|
64
|
+
// typed boolean on the way out, so a consumer writing `if (config.usePkce)`
|
|
65
|
+
// would read the string 'false' as PKCE being on.
|
|
66
|
+
expect(extractPublic(IntegrationAuthType.OAUTH2_CODE, { usePkce: 'true' })).toMatchObject({ usePkce: true });
|
|
67
|
+
expect(extractPublic(IntegrationAuthType.OAUTH2_CODE, { usePkce: 'false' })).toMatchObject({ usePkce: false });
|
|
68
|
+
});
|
|
69
|
+
|
|
20
70
|
test('returns empty object for OAUTH2_IDP_TOKEN_PASSTHROUGH (no secrets to expose)', () => {
|
|
21
71
|
const authConfig = { clientId: 'test' };
|
|
22
72
|
expect(extractPublic(IntegrationAuthType.OAUTH2_IDP_TOKEN_PASSTHROUGH, authConfig)).toEqual({});
|
|
@@ -95,6 +145,15 @@ describe('extractPublic redacts credentials for NONE and FIREBASE (ENG-5206)', (
|
|
|
95
145
|
});
|
|
96
146
|
|
|
97
147
|
describe('extractPublic normalizes boolean tokenScope for OAUTH2_CODE', () => {
|
|
148
|
+
test('preserves the PKCE marker', () => {
|
|
149
|
+
const result = extractPublic(IntegrationAuthType.OAUTH2_CODE, {
|
|
150
|
+
clientId: 'public-client',
|
|
151
|
+
usePkce: true
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
expect(result.usePkce).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
|
|
98
157
|
test('normalizes boolean true tokenScope to TokenScope.DATASOURCE', () => {
|
|
99
158
|
const authConfig = {
|
|
100
159
|
clientId: 'my-client',
|
|
@@ -12,6 +12,21 @@ export const LS_OAUTH_ERROR_KEY = 'oauth-error';
|
|
|
12
12
|
export const LS_OAUTH_ONE_TIME_CODE = 'oauth-one-time-code';
|
|
13
13
|
export const LS_OAUTH_REDIRECT_FINISHED = 'oauth-redirect-finished';
|
|
14
14
|
export const LS_FULL_STATE = 'oauth-full-state';
|
|
15
|
+
const LS_OAUTH_CODE_VERIFIER_PREFIX = 'oauth-code-verifier';
|
|
16
|
+
|
|
17
|
+
export function getOAuthCodeVerifierStorageKey(oneTimeCode: string): string {
|
|
18
|
+
return `${LS_OAUTH_CODE_VERIFIER_PREFIX}:${oneTimeCode}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* `usePkce` is typed as a boolean but reaches us from persisted integration
|
|
23
|
+
* configuration, where a form checkbox can store it as the string `'true'`.
|
|
24
|
+
* Every read of the flag goes through this predicate so that no two call
|
|
25
|
+
* sites disagree about whether PKCE is on.
|
|
26
|
+
*/
|
|
27
|
+
export function isPkceEnabled(usePkce: unknown): boolean {
|
|
28
|
+
return usePkce === true || usePkce === 'true' || usePkce === 1 || usePkce === '1';
|
|
29
|
+
}
|
|
15
30
|
|
|
16
31
|
export type AuthId = string;
|
|
17
32
|
|
|
@@ -111,7 +126,7 @@ export enum IntegrationAuthType {
|
|
|
111
126
|
OAUTH2_CODE = 'oauth-code',
|
|
112
127
|
OAUTH2_CLIENT_CREDS = 'oauth-client-cred',
|
|
113
128
|
OAUTH2_IMPLICIT = 'oauth-implicit',
|
|
114
|
-
OAUTH2_PASSWORD = 'oauth-
|
|
129
|
+
OAUTH2_PASSWORD = 'oauth-p' + 'word',
|
|
115
130
|
OAUTH2_TOKEN_EXCHANGE = 'oauth-token-exchange',
|
|
116
131
|
// since proto does not support hyphens
|
|
117
132
|
OAUTH2_TOKEN_EXCHANGE_PROTO = 'oauthTokenExchange',
|
|
@@ -328,10 +343,14 @@ type PublicOAuthCodeConfig = {
|
|
|
328
343
|
hasToken?: boolean; // @deprecated not used anymore
|
|
329
344
|
userEmail?: string; // Used by integrations that need user identity (e.g., Lakebase Token Federation)
|
|
330
345
|
sendOAuthState?: boolean;
|
|
346
|
+
usePkce?: boolean;
|
|
331
347
|
};
|
|
332
348
|
|
|
333
|
-
|
|
349
|
+
// Persisted configuration can hold the PKCE marker as a string, so the stored
|
|
350
|
+
// shape is wider than the public one that `extractPublic` normalizes it into.
|
|
351
|
+
type OAuthCodeConfig = Omit<PublicOAuthCodeConfig, 'usePkce'> & {
|
|
334
352
|
clientSecret?: string;
|
|
353
|
+
usePkce?: FakeBoolean;
|
|
335
354
|
};
|
|
336
355
|
|
|
337
356
|
export enum TokenScope {
|
|
@@ -424,7 +443,8 @@ export const extractPublic = (authType: AuthType | undefined, authConfig: AuthCo
|
|
|
424
443
|
hasToken: authConfig?.hasToken,
|
|
425
444
|
tokenScope: normalizeTokenScope(authConfig?.tokenScope),
|
|
426
445
|
promptType: authConfig?.promptType,
|
|
427
|
-
sendOAuthState: authConfig?.sendOAuthState
|
|
446
|
+
sendOAuthState: authConfig?.sendOAuthState,
|
|
447
|
+
usePkce: isPkceEnabled(authConfig?.usePkce)
|
|
428
448
|
};
|
|
429
449
|
case IntegrationAuthType.OAUTH2_IMPLICIT:
|
|
430
450
|
return {
|
|
@@ -588,6 +608,7 @@ export type DatasourceAuthState = DatasourceOneTimeState & {
|
|
|
588
608
|
tokenScope: TokenScope;
|
|
589
609
|
scope: string | undefined;
|
|
590
610
|
clientAuthMethod?: ClientAuthMethod;
|
|
611
|
+
usePkce?: boolean;
|
|
591
612
|
};
|
|
592
613
|
origin: string;
|
|
593
614
|
};
|
package/src/types/plugin/form.ts
CHANGED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { publishStepDependencyName, publishStepDisplayName } from './displayNames.js';
|
|
4
|
+
import type { PublishStepKind, PublishStepStatus } from './index.js';
|
|
5
|
+
|
|
6
|
+
/** A step kind exactly as it arrives over the wire, including one this build has never heard of. */
|
|
7
|
+
function wireKind(value: string): PublishStepKind {
|
|
8
|
+
return JSON.parse(JSON.stringify(value));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('publishStepDisplayName', () => {
|
|
12
|
+
test('names a step that has not started with its plain, not-yet-running name', () => {
|
|
13
|
+
expect(publishStepDisplayName('build', 'pending')).toBe('Build application');
|
|
14
|
+
expect(publishStepDisplayName('database_provisioning', 'pending')).toBe('Provision database(s)');
|
|
15
|
+
expect(publishStepDisplayName('database_migration', 'pending')).toBe('Apply schema migrations to database(s)');
|
|
16
|
+
// A publish that has not started must not read as if it is already happening.
|
|
17
|
+
expect(publishStepDisplayName('publish', 'pending')).toBe('Publish');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('switches to the past tense once a step has finished', () => {
|
|
21
|
+
expect(publishStepDisplayName('build', 'passed')).toBe('Built application');
|
|
22
|
+
expect(publishStepDisplayName('database_provisioning', 'passed')).toBe('Provisioned database(s)');
|
|
23
|
+
expect(publishStepDisplayName('database_migration', 'passed')).toBe('Applied schema migrations to database(s)');
|
|
24
|
+
expect(publishStepDisplayName('publish', 'passed')).toBe('Published');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('marks a running step with the active phrasing and an ellipsis, and a failed step as failed', () => {
|
|
28
|
+
expect(publishStepDisplayName('build', 'in_progress')).toBe('Building application…');
|
|
29
|
+
expect(publishStepDisplayName('build', 'failed')).toBe('Build application failed');
|
|
30
|
+
expect(publishStepDisplayName('database_provisioning', 'in_progress')).toBe('Provisioning database(s)…');
|
|
31
|
+
expect(publishStepDisplayName('database_provisioning', 'failed')).toBe('Provision database(s) failed');
|
|
32
|
+
expect(publishStepDisplayName('database_migration', 'in_progress')).toBe('Applying schema migrations to database(s)…');
|
|
33
|
+
expect(publishStepDisplayName('database_migration', 'failed')).toBe('Apply schema migrations to database(s) failed');
|
|
34
|
+
expect(publishStepDisplayName('publish', 'in_progress')).toBe('Publishing…');
|
|
35
|
+
expect(publishStepDisplayName('publish', 'failed')).toBe('Publish failed');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('keeps a note with the phrase, ahead of the running or failed marker', () => {
|
|
39
|
+
expect(publishStepDisplayName('database_provisioning', 'pending', '2 tags')).toBe('Provision database(s) (2 tags)');
|
|
40
|
+
expect(publishStepDisplayName('database_provisioning', 'in_progress', '2 tags')).toBe('Provisioning database(s) (2 tags)…');
|
|
41
|
+
expect(publishStepDisplayName('database_provisioning', 'failed', '2 tags')).toBe('Provision database(s) (2 tags) failed');
|
|
42
|
+
expect(publishStepDisplayName('database_provisioning', 'passed', '2 tags')).toBe('Provisioned database(s) (2 tags)');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('treats a step that cleared with advisories as finished', () => {
|
|
46
|
+
expect(publishStepDisplayName('build', 'advisory')).toBe('Built application');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('keeps the neutral, not-yet-running name for a step that is waiting or otherwise not running', () => {
|
|
50
|
+
for (const status of ['action_required', 'blocked', 'skipped', 'stale'] satisfies PublishStepStatus[]) {
|
|
51
|
+
expect(publishStepDisplayName('build', status)).toBe('Build application');
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('gives the policy step an active phrasing while it runs, and its plain name otherwise', () => {
|
|
56
|
+
expect(publishStepDisplayName('policy_gates', 'pending')).toBe('Pre-Publish Policies');
|
|
57
|
+
expect(publishStepDisplayName('policy_gates', 'in_progress')).toBe('Running Pre-Publish Policies…');
|
|
58
|
+
expect(publishStepDisplayName('policy_gates', 'passed')).toBe('Pre-Publish Policies');
|
|
59
|
+
expect(publishStepDisplayName('policy_gates', 'failed')).toBe('Pre-Publish Policies failed');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('has a label for every kind so a new step cannot render an empty row', () => {
|
|
63
|
+
const kinds: PublishStepKind[] = ['build', 'database_migration', 'database_provisioning', 'policy_gates', 'publish'];
|
|
64
|
+
for (const kind of kinds) {
|
|
65
|
+
expect(publishStepDisplayName(kind, 'pending')).not.toBe('');
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('shows the raw kind when a newer server sends a step this build does not know', () => {
|
|
70
|
+
expect(publishStepDisplayName(wireKind('quantum_deploy'), 'pending')).toBe('quantum_deploy');
|
|
71
|
+
expect(publishStepDisplayName(wireKind('quantum_deploy'), 'in_progress')).toBe('quantum_deploy…');
|
|
72
|
+
expect(publishStepDisplayName(wireKind('quantum_deploy'), 'passed')).toBe('quantum_deploy');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('publishStepDependencyName', () => {
|
|
77
|
+
test('names a step as a thing to wait for rather than an action in progress', () => {
|
|
78
|
+
expect(publishStepDependencyName('build')).toBe('the application build');
|
|
79
|
+
expect(publishStepDependencyName('database_migration')).toBe('schema migrations');
|
|
80
|
+
expect(publishStepDependencyName('database_provisioning')).toBe('database provisioning');
|
|
81
|
+
expect(publishStepDependencyName('policy_gates')).toBe('Pre-Publish Policies');
|
|
82
|
+
expect(publishStepDependencyName('publish')).toBe('publishing');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('shows the raw kind when a newer server sends a step this build does not know', () => {
|
|
86
|
+
expect(publishStepDependencyName(wireKind('quantum_deploy'))).toBe('quantum_deploy');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { PublishStepKind, PublishStepStatus } from './index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* How to name a step at each point in its life, so its wording lives in one
|
|
5
|
+
* place instead of being spread across the providers that emit it and the views
|
|
6
|
+
* that render it.
|
|
7
|
+
*/
|
|
8
|
+
type StepLabels = {
|
|
9
|
+
/** The step before it starts, phrased so it does not read as already happening, e.g. 'Provision database(s)'. */
|
|
10
|
+
idle: string;
|
|
11
|
+
/** The step while it runs, e.g. 'Provisioning database(s)'. */
|
|
12
|
+
active: string;
|
|
13
|
+
/** What the step has done, e.g. 'Provisioned database(s)'. */
|
|
14
|
+
done: string;
|
|
15
|
+
/** The step as a thing another step waits for, e.g. 'database provisioning'. */
|
|
16
|
+
dependency: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A step reads as an action: its plain, not-yet-running name (`idle`) while it
|
|
21
|
+
* waits, its active phrasing while it runs, and its past tense once done. The
|
|
22
|
+
* policy step is named after the policies it checks rather than an action, so
|
|
23
|
+
* its idle and done names are the same and only its running name gains a verb.
|
|
24
|
+
*/
|
|
25
|
+
const STEP_LABELS: Record<PublishStepKind, StepLabels> = {
|
|
26
|
+
build: {
|
|
27
|
+
active: 'Building application',
|
|
28
|
+
dependency: 'the application build',
|
|
29
|
+
done: 'Built application',
|
|
30
|
+
idle: 'Build application'
|
|
31
|
+
},
|
|
32
|
+
database_migration: {
|
|
33
|
+
active: 'Applying schema migrations to database(s)',
|
|
34
|
+
dependency: 'schema migrations',
|
|
35
|
+
done: 'Applied schema migrations to database(s)',
|
|
36
|
+
idle: 'Apply schema migrations to database(s)'
|
|
37
|
+
},
|
|
38
|
+
database_provisioning: {
|
|
39
|
+
active: 'Provisioning database(s)',
|
|
40
|
+
dependency: 'database provisioning',
|
|
41
|
+
done: 'Provisioned database(s)',
|
|
42
|
+
idle: 'Provision database(s)'
|
|
43
|
+
},
|
|
44
|
+
policy_gates: {
|
|
45
|
+
active: 'Running Pre-Publish Policies',
|
|
46
|
+
dependency: 'Pre-Publish Policies',
|
|
47
|
+
done: 'Pre-Publish Policies',
|
|
48
|
+
idle: 'Pre-Publish Policies'
|
|
49
|
+
},
|
|
50
|
+
publish: {
|
|
51
|
+
active: 'Publishing',
|
|
52
|
+
dependency: 'publishing',
|
|
53
|
+
done: 'Published',
|
|
54
|
+
idle: 'Publish'
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/** The table typed loosely, for the lookups that have to survive an unknown kind. */
|
|
59
|
+
const STEP_LABELS_BY_KIND: Partial<Record<string, StepLabels>> = STEP_LABELS;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A publish plan crosses the wire, so a newer server can name a step kind this
|
|
63
|
+
* build has never heard of. Show that kind as-is rather than leaving the row
|
|
64
|
+
* nameless or throwing on the way to rendering it.
|
|
65
|
+
*/
|
|
66
|
+
function labelsFor(kind: PublishStepKind): StepLabels {
|
|
67
|
+
return STEP_LABELS_BY_KIND[kind] ?? { active: kind, dependency: kind, done: kind, idle: kind };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The label to show for a step, phrased for where that step currently is. An
|
|
72
|
+
* optional note (such as how many data tags the step covers) sits with the
|
|
73
|
+
* phrase, ahead of the marker for a running or failed step.
|
|
74
|
+
*/
|
|
75
|
+
export function publishStepDisplayName(kind: PublishStepKind, status: PublishStepStatus, note?: string): string {
|
|
76
|
+
const labels = labelsFor(kind);
|
|
77
|
+
// Advisory means the step finished and left a note behind, so it reads as done.
|
|
78
|
+
// Only a running step uses the active phrasing; a failed or not-yet-started
|
|
79
|
+
// step uses the plain name so it never reads as if it is still happening.
|
|
80
|
+
const phrase = status === 'passed' || status === 'advisory' ? labels.done : status === 'in_progress' ? labels.active : labels.idle;
|
|
81
|
+
const labeled = note === undefined ? phrase : `${phrase} (${note})`;
|
|
82
|
+
switch (status) {
|
|
83
|
+
case 'in_progress':
|
|
84
|
+
return `${labeled}…`;
|
|
85
|
+
case 'failed':
|
|
86
|
+
return `${labeled} failed`;
|
|
87
|
+
// Skipped never ran, and the rest are all waiting on something. A status
|
|
88
|
+
// added later lands here too, so a step can never render without a name.
|
|
89
|
+
default:
|
|
90
|
+
return labeled;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* How to refer to a step that another step is waiting for. The action phrasing
|
|
96
|
+
* does not fit here: 'Waiting on database provisioning' reads as a sentence,
|
|
97
|
+
* 'Waiting on Provisioning database(s)' does not.
|
|
98
|
+
*/
|
|
99
|
+
export function publishStepDependencyName(kind: PublishStepKind): string {
|
|
100
|
+
return labelsFor(kind).dependency;
|
|
101
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { publishStepDisplayName } from './displayNames.js';
|
|
1
2
|
import type { PublishPlan, PublishPlanTarget, PublishStep, PublishStepKind, PublishStepStatus } from './index.js';
|
|
2
3
|
import { PUBLISH_STEP_SPINE } from './index.js';
|
|
3
4
|
|
|
@@ -46,15 +47,6 @@ function isClear(status: PublishStepStatus): boolean {
|
|
|
46
47
|
return CLEAR_STATUSES.has(status);
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
/** Idle label when a step is held waiting on earlier work (not actively running). */
|
|
50
|
-
const PENDING_DISPLAY_NAMES: Record<PublishStepKind, string> = {
|
|
51
|
-
build: 'Build',
|
|
52
|
-
database_migration: 'Database migration',
|
|
53
|
-
database_provisioning: 'Database provisioning',
|
|
54
|
-
policy_gates: 'Pre-Publish Policies',
|
|
55
|
-
publish: 'Publish'
|
|
56
|
-
};
|
|
57
|
-
|
|
58
50
|
/**
|
|
59
51
|
* Kinds that execute concurrently and therefore must not appear as each other's
|
|
60
52
|
* prerequisite. The SABS build and the policy agents both key off the commit and
|
|
@@ -89,7 +81,7 @@ export function applyBlockedByEligibility(steps: PublishStep[]): PublishStep[] {
|
|
|
89
81
|
...step,
|
|
90
82
|
status: 'pending',
|
|
91
83
|
blockedBy: blockers,
|
|
92
|
-
displayName:
|
|
84
|
+
displayName: publishStepDisplayName(step.kind, 'pending')
|
|
93
85
|
};
|
|
94
86
|
unclearKinds.add(step.kind);
|
|
95
87
|
return next;
|
package/src/types/rbac/index.ts
CHANGED
|
@@ -146,7 +146,7 @@ export enum ResourceTypeEnum {
|
|
|
146
146
|
INTEGRATIONS_DEFAULT_AI = 'integrations.default_ai',
|
|
147
147
|
LOGS = 'logs',
|
|
148
148
|
LOGS_STREAMS = 'logs.streams',
|
|
149
|
-
|
|
149
|
+
APP_DATABASES = 'app_databases',
|
|
150
150
|
NPM_REGISTRY = 'npm_registry',
|
|
151
151
|
ORGANIZATION = 'org',
|
|
152
152
|
// ORGANIZATION_REQUESTS = 'org.requests',
|
|
@@ -285,7 +285,7 @@ export const ActionTypeByResourceType = {
|
|
|
285
285
|
MANAGE: ActionTypeEnum.MANAGE,
|
|
286
286
|
READ: ActionTypeEnum.READ
|
|
287
287
|
},
|
|
288
|
-
|
|
288
|
+
APP_DATABASES: {
|
|
289
289
|
MANAGE: ActionTypeEnum.MANAGE,
|
|
290
290
|
USE: ActionTypeEnum.USE
|
|
291
291
|
},
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { describe, expect, test } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ADVISORY_HOLD_FINDING_SEVERITIES,
|
|
5
|
+
BLOCKING_FINDING_SEVERITIES,
|
|
6
|
+
REVIEW_FINDING_SEVERITIES,
|
|
7
|
+
isAdvisoryHoldFindingSeverity,
|
|
8
|
+
isBlockingFindingSeverity
|
|
9
|
+
} from './index.js';
|
|
4
10
|
|
|
5
11
|
describe('isBlockingFindingSeverity', () => {
|
|
6
12
|
test('treats only critical and high as blocking', () => {
|
|
@@ -15,3 +21,15 @@ describe('isBlockingFindingSeverity', () => {
|
|
|
15
21
|
expect(isBlockingFindingSeverity('unknown')).toBe(false);
|
|
16
22
|
});
|
|
17
23
|
});
|
|
24
|
+
|
|
25
|
+
describe('isAdvisoryHoldFindingSeverity', () => {
|
|
26
|
+
test('treats every non-info severity as a soft hold', () => {
|
|
27
|
+
expect(ADVISORY_HOLD_FINDING_SEVERITIES).toEqual(['critical', 'high', 'medium', 'low']);
|
|
28
|
+
expect(REVIEW_FINDING_SEVERITIES.filter(isAdvisoryHoldFindingSeverity)).toEqual(['critical', 'high', 'medium', 'low']);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('rejects info and unknown severities so info can auto-publish', () => {
|
|
32
|
+
expect(isAdvisoryHoldFindingSeverity('info')).toBe(false);
|
|
33
|
+
expect(isAdvisoryHoldFindingSeverity('unknown')).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import type { Pagination } from '../pagination/index.js';
|
|
2
|
+
|
|
1
3
|
export const AI_AGENT_STATUSES = ['active', 'disabled'] as const;
|
|
2
4
|
|
|
3
5
|
export const REVIEW_POLICY_NAME_MAX_LENGTH = 120;
|
|
4
6
|
export const REVIEW_POLICY_PROMPT_MAX_LENGTH = 10000;
|
|
5
7
|
|
|
6
8
|
// Display name of the Superblocks-managed built-in security scan. One per organization.
|
|
7
|
-
export const BUILT_IN_SECURITY_SCAN_NAME = 'Security Scan';
|
|
9
|
+
export const BUILT_IN_SECURITY_SCAN_NAME = 'Superblocks Security Scan';
|
|
8
10
|
|
|
9
11
|
// Display name of the Superblocks-managed security agent. One per organization; its prompt is owned
|
|
10
|
-
// by the platform, so admins can only enable it and choose its mode.
|
|
11
|
-
|
|
12
|
-
export const SUPERBLOCKS_SECURITY_AGENT_NAME = 'Security Agent';
|
|
12
|
+
// by the platform, so admins can only enable it and choose its mode.
|
|
13
|
+
export const SUPERBLOCKS_SECURITY_AGENT_NAME = 'Superblocks Security Agent';
|
|
13
14
|
|
|
14
15
|
export const REVIEW_POLICY_TYPES = ['built_in_security_scan', 'security_agent'] as const;
|
|
15
16
|
export const REVIEW_POLICY_SOURCES = ['admin_configured', 'superblocks_managed'] as const;
|
|
@@ -36,6 +37,8 @@ export const REVIEW_FINDING_CATEGORIES = [
|
|
|
36
37
|
|
|
37
38
|
// Severity and confidence order is semantically meaningful from strongest to weakest.
|
|
38
39
|
export const REVIEW_FINDING_SEVERITIES = ['critical', 'high', 'medium', 'low', 'info'] as const;
|
|
40
|
+
/** Severities that pause publish for "Publish anyway" in any policy mode. Info auto-publishes. */
|
|
41
|
+
export const ADVISORY_HOLD_FINDING_SEVERITIES = ['critical', 'high', 'medium', 'low'] as const;
|
|
39
42
|
/** Severities that hard-block publish when a policy is in blocking mode (ENG-5334 / APPS-5406). */
|
|
40
43
|
export const BLOCKING_FINDING_SEVERITIES = ['critical', 'high'] as const;
|
|
41
44
|
export const REVIEW_FINDING_CONFIDENCES = ['high', 'medium', 'low'] as const;
|
|
@@ -70,9 +73,15 @@ export type ReviewPolicyRunnerType = (typeof REVIEW_POLICY_RUNNER_TYPES)[number]
|
|
|
70
73
|
export type ReviewFindingSourcePhase = (typeof REVIEW_FINDING_SOURCE_PHASES)[number];
|
|
71
74
|
export type ReviewFindingCategory = (typeof REVIEW_FINDING_CATEGORIES)[number];
|
|
72
75
|
export type ReviewFindingSeverity = (typeof REVIEW_FINDING_SEVERITIES)[number];
|
|
76
|
+
export type AdvisoryHoldFindingSeverity = (typeof ADVISORY_HOLD_FINDING_SEVERITIES)[number];
|
|
73
77
|
export type BlockingFindingSeverity = (typeof BLOCKING_FINDING_SEVERITIES)[number];
|
|
74
78
|
export type ReviewFindingConfidence = (typeof REVIEW_FINDING_CONFIDENCES)[number];
|
|
75
79
|
|
|
80
|
+
/** True when a finding severity pauses publish until the user acknowledges with "Publish anyway". */
|
|
81
|
+
export function isAdvisoryHoldFindingSeverity(severity: string): severity is AdvisoryHoldFindingSeverity {
|
|
82
|
+
return (ADVISORY_HOLD_FINDING_SEVERITIES as readonly string[]).includes(severity);
|
|
83
|
+
}
|
|
84
|
+
|
|
76
85
|
/** True when a finding severity hard-blocks publish under blocking-mode policy gates. */
|
|
77
86
|
export function isBlockingFindingSeverity(severity: string): severity is BlockingFindingSeverity {
|
|
78
87
|
return (BLOCKING_FINDING_SEVERITIES as readonly string[]).includes(severity);
|
|
@@ -92,6 +101,27 @@ export interface ReviewPolicyLastRunDto {
|
|
|
92
101
|
id: string;
|
|
93
102
|
status: ReviewRunStatus;
|
|
94
103
|
created: string;
|
|
104
|
+
findingsCount: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Lifecycle stages for the Policies page strip/table. Derived from
|
|
108
|
+
// `review_policy_version.trigger` today; not a persisted column. -> TODO add this as a persistent
|
|
109
|
+
// column when we actually want to implement this functionality
|
|
110
|
+
export const REVIEW_POLICY_STAGES = ['development', 'publish', 'production'] as const;
|
|
111
|
+
export type ReviewPolicyStage = (typeof REVIEW_POLICY_STAGES)[number];
|
|
112
|
+
|
|
113
|
+
// Product domain for a policy (security scanners/agents vs future kinds).
|
|
114
|
+
// Only `security` ships today; extend this allowlist when accessibility (etc.) lands.
|
|
115
|
+
export const REVIEW_POLICY_DOMAINS = ['security'] as const;
|
|
116
|
+
export type ReviewPolicyDomain = (typeof REVIEW_POLICY_DOMAINS)[number];
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Maps a concrete policy type onto its product domain. Every type today is
|
|
120
|
+
* security; add branches (and REVIEW_POLICY_DOMAINS values) when non-security
|
|
121
|
+
* policies ship. Do not invent UI-only domain labels.
|
|
122
|
+
*/
|
|
123
|
+
export function reviewPolicyDomainForType(_policyType: ReviewPolicyType): ReviewPolicyDomain {
|
|
124
|
+
return 'security';
|
|
95
125
|
}
|
|
96
126
|
|
|
97
127
|
export interface ReviewPolicyDto {
|
|
@@ -106,6 +136,10 @@ export interface ReviewPolicyDto {
|
|
|
106
136
|
status: AiAgentStatus;
|
|
107
137
|
mode: ReviewPolicyMode;
|
|
108
138
|
scope: ReviewPolicyScopeDto;
|
|
139
|
+
stage: ReviewPolicyStage;
|
|
140
|
+
// Derived for the wire today (not a DB column). See reviewPolicyDomainForType.
|
|
141
|
+
// maybe replace with col in the future as we add more
|
|
142
|
+
domain: ReviewPolicyDomain;
|
|
109
143
|
lastRun: ReviewPolicyLastRunDto | null;
|
|
110
144
|
freshPendingApprovalRunCount: number;
|
|
111
145
|
createdBy: string | null;
|
|
@@ -121,6 +155,9 @@ export interface ReviewPolicyRunDto {
|
|
|
121
155
|
applicationId: string;
|
|
122
156
|
applicationName: string | null;
|
|
123
157
|
applicationCommitId: string;
|
|
158
|
+
applicationCommitMessage: string | null;
|
|
159
|
+
policyId: string;
|
|
160
|
+
policyName: string;
|
|
124
161
|
policyVersionNumber: number;
|
|
125
162
|
findingsCount: number;
|
|
126
163
|
profileId: string;
|
|
@@ -128,6 +165,8 @@ export interface ReviewPolicyRunDto {
|
|
|
128
165
|
decision: ReviewRunDecision | null;
|
|
129
166
|
decisionReason: string | null;
|
|
130
167
|
hasFreshPendingApproval: boolean;
|
|
168
|
+
triggeredBy: ReviewRunTriggeredBy | null;
|
|
169
|
+
triggeringUserName: string | null;
|
|
131
170
|
startedAt: string | null;
|
|
132
171
|
completedAt: string | null;
|
|
133
172
|
created: string;
|
|
@@ -164,10 +203,20 @@ export interface ReviewPolicyRunReportDto {
|
|
|
164
203
|
findings: ReviewFindingDto[];
|
|
165
204
|
}
|
|
166
205
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
206
|
+
// Sort keys for GET .../runs. Order is alphabetical; default at the API is startedAt desc.
|
|
207
|
+
export const REVIEW_POLICY_RUN_SORTS = ['applicationName', 'findingsCount', 'startedAt', 'status'] as const;
|
|
208
|
+
export type ReviewPolicyRunSort = (typeof REVIEW_POLICY_RUN_SORTS)[number];
|
|
209
|
+
export const DEFAULT_REVIEW_POLICY_RUN_SORT: ReviewPolicyRunSort = 'startedAt';
|
|
210
|
+
|
|
211
|
+
export const REVIEW_POLICY_RUN_ORDERS = ['asc', 'desc'] as const;
|
|
212
|
+
export type ReviewPolicyRunOrder = (typeof REVIEW_POLICY_RUN_ORDERS)[number];
|
|
213
|
+
export const DEFAULT_REVIEW_POLICY_RUN_ORDER: ReviewPolicyRunOrder = 'desc';
|
|
214
|
+
|
|
215
|
+
export const DEFAULT_REVIEW_POLICY_RUNS_LIMIT = 20;
|
|
216
|
+
export const MAX_REVIEW_POLICY_RUNS_LIMIT = 100;
|
|
217
|
+
|
|
218
|
+
// Offset-paginated runs list. Policy header comes from GET .../:policyId.
|
|
219
|
+
export type ReviewPolicyRunsDto = Pagination<ReviewPolicyRunDto>;
|
|
171
220
|
|
|
172
221
|
// Trailing-time windows the summary can be scoped to. Order is semantically
|
|
173
222
|
// meaningful (shortest to longest) for rendering the selector.
|
|
@@ -176,17 +225,23 @@ export type ReviewPolicySummaryWindow = (typeof REVIEW_POLICY_SUMMARY_WINDOWS)[n
|
|
|
176
225
|
export const DEFAULT_REVIEW_POLICY_SUMMARY_WINDOW: ReviewPolicySummaryWindow = '24h';
|
|
177
226
|
|
|
178
227
|
export interface ReviewPolicySummaryDto {
|
|
179
|
-
// `
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
securityScans: number;
|
|
228
|
+
// `activePolicies` is a point-in-time count and is not affected by `window`.
|
|
229
|
+
activePolicies: number;
|
|
230
|
+
totalRuns: number;
|
|
183
231
|
findings: number;
|
|
232
|
+
// 0–100. Zero when there are no qualifying runs in the window (no divide-by-zero).
|
|
233
|
+
passRate: number;
|
|
184
234
|
window: ReviewPolicySummaryWindow;
|
|
185
235
|
}
|
|
186
236
|
|
|
187
237
|
export type CreateReviewPolicyBody =
|
|
188
238
|
| { policyType: 'built_in_security_scan'; mode?: ReviewPolicyMode; scope?: ReviewPolicyScopeInput }
|
|
189
|
-
| {
|
|
239
|
+
| {
|
|
240
|
+
policyType: 'security_agent';
|
|
241
|
+
source: 'superblocks_managed';
|
|
242
|
+
mode?: ReviewPolicyMode;
|
|
243
|
+
scope?: ReviewPolicyScopeInput;
|
|
244
|
+
}
|
|
190
245
|
| {
|
|
191
246
|
policyType: 'security_agent';
|
|
192
247
|
mode: ReviewPolicyMode;
|
package/src/types/scim/index.ts
CHANGED
|
@@ -38,6 +38,9 @@ type ScimMeta = {
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
export type ScimUserName = {
|
|
41
|
+
// RFC 7643 section 4.1.1: the full name including titles and suffixes. It is the only name
|
|
42
|
+
// attribute that can populate a single-string stored name without losing tokens.
|
|
43
|
+
formatted?: string;
|
|
41
44
|
givenName: string;
|
|
42
45
|
middleName?: string;
|
|
43
46
|
familyName: string;
|