movidas openspec a /docs
This commit is contained in:
parent
0ef0c9951c
commit
aae6b6096e
9 changed files with 486 additions and 0 deletions
|
|
@ -0,0 +1,87 @@
|
|||
## 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue