mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-26 11:49:16 +00:00
fix(fleet): drop tier gate from stack and container list endpoints (#1012)
Community tier opened the Fleet Overview drilldown (node card → stack list → container list) but two read-only metadata endpoints in fleet.ts kept their requirePaid gate. Stack names still rendered because they ride on the un-gated /api/fleet/overview payload, but expanding a stack always re-fetched containers and hit the orphan gate, surfacing as a "Failed to load containers for X" toast on every node card on Community. Drop requirePaid from GET /node/:nodeId/stacks and GET /node/:nodeId/stacks/:stackName/containers. Both handlers stay behind authMiddleware, validate inputs, and proxy to the per-node api_token for remote nodes. Paid mutations (bulk update, scheduled snapshots, label bulk actions, Fleet Actions cards) keep their gates in fleetActions.ts. Add positive Community-tier tests in fleet.test.ts and clear the stale "Requires Skipper or Admiral license" line from the OpenAPI descriptions.
This commit is contained in:
@@ -205,6 +205,22 @@ describe('Fleet tier gating', () => {
|
||||
.set('Authorization', authHeader);
|
||||
expect(res.body.code).not.toBe('PAID_REQUIRED');
|
||||
});
|
||||
|
||||
it('GET /api/fleet/node/:nodeId/stacks is accessible on community tier', async () => {
|
||||
mockTier('community');
|
||||
const res = await request(app)
|
||||
.get('/api/fleet/node/1/stacks')
|
||||
.set('Authorization', authHeader);
|
||||
expect(res.body.code).not.toBe('PAID_REQUIRED');
|
||||
});
|
||||
|
||||
it('GET /api/fleet/node/:nodeId/stacks/:stackName/containers is accessible on community tier', async () => {
|
||||
mockTier('community');
|
||||
const res = await request(app)
|
||||
.get('/api/fleet/node/1/stacks/db-compose/containers')
|
||||
.set('Authorization', authHeader);
|
||||
expect(res.body.code).not.toBe('PAID_REQUIRED');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Update Endpoint Input Validation ───
|
||||
|
||||
@@ -595,8 +595,6 @@ fleetRouter.get('/configuration', authMiddleware, async (req: Request, res: Resp
|
||||
});
|
||||
|
||||
fleetRouter.get('/node/:nodeId/stacks', authMiddleware, async (req: Request, res: Response): Promise<void> => {
|
||||
if (!requirePaid(req, res)) return;
|
||||
|
||||
try {
|
||||
const nodeId = parseIntParam(req, res, 'nodeId', 'node ID');
|
||||
if (nodeId === null) return;
|
||||
@@ -635,8 +633,6 @@ fleetRouter.get('/node/:nodeId/stacks', authMiddleware, async (req: Request, res
|
||||
});
|
||||
|
||||
fleetRouter.get('/node/:nodeId/stacks/:stackName/containers', authMiddleware, async (req: Request, res: Response): Promise<void> => {
|
||||
if (!requirePaid(req, res)) return;
|
||||
|
||||
try {
|
||||
const nodeId = parseIntParam(req, res, 'nodeId', 'node ID');
|
||||
if (nodeId === null) return;
|
||||
|
||||
+2
-2
@@ -1888,7 +1888,7 @@ paths:
|
||||
operationId: getFleetNodeStacks
|
||||
tags: [Fleet]
|
||||
summary: List stacks on a fleet node
|
||||
description: Returns stack names from a specific fleet node. Requires Skipper or Admiral license.
|
||||
description: Returns stack names from a specific fleet node.
|
||||
parameters:
|
||||
- name: nodeId
|
||||
in: path
|
||||
@@ -1928,7 +1928,7 @@ paths:
|
||||
operationId: getFleetNodeStackContainers
|
||||
tags: [Fleet]
|
||||
summary: List containers in a fleet node stack
|
||||
description: Returns containers for a specific stack on a specific fleet node. Requires Skipper or Admiral license.
|
||||
description: Returns containers for a specific stack on a specific fleet node.
|
||||
parameters:
|
||||
- name: nodeId
|
||||
in: path
|
||||
|
||||
Reference in New Issue
Block a user