docs: state the scopes for token regeneration and resource links

Follows the token scope fixes. POST /api/security/regenerate-token now
needs an instance-wide full-access token from API-token callers and
replaces every stored token; the reference says so and points scoped
tokens at the per-token rotate route. POST /api/resources/{id}/link,
/unlink and /report-merge need monitoring:write.

test_api_reference_routes.py pins each of these to the code that
enforces it, so the reference and the gates cannot drift apart again.
Each pin fails when the code or the reference is reverted.

Contract-Neutral: Customer docs corrected to match shipped behaviour; no runtime, API or contract change.
This commit is contained in:
rcourtman
2026-10-11 16:34:02 +01:00
parent 7482418db3
commit a65e18d9b3
3 changed files with 36 additions and 10 deletions
+11 -5
View File
@@ -356,19 +356,19 @@ Returns child resources for the parent ID.
`GET /api/resources/{id}/metrics`
Returns the resource metrics payload.
`POST /api/resources/{id}/link`
`POST /api/resources/{id}/link` (`monitoring:write`)
Manually link two resources.
```json
{ "targetId": "resource-id", "reason": "optional note" }
```
`POST /api/resources/{id}/unlink`
`POST /api/resources/{id}/unlink` (`monitoring:write`)
Manually unlink two resources.
```json
{ "targetId": "resource-id", "reason": "optional note" }
```
`POST /api/resources/{id}/report-merge`
`POST /api/resources/{id}/report-merge` (`monitoring:write`)
Report an incorrect merge (creates exclusions).
```json
{ "sources": ["proxmox", "agent"], "notes": "optional note" }
@@ -1130,9 +1130,15 @@ Supports actions:
Callers need an admin session, or an API token with the `settings:write` scope; a token without that scope gets `403` with `error: "missing_scope"`. Identifier can be a username or IP address. An empty identifier returns `400 missing_identifier`. Success returns `{ "success": true, "message": "Lockout reset for admin" }`.
### Regenerate API Token (Admin)
`POST /api/security/regenerate-token`
`POST /api/security/regenerate-token` (admin, `settings:write`)
Returns a new raw token (shown once) and updates stored hashes:
Replaces every stored API token with one new full-access token. All other
tokens stop working. An API token may call this only if it has full-access
scope (`*`) and is not bound to a non-default organization; any other token
gets `403`, and should use `POST /api/security/tokens/{id}/rotate` to replace
just itself.
Returns the new raw token (shown once) and updates stored hashes:
```json
{
"success": true,
+11 -5
View File
@@ -356,19 +356,19 @@ Returns child resources for the parent ID.
`GET /api/resources/{id}/metrics`
Returns the resource metrics payload.
`POST /api/resources/{id}/link`
`POST /api/resources/{id}/link` (`monitoring:write`)
Manually link two resources.
```json
{ "targetId": "resource-id", "reason": "optional note" }
```
`POST /api/resources/{id}/unlink`
`POST /api/resources/{id}/unlink` (`monitoring:write`)
Manually unlink two resources.
```json
{ "targetId": "resource-id", "reason": "optional note" }
```
`POST /api/resources/{id}/report-merge`
`POST /api/resources/{id}/report-merge` (`monitoring:write`)
Report an incorrect merge (creates exclusions).
```json
{ "sources": ["proxmox", "agent"], "notes": "optional note" }
@@ -1130,9 +1130,15 @@ Supports actions:
Callers need an admin session, or an API token with the `settings:write` scope; a token without that scope gets `403` with `error: "missing_scope"`. Identifier can be a username or IP address. An empty identifier returns `400 missing_identifier`. Success returns `{ "success": true, "message": "Lockout reset for admin" }`.
### Regenerate API Token (Admin)
`POST /api/security/regenerate-token`
`POST /api/security/regenerate-token` (admin, `settings:write`)
Returns a new raw token (shown once) and updates stored hashes:
Replaces every stored API token with one new full-access token. All other
tokens stop working. An API token may call this only if it has full-access
scope (`*`) and is not bound to a non-default organization; any other token
gets `403`, and should use `POST /api/security/tokens/{id}/rotate` to replace
just itself.
Returns the new raw token (shown once) and updates stored hashes:
```json
{
"success": true,
@@ -79,6 +79,20 @@ ROUTE_ANCHORS = [
("Token callers also need `settings:write` on every profile route, including GET requests",
"internal/api/router_routes_registration.go",
'r.mux.Handle("/api/admin/profiles/", RequireAdmin(r.config, RequireScope(config.ScopeSettingsWrite,'),
# Everything other than GET or HEAD on the /api/resources/ prefix needs the write scope.
("`POST /api/resources/{id}/link` (`monitoring:write`)",
"internal/api/router_routes_monitoring.go",
"if req.Method != http.MethodGet && req.Method != http.MethodHead {\n\t\t\tscope = config.ScopeMonitoringWrite"),
("`POST /api/resources/{id}/unlink` (`monitoring:write`)",
"internal/api/router_routes_monitoring.go",
"if req.Method != http.MethodGet && req.Method != http.MethodHead {\n\t\t\tscope = config.ScopeMonitoringWrite"),
("`POST /api/resources/{id}/report-merge` (`monitoring:write`)",
"internal/api/router_routes_monitoring.go",
"if req.Method != http.MethodGet && req.Method != http.MethodHead {\n\t\t\tscope = config.ScopeMonitoringWrite"),
# Regeneration replaces the whole inventory, so a token caller must be instance-wide.
("An API token may call this only if it has full-access\nscope (`*`) and is not bound to a non-default organization",
"internal/api/security_setup_fix.go",
"!tokenHasInstanceWideAuthority(callerToken)"),
("`PUT /api/notifications/email` (admin, `settings:write`)",
"internal/api/alerting/notifications.go",
'case path == "/email" && r.Method == http.MethodPut:\n\t\tif !requireAnyScope(config.ScopeSettingsWrite'),