@agent-native/core 0.212.1 → 0.214.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/a2a/anthropic-managed-agents.js +1 -0
- package/dist/a2a/caller-auth.js +7 -2
- package/dist/a2a/client.d.ts +1 -0
- package/dist/a2a/client.js +27 -0
- package/dist/a2a/handlers.js +15 -3
- package/dist/a2a/organization-identity.d.ts +4 -1
- package/dist/a2a/organization-identity.js +3 -1
- package/dist/a2a/server.d.ts +6 -5
- package/dist/a2a/server.js +79 -6
- package/dist/a2a-claims.d.ts +1 -0
- package/dist/a2a-claims.js +1 -0
- package/dist/agent/actions/manage-provider-key-policy.js +4 -2
- package/dist/agent/app-model-defaults.js +2 -10
- package/dist/agent/loop-settings.js +2 -10
- package/dist/appearance/actions/get-theme-family.d.ts +8 -0
- package/dist/appearance/actions/get-theme-family.js +38 -0
- package/dist/appearance/actions/set-theme-family.d.ts +7 -0
- package/dist/appearance/actions/set-theme-family.js +33 -0
- package/dist/appearance/theme-family.d.ts +13 -0
- package/dist/appearance/theme-family.js +38 -0
- package/dist/audit/actions/export-audit-events.js +1 -0
- package/dist/audit/attribution.d.ts +5 -4
- package/dist/audit/attribution.js +2 -1
- package/dist/audit/index.d.ts +1 -1
- package/dist/audit/ocsf.js +1 -0
- package/dist/audit/read-scope.js +2 -12
- package/dist/audit/record.js +1 -0
- package/dist/audit/store.js +12 -3
- package/dist/audit/types.d.ts +4 -0
- package/dist/automation/index.d.ts +1 -1
- package/dist/automations/service.js +3 -10
- package/dist/client/org/hooks.d.ts +3 -0
- package/dist/client/org/hooks.js +12 -0
- package/dist/client/theme-family.d.ts +35 -0
- package/dist/client/theme-family.js +223 -0
- package/dist/client/theme.d.ts +1 -1
- package/dist/client/theme.js +5 -2
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +1 -1
- package/dist/connections/catalog.js +7 -1
- package/dist/credentials/index.js +18 -2
- package/dist/data-widgets/index.d.ts +339 -4
- package/dist/data-widgets/index.js +150 -7
- package/dist/db/schema-snapshot.generated.js +5 -2
- package/dist/feature-flags/a2a-action-route.js +1 -0
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/file-upload/storage-settings.js +2 -9
- package/dist/framework-tools.js +2 -0
- package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
- package/dist/jobs/tools.js +2 -12
- package/dist/mcp/actions/service-token-access.js +15 -11
- package/dist/mcp/credential-issuance.js +9 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +1 -1
- package/dist/org/actions.d.ts +1 -1
- package/dist/org/actions.js +3 -7
- package/dist/org/app-roles.js +10 -1
- package/dist/org/context.d.ts +1 -0
- package/dist/org/context.js +122 -24
- package/dist/org/federation.d.ts +1 -1
- package/dist/org/federation.js +2 -2
- package/dist/org/handlers.d.ts +4 -0
- package/dist/org/handlers.js +140 -44
- package/dist/org/index.d.ts +2 -1
- package/dist/org/membership.d.ts +6 -4
- package/dist/org/membership.js +7 -5
- package/dist/org/migrations.js +6 -0
- package/dist/org/plugin.d.ts +1 -0
- package/dist/org/plugin.js +9 -1
- package/dist/org/private-icon-handlers.js +4 -10
- package/dist/org/types.d.ts +2 -0
- package/dist/org/workspace-app-access.js +62 -14
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/action-discovery.js +8 -0
- package/dist/server/action-routes.d.ts +1 -0
- package/dist/server/action-routes.js +13 -1
- package/dist/server/agent-chat/context-tools.js +43 -1
- package/dist/server/agent-chat/prompt-resources.js +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/org-admin.js +3 -2
- package/dist/server/personal-provider-key-holders.d.ts +1 -1
- package/dist/server/personal-provider-key-holders.js +7 -2
- package/dist/server/personal-provider-key-policy.d.ts +2 -0
- package/dist/server/personal-provider-key-policy.js +21 -5
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/request-context.js +7 -0
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -13
- package/dist/triggers/actions/manage-automation.d.ts +4 -4
- package/dist/triggers/routes.js +2 -9
- package/dist/usage/alerts-store.js +2 -9
- package/dist/usage/metrics-store.js +2 -9
- package/dist/workspace-connections/actions/list-workspace-user-groups.d.ts +1 -1
- package/dist/workspace-connections/groups.js +2 -11
- package/package.json +3 -3
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -13
package/dist/org/handlers.d.ts
CHANGED
|
@@ -62,6 +62,7 @@ export declare const getMyOrgHandler: import("h3").EventHandlerWithFetch<import(
|
|
|
62
62
|
workspaceAppDefaultVisibility: WorkspaceAppDefaultVisibility;
|
|
63
63
|
signInMethods: import("./sign-in-methods.js").OrgSignInMethods;
|
|
64
64
|
a2aSecretSet: boolean;
|
|
65
|
+
a2aMemberDelegationEnabled: boolean;
|
|
65
66
|
soloDeploymentAdmin: boolean;
|
|
66
67
|
}>>;
|
|
67
68
|
export declare const retryPendingFederatedRemovalHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
@@ -175,6 +176,9 @@ export declare const setRequiredAuthProviderHandler: import("h3").EventHandlerWi
|
|
|
175
176
|
revokedLegacySessions: number;
|
|
176
177
|
provider: RequiredAuthProvider;
|
|
177
178
|
}>>;
|
|
179
|
+
export declare const setA2AMemberDelegationHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
180
|
+
enabled: any;
|
|
181
|
+
}>>;
|
|
178
182
|
export declare const revealA2ASecretHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
179
183
|
a2aSecret: string;
|
|
180
184
|
}>>;
|
package/dist/org/handlers.js
CHANGED
|
@@ -35,6 +35,8 @@ import { getAppProductionUrl, resolveAppRuntimeUrl, } from "../server/app-url.js
|
|
|
35
35
|
import { isTrustedSelfHostedRuntime, resolveVercelDeploymentProtectionHeaders, } from "../server/credential-provider.js";
|
|
36
36
|
import { sendEmail, isEmailConfigured } from "../server/email.js";
|
|
37
37
|
import { readBody } from "../server/h3-helpers.js";
|
|
38
|
+
import { effectiveOrgMemberRole } from "../server/personal-provider-key-policy.js";
|
|
39
|
+
import { getRequestContext } from "../server/request-context.js";
|
|
38
40
|
import { resolveDeploymentSignInMethods } from "../server/social-sign-in-providers.js";
|
|
39
41
|
import { getOrgSetting, putOrgSetting } from "../settings/org-settings.js";
|
|
40
42
|
import { isEmailDerivedName } from "../user-profile/shared.js";
|
|
@@ -140,37 +142,82 @@ async function getSessionForEvent(event) {
|
|
|
140
142
|
}
|
|
141
143
|
export const getMyOrgHandler = defineEventHandler(async (event) => {
|
|
142
144
|
const ctx = await getOrgContext(event);
|
|
145
|
+
const requestContext = getRequestContext();
|
|
146
|
+
const delegatedOrgMember = requestContext?.a2aIdentityAssurance === "org-member";
|
|
147
|
+
const delegatedEmail = requestContext?.userEmail?.trim().toLowerCase();
|
|
148
|
+
const delegatedOrgId = delegatedOrgMember
|
|
149
|
+
? requestContext.orgId?.trim()
|
|
150
|
+
: undefined;
|
|
151
|
+
const scopedDelegatedOrgId = delegatedEmail &&
|
|
152
|
+
delegatedEmail === ctx.email.trim().toLowerCase() &&
|
|
153
|
+
delegatedOrgId &&
|
|
154
|
+
ctx.orgId === delegatedOrgId
|
|
155
|
+
? delegatedOrgId
|
|
156
|
+
: null;
|
|
157
|
+
const visibleOrgId = delegatedOrgMember ? scopedDelegatedOrgId : ctx.orgId;
|
|
158
|
+
const visibleOrgName = visibleOrgId ? ctx.orgName : null;
|
|
159
|
+
const visibleRole = delegatedOrgMember
|
|
160
|
+
? visibleOrgId
|
|
161
|
+
? "member"
|
|
162
|
+
: null
|
|
163
|
+
: ctx.role;
|
|
143
164
|
const e = await exec();
|
|
144
|
-
const allOrgsRes =
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
const allOrgsRes = delegatedOrgMember
|
|
166
|
+
? scopedDelegatedOrgId
|
|
167
|
+
? await e.execute({
|
|
168
|
+
sql: `SELECT m.org_id AS "orgId", m.role AS role, o.name AS "orgName",
|
|
169
|
+
o.icon_json AS "iconJson", o.icon_revision AS "iconRevision"
|
|
170
|
+
FROM org_members m
|
|
171
|
+
INNER JOIN organizations o ON m.org_id = o.id
|
|
172
|
+
WHERE LOWER(m.email) = ? AND m.org_id = ?
|
|
173
|
+
AND m.federation_removal_pending_at IS NULL`,
|
|
174
|
+
args: [ctx.email.toLowerCase(), scopedDelegatedOrgId],
|
|
175
|
+
})
|
|
176
|
+
: { rows: [] }
|
|
177
|
+
: await e.execute({
|
|
178
|
+
sql: `SELECT m.org_id AS "orgId", m.role AS role, o.name AS "orgName",
|
|
179
|
+
o.icon_json AS "iconJson", o.icon_revision AS "iconRevision"
|
|
180
|
+
FROM org_members m
|
|
181
|
+
INNER JOIN organizations o ON m.org_id = o.id
|
|
182
|
+
WHERE LOWER(m.email) = ?
|
|
183
|
+
AND m.federation_removal_pending_at IS NULL`,
|
|
184
|
+
args: [ctx.email.toLowerCase()],
|
|
185
|
+
});
|
|
186
|
+
const orgs = allOrgsRes.rows.flatMap((r) => {
|
|
187
|
+
const orgId = String(r.orgId ?? r.org_id);
|
|
188
|
+
const role = delegatedOrgMember
|
|
189
|
+
? effectiveOrgMemberRole(r.role, orgId, ctx.email)
|
|
190
|
+
: String(r.role);
|
|
191
|
+
return role
|
|
192
|
+
? [
|
|
193
|
+
{
|
|
194
|
+
orgId,
|
|
195
|
+
role,
|
|
196
|
+
orgName: String(r.orgName ?? r.org_name),
|
|
197
|
+
icon: parseOrganizationIconJson(r.iconJson ?? r.icon_json),
|
|
198
|
+
iconRevision: Number(r.iconRevision ?? r.icon_revision ?? 0),
|
|
199
|
+
},
|
|
200
|
+
]
|
|
201
|
+
: [];
|
|
167
202
|
});
|
|
203
|
+
const pendingRemovalRes = delegatedOrgMember
|
|
204
|
+
? { rows: [] }
|
|
205
|
+
: await e.execute({
|
|
206
|
+
sql: `SELECT m.org_id AS "orgId", o.name AS "orgName"
|
|
207
|
+
FROM org_members m
|
|
208
|
+
INNER JOIN organizations o ON m.org_id = o.id
|
|
209
|
+
WHERE LOWER(m.email) = ?
|
|
210
|
+
AND m.federation_removal_pending_at IS NOT NULL`,
|
|
211
|
+
args: [ctx.email.toLowerCase()],
|
|
212
|
+
});
|
|
168
213
|
const pendingRemovals = pendingRemovalRes.rows.map((r) => ({
|
|
169
214
|
orgId: String(r.orgId ?? r.org_id),
|
|
170
215
|
orgName: String(r.orgName ?? r.org_name),
|
|
171
216
|
}));
|
|
172
217
|
let domainMatches = [];
|
|
173
|
-
const domain =
|
|
218
|
+
const domain = delegatedOrgMember
|
|
219
|
+
? undefined
|
|
220
|
+
: ctx.email.split("@")[1]?.toLowerCase();
|
|
174
221
|
if (domain) {
|
|
175
222
|
try {
|
|
176
223
|
const dmRes = await e.execute({
|
|
@@ -199,14 +246,16 @@ export const getMyOrgHandler = defineEventHandler(async (event) => {
|
|
|
199
246
|
let workspaceUrl = null;
|
|
200
247
|
let requiredAuthProvider = null;
|
|
201
248
|
let a2aSecretSet = false;
|
|
249
|
+
let a2aMemberDelegationEnabled = false;
|
|
202
250
|
let icon = null;
|
|
203
251
|
let iconRevision = 0;
|
|
204
|
-
if (
|
|
252
|
+
if (visibleOrgId) {
|
|
205
253
|
const adRes = await e.execute({
|
|
206
|
-
sql: `SELECT allowed_domain, a2a_secret,
|
|
254
|
+
sql: `SELECT allowed_domain, a2a_secret, a2a_member_delegation_enabled,
|
|
255
|
+
workspace_url, required_auth_provider,
|
|
207
256
|
icon_json, icon_revision
|
|
208
257
|
FROM organizations WHERE id = ? LIMIT 1`,
|
|
209
|
-
args: [
|
|
258
|
+
args: [visibleOrgId],
|
|
210
259
|
});
|
|
211
260
|
if (adRes.rows[0]) {
|
|
212
261
|
allowedDomain =
|
|
@@ -214,35 +263,49 @@ export const getMyOrgHandler = defineEventHandler(async (event) => {
|
|
|
214
263
|
workspaceUrl = String(adRes.rows[0].workspace_url ?? "") || null;
|
|
215
264
|
requiredAuthProvider = parseRequiredAuthProvider(adRes.rows[0].required_auth_provider ?? null);
|
|
216
265
|
a2aSecretSet = Boolean(String(adRes.rows[0].a2a_secret ?? "").trim());
|
|
266
|
+
a2aMemberDelegationEnabled =
|
|
267
|
+
adRes.rows[0].a2a_member_delegation_enabled === true;
|
|
217
268
|
icon = parseOrganizationIconJson(adRes.rows[0].icon_json);
|
|
218
269
|
iconRevision = Number(adRes.rows[0].icon_revision ?? 0);
|
|
219
270
|
}
|
|
220
271
|
}
|
|
221
|
-
const isOwnerOrAdmin =
|
|
272
|
+
const isOwnerOrAdmin = visibleRole === "owner" || visibleRole === "admin";
|
|
222
273
|
let workspaceAppDefaultVisibility = "org";
|
|
223
|
-
if (
|
|
224
|
-
const setting = await getOrgSetting(
|
|
274
|
+
if (visibleOrgId) {
|
|
275
|
+
const setting = await getOrgSetting(visibleOrgId, WORKSPACE_APP_DEFAULT_VISIBILITY_KEY);
|
|
225
276
|
workspaceAppDefaultVisibility = normalizeWorkspaceAppDefaultVisibility(setting?.visibility);
|
|
226
277
|
}
|
|
227
|
-
const invitesRes =
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
278
|
+
const invitesRes = delegatedOrgMember
|
|
279
|
+
? scopedDelegatedOrgId
|
|
280
|
+
? await e.execute({
|
|
281
|
+
sql: `SELECT i.id AS id, i.org_id AS "orgId", o.name AS "orgName", i.invited_by AS "invitedBy"
|
|
282
|
+
FROM org_invitations i
|
|
283
|
+
INNER JOIN organizations o ON i.org_id = o.id
|
|
284
|
+
WHERE LOWER(i.email) = ? AND i.org_id = ? AND i.status = 'pending'`,
|
|
285
|
+
args: [ctx.email.toLowerCase(), scopedDelegatedOrgId],
|
|
286
|
+
})
|
|
287
|
+
: { rows: [] }
|
|
288
|
+
: await e.execute({
|
|
289
|
+
sql: `SELECT i.id AS id, i.org_id AS "orgId", o.name AS "orgName", i.invited_by AS "invitedBy"
|
|
290
|
+
FROM org_invitations i
|
|
291
|
+
INNER JOIN organizations o ON i.org_id = o.id
|
|
292
|
+
WHERE LOWER(i.email) = ? AND i.status = 'pending'`,
|
|
293
|
+
args: [ctx.email.toLowerCase()],
|
|
294
|
+
});
|
|
234
295
|
const pendingInvitations = invitesRes.rows.map((r) => ({
|
|
235
296
|
id: String(r.id),
|
|
236
297
|
orgId: String(r.orgId ?? r.org_id),
|
|
237
298
|
orgName: String(r.orgName ?? r.org_name),
|
|
238
299
|
invitedBy: String(r.invitedBy ?? r.invited_by),
|
|
239
300
|
}));
|
|
240
|
-
|
|
301
|
+
if (!delegatedOrgMember) {
|
|
302
|
+
scheduleFederatedOrgSync(event, { ...ctx, icon, iconRevision });
|
|
303
|
+
}
|
|
241
304
|
return {
|
|
242
|
-
email: ctx.email,
|
|
243
|
-
orgId:
|
|
244
|
-
orgName:
|
|
245
|
-
role:
|
|
305
|
+
email: delegatedOrgMember ? (delegatedEmail ?? "") : ctx.email,
|
|
306
|
+
orgId: visibleOrgId,
|
|
307
|
+
orgName: visibleOrgName,
|
|
308
|
+
role: visibleRole,
|
|
246
309
|
icon,
|
|
247
310
|
iconRevision,
|
|
248
311
|
emailConfigured: await isEmailConfigured(),
|
|
@@ -268,8 +331,13 @@ export const getMyOrgHandler = defineEventHandler(async (event) => {
|
|
|
268
331
|
// so the value would sit in JSON any script on the page can read, and it
|
|
269
332
|
// signs the JWTs peers accept as first-party callers. Reveal is an explicit
|
|
270
333
|
// owner GET on /_agent-native/org/a2a-secret.
|
|
271
|
-
a2aSecretSet: canManageOrgA2ASecret(
|
|
272
|
-
|
|
334
|
+
a2aSecretSet: canManageOrgA2ASecret(visibleRole) ? a2aSecretSet : undefined,
|
|
335
|
+
a2aMemberDelegationEnabled: visibleRole === "owner" ? a2aMemberDelegationEnabled : undefined,
|
|
336
|
+
soloDeploymentAdmin: delegatedOrgMember
|
|
337
|
+
? undefined
|
|
338
|
+
: visibleOrgId
|
|
339
|
+
? undefined
|
|
340
|
+
: isTrustedSelfHostedRuntime(),
|
|
273
341
|
};
|
|
274
342
|
});
|
|
275
343
|
export const retryPendingFederatedRemovalHandler = defineEventHandler(async (event) => {
|
|
@@ -1558,6 +1626,33 @@ export const setRequiredAuthProviderHandler = defineEventHandler(async (event) =
|
|
|
1558
1626
|
const result = await setRequiredAuthProvider(ctx.orgId, provider);
|
|
1559
1627
|
return { provider, ...result };
|
|
1560
1628
|
});
|
|
1629
|
+
export const setA2AMemberDelegationHandler = defineEventHandler(async (event) => {
|
|
1630
|
+
const ctx = await getOrgContext(event);
|
|
1631
|
+
if (!ctx.orgId) {
|
|
1632
|
+
throw createError({ statusCode: 400, message: "No active organization" });
|
|
1633
|
+
}
|
|
1634
|
+
if (ctx.role !== "owner") {
|
|
1635
|
+
throw createError({
|
|
1636
|
+
statusCode: 403,
|
|
1637
|
+
message: "Only the organization owner can manage member delegation",
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
const body = await readBody(event);
|
|
1641
|
+
if (typeof body?.enabled !== "boolean") {
|
|
1642
|
+
throw createError({
|
|
1643
|
+
statusCode: 400,
|
|
1644
|
+
message: "enabled must be a boolean",
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
const e = await exec();
|
|
1648
|
+
await e.execute({
|
|
1649
|
+
sql: `UPDATE organizations
|
|
1650
|
+
SET a2a_member_delegation_enabled = ?
|
|
1651
|
+
WHERE id = ?`,
|
|
1652
|
+
args: [body.enabled, ctx.orgId],
|
|
1653
|
+
});
|
|
1654
|
+
return { enabled: body.enabled };
|
|
1655
|
+
});
|
|
1561
1656
|
export const revealA2ASecretHandler = defineEventHandler(async (event) => {
|
|
1562
1657
|
const ctx = await getOrgContext(event);
|
|
1563
1658
|
if (!ctx.orgId) {
|
|
@@ -1886,6 +1981,7 @@ export const receiveA2ASecretHandler = defineEventHandler(async (event) => {
|
|
|
1886
1981
|
verified = null;
|
|
1887
1982
|
}
|
|
1888
1983
|
if (!verified ||
|
|
1984
|
+
verified.identityAssurance !== "organization" ||
|
|
1889
1985
|
verified.orgId !== localOrgId ||
|
|
1890
1986
|
verified.orgDomain?.trim().toLowerCase() !== orgDomain) {
|
|
1891
1987
|
throw createError({
|
package/dist/org/index.d.ts
CHANGED
|
@@ -159,13 +159,14 @@ export declare const getMyOrgHandler: import("h3").EventHandlerWithFetch<import(
|
|
|
159
159
|
workspaceAppDefaultVisibility: import("./types.js").WorkspaceAppDefaultVisibility;
|
|
160
160
|
signInMethods: import("./sign-in-methods.js").OrgSignInMethods;
|
|
161
161
|
a2aSecretSet: boolean;
|
|
162
|
+
a2aMemberDelegationEnabled: boolean;
|
|
162
163
|
soloDeploymentAdmin: boolean;
|
|
163
164
|
}>>;
|
|
164
165
|
export declare const createOrgHandler: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
165
166
|
success: boolean;
|
|
167
|
+
id?: undefined;
|
|
166
168
|
name?: undefined;
|
|
167
169
|
role?: undefined;
|
|
168
|
-
id?: undefined;
|
|
169
170
|
} | {
|
|
170
171
|
success?: undefined;
|
|
171
172
|
id: string;
|
package/dist/org/membership.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import type { H3Event } from "h3";
|
|
1
2
|
export declare function isMissingOrganizationTableError(error: unknown): boolean;
|
|
2
3
|
export declare function isOrgMember(orgId: string, email: string, options?: {
|
|
3
4
|
requireOrganizationMetadata?: boolean;
|
|
5
|
+
requestEvent?: H3Event;
|
|
4
6
|
}): Promise<boolean>;
|
|
5
7
|
/**
|
|
6
|
-
* Checks
|
|
7
|
-
*
|
|
8
|
-
*
|
|
8
|
+
* Checks the live roster for an opted-in org-member A2A assertion. This proves
|
|
9
|
+
* membership in the asserted org; authorization still caps the identity at
|
|
10
|
+
* member regardless of the stored owner/admin role.
|
|
9
11
|
*/
|
|
10
|
-
export declare function isOrgMemberForA2A(orgId: string, email: string): Promise<boolean>;
|
|
12
|
+
export declare function isOrgMemberForA2A(orgId: string, email: string, requestEvent?: H3Event): Promise<boolean>;
|
package/dist/org/membership.js
CHANGED
|
@@ -65,23 +65,25 @@ async function isOrgMemberWithPolicy(orgId, email, options) {
|
|
|
65
65
|
const validation = await validateFederatedOrganizationMembershipForCurrentRequest({
|
|
66
66
|
orgId,
|
|
67
67
|
email: normalized,
|
|
68
|
-
});
|
|
68
|
+
}, options.requestEvent);
|
|
69
69
|
return validation.active;
|
|
70
70
|
}
|
|
71
71
|
export function isOrgMember(orgId, email, options = {}) {
|
|
72
72
|
return isOrgMemberWithPolicy(orgId, email, {
|
|
73
73
|
allowMissingOrganizationTable: !options.requireOrganizationMetadata,
|
|
74
74
|
requireOrganizationRecord: !!options.requireOrganizationMetadata,
|
|
75
|
+
requestEvent: options.requestEvent,
|
|
75
76
|
});
|
|
76
77
|
}
|
|
77
78
|
/**
|
|
78
|
-
* Checks
|
|
79
|
-
*
|
|
80
|
-
*
|
|
79
|
+
* Checks the live roster for an opted-in org-member A2A assertion. This proves
|
|
80
|
+
* membership in the asserted org; authorization still caps the identity at
|
|
81
|
+
* member regardless of the stored owner/admin role.
|
|
81
82
|
*/
|
|
82
|
-
export function isOrgMemberForA2A(orgId, email) {
|
|
83
|
+
export function isOrgMemberForA2A(orgId, email, requestEvent) {
|
|
83
84
|
return isOrgMemberWithPolicy(orgId, email, {
|
|
84
85
|
allowMissingOrganizationTable: false,
|
|
85
86
|
requireOrganizationRecord: true,
|
|
87
|
+
requestEvent,
|
|
86
88
|
});
|
|
87
89
|
}
|
package/dist/org/migrations.js
CHANGED
|
@@ -284,4 +284,10 @@ export const ORG_MIGRATIONS = [
|
|
|
284
284
|
ON private_icon_assets (owner_email, org_id, created_at);
|
|
285
285
|
`,
|
|
286
286
|
},
|
|
287
|
+
{
|
|
288
|
+
version: 1035,
|
|
289
|
+
name: "organization-a2a-member-delegation",
|
|
290
|
+
sql: `ALTER TABLE organizations
|
|
291
|
+
ADD COLUMN IF NOT EXISTS a2a_member_delegation_enabled BOOLEAN NOT NULL DEFAULT FALSE`,
|
|
292
|
+
},
|
|
287
293
|
];
|
package/dist/org/plugin.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ type NitroPluginDef = (nitroApp: any) => void | Promise<void>;
|
|
|
24
24
|
* PUT /_agent-native/org/domain — set/clear allowed email domain (owner/admin)
|
|
25
25
|
* PUT /_agent-native/org/workspace-url — set/clear the org's workspace origin (owner/admin)
|
|
26
26
|
* PUT /_agent-native/org/auth-provider — require/clear Google sign-in (owner/admin)
|
|
27
|
+
* PUT /_agent-native/org/a2a-member-delegation — allow org-member A2A assertions (owner only)
|
|
27
28
|
* PUT /_agent-native/org/visual-identity — set/clear workspace icon (owner/admin)
|
|
28
29
|
* GET /_agent-native/org/a2a-secret — reveal A2A secret on demand (owner/admin)
|
|
29
30
|
* PUT /_agent-native/org/a2a-secret — regenerate or set A2A secret (owner/admin)
|
package/dist/org/plugin.js
CHANGED
|
@@ -4,7 +4,7 @@ import { awaitBootstrap, getH3App, FRAMEWORK_PREFIX, markDefaultPluginProvided,
|
|
|
4
4
|
import { listAppRolesHandler, setAppRoleHandler, getAppPermissionsHandler, setAppPermissionsHandler, resetAppPermissionHandler, } from "./app-roles-handlers.js";
|
|
5
5
|
import { listSSOProvidersHandler, createSSOProviderHandler, verifySSOProviderHandler, deleteSSOProviderHandler, getSCIMHandler, createSCIMHandler, deleteSCIMHandler, } from "./enterprise-auth-handlers.js";
|
|
6
6
|
import { CROSS_APP_ORG_FEDERATION_FLAG } from "./feature-flags.js";
|
|
7
|
-
import { getMyOrgHandler, createOrgHandler, updateOrgHandler, deleteOrgHandler, switchOrgHandler, listMembersHandler, removeMemberHandler, retryPendingFederatedRemovalHandler, changeMemberRoleHandler, listInvitationsHandler, createInvitationHandler, acceptInvitationHandler, joinByDomainHandler, setDomainHandler, setWorkspaceUrlHandler, setRequiredAuthProviderHandler, revealA2ASecretHandler, setA2ASecretHandler, syncA2ASecretHandler, receiveA2ASecretHandler, setWorkspaceAppDefaultVisibilityHandler, setOrgVisualIdentityHandler, } from "./handlers.js";
|
|
7
|
+
import { getMyOrgHandler, createOrgHandler, updateOrgHandler, deleteOrgHandler, switchOrgHandler, listMembersHandler, removeMemberHandler, retryPendingFederatedRemovalHandler, changeMemberRoleHandler, listInvitationsHandler, createInvitationHandler, acceptInvitationHandler, joinByDomainHandler, setDomainHandler, setWorkspaceUrlHandler, setRequiredAuthProviderHandler, setA2AMemberDelegationHandler, revealA2ASecretHandler, setA2ASecretHandler, syncA2ASecretHandler, receiveA2ASecretHandler, setWorkspaceAppDefaultVisibilityHandler, setOrgVisualIdentityHandler, } from "./handlers.js";
|
|
8
8
|
import { readWorkspacePrivateIconHandler, uploadWorkspacePrivateIconHandler, } from "./private-icon-handlers.js";
|
|
9
9
|
import { orgStore } from "./schema-store.js";
|
|
10
10
|
const ORG_PREFIX = `${FRAMEWORK_PREFIX}/org`;
|
|
@@ -56,6 +56,7 @@ async function workspaceIconUploadResponse(event) {
|
|
|
56
56
|
* PUT /_agent-native/org/domain — set/clear allowed email domain (owner/admin)
|
|
57
57
|
* PUT /_agent-native/org/workspace-url — set/clear the org's workspace origin (owner/admin)
|
|
58
58
|
* PUT /_agent-native/org/auth-provider — require/clear Google sign-in (owner/admin)
|
|
59
|
+
* PUT /_agent-native/org/a2a-member-delegation — allow org-member A2A assertions (owner only)
|
|
59
60
|
* PUT /_agent-native/org/visual-identity — set/clear workspace icon (owner/admin)
|
|
60
61
|
* GET /_agent-native/org/a2a-secret — reveal A2A secret on demand (owner/admin)
|
|
61
62
|
* PUT /_agent-native/org/a2a-secret — regenerate or set A2A secret (owner/admin)
|
|
@@ -205,6 +206,13 @@ export function createOrgPlugin() {
|
|
|
205
206
|
}
|
|
206
207
|
return retryPendingFederatedRemovalHandler(event);
|
|
207
208
|
}));
|
|
209
|
+
app.use(`${ORG_PREFIX}/a2a-member-delegation`, defineEventHandler(async (event) => {
|
|
210
|
+
if (getMethod(event) !== "PUT") {
|
|
211
|
+
setResponseStatus(event, 405);
|
|
212
|
+
return { error: "Method not allowed" };
|
|
213
|
+
}
|
|
214
|
+
return setA2AMemberDelegationHandler(event);
|
|
215
|
+
}));
|
|
208
216
|
app.use(`${ORG_PREFIX}/workspace-app-default-visibility`, defineEventHandler(async (event) => {
|
|
209
217
|
if (getMethod(event) !== "PUT") {
|
|
210
218
|
setResponseStatus(event, 405);
|
|
@@ -3,6 +3,7 @@ import { getDbExec } from "../db/client.js";
|
|
|
3
3
|
import { getIconAsset, IconUploadBodyError, putIconAsset, readIconUploadFormData, readIconAssetForAuthorizedReference, } from "../icon-assets/index.js";
|
|
4
4
|
import { readFederatedWorkspaceIcon, uploadFederatedWorkspaceIcon, verifyFederatedWorkspaceIconOwner, } from "../icon-assets/workspace-transport.js";
|
|
5
5
|
import { getSession } from "../server/auth.js";
|
|
6
|
+
import { readOrgMemberRole } from "../server/personal-provider-key-policy.js";
|
|
6
7
|
import { runWithRequestContext } from "../server/request-context.js";
|
|
7
8
|
import { getOrgContext } from "./context.js";
|
|
8
9
|
import { validateFederatedOrganizationMembership } from "./federation.js";
|
|
@@ -118,20 +119,13 @@ export const readWorkspacePrivateIconHandler = defineEventHandler(async (event)
|
|
|
118
119
|
});
|
|
119
120
|
}
|
|
120
121
|
const [, library, orgId, assetId] = match;
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
WHERE org_id = ? AND LOWER(email) = ?
|
|
124
|
-
AND federation_removal_pending_at IS NULL LIMIT 1`,
|
|
125
|
-
args: [orgId, session.email.toLowerCase()],
|
|
126
|
-
});
|
|
127
|
-
if (!membership.rows.length)
|
|
122
|
+
const role = await readOrgMemberRole(orgId, session.email);
|
|
123
|
+
if (!role)
|
|
128
124
|
throw createError({
|
|
129
125
|
statusCode: 404,
|
|
130
126
|
message: "Workspace icon not found",
|
|
131
127
|
});
|
|
132
|
-
if (library &&
|
|
133
|
-
membership.rows[0]?.role !== "owner" &&
|
|
134
|
-
membership.rows[0]?.role !== "admin") {
|
|
128
|
+
if (library && role !== "owner" && role !== "admin") {
|
|
135
129
|
throw createError({
|
|
136
130
|
statusCode: 404,
|
|
137
131
|
message: "Workspace icon not found",
|
package/dist/org/types.d.ts
CHANGED
|
@@ -63,6 +63,8 @@ export interface OrgInfo {
|
|
|
63
63
|
* fetches it on demand from `GET /_agent-native/org/a2a-secret`.
|
|
64
64
|
*/
|
|
65
65
|
a2aSecretSet?: boolean;
|
|
66
|
+
/** Owners only; enables current-member assertions signed with the org secret. */
|
|
67
|
+
a2aMemberDelegationEnabled?: boolean;
|
|
66
68
|
/**
|
|
67
69
|
* Set only when the viewer has no active organization. True on a
|
|
68
70
|
* single-tenant self-hosted deployment, where that viewer manages the
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { createHmac, randomUUID } from "node:crypto";
|
|
2
2
|
import { canonicalA2AAudience } from "../a2a/audience.js";
|
|
3
3
|
import { isLoopbackAddress } from "../a2a/auth-policy.js";
|
|
4
|
-
import { signA2AToken } from "../a2a/client.js";
|
|
4
|
+
import { signA2AOrgMemberDelegationToken, signA2AToken, } from "../a2a/client.js";
|
|
5
5
|
import { getAppConfig } from "../app-config/index.js";
|
|
6
6
|
import { getDbExec } from "../db/client.js";
|
|
7
7
|
import { readDeployCredentialEnv } from "../server/credential-provider.js";
|
|
8
8
|
import { isHostedWorkspaceRuntime, resolveVercelDeploymentProtectionHeaders, } from "../server/deployment-protection.js";
|
|
9
|
+
import { effectiveOrgMemberRole } from "../server/personal-provider-key-policy.js";
|
|
10
|
+
import { getRequestContext } from "../server/request-context.js";
|
|
9
11
|
import { workspaceUserGroupsIncludeUser } from "../workspace-connections/groups.js";
|
|
10
12
|
import { isMissingOrganizationTableError } from "./membership.js";
|
|
11
13
|
import { getCachedWorkspaceAccess, invalidateMemberOrgCaches, rememberWorkspaceAccess, workspaceAccessGenerationNow, } from "./request-org-cache.js";
|
|
@@ -239,25 +241,54 @@ async function resolveHostedWorkspaceAppAuth(configuredDirectory, context, email
|
|
|
239
241
|
const orgSecret = orgId
|
|
240
242
|
? (await cachedOrgA2ASecret(orgId))?.trim() || undefined
|
|
241
243
|
: undefined;
|
|
242
|
-
const
|
|
244
|
+
const deploymentSecret = readDeployCredentialEnv("A2A_SECRET")?.trim();
|
|
245
|
+
const signingSecret = orgSecret || deploymentSecret;
|
|
243
246
|
if (!signingSecret) {
|
|
244
247
|
return workspaceAppAccessUnavailable("a2a-secret-missing", { audience });
|
|
245
248
|
}
|
|
246
249
|
stage = "token-signing-failed";
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
250
|
+
const requestContext = getRequestContext();
|
|
251
|
+
let token;
|
|
252
|
+
if (requestContext?.a2aIdentityAssurance === "org-member") {
|
|
253
|
+
if (!orgId ||
|
|
254
|
+
!normalizedOrgDomain ||
|
|
255
|
+
requestContext.orgId?.trim() !== orgId ||
|
|
256
|
+
requestContext.userEmail?.trim().toLowerCase() !== email) {
|
|
257
|
+
return workspaceAppAccessUnavailable("token-signing-failed", {
|
|
258
|
+
audience,
|
|
259
|
+
detail: "Delegated member identity is missing or out of scope.",
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
if (!orgSecret) {
|
|
263
|
+
return workspaceAppAccessUnavailable("a2a-secret-missing", {
|
|
264
|
+
audience,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
if (orgSecret === deploymentSecret) {
|
|
268
|
+
return workspaceAppAccessUnavailable("token-signing-failed", {
|
|
269
|
+
audience,
|
|
270
|
+
detail: "Organization and deployment A2A secrets must differ for delegated identity.",
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
token = await signA2AOrgMemberDelegationToken(email, normalizedOrgDomain, orgSecret, audience);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
token = await signA2AToken(email, normalizedOrgDomain, orgSecret, {
|
|
277
|
+
expiresIn: "1m",
|
|
278
|
+
preferGlobalSecret: false,
|
|
279
|
+
audience,
|
|
280
|
+
extraClaims: {
|
|
281
|
+
jti: randomUUID(),
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
}
|
|
255
285
|
const protectionHeaders = resolveVercelDeploymentProtectionHeaders(url.toString());
|
|
256
286
|
const requestKey = createHmac("sha256", signingSecret)
|
|
257
287
|
.update(JSON.stringify([
|
|
258
288
|
configuredDirectory,
|
|
259
289
|
email,
|
|
260
290
|
orgId,
|
|
291
|
+
requestContext?.a2aIdentityAssurance ?? "user",
|
|
261
292
|
normalizedOrgDomain ?? null,
|
|
262
293
|
getAppConfig().app.url ?? "http://localhost:3000",
|
|
263
294
|
protectionHeaders,
|
|
@@ -603,7 +634,13 @@ export async function claimWorkspaceAppForOrganization(appId, context) {
|
|
|
603
634
|
if (!member || !(await isActiveWorkspaceOrgMember(member, orgId, email))) {
|
|
604
635
|
return false;
|
|
605
636
|
}
|
|
606
|
-
|
|
637
|
+
const role = effectiveOrgMemberRole(member.role, orgId, email);
|
|
638
|
+
return role
|
|
639
|
+
? claimWorkspaceAppOrganization(db, normalizedAppId, orgId, {
|
|
640
|
+
...member,
|
|
641
|
+
role,
|
|
642
|
+
})
|
|
643
|
+
: false;
|
|
607
644
|
}
|
|
608
645
|
catch (error) {
|
|
609
646
|
console.error("[workspace-app-access] organization claim failed", error);
|
|
@@ -667,7 +704,13 @@ export async function checkWorkspaceAppAccess(appId, context) {
|
|
|
667
704
|
!(await isActiveWorkspaceOrgMember(member, orgId, email))) {
|
|
668
705
|
return false;
|
|
669
706
|
}
|
|
670
|
-
|
|
707
|
+
const role = effectiveOrgMemberRole(member.role, orgId, email);
|
|
708
|
+
return role
|
|
709
|
+
? claimWorkspaceAppOrganization(db, normalizedAppId, orgId, {
|
|
710
|
+
...member,
|
|
711
|
+
role,
|
|
712
|
+
})
|
|
713
|
+
: false;
|
|
671
714
|
}
|
|
672
715
|
const ownerEmail = normalizedEmail(typeof app.owner_email === "string" ? app.owner_email : "");
|
|
673
716
|
const resourceOrgId = (typeof app.org_id === "string" ? app.org_id : "").trim() || null;
|
|
@@ -688,9 +731,14 @@ export async function checkWorkspaceAppAccess(appId, context) {
|
|
|
688
731
|
if (!member || !(await isActiveWorkspaceOrgMember(member, orgId, email))) {
|
|
689
732
|
return false;
|
|
690
733
|
}
|
|
691
|
-
const memberRole = member.role;
|
|
734
|
+
const memberRole = effectiveOrgMemberRole(member.role, orgId, email);
|
|
735
|
+
if (!memberRole)
|
|
736
|
+
return false;
|
|
692
737
|
if (canClaimCallerOrg) {
|
|
693
|
-
if (!(await claimWorkspaceAppOrganization(db, normalizedAppId, orgId,
|
|
738
|
+
if (!(await claimWorkspaceAppOrganization(db, normalizedAppId, orgId, {
|
|
739
|
+
...member,
|
|
740
|
+
role: memberRole,
|
|
741
|
+
}))) {
|
|
694
742
|
return false;
|
|
695
743
|
}
|
|
696
744
|
}
|
|
@@ -75,7 +75,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
|
|
78
|
+
message?: undefined;
|
|
79
|
+
found?: undefined;
|
|
79
80
|
providers: {
|
|
80
81
|
id: string;
|
|
81
82
|
label: string;
|
|
@@ -86,13 +87,13 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
86
87
|
updatedAt: number;
|
|
87
88
|
}[];
|
|
88
89
|
count: number;
|
|
89
|
-
|
|
90
|
+
provider?: undefined;
|
|
90
91
|
deleted?: undefined;
|
|
91
92
|
registered?: undefined;
|
|
92
93
|
id?: undefined;
|
|
93
94
|
label?: undefined;
|
|
94
|
-
message?: undefined;
|
|
95
95
|
} | {
|
|
96
|
+
message?: undefined;
|
|
96
97
|
providers?: undefined;
|
|
97
98
|
count?: undefined;
|
|
98
99
|
found: boolean;
|
|
@@ -101,32 +102,31 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
101
102
|
registered?: undefined;
|
|
102
103
|
id?: undefined;
|
|
103
104
|
label?: undefined;
|
|
104
|
-
message?: undefined;
|
|
105
105
|
} | {
|
|
106
|
-
|
|
106
|
+
message?: undefined;
|
|
107
107
|
providers?: undefined;
|
|
108
108
|
count?: undefined;
|
|
109
|
+
provider?: undefined;
|
|
109
110
|
found: boolean;
|
|
110
111
|
id: string;
|
|
111
112
|
deleted?: undefined;
|
|
112
113
|
registered?: undefined;
|
|
113
114
|
label?: undefined;
|
|
114
|
-
message?: undefined;
|
|
115
115
|
} | {
|
|
116
|
-
|
|
116
|
+
message?: undefined;
|
|
117
|
+
found?: undefined;
|
|
117
118
|
providers?: undefined;
|
|
118
119
|
count?: undefined;
|
|
119
|
-
|
|
120
|
+
provider?: undefined;
|
|
120
121
|
deleted: boolean;
|
|
121
122
|
id: string;
|
|
122
123
|
registered?: undefined;
|
|
123
124
|
label?: undefined;
|
|
124
|
-
message?: undefined;
|
|
125
125
|
} | {
|
|
126
|
-
|
|
126
|
+
found?: undefined;
|
|
127
127
|
providers?: undefined;
|
|
128
128
|
count?: undefined;
|
|
129
|
-
|
|
129
|
+
provider?: undefined;
|
|
130
130
|
deleted?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|