Skip to content

feat(portal): persona editor by surface, resource shares (#2257, #2258) - #2261

Merged
cjimti merged 1 commit into
mainfrom
feat/2257-2258-persona-editor-resource-shares
Oct 23, 2026
Merged

cjimti merged 1 commit into
mainfrom
feat/2257-2258-persona-editor-resource-shares

Conversation

@cjimti

@cjimti cjimti commented Oct 23, 2026

Copy link
Copy Markdown
Member

Description

Rebuilds Admin > Personas (ui/src/pages/settings/PersonaEditor.tsx) as one page grouped by surface, adds POST /api/v1/admin/personas/effective-access, makes DELETE /api/v1/admin/personas/{name} answer 409 while other records name the persona, and fixes the 22 defects #2257 lists. Adds file sharing (#2258): GET/POST /api/v1/resources/{id}/shares, DELETE /api/v1/resources/{id}/shares/{shareID}, GET /api/v1/resources/shared-with-me, POST /api/v1/resources/{id}/channel-shares, and access requests for files under /api/v1/portal/resources/{id}/access-request(s). An External persona can now be allowed to upload files, and each upload is shared on arrival with the personas or people the persona names.

#2257: persona access defects

The worst of the 22: the admin API admitted an External admin persona that Registry.AdminRule refuses, and scratch tables were reachable past both External and the portal levels.

  1. External admin persona (defects 1 and 20): the admin persona can no longer be External. persona.ValidateAccount refuses it on create and update, and loadPersonas refuses it at startup. Every name-only admin check now goes through AdminRule: the admin middleware, pkg/middleware/mcp.go (IsAdmin now means authorized and named), the prompt, script and notify layers (through pc.IsAdmin; their AdminPersona config fields are removed), MCP resources, the stored-secret lookup (secretstore.WithAdmin), iam.Authority and the webhook default library.
  2. The tool preview (defect 2): the server now computes what a persona can call, honoring connections and External, through the new effective-access endpoint. tools_detail.go builds personas with def.ToPersona(), so External is copied.
  3. External and Global files (defect 3): External no longer reads Global resources (resource.Claims.NoGlobal, set by resourcelevel).
  4. Saving an External persona (defect 4): the persona detail returns the stored portal block (portal) beside the effective one (effective_portal, capped_by_external). The editor saves only the stored block, so saving an External persona no longer lowers its settings for good.
  5. Per-row Allow (defect 5): the per-row Allow control is disabled when a deny pattern matches, and names the pattern.
  6. Starting points (defects 6 and 7): "Starting points" (All tools, Read only, Analyst, Clear) replace Quick Templates. Pattern rules sit inside each section, and the shared rail is gone.
  7. Account type and instructions (defects 8 and 9): Account type is one radio: Internal people, External people, Automated caller. Automated caller says when calls.exclude_personas also names the persona. Tool descriptions and agent instructions each have one textarea with an Add or Replace mode.
  8. Role mapping (defect 10): roles assigned by personas.role_mapping are shown read-only under Roles. The server also warns about role overlap.
  9. Scratch tables (defects 11 and 13): a new scratch_tables portal area (none, list, register; unset reads register) is checked on /api/v1/tables*, /api/v1/table-connections and the resource and asset table routes. External caps it at none, and the nav item follows it. The Resources level now gates POST /api/v1/resources/{id}/tables.
  10. Dropping tables through SQL (defect 12): a scratch connection where trino_execute is callable is reported drop_via_sql: true. The editor shows it as "Can drop any registered table through SQL".
  11. PDF export (defect 14): the switch is relabeled PDF export and enforced on the PDF routes themselves, /api/v1/resources/{id}/pdf included. The dead last == "pdf" rule in portalperm is removed. Content Download buttons no longer follow this switch.
  12. Approving access requests (defect 15): approving an access request checks the approver's sharing setting (403, and no share row).
  13. Shown in the access summary, rules unchanged (defects 16, 18 and 19): persona folders follow role overlap, signed-in endpoints admit any account, and memory is a pool shared across the persona. The summary now shows all three. Changing these rules is out of scope (decisions 7 and 8 in feat(portal): persona editor grouped by the surface each setting governs #2257).
  14. Folder writers (defect 17): the Resources setting lists the folders each option reaches, and the page names who writes the persona's folder: role persona-admin:<name> and administrators.
  15. Deleting a persona (defect 21): delete answers 409 with the references unless ?confirm=true, and the confirmation dialog lists them.
  16. Grants held elsewhere (defect 22): effective-access reports what names the persona elsewhere: stored secrets, script run grants, script versions, prompts, shares, webhook sources, external accounts and API keys.

#2258: file shares and external uploads

  • Migration 000217:
    • adds portal_shares.resource_id (ON DELETE CASCADE);
    • extends the one-target check to num_nonnulls(asset_id, collection_id, prompt_id, resource_id) = 1;
    • widens the access_requests target check to resource.
  • Permissions (internal/portal/resourceshare):
    • resource.Claims.Shared admits a recipient to read the file.
    • An Editor share admits editing (CanEditResource): fields and new versions. Move and delete stay with modify.
    • An External recipient is held to Viewer.
    • Sharing honors the sharer's persona SharingAllowed.
  • Channel posts (internal/httpserver/resourcesharewire/channel.go): a file posted to a channel gets a link share for signed-in internal people, or reuses existing access. There is no public file link.
  • Uploads by external accounts: a setting on an External persona (portal.uploads.share_personas, share_people). An upload lands in the uploader's own folder and is shared, as Viewer, with every recipient the persona names. An external uploader can also share their own upload with someone who shared with them.
  • UI:
    • Share on the file page and in the file manager, with the file share dialog covering channels and access requests.
    • "Upload and share..." in the Resources menu.
    • A "Shared with me" root in the file manager.
    • Global hidden for external accounts.

ui/package.json raises dompurify to ^3.4.17 for GHSA-c6gr-qvv4-5v3f, GHSA-cg2g-xh64-v4q7 and GHSA-mrv2-3pqr-j5jr, which osv-scanner reports against 3.4.16.

New UI wording not in either ticket: "People who can already open it", "Upload and share...", "Can edit" / "Can view", "Nothing is shared with you.", "Assets they own", and the access summary row texts.

New import edges in test/structure/testdata/allowed_internal_imports.txt:

  • internal/admin/personaaccess and internal/portal/resourceshare are new packages.
  • internal/httpserver/personaaccesswire and internal/httpserver/resourcesharewire assemble them from the platform's toolkits and stores.
  • accessreqwire reads file shares.
  • pdfhttp reads the caller's persona for PDF export.
  • The secret and resource-index admin mounts moved from internal/httpserver to adminwire to keep internal/httpserver under its size budget.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Test improvement (new or updated tests)
  • Documentation update

Related Issues

Closes #2257
Closes #2258

Readers of this state

  • Persona detail (GET /api/v1/admin/personas/{name}): portal is now the stored block, and effective_portal and capped_by_external are new. Read by the persona editor hooks (usePersonaEditor), which edit and save portal only. The TestIssue2257_ExternalKeepsTheStoredPortal acceptance test covers this.
  • The portal access block: scratch_tables and uploads are new.
    • Read by ui/src/lib/portalAccess.ts and the sidebar nav (navItems.ts), which hides Scratch Tables when the area is none.
    • Read by the server gates in portalperm and resourcelevel.
    • Both acceptance runs used the two-replica dev stack.
  • POST /api/v1/admin/personas/effective-access: new. Read by the editor's access summary and rule rows.
  • DELETE /api/v1/admin/personas/{name}: now 409 with references. Read by PersonasPanel, which lists them and sends ?confirm=true.
  • Resource shares routes and shared-with-me: new. Read by ui/src/api/resources/shares.ts, the share dialog's file target, the file page and the file manager's Shared with me root.
  • Notifications: a new kind, resource ("shared the file"), links to /resources/{id}.
  • Swagger: regenerated. make apidocs-openapi3-check passes.

Testing

  • Acceptance through the real server on make dev with two replicas:
  • Allow-disabled criterion: "Allow disabled under a deny pattern" is covered by vitest (editorSections.test.tsx), not by the acceptance run.
  • RealDB tests: the persona reference queries (internal/admin/personaaccess/refs_realdb_integration_test.go) and the resource share store.
  • sqlmock tests: every resource share store function, LinkShare, and the resources API claims extractor.
  • Patch coverage: 85.2%.
  • Frontend: vitest 3326 tests pass, npm run build, and Playwright interactive specs. Screenshots were regenerated for the persona editor states (summary, portal, external, delete, API routes, create) and the file share and Shared with me views, light and dark.
  • make verify: passes.
  • Built-in pages check: it names writing-managed-scripts.md (it covers scriptlayer.go). The page is unchanged because what it says, that administrators act on every script, still holds with pc.IsAdmin.

Rebuilds the admin persona editor as one page grouped by surface, adds POST /api/v1/admin/personas/effective-access, makes DELETE /api/v1/admin/personas/{name} answer 409 while API keys or files still reference the persona, and adds resource shares (portal_shares.resource_id, migration 000217) with access requests, channel posting and uploads by external accounts.

Closes #2257
Closes #2258
@codecov

codecov Bot commented Oct 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.84211% with 120 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.77%. Comparing base (4390d6f) to head (91f40ef).

Files with missing lines Patch % Lines
.../httpserver/resourcesharewire/resourcesharewire.go 49.05% 27 Missing ⚠️
.../httpserver/personaaccesswire/personaaccesswire.go 60.00% 26 Missing ⚠️
internal/portal/resourceshare/api.go 91.46% 14 Missing ⚠️
internal/httpserver/adminwire/adminwire.go 0.00% 10 Missing ⚠️
internal/httpserver/pdfhttp/pdfhttp.go 52.63% 9 Missing ⚠️
pkg/persona/portal.go 85.71% 7 Missing ⚠️
internal/admin/personaaccess/refs.go 89.65% 6 Missing ⚠️
internal/admin/personaaccess/report.go 96.93% 5 Missing ⚠️
internal/httpserver/tablemounts.go 0.00% 4 Missing ⚠️
pkg/platform/platform.go 60.00% 4 Missing ⚠️
... and 6 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2261      +/-   ##
==========================================
- Coverage   94.83%   94.77%   -0.06%     
==========================================
  Files        1398     1406       +8     
  Lines      113176   113978     +802     
==========================================
+ Hits       107332   108027     +695     
- Misses       5826     5933     +107     
  Partials       18       18              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cjimti
cjimti merged commit cb0e8b2 into main Oct 23, 2026
12 checks passed
@cjimti
cjimti deleted the feat/2257-2258-persona-editor-resource-shares branch October 23, 2026 01:48
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.

feat(portal): share resources, and uploads by external accounts feat(portal): persona editor grouped by the surface each setting governs

1 participant