Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,27 @@ jobs:
Import-Module Pester -PassThru
Write-Host "[+] Pester installed successfully"

- name: Enable SSH Agent Service
shell: pwsh
run: |
Write-Host "[i] Enabling SSH agent service for tests..."

# Check if OpenSSH is installed
$sshAgent = Get-Service -Name "ssh-agent" -ErrorAction SilentlyContinue

if (-not $sshAgent) {
Write-Host "[i] Installing OpenSSH..."
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
}

# Set service to Manual and start it
Set-Service -Name "ssh-agent" -StartupType Manual
Start-Service -Name "ssh-agent"

# Verify
$service = Get-Service -Name "ssh-agent"
Write-Host "[+] SSH agent status: $($service.Status)"

- name: Run Windows tests
shell: pwsh
run: |
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/test-scripts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,27 @@ jobs:
Import-Module Pester
Import-Module PSScriptAnalyzer

- name: Enable SSH Agent Service
shell: pwsh
run: |
Write-Host "[i] Enabling SSH agent service for tests..."

# Check if OpenSSH is installed
$sshAgent = Get-Service -Name "ssh-agent" -ErrorAction SilentlyContinue

if (-not $sshAgent) {
Write-Host "[i] Installing OpenSSH..."
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
}

# Set service to Manual and start it
Set-Service -Name "ssh-agent" -StartupType Manual
Start-Service -Name "ssh-agent"

# Verify
$service = Get-Service -Name "ssh-agent"
Write-Host "[+] SSH agent status: $($service.Status)"

- name: Run PSScriptAnalyzer
shell: pwsh
run: |
Expand Down
49 changes: 49 additions & 0 deletions tests/TestHelpers.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,54 @@ function Test-NoPrivateIPs {
return $true
}

function Test-NoPrivateIPsInCode {
<#
.SYNOPSIS
Checks script for hardcoded private IPs in executable code only.
.DESCRIPTION
Uses PowerShell AST to parse the script and only checks non-comment,
non-string-literal tokens for private IP addresses. This allows
example IPs in documentation/comments while catching actual hardcoded IPs.
.PARAMETER Path
Path to the script file.
.OUTPUTS
Returns $true if no private IPs found in code, $false otherwise.
#>
[CmdletBinding()]
[OutputType([bool])]
param(
[Parameter(Mandatory = $true)]
[string]$Path
)

$tokens = $null
$errors = $null
[System.Management.Automation.Language.Parser]::ParseFile(
$Path, [ref]$tokens, [ref]$errors
) | Out-Null

$patterns = @(
'10\.\d{1,3}\.\d{1,3}\.\d{1,3}',
'172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}',
'192\.168\.\d{1,3}\.\d{1,3}'
)

$skipKinds = @('Comment', 'StringLiteral', 'StringExpandable',
'HereStringLiteral', 'HereStringExpandable')

foreach ($token in $tokens) {
if ($token.Kind -in $skipKinds) { continue }
foreach ($pattern in $patterns) {
if ($token.Text -match $pattern) {
Write-Warning "Private IP found in code at line $($token.Extent.StartLineNumber): $($Matches[0])"
return $false
}
}
}

return $true
}

# ============================================================================
# OUTPUT FORMAT HELPERS
# ============================================================================
Expand Down Expand Up @@ -429,6 +477,7 @@ Export-ModuleMember -Function @(
'Get-ScriptParameters'
'Test-NoHardcodedSecrets'
'Test-NoPrivateIPs'
'Test-NoPrivateIPsInCode'
'Test-ConsistentLogging'
'New-MockService'
'New-MockProcess'
Expand Down
17 changes: 14 additions & 3 deletions tests/Windows/Integration.Advanced.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,13 @@ Describe "Integration Tests - SSH Setup Workflow" {
}
}

It "Verifies SSH agent service is running" -Skip:(-not (Get-Service -Name 'ssh-agent' -ErrorAction SilentlyContinue)) {
# Assert if service exists
It "Verifies SSH agent service is running" {
# Check if ssh-agent service exists
$service = Get-Service -Name 'ssh-agent' -ErrorAction SilentlyContinue
if (-not $service) {
Set-ItResult -Skipped -Because "SSH agent service is not installed"
return
}
$service | Should -Not -BeNullOrEmpty
}

Expand Down Expand Up @@ -400,7 +404,14 @@ Describe "Integration Tests - Full Workflow Scenarios" {
Mock-NetworkCommands -ReachableHosts @('github.com', 'registry.npmjs.org')
}

It "Validates environment before starting setup" -Skip:(-not ((Get-Service -Name 'ssh-agent' -ErrorAction SilentlyContinue).Status -eq 'Running')) {
It "Validates environment before starting setup" {
# Check if ssh-agent is running, skip if not
$sshAgent = Get-Service -Name 'ssh-agent' -ErrorAction SilentlyContinue
if (-not $sshAgent -or $sshAgent.Status -ne 'Running') {
Set-ItResult -Skipped -Because "SSH agent service is not running"
return
}

# Arrange
$requiredServices = @('ssh-agent')

Expand Down
48 changes: 36 additions & 12 deletions tests/Windows/Integration.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ Describe "Cross-Script Integration" {
$scriptExists | Should -Be $true
}

It "SSH setup script can be parsed" -Skip:(-not $scriptExists) {
It "SSH setup script can be parsed" {
if (-not $scriptExists) {
Set-ItResult -Skipped -Because "SSH setup script does not exist"
return
}
{ [scriptblock]::Create((Get-Content $setupScript -Raw)) } | Should -Not -Throw
}

Expand Down Expand Up @@ -186,21 +190,41 @@ Describe "Security Integration Tests" {
$foundSecrets | Should -BeNullOrEmpty
}

It "No scripts contain private IPs (except examples)" -Skip {
# Skipped: Sysadmin toolkit scripts legitimately contain example IPs for documentation
$scriptsToCheck = $allScripts | Where-Object {
$_.FullName -notmatch 'examples|docs|README'
}
It "No scripts contain private IPs in executable code" {
# Uses AST-based detection: allows IPs in comments/strings (documentation)
# but rejects them in actual executable code
$privateIpPatterns = @(
'10\.\d{1,3}\.\d{1,3}\.\d{1,3}',
'172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}',
'192\.168\.\d{1,3}\.\d{1,3}'
)

$foundPrivateIPs = @()
foreach ($script in $scriptsToCheck) {
$result = Test-NoPrivateIPs -Path $script.FullName -AllowExampleIPs
if (-not $result) {
$foundPrivateIPs += $script.Name
$foundProblems = @()

foreach ($script in $allScripts) {
$tokens = $null
$errors = $null
[System.Management.Automation.Language.Parser]::ParseFile(
$script.FullName, [ref]$tokens, [ref]$errors
) | Out-Null

foreach ($token in $tokens) {
# Skip comments and string literals (documentation/examples are OK)
$skipKinds = @('Comment', 'StringLiteral', 'StringExpandable',
'HereStringLiteral', 'HereStringExpandable')
if ($token.Kind -in $skipKinds) {
continue
}

foreach ($pattern in $privateIpPatterns) {
if ($token.Text -match $pattern) {
$foundProblems += "$($script.Name):$($token.Extent.StartLineNumber)"
}
}
}
}

$foundPrivateIPs | Should -BeNullOrEmpty
$foundProblems | Should -BeNullOrEmpty
}
}

Expand Down
36 changes: 23 additions & 13 deletions tests/Windows/Tier3Scripts.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -682,21 +682,31 @@ Describe "Tier 3 Scripts - Standards Compliance" -Tag "Standards", "Tier3" {
}
}

Describe "Tier 3 Scripts - SupportsShouldProcess" -Tag "ShouldProcess", "Tier3" -Skip {
# Skipped: SupportsShouldProcess is a future enhancement, not currently implemented
$scriptsWithShouldProcess = @('Backup-BrowserProfiles', 'Manage-VPN', 'Manage-WSL', 'Manage-Docker')
Describe "Tier 3 Scripts - SupportsShouldProcess" -Tag "ShouldProcess", "Tier3" {
BeforeDiscovery {
# Initialize paths during discovery for -ForEach
$testRoot = Split-Path -Parent $PSScriptRoot
$repoRoot = Split-Path -Parent $testRoot
$windowsRoot = Join-Path $repoRoot "Windows"

$script:ShouldProcessScripts = @(
@{ Name = 'Backup-BrowserProfiles'; Path = (Join-Path $windowsRoot "backup\Backup-BrowserProfiles.ps1") }
@{ Name = 'Manage-VPN'; Path = (Join-Path $windowsRoot "network\Manage-VPN.ps1") }
@{ Name = 'Manage-WSL'; Path = (Join-Path $windowsRoot "development\Manage-WSL.ps1") }
@{ Name = 'Manage-Docker'; Path = (Join-Path $windowsRoot "development\Manage-Docker.ps1") }
)
}

foreach ($scriptName in $scriptsWithShouldProcess) {
Context "$scriptName ShouldProcess support" {
It "Should have SupportsShouldProcess = `$true" {
$content = Get-Content $script:Tier3Scripts[$scriptName] -Raw
$content | Should -Match 'SupportsShouldProcess\s*=\s*\$true'
}
# All Tier 3 scripts now implement SupportsShouldProcess
Context "<Name> ShouldProcess support" -ForEach $script:ShouldProcessScripts {
It "Should have SupportsShouldProcess = `$true" {
$content = Get-Content $Path -Raw
$content | Should -Match 'SupportsShouldProcess\s*=\s*\$true'
}

It "Should use PSCmdlet.ShouldProcess for destructive operations" {
$content = Get-Content $script:Tier3Scripts[$scriptName] -Raw
$content | Should -Match '\$PSCmdlet\.ShouldProcess'
}
It "Should use PSCmdlet.ShouldProcess for destructive operations" {
$content = Get-Content $Path -Raw
$content | Should -Match '\$PSCmdlet\.ShouldProcess'
}
}
}
Loading