Skip to content

Commit 90018a0

Browse files
authored
H-4622: Allow creating policies alongside entity creation (#7405)
1 parent 3b7f4db commit 90018a0

File tree

31 files changed

+341
-294
lines changed

31 files changed

+341
-294
lines changed

apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/get-entity-summaries-from-text.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,9 @@ export const getEntitySummariesFromText = async (params: {
257257
};
258258

259259
for (const { name, summary, type } of toolCallEntitySummaries) {
260-
const entityUuid = generateUuid();
260+
const entityUuid = generateUuid() as EntityUuid;
261261

262-
const entityId = entityIdFromComponents(webId, entityUuid as EntityUuid);
262+
const entityId = entityIdFromComponents(webId, entityUuid);
263263

264264
const isKnownType = dereferencedEntityTypes.some(
265265
(dereferencedEntityType) => dereferencedEntityType.$id === type,

apps/hash-ai-worker-ts/src/activities/shared/get-llm-response.ts

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { getInstanceAdminsTeam } from "@local/hash-backend-utils/hash-instance";
1010
import { createUsageRecord } from "@local/hash-backend-utils/service-usage";
1111
import type { GraphApi } from "@local/hash-graph-client";
1212
import { HashEntity } from "@local/hash-graph-sdk/entity";
13-
import { createPolicy } from "@local/hash-graph-sdk/policy";
1413
import type { FlowUsageRecordCustomMetadata } from "@local/hash-isomorphic-utils/flows/types";
1514
import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid";
1615
import { systemLinkEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids";
@@ -207,6 +206,19 @@ export const getLlmResponse = async <T extends LlmParams>(
207206
} satisfies OriginProvenance,
208207
};
209208

209+
const viewPrincipals: PrincipalConstraint[] = [
210+
{
211+
type: "actor",
212+
actorType: "user",
213+
id: userAccountId,
214+
},
215+
{
216+
type: "actor",
217+
actorType: "ai",
218+
id: aiAssistantAccountId,
219+
},
220+
];
221+
210222
const errors = await Promise.all(
211223
incurredInEntities.map(async ({ entityId }) => {
212224
try {
@@ -251,40 +263,14 @@ export const getLlmResponse = async <T extends LlmParams>(
251263
},
252264
},
253265
],
254-
},
255-
);
256-
257-
const viewPrincipals: PrincipalConstraint[] = [
258-
{
259-
type: "actor",
260-
actorType: "user",
261-
id: userAccountId,
262-
},
263-
{
264-
type: "actor",
265-
actorType: "ai",
266-
id: aiAssistantAccountId,
267-
},
268-
];
269-
270-
// TODO: allow creating policies alongside entity creation
271-
// see https://linear.app/hash/issue/H-4622/allow-creating-policies-alongside-entity-creation
272-
for (const principal of viewPrincipals) {
273-
await createPolicy(
274-
graphApiClient,
275-
{ actorId: aiAssistantAccountId },
276-
{
266+
policies: viewPrincipals.map((principal) => ({
277267
name: `usage-record-view-entity-${incurredInEntityUuid}`,
278268
effect: "permit",
279269
actions: ["viewEntity"],
280270
principal,
281-
resource: {
282-
type: "entity",
283-
id: incurredInEntityUuid,
284-
},
285-
},
286-
);
287-
}
271+
})),
272+
},
273+
);
288274

289275
return [];
290276
} catch (error) {

apps/hash-api/src/graph/knowledge/system-types/linear-integration-entity.ts

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
BaseUrl,
99
Entity,
1010
EntityId,
11+
EntityUuid,
1112
MachineId,
1213
} from "@blockprotocol/type-system";
1314
import {
@@ -17,7 +18,7 @@ import {
1718
import { EntityTypeMismatchError } from "@local/hash-backend-utils/error";
1819
import type { EntityRelationAndSubjectBranded } from "@local/hash-graph-sdk/authorization";
1920
import type { HashEntity } from "@local/hash-graph-sdk/entity";
20-
import { createPolicy } from "@local/hash-graph-sdk/policy";
21+
import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid";
2122
import {
2223
currentTimeInstantTemporalAxes,
2324
generateVersionedUrlMatchingFilter,
@@ -391,42 +392,31 @@ export const linkIntegrationToWeb: ImpureGraphFunction<
391392
linearIntegrationEntityId,
392393
);
393394

394-
const linkEntity = await createLinkEntity<SyncLinearDataWith>(
395-
context,
396-
authentication,
397-
{
398-
webId: linearIntegrationWebId,
399-
properties,
400-
linkData: {
401-
leftEntityId: linearIntegrationEntityId,
402-
rightEntityId: webEntityId,
403-
},
404-
entityTypeIds: [
405-
systemLinkEntityTypes.syncLinearDataWith.linkEntityTypeId,
406-
],
407-
relationships: linearIntegrationRelationships,
408-
},
409-
);
410-
411-
const linkEntityUuid = extractEntityUuidFromEntityId(
412-
linkEntity.metadata.recordId.entityId,
413-
);
414-
415-
// TODO: allow creating policies alongside entity creation
416-
// see https://linear.app/hash/issue/H-4622/allow-creating-policies-alongside-entity-creation
417-
await createPolicy(context.graphApi, authentication, {
418-
name: `linear-integration-bot-view-link-entity-${linkEntityUuid}`,
419-
principal: {
420-
type: "actor",
421-
actorType: "machine",
422-
id: linearBotMachineId,
423-
},
424-
effect: "permit",
425-
actions: ["viewEntity"],
426-
resource: {
427-
type: "entity",
428-
id: linkEntityUuid,
395+
const linkEntityUuid = generateUuid() as EntityUuid;
396+
await createLinkEntity<SyncLinearDataWith>(context, authentication, {
397+
webId: linearIntegrationWebId,
398+
entityUuid: linkEntityUuid,
399+
properties,
400+
linkData: {
401+
leftEntityId: linearIntegrationEntityId,
402+
rightEntityId: webEntityId,
429403
},
404+
entityTypeIds: [
405+
systemLinkEntityTypes.syncLinearDataWith.linkEntityTypeId,
406+
],
407+
relationships: linearIntegrationRelationships,
408+
policies: [
409+
{
410+
name: `linear-integration-bot-view-link-entity-${linkEntityUuid}`,
411+
principal: {
412+
type: "actor",
413+
actorType: "machine",
414+
id: linearBotMachineId,
415+
},
416+
effect: "permit",
417+
actions: ["viewEntity"],
418+
},
419+
],
430420
});
431421
}
432422
};

apps/hash-api/src/graph/knowledge/system-types/user-secret.ts

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import type {
1414
import { createUserSecretPath } from "@local/hash-backend-utils/vault";
1515
import type { GraphApi } from "@local/hash-graph-client";
1616
import type { EntityRelationAndSubjectBranded } from "@local/hash-graph-sdk/authorization";
17-
import { createPolicy } from "@local/hash-graph-sdk/policy";
1817
import { generateUuid } from "@local/hash-isomorphic-utils/generate-uuid";
1918
import {
2019
systemEntityTypes,
@@ -182,6 +181,19 @@ export const createUserSecret = async <
182181
);
183182
}
184183

184+
const viewPrincipals: PrincipalConstraint[] = [
185+
{
186+
type: "actor",
187+
actorType: "user",
188+
id: userAccountId,
189+
},
190+
{
191+
type: "actor",
192+
actorType: "machine",
193+
id: managingBotAccountId,
194+
},
195+
];
196+
185197
const userSecretEntityUuid = generateUuid() as EntityUuid;
186198
const usesUserSecretEntityUuid = generateUuid() as EntityUuid;
187199

@@ -194,6 +206,16 @@ export const createUserSecret = async <
194206
entityUuid: userSecretEntityUuid,
195207
properties: secretMetadata,
196208
relationships: botEditorUserViewerOnly,
209+
policies: viewPrincipals.map((principal) => ({
210+
name: `user-secret-view-entity-${userSecretEntityUuid}`,
211+
principal,
212+
effect: "permit",
213+
actions: ["viewEntity"],
214+
resource: {
215+
type: "entity",
216+
id: userSecretEntityUuid,
217+
},
218+
})),
197219
},
198220
);
199221

@@ -211,38 +233,18 @@ export const createUserSecret = async <
211233
},
212234
entityTypeIds: [systemLinkEntityTypes.usesUserSecret.linkEntityTypeId],
213235
relationships: botEditorUserViewerOnly,
214-
},
215-
);
216-
217-
const viewPrincipals: PrincipalConstraint[] = [
218-
{
219-
type: "actor",
220-
actorType: "user",
221-
id: userAccountId,
222-
},
223-
{
224-
type: "actor",
225-
actorType: "machine",
226-
id: managingBotAccountId,
227-
},
228-
];
229-
230-
// TODO: allow creating policies alongside entity creation
231-
// see https://linear.app/hash/issue/H-4622/allow-creating-policies-alongside-entity-creation
232-
for (const entityUuid of [userSecretEntityUuid, usesUserSecretEntityUuid]) {
233-
for (const principal of viewPrincipals) {
234-
await createPolicy(graphApi, authentication, {
235-
name: `user-secret-view-entity-${entityUuid}`,
236+
policies: viewPrincipals.map((principal) => ({
237+
name: `user-secret-view-entity-${usesUserSecretEntityUuid}`,
236238
principal,
237239
effect: "permit",
238240
actions: ["viewEntity"],
239241
resource: {
240242
type: "entity",
241-
id: entityUuid,
243+
id: usesUserSecretEntityUuid,
242244
},
243-
});
244-
}
245-
}
245+
})),
246+
},
247+
);
246248

247249
return userSecretEntity.metadata.recordId.entityId;
248250
};

apps/hash-api/src/graphql/resolvers/knowledge/user/submit-early-access-form.ts

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
import {
2-
extractEntityUuidFromEntityId,
3-
type WebId,
4-
} from "@blockprotocol/type-system";
1+
import type { WebId } from "@blockprotocol/type-system";
52
import { getInstanceAdminsTeam } from "@local/hash-backend-utils/hash-instance";
6-
import { createPolicy } from "@local/hash-graph-sdk/policy";
73
import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids";
84
import { simplifyProperties } from "@local/hash-isomorphic-utils/simplify-properties";
95
import type { ProspectiveUser } from "@local/hash-isomorphic-utils/system-types/prospectiveuser";
@@ -35,7 +31,7 @@ export const submitEarlyAccessFormResolver: ResolverFn<
3531
authentication,
3632
);
3733

38-
const entity = await createEntity<ProspectiveUser>(
34+
await createEntity<ProspectiveUser>(
3935
context,
4036
/** The user does not yet have permissions to create entities, so we do it with the HASH system account instead */
4137
authentication,
@@ -134,26 +130,21 @@ export const submitEarlyAccessFormResolver: ResolverFn<
134130
},
135131
},
136132
],
133+
policies: [
134+
{
135+
name: "prospective-user-view-entity",
136+
principal: {
137+
type: "actor",
138+
actorType: "user",
139+
id: user.accountId,
140+
},
141+
effect: "permit",
142+
actions: ["viewEntity"],
143+
},
144+
],
137145
},
138146
);
139147

140-
// TODO: allow creating policies alongside entity creation
141-
// see https://linear.app/hash/issue/H-4622/allow-creating-policies-alongside-entity-creation
142-
await createPolicy(context.graphApi, authentication, {
143-
name: "prospective-user-view-entity",
144-
principal: {
145-
type: "actor",
146-
actorType: "user",
147-
id: user.accountId,
148-
},
149-
effect: "permit",
150-
actions: ["viewEntity"],
151-
resource: {
152-
type: "entity",
153-
id: extractEntityUuidFromEntityId(entity.entityId),
154-
},
155-
});
156-
157148
if (process.env.ACCESS_FORM_SLACK_WEBHOOK_URL) {
158149
const simpleProperties = simplifyProperties(properties);
159150
const slackMessage = {

0 commit comments

Comments
 (0)