|
2 | 2 | import { describe, expect, it, vi } from "vitest"; |
3 | 3 | import { |
4 | 4 | DEFAULT_WINDOWS_GATEWAY_FIREWALL_TIMEOUT_MS, |
| 5 | + QUICK_WINDOWS_GATEWAY_FIREWALL_TIMEOUT_MS, |
5 | 6 | inspectWindowsGatewayFirewall, |
6 | 7 | parseWindowsGatewayFirewallState, |
7 | 8 | classifyWindowsGatewayFirewallState, |
@@ -103,6 +104,18 @@ function ruleJson(params?: { |
103 | 104 | return JSON.stringify([ruleRow(params)]); |
104 | 105 | } |
105 | 106 |
|
| 107 | +function quickPayloadJson(params?: { |
| 108 | + state?: string; |
| 109 | + activeRules?: Array<Record<string, unknown>>; |
| 110 | + localRules?: Array<Record<string, unknown>>; |
| 111 | +}) { |
| 112 | + return JSON.stringify({ |
| 113 | + State: JSON.parse(params?.state ?? stateJson({ localAllowRules: "True" })), |
| 114 | + ActiveRules: params?.activeRules ?? [], |
| 115 | + LocalRules: params?.localRules ?? [ruleRow()], |
| 116 | + }); |
| 117 | +} |
| 118 | + |
106 | 119 | function rulesPayloadJson(params: { active?: unknown[]; local?: unknown[] }) { |
107 | 120 | return JSON.stringify({ |
108 | 121 | ActiveRules: params.active ?? [], |
@@ -527,7 +540,75 @@ describe("Windows Gateway firewall diagnostics", () => { |
527 | 540 | }); |
528 | 541 | }); |
529 | 542 |
|
530 | | - it("runs bounded read-only Windows probes for LAN binding", async () => { |
| 543 | + it("runs a quick bounded Windows probe without netsh or follow-up commands", async () => { |
| 544 | + const runner = vi.fn<WindowsGatewayFirewallCommandRunner>(async (argv) => { |
| 545 | + const command = argv.join(" "); |
| 546 | + expect(command).toContain("Get-NetConnectionProfile"); |
| 547 | + expect(command).toContain("HNetCfg.FwPolicy2"); |
| 548 | + expect(command).toContain("Get-NetFirewallRule"); |
| 549 | + expect(command).toContain("PolicyStore ActiveStore"); |
| 550 | + expect(command).toContain("foreach ($entry in @($value))"); |
| 551 | + expect(command).not.toContain("advfirewall"); |
| 552 | + expect(command).not.toContain("PolicyStore PersistentStore"); |
| 553 | + return { code: 0, stdout: quickPayloadJson() }; |
| 554 | + }); |
| 555 | + |
| 556 | + await expect( |
| 557 | + inspectWindowsGatewayFirewall({ |
| 558 | + bind: "lan", |
| 559 | + mode: "quick", |
| 560 | + port: 18789, |
| 561 | + platform: "win32", |
| 562 | + runCommandWithTimeout: runner, |
| 563 | + }), |
| 564 | + ).resolves.toMatchObject({ |
| 565 | + code: "windows_firewall_rule_present", |
| 566 | + }); |
| 567 | + expect(runner).toHaveBeenCalledTimes(1); |
| 568 | + expect(runner.mock.calls[0]?.[0][0]).toBe(getWindowsPowerShellExePath()); |
| 569 | + expect(runner.mock.calls[0]?.[1]).toMatchObject({ |
| 570 | + timeoutMs: QUICK_WINDOWS_GATEWAY_FIREWALL_TIMEOUT_MS, |
| 571 | + }); |
| 572 | + }); |
| 573 | + |
| 574 | + it("preserves managed ActiveStore allow rules during quick inspection", async () => { |
| 575 | + const runner = vi.fn<WindowsGatewayFirewallCommandRunner>(async (argv) => { |
| 576 | + const command = argv.join(" "); |
| 577 | + expect(command).toContain("Get-NetFirewallRule"); |
| 578 | + expect(command).toContain("GroupPolicy"); |
| 579 | + expect(command).toContain("MDM"); |
| 580 | + return { |
| 581 | + code: 0, |
| 582 | + stdout: quickPayloadJson({ |
| 583 | + state: stateJson({ activeAllowLocalRules: "False" }), |
| 584 | + activeRules: [ |
| 585 | + ruleRow({ |
| 586 | + displayName: "MDM-managed Gateway allow", |
| 587 | + policyStoreSource: "Intune", |
| 588 | + policyStoreSourceType: "MDM", |
| 589 | + }), |
| 590 | + ], |
| 591 | + localRules: [ruleRow({ displayName: "Ignored local allow" })], |
| 592 | + }), |
| 593 | + }; |
| 594 | + }); |
| 595 | + |
| 596 | + await expect( |
| 597 | + inspectWindowsGatewayFirewall({ |
| 598 | + bind: "lan", |
| 599 | + mode: "quick", |
| 600 | + port: 18789, |
| 601 | + platform: "win32", |
| 602 | + runCommandWithTimeout: runner, |
| 603 | + }), |
| 604 | + ).resolves.toMatchObject({ |
| 605 | + severity: "info", |
| 606 | + code: "windows_firewall_rule_present", |
| 607 | + }); |
| 608 | + expect(runner).toHaveBeenCalledTimes(1); |
| 609 | + }); |
| 610 | + |
| 611 | + it("runs bounded read-only full Windows probes for LAN binding", async () => { |
531 | 612 | const runner = vi.fn<WindowsGatewayFirewallCommandRunner>(async (argv) => { |
532 | 613 | const command = argv.join(" "); |
533 | 614 | if (command.includes("Get-NetConnectionProfile")) { |
|
0 commit comments