mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-31 12:48:10 +00:00
fix: probe remote RBAC capability live and enforce exact stop-result membership (#1510)
The cross-node capability gate cached its verdict, so a remote replaced by older code at the same URL stayed trusted until the cache expired, reopening the non-admin HTTP escalation and the over-broad stop. The probe now hits the remote's live /api/meta on every gated action (concurrent calls deduped, never cached across requests, fail-closed), so a downgraded remote is detected immediately. Two stop-result gaps are also closed: - A remote stop result must now cover exactly the confirmed stacks (one per stack, no extras, no omissions), not merely exclude extras, so a dropped confirmed stack is no longer accepted as clean. runLocalLabelStop reports one result per confirmed stack even when the label has vanished, so a current remote always satisfies the check. - The local stop exception path now reports the full confirmed set, so a confirmed stack that lost its label is not dropped when the local stop throws.
This commit is contained in:
@@ -420,6 +420,22 @@ describe('local-stop behavior', () => {
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.results).toEqual([{ stackName: 'ghostdisk-stack', success: false, error: 'Stack not found on this node' }]);
|
||||
});
|
||||
|
||||
it('reports one failure per confirmed stack when the label no longer exists', async () => {
|
||||
// The label vanished between preview and execution. With a confirmed
|
||||
// allowlist the receiver must return one result per confirmed stack (so the
|
||||
// control's exact-membership check sees a complete set), not an empty body.
|
||||
const res = await request(app)
|
||||
.post('/api/fleet-actions/labels/local-stop')
|
||||
.set('Authorization', authHeader)
|
||||
.send({ labelName: 'no-such-label', dryRun: true, stackNames: ['gone-a', 'gone-b'] });
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body.matched).toBe(false);
|
||||
expect(res.body.results).toEqual([
|
||||
{ stackName: 'gone-a', success: false, error: 'No longer carries this label' },
|
||||
{ stackName: 'gone-b', success: false, error: 'No longer carries this label' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
// Orchestrator-level binding: the control sends the exact node + stack list the
|
||||
|
||||
Reference in New Issue
Block a user