mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-20 07:13:05 +00:00
feat: block self-stack lifecycle ops with UI and preflight guardrails (#1569)
* feat: block self-stack lifecycle ops with UI and preflight guardrails Refuse update, deploy, down, stop, and delete when the stack matches Sencho's compose project. Return 409 self_stack_protected. Expose isSelf on /statuses and disable guarded UI actions. Add SelfStackProtectedDialog and self-managed-stack preflight warning. Closes #1564 * fix: add missing stackSelfFlags mock to useSidebarContextMenu test The production hook now reads stackListState.stackSelfFlags[file], but the test mock did not include it, causing 6 tests to fail with TypeError: Cannot read properties of undefined (reading 'web.yml'). * fix: harden self-stack protection during startup Add a global environment preflight warning when Sencho is managed inside COMPOSE_DIR. Align status decoration and route guards on Docker label fallback detection. Block rollback and service-level stop on the protected self stack. * fix: add self_stack_location to diagnostics-route expected check IDs
This commit is contained in:
@@ -608,6 +608,20 @@ const effectiveModelExpanded: PreflightRule = {
|
||||
},
|
||||
};
|
||||
|
||||
const selfManagedStack: PreflightRule = {
|
||||
id: 'self-managed-stack',
|
||||
run(ctx) {
|
||||
if (!ctx.isSelfStack) return [];
|
||||
return [{
|
||||
ruleId: 'self-managed-stack',
|
||||
severity: 'warning',
|
||||
title: 'This stack is the running Sencho instance',
|
||||
message: 'Sencho discovered its own compose project as a managed stack. Generic deploy, update, stop, down, and delete actions are blocked here because they would recreate or remove the dashboard you are using.',
|
||||
remediation: 'Update Sencho via Fleet -> Node Update. To manage it as a normal stack, move its compose project outside COMPOSE_DIR.',
|
||||
}];
|
||||
},
|
||||
};
|
||||
|
||||
// ----- exposure-intent rules ------------------------------------------------
|
||||
// These read the user's stored exposure classification (resolved per service)
|
||||
// and the dossier's documented access URLs from the context, plus a sensitivity
|
||||
@@ -785,6 +799,7 @@ export const PREFLIGHT_RULES: PreflightRule[] = [
|
||||
exposurePortVsDossier,
|
||||
reverseProxyUndocumented,
|
||||
effectiveModelExpanded,
|
||||
selfManagedStack,
|
||||
];
|
||||
|
||||
export const RULE_IDS: readonly string[] = PREFLIGHT_RULES.map(r => r.id);
|
||||
|
||||
@@ -125,4 +125,6 @@ export interface PreflightContext {
|
||||
accessUrlPorts: Set<number>;
|
||||
/** Whether the dossier records any access URL (gates the port-vs-documented rule). */
|
||||
hasAccessUrls: boolean;
|
||||
/** True when this stack is the running Sencho instance on the node. */
|
||||
isSelfStack: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user