feat(jsm): add Atlassian Assets (Insight/CMDB) tools for asset management#5072
Conversation
…ment
Add nine JSM Assets tools so workflows can read and write Atlassian Assets
(Insight/CMDB) objects — the foundation for keeping JSM asset tables in sync
for software/hardware asset management.
Tools (wired into the Jira Service Management block):
- jsm_list_object_schemas, jsm_get_object_schema
- jsm_list_object_types, jsm_get_object_type_attributes
- jsm_search_objects_aql (AQL search with pagination)
- jsm_get_object, jsm_create_object, jsm_update_object, jsm_delete_object
Each tool proxies through an internal route that resolves the Jira cloudId and
the Assets workspaceId, then calls the Assets API via the OAuth 2.0 (3LO)
gateway form (/ex/jira/{cloudId}/jsm/assets/workspace/{workspaceId}/v1).
Adds the CMDB OAuth scopes to the jira provider (read/write/delete cmdb-object,
read cmdb-schema/type/attribute) with descriptions, contract schemas for each
route, and block operations/subBlocks/outputs. Bumps the API-validation route
baseline for the nine new routes.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Each operation is exposed as a tool and backed by a new authenticated internal route under The Jira Service Management block gains matching operations, conditional asset-specific inputs (including optional AQL/attribute wand helpers), and new outputs. OAuth for the Reviewed by Cursor Bugbot for commit 3933d55. Configure here. |
|
@greptile review |
|
@cursor review |
Greptile SummaryAdds nine Atlassian Assets (Insight/CMDB) tools to the JSM integration, covering schema discovery, object type inspection, AQL search, and full CRUD on objects. Each tool follows the established JSM proxy pattern: a Zod-validated internal route resolves
Confidence Score: 4/5Safe to merge with one fix: the search tool's The nine new tools follow every established security and architectural pattern: internal-auth gating, Zod request validation, apps/sim/blocks/blocks/jira_service_management.ts — the Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Block as JiraServiceManagement Block
participant Route as /api/tools/jsm/assets/* Route
participant Auth as checkInternalAuth
participant Validate as Input Validation
participant Resolver as resolveAssetsContext
participant AtlassianDisc as api.atlassian.com (workspace discovery)
participant AtlassianAssets as api.atlassian.com (Assets API)
Block->>Route: "POST { domain, accessToken, workspaceId?, ...params }"
Route->>Auth: checkInternalAuth(request)
Auth-->>Route: "{ success, userId }"
Route->>Route: parseRequest(contract, body)
Route->>Resolver: resolveAssetsContext(domain, token, cloudId?, workspaceId?)
Resolver->>AtlassianDisc: "GET /ex/jira/{cloudId}/rest/servicedeskapi/assets/workspace"
AtlassianDisc-->>Resolver: "{ values: [{ workspaceId }] }"
Resolver-->>Route: "{ cloudId, workspaceId }"
Route->>Validate: validateJiraCloudId(cloudId)
Route->>Validate: validateAssetsWorkspaceId(workspaceId)
Validate-->>Route: isValid
Route->>AtlassianAssets: "GET/POST/PUT/DELETE /ex/jira/{cloudId}/jsm/assets/workspace/{workspaceId}/v1/..."
AtlassianAssets-->>Route: response data
Route-->>Block: "{ success, output: { ts, ...data } }"
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Block as JiraServiceManagement Block
participant Route as /api/tools/jsm/assets/* Route
participant Auth as checkInternalAuth
participant Validate as Input Validation
participant Resolver as resolveAssetsContext
participant AtlassianDisc as api.atlassian.com (workspace discovery)
participant AtlassianAssets as api.atlassian.com (Assets API)
Block->>Route: "POST { domain, accessToken, workspaceId?, ...params }"
Route->>Auth: checkInternalAuth(request)
Auth-->>Route: "{ success, userId }"
Route->>Route: parseRequest(contract, body)
Route->>Resolver: resolveAssetsContext(domain, token, cloudId?, workspaceId?)
Resolver->>AtlassianDisc: "GET /ex/jira/{cloudId}/rest/servicedeskapi/assets/workspace"
AtlassianDisc-->>Resolver: "{ values: [{ workspaceId }] }"
Resolver-->>Route: "{ cloudId, workspaceId }"
Route->>Validate: validateJiraCloudId(cloudId)
Route->>Validate: validateAssetsWorkspaceId(workspaceId)
Validate-->>Route: isValid
Route->>AtlassianAssets: "GET/POST/PUT/DELETE /ex/jira/{cloudId}/jsm/assets/workspace/{workspaceId}/v1/..."
AtlassianAssets-->>Route: response data
Route-->>Block: "{ success, output: { ts, ...data } }"
Reviews (5): Last reviewed commit: "refactor(jsm): include Assets responses ..." | Re-trigger Greptile |
- Add toOptionalInt helper so non-numeric pagination inputs never emit NaN into the Assets query string (startAt/maxResults/page/resultsPerPage) - Replace Record<string, any> in mapAssetObject with typed Raw* interfaces
Greptile SummaryAdds nine Atlassian Assets (Insight/CMDB) tools to the existing JSM block, covering the full CRUD lifecycle for objects plus schema/type/attribute discovery. The implementation follows the established JSM proxy-route pattern — each tool POSTs to an internal Next.js route that resolves
Confidence Score: 3/5Safe to merge once workspaceId path validation is added; all routes are internally authenticated and the scope of any traversal is bounded to api.atlassian.com. The nine new route handlers consistently validate cloudId with validateJiraCloudId, but workspaceId — which is also interpolated into the URL path — receives no equivalent check. An authenticated user could craft a workspaceId with path-traversal segments to reach unintended Atlassian API paths. This needs to be fixed before the routes are live, but the fix is a small addition of a validatePathSegment call. apps/sim/tools/jsm/utils.ts (getAssetsApiBaseUrl uses workspaceId without validation) and all nine route handlers that call resolveAssetsContext without subsequently validating workspaceId.
|
| Filename | Overview |
|---|---|
| apps/sim/tools/jsm/utils.ts | Adds resolveAssetsContext, getAssetsApiBaseUrl, getAssetsWorkspaceId, and mapAssetObject helpers. workspaceId is interpolated into URLs without the same path-segment validation applied to cloudId. |
| apps/sim/app/api/tools/jsm/assets/object/create/route.ts | New POST handler proxying object creation to the Assets API; follows existing JSM route patterns, checks internal auth, and validates cloudId but not workspaceId. |
| apps/sim/app/api/tools/jsm/assets/search/route.ts | AQL search proxy; toNumber coercion and includeAttributes boolean handling look correct. workspaceId validation gap is inherited from utils.ts. |
| apps/sim/blocks/blocks/jira_service_management.ts | Wires nine new Assets operations into the JSM block. The deleted boolean is returned by the tool but not declared in the block's outputs section. |
| apps/sim/lib/api/contracts/selectors/jsm.ts | Adds nine new Zod-validated contracts for the Assets endpoints; schemas are correct and consistent with the existing base schema pattern. |
| apps/sim/lib/oauth/oauth.ts | Adds six CMDB OAuth scopes to the jira provider. Scopes match documented Atlassian Assets 3LO requirements. |
| apps/sim/tools/jsm/types.ts | Adds comprehensive TypeScript types for all new Assets tools; interfaces and ASSET_OBJECT_PROPERTIES constant are well-structured and reused correctly. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as Block / Tool
participant Route as Next.js API Route
participant Auth as checkInternalAuth
participant Util as resolveAssetsContext
participant AtlJira as api.atlassian.com /ex/jira/{cloudId}
participant AtlAssets as Assets API /workspace/{workspaceId}/v1
UI->>Route: "POST /api/tools/jsm/assets/{operation}"
Route->>Auth: checkInternalAuth(request)
Auth-->>Route: "{ success, userId }"
Route->>Util: resolveAssetsContext(domain, accessToken, cloudId?, workspaceId?)
Util->>AtlJira: GET /rest/api/2/serverInfo
AtlJira-->>Util: cloudId
Util->>AtlJira: GET /rest/servicedeskapi/assets/workspace
AtlJira-->>Util: workspaceId
Util-->>Route: "{ cloudId, workspaceId }"
Route->>Route: validateJiraCloudId(cloudId) ok / validateWorkspaceId missing
Route->>AtlAssets: "GET/POST/PUT/DELETE /{resource}"
AtlAssets-->>Route: response
Route-->>UI: "{ success, output }"
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as Block / Tool
participant Route as Next.js API Route
participant Auth as checkInternalAuth
participant Util as resolveAssetsContext
participant AtlJira as api.atlassian.com /ex/jira/{cloudId}
participant AtlAssets as Assets API /workspace/{workspaceId}/v1
UI->>Route: "POST /api/tools/jsm/assets/{operation}"
Route->>Auth: checkInternalAuth(request)
Auth-->>Route: "{ success, userId }"
Route->>Util: resolveAssetsContext(domain, accessToken, cloudId?, workspaceId?)
Util->>AtlJira: GET /rest/api/2/serverInfo
AtlJira-->>Util: cloudId
Util->>AtlJira: GET /rest/servicedeskapi/assets/workspace
AtlJira-->>Util: workspaceId
Util-->>Route: "{ cloudId, workspaceId }"
Route->>Route: validateJiraCloudId(cloudId) ok / validateWorkspaceId missing
Route->>AtlAssets: "GET/POST/PUT/DELETE /{resource}"
AtlAssets-->>Route: response
Route-->>UI: "{ success, output }"
Comments Outside Diff (1)
-
apps/sim/blocks/blocks/jira_service_management.ts, line 1558-1590 (link)deletedboolean missing from block output declarationsThe
jsm_delete_objecttool returns{ ts, objectId, deleted }(seeJsmDeleteObjectResponse), but the block's outputs section only declaresobjectId. Downstream blocks that referenceoutput.deletedto branch on success vs. no-op will getundefinedrather thantrue. Addingdeleted: { type: 'boolean', description: 'Whether the delete succeeded' }alongsideobjectIdfixes this.
Reviews (2): Last reviewed commit: "refactor(jsm): harden Assets param coerc..." | Re-trigger Greptile
Address review findings on the Assets tools: - Add validateAssetsWorkspaceId and guard the workspaceId in every Assets route before it is interpolated into the API path (mirrors the existing cloudId guard) — prevents a crafted workspaceId from escaping the workspace-scoped path - Object schema list now falls back to the `last` flag when `isLast` is absent, so pagination doesn't stop early
|
@greptile review |
|
@cursor review |
Atlassian provisions one Assets workspace per site, so workspace discovery uses values[0] by design. For the rare multi-workspace site, expose an advanced "Assets Workspace ID" override on the block that flows through to every Assets operation, and document the single-workspace assumption.
d22bee2 to
e7054cd
Compare
|
@greptile review |
|
@cursor review |
Append the nine Assets tool response types to JsmResponse for completeness and consistency with the rest of the JSM tool surface.
|
@greptile review |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 3933d55. Configure here.
What
Adds nine JSM Assets (Atlassian Assets / Insight / CMDB) tools to the existing Jira Service Management integration, so workflows can read and write Atlassian Assets objects. This is the foundation for keeping JSM asset tables in sync (software/hardware asset management).
Tools
jsm_list_object_schemasGET /objectschema/listjsm_get_object_schemaGET /objectschema/{id}jsm_list_object_typesGET /objectschema/{id}/objecttypesjsm_get_object_type_attributesGET /objecttype/{id}/attributesjsm_search_objects_aqlPOST /object/aql(paginated)jsm_get_objectGET /object/{id}jsm_create_objectPOST /object/createjsm_update_objectPUT /object/{id}jsm_delete_objectDELETE /object/{id}How
cloudIdand the AssetsworkspaceId, then calls the Assets API via the OAuth 2.0 (3LO) gateway form:https://api.atlassian.com/ex/jira/{cloudId}/jsm/assets/workspace/{workspaceId}/v1/...— consistent withgetJsmApiBaseUrl.workspaceIdis discovered viaGET /rest/servicedeskapi/assets/workspace(uses the already-grantedread:servicedesk-requestscope).jira_service_managementblock (dropdown, subBlocks with conditions/required,tools.access,tool()selector,params()mapping, outputs, inputs).OAuth scopes added (
jiraprovider)read:cmdb-object:jira,write:cmdb-object:jira,delete:cmdb-object:jira,read:cmdb-schema:jira,read:cmdb-type:jira,read:cmdb-attribute:jira— each with a description inSCOPE_DESCRIPTIONS.Validation
tscclean,biomeclean,check:api-validationpasses (route baseline bumped 828→837).Notes
POST /object/aqlcarries no OAuth exclusion (unlike the removedGET /aql/objects), but a real-token check is wise.Pre-merge verification gates (do not skip)
Static validation is complete (tsc/biome/api-validation green; spec parity + internal semantics verified by multiple passes; 4 clean review rounds). The following require a live JSM+Assets instance and are not certifiable from code:
read:cmdb-object:jira(and write/delete for mutations). The 6 scope strings are verified correct and documented as OAuth 2.0 (3LO)-grantable, but enabling them on the registered app + user re-consent is an operational step.jsm_search_objects_aqlagainst a real workspace and confirmPOST /object/aqlreturns results over 3LO (the deprecatedGET /aql/objectswas OAuth-blocked; the replacement is documented as accessible, but worth one live call)./ex/jira/{cloudId}/jsm/assets/...gateway host.