@tearleads/client-sdk 0.1.99 → 0.1.101

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.
@@ -1 +1 @@
1
- {"version":3,"file":"commitCurrentGroupPolicyMutation.js","sourceRoot":"","sources":["commitCurrentGroupPolicyMutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SigningKeyPair,\n VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport type { PutPrincipalPolicyRequest } from \"@tearleads/validators/request\";\nimport type { PrincipalPolicyMutationResponse } from \"@tearleads/validators/response\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport type { TrustedUserIdentityResolver } from \"../../../data/trustedUserIdentity\";\nimport type {\n PreparedPrincipalContainerRematerializationBatch,\n PrincipalRematerializationPredecessor,\n} from \"../../containers/rematerialization\";\nimport {\n buildOrganizationGroupDirectoryPolicyRequest,\n replaceOrganizationGroupHead,\n} from \"../groups/organizationGroupDirectory\";\nimport { assertAuthoredPrincipalMutationReceipt } from \"../principalMutations/principalMutationReceipt\";\nimport type { RuntimeCurrentGroupMutationContext } from \"../principalMutations/runtimeCurrentGroupMutation\";\nimport {\n projectionUserIds,\n resolveRequiredUserIdentities,\n} from \"../trustedOrganizationUsers\";\nimport { prepareAuthoredGroupPolicy } from \"./groupPolicyMutationAcknowledgement\";\nimport {\n type PrincipalPolicyReadWriteApi,\n submitGroupPolicyCommit,\n} from \"./groupPolicyMutationContext\";\nimport { groupPolicyMutationHead } from \"./groupPolicyMutationHead\";\n\ninterface GroupPolicyChange {\n readonly context: RuntimeCurrentGroupMutationContext;\n readonly request: PutPrincipalPolicyRequest;\n readonly prepareContainerMutations: (\n nextPolicy: VerifiedPrincipalPolicyCurrent,\n preceding?: PrincipalRematerializationPredecessor | undefined,\n ) => Promise<PreparedPrincipalContainerRematerializationBatch>;\n}\n\ninterface CommitInput extends GroupPolicyChange {\n readonly member?: GroupPolicyChange | undefined;\n readonly apiClient: PrincipalPolicyReadWriteApi;\n readonly groupId: string;\n readonly organizationId: string;\n readonly signerUserId: string;\n readonly signingFingerprint: string;\n readonly signingKeyPair: SigningKeyPair;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n}\n\n/** Commit and retain the group, optional roster enrollment and directory together. */\nexport async function commitCurrentGroupPolicyMutation(\n input: CommitInput,\n): Promise<PrincipalPolicyMutationResponse> {\n const { context } = input;\n assertProjectionVerificationCurrent(context.stillCurrent);\n const [signer] = await resolveRequiredUserIdentities({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n userIds: [input.signerUserId],\n });\n if (!signer) throw new Error(\"Group policy signer is unavailable\");\n const member = input.member\n ? await prepareChange(input.member, signer)\n : null;\n const { expectedHead, prepared } = await prepareChange(\n input,\n signer,\n member?.preceding,\n );\n const organizationRequest = await prepareDirectory(\n input,\n expectedHead,\n member?.expectedHead,\n );\n assertProjectionVerificationCurrent(context.stillCurrent);\n const response = await submitGroupPolicyCommit({\n apiClient: input.apiClient,\n groupId: input.groupId,\n organizationId: input.organizationId,\n request: input.request,\n organizationRequest,\n memberRequest: input.member?.request,\n // A compound retry must rebuild both batches' shared speculative heads.\n // Refuse the whole transaction if a damaged-key repair needs extra rekeys;\n // ordinary adds preserve key epochs and need no descendant carry retry.\n carryDescendantRekeys: member ? undefined : prepared.carry,\n stillCurrent: context.stillCurrent,\n });\n if (!response) throw new Error(\"Group policy update failed\");\n assertProjectionVerificationCurrent(context.stillCurrent);\n await assertAuthoredPrincipalMutationReceipt(\n {\n groupPolicy: input.request,\n organizationPolicy: organizationRequest,\n ...(input.member ? { memberPolicy: input.member.request } : {}),\n },\n response,\n );\n await context.retainAcknowledged({\n additionalGroups:\n input.member && response.memberPolicy\n ? [\n {\n ...input.member.context.groupRetention,\n request: input.member.request,\n response: response.memberPolicy,\n retiredContainerIds: member?.prepared.retiredContainerIds,\n },\n ]\n : [],\n request: input.request,\n organizationRequest,\n response,\n retiredContainerIds: prepared.retiredContainerIds,\n });\n if (member && response.memberPolicy) {\n await member.prepared.acknowledge(\n response.memberPolicy.containerMutations,\n context.stillCurrent,\n );\n }\n await prepared.acknowledge(\n response.groupPolicy.containerMutations,\n context.stillCurrent,\n );\n assertProjectionVerificationCurrent(context.stillCurrent);\n return response.groupPolicy;\n}\n\nasync function prepareChange(\n change: GroupPolicyChange,\n signer: Awaited<ReturnType<typeof resolveRequiredUserIdentities>>[number],\n preceding?: PrincipalRematerializationPredecessor,\n) {\n const expectedHead = await groupPolicyMutationHead(change.request);\n const nextPolicy = await prepareAuthoredGroupPolicy({\n verifiedCurrentPolicy: change.context.verifiedCurrentPolicy,\n expectedHead,\n request: change.request,\n signerPublicKeys: [signer],\n externalAuthority: change.context.externalAuthority,\n localPolicyCheckpoint: change.context.localPolicyCheckpoint,\n stillCurrent: change.context.stillCurrent,\n });\n const prepared = await change.prepareContainerMutations(\n nextPolicy,\n preceding,\n );\n change.request.containerMutations = [...prepared.requests];\n return {\n expectedHead,\n prepared,\n preceding: prepared.preceding\n ? {\n ...prepared.preceding,\n authored: [\n ...(preceding?.authored ?? []),\n {\n organizationId:\n change.context.organizationDescriptor.organizationId,\n policy: nextPolicy,\n dependencies: [\n change.context.organizationCurrent.policy,\n change.context.adminCurrent.policy,\n ],\n stillCurrent: change.context.stillCurrent,\n },\n ],\n }\n : undefined,\n };\n}\n\nasync function prepareDirectory(\n input: CommitInput,\n expectedHead: Awaited<ReturnType<typeof groupPolicyMutationHead>>,\n memberHead: Awaited<ReturnType<typeof groupPolicyMutationHead>> | undefined,\n) {\n const { context } = input;\n if (\n input.member &&\n (input.member.context.currentPolicy.currentState.principalId !==\n context.memberGroupId ||\n input.member.context.organizationCurrent.current.currentState\n .stateHash !==\n context.organizationCurrent.current.currentState.stateHash)\n )\n throw new Error(\n \"Roster and group changes must share the same organization policy\",\n );\n let groupHeads = replaceOrganizationGroupHead({\n descriptor: context.organizationDescriptor,\n nextHead: expectedHead,\n });\n if (memberHead)\n groupHeads = replaceOrganizationGroupHead({\n descriptor: { ...context.organizationDescriptor, groupHeads },\n nextHead: memberHead,\n });\n const adminProjection = context.isOrganizationAdminsGroup\n ? input.request.projection\n : context.adminCurrent.current.currentProjection;\n const adminUsers = await resolveRequiredUserIdentities({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n userIds: projectionUserIds(adminProjection),\n });\n return buildOrganizationGroupDirectoryPolicyRequest({\n adminProjection,\n adminUsers,\n currentPolicy: context.organizationCurrent.current,\n descriptor: context.organizationDescriptor,\n groupHeads,\n signerUserId: input.signerUserId,\n signingFingerprint: input.signingFingerprint,\n signingKeyPair: input.signingKeyPair,\n });\n}\n"]}
1
+ {"version":3,"file":"commitCurrentGroupPolicyMutation.js","sourceRoot":"","sources":["commitCurrentGroupPolicyMutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SigningKeyPair,\n VerifiedPrincipalPolicyCurrent,\n} from \"@tearleads/crypto\";\nimport type { PutPrincipalPolicyRequest } from \"@tearleads/validators/request\";\nimport type { PrincipalPolicyMutationResponse } from \"@tearleads/validators/response\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport type { TrustedUserIdentityResolver } from \"../../../data/trustedUserIdentity\";\nimport type {\n PreparedPrincipalContainerRematerializationBatch,\n PrincipalRematerializationPredecessor,\n} from \"../../containers/rematerialization\";\nimport {\n buildOrganizationGroupDirectoryPolicyRequest,\n replaceOrganizationGroupHead,\n} from \"../groups/organizationGroupDirectory\";\nimport { assertAuthoredPrincipalMutationReceipt } from \"../principalMutations/principalMutationReceipt\";\nimport type { RuntimeCurrentGroupMutationContext } from \"../principalMutations/runtimeCurrentGroupMutation\";\nimport {\n projectionUserIds,\n resolveRequiredUserIdentities,\n} from \"../trustedOrganizationUsers\";\nimport { prepareAuthoredGroupPolicy } from \"./groupPolicyMutationAcknowledgement\";\nimport {\n type PrincipalPolicyReadWriteApi,\n submitGroupPolicyCommit,\n} from \"./groupPolicyMutationContext\";\nimport { groupPolicyMutationHead } from \"./groupPolicyMutationHead\";\n\ninterface GroupPolicyChange {\n readonly context: RuntimeCurrentGroupMutationContext;\n readonly request: PutPrincipalPolicyRequest;\n readonly prepareContainerMutations: (\n nextPolicy: VerifiedPrincipalPolicyCurrent,\n preceding?: PrincipalRematerializationPredecessor | undefined,\n ) => Promise<PreparedPrincipalContainerRematerializationBatch>;\n}\n\ninterface CommitInput extends GroupPolicyChange {\n readonly member?: GroupPolicyChange | undefined;\n readonly apiClient: PrincipalPolicyReadWriteApi;\n readonly groupId: string;\n readonly organizationId: string;\n readonly signerUserId: string;\n readonly signingFingerprint: string;\n readonly signingKeyPair: SigningKeyPair;\n readonly resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n}\n\n/** Commit and retain the group, optional roster enrollment and directory together. */\nexport async function commitCurrentGroupPolicyMutation(\n input: CommitInput,\n): Promise<PrincipalPolicyMutationResponse> {\n const { context } = input;\n assertProjectionVerificationCurrent(context.stillCurrent);\n const [signer] = await resolveRequiredUserIdentities({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n userIds: [input.signerUserId],\n });\n if (!signer) throw new Error(\"Group policy signer is unavailable\");\n const member = input.member\n ? await prepareChange(input.member, signer)\n : null;\n const { expectedHead, prepared } = await prepareChange(\n input,\n signer,\n member?.preceding,\n );\n const organizationRequest = await prepareDirectory(\n input,\n expectedHead,\n member?.expectedHead,\n );\n assertProjectionVerificationCurrent(context.stillCurrent);\n const response = await submitGroupPolicyCommit({\n apiClient: input.apiClient,\n groupId: input.groupId,\n organizationId: input.organizationId,\n request: input.request,\n organizationRequest,\n memberRequest: input.member?.request,\n // A compound retry must rebuild both batches' shared speculative heads.\n // Refuse the whole transaction if a damaged-key repair needs extra rekeys;\n // ordinary adds preserve key epochs and need no descendant carry retry.\n carryDescendantRekeys: member ? undefined : prepared.carry,\n stillCurrent: context.stillCurrent,\n });\n if (!response) throw new Error(\"Group policy update failed\");\n assertProjectionVerificationCurrent(context.stillCurrent);\n await assertAuthoredPrincipalMutationReceipt(\n {\n groupPolicy: input.request,\n organizationPolicy: organizationRequest,\n ...(input.member ? { memberPolicy: input.member.request } : {}),\n },\n response,\n );\n await context.retainAcknowledged({\n additionalGroups:\n input.member && response.memberPolicy\n ? [\n {\n ...input.member.context.groupRetention,\n request: input.member.request,\n response: response.memberPolicy,\n retiredContainerIds: member?.prepared.retiredContainerIds,\n },\n ]\n : [],\n request: input.request,\n organizationRequest,\n response,\n retiredContainerIds: prepared.retiredContainerIds,\n });\n if (member && response.memberPolicy) {\n await member.prepared.acknowledge(\n response.memberPolicy.containerMutations,\n context.stillCurrent,\n );\n }\n await prepared.acknowledge(\n response.groupPolicy.containerMutations,\n context.stillCurrent,\n );\n assertProjectionVerificationCurrent(context.stillCurrent);\n return response.groupPolicy;\n}\n\nasync function prepareChange(\n change: GroupPolicyChange,\n signer: Awaited<ReturnType<typeof resolveRequiredUserIdentities>>[number],\n preceding?: PrincipalRematerializationPredecessor,\n) {\n const expectedHead = await groupPolicyMutationHead(change.request);\n const nextPolicy = await prepareAuthoredGroupPolicy({\n verifiedCurrentPolicy: change.context.verifiedCurrentPolicy,\n expectedHead,\n request: change.request,\n signerPublicKeys: [signer],\n externalAuthority: change.context.externalAuthority,\n localPolicyCheckpoint: change.context.localPolicyCheckpoint,\n stillCurrent: change.context.stillCurrent,\n });\n const authored = [\n ...(preceding?.authored ?? []),\n {\n organizationId: change.context.organizationDescriptor.organizationId,\n policy: nextPolicy,\n dependencies: [\n change.context.organizationCurrent.policy,\n change.context.adminCurrent.policy,\n ],\n stillCurrent: change.context.stillCurrent,\n },\n ];\n // A level the batch plans under its own rotation cites this successor\n // before the transaction commits, so the batch resolves it as authored,\n // exactly as the next group in a compound transaction does (#2646).\n const prepared = await change.prepareContainerMutations(nextPolicy, {\n policies: preceding?.policies ?? [],\n projections: preceding?.projections ?? [],\n knownContainerKeks: preceding?.knownContainerKeks ?? new Map(),\n authored,\n });\n change.request.containerMutations = [...prepared.requests];\n return {\n expectedHead,\n prepared,\n preceding: prepared.preceding\n ? { ...prepared.preceding, authored }\n : undefined,\n };\n}\n\nasync function prepareDirectory(\n input: CommitInput,\n expectedHead: Awaited<ReturnType<typeof groupPolicyMutationHead>>,\n memberHead: Awaited<ReturnType<typeof groupPolicyMutationHead>> | undefined,\n) {\n const { context } = input;\n if (\n input.member &&\n (input.member.context.currentPolicy.currentState.principalId !==\n context.memberGroupId ||\n input.member.context.organizationCurrent.current.currentState\n .stateHash !==\n context.organizationCurrent.current.currentState.stateHash)\n )\n throw new Error(\n \"Roster and group changes must share the same organization policy\",\n );\n let groupHeads = replaceOrganizationGroupHead({\n descriptor: context.organizationDescriptor,\n nextHead: expectedHead,\n });\n if (memberHead)\n groupHeads = replaceOrganizationGroupHead({\n descriptor: { ...context.organizationDescriptor, groupHeads },\n nextHead: memberHead,\n });\n const adminProjection = context.isOrganizationAdminsGroup\n ? input.request.projection\n : context.adminCurrent.current.currentProjection;\n const adminUsers = await resolveRequiredUserIdentities({\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n userIds: projectionUserIds(adminProjection),\n });\n return buildOrganizationGroupDirectoryPolicyRequest({\n adminProjection,\n adminUsers,\n currentPolicy: context.organizationCurrent.current,\n descriptor: context.organizationDescriptor,\n groupHeads,\n signerUserId: input.signerUserId,\n signingFingerprint: input.signingFingerprint,\n signingKeyPair: input.signingKeyPair,\n });\n}\n"]}
@@ -40,8 +40,8 @@ export async function commitCurrentShareGrant(input) {
40
40
  signingFingerprint: share.author.signerKeyFingerprint,
41
41
  signingKeyPair,
42
42
  resolveTrustedUserIdentity: share.resolveTrustedUserIdentity,
43
- prepareContainerMutations: async (nextPolicy) => {
44
- prepared.batch = await prepareCurrentShareGrantBatch(share, context, nextPolicy, input.recitationStillCurrent);
43
+ prepareContainerMutations: async (nextPolicy, preceding) => {
44
+ prepared.batch = await prepareCurrentShareGrantBatch(share, context, { nextPolicy, preceding }, input.recitationStillCurrent);
45
45
  return prepared.batch;
46
46
  },
47
47
  });
@@ -66,9 +66,10 @@ async function assertCurrentShareGrantName(runtime, share, context, expectedName
66
66
  throw new GroupShareNameMismatchError("Container share group name does not match the signed group policy");
67
67
  assertProjectionVerificationCurrent(context.stillCurrent);
68
68
  }
69
- function prepareCurrentShareGrantBatch(share, context, nextPolicy, recitationStillCurrent) {
69
+ function prepareCurrentShareGrantBatch(share, context, { nextPolicy, preceding, }, recitationStillCurrent) {
70
70
  return preparePrincipalContainerRematerializationBatch({
71
71
  ...share,
72
+ preceding,
72
73
  grants: [
73
74
  ...new Map([...context.currentPolicy.currentGrants, ...nextPolicy.grants].map((grant) => [grant.containerId, grant])).values(),
74
75
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"currentShareGrantMutation.js","sourceRoot":"","sources":["currentShareGrantMutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MaterializedContainerSharePlan } from \"../../../data/containers/shared/types\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport {\n type PreparedPrincipalContainerRematerializationBatch,\n preparePrincipalContainerRematerializationBatch,\n} from \"../../containers/rematerialization\";\nimport { createRuntimeGroupMetadataAccess } from \"../groupMetadata/groupMetadataRuntime\";\nimport { commitCurrentGroupPolicyMutation } from \"../groupPolicy/commitCurrentGroupPolicyMutation\";\nimport { buildSetGroupContainerGrantPolicyRequest } from \"../groupPolicy/groupPolicyRequests\";\nimport type {\n createRuntimeCurrentGroupMutation,\n RuntimeCurrentGroupMutationContext,\n} from \"../principalMutations/runtimeCurrentGroupMutation\";\nimport { groupPolicyNameMismatch } from \"../principalPolicy/principalPolicyRequest\";\nimport type { createRuntimeCurrentSharePrincipalPolicy } from \"./currentSharePrincipalPolicy\";\nimport { GroupShareNameMismatchError } from \"./sharePrincipalPolicy\";\nimport type { shareRemoteContainerWithGroup } from \"./shareWithGroup\";\n\n/** Fresh mutation authority rechecks the chosen name before authoring a grant. */\nexport async function commitCurrentShareGrant(input: {\n readonly runtime: Parameters<\n typeof createRuntimeCurrentSharePrincipalPolicy\n >[0];\n readonly share: Parameters<typeof shareRemoteContainerWithGroup>[0];\n readonly recitationStillCurrent?: (() => boolean) | undefined;\n readonly mutate: NonNullable<\n ReturnType<typeof createRuntimeCurrentGroupMutation>\n >;\n}): ReturnType<typeof shareRemoteContainerWithGroup> {\n const share = input.share;\n const expectedName = share.expectedGroupName;\n if (expectedName === null)\n throw new Error(\n \"Minting a group grant requires the chosen group name; only a re-wrap of an existing signed grant may omit it\",\n );\n const signingKeyPair = share.signingKeyPair;\n if (!signingKeyPair)\n throw new Error(\n \"Container group share requires principal policy signing context\",\n );\n return input.mutate(\n {\n groupId: share.recipientGroupId,\n organizationId: share.author.organizationId,\n signerUserId: share.author.signerUserId,\n stillCurrent: share.stillCurrent ?? (() => true),\n },\n async (context) => {\n await assertCurrentShareGrantName(\n input.runtime,\n share,\n context,\n expectedName,\n );\n const request = await buildSetGroupContainerGrantPolicyRequest({\n ...context,\n accessLevel: share.accessLevel,\n containerId: share.containerId,\n signerUserId: share.author.signerUserId,\n signingFingerprint: share.author.signerKeyFingerprint,\n signingKeyPair,\n });\n const prepared: {\n batch?: PreparedPrincipalContainerRematerializationBatch;\n } = {};\n const response = await commitCurrentGroupPolicyMutation({\n apiClient: share.apiClient,\n context,\n groupId: share.recipientGroupId,\n organizationId: share.author.organizationId,\n request,\n signerUserId: share.author.signerUserId,\n signingFingerprint: share.author.signerKeyFingerprint,\n signingKeyPair,\n resolveTrustedUserIdentity: share.resolveTrustedUserIdentity,\n prepareContainerMutations: async (nextPolicy) => {\n prepared.batch = await prepareCurrentShareGrantBatch(\n share,\n context,\n nextPolicy,\n input.recitationStillCurrent,\n );\n return prepared.batch;\n },\n });\n const index =\n prepared.batch?.plans.findIndex(\n (planned) => planned.plan.containerId === share.containerId,\n ) ?? -1;\n const plan = prepared.batch?.plans[index];\n const acknowledgement = response.containerMutations[index];\n if (!plan || !acknowledgement || !isSharePlan(plan))\n throw new Error(\"Container group share acknowledgement is incomplete\");\n return {\n containerKey: plan.containerKey,\n plan: plan.plan,\n response: acknowledgement,\n };\n },\n );\n}\n\nfunction isSharePlan(\n plan: PreparedPrincipalContainerRematerializationBatch[\"plans\"][number],\n): plan is MaterializedContainerSharePlan {\n return plan.plan.body.eventType === \"container.grant\";\n}\n\nasync function assertCurrentShareGrantName(\n runtime: Parameters<typeof createRuntimeCurrentSharePrincipalPolicy>[0],\n share: Parameters<typeof shareRemoteContainerWithGroup>[0],\n context: RuntimeCurrentGroupMutationContext,\n expectedName: string,\n) {\n const mismatch = await groupPolicyNameMismatch(\n context.currentPolicy,\n expectedName,\n createRuntimeGroupMetadataAccess(\n runtime,\n share.author.organizationId,\n context.stillCurrent,\n context.verifyMetadataContainer,\n ).readName,\n );\n if (mismatch)\n throw new GroupShareNameMismatchError(\n \"Container share group name does not match the signed group policy\",\n );\n assertProjectionVerificationCurrent(context.stillCurrent);\n}\n\nfunction prepareCurrentShareGrantBatch(\n share: Parameters<typeof shareRemoteContainerWithGroup>[0],\n context: RuntimeCurrentGroupMutationContext,\n nextPolicy: Parameters<\n typeof preparePrincipalContainerRematerializationBatch\n >[0][\"nextPolicy\"],\n recitationStillCurrent?: () => boolean,\n) {\n return preparePrincipalContainerRematerializationBatch({\n ...share,\n grants: [\n ...new Map(\n [...context.currentPolicy.currentGrants, ...nextPolicy.grants].map(\n (grant) => [grant.containerId, grant] as const,\n ),\n ).values(),\n ],\n groupId: share.recipientGroupId,\n nextPolicy,\n resolveAuthoredPolicyReferences: context.resolveAuthoredPolicyReferences,\n stillCurrent: context.stillCurrent,\n recitationStillCurrent,\n });\n}\n"]}
1
+ {"version":3,"file":"currentShareGrantMutation.js","sourceRoot":"","sources":["currentShareGrantMutation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MaterializedContainerSharePlan } from \"../../../data/containers/shared/types\";\nimport { assertProjectionVerificationCurrent } from \"../../../data/keyingProjectionVerification/types\";\nimport {\n type PreparedPrincipalContainerRematerializationBatch,\n preparePrincipalContainerRematerializationBatch,\n} from \"../../containers/rematerialization\";\nimport { createRuntimeGroupMetadataAccess } from \"../groupMetadata/groupMetadataRuntime\";\nimport { commitCurrentGroupPolicyMutation } from \"../groupPolicy/commitCurrentGroupPolicyMutation\";\nimport { buildSetGroupContainerGrantPolicyRequest } from \"../groupPolicy/groupPolicyRequests\";\nimport type {\n createRuntimeCurrentGroupMutation,\n RuntimeCurrentGroupMutationContext,\n} from \"../principalMutations/runtimeCurrentGroupMutation\";\nimport { groupPolicyNameMismatch } from \"../principalPolicy/principalPolicyRequest\";\nimport type { createRuntimeCurrentSharePrincipalPolicy } from \"./currentSharePrincipalPolicy\";\nimport { GroupShareNameMismatchError } from \"./sharePrincipalPolicy\";\nimport type { shareRemoteContainerWithGroup } from \"./shareWithGroup\";\n\n/** Fresh mutation authority rechecks the chosen name before authoring a grant. */\nexport async function commitCurrentShareGrant(input: {\n readonly runtime: Parameters<\n typeof createRuntimeCurrentSharePrincipalPolicy\n >[0];\n readonly share: Parameters<typeof shareRemoteContainerWithGroup>[0];\n readonly recitationStillCurrent?: (() => boolean) | undefined;\n readonly mutate: NonNullable<\n ReturnType<typeof createRuntimeCurrentGroupMutation>\n >;\n}): ReturnType<typeof shareRemoteContainerWithGroup> {\n const share = input.share;\n const expectedName = share.expectedGroupName;\n if (expectedName === null)\n throw new Error(\n \"Minting a group grant requires the chosen group name; only a re-wrap of an existing signed grant may omit it\",\n );\n const signingKeyPair = share.signingKeyPair;\n if (!signingKeyPair)\n throw new Error(\n \"Container group share requires principal policy signing context\",\n );\n return input.mutate(\n {\n groupId: share.recipientGroupId,\n organizationId: share.author.organizationId,\n signerUserId: share.author.signerUserId,\n stillCurrent: share.stillCurrent ?? (() => true),\n },\n async (context) => {\n await assertCurrentShareGrantName(\n input.runtime,\n share,\n context,\n expectedName,\n );\n const request = await buildSetGroupContainerGrantPolicyRequest({\n ...context,\n accessLevel: share.accessLevel,\n containerId: share.containerId,\n signerUserId: share.author.signerUserId,\n signingFingerprint: share.author.signerKeyFingerprint,\n signingKeyPair,\n });\n const prepared: {\n batch?: PreparedPrincipalContainerRematerializationBatch;\n } = {};\n const response = await commitCurrentGroupPolicyMutation({\n apiClient: share.apiClient,\n context,\n groupId: share.recipientGroupId,\n organizationId: share.author.organizationId,\n request,\n signerUserId: share.author.signerUserId,\n signingFingerprint: share.author.signerKeyFingerprint,\n signingKeyPair,\n resolveTrustedUserIdentity: share.resolveTrustedUserIdentity,\n prepareContainerMutations: async (nextPolicy, preceding) => {\n prepared.batch = await prepareCurrentShareGrantBatch(\n share,\n context,\n { nextPolicy, preceding },\n input.recitationStillCurrent,\n );\n return prepared.batch;\n },\n });\n const index =\n prepared.batch?.plans.findIndex(\n (planned) => planned.plan.containerId === share.containerId,\n ) ?? -1;\n const plan = prepared.batch?.plans[index];\n const acknowledgement = response.containerMutations[index];\n if (!plan || !acknowledgement || !isSharePlan(plan))\n throw new Error(\"Container group share acknowledgement is incomplete\");\n return {\n containerKey: plan.containerKey,\n plan: plan.plan,\n response: acknowledgement,\n };\n },\n );\n}\n\nfunction isSharePlan(\n plan: PreparedPrincipalContainerRematerializationBatch[\"plans\"][number],\n): plan is MaterializedContainerSharePlan {\n return plan.plan.body.eventType === \"container.grant\";\n}\n\nasync function assertCurrentShareGrantName(\n runtime: Parameters<typeof createRuntimeCurrentSharePrincipalPolicy>[0],\n share: Parameters<typeof shareRemoteContainerWithGroup>[0],\n context: RuntimeCurrentGroupMutationContext,\n expectedName: string,\n) {\n const mismatch = await groupPolicyNameMismatch(\n context.currentPolicy,\n expectedName,\n createRuntimeGroupMetadataAccess(\n runtime,\n share.author.organizationId,\n context.stillCurrent,\n context.verifyMetadataContainer,\n ).readName,\n );\n if (mismatch)\n throw new GroupShareNameMismatchError(\n \"Container share group name does not match the signed group policy\",\n );\n assertProjectionVerificationCurrent(context.stillCurrent);\n}\n\nfunction prepareCurrentShareGrantBatch(\n share: Parameters<typeof shareRemoteContainerWithGroup>[0],\n context: RuntimeCurrentGroupMutationContext,\n {\n nextPolicy,\n preceding,\n }: Pick<\n Parameters<typeof preparePrincipalContainerRematerializationBatch>[0],\n \"nextPolicy\" | \"preceding\"\n >,\n recitationStillCurrent?: () => boolean,\n) {\n return preparePrincipalContainerRematerializationBatch({\n ...share,\n preceding,\n grants: [\n ...new Map(\n [...context.currentPolicy.currentGrants, ...nextPolicy.grants].map(\n (grant) => [grant.containerId, grant] as const,\n ),\n ).values(),\n ],\n groupId: share.recipientGroupId,\n nextPolicy,\n resolveAuthoredPolicyReferences: context.resolveAuthoredPolicyReferences,\n stillCurrent: context.stillCurrent,\n recitationStillCurrent,\n });\n}\n"]}
@@ -8,6 +8,7 @@ import type { TrustedUserIdentityResolver } from "../../../data/trustedUserIdent
8
8
  import type { CurrentPrincipalPolicyReader } from "../../principals/currentPrincipalPolicyReader.js";
9
9
  import { type GroupPolicyNameReader } from "../principalPolicy/principalPolicyRequest.js";
10
10
  export interface ContainerManagedPrincipalShareApi extends ContainerShareApi, CurrentPrincipalPolicyReader, Pick<ApiClient, "evictContainerWriterProjection" | "getContainerWriterProjectionResult"> {
11
+ evictContainerWriterProjection(containerId: string): void;
11
12
  readonly recoverPendingPrincipalMutation?: ((organizationId: string) => Promise<void>) | undefined;
12
13
  commitOrganizationGroupPolicy: (organizationId: string, groupId: string, input: CommitOrganizationGroupPolicyRequest) => Promise<CommitOrganizationGroupPolicyResponse | null>;
13
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sharePrincipalPolicy.js","sourceRoot":"","sources":["sharePrincipalPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport {\n KeyingVerificationError,\n type PrincipalPolicyCheckpoint,\n type ReferencedPrincipalHead,\n type VerifiedPrincipalPolicy,\n} from \"@tearleads/crypto\";\nimport type { CommitOrganizationGroupPolicyRequest } from \"@tearleads/validators/request\";\nimport type {\n CommitOrganizationGroupPolicyResponse,\n PrincipalPolicyBundleResponse,\n} from \"@tearleads/validators/response\";\nimport type { ContainerShareApi } from \"../../../data/containers/shared/types\";\nimport { throwKeyingVerificationErrorWithContext } from \"../../../data/keyingProjectionVerification/error\";\nimport { advanceKeyingCheckpointsAtomically } from \"../../../data/persistence/keyingCheckpoints/keyingCheckpointAdvancePersistence\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../../data/persistence/keyingCheckpoints/keyingCheckpointPersistence\";\nimport { savePrincipalPolicyBundle } from \"../../../data/persistence/principalPolicy/principalPolicyPersistence\";\nimport { loadPrincipalPolicyBundleForReference } from \"../../../data/persistence/principalPolicy/principalPolicyReferencePersistence\";\nimport { retainVerifiedPrincipalPolicyBundle } from \"../../../data/persistence/principalPolicy/verifiedPrincipalPolicyRetentionPersistence\";\nimport {\n principalHeadMatchesReference,\n requireOrganizationGroupHead,\n} from \"../../../data/principals/organizationAuthorityDescriptor\";\nimport {\n principalPolicyReferenceFromBundle,\n verifyPrincipalPolicyBundleWithExternalOrganizationAdmins,\n} from \"../../../data/principals/principalPolicyAdminSigners\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../../data/trustedUserIdentity\";\nimport type { CurrentPrincipalPolicyReader } from \"../../principals/currentPrincipalPolicyReader\";\nimport {\n externalAdminPolicyPersistenceEntries,\n loadOrganizationExternalAdminPolicy,\n type VerifiedExternalAdminPolicy,\n} from \"../../principals/externalAdminPolicy\";\nimport {\n collectPrincipalPolicySignerPublicKeys,\n type PrincipalPolicySignerPublicKeyLoadErrorCode,\n} from \"../../principals/policyVerification\";\nimport { assertGroupMetadataBinding } from \"../groupMetadata/groupMetadataBinding\";\nimport {\n type GroupPolicyNameReader,\n groupPolicyNameMismatch,\n} from \"../principalPolicy/principalPolicyRequest\";\n\nexport interface ContainerManagedPrincipalShareApi\n extends ContainerShareApi,\n CurrentPrincipalPolicyReader,\n Pick<\n ApiClient,\n \"evictContainerWriterProjection\" | \"getContainerWriterProjectionResult\"\n > {\n readonly recoverPendingPrincipalMutation?:\n | ((organizationId: string) => Promise<void>)\n | undefined;\n commitOrganizationGroupPolicy: (\n organizationId: string,\n groupId: string,\n input: CommitOrganizationGroupPolicyRequest,\n ) => Promise<CommitOrganizationGroupPolicyResponse | null>;\n}\n\nexport interface VerifiedSharePrincipalPolicy {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly checkpointPolicies: readonly VerifiedPrincipalPolicy[];\n readonly dependencyBundles: readonly PrincipalPolicyBundleResponse[];\n readonly organizationId: string;\n readonly policy: VerifiedPrincipalPolicy;\n}\n\nasync function retainVerifiedSharePolicies(input: {\n bundle: PrincipalPolicyBundleResponse;\n execSql: ExecSql;\n organizationId: string;\n organizationPolicy: VerifiedExternalAdminPolicy | null;\n policy: VerifiedPrincipalPolicy;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<VerifiedPrincipalPolicy[]> {\n const retainedAt = new Date().toISOString();\n if (input.organizationPolicy) {\n for (const entry of externalAdminPolicyPersistenceEntries(\n input.organizationPolicy,\n )) {\n await retainVerifiedPrincipalPolicyBundle({\n ...entry,\n execSql: input.execSql,\n organizationId: input.organizationId,\n stillCurrent: input.stillCurrent,\n updatedAt: retainedAt,\n });\n }\n }\n await retainVerifiedPrincipalPolicyBundle({\n bundle: input.bundle,\n execSql: input.execSql,\n organizationId: input.organizationId,\n policy: input.policy,\n stillCurrent: input.stillCurrent,\n updatedAt: retainedAt,\n });\n return [\n ...(input.organizationPolicy\n ? externalAdminPolicyPersistenceEntries(input.organizationPolicy).map(\n (entry) => entry.policy,\n )\n : []),\n input.policy,\n ];\n}\n\n/**\n * Commits the verification a loadVerifiedGroupSharePrincipalPolicy call\n * deferred: advances the keying checkpoints for the verified policies and\n * caches the dependency bundles they were verified against.\n */\nexport async function advanceVerifiedSharePolicies(\n execSql: ExecSql,\n verified: Pick<\n VerifiedSharePrincipalPolicy,\n \"checkpointPolicies\" | \"dependencyBundles\" | \"organizationId\"\n >,\n stillCurrent?: (() => boolean) | undefined,\n): Promise<void> {\n await advanceKeyingCheckpointsAtomically({\n access: [],\n execSql,\n organizationId: verified.organizationId,\n policies: verified.checkpointPolicies,\n stillCurrent,\n });\n if (stillCurrent?.() === false) return;\n for (const bundle of verified.dependencyBundles) {\n await savePrincipalPolicyBundle(\n execSql,\n bundle,\n new Date().toISOString(),\n verified.organizationId,\n { stillCurrent },\n );\n if (stillCurrent?.() === false) return;\n }\n}\n\nfunction assertGroupPolicyTarget(\n bundle: PrincipalPolicyBundleResponse,\n groupId: string,\n): void {\n if (\n bundle.currentState.principalType !== \"group\" ||\n bundle.currentState.principalId !== groupId\n ) {\n throw new Error(\"Container share principal policy target mismatch\");\n }\n}\n\nfunction signerPublicKeyLoadErrorMessage(\n code: PrincipalPolicySignerPublicKeyLoadErrorCode,\n): string {\n switch (code) {\n case \"fingerprint-mismatch\":\n return \"principal policy signer key fingerprint mismatch\";\n case \"not-found\":\n return \"principal policy signer key could not be loaded\";\n }\n}\n\nasync function loadGroupSharePolicyBundle(input: {\n apiClient: ContainerManagedPrincipalShareApi;\n execSql: ExecSql;\n expectedGroupHead?: ReferencedPrincipalHead | undefined;\n groupId: string;\n localCheckpoint: PrincipalPolicyCheckpoint | null;\n}): Promise<PrincipalPolicyBundleResponse> {\n if (\n input.expectedGroupHead &&\n (input.expectedGroupHead.principalType !== \"group\" ||\n input.expectedGroupHead.principalId !== input.groupId)\n ) {\n throw new Error(\"Container share expected group policy target mismatch\");\n }\n const bundleFromCache = input.expectedGroupHead\n ? await loadPrincipalPolicyBundleForReference(\n input.execSql,\n input.expectedGroupHead,\n input.localCheckpoint,\n )\n : null;\n let bundle = bundleFromCache;\n bundle ??= await input.apiClient.getCurrentPrincipalPolicy(\n \"group\",\n input.groupId,\n );\n if (!bundle) {\n throw new Error(\"Container share principal policy could not be loaded\");\n }\n assertGroupPolicyTarget(bundle, input.groupId);\n if (\n input.expectedGroupHead &&\n !principalHeadMatchesReference(\n principalPolicyReferenceFromBundle(bundle),\n input.expectedGroupHead,\n )\n ) {\n throw new Error(\n \"Container share group policy does not match the signed organization directory\",\n );\n }\n return bundle;\n}\n\n/**\n * The chosen group label does not match the name in the group's verified\n * policy. A KeyingVerificationError (so it is reported as an incident), with\n * its own class so a caller can tell this refusal from every other\n * `object_mismatch` and say what happened.\n */\nexport class GroupShareNameMismatchError extends KeyingVerificationError {\n constructor(message: string) {\n super(\"object_mismatch\", message);\n this.name = \"GroupShareNameMismatchError\";\n }\n}\n\n/**\n * The share picker labels groups from the organization read model, which a\n * compromised server can relabel, so the name the user chose must equal the\n * name committed in the target's verified policy. Names compare by their\n * canonical key so look-alike spellings count as the same name. Uniqueness of\n * signed names within an organization is enforced where names enter — group\n * creation verifies every group in the signed directory — so a single\n * verified match identifies the group.\n */\nasync function assertShareGroupName(input: {\n readEncryptedName?: GroupPolicyNameReader | undefined;\n bundle: PrincipalPolicyBundleResponse;\n expectedGroupName: string;\n}): Promise<void> {\n // The label comes from the untrusted read model. Signed names never carry\n // an invisible code point, so a label that does is a look-alike that would\n // only match after canonicalization strips it; refuse it outright.\n const mismatch = await groupPolicyNameMismatch(\n input.bundle,\n input.expectedGroupName,\n input.readEncryptedName,\n );\n if (mismatch === \"forbidden_characters\") {\n throw new GroupShareNameMismatchError(\n \"Container share group name contains control or format characters\",\n );\n }\n if (mismatch === \"name_mismatch\") {\n throw new GroupShareNameMismatchError(\n \"Container share group name does not match the signed group policy\",\n );\n }\n}\n\nexport async function loadVerifiedGroupSharePrincipalPolicy(input: {\n readEncryptedName?: GroupPolicyNameReader | undefined;\n apiClient: ContainerManagedPrincipalShareApi;\n execSql: ExecSql;\n expectedGroupHead?: ReferencedPrincipalHead | undefined;\n /**\n * The display name the user chose the group by. The read model that labels\n * groups is a server projection; only the name committed in the signed\n * group payload can confirm the share lands on the group the user saw.\n */\n expectedGroupName?: string | undefined;\n groupId: string;\n organizationId: string;\n resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<VerifiedSharePrincipalPolicy> {\n const organizationAdminPolicy = await loadOrganizationExternalAdminPolicy({\n currentPolicyReader: input.apiClient,\n execSql: input.execSql,\n organizationId: input.organizationId,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n stillCurrent: input.stillCurrent,\n });\n if (!organizationAdminPolicy) {\n throw new Error(\"Organization admin authority could not be verified\");\n }\n const committedGroupHead = requireOrganizationGroupHead(\n organizationAdminPolicy.descriptor,\n input.groupId,\n );\n if (\n input.expectedGroupHead &&\n !principalHeadMatchesReference(input.expectedGroupHead, committedGroupHead)\n ) {\n throw new Error(\n \"Container share expected group head conflicts with the signed organization directory\",\n );\n }\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n \"group\",\n input.groupId,\n );\n const bundle = await loadGroupSharePolicyBundle({\n ...input,\n expectedGroupHead: committedGroupHead,\n localCheckpoint,\n });\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (\"error\" in signerPublicKeys) {\n throw new Error(signerPublicKeyLoadErrorMessage(signerPublicKeys.error));\n }\n\n const verified =\n await verifyPrincipalPolicyBundleWithExternalOrganizationAdmins({\n bundle,\n expectedReference: committedGroupHead,\n loadExternalAuthority: async () =>\n organizationAdminPolicy.externalAuthority,\n localCheckpoint,\n signerPublicKeys: signerPublicKeys.signerPublicKeys,\n });\n if (!verified.ok) {\n throwKeyingVerificationErrorWithContext(\n verified.error,\n \"Container share principal policy verification failed\",\n );\n }\n assertGroupMetadataBinding(bundle, organizationAdminPolicy.descriptor);\n if (input.expectedGroupName !== undefined) {\n await assertShareGroupName({\n readEncryptedName: input.readEncryptedName,\n bundle,\n expectedGroupName: input.expectedGroupName,\n });\n }\n\n const checkpointPolicies = await retainVerifiedSharePolicies({\n bundle,\n execSql: input.execSql,\n organizationId: input.organizationId,\n organizationPolicy: organizationAdminPolicy,\n policy: verified.value,\n stillCurrent: input.stillCurrent,\n });\n return {\n bundle,\n checkpointPolicies,\n dependencyBundles: externalAdminPolicyPersistenceEntries(\n organizationAdminPolicy,\n ).map((entry) => entry.bundle),\n organizationId: input.organizationId,\n policy: verified.value,\n };\n}\n"]}
1
+ {"version":3,"file":"sharePrincipalPolicy.js","sourceRoot":"","sources":["sharePrincipalPolicy.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApiClient } from \"@tearleads/api-client\";\nimport {\n KeyingVerificationError,\n type PrincipalPolicyCheckpoint,\n type ReferencedPrincipalHead,\n type VerifiedPrincipalPolicy,\n} from \"@tearleads/crypto\";\nimport type { CommitOrganizationGroupPolicyRequest } from \"@tearleads/validators/request\";\nimport type {\n CommitOrganizationGroupPolicyResponse,\n PrincipalPolicyBundleResponse,\n} from \"@tearleads/validators/response\";\nimport type { ContainerShareApi } from \"../../../data/containers/shared/types\";\nimport { throwKeyingVerificationErrorWithContext } from \"../../../data/keyingProjectionVerification/error\";\nimport { advanceKeyingCheckpointsAtomically } from \"../../../data/persistence/keyingCheckpoints/keyingCheckpointAdvancePersistence\";\nimport { loadPrincipalPolicyCheckpoint } from \"../../../data/persistence/keyingCheckpoints/keyingCheckpointPersistence\";\nimport { savePrincipalPolicyBundle } from \"../../../data/persistence/principalPolicy/principalPolicyPersistence\";\nimport { loadPrincipalPolicyBundleForReference } from \"../../../data/persistence/principalPolicy/principalPolicyReferencePersistence\";\nimport { retainVerifiedPrincipalPolicyBundle } from \"../../../data/persistence/principalPolicy/verifiedPrincipalPolicyRetentionPersistence\";\nimport {\n principalHeadMatchesReference,\n requireOrganizationGroupHead,\n} from \"../../../data/principals/organizationAuthorityDescriptor\";\nimport {\n principalPolicyReferenceFromBundle,\n verifyPrincipalPolicyBundleWithExternalOrganizationAdmins,\n} from \"../../../data/principals/principalPolicyAdminSigners\";\nimport type { ExecSql } from \"../../../data/sqlite/sqlSchema\";\nimport type { TrustedUserIdentityResolver } from \"../../../data/trustedUserIdentity\";\nimport type { CurrentPrincipalPolicyReader } from \"../../principals/currentPrincipalPolicyReader\";\nimport {\n externalAdminPolicyPersistenceEntries,\n loadOrganizationExternalAdminPolicy,\n type VerifiedExternalAdminPolicy,\n} from \"../../principals/externalAdminPolicy\";\nimport {\n collectPrincipalPolicySignerPublicKeys,\n type PrincipalPolicySignerPublicKeyLoadErrorCode,\n} from \"../../principals/policyVerification\";\nimport { assertGroupMetadataBinding } from \"../groupMetadata/groupMetadataBinding\";\nimport {\n type GroupPolicyNameReader,\n groupPolicyNameMismatch,\n} from \"../principalPolicy/principalPolicyRequest\";\n\nexport interface ContainerManagedPrincipalShareApi\n extends ContainerShareApi,\n CurrentPrincipalPolicyReader,\n Pick<\n ApiClient,\n \"evictContainerWriterProjection\" | \"getContainerWriterProjectionResult\"\n > {\n evictContainerWriterProjection(containerId: string): void;\n readonly recoverPendingPrincipalMutation?:\n | ((organizationId: string) => Promise<void>)\n | undefined;\n commitOrganizationGroupPolicy: (\n organizationId: string,\n groupId: string,\n input: CommitOrganizationGroupPolicyRequest,\n ) => Promise<CommitOrganizationGroupPolicyResponse | null>;\n}\n\nexport interface VerifiedSharePrincipalPolicy {\n readonly bundle: PrincipalPolicyBundleResponse;\n readonly checkpointPolicies: readonly VerifiedPrincipalPolicy[];\n readonly dependencyBundles: readonly PrincipalPolicyBundleResponse[];\n readonly organizationId: string;\n readonly policy: VerifiedPrincipalPolicy;\n}\n\nasync function retainVerifiedSharePolicies(input: {\n bundle: PrincipalPolicyBundleResponse;\n execSql: ExecSql;\n organizationId: string;\n organizationPolicy: VerifiedExternalAdminPolicy | null;\n policy: VerifiedPrincipalPolicy;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<VerifiedPrincipalPolicy[]> {\n const retainedAt = new Date().toISOString();\n if (input.organizationPolicy) {\n for (const entry of externalAdminPolicyPersistenceEntries(\n input.organizationPolicy,\n )) {\n await retainVerifiedPrincipalPolicyBundle({\n ...entry,\n execSql: input.execSql,\n organizationId: input.organizationId,\n stillCurrent: input.stillCurrent,\n updatedAt: retainedAt,\n });\n }\n }\n await retainVerifiedPrincipalPolicyBundle({\n bundle: input.bundle,\n execSql: input.execSql,\n organizationId: input.organizationId,\n policy: input.policy,\n stillCurrent: input.stillCurrent,\n updatedAt: retainedAt,\n });\n return [\n ...(input.organizationPolicy\n ? externalAdminPolicyPersistenceEntries(input.organizationPolicy).map(\n (entry) => entry.policy,\n )\n : []),\n input.policy,\n ];\n}\n\n/**\n * Commits the verification a loadVerifiedGroupSharePrincipalPolicy call\n * deferred: advances the keying checkpoints for the verified policies and\n * caches the dependency bundles they were verified against.\n */\nexport async function advanceVerifiedSharePolicies(\n execSql: ExecSql,\n verified: Pick<\n VerifiedSharePrincipalPolicy,\n \"checkpointPolicies\" | \"dependencyBundles\" | \"organizationId\"\n >,\n stillCurrent?: (() => boolean) | undefined,\n): Promise<void> {\n await advanceKeyingCheckpointsAtomically({\n access: [],\n execSql,\n organizationId: verified.organizationId,\n policies: verified.checkpointPolicies,\n stillCurrent,\n });\n if (stillCurrent?.() === false) return;\n for (const bundle of verified.dependencyBundles) {\n await savePrincipalPolicyBundle(\n execSql,\n bundle,\n new Date().toISOString(),\n verified.organizationId,\n { stillCurrent },\n );\n if (stillCurrent?.() === false) return;\n }\n}\n\nfunction assertGroupPolicyTarget(\n bundle: PrincipalPolicyBundleResponse,\n groupId: string,\n): void {\n if (\n bundle.currentState.principalType !== \"group\" ||\n bundle.currentState.principalId !== groupId\n ) {\n throw new Error(\"Container share principal policy target mismatch\");\n }\n}\n\nfunction signerPublicKeyLoadErrorMessage(\n code: PrincipalPolicySignerPublicKeyLoadErrorCode,\n): string {\n switch (code) {\n case \"fingerprint-mismatch\":\n return \"principal policy signer key fingerprint mismatch\";\n case \"not-found\":\n return \"principal policy signer key could not be loaded\";\n }\n}\n\nasync function loadGroupSharePolicyBundle(input: {\n apiClient: ContainerManagedPrincipalShareApi;\n execSql: ExecSql;\n expectedGroupHead?: ReferencedPrincipalHead | undefined;\n groupId: string;\n localCheckpoint: PrincipalPolicyCheckpoint | null;\n}): Promise<PrincipalPolicyBundleResponse> {\n if (\n input.expectedGroupHead &&\n (input.expectedGroupHead.principalType !== \"group\" ||\n input.expectedGroupHead.principalId !== input.groupId)\n ) {\n throw new Error(\"Container share expected group policy target mismatch\");\n }\n const bundleFromCache = input.expectedGroupHead\n ? await loadPrincipalPolicyBundleForReference(\n input.execSql,\n input.expectedGroupHead,\n input.localCheckpoint,\n )\n : null;\n let bundle = bundleFromCache;\n bundle ??= await input.apiClient.getCurrentPrincipalPolicy(\n \"group\",\n input.groupId,\n );\n if (!bundle) {\n throw new Error(\"Container share principal policy could not be loaded\");\n }\n assertGroupPolicyTarget(bundle, input.groupId);\n if (\n input.expectedGroupHead &&\n !principalHeadMatchesReference(\n principalPolicyReferenceFromBundle(bundle),\n input.expectedGroupHead,\n )\n ) {\n throw new Error(\n \"Container share group policy does not match the signed organization directory\",\n );\n }\n return bundle;\n}\n\n/**\n * The chosen group label does not match the name in the group's verified\n * policy. A KeyingVerificationError (so it is reported as an incident), with\n * its own class so a caller can tell this refusal from every other\n * `object_mismatch` and say what happened.\n */\nexport class GroupShareNameMismatchError extends KeyingVerificationError {\n constructor(message: string) {\n super(\"object_mismatch\", message);\n this.name = \"GroupShareNameMismatchError\";\n }\n}\n\n/**\n * The share picker labels groups from the organization read model, which a\n * compromised server can relabel, so the name the user chose must equal the\n * name committed in the target's verified policy. Names compare by their\n * canonical key so look-alike spellings count as the same name. Uniqueness of\n * signed names within an organization is enforced where names enter — group\n * creation verifies every group in the signed directory — so a single\n * verified match identifies the group.\n */\nasync function assertShareGroupName(input: {\n readEncryptedName?: GroupPolicyNameReader | undefined;\n bundle: PrincipalPolicyBundleResponse;\n expectedGroupName: string;\n}): Promise<void> {\n // The label comes from the untrusted read model. Signed names never carry\n // an invisible code point, so a label that does is a look-alike that would\n // only match after canonicalization strips it; refuse it outright.\n const mismatch = await groupPolicyNameMismatch(\n input.bundle,\n input.expectedGroupName,\n input.readEncryptedName,\n );\n if (mismatch === \"forbidden_characters\") {\n throw new GroupShareNameMismatchError(\n \"Container share group name contains control or format characters\",\n );\n }\n if (mismatch === \"name_mismatch\") {\n throw new GroupShareNameMismatchError(\n \"Container share group name does not match the signed group policy\",\n );\n }\n}\n\nexport async function loadVerifiedGroupSharePrincipalPolicy(input: {\n readEncryptedName?: GroupPolicyNameReader | undefined;\n apiClient: ContainerManagedPrincipalShareApi;\n execSql: ExecSql;\n expectedGroupHead?: ReferencedPrincipalHead | undefined;\n /**\n * The display name the user chose the group by. The read model that labels\n * groups is a server projection; only the name committed in the signed\n * group payload can confirm the share lands on the group the user saw.\n */\n expectedGroupName?: string | undefined;\n groupId: string;\n organizationId: string;\n resolveTrustedUserIdentity: TrustedUserIdentityResolver;\n stillCurrent?: (() => boolean) | undefined;\n}): Promise<VerifiedSharePrincipalPolicy> {\n const organizationAdminPolicy = await loadOrganizationExternalAdminPolicy({\n currentPolicyReader: input.apiClient,\n execSql: input.execSql,\n organizationId: input.organizationId,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n stillCurrent: input.stillCurrent,\n });\n if (!organizationAdminPolicy) {\n throw new Error(\"Organization admin authority could not be verified\");\n }\n const committedGroupHead = requireOrganizationGroupHead(\n organizationAdminPolicy.descriptor,\n input.groupId,\n );\n if (\n input.expectedGroupHead &&\n !principalHeadMatchesReference(input.expectedGroupHead, committedGroupHead)\n ) {\n throw new Error(\n \"Container share expected group head conflicts with the signed organization directory\",\n );\n }\n const localCheckpoint = await loadPrincipalPolicyCheckpoint(\n input.execSql,\n \"group\",\n input.groupId,\n );\n const bundle = await loadGroupSharePolicyBundle({\n ...input,\n expectedGroupHead: committedGroupHead,\n localCheckpoint,\n });\n const signerPublicKeys = await collectPrincipalPolicySignerPublicKeys({\n bundle,\n resolveTrustedUserIdentity: input.resolveTrustedUserIdentity,\n });\n if (\"error\" in signerPublicKeys) {\n throw new Error(signerPublicKeyLoadErrorMessage(signerPublicKeys.error));\n }\n\n const verified =\n await verifyPrincipalPolicyBundleWithExternalOrganizationAdmins({\n bundle,\n expectedReference: committedGroupHead,\n loadExternalAuthority: async () =>\n organizationAdminPolicy.externalAuthority,\n localCheckpoint,\n signerPublicKeys: signerPublicKeys.signerPublicKeys,\n });\n if (!verified.ok) {\n throwKeyingVerificationErrorWithContext(\n verified.error,\n \"Container share principal policy verification failed\",\n );\n }\n assertGroupMetadataBinding(bundle, organizationAdminPolicy.descriptor);\n if (input.expectedGroupName !== undefined) {\n await assertShareGroupName({\n readEncryptedName: input.readEncryptedName,\n bundle,\n expectedGroupName: input.expectedGroupName,\n });\n }\n\n const checkpointPolicies = await retainVerifiedSharePolicies({\n bundle,\n execSql: input.execSql,\n organizationId: input.organizationId,\n organizationPolicy: organizationAdminPolicy,\n policy: verified.value,\n stillCurrent: input.stillCurrent,\n });\n return {\n bundle,\n checkpointPolicies,\n dependencyBundles: externalAdminPolicyPersistenceEntries(\n organizationAdminPolicy,\n ).map((entry) => entry.bundle),\n organizationId: input.organizationId,\n policy: verified.value,\n };\n}\n"]}