Refactor every /voicediag check to declare a top-level `standards` object so the desired state is legible without reading run() logic and can drive a documented reference table. Upgrade callForwarding to error severity, tighten voicemail with three send-to-VM error paths + a `stop_sending_to_voicemail` remediation, and add a `disable_hoteling` remediation. Add a port-hygiene check bucket under services/voiceDiag/checks/port (portType, portVlan, portPoe, portEnabled) that reuses the phone- status snapshot to enforce switchport standards. Configurable via VOICE_STANDARD_PHONE_VLAN (default 102) and VOICE_STANDARD_ENABLED (kill-switch). Preserve Meraki `portType`/`voiceVlan`/`dataVlan` through the enrichment chain so the checks have clean data to read. Add an "apply all N fixes" combined card that shows up when 2+ remediations are available. New confirm_voicediag_all / cancel_voicediag_all actions run each fix in sequence (readable audit trail, no per-person write-throttle stacking), accumulate individual failures into a summary rather than aborting. Adds regression tests asserting every check exposes .standards, plus coverage for port checks, kill-switch, and combined-card iteration. 63 tests in the checks file, 188 total, all green. Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
3.2 KiB
JavaScript
99 lines
3.2 KiB
JavaScript
// src/services/voiceDiag/checks/port/portEnabled.js
|
|
//
|
|
// Store phone standard: administratively enabled on every wired-
|
|
// phone switchport. If the port is admin-disabled the phone
|
|
// obviously won't work — this is a common footgun when a tech
|
|
// disables the wrong port during troubleshooting.
|
|
//
|
|
// Env kill-switch (shared with the other port checks) —
|
|
// VOICE_STANDARD_ENABLED=false → check reports skipped
|
|
// so operators can silence all port-hygiene noise while the
|
|
// underlying Meraki state is being cleaned up.
|
|
//
|
|
// Skip rules:
|
|
// - Wireless: skipped.
|
|
// - Trunk uplink: skipped (owned by portType check).
|
|
// - No portEnabled field at all: reported as unknown.
|
|
|
|
import { collectPortDevices, isWireless, portLabelFor, maybeSkippedByKillSwitch } from './_helpers.js';
|
|
|
|
export const PORT_ENABLED_STANDARDS = Object.freeze({
|
|
portEnabled: true,
|
|
});
|
|
|
|
export const portEnabledCheck = {
|
|
id: 'portEnabled',
|
|
label: 'Switchport Admin State',
|
|
requires: ['phoneStatus'],
|
|
scope: null,
|
|
standards: PORT_ENABLED_STANDARDS,
|
|
|
|
async run(ctx) {
|
|
const skip = maybeSkippedByKillSwitch(portEnabledCheck);
|
|
if (skip) return skip;
|
|
const devices = collectPortDevices(ctx.phoneStatus);
|
|
if (devices.length === 0) {
|
|
return {
|
|
status: 'skipped',
|
|
message: 'No wired devices with Meraki port data to inspect.',
|
|
details: null,
|
|
remediation: null,
|
|
};
|
|
}
|
|
|
|
const perDevice = devices.map((d) => {
|
|
if (isWireless(d)) {
|
|
return { ...portLabelFor(d), portEnabled: null, verdict: 'wireless' };
|
|
}
|
|
const portType = d.meraki?.portType;
|
|
if (portType && String(portType).toLowerCase() === 'trunk') {
|
|
return { ...portLabelFor(d), portEnabled: null, verdict: 'trunk-skip' };
|
|
}
|
|
const enabled = d.meraki?.portEnabled;
|
|
if (enabled === undefined || enabled === null) {
|
|
return { ...portLabelFor(d), portEnabled: null, verdict: 'unknown' };
|
|
}
|
|
return { ...portLabelFor(d), portEnabled: !!enabled, verdict: enabled ? 'compliant' : 'disabled' };
|
|
});
|
|
|
|
const disabled = perDevice.filter((r) => r.verdict === 'disabled');
|
|
const unknown = perDevice.filter((r) => r.verdict === 'unknown');
|
|
|
|
const details = {
|
|
total: perDevice.length,
|
|
compliant: perDevice.filter((r) => r.verdict === 'compliant').length,
|
|
disabled: disabled.length,
|
|
unknown: unknown.length,
|
|
wireless: perDevice.filter((r) => r.verdict === 'wireless').length,
|
|
trunkSkipped: perDevice.filter((r) => r.verdict === 'trunk-skip').length,
|
|
offenders: disabled,
|
|
};
|
|
|
|
if (disabled.length > 0) {
|
|
return {
|
|
status: 'error',
|
|
message:
|
|
`${disabled.length} device(s) on ADMIN-DISABLED switchports (phone will not work): ` +
|
|
disabled.map((r) => `${r.deviceLabel}@${r.portLabel}`).join(', '),
|
|
details,
|
|
remediation: null,
|
|
};
|
|
}
|
|
|
|
if (unknown.length > 0) {
|
|
return {
|
|
status: 'warn',
|
|
message: `${unknown.length} device(s) have no admin-state info from Meraki.`,
|
|
details,
|
|
remediation: null,
|
|
};
|
|
}
|
|
|
|
return {
|
|
status: 'ok',
|
|
message: `All ${details.compliant} wired switchports admin-enabled.`,
|
|
details,
|
|
remediation: null,
|
|
};
|
|
},
|
|
};
|