Repository navigation
feat(endpoints): form page, file fields, event runs (#2331-#2333, #2337) - #2340
Merged
Merged
Conversation
- #2331: the form page moves to /forms/{endpoint}; a site its binding's allowed_origins lists may frame it, an asset frames it with a signed 12-hour embed marker, and the automation's page offers an embed snippet that sizes the frame to the form. - #2332: a script names a webhook source (manage_script update event_source, or the Events section on its page) and each event the source stores enqueues one run with trigger event reading run.event; past scripts.events.max_queued (default 100) pending event runs an event is recorded as a skipped_backlog run. Migration 000222. - #2333: file fields (max_files, max_bytes, accept) on a form; files are saved as managed resources in the form source's attachments folder only after form_submit accepts, and the submissions view and exports name them. - #2337: the admin API answers a signed-in non-admin 403 instead of 401, the Changesets tab reads new /api/v1/portal/knowledge/changesets routes open to apply_knowledge holders, and the portal no longer redirects to sign-in again within a minute of a sign-in redirect. - The webhook receiver no longer registers a raw window twice when a delivery lands while that window's registration is finishing.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2340 +/- ##
========================================
Coverage 94.81% 94.81%
========================================
Files 1435 1443 +8
Lines 116477 117111 +634
========================================
+ Hits 110433 111035 +602
- Misses 6024 6056 +32
Partials 20 20 ☔ 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 the
/forms/{endpoint}page and its embed snippet,fileform fields, runs per stored webhook event (manage_script update event_source,PUT /api/v1/portal/scripts/{id}/event-source,GET /api/v1/portal/scripts/{id}/events, migration 000222), andGET/POST /api/v1/portal/knowledge/changesets[/{id}[/rollback]], and fixes 3 bugs: 1) a signed-in non-admin opening Knowledge > Changesets was caught in a sign-in loop (#2337), 2) the webhook receiver could register a raw window twice, 3) the #2176 acceptance tests named no scratch connection, which a stack with two of them requires.Closes #2331
Closes #2332
Closes #2333
Closes #2337
Closes #2094
Hosted form page and embed snippet (#2331)
/forms/{endpoint}(internal/endpoint/epformpage,epform.PagePrefix)./portal/forms/is gone, with no alias.frame-ancestorsis'self'plus the binding'sallowed_origins. A form framed inside an asset carries a signed, 12-hour, endpoint-bound embed marker (form_embed,internal/endpoint/epform/embed.go) that exempts it, because the asset's sandboxed frame has no origin the list could name. The asset rewrite (pkg/portal/assetrefs.go,internal/portal/assetrefs) adds the marker to every form address, and adds the viewer token for a signed-in reader.mcp-form:height) as it changes. The automation's page shows a copyable snippet for a bound form (ui/src/pages/scripts/endpoints/FormEmbed.tsx,embedSnippet.ts) whose frame resizes to that height.manage_script endpoint_listand the binding route report the bound form'spage_url.File fields (#2333)
file, withmax_files(default 1, at most 20),max_bytes(default 10 MiB) andaccept. A submission with a file field ismultipart/form-data(at most 1000 parts). Each file's type is judged from its bytes, not its name. Prefilling a file field is refused.form_submitis then handed each file'smcp://address, and the files are saved only after it accepts (internal/endpoint/epcollect/files.go, at most 4 saves in parallel). If saving or storing the event fails, the files already saved are deleted, so a refused or unstored submission keeps none.<attachments>/<date>/<event id>/<field>. Deleting the form source deletes them.name <uri>.A run for each stored webhook event (#2332)
scripts.event_source), throughmanage_script update event_source=...or the new Events section on its page. After the receiver has stored an event (spool, segment, or an imap poll's segment),internal/platform/scripteventsenqueues one run with triggereventfor each script naming that source. The run reads the event asrun.event:id,type,key,received_at,sourceandpayload.(script_id, event_source, event_id)makes it one run per event, even when a sender retries.exclusivequeueorrefuse) queues its event runs and runs them in order.scripts.events.max_queued(default 100) event runs waiting, a new event is recorded as a finished run with statusskipped_backlogand a reason, not executed. The Events section shows the runs waiting, the runs skipped in the last 7 days, and the bound.internal/platform/scriptevents/sourcerule): an administrator may name any source; anyone else only the source of a form whose script they own, since naming a source means reading every event it stores.scripts.event_source, andscript_runs.event_source,event_idandevent(JSONB), plus the unique index and a pending index. It also addseventto the trigger check andskipped_backlogto the status check. The migration passedmigrate-checkon pg16 and pg17.TriggerEventandStatusSkippedBackloglive ininternal/runstate, which keeps them offpkg/script's exported surface.Changesets for apply_knowledge holders (#2337)
pkg/adminanswers valid credentials that are not the admin persona with 403 (ErrNotAdmin), not 401. The portal reads 401 as an expired session, which is what started the loop.internal/httpserver/changesethttpservesGET /api/v1/portal/knowledge/changesets,GET .../{id}andPOST .../{id}/rollbackto a portal caller whose persona holdsapply_knowledge, and to administrators. With no caller it answers 401; with a caller who lacksapply_knowledge, 403. The routes run the admin knowledge handler with the portal caller as its user, so a rollback is recorded under the reviewer.ui/src/api/portal/hooks/changesets.ts). The tab's audit-filter query runs only for administrators.ui/src/api/admin/client.tsdoes not redirect to sign-in on a 401 within 60 seconds of its previous sign-in redirect.Webhook receiver fix
registerPendingis now serialized, andregisterOneskips a window that is already registered (internal/webhook/receiver). It showed up asTestNewWindowIsRegisteredOncefailing only under full verify load. It did not fail in 300 targeted runs before the fix or 1,200 after, so the fix rests on reading the code, plus a new test of the case.Readers of this state
changesethttp.changesetList(data,page,per_page,total) and the three changeset routes:ui/src/api/portal/hooks/changesets.ts,ui/src/pages/knowledge/capture/ChangesetsTab.tsx,ChangesetDrawer.tsx, and the MSW handlers inui/src/mocks/handlers.tsmoved to the portal base.eventshttp.sourceRequest/sourceResponse(source,message) andPUT .../event-source:ui/src/api/portal/hooks/scriptEvents.ts,ui/src/pages/scripts/ScriptEventsCard.tsx,ui/src/mocks/handlers/scripts.ts.eventshttp.summaryResponse(pending,skipped_since,skipped_window_days,max_queued) andGET .../events:scriptEvents.ts,ScriptEventsCard.tsx(EventSummaryFacts), the scripts mock.script.Script.event_sourceandscript.Contract.event_source:ui/src/api/portal/hooks/scripts.ts, and the Events fact inui/src/pages/scripts/ScriptDetailPage.tsx. The run statusskipped_backlogis labelled inui/src/pages/scripts/runFormat.ts.GET /portal/scripts/{id}/endpoint(description changed; the form'spage_url):ui/src/api/portal/hooks/scriptEndpoint.tsandui/src/pages/scripts/ScriptEndpointCard.tsx./forms/:ui/src/components/renderers/formFrames.ts(FORM_PATH_PREFIX; it rewrites only an address that carriesform_embed) andui/src/pages/webhooks/FormSourceSection.tsx.Docs
docs/scripts/endpoints.md: the form page, embedding a form on a site, file fields.docs/scripts/running.md: runs per stored event.docs/server/asset-references.md,docs/knowledge/admin-api.md,docs/portal/admin-knowledge.md.docs/llms.txtanddocs/llms-full.txt,CLAUDE.md, and thewriting-managed-scriptsbuilt-in page (run.event).Verification
make verifypassed.build/<n>/acceptance.jsonl:TestIssue2331_*, five criteria, including a browser check of the snippet on a site the binding lists and one it does not.TestIssue2332_*, three criteria, including ten events run one at a time and a failed run followed by the next event.TestIssue2333_*, two criteria: two images saved with their addresses on the row, and refused files saving nothing.TestIssue2337_*, three criteria, including the Changesets tab opened in a browser after a Keycloak sign-in.