87 lines
4.7 KiB
Markdown
87 lines
4.7 KiB
Markdown
## ADDED Requirements
|
|
|
|
### Requirement: Least-privilege ACLs for group order models
|
|
|
|
`group.order` and `group.order.slot` SHALL NOT grant write, create or unlink to portal, public
|
|
or unassigned internal users. Write/create/unlink SHALL be limited to the group-order manager
|
|
group (`website_sale_aplicoop.group_group_order_manager`) and ERP admins. Read MAY be granted to
|
|
internal users and portal users through explicit, group-scoped ACLs (no empty `group_id` rows).
|
|
Controller mutations continue to run via `sudo()` and MUST NOT depend on broad ACLs.
|
|
|
|
#### Scenario: Portal user cannot mutate group orders
|
|
- **WHEN** a portal user calls the external API to `create`, `write` or `unlink` on `group.order`
|
|
or `group.order.slot`
|
|
- **THEN** the operation is denied with an `AccessError`
|
|
|
|
#### Scenario: Manager retains full access
|
|
- **WHEN** a user in `group_group_order_manager` creates or edits a `group.order` of their company
|
|
- **THEN** the operation succeeds
|
|
|
|
#### Scenario: Controllers still operate
|
|
- **WHEN** an authenticated portal member confirms a cart through the eskaera controller (which
|
|
uses `sudo()`)
|
|
- **THEN** the underlying `sale.order`/`group.order` writes succeed despite the tighter ACLs
|
|
|
|
### Requirement: Supplier cost not broadly exposed to portal
|
|
|
|
Portal users SHALL NOT read `product.supplierinfo` cost/price rows for products or vendors
|
|
unrelated to them. The unrestricted record rule (`domain=[(1,'=',1)]`) granting portal read on
|
|
`product.supplierinfo` SHALL NOT exist. The product **origin** and **main seller** shown in the
|
|
eskaera shop — currently painted from `supplierinfo` — MUST keep working, either by preparing those
|
|
values server-side (via `sudo()` in the controller, per the repo's "no logic in QWeb" rule) or via
|
|
a record rule scoped to the products the user can access, exposing no supplier cost/price fields.
|
|
|
|
#### Scenario: Portal user cannot list unrelated supplier cost
|
|
- **WHEN** a portal user calls `search_read` on `product.supplierinfo` via the external API
|
|
- **THEN** the result does not include supplier cost/price rows of products/vendors unrelated to
|
|
the user
|
|
|
|
#### Scenario: Origin and main seller still render
|
|
- **WHEN** a portal member opens the eskaera shop
|
|
- **THEN** each product's origin and main seller display correctly, without exposing supplier
|
|
cost/price across all vendors
|
|
|
|
### Requirement: CSRF protection on state-changing eskaera endpoints
|
|
|
|
State-changing eskaera endpoints SHALL be protected against cross-site request forgery. The
|
|
endpoints `/eskaera/save-order`, `/eskaera/confirm`, `/eskaera/clear-cart` and `/eskaera/save-cart`
|
|
(which create, confirm, merge or cancel `sale.order` records) SHALL NOT be `type="http"` with
|
|
`csrf=False`; they SHALL be `type="json"` (or otherwise validate a CSRF token) so that a cross-site
|
|
HTML form POST cannot trigger them.
|
|
|
|
#### Scenario: Cross-site form POST is rejected
|
|
- **WHEN** a logged-in user's browser is induced to submit a cross-site form POST to
|
|
`/eskaera/clear-cart` or `/eskaera/confirm`
|
|
- **THEN** the request is rejected and no order is cancelled/confirmed
|
|
|
|
#### Scenario: Legitimate same-origin call works
|
|
- **WHEN** the eskaera frontend submits the JSON-RPC request from the same origin
|
|
- **THEN** the order is created/confirmed as before
|
|
|
|
### Requirement: Consumer-group membership enforced on group-order endpoints
|
|
|
|
Every eskaera endpoint that resolves a `group.order` from a request id SHALL verify that the
|
|
requesting user belongs to a consumer group of that order before returning data. This applies to
|
|
`load_eskaera_page`, `load_products_ajax`, `add_to_eskaera_cart`, `eskaera_checkout` and
|
|
`check_group_order_status`, reusing `_validate_user_group_access` / `_get_consumer_group_for_user`.
|
|
Internal users MAY be exempt (matching `eskaera_shop`).
|
|
|
|
#### Scenario: Non-member gets no cross-group data
|
|
- **WHEN** a portal user who is not a member of a group order requests
|
|
`/eskaera/<order_id>/load-products-ajax` for that order
|
|
- **THEN** the endpoint returns empty/redirect and discloses no catalog or pricing of that order
|
|
|
|
#### Scenario: Member accesses own group order
|
|
- **WHEN** a portal member of the order's consumer group requests the same endpoint
|
|
- **THEN** the products and pricing are returned normally
|
|
|
|
### Requirement: Safe template output in inline scripts
|
|
|
|
QWeb templates SHALL NOT inject data into inline `<script>` blocks via `t-raw`. JSON payloads for
|
|
the client SHALL be emitted through a safe pattern (e.g. `<script type="application/json">` read by
|
|
the JS layer).
|
|
|
|
#### Scenario: Rendered history payload is not raw-injected
|
|
- **WHEN** the load-from-history template renders its JSON payload
|
|
- **THEN** the payload is emitted through a safe (escaped/typed) mechanism, not `t-raw` inside a
|
|
`<script>` tag
|