@agent-native/core 0.212.0 → 0.213.1
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/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/collab/awareness.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/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/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/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +6 -6
- 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 +142 -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-outcome.d.ts +1 -1
- package/dist/org/workspace-app-access.js +77 -14
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +3 -3
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +10 -10
- package/dist/server/action-routes.d.ts +1 -0
- package/dist/server/action-routes.js +13 -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-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/sharing/actions/list-resource-shares.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +16 -13
- package/dist/triggers/actions/manage-automation.d.ts +5 -5
- 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
|
@@ -6,6 +6,7 @@ import { deleteAutomationRunsWithDb, ensureAutomationRunHistoryReady, prepareAut
|
|
|
6
6
|
import { applyJobResourceEdit } from "../jobs/update-job-resource.js";
|
|
7
7
|
import { resolveUserSchedulingTimezone } from "../localization/user-timezone.js";
|
|
8
8
|
import { organizationIdFromResourceOwner, organizationResourceOwner, ensureResourceStoreReady, prepareResourceBatchAssertion, prepareResourceCreate, prepareResourceDelete, prepareResourceUpdate, resourceGetByPath, resourceList, resourcePutWithDb, resourceDelete, SHARED_OWNER, } from "../resources/store.js";
|
|
9
|
+
import { readOrgMemberRole } from "../server/personal-provider-key-policy.js";
|
|
9
10
|
import { isReasoningEffort, } from "../shared/reasoning-effort.js";
|
|
10
11
|
import { deleteAutomationWebhookToken, readAutomationWebhookPath, saveAutomationWebhookToken, } from "../triggers/webhook-store.js";
|
|
11
12
|
import { createAutomationWebhookToken, automationWebhookPath, } from "../triggers/webhook.js";
|
|
@@ -61,16 +62,8 @@ function ownerForScope(actor, scope) {
|
|
|
61
62
|
return organizationResourceOwner(actor.orgId);
|
|
62
63
|
}
|
|
63
64
|
async function readOrganizationMembership(orgId, email) {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
WHERE org_id = ? AND LOWER(email) = ?
|
|
67
|
-
AND federation_removal_pending_at IS NULL
|
|
68
|
-
LIMIT 1`,
|
|
69
|
-
args: [orgId, email.toLowerCase()],
|
|
70
|
-
});
|
|
71
|
-
if (!result.rows.length)
|
|
72
|
-
return null;
|
|
73
|
-
return { role: String(result.rows[0]?.role ?? "").toLowerCase() };
|
|
65
|
+
const role = await readOrgMemberRole(orgId, email);
|
|
66
|
+
return role ? { role } : null;
|
|
74
67
|
}
|
|
75
68
|
async function requireOrganizationMembership(actor) {
|
|
76
69
|
if (!actor.orgId) {
|
|
@@ -235,6 +235,9 @@ export declare function useSetA2ASecret(): import("@tanstack/react-query").UseMu
|
|
|
235
235
|
a2aSecret: string;
|
|
236
236
|
previousSecret: string | null;
|
|
237
237
|
}, Error, string | undefined, unknown>;
|
|
238
|
+
export declare function useSetA2AMemberDelegation(): import("@tanstack/react-query").UseMutationResult<{
|
|
239
|
+
enabled: boolean;
|
|
240
|
+
}, Error, boolean, unknown>;
|
|
238
241
|
export interface SyncA2ASecretResult {
|
|
239
242
|
total: number;
|
|
240
243
|
succeeded: number;
|
package/dist/client/org/hooks.js
CHANGED
|
@@ -486,6 +486,18 @@ export function useSetA2ASecret() {
|
|
|
486
486
|
},
|
|
487
487
|
});
|
|
488
488
|
}
|
|
489
|
+
export function useSetA2AMemberDelegation() {
|
|
490
|
+
const qc = useQueryClient();
|
|
491
|
+
return useMutation({
|
|
492
|
+
mutationFn: (enabled) => apiFetch(`${orgBasePath()}/a2a-member-delegation`, {
|
|
493
|
+
method: "PUT",
|
|
494
|
+
body: JSON.stringify({ enabled }),
|
|
495
|
+
}),
|
|
496
|
+
onSuccess: async () => {
|
|
497
|
+
await qc.invalidateQueries({ queryKey: ["org-me"] });
|
|
498
|
+
},
|
|
499
|
+
});
|
|
500
|
+
}
|
|
489
501
|
export function useSyncA2ASecret() {
|
|
490
502
|
return useMutation({
|
|
491
503
|
mutationFn: (vars) => apiFetch(`${orgBasePath()}/a2a-secret/sync`, {
|
|
@@ -38,19 +38,19 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
38
38
|
error: string;
|
|
39
39
|
states?: undefined;
|
|
40
40
|
} | {
|
|
41
|
-
error?: undefined;
|
|
42
41
|
states: {
|
|
43
42
|
clientId: number;
|
|
44
43
|
state: string;
|
|
45
44
|
}[];
|
|
45
|
+
error?: undefined;
|
|
46
46
|
}>>;
|
|
47
47
|
export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
48
48
|
error: string;
|
|
49
49
|
users?: undefined;
|
|
50
50
|
} | {
|
|
51
|
-
error?: undefined;
|
|
52
51
|
users: {
|
|
53
52
|
clientId: number;
|
|
54
53
|
lastSeen: number;
|
|
55
54
|
}[];
|
|
55
|
+
error?: undefined;
|
|
56
56
|
}>>;
|
|
@@ -65,7 +65,7 @@ export declare const WORKSPACE_CONNECTION_PROVIDERS: readonly [{
|
|
|
65
65
|
readonly scopes: readonly ["repo", "read:org", "read:user", "user:email"];
|
|
66
66
|
};
|
|
67
67
|
readonly capabilities: readonly ["search", "import", "code", "docs"];
|
|
68
|
-
readonly recommendedTemplateUses: readonly ["brain", "analytics", "dispatch", "factory"];
|
|
68
|
+
readonly recommendedTemplateUses: readonly ["brain", "analytics", "content", "dispatch", "factory"];
|
|
69
69
|
}, {
|
|
70
70
|
readonly id: "figma";
|
|
71
71
|
readonly label: "Figma";
|
|
@@ -59,7 +59,13 @@ export const WORKSPACE_CONNECTION_PROVIDERS = [
|
|
|
59
59
|
scopes: ["repo", "read:org", "read:user", "user:email"],
|
|
60
60
|
},
|
|
61
61
|
capabilities: ["search", "import", "code", "docs"],
|
|
62
|
-
recommendedTemplateUses: [
|
|
62
|
+
recommendedTemplateUses: [
|
|
63
|
+
"brain",
|
|
64
|
+
"analytics",
|
|
65
|
+
"content",
|
|
66
|
+
"dispatch",
|
|
67
|
+
"factory",
|
|
68
|
+
],
|
|
63
69
|
}),
|
|
64
70
|
defineWorkspaceConnectionProvider({
|
|
65
71
|
id: "figma",
|
|
@@ -5,6 +5,7 @@ import { deleteAppSecret, readAppSecret, } from "../secrets/storage.js";
|
|
|
5
5
|
import { assertCredentialStoreReadable } from "../server/credential-provider.js";
|
|
6
6
|
import { isPersonalCredentialScope, readsOrgCredentialFirst, } from "../server/credential-read-order.js";
|
|
7
7
|
import { isPersonalProviderKeyUseRestricted, isPersonalProviderPolicyKey, readOrgMemberRole, } from "../server/personal-provider-key-policy.js";
|
|
8
|
+
import { getRequestContext } from "../server/request-context.js";
|
|
8
9
|
import { getSetting, putSetting, deleteSetting } from "../settings/store.js";
|
|
9
10
|
const SETTING_PREFIX = "credential:";
|
|
10
11
|
export class CredentialEndpointMismatchError extends Error {
|
|
@@ -239,7 +240,20 @@ export async function resolveCredential(key, ctx) {
|
|
|
239
240
|
export async function describeCredentialScopeGap(keys, ctx) {
|
|
240
241
|
if (!ctx?.userEmail)
|
|
241
242
|
return null;
|
|
242
|
-
const
|
|
243
|
+
const requestContext = getRequestContext();
|
|
244
|
+
const isDelegatedOrgMember = requestContext?.a2aIdentityAssurance === "org-member";
|
|
245
|
+
const delegatedEmail = requestContext?.userEmail?.trim().toLowerCase();
|
|
246
|
+
const delegatedOrgId = requestContext?.orgId?.trim();
|
|
247
|
+
if (isDelegatedOrgMember &&
|
|
248
|
+
(!delegatedEmail ||
|
|
249
|
+
delegatedEmail !== ctx.userEmail.trim().toLowerCase() ||
|
|
250
|
+
!delegatedOrgId ||
|
|
251
|
+
(ctx.orgId && ctx.orgId.trim() !== delegatedOrgId))) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
const orgLookup = isDelegatedOrgMember
|
|
255
|
+
? { orgId: delegatedOrgId, lookupFailed: false }
|
|
256
|
+
: await resolveEffectiveOrgId(ctx);
|
|
243
257
|
if (orgLookup.lookupFailed || !orgLookup.orgId)
|
|
244
258
|
return null;
|
|
245
259
|
const scopedCtx = { ...ctx, orgId: orgLookup.orgId };
|
|
@@ -251,7 +265,9 @@ export async function describeCredentialScopeGap(keys, ctx) {
|
|
|
251
265
|
`integration, job, or automation — so it needs "${key}" saved with ` +
|
|
252
266
|
`Workspace or Organization scope instead.`);
|
|
253
267
|
}
|
|
254
|
-
const holder =
|
|
268
|
+
const holder = isDelegatedOrgMember
|
|
269
|
+
? null
|
|
270
|
+
: await findMemberOrgHoldingCredential(key, scopedCtx);
|
|
255
271
|
if (holder) {
|
|
256
272
|
return (`A "${key}" key is saved in the ${holder} organization, but this ` +
|
|
257
273
|
`request resolved to a different organization you also belong to. ` +
|
|
@@ -16,7 +16,7 @@ export const SCHEMA_SNAPSHOT = {
|
|
|
16
16
|
'CREATE TABLE "a2a_approvals" (\n "id" text NOT NULL,\n "task_id" text NOT NULL,\n "owner_email" text NOT NULL,\n "org_id" text,\n "tool_name" text NOT NULL,\n "tool_input" text NOT NULL,\n "approval_key" text NOT NULL,\n "call_id" text NOT NULL,\n "status" text DEFAULT \'pending\'::text NOT NULL,\n "result" text,\n "expires_at" bigint NOT NULL,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL\n);',
|
|
17
17
|
'CREATE TABLE "a2a_tasks" (\n "id" text NOT NULL,\n "context_id" text,\n "status_state" text DEFAULT \'submitted\'::text NOT NULL,\n "status_message" text,\n "status_timestamp" text NOT NULL,\n "history" text DEFAULT \'[]\'::text NOT NULL,\n "artifacts" text DEFAULT \'[]\'::text NOT NULL,\n "metadata" text,\n "owner_email" text,\n "owner_scope" text DEFAULT \'\'::text NOT NULL,\n "idempotency_key" text,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL\n);',
|
|
18
18
|
'CREATE TABLE "account" (\n "id" text NOT NULL,\n "account_id" text NOT NULL,\n "provider_id" text NOT NULL,\n "user_id" text NOT NULL,\n "access_token" text,\n "refresh_token" text,\n "id_token" text,\n "access_token_expires_at" timestamp with time zone,\n "refresh_token_expires_at" timestamp with time zone,\n "scope" text,\n "password" text,\n "created_at" timestamp with time zone NOT NULL,\n "updated_at" timestamp with time zone NOT NULL\n);',
|
|
19
|
-
'CREATE TABLE "agent_audit_log" (\n "id" text NOT NULL,\n "created_at" bigint NOT NULL,\n "action" text NOT NULL,\n "caller" text NOT NULL,\n "actor_kind" text NOT NULL,\n "actor_email" text,\n "org_id" text,\n "thread_id" text,\n "turn_id" text,\n "target_type" text,\n "target_id" text,\n "status" text DEFAULT \'success\'::text NOT NULL,\n "summary" text,\n "input" text,\n "error_code" text,\n "owner_email" text,\n "visibility" text DEFAULT \'private\'::text NOT NULL,\n "run_id" text,\n "task_id" text,\n "parent_task_id" text,\n "source_kind" text,\n "source_platform" text,\n "source_id" text,\n "source_url" text,\n "network_protocol" text,\n "network_id" text,\n "network_peer" text,\n "app" text,\n "reported_client_name" text,\n "reported_client_version" text,\n "oauth_client_id" text,\n "approval" text\n);',
|
|
19
|
+
'CREATE TABLE "agent_audit_log" (\n "id" text NOT NULL,\n "created_at" bigint NOT NULL,\n "action" text NOT NULL,\n "caller" text NOT NULL,\n "actor_kind" text NOT NULL,\n "actor_email" text,\n "org_id" text,\n "thread_id" text,\n "turn_id" text,\n "target_type" text,\n "target_id" text,\n "status" text DEFAULT \'success\'::text NOT NULL,\n "summary" text,\n "input" text,\n "error_code" text,\n "owner_email" text,\n "visibility" text DEFAULT \'private\'::text NOT NULL,\n "run_id" text,\n "task_id" text,\n "parent_task_id" text,\n "source_kind" text,\n "source_platform" text,\n "source_id" text,\n "source_url" text,\n "network_protocol" text,\n "network_id" text,\n "network_peer" text,\n "app" text,\n "reported_client_name" text,\n "reported_client_version" text,\n "oauth_client_id" text,\n "approval" text,\n "identity_assurance" text\n);',
|
|
20
20
|
'CREATE TABLE "agent_chat_submission_inbox" (\n "thread_id" text NOT NULL,\n "message_id" text NOT NULL,\n "state" text NOT NULL,\n "actor_email" text NOT NULL,\n "actor_auth_user_id" text,\n "actor_identity_authenticated_at_ms" bigint,\n "actor_name" text,\n "actor_org_id" text,\n "actor_org_scope" text,\n "actor_anonymous" boolean DEFAULT false NOT NULL,\n "payload_hash" text NOT NULL,\n "payload_json" text NOT NULL,\n "interrupt_active_run" boolean DEFAULT false NOT NULL,\n "submitted_run_id" text,\n "queue_order" bigint DEFAULT nextval(\'agent_chat_submission_inbox_queue_order_seq\'::regclass) NOT NULL,\n "move_to_top_at" bigint,\n "retry_after" bigint,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL,\n "interrupt_run_id" text\n);',
|
|
21
21
|
'CREATE TABLE "agent_checkpoints" (\n "id" text NOT NULL,\n "thread_id" text NOT NULL,\n "run_id" text,\n "commit_sha" text NOT NULL,\n "message" text DEFAULT \'\'::text NOT NULL,\n "created_at" bigint NOT NULL\n);',
|
|
22
22
|
'CREATE TABLE "agent_eval_datasets" (\n "id" text NOT NULL,\n "name" text NOT NULL,\n "description" text DEFAULT \'\'::text NOT NULL,\n "entries" text DEFAULT \'[]\'::text NOT NULL,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL,\n "user_id" text,\n "idempotency_key" text\n);',
|
|
@@ -121,7 +121,7 @@ export const SCHEMA_SNAPSHOT = {
|
|
|
121
121
|
'CREATE TABLE "org_members" (\n "id" text NOT NULL,\n "org_id" text NOT NULL,\n "email" text NOT NULL,\n "role" text NOT NULL,\n "joined_at" bigint NOT NULL,\n "federation_removal_pending_at" bigint\n);',
|
|
122
122
|
'CREATE TABLE "org_scim_memberships" (\n "id" text NOT NULL,\n "org_id" text NOT NULL,\n "user_id" text NOT NULL,\n "created_membership" boolean DEFAULT false NOT NULL,\n "created_at" bigint NOT NULL,\n "member_id" text\n);',
|
|
123
123
|
'CREATE TABLE "organization" (\n "id" text NOT NULL,\n "name" text NOT NULL,\n "slug" text NOT NULL,\n "logo" text,\n "metadata" text,\n "created_at" timestamp with time zone NOT NULL,\n "updated_at" timestamp with time zone NOT NULL\n);',
|
|
124
|
-
'CREATE TABLE "organizations" (\n "id" text NOT NULL,\n "name" text NOT NULL,\n "created_by" text NOT NULL,\n "created_at" bigint NOT NULL,\n "allowed_domain" text,\n "a2a_secret" text,\n "workspace_url" text,\n "required_auth_provider" text,\n "identity_authority" text,\n "identity_id" text,\n "federation_roster_initialized_at" bigint,\n "icon_json" text,\n "icon_revision" bigint DEFAULT 0 NOT NULL\n);',
|
|
124
|
+
'CREATE TABLE "organizations" (\n "id" text NOT NULL,\n "name" text NOT NULL,\n "created_by" text NOT NULL,\n "created_at" bigint NOT NULL,\n "allowed_domain" text,\n "a2a_secret" text,\n "workspace_url" text,\n "required_auth_provider" text,\n "identity_authority" text,\n "identity_id" text,\n "federation_roster_initialized_at" bigint,\n "icon_json" text,\n "icon_revision" bigint DEFAULT 0 NOT NULL,\n "a2a_member_delegation_enabled" boolean DEFAULT false NOT NULL\n);',
|
|
125
125
|
'CREATE TABLE "private_icon_assets" (\n "id" text NOT NULL,\n "owner_email" text NOT NULL,\n "org_id" text,\n "mime_type" text NOT NULL,\n "filename" text,\n "alt" text,\n "size" bigint NOT NULL,\n "sha256" text NOT NULL,\n "blob_handle_json" text NOT NULL,\n "created_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL\n);',
|
|
126
126
|
'CREATE TABLE "progress_runs" (\n "id" text NOT NULL,\n "owner" text NOT NULL,\n "title" text NOT NULL,\n "step" text,\n "percent" bigint,\n "status" text DEFAULT \'running\'::text NOT NULL,\n "metadata" text,\n "started_at" bigint NOT NULL,\n "updated_at" bigint NOT NULL,\n "completed_at" bigint\n);',
|
|
127
127
|
'CREATE TABLE "provider_api_cooldowns" (\n "quota_key" text NOT NULL,\n "provider_id" text NOT NULL,\n "scope_key" text NOT NULL,\n "cooldown_until" bigint NOT NULL,\n "status" bigint,\n "reason" text,\n "updated_at" bigint NOT NULL\n);',
|
|
@@ -866,6 +866,7 @@ export const SCHEMA_SNAPSHOT = {
|
|
|
866
866
|
["application_state", "baseline", null],
|
|
867
867
|
["application_state", "indexes", null],
|
|
868
868
|
["application_state", "widen-bigint", null],
|
|
869
|
+
["audit", "a2a-identity-assurance", "5ebfefc25224eaa5"],
|
|
869
870
|
["audit", "baseline", null],
|
|
870
871
|
["audit", "mcp-client-attribution", "bc0ea72722e10241"],
|
|
871
872
|
["auth_sessions", "baseline", null],
|
|
@@ -1038,6 +1039,7 @@ export const SCHEMA_SNAPSHOT = {
|
|
|
1038
1039
|
["org", "org-scim-membership-member-id", "cd1c4fb7479507d3"],
|
|
1039
1040
|
["org", "org-scim-membership-ownership", "09ca1c03026cda83"],
|
|
1040
1041
|
["org", "org-tables-timestamps-bigint", "a71b72b885bd5585"],
|
|
1042
|
+
["org", "organization-a2a-member-delegation", "3d01bcd4e7c259b0"],
|
|
1041
1043
|
["org", "organization-federation-removal-pending", "47fe40eb2ea33753"],
|
|
1042
1044
|
["org", "organization-federation-roster-initialized", "3307d4d99818c2f0"],
|
|
1043
1045
|
["org", "organization-identity-federation", "e24bac924c2d4c7a"],
|
|
@@ -1182,5 +1184,6 @@ export const SCHEMA_SNAPSHOT = {
|
|
|
1182
1184
|
["_org_migrations", 1032, "agent-audit-log-base-table"],
|
|
1183
1185
|
["_org_migrations", 1033, "organization-visual-identity"],
|
|
1184
1186
|
["_org_migrations", 1034, "private-icon-assets"],
|
|
1187
|
+
["_org_migrations", 1035, "organization-a2a-member-delegation"],
|
|
1185
1188
|
],
|
|
1186
1189
|
};
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* keep uploading to the old bucket.
|
|
9
9
|
*/
|
|
10
10
|
import { fail } from "../action.js";
|
|
11
|
-
import { getDbExec } from "../db/client.js";
|
|
12
11
|
import { deleteAppSecret, readAppSecrets, writeAppSecret, } from "../secrets/storage.js";
|
|
12
|
+
import { readOrgMemberRole } from "../server/personal-provider-key-policy.js";
|
|
13
13
|
import { getActiveFileUploadProviderForRequest, listFileUploadProviders, } from "./registry.js";
|
|
14
14
|
import { getPrivateStorageReadinessForUser, } from "./storage-readiness.js";
|
|
15
15
|
export const FILE_STORAGE_SECRET_KEYS = {
|
|
@@ -46,14 +46,7 @@ export async function resolveFileStorageAccess(ctx) {
|
|
|
46
46
|
// matching `canMutateWorkspaceScope` in the secrets routes.
|
|
47
47
|
if (!orgId)
|
|
48
48
|
return { scopeId: `solo:${email}`, canManage: true };
|
|
49
|
-
const
|
|
50
|
-
sql: `SELECT role FROM org_members
|
|
51
|
-
WHERE org_id = ? AND LOWER(email) = LOWER(?)
|
|
52
|
-
AND federation_removal_pending_at IS NULL
|
|
53
|
-
LIMIT 1`,
|
|
54
|
-
args: [orgId, email],
|
|
55
|
-
});
|
|
56
|
-
const role = rows[0]?.role;
|
|
49
|
+
const role = await readOrgMemberRole(orgId, email);
|
|
57
50
|
return { scopeId: orgId, canManage: role === "owner" || role === "admin" };
|
|
58
51
|
}
|
|
59
52
|
export function inferFileStorageProvider(endpoint) {
|
|
@@ -13,10 +13,10 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
13
13
|
enabled?: undefined;
|
|
14
14
|
nextRun?: undefined;
|
|
15
15
|
} | {
|
|
16
|
+
deleted?: undefined;
|
|
16
17
|
resourceId: string;
|
|
17
18
|
name: string;
|
|
18
19
|
enabled: boolean;
|
|
19
20
|
nextRun: string;
|
|
20
|
-
deleted?: undefined;
|
|
21
21
|
}>;
|
|
22
22
|
export default _default;
|
package/dist/jobs/tools.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { resolveAutomationAccess } from "../automations/access.js";
|
|
2
2
|
import { DEFAULT_AUTOMATION_SCHEDULE } from "../automations/service.js";
|
|
3
|
-
import { getDbExec } from "../db/client.js";
|
|
4
3
|
import { resolveUserSchedulingTimezone } from "../localization/user-timezone.js";
|
|
5
4
|
import { organizationIdFromResourceOwner, resourcePutIfAbsent, resourceGetByPath, resourceList, resourceDelete, SHARED_OWNER, sharedResourceOwner, } from "../resources/store.js";
|
|
5
|
+
import { readOrgMemberRole } from "../server/personal-provider-key-policy.js";
|
|
6
6
|
import { getRequestUserEmail, getRequestOrgId, getIntegrationRequestContext, } from "../server/request-context.js";
|
|
7
7
|
import { isReasoningEffort, REASONING_EFFORTS, } from "../shared/reasoning-effort.js";
|
|
8
8
|
import { RESUME_AUTOMATION_PATCH } from "./automation-outcome.js";
|
|
@@ -27,17 +27,7 @@ async function isCurrentUserOrgAdmin(orgId) {
|
|
|
27
27
|
if (!email)
|
|
28
28
|
return false;
|
|
29
29
|
try {
|
|
30
|
-
const
|
|
31
|
-
const { rows } = await client.execute({
|
|
32
|
-
sql: `SELECT role FROM org_members
|
|
33
|
-
WHERE org_id = ? AND LOWER(email) = ?
|
|
34
|
-
AND federation_removal_pending_at IS NULL
|
|
35
|
-
LIMIT 1`,
|
|
36
|
-
args: [orgId, email.toLowerCase()],
|
|
37
|
-
});
|
|
38
|
-
if (rows.length === 0)
|
|
39
|
-
return false;
|
|
40
|
-
const role = String(rows[0].role ?? "").toLowerCase();
|
|
30
|
+
const role = await readOrgMemberRole(orgId, email);
|
|
41
31
|
return role === "owner" || role === "admin";
|
|
42
32
|
}
|
|
43
33
|
catch {
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
import { getDbExec } from "../../db/client.js";
|
|
15
15
|
import { isMissingOrganizationTableError } from "../../org/membership.js";
|
|
16
16
|
import { CREDENTIAL_MEMBERSHIP_UNAVAILABLE_MESSAGE } from "../../server/credential-membership-unavailable.js";
|
|
17
|
+
import { readOrgMemberRole } from "../../server/personal-provider-key-policy.js";
|
|
18
|
+
import { getRequestContext } from "../../server/request-context.js";
|
|
17
19
|
export const SERVICE_TOKEN_MANAGE_FORBIDDEN_MESSAGE = "Only org owners or admins can create or revoke service tokens.";
|
|
18
20
|
export class ServiceTokenError extends Error {
|
|
19
21
|
statusCode;
|
|
@@ -24,17 +26,7 @@ export class ServiceTokenError extends Error {
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
async function readOrgRole(orgId, email) {
|
|
27
|
-
|
|
28
|
-
sql: `SELECT role FROM org_members
|
|
29
|
-
WHERE org_id = ? AND LOWER(email) = ?
|
|
30
|
-
AND federation_removal_pending_at IS NULL
|
|
31
|
-
LIMIT 1`,
|
|
32
|
-
args: [orgId, email.toLowerCase()],
|
|
33
|
-
});
|
|
34
|
-
const role = rows[0]?.role;
|
|
35
|
-
return role === "owner" || role === "admin" || role === "member"
|
|
36
|
-
? role
|
|
37
|
-
: null;
|
|
29
|
+
return readOrgMemberRole(orgId, email);
|
|
38
30
|
}
|
|
39
31
|
export async function getOrgRoleForEmail(orgId, email) {
|
|
40
32
|
try {
|
|
@@ -76,6 +68,18 @@ export async function requireServiceTokenCaller(params) {
|
|
|
76
68
|
throw new ServiceTokenError("Sign in to manage org service tokens.", 401);
|
|
77
69
|
}
|
|
78
70
|
let orgId = params.orgId?.trim() || "";
|
|
71
|
+
const requestContext = getRequestContext();
|
|
72
|
+
if (requestContext?.a2aIdentityAssurance === "org-member") {
|
|
73
|
+
const delegatedEmail = requestContext.userEmail?.trim().toLowerCase();
|
|
74
|
+
const delegatedOrgId = requestContext.orgId?.trim();
|
|
75
|
+
if (!delegatedEmail ||
|
|
76
|
+
delegatedEmail !== email.toLowerCase() ||
|
|
77
|
+
!delegatedOrgId ||
|
|
78
|
+
(orgId && orgId !== delegatedOrgId)) {
|
|
79
|
+
throw new ServiceTokenError("You are not a member of this organization.", 403);
|
|
80
|
+
}
|
|
81
|
+
orgId = delegatedOrgId;
|
|
82
|
+
}
|
|
79
83
|
if (!orgId) {
|
|
80
84
|
const memberOrgs = await lookupMembership(() => readOrgIds(email), []);
|
|
81
85
|
if (memberOrgs.length === 0) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { getDbExec } from "../db/client.js";
|
|
2
2
|
import { identityCredentialLockKey, readEmailRetiredAt, } from "../identity/retired-emails.js";
|
|
3
|
+
import { effectiveOrgMemberRole } from "../server/personal-provider-key-policy.js";
|
|
4
|
+
import { getRequestContext } from "../server/request-context.js";
|
|
3
5
|
import { checkCredentialOrgMembership } from "./credential-membership.js";
|
|
4
6
|
export class McpCredentialIssuanceError extends Error {
|
|
5
7
|
reason;
|
|
@@ -19,6 +21,11 @@ export async function withMcpCredentialIssuance(input, run) {
|
|
|
19
21
|
const email = input.email.trim().toLowerCase();
|
|
20
22
|
const human = input.kind !== "service";
|
|
21
23
|
const requiresMembership = orgId !== null && human;
|
|
24
|
+
if (getRequestContext()?.a2aIdentityAssurance === "org-member") {
|
|
25
|
+
if (!orgId || !effectiveOrgMemberRole("member", orgId, email)) {
|
|
26
|
+
throw new McpCredentialIssuanceError("not-member");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
22
29
|
if (requiresMembership) {
|
|
23
30
|
// Federation validation may update membership on another connection.
|
|
24
31
|
// Finish it before acquiring the local offboarding lock.
|
|
@@ -60,9 +67,9 @@ export async function withMcpCredentialIssuance(input, run) {
|
|
|
60
67
|
FOR UPDATE`,
|
|
61
68
|
args: [orgId, email],
|
|
62
69
|
});
|
|
70
|
+
const role = effectiveOrgMemberRole(rows[0]?.role, orgId, email);
|
|
63
71
|
if (rows.length === 0 ||
|
|
64
|
-
(input.roles &&
|
|
65
|
-
!input.roles.includes(String(rows[0].role)))) {
|
|
72
|
+
(input.roles && !input.roles.includes(role))) {
|
|
66
73
|
throw new McpCredentialIssuanceError("not-member");
|
|
67
74
|
}
|
|
68
75
|
}
|
|
@@ -140,13 +140,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
140
140
|
clientHint?: undefined;
|
|
141
141
|
timestamp?: undefined;
|
|
142
142
|
chapterId?: undefined;
|
|
143
|
-
count?: undefined;
|
|
144
143
|
startAt?: undefined;
|
|
145
144
|
endAt?: undefined;
|
|
146
145
|
reason?: undefined;
|
|
147
146
|
includeMicrophone?: undefined;
|
|
148
147
|
includeSystemAudio?: undefined;
|
|
149
148
|
requestId?: undefined;
|
|
149
|
+
count?: undefined;
|
|
150
150
|
};
|
|
151
151
|
required?: undefined;
|
|
152
152
|
};
|
|
@@ -171,13 +171,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
171
171
|
clientHint?: undefined;
|
|
172
172
|
timestamp?: undefined;
|
|
173
173
|
chapterId?: undefined;
|
|
174
|
-
count?: undefined;
|
|
175
174
|
startAt?: undefined;
|
|
176
175
|
endAt?: undefined;
|
|
177
176
|
reason?: undefined;
|
|
178
177
|
includeMicrophone?: undefined;
|
|
179
178
|
includeSystemAudio?: undefined;
|
|
180
179
|
requestId?: undefined;
|
|
180
|
+
count?: undefined;
|
|
181
181
|
};
|
|
182
182
|
required?: undefined;
|
|
183
183
|
};
|
|
@@ -196,13 +196,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
196
196
|
clientHint?: undefined;
|
|
197
197
|
timestamp?: undefined;
|
|
198
198
|
chapterId?: undefined;
|
|
199
|
-
count?: undefined;
|
|
200
199
|
startAt?: undefined;
|
|
201
200
|
endAt?: undefined;
|
|
202
201
|
reason?: undefined;
|
|
203
202
|
includeMicrophone?: undefined;
|
|
204
203
|
includeSystemAudio?: undefined;
|
|
205
204
|
requestId?: undefined;
|
|
205
|
+
count?: undefined;
|
|
206
206
|
};
|
|
207
207
|
required?: undefined;
|
|
208
208
|
};
|
|
@@ -231,13 +231,13 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
231
231
|
};
|
|
232
232
|
timestamp?: undefined;
|
|
233
233
|
chapterId?: undefined;
|
|
234
|
-
count?: undefined;
|
|
235
234
|
startAt?: undefined;
|
|
236
235
|
endAt?: undefined;
|
|
237
236
|
reason?: undefined;
|
|
238
237
|
includeMicrophone?: undefined;
|
|
239
238
|
includeSystemAudio?: undefined;
|
|
240
239
|
requestId?: undefined;
|
|
240
|
+
count?: undefined;
|
|
241
241
|
};
|
|
242
242
|
};
|
|
243
243
|
} | {
|
|
@@ -260,12 +260,12 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
260
260
|
description: string;
|
|
261
261
|
};
|
|
262
262
|
chapterId?: undefined;
|
|
263
|
-
count?: undefined;
|
|
264
263
|
startAt?: undefined;
|
|
265
264
|
endAt?: undefined;
|
|
266
265
|
includeMicrophone?: undefined;
|
|
267
266
|
includeSystemAudio?: undefined;
|
|
268
267
|
requestId?: undefined;
|
|
268
|
+
count?: undefined;
|
|
269
269
|
};
|
|
270
270
|
};
|
|
271
271
|
} | {
|
|
@@ -317,7 +317,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
317
317
|
clientHint?: undefined;
|
|
318
318
|
timestamp?: undefined;
|
|
319
319
|
chapterId?: undefined;
|
|
320
|
-
count?: undefined;
|
|
321
320
|
startAt: {
|
|
322
321
|
type: string;
|
|
323
322
|
description: string;
|
|
@@ -337,6 +336,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
337
336
|
type: string;
|
|
338
337
|
};
|
|
339
338
|
requestId?: undefined;
|
|
339
|
+
count?: undefined;
|
|
340
340
|
};
|
|
341
341
|
};
|
|
342
342
|
} | {
|
|
@@ -352,7 +352,6 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
352
352
|
clientHint?: undefined;
|
|
353
353
|
timestamp?: undefined;
|
|
354
354
|
chapterId?: undefined;
|
|
355
|
-
count?: undefined;
|
|
356
355
|
startAt?: undefined;
|
|
357
356
|
endAt?: undefined;
|
|
358
357
|
reason?: undefined;
|
|
@@ -361,6 +360,7 @@ export declare function screenMemoryMcpToolDefinitions(): ({
|
|
|
361
360
|
requestId: {
|
|
362
361
|
type: string;
|
|
363
362
|
};
|
|
363
|
+
count?: undefined;
|
|
364
364
|
};
|
|
365
365
|
};
|
|
366
366
|
})[];
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
2
|
-
error?: undefined;
|
|
3
2
|
count: number;
|
|
4
|
-
ok?: undefined;
|
|
5
3
|
updated?: undefined;
|
|
6
|
-
} | {
|
|
7
4
|
error?: undefined;
|
|
5
|
+
ok?: undefined;
|
|
6
|
+
} | {
|
|
8
7
|
count?: undefined;
|
|
9
8
|
updated: number;
|
|
9
|
+
error?: undefined;
|
|
10
10
|
ok?: undefined;
|
|
11
11
|
} | {
|
|
12
12
|
count?: undefined;
|
|
13
|
+
updated?: undefined;
|
|
13
14
|
error: string;
|
|
14
15
|
ok?: undefined;
|
|
15
|
-
updated?: undefined;
|
|
16
16
|
} | {
|
|
17
|
-
error?: undefined;
|
|
18
17
|
count?: undefined;
|
|
19
|
-
ok: boolean;
|
|
20
18
|
updated?: undefined;
|
|
19
|
+
ok: boolean;
|
|
20
|
+
error?: undefined;
|
|
21
21
|
}>>;
|
package/dist/org/actions.d.ts
CHANGED
package/dist/org/actions.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fail } from "../action.js";
|
|
2
|
-
import {
|
|
2
|
+
import { readOrgMemberRole } from "../server/personal-provider-key-policy.js";
|
|
3
3
|
export async function requireOrgMember(ctx, admin = false) {
|
|
4
4
|
const email = ctx?.userEmail?.trim();
|
|
5
5
|
const orgId = ctx?.orgId?.trim();
|
|
@@ -8,11 +8,7 @@ export async function requireOrgMember(ctx, admin = false) {
|
|
|
8
8
|
errorCode: "unauthorized",
|
|
9
9
|
statusCode: 401,
|
|
10
10
|
});
|
|
11
|
-
const
|
|
12
|
-
sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = LOWER(?) AND federation_removal_pending_at IS NULL LIMIT 1`,
|
|
13
|
-
args: [orgId, email],
|
|
14
|
-
});
|
|
15
|
-
const role = rows[0]?.role;
|
|
11
|
+
const role = await readOrgMemberRole(orgId, email);
|
|
16
12
|
if (!role)
|
|
17
13
|
fail("You are not a member of the active organization.", {
|
|
18
14
|
errorCode: "forbidden",
|
|
@@ -23,5 +19,5 @@ export async function requireOrgMember(ctx, admin = false) {
|
|
|
23
19
|
errorCode: "forbidden",
|
|
24
20
|
statusCode: 403,
|
|
25
21
|
});
|
|
26
|
-
return { email, orgId, role
|
|
22
|
+
return { email, orgId, role };
|
|
27
23
|
}
|
package/dist/org/app-roles.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getDbExec } from "../db/client.js";
|
|
2
|
-
import {
|
|
2
|
+
import { effectiveOrgMemberRole } from "../server/personal-provider-key-policy.js";
|
|
3
|
+
import { getRequestContext, getRequestOrgId, getRequestUserEmail, } from "../server/request-context.js";
|
|
3
4
|
import { ForbiddenError } from "../sharing/access.js";
|
|
4
5
|
import { isMissingOrganizationTableError } from "./membership.js";
|
|
5
6
|
const registry = new Map();
|
|
@@ -137,6 +138,9 @@ export async function resolveAppRole(descriptor, caller) {
|
|
|
137
138
|
return { status: "no-identity" };
|
|
138
139
|
if (!orgId)
|
|
139
140
|
return { status: "no-org" };
|
|
141
|
+
if (!effectiveOrgMemberRole("member", orgId, email)) {
|
|
142
|
+
return { status: "not-a-member", orgId };
|
|
143
|
+
}
|
|
140
144
|
let rows;
|
|
141
145
|
try {
|
|
142
146
|
rows = (await getDbExec().execute({
|
|
@@ -187,6 +191,11 @@ export async function resolveAppRole(descriptor, caller) {
|
|
|
187
191
|
return { status: "not-a-member", orgId };
|
|
188
192
|
orgRole = membership.role;
|
|
189
193
|
}
|
|
194
|
+
const isDelegatedOrgMember = getRequestContext()?.a2aIdentityAssurance === "org-member";
|
|
195
|
+
orgRole = effectiveOrgMemberRole(orgRole, orgId, email) ?? undefined;
|
|
196
|
+
if (isDelegatedOrgMember && !orgRole) {
|
|
197
|
+
return { status: "not-a-member", orgId };
|
|
198
|
+
}
|
|
190
199
|
const raw = row.roles ?? row.appRoles ?? row.approles;
|
|
191
200
|
const roles = Array.isArray(raw) ? raw.map(String) : [];
|
|
192
201
|
const validRoles = [
|
package/dist/org/context.d.ts
CHANGED
|
@@ -85,5 +85,6 @@ export declare function resolveA2AOrganizationCredentialsByDomain(domain: string
|
|
|
85
85
|
orgId: string;
|
|
86
86
|
orgDomain: string;
|
|
87
87
|
secret: string;
|
|
88
|
+
a2aMemberDelegationEnabled: boolean;
|
|
88
89
|
} | null>;
|
|
89
90
|
export declare function isSoleOrgDomain(domain: string): Promise<boolean>;
|