fix(cabana): safe account action URLs, per-section isolation and the prompted record action contract (B-WR-03, B-WR-05, B-WR-06)
- an account action URL is kept only when it is http(s) with a host or a same-origin path; anything else is dropped and logged without the URL - a failing Status marks its section error: true and a failing Applies drops only that action, instead of a 500 for the whole list - status text goes through localizeDetail (B-IN-03); the non-string payload refusal is the phrase key action_prompt_invalid (B-IN-02) - the record action annotations and pact's prompt doc say what happens (B-IN-05 text); admin.json and schema.d.ts regenerated
This commit is contained in:
@@ -338,9 +338,13 @@ type AccountContributionView struct {
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
// Status is the section's line for the signed-in admin; "" when the
|
||||
// section has none.
|
||||
// section has none or its status could not be loaded.
|
||||
Status string `json:"status"`
|
||||
Actions []AccountContributionActionView `json:"actions"`
|
||||
// Error is true when the section's status could not be loaded (the
|
||||
// plugin's Status failed); the other sections are answered as usual.
|
||||
// Absent otherwise.
|
||||
Error bool `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// AccountContributionActionView is one button of a contributed section: the
|
||||
@@ -795,7 +799,7 @@ func AdminBulkAction() {}
|
||||
// AdminRecordAction documents the declared record action route.
|
||||
//
|
||||
// @Summary Run a declared record action
|
||||
// @Description Runs a record action the controller registers and the form's recordActions declares. The record is loaded and row-locked through the controller's form scope in one transaction (404 when missing or out of scope); an action that does not apply to the record's current state answers 409. The body must be {}: record_id, values and payload are all refused, and the answer's fill is always empty.
|
||||
// @Description Runs a record action the controller registers and the form's recordActions declares. The record is loaded and row-locked through the controller's form scope in one transaction (404 when missing or out of scope); an action that does not apply to the record's current state answers 409. The body is {} for an action without a prompt; an action whose record response carries prompt takes {"payload": "<text>"}, trimmed, non-empty and at most prompt.max_length runes, with a 422 on payload otherwise. record_id and values are always refused, and the answer's fill is always empty.
|
||||
// @Tags admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
@@ -805,7 +809,7 @@ func AdminBulkAction() {}
|
||||
// @Param controller path string true "Controller"
|
||||
// @Param id path integer true "Record id"
|
||||
// @Param action path string true "Record action name"
|
||||
// @Param body body AdminActionRequest true "Empty object"
|
||||
// @Param body body AdminActionRequest true "Empty object, or {payload: text} for a prompted action"
|
||||
// @Success 200 {object} Envelope[AdminActionResult]
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 403 {object} ErrorEnvelope "also returned when controller code refuses the write; details may name fields"
|
||||
@@ -824,7 +828,8 @@ type AdminActionRequest struct {
|
||||
Values map[string]any `json:"values,omitempty"`
|
||||
// Payload is the widget's own JSON value (the summer-action event's
|
||||
// detail.payload): any JSON, at most 64 KiB, handed to the action as-is.
|
||||
// Toolbar and record routes refuse it.
|
||||
// Toolbar routes refuse it; record routes accept it only for a prompted
|
||||
// action, as a JSON string (the prompt's answer).
|
||||
Payload json.RawMessage `json:"payload,omitempty"`
|
||||
}
|
||||
|
||||
@@ -863,7 +868,7 @@ func AdminWidgetAction() {}
|
||||
// AdminToolbarAction documents the toolbar action route.
|
||||
//
|
||||
// @Summary Run a toolbar action
|
||||
// @Description Runs a controller-registered action that the list's toolbar.buttons declares. The body must be {}: record_id, values and payload are all refused, and the answer's fill is always empty.
|
||||
// @Description Runs a controller-registered action that the list's toolbar.buttons declares. The body must be {}: the route refuses record_id, values and payload, and the answer's fill is always empty.
|
||||
// @Tags admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
|
||||
Reference in New Issue
Block a user