mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-07-13 13:10:01 +00:00
6d7473b56f
Phase 0b of tenant tool config refactor. Closes 3 privilege-escalation
vulnerabilities in the same bug class as commit b419f352 (Phase 1
config.* hotfix):
- CRITICAL: PUT /v1/tools/builtin/{name} — non-master tenant admin
could overwrite global builtin_tools.settings, corrupting tool
defaults for every tenant.
- CRITICAL: POST /v1/packages/install|uninstall — non-master tenant
admin could run pip/npm/apk server-wide. Supply-chain vector.
- HIGH: POST /v1/api-keys/{id}/revoke (HTTP + WS) — tenant admin
could revoke NULL-tenant system keys because store SQL matches
(tenant_id = \$N OR tenant_id IS NULL).
Implementation:
- Export store.IsMasterScope as the single predicate; rewire Phase 1
config.* middleware to delegate (no behaviour change).
- Add http.requireMasterScope helper symmetric to requireTenantAdmin.
- Guard handleUpdate (builtin_tools) and handleInstall/handleUninstall
(packages) with master-scope check before any mutation or shell exec.
- Fix api_keys.Revoke at the handler layer: fetch key via new
APIKeyStore.Get, verify key.TenantID matches caller tenant for
non-owner callers. Applies to both HTTP and WS paths.
- Harden WS router to inject role into ctx so store.IsOwnerRole works
from WS handlers (closes a latent drift between the HTTP and WS
layers that broke the initial WS api_keys.revoke fix).
- Drop unused APIKeyStore.Delete (YAGNI + removes dormant vuln with
the same tenant_id IS NULL arm).
- Emit security.tenant_scope_violation and security.api_key_revoke_
forbidden slog events on every rejection for future SIEM alerting.
- New MsgMasterScopeRequired i18n key + en/vi/zh catalogs.
Tests cover the guard predicate, all 3 HTTP endpoints, and the full
WS api_keys.revoke matrix (cross-tenant deny, system-key deny for
tenant admins, system owner bypass, own-tenant happy path). 14 other
admin-gated write endpoints verified safe by static audit.
24 lines
743 B
Go
24 lines
743 B
Go
package gateway
|
|
|
|
import (
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/permissions"
|
|
)
|
|
|
|
// NewTestClient returns a minimally-wired Client for unit tests in other
|
|
// packages. Role + tenant are set directly because the underlying fields are
|
|
// unexported. SendResponse is safe because the send channel is nil — the
|
|
// writer hits the default branch of the select and drops the frame silently.
|
|
//
|
|
// Not for production use. Any non-test caller should use NewClient instead.
|
|
func NewTestClient(role permissions.Role, tenantID uuid.UUID, userID string) *Client {
|
|
return &Client{
|
|
id: uuid.NewString(),
|
|
authenticated: true,
|
|
role: role,
|
|
userID: userID,
|
|
tenantID: tenantID,
|
|
}
|
|
}
|