@cubist-labs/cubesigner-sdk 0.4.236 → 0.4.239

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.
@@ -0,0 +1,195 @@
1
+ import { z } from "zod/mini";
2
+ import type { components } from "./schema";
3
+
4
+ type OrgEventDiscriminants = components["schemas"]["OrgEventDiscriminants"];
5
+ type BillingEvent = components["schemas"]["BillingEvent"];
6
+ type MemberRole = components["schemas"]["MemberRole"];
7
+ type OperationKind = components["schemas"]["OperationKind"];
8
+ type KeyType = components["schemas"]["KeyType"];
9
+
10
+ const schemaString = <T extends string>() => z.custom<T>((val) => typeof val === "string");
11
+
12
+ const baseFields = {
13
+ /** The type of org event. */
14
+ event: z.string(),
15
+ /** UUID uniquely identifying this event across all events. */
16
+ event_id: z.string(),
17
+ /** The org in which this event occurred. */
18
+ org_id: z.string(),
19
+ /** ID of the HTTP request that triggered this event (one request can trigger multiple events). */
20
+ request_id: z.string(),
21
+ /** Timestamp of when the event was logged, formatted like YYYY-MM-DD HH:MM:SS.NNNNNNNNN */
22
+ time: z.string(),
23
+ /** ID of the user or role that triggered the event; absent for unauthenticated endpoints. */
24
+ triggered_by: z.nullable(z.string()),
25
+ };
26
+
27
+ export const auditLogEntrySchema = z.discriminatedUnion("event", [
28
+ z.object({
29
+ ...baseFields,
30
+ event: z.literal("Billing"),
31
+ kind: schemaString<BillingEvent>(),
32
+ user_id: z.optional(z.string()),
33
+ role_id: z.optional(z.string()),
34
+ key_id: z.optional(z.string()),
35
+ }),
36
+ z.object({
37
+ ...baseFields,
38
+ event: z.literal("Response"),
39
+ kind: schemaString<BillingEvent>(),
40
+ status: z.coerce.number(),
41
+ duration_ms: z.coerce.number(),
42
+ }),
43
+ z.object({
44
+ ...baseFields,
45
+ event: z.literal("OidcAuth"),
46
+ issuer: z.string(),
47
+ membership: schemaString<MemberRole>(),
48
+ email: z.optional(z.string()),
49
+ username: z.optional(z.string()),
50
+ scopes: z.array(z.string()),
51
+ }),
52
+ z.object({
53
+ ...baseFields,
54
+ event: z.literal("Signed"),
55
+ kind: schemaString<OperationKind>(),
56
+ key_type: schemaString<KeyType>(),
57
+ key_id: z.string(),
58
+ }),
59
+ z.object({
60
+ ...baseFields,
61
+ event: z.literal("BabylonEotsConcurrentSigning"),
62
+ key_id: z.string(),
63
+ chain_id: z.string(),
64
+ prev_block_height: z.coerce.number(),
65
+ prev_signing_hash: z.string(),
66
+ req_block_height: z.coerce.number(),
67
+ req_signing_hash: z.string(),
68
+ }),
69
+ z.object({
70
+ ...baseFields,
71
+ event: z.literal("Eth2ConcurrentAttestationSigning"),
72
+ key_id: z.string(),
73
+ }),
74
+ z.object({
75
+ ...baseFields,
76
+ event: z.literal("Eth2ConcurrentBlockSigning"),
77
+ key_id: z.string(),
78
+ }),
79
+ z.object({
80
+ ...baseFields,
81
+ event: z.literal("Eth2InvalidBlockProposerSlotTooLow"),
82
+ slot: z.coerce.number(),
83
+ signing_root: z.string(),
84
+ last_slot: z.coerce.number(),
85
+ last_signing_root: z.string(),
86
+ enforced: z.coerce.boolean(),
87
+ }),
88
+ z.object({
89
+ ...baseFields,
90
+ event: z.literal("Eth2InvalidAttestationSourceEpochTooLow"),
91
+ source_epoch: z.coerce.number(),
92
+ signing_root: z.string(),
93
+ last_target_epoch: z.coerce.number(),
94
+ last_signing_root: z.string(),
95
+ enforced: z.coerce.boolean(),
96
+ }),
97
+ z.object({
98
+ ...baseFields,
99
+ event: z.literal("Eth2InvalidAttestationTargetEpochTooLow"),
100
+ target_epoch: z.coerce.number(),
101
+ signing_root: z.string(),
102
+ last_target_epoch: z.coerce.number(),
103
+ last_signing_root: z.string(),
104
+ enforced: z.coerce.boolean(),
105
+ }),
106
+ z.object({
107
+ ...baseFields,
108
+ event: z.literal("Eth2Unstake"),
109
+ key_id: z.string(),
110
+ validator_index: z.coerce.number(),
111
+ daily_unstake_count: z.coerce.number(),
112
+ }),
113
+ z.object({
114
+ ...baseFields,
115
+ event: z.literal("Eth2ExceededMaxUnstake"),
116
+ max: z.coerce.number(),
117
+ date: z.string(),
118
+ }),
119
+ z.object({
120
+ ...baseFields,
121
+ event: z.literal("KeyCreated"),
122
+ key_type: schemaString<KeyType>(),
123
+ owner_id: z.string(),
124
+ count: z.coerce.number(),
125
+ }),
126
+ z.object({
127
+ ...baseFields,
128
+ event: z.literal("MfaApproved"),
129
+ mfa_id: z.string(),
130
+ meets_approval_criteria: z.coerce.boolean(),
131
+ }),
132
+ z.object({
133
+ ...baseFields,
134
+ event: z.literal("MfaRejected"),
135
+ mfa_id: z.string(),
136
+ }),
137
+ z.object({
138
+ ...baseFields,
139
+ event: z.literal("PolicyChanged"),
140
+ }),
141
+ z.object({
142
+ ...baseFields,
143
+ event: z.literal("TendermintConcurrentSigning"),
144
+ key_id: z.string(),
145
+ chain_id: z.string(),
146
+ last_state: z.string(),
147
+ current_state: z.string(),
148
+ }),
149
+ z.object({
150
+ ...baseFields,
151
+ event: z.literal("InvitationCreated"),
152
+ email: z.string(),
153
+ role: z.string(),
154
+ }),
155
+ z.object({
156
+ ...baseFields,
157
+ event: z.literal("InvitationCanceled"),
158
+ email: z.string(),
159
+ }),
160
+ z.object({
161
+ ...baseFields,
162
+ event: z.literal("UserExportInit"),
163
+ key_id: z.string(),
164
+ valid_epoch: z.coerce.number(),
165
+ }),
166
+ z.object({
167
+ ...baseFields,
168
+ event: z.literal("UserExportComplete"),
169
+ key_id: z.string(),
170
+ }),
171
+ z.object({
172
+ ...baseFields,
173
+ event: z.literal("WasmPolicyExecuted"),
174
+ source: z.string(),
175
+ key_id: z.optional(z.string()),
176
+ policy: z.string(),
177
+ policy_hash: z.string(),
178
+ stdout: z.string(),
179
+ stderr: z.string(),
180
+ response: z.string(),
181
+ reason: z.optional(z.string()),
182
+ error: z.optional(z.string()),
183
+ }),
184
+ ]);
185
+
186
+ export type AuditLogEntry = z.infer<typeof auditLogEntrySchema>;
187
+
188
+ // Compile-time check: errors if a variant is added to OrgEventDiscriminants but not handled here.
189
+ type _AllVariantsCovered = [OrgEventDiscriminants] extends [AuditLogEntry["event"]]
190
+ ? [AuditLogEntry["event"]] extends [OrgEventDiscriminants]
191
+ ? true
192
+ : never
193
+ : never;
194
+ const _allVariantsCovered: _AllVariantsCovered = true;
195
+ void _allVariantsCovered;
package/src/bucket.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type { Ace, AceAttribute } from "./acl";
2
+ import type { BucketAction, schemas } from "./schema_types";
3
+
4
+ /** Access control entry for policy buckets */
5
+ export type BucketAce = Ace<
6
+ BucketAction,
7
+ {
8
+ policy_ids?: AceAttribute<string>;
9
+ bucket_keys?: AceAttribute<string>;
10
+ }
11
+ >;
12
+
13
+ /** Policy bucket information (like the one from {@link schemas} but with more precise `acl`) */
14
+ export type BucketInfo = schemas["BucketInfo"] & {
15
+ acl?: BucketAce[];
16
+ };
17
+
18
+ /**
19
+ * Coerce the less accurate `BucketInfo` type from the OpenAPI schema to a more accurate {@link BucketInfo}.
20
+ *
21
+ * @param b The bucket info received on the wire.
22
+ * @returns The exact same value coerced to the {@link BucketInfo} type.
23
+ */
24
+ export function coerceBucketInfo(b: schemas["BucketInfo"]): BucketInfo {
25
+ return {
26
+ ...b,
27
+ // TODO: parse once we add Zod
28
+ acl: b.acl as BucketAce[],
29
+ };
30
+ }
@@ -54,7 +54,6 @@ import type {
54
54
  UpdatePolicyRequest,
55
55
  ListPoliciesResponse,
56
56
  PolicyType,
57
- PolicyInfo,
58
57
  DiffieHellmanRequest,
59
58
  DiffieHellmanResponse,
60
59
  KeyInfoJwt,
@@ -67,8 +66,12 @@ import type {
67
66
  KeyAttestationQuery,
68
67
  RoleAttestationQuery,
69
68
  ErrorResponse,
69
+ ListBucketsResponse,
70
+ UpdateBucketRequest,
71
+ PolicyInfo,
70
72
  } from "../schema_types";
71
73
  import { encodeToBase64 } from "../util";
74
+ import { auditLogEntrySchema } from "../audit_log";
72
75
  import {
73
76
  AddFidoChallenge,
74
77
  MfaFidoChallenge,
@@ -152,6 +155,9 @@ import {
152
155
  type GetUserByOidcResponse,
153
156
  type EmailTemplatePurpose,
154
157
  ErrResponse,
158
+ coerceBucketInfo,
159
+ coercePolicyInfo,
160
+ type BucketInfo,
155
161
  } from "../index";
156
162
  import { assertOk, op, type Op, type Operation, apiFetch } from "../fetch";
157
163
  import { BaseClient, type ClientConfig, signerSessionFromSessionInfo } from "./base_client";
@@ -560,7 +566,11 @@ export class ApiClient extends BaseClient {
560
566
  return Paginator.items(
561
567
  page ?? Page.default(),
562
568
  (query) => this.exec(o, { body, params: { query } }),
563
- (r) => r.entries,
569
+ (r) =>
570
+ r.entries.flatMap((entry) => {
571
+ const result = auditLogEntrySchema.safeParse(entry);
572
+ return result.success ? [result.data] : [];
573
+ }),
564
574
  (r) => r.last_evaluated_key,
565
575
  );
566
576
  }
@@ -1525,14 +1535,14 @@ export class ApiClient extends BaseClient {
1525
1535
  acl?: JsonValue[],
1526
1536
  ): Promise<PolicyInfo> {
1527
1537
  const o = op("/v0/org/{org_id}/policies", "post");
1528
- return (await this.exec(o, {
1538
+ return await this.exec(o, {
1529
1539
  body: {
1530
1540
  name,
1531
1541
  policy_type: type,
1532
1542
  rules,
1533
1543
  acl,
1534
1544
  },
1535
- })) as PolicyInfo;
1545
+ }).then(coercePolicyInfo);
1536
1546
  }
1537
1547
 
1538
1548
  /**
@@ -1544,9 +1554,9 @@ export class ApiClient extends BaseClient {
1544
1554
  */
1545
1555
  async policyGet(policyId: string, version: policy.Version): Promise<PolicyInfo> {
1546
1556
  const o = op("/v0/org/{org_id}/policies/{policy_id}/{version}", "get");
1547
- return (await this.exec(o, {
1557
+ return await this.exec(o, {
1548
1558
  params: { path: { policy_id: policyId, version } },
1549
- })) as PolicyInfo;
1559
+ }).then(coercePolicyInfo);
1550
1560
  }
1551
1561
 
1552
1562
  /**
@@ -1583,17 +1593,13 @@ export class ApiClient extends BaseClient {
1583
1593
  mfaReceipt?: MfaReceipts,
1584
1594
  ): Promise<CubeSignerResponse<PolicyInfo>> {
1585
1595
  const o = op("/v0/org/{org_id}/policies/{policy_id}", "patch");
1586
- const signFn = async (headers?: HeadersInit) =>
1596
+ const reqFn = async (headers?: HeadersInit) =>
1587
1597
  this.exec(o, {
1588
1598
  params: { path: { policy_id: policyId } },
1589
1599
  body: request,
1590
1600
  headers,
1591
- });
1592
- return (await CubeSignerResponse.create(
1593
- this.env,
1594
- signFn,
1595
- mfaReceipt,
1596
- )) as CubeSignerResponse<PolicyInfo>;
1601
+ }).then((resp) => mapResponse(resp, coercePolicyInfo));
1602
+ return await CubeSignerResponse.create(this.env, reqFn, mfaReceipt);
1597
1603
  }
1598
1604
 
1599
1605
  /**
@@ -1638,6 +1644,62 @@ export class ApiClient extends BaseClient {
1638
1644
 
1639
1645
  // #endregion
1640
1646
 
1647
+ // #region BUCKET: bucket(Get|List|Update)
1648
+
1649
+ /**
1650
+ * List available meta information about all policy buckets in the org.
1651
+ *
1652
+ * @param page Pagination options. Defaults to fetching the entire result set.
1653
+ * @returns Paginator for iterating over policy buckets.
1654
+ */
1655
+ bucketsList(page?: PageOpts): Paginator<ListBucketsResponse, BucketInfo[]> {
1656
+ const o = op("/v0/org/{org_id}/policy/buckets", "get");
1657
+ return Paginator.items(
1658
+ page ?? Page.default(),
1659
+ (pageQuery) => this.exec(o, { params: { query: { ...pageQuery } } }),
1660
+ (r) => r.buckets,
1661
+ (r) => r.last_evaluated_key,
1662
+ ) as Paginator<ListBucketsResponse, BucketInfo[]>;
1663
+ }
1664
+
1665
+ /**
1666
+ * Get the meta information of a policy KV store bucket.
1667
+ *
1668
+ * @param bucketName The name of the bucket to get
1669
+ * @returns The bucket information
1670
+ */
1671
+ async bucketGet(bucketName: string): Promise<BucketInfo> {
1672
+ const o = op("/v0/org/{org_id}/policy/buckets/{bucket_name}", "get");
1673
+ return await this.exec(o, {
1674
+ params: { path: { bucket_name: bucketName } },
1675
+ }).then(coerceBucketInfo);
1676
+ }
1677
+
1678
+ /**
1679
+ * Set or update meta information for a policy KV store bucket.
1680
+ *
1681
+ * @param bucketName The name of the bucket to update.
1682
+ * @param request The update request
1683
+ * @param mfaReceipt Option MFA receipt(s)
1684
+ * @returns The updated bucket information
1685
+ */
1686
+ async bucketUpdate(
1687
+ bucketName: string,
1688
+ request: UpdateBucketRequest,
1689
+ mfaReceipt?: MfaReceipts,
1690
+ ): Promise<CubeSignerResponse<BucketInfo>> {
1691
+ const o = op("/v0/org/{org_id}/policy/buckets/{bucket_name}", "patch");
1692
+ const reqFn = async (headers?: HeadersInit) =>
1693
+ this.exec(o, {
1694
+ params: { path: { bucket_name: bucketName } },
1695
+ body: request,
1696
+ headers,
1697
+ }).then((resp) => mapResponse(resp, coerceBucketInfo));
1698
+ return await CubeSignerResponse.create(this.env, reqFn, mfaReceipt);
1699
+ }
1700
+
1701
+ // #endregion
1702
+
1641
1703
  // #region WASM: wasm(PolicyUpload)
1642
1704
 
1643
1705
  /**
package/src/index.ts CHANGED
@@ -34,6 +34,8 @@ export * from "./contact";
34
34
  export * from "./scopes";
35
35
  /** Policies */
36
36
  export * from "./policy";
37
+ /** Buckets */
38
+ export * from "./bucket";
37
39
  /** Access control */
38
40
  export * from "./acl";
39
41
  /** Utils */
package/src/policy.ts CHANGED
@@ -10,15 +10,15 @@ import type {
10
10
  KeyPolicyRule,
11
11
  MfaReceipts,
12
12
  PolicyAttachedToId,
13
- PolicyInfo,
14
13
  PolicyType,
15
14
  RolePolicy,
16
15
  RolePolicyRule,
17
16
  UpdatePolicyRequest,
18
17
  WasmRule,
19
- Acl,
20
18
  AceAttribute,
21
19
  PolicyAction,
20
+ Ace,
21
+ PolicyInfo,
22
22
  } from ".";
23
23
 
24
24
  import { loadSubtleCrypto } from ".";
@@ -32,7 +32,7 @@ export type PolicyRule = KeyPolicyRule | RolePolicyRule | WasmRule;
32
32
  * A helper type for {@link PolicyInfo} with a more detailed `acl` type.
33
33
  */
34
34
  type NamedPolicyInfo = PolicyInfo & {
35
- acl?: Acl<PolicyAction, PolicyCtx>;
35
+ acl?: PolicyAcl;
36
36
  };
37
37
 
38
38
  /**
@@ -67,7 +67,10 @@ export type C2FInfo = WasmPolicyInfo;
67
67
  export type Version = `v${number}` | `latest`;
68
68
 
69
69
  /** A policy access control entry. */
70
- export type PolicyAcl = Acl<PolicyAction, PolicyCtx>;
70
+ export type PolicyAce = Ace<PolicyAction, PolicyCtx>;
71
+
72
+ /** A policy access control list. */
73
+ export type PolicyAcl = PolicyAce[];
71
74
 
72
75
  /** Additional contexts when using policies. */
73
76
  export type PolicyCtx = {
@@ -476,7 +479,7 @@ export class C2FFunction extends NamedPolicy {
476
479
  // upload the policy object
477
480
  const hash = await uploadWasmFunction(this.apiClient, policy);
478
481
 
479
- // update this policy with the new policy verison.
482
+ // update this policy with the new policy version.
480
483
  const body: UpdatePolicyRequest = { rules: [{ hash }] };
481
484
  this.data = (await this.update(body, mfaReceipt)) as C2FInfo;
482
485
  }