mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-29 03:36:55 +00:00
feat(rbac): make Settings authorization permission-aware (#1738)
* feat(rbac): make Settings authorization permission-aware Align Settings visibility and mutations with the existing permission matrix so Node Admin can edit node-scoped operational settings while system and credential surfaces stay Admin-protected. * fix(rbac): tighten settings permission buckets and tests Collapse settings key permission maps into one source of truth, and cover mixed PATCH atomicity plus image-update enabled writes. * fix(rbac): tighten Settings scoped grants and CI assertions Empty settings PATCH fails closed, node:manage is scoped to the active node, system-only Settings stay hidden without system:settings, and Check updates / webhooks mutate gates follow the permission matrix. * fix(rbac): defer Settings section fallback until authz is ready Keep deep links to permission-gated sections (e.g. license) intact while can() is still fail-closed during permission metadata load. * docs(settings): clarify Notifications channels vs routing authz Channels use node:manage via /api/agents; routing and mute stay Admin-only.
This commit is contained in:
@@ -20,6 +20,7 @@ import { enforcePolicyPreDeploy } from '../services/PolicyEnforcement';
|
||||
import { HealthGateService } from '../services/HealthGateService';
|
||||
import { authMiddleware } from '../middleware/auth';
|
||||
import { requireAdmin } from '../middleware/tierGates';
|
||||
import { requirePermission } from '../middleware/permissions';
|
||||
import { buildPolicyGateOptions } from '../helpers/policyGate';
|
||||
import { FLEET_UPDATE_CACHE_KEY, invalidateFleetUpdateCache } from '../helpers/fleetUpdateCache';
|
||||
import { invalidateNodeCaches } from '../helpers/cacheInvalidation';
|
||||
@@ -75,7 +76,7 @@ imageUpdatesRouter.get('/detail', authMiddleware, (req: Request, res: Response):
|
||||
});
|
||||
|
||||
imageUpdatesRouter.post('/refresh', authMiddleware, (req: Request, res: Response): void => {
|
||||
if (!requireAdmin(req, res)) return;
|
||||
if (!requirePermission(req, res, 'node:manage', 'node', String(req.nodeId ?? 0))) return;
|
||||
try {
|
||||
if (!ImageUpdateService.isChecksEnabled()) {
|
||||
res.status(409).json({
|
||||
@@ -146,7 +147,7 @@ const IntervalPatchSchema = z.object({
|
||||
});
|
||||
|
||||
imageUpdatesRouter.put('/interval', authMiddleware, (req: Request, res: Response): void => {
|
||||
if (!requireAdmin(req, res)) return;
|
||||
if (!requirePermission(req, res, 'system:settings')) return;
|
||||
const parsed = IntervalPatchSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
res.status(400).json({ error: 'minutes must be an integer between 15 and 1440' });
|
||||
@@ -193,7 +194,7 @@ const EnabledPatchSchema = z.object({
|
||||
});
|
||||
|
||||
imageUpdatesRouter.put('/enabled', authMiddleware, (req: Request, res: Response): void => {
|
||||
if (!requireAdmin(req, res)) return;
|
||||
if (!requirePermission(req, res, 'system:settings')) return;
|
||||
const parsed = EnabledPatchSchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
res.status(400).json({ error: 'enabled must be a boolean' });
|
||||
|
||||
Reference in New Issue
Block a user