Repository navigation
feat(portal): share assets to channels, sharing permission (#2241) - #2244
Merged
Merged
Conversation
Nine tickets plus a Go toolchain bump: the Share dialog's channel destination and POST /api/v1/portal/assets/{id}/channel-shares (#2241), notify/platform.publish access and target (#2088), viewer-only current version (#2226), one persona resolution and admin rule (#2228), the portal Profile page (#2215), Markdown feedback bodies (#2214), collapsed script change summaries (#2185), migrate-check in preverify (#2239), and go 1.27.3 for GO-2026-6809.
1. Share offers a channel: the chat channels each Slack or Mattermost bot is in (a chat channel's target is now optional on an immediate channel), Signed-in users or Anyone with the link with an expiration, and a message. Posting creates a channel_post link share with posted_to and posts its URL; Slack shares the preview image into the channel. The Post to a channel button, PostToChannelDialog and POST /api/v1/portal/channels/{name}/publish are removed.
2. allow_sharing on personas (migration 000211, default true; Sharing checkbox; /me sharing). Without it: no Share action, and 403 from the share routes, the channel list and channel share; manage_asset share, an export's create_public_link and notify publish with a share refuse too.
3. notify publish and platform.publish take access (signed_in default, public with expires_in, existing) and target; a signed_in post reuses the share an earlier post to the same place made; a held-back or refused post revokes a share it created. Migration 000210 adds portal_shares.posted_to.
4. A reader whose access is viewer gets 403 from the version routes, an earlier version's content and a signed content URL naming one, and from manage_asset list_versions and diff; the asset page shows no history to them. list_versions had no access check at all and now requires read access.
5. personas.role_mapping.oidc_to_persona is applied by the registry's GetForRoles, ties go to the name that sorts first, and the administrator rule is the resolved persona being admin.persona on the portal, admin API, resources and MCP; the literal admin/platform-admin role rule in resources is removed.
6. Feedback thread bodies render as Markdown with mention chips and a Write/Preview composer; comment, feedback and mention emails render the message as HTML.
7. The sidebar footer shows the signed-in account and opens /portal/profile.
8. The script page shows the newest three change summaries behind Show N more.
9. make preverify runs migrate-check on pg16 and pg17 when the diff touches a migration.
Closes #2241
Closes #2088
Closes #2226
Closes #2228
Closes #2215
Closes #2214
Closes #2185
Closes #2239
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2244 +/- ##
==========================================
+ Coverage 94.80% 94.83% +0.03%
==========================================
Files 1376 1381 +5
Lines 111500 111991 +491
==========================================
+ Hits 105705 106211 +506
+ Misses 5778 5763 -15
Partials 17 17 ☔ 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.
Changes the Share dialog,
notify(action=publish and action=send),platform.publish/platform.notify,manage_asset(share, list_versions, diff), the portal routesPOST /api/v1/portal/assets/{id}/channel-shares(new),GET /api/v1/portal/channels, the asset version and content-url routes,/api/v1/portal/me, the admin persona API, persona resolution on every surface, feedback thread rendering and email, the sidebar footer and a new/portal/profilepage, the script page's change summaries,make preverify, and the Go toolchain. Two migrations (000210, 000211). RemovesPOST /api/v1/portal/channels/{name}/publishand the asset page's Post to a channel button.Closes #2241
Closes #2088
Closes #2226
Closes #2228
Closes #2215
Closes #2214
Closes #2185
Closes #2239
Share to a channel (#2241)
users.conversations, public and private, or public only when the token lacksgroups:read; Mattermost, the open and private channels of every team the bot is on), plus the other channels the person reaches. Aslack/mattermostchannel'stargetis now optional on an immediate channel: without one it stands for the bot, and one channel per workspace is enough. A daily chat channel still needs its own target and takes none per post.origin: channel_postandposted_tonaming where it went (#general (slack)), and posts that share's URL rather than/portal/assets/{id}. The share is listed in the asset's shares as Posted to …, and revoking it stops the posted link from opening.POST /api/v1/portal/assets/{id}/channel-shares(channel,target,access_modeauthenticated|public,expires_in,message) replacesPOST /api/v1/portal/channels/{name}/publish. It is anotifycall made as the signed-in person, so connection scoping, the per-session rate limit and audit apply unchanged.PostToChannelDialogare removed.The sharing permission (#2241)
allow_sharingon a persona: file config (*bool, absent allows),persona_definitions.allow_sharing(migration 000211, default true), the admin persona API, and a Sharing checkbox on the persona editor's AI Assistant Behavior tab./api/v1/portal/mereportssharing.sharing is not available to your personafromPOST .../shares(asset, collection, prompt),POST .../channel-sharesandGET /api/v1/portal/channels; the same refusal frommanage_asset action=share, an export'screate_public_link(through a gated share store), andnotify action=publishwith accesssigned_inorpublic. Administrators can always share.Who opens a published link (#2088)
notify action=publishandplatform.publishtakeaccess:signed_in(default) creates, or reuses, a link share any signed-in user opens;publiccreates one that expires afterexpires_in(required);existingposts the asset page link, today's behavior, which opens only for people who already have access.signed_inandpublicneed the asset's owner (a script run acts for its author) or an administrator.signed_inreuses the share. A post held back by a repeat key, or refused, revokes a share it created.sendandpublishtaketarget, one of the chat channelsaction=listnow reports under each bot channel'stargets. The result carriesaccess,share_idand, for public,expires_at.platform.notifygainstarget;platform.publishgainsaccess,expires_inandtarget. The script contract text is updated.portal_shares.posted_to.Viewers see only the current version (#2226)
GET /api/v1/portal/assets/{id}/versions, from.../versions/{n}/contentfor any version but the current one, and from.../content-url?version=naming an earlier version. The owner, editors and administrators keep the full history.manage_assetlist_versionsanddiffrefuse the same way.list_versionshad no access check at all before this: any caller could list any asset's versions by id. It now requires read access, then the history check.One persona resolution and one admin rule (#2228)
personas.role_mapping.oidc_to_personais applied by the persona registry'sGetForRoles, so the portal, the admin API and managed resources resolve the persona the MCP path does. Two personas of equal priority now resolve to the name that sorts first, on every request, instead of in map order.admin.persona(Registry.AdminRule). It replaces the role-intersection checks in the portal access core, the script, prompt-version, mention, table and API-browser identities and the portal catalog routes. Managed resources no longer treat a role literally namedadminorplatform-adminas administration, and table registration over MCP reads the call's resolvedIsAdmin.Profile (#2215)
The sidebar footer names the signed-in account above Sign Out: the email, or the user ID when there is none, with an avatar of initials (avatar only with a tooltip when collapsed). It opens
/portal/profile, which shows email, user ID, persona, roles, administrator yes/no and the sign-in method (single sign-on or API key), with Sign Out. It reads the/mepayload already loaded and shows no token or key.Markdown in feedback threads (#2214)
metadata.mentions. A mention inside code stays as written.CommentBodyreplacesMentionText.@local(domain)mention written as its address; the text part keeps the Markdown as written. List views show thread titles only, so no body excerpt is involved.Script change summaries (#2185)
The script page shows the newest three change summaries; the rest open with Show N more, remembered in the browser. A line points to the full history under Source.
Migrations in preverify (#2239)
make preverifyrunsmake migrate-check-diff, which runsmigrate-checkon pg16 and pg17 when the diff against main adds or changes a file underpkg/database/migrate/migrations/, and skips it otherwise.TestPreverifyChecksMigrationsOnBothMajorspins it.Go 1.27.3
go.mod's toolchain and every workflow'sgo-versionmove from 1.27.2 to 1.27.3, which fixes GO-2026-6809 (crypto/x509 distrusts compromised intermediates), published 2026-10-21 and reported by govulncheck against 1.27.2.Readers of this state
meResponse.sharing(/api/v1/portal/me):ui/src/stores/auth.ts(canShare), read byAssetViewer,CollectionViewerPage,PromptViewerPage.Share.posted_to/origin:ui/src/api/portal/types.ts, rendered byui/src/components/share/ActiveShares.tsx.allow_sharing:ui/src/api/admin/types/tools.ts,PersonasPanel.tsx,persona/usePersonaEditor.ts,persona/BehaviorTab.tsx, MSW persona mocks.GET /api/v1/portal/channelstargets/targets_error/target, andPOST .../channel-shares:ui/src/api/portal/hooks/channels.ts,ui/src/components/share/ChannelShareSection.tsx, MSW handlers.ui/src/pages/viewer/AssetViewerPage.tsx(no versions request for a viewer),useAssetVersions(assetId, enabled).targetnow optional:ui/src/pages/settings/NotificationChannelEditor.tsx(required only for daily).PostToChannelDialog, removed with it.Size and structure
internal/httpserver/notifywire/channels.gomoved tointernal/platform/notifywiring/upstream.goso the notify tool can list a bot's channels through the connection resolution the send worker uses.internal/portal/access(pkg/portal's exported-surface budget), the export share gate ininternal/platform/portalstore(pkg/platform's size budget), and the sharing check for the channel routes inchannelhttp(notifywire's cohesion).notifyrenderonpkg/portal/mentionfor mention addresses, the toolkit and exporters oninternal/portal/access).Acceptance
Run through the real surfaces against
make dev(two replicas behind the proxy), the Mattermost fixture, a developer Slack workspace and mailpit; transcripts atbuild/<n>/acceptance.md, each opening with its wire forms.sharing:false, 403 on the channel list, channel share and link share; a viewer recipient cannot post; the old route does not post.existingposts the asset page and makes no share; a script'splatform.publish(access="public", expires_in="24h")posts a link that opens signed out.list_versions,diff); an editor reads all three./meand MCP and is an administrator nowhere; a mapped role (dp_inventory_analyst) resolves the same in the portal and MCP ahead of the admin role; equal priorities resolve the same on 15 requests.Notes for review
user-asset-post-to-channelis replaced byuser-asset-share-to-channel, anduser-profileis new.