Skip to content

Commit da33465

Browse files
authored
Merge pull request #1 from Moefire/develop
first verison
2 parents 691abba + 4451915 commit da33465

8 files changed

Lines changed: 1704 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main ]
8+
workflow_dispatch:
9+
10+
jobs:
11+
test:
12+
name: Test on Windows
13+
runs-on: windows-latest
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Install PSScriptAnalyzer
20+
shell: pwsh
21+
run: |
22+
Set-PSRepository PSGallery -InstallationPolicy Trusted
23+
Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser
24+
25+
- name: Install Pester
26+
shell: pwsh
27+
run: |
28+
Install-Module -Name Pester -Force -Scope CurrentUser -MinimumVersion 5.0.0 -SkipPublisherCheck
29+
30+
- name: Run PSScriptAnalyzer
31+
shell: pwsh
32+
run: |
33+
$results = Invoke-ScriptAnalyzer -Path ./src -Recurse -Settings PSGallery
34+
if ($results) {
35+
$results | Format-Table -AutoSize
36+
Write-Error "PSScriptAnalyzer found $($results.Count) issue(s)"
37+
exit 1
38+
}
39+
Write-Host "PSScriptAnalyzer: No issues found" -ForegroundColor Green
40+
41+
- name: Run Pester Tests
42+
shell: pwsh
43+
run: |
44+
$config = New-PesterConfiguration
45+
$config.Run.Path = './tests'
46+
$config.Run.PassThru = $true
47+
$config.Output.Verbosity = 'Detailed'
48+
$config.CodeCoverage.Enabled = $false
49+
50+
$result = Invoke-Pester -Configuration $config
51+
52+
if ($result.FailedCount -gt 0) {
53+
Write-Error "Pester tests failed: $($result.FailedCount) failed out of $($result.TotalCount)"
54+
exit 1
55+
}
56+
57+
Write-Host "All tests passed: $($result.PassedCount)/$($result.TotalCount)" -ForegroundColor Green
58+
59+
- name: Validate Module Manifest
60+
shell: pwsh
61+
run: |
62+
$manifestPath = './src/ScriptWhitelistGuard.psd1'
63+
$manifest = Test-ModuleManifest -Path $manifestPath -ErrorAction Stop
64+
Write-Host "Module manifest is valid" -ForegroundColor Green
65+
Write-Host " Name: $($manifest.Name)"
66+
Write-Host " Version: $($manifest.Version)"
67+
Write-Host " Author: $($manifest.Author)"

.github/workflows/publish.yml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
name: Publish to PowerShell Gallery
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
workflow_dispatch:
8+
9+
jobs:
10+
publish:
11+
name: Publish Module
12+
runs-on: windows-latest
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Validate Tag Format
19+
shell: pwsh
20+
run: |
21+
$tag = $env:GITHUB_REF -replace 'refs/tags/', ''
22+
if ($tag -notmatch '^v\d+\.\d+\.\d+$') {
23+
Write-Error "Tag format invalid. Expected: v1.0.0, Got: $tag"
24+
exit 1
25+
}
26+
$version = $tag -replace '^v', ''
27+
Write-Host "Publishing version: $version"
28+
echo "MODULE_VERSION=$version" >> $env:GITHUB_ENV
29+
30+
- name: Update Module Version
31+
shell: pwsh
32+
run: |
33+
$manifestPath = './src/ScriptWhitelistGuard.psd1'
34+
$version = $env:MODULE_VERSION
35+
36+
# Read manifest content
37+
$content = Get-Content $manifestPath -Raw
38+
39+
# Update ModuleVersion
40+
$content = $content -replace "ModuleVersion\s*=\s*'[\d\.]+'", "ModuleVersion = '$version'"
41+
42+
# Write back
43+
Set-Content -Path $manifestPath -Value $content -NoNewline
44+
45+
Write-Host "Updated module version to $version"
46+
47+
- name: Install Dependencies
48+
shell: pwsh
49+
run: |
50+
Set-PSRepository PSGallery -InstallationPolicy Trusted
51+
Install-Module -Name Pester -Force -Scope CurrentUser -MinimumVersion 5.0.0 -SkipPublisherCheck
52+
Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser
53+
54+
- name: Run Tests Before Publishing
55+
shell: pwsh
56+
run: |
57+
$config = New-PesterConfiguration
58+
$config.Run.Path = './tests'
59+
$config.Run.PassThru = $true
60+
$config.Output.Verbosity = 'Detailed'
61+
62+
$result = Invoke-Pester -Configuration $config
63+
64+
if ($result.FailedCount -gt 0) {
65+
Write-Error "Tests failed. Aborting publish."
66+
exit 1
67+
}
68+
69+
- name: Validate Module Manifest
70+
shell: pwsh
71+
run: |
72+
$manifestPath = './src/ScriptWhitelistGuard.psd1'
73+
$manifest = Test-ModuleManifest -Path $manifestPath -ErrorAction Stop
74+
75+
Write-Host "Module Manifest Valid" -ForegroundColor Green
76+
Write-Host " Name: $($manifest.Name)"
77+
Write-Host " Version: $($manifest.Version)"
78+
Write-Host " GUID: $($manifest.Guid)"
79+
80+
- name: Publish to PowerShell Gallery
81+
shell: pwsh
82+
env:
83+
PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}
84+
run: |
85+
if (-not $env:PSGALLERY_API_KEY) {
86+
Write-Error "PSGALLERY_API_KEY secret not set. Please configure it in repository secrets."
87+
exit 1
88+
}
89+
90+
$modulePath = './src'
91+
92+
try {
93+
Publish-Module -Path $modulePath -NuGetApiKey $env:PSGALLERY_API_KEY -Verbose -ErrorAction Stop
94+
Write-Host "✓ Successfully published to PowerShell Gallery" -ForegroundColor Green
95+
}
96+
catch {
97+
Write-Error "Failed to publish module: $_"
98+
exit 1
99+
}
100+
101+
- name: Create GitHub Release
102+
uses: softprops/action-gh-release@v1
103+
with:
104+
generate_release_notes: true
105+
files: |
106+
./src/*
107+
env:
108+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# PowerShell module artifacts
2+
*.nupkg
3+
*.zip
4+
5+
# Test results
6+
TestResults/
7+
*.trx
8+
*.xml
9+
10+
# User whitelist data (for local testing)
11+
.ps-script-whitelist.json
12+
13+
# IDE and editor folders
14+
.vscode/
15+
.idea/
16+
*.code-workspace
17+
18+
# OS generated files
19+
.DS_Store
20+
Thumbs.db
21+
desktop.ini
22+
23+
# Build output
24+
bin/
25+
obj/
26+
publish/

CHANGELOG.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Changelog
2+
3+
All notable changes to ScriptWhitelistGuard will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [1.0.0] - 2026-01-29
9+
10+
### Added
11+
12+
- **Core Whitelist Management**
13+
- `Add-ScriptWhitelist`: Add or update scripts with SHA256 hash validation
14+
- `Remove-ScriptWhitelist`: Remove scripts from whitelist
15+
- `Test-ScriptWhitelist`: Verify script whitelist status and hash integrity
16+
- `Get-ScriptWhitelist`: List all whitelisted scripts with metadata
17+
- `Repair-ScriptWhitelist`: Convenience command to update hashes after script modifications
18+
19+
- **Interactive Guard System**
20+
- `Enable-WhitelistGuard`: Activate PSReadLine Enter key interception
21+
- `Disable-WhitelistGuard`: Deactivate guard and restore default behavior
22+
- `-Persist` flag: Auto-enable guard in all new PowerShell sessions via profile integration
23+
- `-Unpersist` flag: Remove auto-enable block from profile
24+
25+
- **Whitelist Storage**
26+
- JSON-based persistent storage at `$HOME\.ps-script-whitelist.json`
27+
- Environment variable override: `SCRIPT_WHITELIST_GUARD_STORE` for custom storage paths
28+
- SHA256 hash verification for script integrity
29+
30+
- **PSReadLine Integration**
31+
- Custom Enter key handler with AST-based command parsing
32+
- Selective interception: only external `.ps1` scripts
33+
- Transparent command rewriting: whitelisted scripts execute with `-ExecutionPolicy Bypass`
34+
- Helpful error messages with copy-paste commands for blocked scripts
35+
36+
- **Cross-Platform Support**
37+
- PowerShell 5.1 (Windows PowerShell) compatibility
38+
- PowerShell 7+ (pwsh) support
39+
- Automatic detection of available PowerShell executable
40+
41+
- **Profile Management**
42+
- Idempotent profile block insertion with clear begin/end markers
43+
- Safe removal that preserves user's existing profile content
44+
- Automatic profile file creation if it doesn't exist
45+
46+
- **Testing & Quality**
47+
- Comprehensive Pester test suite (20+ test cases)
48+
- Tests for whitelist operations, hash validation, profile persistence
49+
- GitHub Actions CI/CD workflows
50+
- PSScriptAnalyzer integration for code quality
51+
52+
- **Documentation**
53+
- Comprehensive README with examples and security warnings
54+
- FAQ section covering common scenarios
55+
- Clear explanation of limitations and non-security-boundary nature
56+
57+
### Security Notes
58+
59+
⚠️ **This is NOT a security boundary.** ScriptWhitelistGuard can be easily bypassed by:
60+
- Running `powershell -ExecutionPolicy Bypass` directly
61+
- Executing scripts non-interactively (scheduled tasks, CI/CD)
62+
- Disabling the guard with `Disable-WhitelistGuard`
63+
64+
For true enforcement, use:
65+
- **AppLocker** or **Windows Defender Application Control (WDAC)** on Windows
66+
- **Code signing** with trusted certificates
67+
- **GPO-based** execution policies
68+
69+
This module is designed for **workflow safety** to prevent accidental execution of untrusted scripts, not as malware protection.
70+
71+
## [Unreleased]
72+
73+
### Planned Features
74+
- Optional logging of all script execution attempts
75+
- Integration with Windows Event Log
76+
- Support for wildcard/regex patterns in whitelist paths
77+
- Team whitelist synchronization helpers
78+
- PowerShell 7+ module cache optimization
79+
80+
---
81+
82+
## Release Tags
83+
84+
- `v1.0.0` - Initial public release
85+
86+
[1.0.0]: https://github.com/YourOrg/ScriptWhitelistGuard/releases/tag/v1.0.0

0 commit comments

Comments
 (0)