[workaround] Cache Assets store lookups via user PAT #8
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Workaround for #1 while the object-type-level permission on
Store Address / Hierarchy (109)is being investigated by the Assets admin.Context
The service account (
webex-bot-fzjq885stn) has schema-level read on schema 68 but is silently filtered out for objects in object type 109. Every direct API path (raw Assets API, site gateway, servicedeskapi CMDB proxy) is either 403 ortotal=0. The customer-portal autocomplete endpoint the JSM UI itself uses (found via HAR) works but requires a browser session cookie — no path with Basic Auth or the OAuth-gateway token gets past the permission wall.The workaround
A personal Atlassian PAT (Joe's account, verified to have read access to type 109) periodically syncs
storeNumber -> objectIdinto a local cache.resolveStoreAssetReferencereads from the cache first; the raw Assets AQL path becomes a fallback.Stores are the perfect data for this: small (≈ thousands), stable (only adds/removes for new/closed stores), and the lookup is a plain key-value.
Design
Auth compartmentalization — two Atlassian identities in the app:
webex-bot-fzjq885stn).env(existing)security add-generic-password -s jira-assets-sync -a mcqueenj@ae.com); env-loaded via helper script; never in.envCache layout — two-tier:
Map<paddedStoreNumber, { objectId, objectKey, label, syncedAt }>— sub-ms lookupsdata/stores.json(gitignored) — survives restart, avoids full resync every bootSync mechanics:
data/stores.json; if missing or older than N hours, kick off background full refreshPOST /api/wxccai/admin/storesCache/refreshfor immediate refreshGET /api/wxccai/admin/storesCache/statusreturns{ storeCount, lastSyncAt, ageSeconds, syncing, lastError, assetsSyncConfigured }Updated
resolveStoreAssetReferencebehavior:Trade-offs
lastSyncAtandlastErrorso health checks can flag ">48h stale".Acceptance
POST /api/wxccai/admin/storesCache/refreshpopulates the cache successfully with more than 0 stores using Joe's PAT.data/stores.json).createSSRequestcall for a known store (e.g. 514, 782) succeeds using the cached objectId, without needing the admin fix on #1.Non-goals
POST /requestshape)Shipped on
cursor/stores-cacheat fa06538a.What landed
src/services/jira/assetsSyncClient.js— Basic-auth axios atapi.atlassian.com/jsm/assets/workspace/{ws}/v1, sourced fromASSETS_SYNC_EMAIL/ASSETS_SYNC_TOKEN.src/services/jira/storesCache.js— in-memoryMap+ on-diskdata/stores.json(gitignored, atomic write). Paginated full sync viaobjectTypeId = 109. Boot-time load + background refresh if stale, scheduled resync everySTORES_CACHE_REFRESH_HOURS.bin/load-assets-sync-secret.sh— wraps the process so the PAT is pulled from Keychain (security find-generic-password -s jira-assets-sync -a <email>) and never sits in.env.resolveStoreAssetReferencenow resolves in this order: cache → live PAT lookup → service-account AQL (existing fallback). The fallback is intentionally preserved so it just becomes the primary path again once the permission on #1 is fixed — nothing here has to be ripped out.GET /api/wxccai/admin/storesCache/status,POST /api/wxccai/admin/storesCache/refresh.Verified on boot
Real-credentials smoke test still to run (this is a workflow, not blocker code):
security add-generic-password -s jira-assets-sync -a mcqueenj@ae.com -w '<PAT>' -UASSETS_SYNC_EMAIL=mcqueenj@ae.com ./bin/load-assets-sync-secret.sh npm startcurl -X POST :1866/api/wxccai/admin/storesCache/refresh→ expect ~thousands of stores populated in a few seconds.createSSRequestfor a known store (e.g. 514) → expect success without an Assets API call.Closing this issue on merge. #1 stays open as the real fix; the cache path deactivates itself in favor of the service-account AQL as soon as that permission lands.
End-to-end verification followup (b4bc646)
Real-credentials smoke test surfaced two bugs in the initial cut. Both fixed on the same branch, verified against a real store, real ticket.
Bug 1 — Assets AQL pagination silently capped at 25.
POST /object/aqlusesstartAt+maxResultsas URL query params, notpage+resultPerPagein the body. Passing the wrong param names caused Atlassian to silently fall back tomaxResults=25, so the first sync only cached 25 stores (out of 2,661). After fix: full sync in 5.3s across 6 pages, zero orphans.Bug 2 — Wrong CMDB field shape for Jira Cloud.
resolveStoreAssetReferencewas returning[{ objectId: "75974" }], which is the legacy Data Center / Server shape. Jira Cloud CMDB-object custom fields require[{ id: "<workspaceId>:<objectId>" }]. The old shape is silently accepted (HTTP 204 on REST PUT, no error on JSM POST) but the field is never persisted — confirmed via direct REST GET showingcustomfield_10261: []on the first test ticket (SS-20943). After fix: SS-20948 was created for store 00782 (objectId 75974) via cache-only lookup and shows the field populated correctly:Workaround status: proven working end-to-end. The service account can now create SS tickets with a populated Store Number field without needing direct access to Object Type 109.
Test artifacts (both moved to
Waiting for customerwith an internal explanatory comment; please close manually with the triage fields when you get to them):Follow-ups filed: #9 for a small close-route bug found during cleanup.