Repository navigation
feat(portal): portal permissions, external users, access requests (#2229) - #2252
Merged
Merged
Conversation
) Closes #2229, #2225, #2092, #2089, #2090, #2227, #2186, #2248, #2249, #2232. A persona's portal block sets one level per portal area (#2225), enforced on every route of the area and reported on /api/v1/portal/me; hide_automations is folded into portal.automations by migration 000212. External personas and accounts signed in by an emailed one-time link, with session, invite and link lifetimes in admin settings, converted by an identity-provider sign-in (#2092). Shares addressed to a persona follow its membership (#2089). Requests for access to an item a person cannot open, answered by its owner, with emails and settings (#2090). Three access bugs fixed: manage_asset get and provenance had no read check; a persona share's emailed view link refused the persona's members; an agent never matched a share addressed to its persona. The #2109 acceptance criteria now send portal.automations.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2252 +/- ##
==========================================
- Coverage 94.84% 94.84% -0.01%
==========================================
Files 1381 1398 +17
Lines 112010 113176 +1166
==========================================
+ Hits 106237 107337 +1100
- Misses 5756 5821 +65
- Partials 17 18 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds per-persona portal permissions, external personas and accounts signed in by an emailed link, shares addressed to a persona, internal and shared feedback threads, and requests for access to an item a person cannot open. Five migrations (000212-000216), new routes under
/api/v1/admin/external-users,/api/v1/admin/settings/external-accounts,/api/v1/admin/settings/access-requests,/api/v1/portal/access-requests,/api/v1/portal/share-personasand/portal/auth/email-link, and three gate tickets. Fixes 3 access bugs found in review:manage_assetgetandprovenanceread an asset by id without a read check; any caller who knew an id could read it. Both now go through the same read check as the other read actions./portal/view/<token>link of a share addressed to a persona refused the persona's members:shareaccess.Authorizematched only a recipient id or email. A share now carriesRecipientPersonaand the viewer's persona is matched against it.Closes #2229
Closes #2225
Closes #2092
Closes #2089
Closes #2090
Closes #2227
Closes #2186
Closes #2248
Closes #2249
Closes #2232
Portal permissions per persona (#2225)
A persona's
portalblock sets one level per portal area:assets(shared,own),resources(none,shared,own,persona),knowledgeandcatalog(none,read,write),apis(none,browse), and the switchesfeedback,prompts,automations,search,memory,download. Set in file config, thepersona_definitions.portalcolumn (migration 000212) and the persona editor's new Portal tab.internal/portal/portalpermmaps every portal route to its area; the persona gate (internal/httpserver/accessgate) answers a route of an area the persona lacks with 403 Problem Details naming the area. Administrators have every area.apply_knowledgeelse read, catalog byapply_knowledge/fetch. Resolution is at load (persona.PortalAccess.Resolve), so existing personas behave exactly as before.internal/httpserver/resourcelevel);sharedreads the own folder, the persona folder and Global and uploads nothing.GET /api/v1/portal/mereportsportalresolved; the navigation hides what a persona lacks and an address in a hidden area shows a notice (SectionGate).hide_automationsintoportal.automationsand drops the column; a file persona'shide_automations: truestill reads asautomations: false. The admin persona API no longer acceptshide_automations(a hard cut; the feat(personas): choose per persona whether the portal shows Automations #2109 acceptance criteria now sendportal.automations).External personas and accounts (#2092)
external: trueon a persona makes it a persona for people outside the organization: no tools, viewer-only access to what is shared with them, no sharing, keys or directory.internal/extaccount)./api/v1/admin/settings/external-accountsand on the settings page. Links are rate limited per account per hour; the request route reports nothing about whether an address exists.Shares addressed to a persona (#2089)
manage_asset(migration 000215).GET /api/v1/portal/share-personaslists the personas a share can name with their members.portaldomain.WithCallerPersona), so leaving the persona ends the access.Internal and shared feedback threads (#2227)
A feedback thread is Internal or Shared (migration 000214). An internal thread is for the organization: a person of an external persona never sees it in a list, a count, the sign-off or by its address, and a mention or notification of it reaches nobody external. A shared thread is seen by everyone who can open the item, external people included. The composer opens on Internal; the item's owner, an editor or an administrator can change it later, and the change is recorded on the timeline. A thread an external person opens is always shared.
Requests for access (#2090)
/api/v1/portal/{assets,collections,prompts}/{id}/access-request(s))./api/v1/portal/access-requests, approve as viewer or editor, or decline). An approval creates a person share recorded with originaccess_request; the requester is emailed the answer. A second open request from the same person notifies nobody./api/v1/admin/settings/access-requests: whether the request page names the item, and how many days a request stays open (migration 000216,internal/portal/accessreq, wired byinternal/httpserver/accessreqwire).Gates (#2186, #2248, #2249)
make preverifyruns three gates only verify ran:make security-diff(verify's standalone gosec over packages with a changed production Go file),make route-template-diff(TestEveryRouteReportsItsTemplate_RealDBalone when the diff adds or removes a mux pattern) andmake route-conformance-check(the MSW route conformance test), read from the diff byscripts/preverify-diff.py. Pinned byTestPreverifyRunsTheGatesOnlyVerifyRan.dev/makesmake preverifyrunmake dev-smoke: one call through the platform per service the dev stack runs, in under a minute. Pinned byTestPreverifySmokesAChangedDevStack.REALDB_MAX_CONNECTIONS(100), and every run prints its peak connections and the packages holding the most (scripts/realdb-connections.py). The migration runner now returns its connection when released; before it,pkg/oauth/postgresalone held 268 connections and exhausted a 400 limit under verify's load.Acceptance suite measurement (#2232)
One full serial
make acceptanceagainst the local two-replica stack took 6155 s; 1468 criteria passed. Five criteria in code this PR does not touch failed on that long-lived dev database and are #2251.Acceptance
test/acceptance/issue_2089_test.go,issue_2090_test.go,issue_2092_test.go(including an identity-provider sign-in through Keycloak converting an account),issue_2225_test.go,issue_2227_test.go, and the updatedissue_2109_test.go, each through the real portal, admin API, MCP client and mail delivery on the local stack. Transcripts underbuild/<n>/acceptance.md;make acceptance-checkpasses for all six.Readers of this state
portal,external,hide_automationsremoved):ui/src/pages/settings/PersonaEditor.tsx,persona/PortalTab.tsx,persona/BehaviorTab.tsx,persona/types.ts,PersonasPanel.tsx,ui/src/api/admin/types/tools.ts,ui/src/mocks/data/personas.ts./api/v1/portal/meportal:ui/src/hooks/usePortalAccess.ts,ui/src/lib/portalAccess.ts,Sidebar.tsx,AppShell.tsx,SectionGate.tsx,AssetViewer.tsx,AssetViewerActions.tsx,ContentRenderer.tsx,KnowledgeHub.tsx,KnowledgePagesPage.tsx,pages/resources/scopes.ts,stores/auth.ts.ShareDialog.tsx,share/ShareSections.tsx,share/ActiveShares.tsx,lib/sharedLine.ts, the asset and collection grids and tables,PromptViewerHeader.tsx.api/portal/feedback.ts,hooks/threads.ts,NewThreadForm.tsx,ThreadBadges.tsx,ThreadList.tsx,ThreadHeader.tsx,FeedbackButton.tsx.UsersPanel.tsx(External users section),ExternalAccountsSettingsCard.tsx,api/admin/hooks/externalUsers.ts,LoginForm.tsx(email link).components/access/RequestAccessPanel.tsx,AccessRequestsList.tsx,api/portal/hooks/accessRequests.ts,AccessRequestsSettingsCard.tsx,api/admin/hooks/accessRequests.ts, the asset, collection and prompt viewer pages,FeedbackPage.tsx.New internal imports
test/structure/testdata/allowed_internal_imports.txtgains 46 edges, all from the new packages (internal/extaccount,internal/admin/extaccountapi,internal/admin/personarules,internal/portal/accessreq,internal/portal/portalperm,internal/httpserver/{accessreqwire,extaccountwire,personashare,resourcelevel}) or from existing packages to the persona and permission checks they now call, plusinternal/httpserver/accessreqwire -> pkg/promptfor the prompt an access request names.Docs
docs/personas/overview.md,docs/portal/admin-access.md,docs/portal/admin-settings.md,docs/portal/assets.md,docs/portal/feedback.md,docs/server/configuration.md,README.md,CLAUDE.md,docs/llms.txt,docs/llms-full.txt; swagger regenerated with the "Access requests" and "External users" tags grouped.