mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-07 07:18:18 +00:00
The rules lived inside Sanitization.Tests.ps1, so the publisher in the private toolkit kept its own second list -- and the two guarded different things. The publisher's was about SECRETS: keys, private-key blocks, ssh targets. These are about IDENTITY: internal project names, product domains, private-only script names, operator paths. So the publisher reported "clean" on files this suite rejects, and would have published a tree that fails the public repo's own tests (evo.scripts#106). Proven at the time by copying the private ZHelpers.ps1 in: two failures naming EvoCivilCode, EvoPlatform and three private-only script names, against a scan that called the same file clean. tests/sanitization-patterns.psd1 is now the one source. The suite reads it and refuses to run if it is missing or empty, rather than passing vacuously against no rules -- an empty denylist that reports success is the failure this whole fix is about. No rule changed. Only where they live. .psd1 is not in the scanned extension list, which is deliberate and matches why Sanitization.Tests.ps1 excludes itself: a file that necessarily contains every pattern it looks for cannot also be scanned for them. Pester: 240 passed, 0 failed. CHECKSUMS regenerated; changelog and its plain-text twin updated.
105 lines
4.8 KiB
PowerShell
105 lines
4.8 KiB
PowerShell
# Evomedia.net Token Savers — https://github.com/evomedia-net/evo.zscripts
|
|
# Created by Kelly Michels · dev@evomedia.net
|
|
# Licensed under the MIT License. See LICENSE.
|
|
|
|
# Sanitization.Tests.ps1 — this repo is public and must stay standalone.
|
|
#
|
|
# WHY THIS EXISTS
|
|
# ---------------
|
|
# The toolkit is developed in a private checkout and copied here. Twice in three
|
|
# days a wholesale copy landed carrying environment-specific detail: real
|
|
# project names, internal hostnames, host disk figures, and references to
|
|
# scripts that exist only in the private copy. Each time it was caught by a
|
|
# human reading the diff, which is exactly the control that fails when a diff is
|
|
# 280 lines of good work with three bad words buried in it.
|
|
#
|
|
# So it is a test. A copy that reintroduces private detail turns the suite red
|
|
# at the moment it happens rather than at review.
|
|
#
|
|
# WHAT IT CANNOT DO
|
|
# -----------------
|
|
# This is a denylist, so it proves the absence of KNOWN patterns, not the
|
|
# absence of secrets. It is a regression net for a specific recurring mistake -
|
|
# not a substitute for reading what you publish. Add a pattern whenever a new
|
|
# private identifier appears; the cost of a stale entry is zero.
|
|
|
|
BeforeAll {
|
|
$script:RepoRoot = Split-Path -Parent $PSScriptRoot
|
|
|
|
# Scanned: everything a reader of the published repo can see. Skipped:
|
|
# .git (history is out of scope here), releases/ (published zips are
|
|
# immutable by policy - rewriting one would break its checksum), and this
|
|
# file, which necessarily contains every pattern it looks for.
|
|
$script:Scanned = @(
|
|
Get-ChildItem -LiteralPath $script:RepoRoot -Recurse -File |
|
|
Where-Object {
|
|
$_.Extension -in @('.ps1', '.cmd', '.md', '.txt', '.json', '.bats', '.sh') -and
|
|
$_.FullName -notlike '*\.git\*' -and
|
|
$_.FullName -notlike '*\releases\*' -and
|
|
$_.Name -ne 'Sanitization.Tests.ps1'
|
|
}
|
|
)
|
|
|
|
# The rules live in sanitization-patterns.psd1, not here, so the
|
|
# publisher in the private tree can read the SAME list. It used to keep
|
|
# its own, narrower one - secrets only, no identity rules - and therefore
|
|
# reported "clean" on files this suite rejects (evo.scripts#106).
|
|
$patternFile = Join-Path $PSScriptRoot 'sanitization-patterns.psd1'
|
|
if (-not (Test-Path -LiteralPath $patternFile)) {
|
|
throw "sanitization-patterns.psd1 is missing - the denylist has no source."
|
|
}
|
|
$script:Denied = (Import-PowerShellDataFile -LiteralPath $patternFile).Denied
|
|
if (-not $script:Denied -or $script:Denied.Count -eq 0) {
|
|
throw "sanitization-patterns.psd1 defined no rules - refusing to pass vacuously."
|
|
}
|
|
|
|
function Get-Hits {
|
|
param([string]$Pattern)
|
|
$hits = @()
|
|
foreach ($f in $script:Scanned) {
|
|
$m = Select-String -LiteralPath $f.FullName -Pattern $Pattern -AllMatches -ErrorAction SilentlyContinue
|
|
foreach ($line in $m) {
|
|
$rel = $line.Path.Substring($script:RepoRoot.Length).TrimStart('\')
|
|
$hits += "$rel`:$($line.LineNumber): $($line.Line.Trim())"
|
|
}
|
|
}
|
|
return $hits
|
|
}
|
|
}
|
|
|
|
Describe "public repo carries no private detail" {
|
|
|
|
It "finds files to scan at all" {
|
|
# Guards the guard: a bad filter here would make every test below pass
|
|
# vacuously, which is worse than no test.
|
|
$script:Scanned.Count | Should -BeGreaterThan 30
|
|
}
|
|
|
|
It "contains no <Name>" -ForEach @(
|
|
@{ Name = 'private project name' }
|
|
@{ Name = 'private product domain' }
|
|
@{ Name = 'private-only script' }
|
|
@{ Name = 'local drive path' }
|
|
@{ Name = 'operator home path' }
|
|
@{ Name = 'real pem key name' }
|
|
@{ Name = 'non-documentation IP' }
|
|
) {
|
|
$rule = $script:Denied | Where-Object { $_.Name -eq $Name }
|
|
$hits = Get-Hits -Pattern $rule.Pattern
|
|
$hits | Should -BeNullOrEmpty -Because "these look like private detail copied in from the internal toolkit:`n$($hits -join "`n")"
|
|
}
|
|
|
|
It "still detects a planted violation" {
|
|
# Mutation check. Without this the suite passes just as happily when the
|
|
# patterns are broken as when the repo is clean - the failure mode that
|
|
# makes a denylist worthless.
|
|
$probe = Join-Path ([IO.Path]::GetTempPath()) ("sanitize-probe-" + [guid]::NewGuid().ToString("N") + ".ps1")
|
|
try {
|
|
Set-Content -LiteralPath $probe -Value '# deploy target /home/ubuntu/stack/example' -Encoding UTF8
|
|
$found = Select-String -LiteralPath $probe -Pattern ($script:Denied | Where-Object { $_.Name -eq 'operator home path' }).Pattern
|
|
$found | Should -Not -BeNullOrEmpty
|
|
}
|
|
finally { Remove-Item -LiteralPath $probe -Force -ErrorAction SilentlyContinue }
|
|
}
|
|
}
|