Skip to content

Enrich 403 register response with structured permission hint

Placeholder ppxd requested to merge feat/permission-denied-hint into main

Summary

Operator-visible failure today: a Tentacle register call against an API key that lacks `MachineCreate` returns a bare HTTP 403 with a prose message. The operator has no way to know which role to assign without reading server source.

Three coordinated changes:

Server: `PermissionRoleResolver` maps a permission to its granting built-in roles. `SquidResponse` gains optional `MissingPermission` + `SuggestedRoles` fields (additive; null on non-403). `GlobalExceptionFilter` populates them on `PermissionDeniedException`.

Tentacle: New `PermissionDeniedRegistrationException` (extends `HttpRequestException`). `TentacleRegistrationClient` parses the structured 403 body; `TentacleEntry` catches the typed exception, emits a multi-line operator hint to stderr, exits with code 403 (instead of generic 1).

Install script (PR 1): already wraps `$LASTEXITCODE -eq 403` → operator copy-pasted snippet now surfaces the hint automatically.

Pinned: `MachineCreate` → `Environment Manager + Space Owner` (System Administrator is system-level only, deliberately omitted).

Test plan

  • Unit: 5 new PermissionRoleResolver tests + 3 new TentacleRegistrationClient tests
  • Backwards-compat: old server without structured fields → client falls back to generic exception (test pinned)
  • WAF robustness: malformed-JSON 403 body → generic exception, no crash (test pinned)
  • Build: zero errors across Squid.Core / Squid.Tentacle / Squid.Api

Depends on PR #329 (install-info.json + auto-elevation) to be in place for the install-script-side exit-code propagation to work end-to-end.

🤖 Generated with Claude Code

Merge request reports

Loading