Skip to content

feat(jsm): add Atlassian Assets (Insight/CMDB) tools for asset management#5072

Merged
waleedlatif1 merged 5 commits into
stagingfrom
feat/jsm-assets-tools
Jun 15, 2026
Merged

feat(jsm): add Atlassian Assets (Insight/CMDB) tools for asset management#5072
waleedlatif1 merged 5 commits into
stagingfrom
feat/jsm-assets-tools

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

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

Tool API
jsm_list_object_schemas GET /objectschema/list
jsm_get_object_schema GET /objectschema/{id}
jsm_list_object_types GET /objectschema/{id}/objecttypes
jsm_get_object_type_attributes GET /objecttype/{id}/attributes
jsm_search_objects_aql POST /object/aql (paginated)
jsm_get_object GET /object/{id}
jsm_create_object POST /object/create
jsm_update_object PUT /object/{id}
jsm_delete_object DELETE /object/{id}

How

  • Each tool proxies through an internal route (matching every other JSM tool) that resolves the Jira cloudId and the Assets workspaceId, 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 with getJsmApiBaseUrl.
  • workspaceId is discovered via GET /rest/servicedeskapi/assets/workspace (uses the already-granted read:servicedesk-request scope).
  • All nine operations are wired into the jira_service_management block (dropdown, subBlocks with conditions/required, tools.access, tool() selector, params() mapping, outputs, inputs).

OAuth scopes added (jira provider)

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 in SCOPE_DESCRIPTIONS.

Validation

  • tsc clean, biome clean, check:api-validation passes (route baseline bumped 828→837).
  • Every endpoint, field name, response shape, and scope string verified against the live Atlassian Assets docs.

Notes

  • Assets object attachments (file upload/download on objects) are a separate endpoint group and are intentionally out of scope here — none of these tools take file inputs.
  • ⚠️ Smoke-test against a live Assets workspace before relying on AQL: the docs publish CMDB scopes for 3LO and POST /object/aql carries no OAuth exclusion (unlike the removed GET /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:

  • Scope grant — confirm the Sim production Atlassian OAuth app has the Assets/CMDB scopes enabled in the Developer Console, then reconnect JSM and verify the issued token carries 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.
  • AQL smoke test — run jsm_search_objects_aql against a real workspace and confirm POST /object/aql returns results over 3LO (the deprecated GET /aql/objects was OAuth-blocked; the replacement is documented as accessible, but worth one live call).
  • Base-URL — confirm one read call succeeds via the /ex/jira/{cloudId}/jsm/assets/... gateway host.
  • Re-consent note — existing JSM connections must reconnect to pick up the new scopes.

…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.
@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 15, 2026 11:33pm

Request Review

@cursor

cursor Bot commented Jun 15, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
New OAuth scopes and mutating delete/create/update paths against customer CMDB data; routes follow existing JSM auth and validation patterns but need live-workspace verification (especially AQL).

Overview
Adds nine JSM Assets (Atlassian Assets / Insight / CMDB) operations to the existing Jira Service Management integration so workflows can list schemas and types, search with AQL, and read, create, update, or delete CMDB objects.

Each operation is exposed as a tool and backed by a new authenticated internal route under /api/tools/jsm/assets/… that resolves Jira cloudId and Assets workspaceId (auto-discovery when omitted), validates IDs, and proxies to the Atlassian Assets gateway API. Shared helpers in jsm/utils handle workspace discovery, URL building, and normalizing object payloads.

The Jira Service Management block gains matching operations, conditional asset-specific inputs (including optional AQL/attribute wand helpers), and new outputs. OAuth for the jira provider adds CMDB read/write/delete scopes with user-facing descriptions. Zod contracts, tool registry entries, integration metadata, and JSM docs are updated; the API route validation baseline moves 828 → 837.

Reviewed by Cursor Bugbot for commit 3933d55. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/app/api/tools/jsm/assets/schemas/route.ts Outdated
@greptile-apps

greptile-apps Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds 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 cloudId and workspaceId server-side, validates both via validateJiraCloudId / validateAssetsWorkspaceId before URL construction, and forwards to api.atlassian.com over the existing OAuth 2.0 (3LO) gateway.

  • 9 new route handlers (/api/tools/jsm/assets/…) each enforcing checkInternalAuth, Zod request parsing, and path-segment validation before any outbound fetch.
  • validateAssetsWorkspaceId added to mirror validateJiraCloudId, closing the path-traversal gap raised in the previous review round.
  • Block integration wires all nine operations into the jira_service_management block with sub-blocks, tool selector, params mapper, and outputs; pageNumber / pageSize fields returned by jsm_search_objects_aql are absent from the block's outputs declaration, preventing pagination workflows from referencing them in downstream steps.

Confidence Score: 4/5

Safe to merge with one fix: the search tool's pageNumber and pageSize outputs are missing from the block declaration, so pagination workflows built in the editor will silently get undefined for those fields.

The nine new tools follow every established security and architectural pattern: internal-auth gating, Zod request validation, validateJiraCloudId + validateAssetsWorkspaceId before any URL construction, and encodeURIComponent on all dynamic path segments. The one concrete defect is in the block's outputs map — pageNumber and pageSize returned by jsm_search_objects_aql are not declared, which means any downstream block referencing output.pageNumber to drive pagination will receive undefined rather than the current page number.

apps/sim/blocks/blocks/jira_service_management.ts — the outputs section needs pageNumber and pageSize entries for the AQL search operation.

Important Files Changed

Filename Overview
apps/sim/blocks/blocks/jira_service_management.ts Adds 9 new Assets operations to the dropdown, subBlocks, tool selector, params mapper, and outputs; pageNumber and pageSize are missing from the outputs declaration for search_objects_aql, breaking pagination workflows.
apps/sim/tools/jsm/utils.ts Adds resolveAssetsContext, mapAssetObject, getAssetsApiBaseUrl, and getAssetsWorkspaceId helpers; workspace discovery via /rest/servicedeskapi/assets/workspace is correct, and encodeURIComponent is used consistently on path segments in the caller routes.
apps/sim/lib/core/security/input-validation.ts Adds validateAssetsWorkspaceId using validatePathSegment with alphanumeric + hyphens only, matching UUID-shaped workspace IDs and mirroring the existing validateJiraCloudId guard.
apps/sim/app/api/tools/jsm/assets/search/route.ts AQL search proxy route; validates both cloudId and workspaceId before URL construction, handles includeAttributes coercion, and normalises the paginated objectEntries response correctly.
apps/sim/app/api/tools/jsm/assets/object/create/route.ts Create object proxy route; validates both path identifiers, forwards the Zod-validated attributes payload, and maps the response through mapAssetObject.
apps/sim/app/api/tools/jsm/assets/object/delete/route.ts Delete object proxy route; uses encodeURIComponent on objectId, validates both path identifiers, and returns { objectId, deleted: true } on success.
apps/sim/lib/api/contracts/selectors/jsm.ts Adds 9 Zod body schemas and contracts for the new Assets endpoints; attribute input schema validates objectTypeAttributeId and objectAttributeValues structure correctly.
apps/sim/tools/jsm/types.ts Adds all Assets-specific param/response interfaces, ASSET_OBJECT_PROPERTIES constant, and raw/normalised object shapes; types are consistent with what routes produce and tools consume.
apps/sim/lib/oauth/oauth.ts Appends six CMDB OAuth scopes to the jira provider configuration; all six are standard Atlassian 3LO scopes for the Assets API.

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 } }"
Loading
%%{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 } }"
Loading

Reviews (5): Last reviewed commit: "refactor(jsm): include Assets responses ..." | Re-trigger Greptile

Comment thread apps/sim/tools/jsm/utils.ts
Comment thread apps/sim/blocks/blocks/jira_service_management.ts
- 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-apps

greptile-apps Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds 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 cloudId and workspaceId, then calls the Assets REST API via the Atlassian OAuth gateway.

  • Nine new route handlers under app/api/tools/jsm/assets/, nine tool configs under tools/jsm/, and matching Zod contracts in lib/api/contracts/selectors/jsm.ts.
  • Shared utilities (resolveAssetsContext, getAssetsWorkspaceId, mapAssetObject, getAssetsApiBaseUrl) added to tools/jsm/utils.ts; six CMDB OAuth scopes added to the jira provider.
  • workspaceId is interpolated into the Assets base URL without the same validatePathSegment guard that protects cloudId, leaving a path-traversal window on the Atlassian gateway host for authenticated users.

Confidence Score: 3/5

Safe 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.

Security Review

  • Path traversal via unvalidated workspaceId (apps/sim/tools/jsm/utils.tsgetAssetsApiBaseUrl): workspaceId is interpolated directly into the Atlassian API URL path without the alphanumeric+hyphen validatePathSegment check applied to cloudId. An authenticated user who POSTs a crafted workspaceId to any of the nine new route handlers could route the server-side fetch to unintended paths on api.atlassian.com.

Important Files Changed

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 }"
Loading
%%{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 }"
Loading

Comments Outside Diff (1)

  1. apps/sim/blocks/blocks/jira_service_management.ts, line 1558-1590 (link)

    P2 deleted boolean missing from block output declarations

    The jsm_delete_object tool returns { ts, objectId, deleted } (see JsmDeleteObjectResponse), but the block's outputs section only declares objectId. Downstream blocks that reference output.deleted to branch on success vs. no-op will get undefined rather than true. Adding deleted: { type: 'boolean', description: 'Whether the delete succeeded' } alongside objectId fixes this.

Reviews (2): Last reviewed commit: "refactor(jsm): harden Assets param coerc..." | Re-trigger Greptile

Comment thread apps/sim/tools/jsm/utils.ts
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
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/tools/jsm/utils.ts
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.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/app/api/tools/jsm/assets/search/route.ts
Append the nine Assets tool response types to JsmResponse for completeness
and consistency with the rest of the JSM tool surface.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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.

@waleedlatif1 waleedlatif1 merged commit dd32abe into staging Jun 15, 2026
15 checks passed
@waleedlatif1 waleedlatif1 deleted the feat/jsm-assets-tools branch June 15, 2026 23:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant