@sixb/core 0.1.19 → 0.1.20

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.
Files changed (211) hide show
  1. package/dist/actions/index.js +24 -24
  2. package/dist/agents/index.js +25 -25
  3. package/dist/agents/index.js.map +1 -1
  4. package/dist/auth/cookies.d.ts +2 -4
  5. package/dist/auth/cookies.d.ts.map +1 -1
  6. package/dist/auth/index.d.ts +0 -2
  7. package/dist/auth/index.d.ts.map +1 -1
  8. package/dist/auth/index.js +8 -14
  9. package/dist/auth/index.js.map +1 -1
  10. package/dist/auth/runtime.d.ts +8 -10
  11. package/dist/auth/runtime.d.ts.map +1 -1
  12. package/dist/auth/session-cache.d.ts +1 -5
  13. package/dist/auth/session-cache.d.ts.map +1 -1
  14. package/dist/auth/strategy.js +1 -1
  15. package/dist/auth/types.d.ts +4 -8
  16. package/dist/auth/types.d.ts.map +1 -1
  17. package/dist/auth/validation.d.ts +0 -1
  18. package/dist/auth/validation.d.ts.map +1 -1
  19. package/dist/authorization/decision.d.ts +0 -4
  20. package/dist/authorization/decision.d.ts.map +1 -1
  21. package/dist/authorization/grant-kinds.d.ts +6 -8
  22. package/dist/authorization/grant-kinds.d.ts.map +1 -1
  23. package/dist/authorization/index.d.ts +0 -1
  24. package/dist/authorization/index.d.ts.map +1 -1
  25. package/dist/authorization/index.js +3 -7
  26. package/dist/authorization/index.js.map +1 -1
  27. package/dist/authorization/resolve.d.ts +1 -1
  28. package/dist/authorization/resolve.d.ts.map +1 -1
  29. package/dist/bootstrap/index.js +26 -26
  30. package/dist/{chunk-aff7cyea.js → chunk-0rbyz4qy.js} +21 -21
  31. package/dist/{chunk-aff7cyea.js.map → chunk-0rbyz4qy.js.map} +1 -1
  32. package/dist/{chunk-rz53yb4v.js → chunk-0yh890a4.js} +1 -1
  33. package/dist/{chunk-7mbzgd9m.js → chunk-1zq2p6g0.js} +1 -1
  34. package/dist/{chunk-dnmadg9k.js → chunk-3t2hgbgd.js} +2 -2
  35. package/dist/{chunk-wwdfe68s.js → chunk-4vyr1j8f.js} +2 -2
  36. package/dist/{chunk-kyzq4wy9.js → chunk-5j58wjct.js} +15 -15
  37. package/dist/chunk-5j58wjct.js.map +18 -0
  38. package/dist/{chunk-ey3pyej1.js → chunk-6c6sn0bh.js} +29 -24
  39. package/dist/{chunk-ey3pyej1.js.map → chunk-6c6sn0bh.js.map} +3 -3
  40. package/dist/{chunk-q1vkr2ys.js → chunk-6p49a5cq.js} +2 -2
  41. package/dist/{chunk-nre82s12.js → chunk-9dmt152s.js} +1 -1
  42. package/dist/{chunk-7kg3k1m9.js → chunk-9w055r5b.js} +1 -1
  43. package/dist/{chunk-4tcx876c.js → chunk-bx9q3cwv.js} +15 -15
  44. package/dist/{chunk-4tcx876c.js.map → chunk-bx9q3cwv.js.map} +1 -1
  45. package/dist/{chunk-bpgy64fw.js → chunk-d09tj99x.js} +1 -1
  46. package/dist/{chunk-y7rqfrgg.js → chunk-d0bqz29d.js} +23 -36
  47. package/dist/chunk-d0bqz29d.js.map +23 -0
  48. package/dist/{chunk-rhg02hxq.js → chunk-dk8tkk5f.js} +3 -3
  49. package/dist/{chunk-xt1zt7gv.js → chunk-es1gxsbf.js} +24 -15
  50. package/dist/chunk-es1gxsbf.js.map +13 -0
  51. package/dist/{chunk-52bk93x8.js → chunk-fkgc1wt8.js} +1 -1
  52. package/dist/{chunk-enpsx8k5.js → chunk-gsjm1wms.js} +16 -20
  53. package/dist/chunk-gsjm1wms.js.map +10 -0
  54. package/dist/{chunk-2jntasmh.js → chunk-hcbyfxbe.js} +25 -49
  55. package/dist/chunk-hcbyfxbe.js.map +12 -0
  56. package/dist/{chunk-zrmy8zvw.js → chunk-hjzdd750.js} +3 -3
  57. package/dist/chunk-hkc3jct7.js.map +1 -1
  58. package/dist/{chunk-85yvv5n0.js → chunk-k6q3n2sc.js} +3 -3
  59. package/dist/{chunk-j2bp5ryw.js → chunk-n33z5bjw.js} +11 -10
  60. package/dist/{chunk-j2bp5ryw.js.map → chunk-n33z5bjw.js.map} +3 -3
  61. package/dist/{chunk-80mc0971.js → chunk-ren4kg2j.js} +8 -8
  62. package/dist/{chunk-1f7wpmyp.js → chunk-rrzt8jdy.js} +2 -2
  63. package/dist/{chunk-6gmfggss.js → chunk-t7x8dmn0.js} +2 -2
  64. package/dist/{chunk-wz0xs816.js → chunk-tg2cw67r.js} +1 -1
  65. package/dist/{chunk-3gnrh4ve.js → chunk-vpq4shxz.js} +46 -106
  66. package/dist/chunk-vpq4shxz.js.map +39 -0
  67. package/dist/{chunk-bwjcehza.js → chunk-way52z4h.js} +1 -1
  68. package/dist/{chunk-tjb1mk5t.js → chunk-x6m907x7.js} +2 -2
  69. package/dist/{chunk-t6vq7bff.js → chunk-xfs8x8m9.js} +3 -3
  70. package/dist/{chunk-d2ync1v3.js → chunk-yevzdx4y.js} +3 -3
  71. package/dist/{chunk-kg5j6fct.js → chunk-z4m0yz8c.js} +1 -1
  72. package/dist/datasets/write.js +5 -5
  73. package/dist/deploy/internal.js +4 -3
  74. package/dist/deploy/internal.js.map +4 -4
  75. package/dist/deploy/services.d.ts.map +1 -1
  76. package/dist/deploy/types.d.ts +1 -2
  77. package/dist/deploy/types.d.ts.map +1 -1
  78. package/dist/execution/agent.js +24 -24
  79. package/dist/execution/authorization.d.ts.map +1 -1
  80. package/dist/execution/primitive.js +24 -24
  81. package/dist/execution/request.js +23 -23
  82. package/dist/index.d.ts +5 -5
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +33 -46
  85. package/dist/index.js.map +1 -1
  86. package/dist/lake-storage/index.js +5 -5
  87. package/dist/materializer/index.js +13 -13
  88. package/dist/models/execution/index.js +10 -10
  89. package/dist/objects/index.js +24 -24
  90. package/dist/objects/query/index.js +12 -12
  91. package/dist/objects/vectors/handle.d.ts.map +1 -1
  92. package/dist/objects/vectors/profile.d.ts +5 -0
  93. package/dist/objects/vectors/profile.d.ts.map +1 -1
  94. package/dist/ontology/index.js +3 -3
  95. package/dist/pipelines/index.js +15 -15
  96. package/dist/projections/internal.js +13 -13
  97. package/dist/runtime/internal.js +13 -13
  98. package/dist/security/builders.d.ts.map +1 -1
  99. package/dist/security/every.d.ts +1 -4
  100. package/dist/security/every.d.ts.map +1 -1
  101. package/dist/security/grants.d.ts +2 -4
  102. package/dist/security/grants.d.ts.map +1 -1
  103. package/dist/security/index.d.ts +1 -2
  104. package/dist/security/index.d.ts.map +1 -1
  105. package/dist/security/membership-policies.d.ts.map +1 -1
  106. package/dist/security/public.d.ts +10 -0
  107. package/dist/security/public.d.ts.map +1 -0
  108. package/dist/security/public.js +10 -0
  109. package/dist/security/public.js.map +9 -0
  110. package/dist/security/registry.d.ts +0 -1
  111. package/dist/security/registry.d.ts.map +1 -1
  112. package/dist/security/types.d.ts +13 -18
  113. package/dist/security/types.d.ts.map +1 -1
  114. package/dist/security/validation.d.ts +0 -6
  115. package/dist/security/validation.d.ts.map +1 -1
  116. package/dist/shares/internal.js +10 -10
  117. package/dist/storage/agents/types.d.ts +1 -1
  118. package/dist/storage/auth/in-memory/auth-storage.d.ts.map +1 -1
  119. package/dist/storage/auth/in-memory/magic-links.d.ts.map +1 -1
  120. package/dist/storage/auth/in-memory/oidc-attempts.d.ts.map +1 -1
  121. package/dist/storage/auth/in-memory/sessions.d.ts +0 -10
  122. package/dist/storage/auth/in-memory/sessions.d.ts.map +1 -1
  123. package/dist/storage/auth/in-memory/shared.d.ts +1 -2
  124. package/dist/storage/auth/in-memory/shared.d.ts.map +1 -1
  125. package/dist/storage/auth/types.d.ts +1 -17
  126. package/dist/storage/auth/types.d.ts.map +1 -1
  127. package/dist/storage/file-upload-sessions/provider.js +6 -6
  128. package/dist/storage/index.js +21 -21
  129. package/dist/storage/index.js.map +1 -1
  130. package/dist/storage/workflow-runs/provider.js +6 -6
  131. package/dist/syncs/index.js +16 -16
  132. package/dist/testing/auth-storage-contract.d.ts.map +1 -1
  133. package/dist/testing/index.js +41 -124
  134. package/dist/testing/index.js.map +4 -4
  135. package/dist/webhooks/internal.js +11 -11
  136. package/dist/workflows/index.js +25 -25
  137. package/package.json +8 -2
  138. package/src/auth/cookies.ts +3 -20
  139. package/src/auth/index.ts +0 -6
  140. package/src/auth/runtime.ts +59 -76
  141. package/src/auth/session-cache.ts +2 -9
  142. package/src/auth/types.ts +4 -8
  143. package/src/auth/validation.ts +0 -2
  144. package/src/authorization/decision.ts +8 -23
  145. package/src/authorization/grant-kinds.ts +20 -27
  146. package/src/authorization/index.ts +0 -1
  147. package/src/authorization/resolve.ts +10 -6
  148. package/src/deploy/services.ts +0 -1
  149. package/src/deploy/types.ts +1 -2
  150. package/src/deploy/validation.ts +3 -1
  151. package/src/execution/authorization.ts +11 -5
  152. package/src/index.ts +1 -14
  153. package/src/models/execution/embedding.ts +6 -6
  154. package/src/objects/vectors/README.md +4 -0
  155. package/src/objects/vectors/handle.ts +11 -2
  156. package/src/objects/vectors/indexing-generate.ts +2 -2
  157. package/src/objects/vectors/profile.ts +5 -0
  158. package/src/security/builders.ts +7 -2
  159. package/src/security/every.ts +0 -4
  160. package/src/security/grants.ts +5 -25
  161. package/src/security/index.ts +0 -3
  162. package/src/security/membership-policies.ts +3 -1
  163. package/src/security/public.ts +10 -0
  164. package/src/security/registry.ts +0 -8
  165. package/src/security/types.ts +19 -25
  166. package/src/security/validation.ts +19 -17
  167. package/src/storage/agents/types.ts +1 -1
  168. package/src/storage/auth/in-memory/auth-storage.ts +0 -18
  169. package/src/storage/auth/in-memory/magic-links.ts +0 -3
  170. package/src/storage/auth/in-memory/oidc-attempts.ts +0 -3
  171. package/src/storage/auth/in-memory/sessions.ts +1 -25
  172. package/src/storage/auth/in-memory/shared.ts +1 -10
  173. package/src/storage/auth/types.ts +2 -18
  174. package/src/testing/auth-storage-contract.ts +14 -107
  175. package/src/testing/execution-storage-contract.ts +0 -2
  176. package/dist/auth/audience.d.ts +0 -8
  177. package/dist/auth/audience.d.ts.map +0 -1
  178. package/dist/authorization/application-access.d.ts +0 -18
  179. package/dist/authorization/application-access.d.ts.map +0 -1
  180. package/dist/chunk-2jntasmh.js.map +0 -13
  181. package/dist/chunk-3gnrh4ve.js.map +0 -40
  182. package/dist/chunk-enpsx8k5.js.map +0 -10
  183. package/dist/chunk-kyzq4wy9.js.map +0 -18
  184. package/dist/chunk-xt1zt7gv.js.map +0 -13
  185. package/dist/chunk-y7rqfrgg.js.map +0 -24
  186. package/dist/security/applications.d.ts +0 -15
  187. package/dist/security/applications.d.ts.map +0 -1
  188. package/src/auth/audience.ts +0 -28
  189. package/src/authorization/application-access.ts +0 -34
  190. package/src/security/applications.ts +0 -11
  191. /package/dist/{chunk-rz53yb4v.js.map → chunk-0yh890a4.js.map} +0 -0
  192. /package/dist/{chunk-7mbzgd9m.js.map → chunk-1zq2p6g0.js.map} +0 -0
  193. /package/dist/{chunk-dnmadg9k.js.map → chunk-3t2hgbgd.js.map} +0 -0
  194. /package/dist/{chunk-wwdfe68s.js.map → chunk-4vyr1j8f.js.map} +0 -0
  195. /package/dist/{chunk-q1vkr2ys.js.map → chunk-6p49a5cq.js.map} +0 -0
  196. /package/dist/{chunk-nre82s12.js.map → chunk-9dmt152s.js.map} +0 -0
  197. /package/dist/{chunk-7kg3k1m9.js.map → chunk-9w055r5b.js.map} +0 -0
  198. /package/dist/{chunk-bpgy64fw.js.map → chunk-d09tj99x.js.map} +0 -0
  199. /package/dist/{chunk-rhg02hxq.js.map → chunk-dk8tkk5f.js.map} +0 -0
  200. /package/dist/{chunk-52bk93x8.js.map → chunk-fkgc1wt8.js.map} +0 -0
  201. /package/dist/{chunk-zrmy8zvw.js.map → chunk-hjzdd750.js.map} +0 -0
  202. /package/dist/{chunk-85yvv5n0.js.map → chunk-k6q3n2sc.js.map} +0 -0
  203. /package/dist/{chunk-80mc0971.js.map → chunk-ren4kg2j.js.map} +0 -0
  204. /package/dist/{chunk-1f7wpmyp.js.map → chunk-rrzt8jdy.js.map} +0 -0
  205. /package/dist/{chunk-6gmfggss.js.map → chunk-t7x8dmn0.js.map} +0 -0
  206. /package/dist/{chunk-wz0xs816.js.map → chunk-tg2cw67r.js.map} +0 -0
  207. /package/dist/{chunk-bwjcehza.js.map → chunk-way52z4h.js.map} +0 -0
  208. /package/dist/{chunk-tjb1mk5t.js.map → chunk-x6m907x7.js.map} +0 -0
  209. /package/dist/{chunk-t6vq7bff.js.map → chunk-xfs8x8m9.js.map} +0 -0
  210. /package/dist/{chunk-d2ync1v3.js.map → chunk-yevzdx4y.js.map} +0 -0
  211. /package/dist/{chunk-kg5j6fct.js.map → chunk-z4m0yz8c.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Grant builders for role definitions.
3
3
  *
4
- * Grants are plain data referencing application and runtime definitions
4
+ * Grants are plain data referencing runtime definitions
5
5
  * by id. They carry no enforcement logic — the authorization engine expands
6
6
  * each grant's selection into per-principal id sets at startup, so runtime
7
7
  * checks stay simple `set.has(id)` lookups.
@@ -31,10 +31,8 @@ import {
31
31
  isBreadthSelector,
32
32
  } from "./every"
33
33
  import type {
34
- AccessGrant,
35
34
  AgentRunGrant,
36
35
  AppendGrant,
37
- ApplicationDefinition,
38
36
  ApplyGrant,
39
37
  EditGrant,
40
38
  ManageGrant,
@@ -54,7 +52,7 @@ const VIEW_TARGETS = ["object", "dataset"] as const
54
52
  const RUN_TARGETS = ["workflow", "sync", "pipeline"] as const
55
53
 
56
54
  /**
57
- * Seven of the nine targets carry a `kind` discriminant naming themselves. The other two — an
55
+ * Six of the eight targets carry a `kind` discriminant naming themselves. The other two — an
58
56
  * `ObjectType` and an `ActionDefinition` — carry none, and each appears in exactly one builder that
59
57
  * allows no other undiscriminated target, so the allowed set names them unambiguously.
60
58
  */
@@ -63,7 +61,6 @@ const TARGET_BY_DEFINITION_KIND: Readonly<Partial<Record<string, BreadthTarget>>
63
61
  sync: "sync",
64
62
  pipeline: "pipeline",
65
63
  workflow: "workflow",
66
- application: "application",
67
64
  connector: "connector",
68
65
  share: "share",
69
66
  }
@@ -82,7 +79,7 @@ function targetOfDefinition<TTarget extends BreadthTarget>(
82
79
  // `spec.universeKey` with a `TypeError` naming neither the role nor the definition.
83
80
  if (discriminated) {
84
81
  if (!isAllowedTarget(discriminated, allowedTargets)) {
85
- // "one targeting x", not "a x definition": four of the eight targets start with a vowel, and
82
+ // "one targeting x", not "a x definition": object and action start with a vowel, and
86
83
  // this string ships in a release. Same reason the selector branch below writes no article.
87
84
  throw new SecurityValidationError(
88
85
  `[Sixb] ${label} accepts ${allowedTargets.join(" or ")} definitions, but received one targeting ${discriminated}.`
@@ -158,11 +155,6 @@ function resolveGrant<TDefinition extends { readonly id?: unknown }, TTarget ext
158
155
  return { target, selection: { all: false, ids } }
159
156
  }
160
157
 
161
- function access(input: GrantInput<ApplicationDefinition, "application">): AccessGrant {
162
- const { selection } = resolveGrant(input, "can.access", ["application"])
163
- return { kind: "grant", capability: "access", target: "application", selection }
164
- }
165
-
166
158
  function view<const TObjectTypeId extends string>(
167
159
  input: ShareTarget<TObjectTypeId>
168
160
  ): ShareViewGrantBuilder<TObjectTypeId>
@@ -270,13 +262,7 @@ function observe(input: "logs" | AgentUsageReference): ObserveGrant {
270
262
  if (input !== "logs" && !isAgentUsageReference(input)) {
271
263
  throw new SecurityValidationError('[Sixb] can.observe accepts "logs" or agent.usage.')
272
264
  }
273
- const target = input === "logs" ? "logs" : "aiUsage"
274
- return {
275
- kind: "grant",
276
- capability: "observe",
277
- target,
278
- selection: { all: false, ids: [target] },
279
- }
265
+ return { kind: "grant", capability: "observe", target: input === "logs" ? "logs" : "aiUsage" }
280
266
  }
281
267
 
282
268
  function manage(input: GrantInput<ConnectorDefinition, "connector">): ManageGrant<"connector">
@@ -285,12 +271,7 @@ function manage(
285
271
  input: GrantInput<ConnectorDefinition, "connector"> | AgentUsageReference
286
272
  ): ManageGrant {
287
273
  if (isAgentUsageReference(input)) {
288
- return {
289
- kind: "grant",
290
- capability: "manage",
291
- target: "aiUsage",
292
- selection: { all: false, ids: ["aiUsage"] },
293
- }
274
+ return { kind: "grant", capability: "manage", target: "aiUsage" }
294
275
  }
295
276
  return {
296
277
  kind: "grant",
@@ -301,7 +282,6 @@ function manage(
301
282
  }
302
283
 
303
284
  export const can = {
304
- access,
305
285
  view,
306
286
  edit,
307
287
  append,
@@ -1,4 +1,3 @@
1
- export { applications } from "./applications"
2
1
  export type {
3
2
  DefineGroupOptions,
4
3
  DefineMarkingOptions,
@@ -20,10 +19,8 @@ export {
20
19
  export type { SecurityDefinitionCatalog, SecurityRegistryOptions } from "./registry"
21
20
  export { SecurityRegistry } from "./registry"
22
21
  export type {
23
- AccessGrant,
24
22
  AgentRunGrant,
25
23
  AppendGrant,
26
- ApplicationDefinition,
27
24
  ApplyGrant,
28
25
  EditGrant,
29
26
  GrantCapability,
@@ -10,7 +10,7 @@ export interface MembershipPolicyScope {
10
10
  readonly operations: Readonly<Record<MembershipOperation, MembershipOperationScope>>
11
11
  }
12
12
 
13
- const MEMBERSHIP_OPERATIONS = ["invite", "assignGroups", "suspend"] as const
13
+ const MEMBERSHIP_OPERATIONS = ["invite", "assignGroups", "suspend", "serviceAccounts"] as const
14
14
 
15
15
  export function resolveMembershipPolicyScope(input: {
16
16
  readonly membershipPolicies: readonly MembershipPolicyDefinition[]
@@ -40,6 +40,7 @@ export function resolveMembershipPolicyScope(input: {
40
40
  invite: freezeOperationScope(operations.invite),
41
41
  assignGroups: freezeOperationScope(operations.assignGroups),
42
42
  suspend: freezeOperationScope(operations.suspend),
43
+ serviceAccounts: freezeOperationScope(operations.serviceAccounts),
43
44
  },
44
45
  }
45
46
  }
@@ -83,6 +84,7 @@ function createEmptyOperationScopes(): Record<
83
84
  invite: { policyIds: [], groupIds: new Set<string>() },
84
85
  assignGroups: { policyIds: [], groupIds: new Set<string>() },
85
86
  suspend: { policyIds: [], groupIds: new Set<string>() },
87
+ serviceAccounts: { policyIds: [], groupIds: new Set<string>() },
86
88
  }
87
89
  }
88
90
 
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Browser-safe security entrypoint (`@sixb/core/security`).
3
+ *
4
+ * Group files import `defineGroup` from here, because an app layout imports groups to decide who
5
+ * sees which screens, and the browser cannot load the `@sixb/core` root.
6
+ */
7
+
8
+ export type { DefineGroupOptions } from "./builders"
9
+ export { defineGroup } from "./builders"
10
+ export type { GroupDefinition } from "./types"
@@ -1,5 +1,4 @@
1
1
  import { type ResolvedRole, resolveRoleGrants } from "../authorization"
2
- import { APPLICATION_IDS } from "./applications"
3
2
  import type {
4
3
  GroupDefinition,
5
4
  MarkingDefinition,
@@ -26,7 +25,6 @@ export interface SecurityRegistryOptions {
26
25
  readonly groups?: readonly GroupDefinition[]
27
26
  readonly roles?: readonly RoleDefinition[]
28
27
  readonly membershipPolicies?: readonly MembershipPolicyDefinition[]
29
- readonly applicationIds?: ReadonlySet<string>
30
28
  readonly objectTypeIds?: ReadonlySet<string>
31
29
  readonly datasetIds?: ReadonlySet<string>
32
30
  readonly actionIds?: ReadonlySet<string>
@@ -52,7 +50,6 @@ export class SecurityRegistry implements SecurityDefinitionCatalog {
52
50
  groups: input.groups ?? [],
53
51
  roles: input.roles ?? [],
54
52
  membershipPolicies: input.membershipPolicies ?? [],
55
- applicationIds: input.applicationIds ?? APPLICATION_IDS,
56
53
  objectTypeIds: input.objectTypeIds,
57
54
  datasetIds: input.datasetIds,
58
55
  actionIds: input.actionIds,
@@ -61,13 +58,10 @@ export class SecurityRegistry implements SecurityDefinitionCatalog {
61
58
  pipelineIds: input.pipelineIds,
62
59
  agentAvailable: input.agentAvailable,
63
60
  connectorIds: input.connectorIds,
64
- observableIds: new Set(["logs", "aiUsage"]),
65
- manageableIds: new Set(["aiUsage"]),
66
61
  shareIds: input.shareIds,
67
62
  })
68
63
 
69
64
  const universe = {
70
- applicationIds: input.applicationIds ?? APPLICATION_IDS,
71
65
  objectTypeIds: input.objectTypeIds ?? new Set<string>(),
72
66
  datasetIds: input.datasetIds ?? new Set<string>(),
73
67
  actionIds: input.actionIds ?? new Set<string>(),
@@ -75,8 +69,6 @@ export class SecurityRegistry implements SecurityDefinitionCatalog {
75
69
  syncIds: input.syncIds ?? new Set<string>(),
76
70
  pipelineIds: input.pipelineIds ?? new Set<string>(),
77
71
  connectorIds: input.connectorIds ?? new Set<string>(),
78
- observableIds: new Set(["logs", "aiUsage"]),
79
- manageableIds: new Set(["aiUsage"]),
80
72
  shareIds: input.shareIds ?? new Set<string>(),
81
73
  getSubTypes: input.getSubTypes ?? (() => []),
82
74
  }
@@ -1,5 +1,3 @@
1
- import type { AuthSessionAudience } from "../auth/audience"
2
-
3
1
  export interface GroupDefinition<TId extends string = string> {
4
2
  readonly kind: "group"
5
3
  readonly id: TId
@@ -48,19 +46,6 @@ export type Selection =
48
46
  | { readonly all: true; readonly except: readonly string[] }
49
47
  | { readonly all: false; readonly ids: readonly string[] }
50
48
 
51
- export interface ApplicationDefinition<TId extends AuthSessionAudience = AuthSessionAudience> {
52
- readonly kind: "application"
53
- readonly id: TId
54
- readonly label: string
55
- }
56
-
57
- export interface AccessGrant {
58
- readonly kind: "grant"
59
- readonly capability: "access"
60
- readonly target: "application"
61
- readonly selection: Selection
62
- }
63
-
64
49
  export type ViewGrantTarget = "object" | "dataset"
65
50
 
66
51
  export interface ViewGrant<TTarget extends ViewGrantTarget = ViewGrantTarget> {
@@ -133,25 +118,34 @@ export interface AgentRunGrant {
133
118
 
134
119
  export type ObserveGrantTarget = "logs" | "aiUsage"
135
120
 
121
+ /** Read the project's logs or its AI usage. Each is one surface, so there is nothing to select. */
136
122
  export interface ObserveGrant {
137
123
  readonly kind: "grant"
138
124
  readonly capability: "observe"
139
125
  readonly target: ObserveGrantTarget
140
- readonly selection: Selection
141
126
  }
142
127
 
143
128
  export type ManageGrantTarget = "connector" | "aiUsage"
144
129
 
145
- /** Manage a selected connector or the project's AI usage-limit policies. */
146
- export interface ManageGrant<TTarget extends ManageGrantTarget = ManageGrantTarget> {
147
- readonly kind: "grant"
148
- readonly capability: "manage"
149
- readonly target: TTarget
150
- readonly selection: Selection
151
- }
130
+ /**
131
+ * Manage the selected connectors, or the project's AI usage-limit policies. AI usage is one
132
+ * surface, so its grant selects nothing.
133
+ */
134
+ export type ManageGrant<TTarget extends ManageGrantTarget = ManageGrantTarget> =
135
+ TTarget extends "connector"
136
+ ? {
137
+ readonly kind: "grant"
138
+ readonly capability: "manage"
139
+ readonly target: TTarget
140
+ readonly selection: Selection
141
+ }
142
+ : {
143
+ readonly kind: "grant"
144
+ readonly capability: "manage"
145
+ readonly target: TTarget
146
+ }
152
147
 
153
148
  export type GrantDefinition =
154
- | AccessGrant
155
149
  | ViewGrant
156
150
  | EditGrant
157
151
  | AppendGrant
@@ -175,7 +169,7 @@ export interface RoleDefinition<TId extends string = string> {
175
169
  readonly clearances?: readonly string[]
176
170
  }
177
171
 
178
- export type MembershipOperation = "invite" | "assignGroups" | "suspend"
172
+ export type MembershipOperation = "invite" | "assignGroups" | "suspend" | "serviceAccounts"
179
173
 
180
174
  export interface MembershipPolicyDefinition<TId extends string = string> {
181
175
  readonly kind: "membershipPolicy"
@@ -1,4 +1,9 @@
1
- import { GRANT_KINDS, type GrantUniverseKey, grantKindOf } from "../authorization/grant-kinds"
1
+ import {
2
+ GRANT_KINDS,
3
+ type GrantUniverseKey,
4
+ grantKindOf,
5
+ isSingletonGrantKind,
6
+ } from "../authorization/grant-kinds"
2
7
  import { SecurityValidationError } from "./errors"
3
8
  import { isMembershipOperation } from "./membership-policies"
4
9
  import type {
@@ -22,11 +27,10 @@ type RegisteredUniverses = Partial<Record<GrantUniverseKey, ReadonlySet<string>>
22
27
  *
23
28
  * Written as a total `Record<GrantCapability, true>` rather than a bare array so a capability added
24
29
  * to `GrantDefinition` is a compile error here — the same discipline `GRANT_KINDS` uses. The
25
- * hand-written `capability !== "access" && …` chain this replaces would have accepted the new
30
+ * hand-written `capability !== "view" && …` chain this replaces would have accepted the new
26
31
  * capability at startup and then died on `GRANT_KINDS[kind].universeKey`.
27
32
  */
28
33
  const GRANT_CAPABILITIES = Object.keys({
29
- access: true,
30
34
  view: true,
31
35
  edit: true,
32
36
  append: true,
@@ -102,7 +106,7 @@ function assertMembershipOperationArray(
102
106
  for (const item of value) {
103
107
  if (!isMembershipOperation(item)) {
104
108
  throw createError(
105
- `[Sixb] ${field} must contain only membership operations: invite, assignGroups, suspend.`
109
+ `[Sixb] ${field} must contain only membership operations: invite, assignGroups, suspend, serviceAccounts.`
106
110
  )
107
111
  }
108
112
  }
@@ -231,10 +235,6 @@ export function assertGrantDefinition(
231
235
  )
232
236
  }
233
237
 
234
- if (value.capability === "access" && value.target !== "application") {
235
- throw createError(`[Sixb] ${field} access grant target must be 'application'.`)
236
- }
237
-
238
238
  if (value.capability === "view" && value.target !== "object" && value.target !== "dataset") {
239
239
  throw createError(`[Sixb] ${field} view grant target must be 'object' or 'dataset'.`)
240
240
  }
@@ -259,9 +259,13 @@ export function assertGrantDefinition(
259
259
  throw createError(`[Sixb] ${field} manage grant target must be 'connector' or 'aiUsage'.`)
260
260
  }
261
261
 
262
- if (value.capability === "run" && value.target === "agent") {
262
+ // The agent, logs and AI usage are one surface each, so their grants select nothing. The checks
263
+ // above settled the capability and target, so the kind is known.
264
+ if (isSingletonGrantKind(grantKindOf(value as unknown as GrantDefinition))) {
263
265
  if (value.selection !== undefined) {
264
- throw createError(`[Sixb] ${field} agent run grant must not declare a selection.`)
266
+ throw createError(
267
+ `[Sixb] ${field} ${value.capability} grant on '${value.target}' must not declare a selection.`
268
+ )
265
269
  }
266
270
  return
267
271
  }
@@ -332,8 +336,6 @@ export function validateSecurityDefinitionsAtStartup(input: {
332
336
  readonly groups: readonly GroupDefinition[]
333
337
  readonly membershipPolicies: readonly MembershipPolicyDefinition[]
334
338
  readonly roles?: readonly RoleDefinition[]
335
- /** Registered browser application ids — when provided, access grants must reference them. */
336
- readonly applicationIds?: ReadonlySet<string>
337
339
  /** Registered object type ids — when provided, view grants must reference them. */
338
340
  readonly objectTypeIds?: ReadonlySet<string>
339
341
  /** Registered dataset ids — when provided, dataset view grants must reference them. */
@@ -348,10 +350,6 @@ export function validateSecurityDefinitionsAtStartup(input: {
348
350
  readonly pipelineIds?: ReadonlySet<string>
349
351
  /** Whether the project's single conversational Agent is configured. */
350
352
  readonly agentAvailable?: boolean
351
- /** Registered observability surfaces. */
352
- readonly observableIds?: ReadonlySet<string>
353
- /** Registered singleton management surfaces. */
354
- readonly manageableIds?: ReadonlySet<string>
355
353
  /** Registered connector ids — when provided, manage grants must reference them. */
356
354
  readonly connectorIds?: ReadonlySet<string>
357
355
  /** Registered Share ids — when provided, share grants must reference them. */
@@ -496,7 +494,11 @@ function assertGrantReferences(
496
494
  }
497
495
  return
498
496
  }
499
- const spec = GRANT_KINDS[grantKindOf(grant)]
497
+ // Logs and AI usage are always there; only targeted grants name ids to check.
498
+ if (!("selection" in grant)) return
499
+ const kind = grantKindOf(grant)
500
+ if (isSingletonGrantKind(kind)) return
501
+ const spec = GRANT_KINDS[kind]
500
502
  const universe = registered[spec.universeKey]
501
503
 
502
504
  if (!universe) {
@@ -172,7 +172,7 @@ export const AGENT_RUN_DIAGNOSTIC_CODES = [
172
172
  *
173
173
  * Sixb writes these codes and the generated client is what reads them, so an open union would only
174
174
  * be honest if the HTTP schema were open too — and that costs the OpenAPI enum, the client's
175
- * autocompletion, and Atlas's exhaustive `switch`. Sixb owns both ends, so a new code is a minor
175
+ * autocompletion, and the app's exhaustive `switch`. Sixb owns both ends, so a new code is a minor
176
176
  * version bump: cheap here, and a broken `switch` is better than a 500 from `z.enum`.
177
177
  */
178
178
  export type AgentRunDiagnosticCode = (typeof AGENT_RUN_DIAGNOSTIC_CODES)[number]
@@ -222,7 +222,6 @@ export class InMemoryAuthStorage implements AuthStorage {
222
222
  }
223
223
 
224
224
  validateCompleteSessionInput(this.state, projectId, input.session)
225
- assertSignInSessionAudience(projectId, input.session.audience, magicLink.audience)
226
225
 
227
226
  let newUserId: string | undefined
228
227
  if (shouldCreateUser) {
@@ -353,7 +352,6 @@ export class InMemoryAuthStorage implements AuthStorage {
353
352
  }
354
353
 
355
354
  validateCompleteSessionInput(this.state, projectId, input.session)
356
- assertSignInSessionAudience(projectId, input.session.audience, attempt.audience)
357
355
 
358
356
  let newUserId: string | undefined
359
357
  if (shouldCreateUser) {
@@ -555,7 +553,6 @@ export class InMemoryAuthStorage implements AuthStorage {
555
553
  projectId: input.projectId,
556
554
  userId: input.userId,
557
555
  strategyId: input.strategyId,
558
- audience: input.session.audience,
559
556
  tokenHash: input.session.tokenHash,
560
557
  createdAt: input.session.createdAt,
561
558
  expiresAt: input.session.expiresAt,
@@ -587,18 +584,3 @@ function restoreMap<TKey, TValue>(target: Map<TKey, TValue>, snapshot: Map<TKey,
587
584
  target.set(key, value)
588
585
  }
589
586
  }
590
-
591
- function assertSignInSessionAudience(
592
- projectId: string,
593
- sessionAudience: string,
594
- storedAudience: string
595
- ): void {
596
- if (sessionAudience === storedAudience) {
597
- return
598
- }
599
-
600
- throw new AuthStorageError(
601
- "invalid_input",
602
- `[Sixb] Sign-in session audience '${sessionAudience}' does not match stored auth audience '${storedAudience}' for project '${projectId}'.`
603
- )
604
- }
@@ -1,4 +1,3 @@
1
- import { resolveAuthSessionAudience } from "../../../auth/audience"
2
1
  import { AuthStorageError } from "../errors"
3
2
  import type { AuthMagicLinkStore, CreateAuthMagicLinkInput, MagicLinkRecord } from "../types"
4
3
  import type { AuthStorageState } from "./shared"
@@ -22,7 +21,6 @@ export class InMemoryAuthMagicLinkStore implements AuthMagicLinkStore {
22
21
  const id = assertNonEmpty(input.id, "Magic link id")
23
22
  const projectId = assertNonEmpty(input.projectId, "Project id")
24
23
  const strategyId = assertNonEmpty(input.strategyId, "Strategy id")
25
- const audience = resolveAuthSessionAudience(input.audience)
26
24
  const email = normalizeEmail(input.email)
27
25
  const tokenHash = assertNonEmpty(input.tokenHash, "Magic link token hash")
28
26
  const key = magicLinkKey(projectId, id)
@@ -40,7 +38,6 @@ export class InMemoryAuthMagicLinkStore implements AuthMagicLinkStore {
40
38
  id,
41
39
  projectId,
42
40
  strategyId,
43
- audience,
44
41
  email,
45
42
  tokenHash,
46
43
  returnTo: input.returnTo,
@@ -1,4 +1,3 @@
1
- import { resolveAuthSessionAudience } from "../../../auth/audience"
2
1
  import { AuthStorageError } from "../errors"
3
2
  import type {
4
3
  AuthOidcAuthorizationAttemptStore,
@@ -26,7 +25,6 @@ export class InMemoryAuthOidcAuthorizationAttemptStore
26
25
  const id = assertNonEmpty(input.id, "OIDC authorization attempt id")
27
26
  const projectId = assertNonEmpty(input.projectId, "Project id")
28
27
  const strategyId = assertNonEmpty(input.strategyId, "Strategy id")
29
- const audience = resolveAuthSessionAudience(input.audience)
30
28
  const stateHash = assertNonEmpty(input.stateHash, "OIDC state hash")
31
29
  const nonceHash = assertNonEmpty(input.nonceHash, "OIDC nonce hash")
32
30
  const codeVerifier = assertNonEmpty(input.codeVerifier, "OIDC code verifier")
@@ -43,7 +41,6 @@ export class InMemoryAuthOidcAuthorizationAttemptStore
43
41
  id,
44
42
  projectId,
45
43
  strategyId,
46
- audience,
47
44
  stateHash,
48
45
  nonceHash,
49
46
  codeVerifier,
@@ -1,4 +1,3 @@
1
- import type { AuthSessionAudience } from "../../../auth/audience"
2
1
  import { AuthStorageError } from "../errors"
3
2
  import type {
4
3
  AuthSessionStore,
@@ -11,7 +10,6 @@ import {
11
10
  cloneDate,
12
11
  cloneOptionalRecord,
13
12
  cloneRecord,
14
- compareByCreatedAt,
15
13
  createSessionRecord,
16
14
  isActiveSession,
17
15
  revokeActiveSessionsForUser,
@@ -33,22 +31,6 @@ export class InMemoryAuthSessionStore implements AuthSessionStore {
33
31
  return cloneOptionalRecord(record)
34
32
  }
35
33
 
36
- async getActiveByUserId(params: {
37
- readonly projectId: string
38
- readonly userId: string
39
- readonly audience: AuthSessionAudience
40
- readonly now: Date
41
- }): Promise<SessionRecord | null> {
42
- const sessions = [...this.state.sessions.values()]
43
- .filter((session) => session.projectId === params.projectId)
44
- .filter((session) => session.userId === params.userId)
45
- .filter((session) => session.audience === params.audience)
46
- .filter((session) => isActiveSession(session, params.now))
47
- .sort((a, b) => compareByCreatedAt(a, b, "desc"))
48
-
49
- return cloneOptionalRecord(sessions[0] ?? null)
50
- }
51
-
52
34
  async listActiveByUserId(params: {
53
35
  readonly projectId: string
54
36
  readonly userId: string
@@ -71,7 +53,6 @@ export class InMemoryAuthSessionStore implements AuthSessionStore {
71
53
  async findValidByTokenHash(params: {
72
54
  readonly projectId: string
73
55
  readonly id: string
74
- readonly audience: AuthSessionAudience
75
56
  readonly tokenHash: string
76
57
  readonly now: Date
77
58
  }): Promise<SessionRecord | null> {
@@ -79,7 +60,6 @@ export class InMemoryAuthSessionStore implements AuthSessionStore {
79
60
  if (
80
61
  !session ||
81
62
  session.bearer ||
82
- session.audience !== params.audience ||
83
63
  session.tokenHash !== params.tokenHash ||
84
64
  !isActiveSession(session, params.now)
85
65
  ) {
@@ -153,7 +133,6 @@ export class InMemoryAuthSessionStore implements AuthSessionStore {
153
133
  async renewIfValid(params: {
154
134
  readonly projectId: string
155
135
  readonly id: string
156
- readonly audience: AuthSessionAudience
157
136
  readonly tokenHash: string
158
137
  readonly now: Date
159
138
  readonly expiresAt: Date
@@ -163,7 +142,6 @@ export class InMemoryAuthSessionStore implements AuthSessionStore {
163
142
  if (
164
143
  !session ||
165
144
  session.bearer ||
166
- session.audience !== params.audience ||
167
145
  session.tokenHash !== params.tokenHash ||
168
146
  !isActiveSession(session, params.now)
169
147
  ) {
@@ -208,15 +186,13 @@ export class InMemoryAuthSessionStore implements AuthSessionStore {
208
186
  async revokeActiveForUser(params: {
209
187
  readonly projectId: string
210
188
  readonly userId: string
211
- readonly audience?: AuthSessionAudience
212
189
  readonly revokedAt: Date
213
190
  }): Promise<readonly SessionRecord[]> {
214
191
  return revokeActiveSessionsForUser(
215
192
  this.state,
216
193
  params.projectId,
217
194
  params.userId,
218
- params.revokedAt,
219
- params.audience
195
+ params.revokedAt
220
196
  ).map(cloneRecord)
221
197
  }
222
198
 
@@ -1,4 +1,3 @@
1
- import { type AuthSessionAudience, resolveAuthSessionAudience } from "../../../auth/audience"
2
1
  import { AuthStorageError } from "../errors"
3
2
  import type {
4
3
  AccessTokenRecord,
@@ -213,8 +212,7 @@ export function revokeActiveSessionsForUser(
213
212
  state: AuthStorageState,
214
213
  projectId: string,
215
214
  userId: string,
216
- revokedAt: Date,
217
- audience?: AuthSessionAudience
215
+ revokedAt: Date
218
216
  ): readonly SessionRecord[] {
219
217
  const revoked: SessionRecord[] = []
220
218
 
@@ -223,10 +221,6 @@ export function revokeActiveSessionsForUser(
223
221
  continue
224
222
  }
225
223
 
226
- if (audience !== undefined && session.audience !== audience) {
227
- continue
228
- }
229
-
230
224
  if (!isActiveSession(session, revokedAt)) {
231
225
  continue
232
226
  }
@@ -290,7 +284,6 @@ export function validateCompleteSessionInput(
290
284
  session: CompleteAuthSessionInput
291
285
  ): void {
292
286
  const sessionId = assertNonEmpty(session.id, "Session id")
293
- assertNonEmpty(session.audience, "Session audience")
294
287
  assertNonEmpty(session.tokenHash, "Session token hash")
295
288
  assertSessionIdAvailable(state, projectId, sessionId)
296
289
  }
@@ -303,7 +296,6 @@ export function createSessionRecord(
303
296
  const projectId = assertNonEmpty(input.projectId, "Project id")
304
297
  const userId = assertNonEmpty(input.userId, "User id")
305
298
  const strategyId = assertNonEmpty(input.strategyId, "Strategy id")
306
- const audience = resolveAuthSessionAudience(input.audience)
307
299
  const tokenHash = assertNonEmpty(input.tokenHash, "Session token hash")
308
300
 
309
301
  assertSessionIdAvailable(state, projectId, id)
@@ -313,7 +305,6 @@ export function createSessionRecord(
313
305
  projectId,
314
306
  userId,
315
307
  strategyId,
316
- audience,
317
308
  tokenHash,
318
309
  createdAt: cloneDate(input.createdAt),
319
310
  expiresAt: cloneDate(input.expiresAt),