Zuar Portal v1.21.0

Notes

Portal MCP Server and Agent Harness Plugin

  • New Portal MCP Server: connect an AI coding assistant (e.g., Claude Code or Codex) directly to your portal and build or edit content conversationally. The assistant acts as the signed-in admin, bounded by their existing permissions — there is no service account. See Portal MCP Server and Connect an AI assistant to Portal MCP.
  • New zportal agent harness plugin for Claude Code, which connects the assistant to one or more portals through their MCP servers. Install it from the zuar-portal-mcp-plugin repository. The plugin requires Portal 1.21.0 or later.

Undo and Redo

  • Portal now keeps a history of every change to pages, blocks, themes, queries, and data sources, whether it was made in the Portal interface or by an AI assistant. Each save is recorded as one change set, and history is on by default.
  • Through the Portal MCP Server, an AI assistant can show what a change set altered and undo it, including restoring a deleted page, block, or theme with its user group access.
  • If someone has changed the same item since, the assistant shows that later change and asks before overwriting it.
  • History keeps the newest 1,000 changes per item and does not store credentials.
  • Undo and redo in the page editor are coming in a future release.

Backup and Restore

  • New Admin > Backups page to take an instance backup and restore from one in the browser. While a restore runs, the Portal shows a maintenance page and admin navigation is locked until it finishes. See Backups.

API Keys

  • New Admin > API Keys section to create, list, and delete API keys. A new key is shown once, when it is created. See API Keys.
  • External URL items in the navigation can now be limited to selected user groups, so each group sees only the links meant for it. See Navigation.

Security

  • Login attempt limits: each IP address can submit at most 5 login attempts per minute, and 10 consecutive failed password attempts lock a local account for 15 minutes. SSO accounts are not affected. See Login attempt limits.
  • Security updates and fixes: this release includes further hardening of authentication and admin file editing.

Breaking Changes

  • Self-managed deployments: backup archives are now written to for_mounting/backups/ instead of app/. Existing archives are moved there automatically during the upgrade. Update any scripts that copy or rotate backups from the old location. See the 1.21.0 upgrade guide.

Issues Resolved in this Release

New Features

Issue Summary Resolution
POR-2562 API Key admin UI Done
POR-2561 Portal MCP backup / restore Done
POR-2560 Portal MCP Undo/Redo Done
POR-2557 Create MCP skills Done

Improvements

Issue Summary Resolution
POR-2653 FE// A datasource whose DB connection was deleted: page crashes, the editor silently switches it to the default connection, and Test reports success Done
POR-2646 FE// Error messages show [object Object] when the API returns an object detail (e.g. 503 datasource_unavailable in Test Query) Done
POR-2644 Portal MCP: undoing a delete restores the entity without its access groups, and the agent is not warned Done
POR-2641 Portal MCP skills: the browser-session check is reached only at the end, and visual verification has no path without browser tools Done
POR-2614 Portal MCP: create_entity accepts a query with no name, and a blank name on any kind Done
POR-2613 Portal MCP: execute_sql and execute_query say nothing when the page was cut, and fake row_count when the portal omits a total Done
POR-2611 Portal MCP: update_entity merges json_data recursively so one key can change without resending the object Done
POR-2610 zportal client MCP: surface the cause of transport failures, recover from dead pooled connections, and tell the caller how to verify an ambiguous write Done
POR-2606 Portal MCP: tool responses return more than the caller asked for (get_entity, writes, SQL runs) Done
POR-2604 zportal connect skill: never infer the portal URL, stop and ask even in non-interactive runs Done
POR-2596 Portal MCP takes instance backups only when the user asks Done
POR-2582 FE// Remove stale unit tests from UI repo Done
POR-2569 Add API endpoint to execute SQL without Data Source Done
POR-2568 Add credentials meta field to Credentails API Done
POR-2558 FE// Add pagination to blocks Done
POR-2556 BE// Add filter by ID to enteties API for Portal MCP Done
POR-2555 BE// Query create/update sql validation for Portal MCP Done
POR-2541 Portal MCP Done
POR-2538 CLONE - E15 Group - User-based dynamic visibility for navigation bar external urls Done
POR-2536 zwaf: exchange API Key for a short-lived JWT at the edge Done

Bug Fixes

Issue Summary Resolution
POR-2678 FE// Asset Manager settings: switching storage type shows "Connection <id> not found" instead of an empty credentials field Done
POR-2677 FE// Credentials: updating an existing credential fails with 422 - API rejects the read-only meta field the UI sends back Done
POR-2676 FE// Backups: after a restore the page can reload while the portal is still restarting and stays on the loader Done
POR-2675 FE// Access groups picker: selected group tiles show no × to remove the group Done
POR-2666 1.21: extra count(*) on list endpoints and double /access_policies call on /blocks raise per-request cost vs 1.20.0 (+15% portal CPU, +31% auth CPU, -8% capacity) Done
POR-2665 Scheduler license-credentials sync fails with "client has been closed" after first run Done
POR-2664 BE// SCIM: a group-member removal from Entra returns 500 - the member is never removed from the portal group Done
POR-2663 Memory leak in portal 1.20.1 Done
POR-2658 FE// Blocks: selection is cleared on every sort change - 1.20 kept it for all sorts except Type Done
POR-2656 FE// A cascading-filter-group without json_data.filters leaves the whole page on its loader; the block editor throws on a null json_data Done
POR-2655 Portal MCP: the <style> refusal says "the css list" without a path, and CSS written to a block's json_data.css is accepted silently and never applied Done
POR-2654 FE// Every visit to a page without a slug shows a 422 "Field required" error toast (page-view metric sent without page_url) Done
POR-2642 Portal MCP: on a % grid, place_blocks and the skills treat the canvas as layouts.height tall, while the UI draws blocks as a percentage of the grid Done
POR-2639 Portal MCP: update_entity accepts json_data: null on a block, and the block then throws on render Done
POR-2638 BE// updated_at is not bumped when only a relation field changes (tags, access, ui_queries) Done
POR-2637 Portal MCP: the layout json_data schema names a page route that does not exist (/page/{slug}) Done
POR-2636 FE// Page thumbnail: "is not an image" error does not fit the thumbnail box - no padding, long names overflow it Done
POR-2632 Portal MCP: the theme schema declares css "default": [], but a theme with an empty css renders data tables unreadable and the clear-filters button invisible Done
POR-2631 FE// Changing the Data Source of a cascading-filter-group bound to a raw_sql query keeps the old SQL, and the block cannot be repaired from the UI Done
POR-2629 FE// A px grid wider than the window stays centred on page load, so its left part is cut off and cannot be scrolled to Done
POR-2628 Portal MCP: deleting a page reports an empty impact although get_references models the page -> block link, and the blocks it placed are silently orphaned Closed
POR-2627 Portal MCP: the RLS skill claims the data path scopes rows per caller, so an agent is told not to write the filter that actually does it Done
POR-2626 Portal MCP: the amchart schema promises chart-click filtering for chart types where no handler is attached Closed
POR-2625 Portal MCP: filtering.by is never validated against the query's columns, so chart-click filtering fails silently when the query aliases the column Done
POR-2624 Portal MCP: the block schema says css is optional and nullable, the write gate requires it Done
POR-2623 BE// A datasource connection or authentication failure escapes as a bare 500 on query execution instead of a handled error Done
POR-2622 zportal client MCP: a session silently destroys portal registrations made by other sessions Done
POR-2621 Portal MCP: a malformed reference id is reported as an infrastructure fault, with advice to retry Done
POR-2620 Portal MCP: the list_entities cursor is a plain offset, so paging can silently skip entities Done
POR-2619 Portal MCP: navigation -> page references are not modelled, so deleting a linked page is not flagged and the dangling id is never reported Closed
POR-2618 FE// Navigation item editors crash when a menu node omits the optional `tags` field Done
POR-2617 SEC// ThoughtSpot trusted-auth secret key is logged in plaintext on every token request and shipped to ELK Done
POR-2615 Portal MCP: the literal-$ validation rule suggests an HTML entity fix that does not work inside script Done
POR-2612 Portal MCP: HTTP failures report "portal API unreachable:" with an empty reason, and SQL execution shares the 5-second timeout Done
POR-2609 FE// Page CSS cannot style a page region: the scoper prefixes a region selector with itself, and the rule fails silently Done
POR-2608 BE// Query SQL validator rejects sql_form the renderer accepts and stores (unquoted identifiers with spaces) Closed
POR-2607 BE// Renaming or tagging a datasource or query is rejected when the stored record is already broken (write re-validates the whole entity) Done
POR-2605 portal-client-mcp: repo manifest version 0.2.0 lags the published plugin 0.4.0, so dev runs report a version that matches no release Done
POR-2603 FE// Shortcuts modal: ESC label mentions edit mode, which non-admin users do not have Done
POR-2601 FE// Admin navigation loses the Users & Groups location on the Groups tab - Access section not active, item not highlighted Done
POR-2600 FE// Themes panel: clicking + while the theme list is still loading silently discards the new theme Done
POR-2599 FE// Success toasts stay on screen for 10+ s and swallow clicks on the Save button underneath Done
POR-2598 FE// Tableau v3: a Dashboard URL set while a new block is still loading is ignored - the block stays on "Dashboard URL is required." until save Done
POR-2595 A ThoughtSpot outage is reported to the client as 400 Bad Request, with the raw errno in the response body Done
POR-2594 zwaf: a full auth outage is served to the user as 404 Not Found (maintenance.html is missing from the image) Done
POR-2593 Test connect message shown after adding API key to plugin Done
POR-2591 FE// One failing query save aborts the whole page save silently, leaving a partially applied state Done
POR-2590 FE// A page cannot be saved once a block's query is deleted - the empty query slot is POSTed and rejected with 422, silently Done
POR-2589 FE// Form Query: Column dropdown does not load datasource columns — only * available Done
POR-2588 FE// Blocks: changing the sort after scrolling freezes the page for several seconds (renders the whole loaded set before reloading page 1) Done
POR-2587 FE// Blocks: selection outline on a selected card is missing its right edge Done
POR-2586 FE// Confirmation modal overflows horizontally on a long unbroken entity name Done
POR-2584 SEC// Stored XSS in the shared confirmation modal — non-admin sets a user name (SCIM) that executes in an admin's session Done
POR-2580 BE// A transport failure to the auth service is reported to the client as 404 Not Found on the requested resource Done
POR-2578 MCP authored cascading-filter query issue Done
POR-2577 FE// Duplicating a theme renders no logo/favicon - CSP connect-src blocks the blob: asset request Done
POR-2576 PDS// First upgrade to 1.21.x from any older install fails — portal-mcp core service has no image (compose runs before IMAGE_PORTAL_MCP is written) Done
POR-2573 BE// API Keys: a revoked or unknown key answers 400 "User not found" instead of 401 Done
POR-2572 BE// API Keys: POST /auth/api_keys answers 404 for an unknown user_id instead of 400 Done
POR-2564 FE+BE// ThoughtSpot Org Picker sends a numeric org_id — every non-primary Org 422s and the picker goes blank Done
POR-2563 BE// portal-api returns 500 instead of 401 when the session JWT has expired Done
POR-2559 FE// ThoughtSpot Search Page: "Hide Data Sources" checkbox writes the wrong config key and does nothing Done
POR-2551 FE// Saving a page drops the :embed special parameter from the URL Done
POR-2592 BUG 1.19.1 page thumbnail is not working Done
POR-2540 1.19 Date Filter issue with data types and setting Default Date Time Done
POR-2535 SEC: /admin/edit performs no filename validation — authenticated-admin arbitrary file write (CWE-22) Done
POR-2537 GET /layouts/{id} returns 500 instead of treating the session as anonymous when JWT expires Closed
POR-2506 SEC// Authenticated SQLi via columns/where/order_by in GET|POST /api/datasources/{id}/data — cross-table read, bypasses datasource scope Closed
POR-2505 SEC// Logout does not invalidate the session — JWT stays valid for its full lifetime after logout Done
POR-2449 Security: `/login` endpoint has no rate-limit or account lockout Done

Tasks

Issue Summary Resolution
POR-2554 AQA// Write automated tests for 1.20 release - new functionality and bug fixes Done