You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(tools): address the cubic review round on direct tool execution
Two were real defects rather than polish:
The usage ledger de-duplicates on `eventKey`, and the derived key hashes actor,
workspace, source and description — identical for every call to the same tool.
`onConflictDoNothing` therefore billed the first hosted-key call and silently
dropped every one after it. A workflow run has an `executionId` to separate its
rows; a direct call has nothing, so it now mints one.
Undeclared input keys reached the executor. `impersonateUserEmail` is read
straight out of params and forwarded to credential-token resolution as an
impersonation request, and no tool declares it. The two ad-hoc denylists are
replaced by a declared-parameter allowlist — the actual boundary, and the one
`GET /api/v2/tools/{toolId}` already publishes.
Also: renaming a canonical id orphans `data.canonicalModes`, and the backfill
recovers it only when one side holds a value. `setBlockCanonicalMode` writes the
mode without clearing its sibling, so a workflow holding both would have
silently switched from the typed reference to the uploaded file.
`migrateCanonicalModeIds` carries the key across, ahead of the backfill.
Smaller: the reachability audit now mirrors execution exactly, exempting
`credentialType` only under `authoritativeParams` and refusing to treat
conditional hosting as a guarantee; the boundary guard splits on both path
separators so it still excludes the execute route on Windows; the route stops
documenting the 409 and 423 it cannot produce; and `sim tools execute` prints
the output it promised in the human formats.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: apps/sim/lib/api/contracts/v2/openapi/resources.ts
+1-2Lines changed: 1 addition & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -38,7 +38,6 @@ import {
38
38
RATE_LIMIT_HEADERS,
39
39
RESOURCE_CONFLICT_ERRORS,
40
40
RESOURCE_ERRORS,
41
-
RESOURCE_MUTATION_ERRORS,
42
41
V2_API_KEY_SECURITY,
43
42
V2_API_KEY_SECURITY_SCHEMES,
44
43
V2_COMMON_HEADERS,
@@ -1828,7 +1827,7 @@ const declaredRoutes = [
1828
1827
operationId: 'executeTool',
1829
1828
summary: 'Run Tool',
1830
1829
description: `Run one built-in tool and return what it produced. Supply \`input\` using the parameter ids \`GET /api/v2/tools/{toolId}\` publishes; Sim resolves the credential named by \`credentialId\`, injects a hosted API key for the tools it supplies one for, and substitutes environment-variable references, so the request carries arguments rather than secrets. A parameter the tool marks \`user-only\` also accepts \`{{VAR_NAME}}\` as its whole value, resolved server-side against the workspace environment; every other value is sent verbatim, so a literal secret passes through untouched. A tool that runs and refuses is a \`200\` carrying \`status: "failed"\` and the reason — the error envelope is reserved for failures of this API, not of the third party. A tool the workspace's visible blocks do not expose answers \`404\` identically to one that does not exist; one whose integration the workspace does not permit answers \`403\` with \`error.details.code\` \`INTEGRATION_NOT_ALLOWED\`. Hosted-key spend this call incurs is billed to the workspace. ${WORKSPACE_API_KEY_DENIED}`,
1831
-
errors: RESOURCE_MUTATION_ERRORS,
1830
+
errors: RESOURCE_ERRORS,
1832
1831
success: {description: 'The outcome of the tool call.'},
Copy file name to clipboardExpand all lines: apps/sim/lib/tool-execution/application/operations.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -28,7 +28,7 @@ import { defineWorkspaceOperation } from '@/lib/core/application'
28
28
* kinds ahead of a surface that uses them.
29
29
*/
30
30
exportconsttoolExecutionOperations={
31
-
// permission-group-exempt: no static capability names running one built-in tool — the per-tool denial is the deniedTools key, applied inside @/tools against the resolved id, and the per-integration denial is the parameterized allowedIntegrations key, which the funnel cannot apply because it never sees which integration a tool id reaches. That decision is enforced from the use case by the owning-block-type check in executeToolForCaller, ahead of dispatch.
31
+
// permission-group-exempt: declares capability: 'none' because no static capability names running one built-in tool — the per-tool denial is the deniedTools key, applied inside @/tools against the resolved id, and the per-integration denial is the parameterized allowedIntegrations key, which the funnel cannot apply because it never sees which integration a tool id reaches. That decision is enforced from the use case by the owning-block-type check in executeToolForCaller, ahead of dispatch.
0 commit comments