Files
deusdata--codebase-memory-mcp/scripts/ci/ensure-defender.ps1
Martin Vogel 0a40fe8bea feat(ci): local-remote parity lanes — artifact-flow smoke, glibc floor, Defender-ON everywhere
Closes the closable local-vs-remote venue gaps so that, outside arch
legs / YAML glue / release plumbing, every local red is a remote red
and vice versa on shared legs:

- scripts/package-release.sh: THE canonical archive step (names +
  five-file Windows bundle layout defined once); _build.yml's eight
  inline archive blocks become calls to it.
- scripts/ci/smoke-artifact.sh: the artifact-flow smoke lane — build,
  package, extract, then the canonical wrapper in artifact mode; wired
  as run.sh smoke-artifact (compose service), win.sh smoke-artifact,
  and directly runnable on macOS. Archive-layout bugs now surface
  locally instead of in a release dry run.
- glibc-floor leg (Dockerfile.glibc22 + compose + run.sh): portable
  binary smokes on ubuntu-22.04/glibc 2.35; the dynamic binary must
  refuse there (2.38+ floor by design).
- Defender-ON parity (user directive): scripts/ci/ensure-defender.ps1
  enables + VERIFIES real-time protection, fail-closed; runs in every
  Windows CI job (_test x2, _soak x3, _smoke, pr.yml) AND in the VM
  preflight; _smoke.yml's scan engine-failure soft-skip becomes a red
  gate. Expected cost: slower Windows jobs (AV scanning during
  install/build/test I/O); the next dry run proves the runner side.
- Contracts: launcher-bundle five-file check retargeted onto
  package-release.sh + per-archive canonical-call association;
  venue-parity contract requires the new lanes, counts one
  ensure-defender step per Windows job, adds --help probes for the new
  entries. Extended contract fails on the pre-change tree (verified:
  20 violations on HEAD).
- VM README: ephemerality/Defender posture documented — utmctl has no
  snapshot verb, so per-run revert stays a manual qcow2 option; the
  sweep preflight remains the standing mechanism.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-07-26 22:37:48 +02:00

60 lines
2.1 KiB
PowerShell

# ensure-defender.ps1 — Windows Defender real-time protection must be ACTIVE
# on every Windows venue: the local test VM and every GitHub Windows runner
# alike. The AV interaction surface (file locks on fresh binaries, scan-on-
# first-execute latency, quarantine behavior) is part of what the Windows legs
# test; a venue with Defender off is testing a different operating system.
#
# GitHub's runner images ship with Defender disabled, so this script ENABLES
# it, then VERIFIES it is actually running — and fails closed if it cannot be
# made active. No silent skip: a leg that cannot get Defender on must go red,
# not quietly measure the wrong environment. (Same doctrine as the smoke
# no-skip rules: a gate that can be skipped is not a gate.)
#
# Canonical entry: local VM preflight (win.sh) and the Windows CI jobs all run
# THIS file — venue parity by construction.
$ErrorActionPreference = 'Stop'
function Try-Step {
param([string]$What, [scriptblock]$Action)
try {
& $Action
Write-Host "ensure-defender: $What - ok"
} catch {
# Individual enable steps may legitimately no-op (already enabled,
# service already running); only the final verification gates.
Write-Host "ensure-defender: $What - $($_.Exception.Message)"
}
}
Try-Step "WinDefend service startup type" {
Set-Service -Name WinDefend -StartupType Automatic
}
Try-Step "WinDefend service start" {
Start-Service -Name WinDefend
}
Try-Step "enable real-time monitoring" {
Set-MpPreference -DisableRealtimeMonitoring $false
}
$status = $null
try {
$status = Get-MpComputerStatus
} catch {
Write-Host "ensure-defender: FAIL - Defender engine unavailable: $($_.Exception.Message)"
exit 1
}
if (-not $status.AntivirusEnabled) {
Write-Host "ensure-defender: FAIL - antivirus engine is not enabled on this venue"
exit 1
}
if (-not $status.RealTimeProtectionEnabled) {
Write-Host "ensure-defender: FAIL - real-time protection is OFF and could not be enabled"
exit 1
}
Write-Host ("=== ensure-defender: ACTIVE (engine {0}, signatures {1}, RTP on) ===" -f `
$status.AMEngineVersion, $status.AntivirusSignatureVersion)
exit 0