PS 5.1 parses a BOM-less .ps1 as the system ANSI codepage, garbling the Chinese / em-dash string literals in five scripts. verify-doc-facts.ps1 failed four checks under 5.1 (CI only ran it under pwsh). Add a BOM to the five files and a CI guard that fails any non-ASCII .ps1 lacking one.
87 lines
4.2 KiB
PowerShell
87 lines
4.2 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Verify doc fact tables (capability lists, MCP ports, Burp tool count)
|
|
against source-of-truth (bootstrap-manifest.json / McpHttpServer.java).
|
|
|
|
.DESCRIPTION
|
|
P1-4 guard: RULES.md / RULES_zh.md / skills/SKILL.md fact tables must not
|
|
drift from the manifest and the Burp extension source. Exit 1 on mismatch.
|
|
#>
|
|
$ErrorActionPreference = 'Stop'
|
|
$Root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
|
|
$fail = 0
|
|
|
|
function Check([string]$Name, [bool]$Ok, [string]$Detail) {
|
|
if ($Ok) { Write-Host "OK $Name" } else { $script:fail++; Write-Host "FAIL $Name : $Detail" }
|
|
}
|
|
|
|
# --- Source of truth: manifest ---
|
|
$manifestPath = Join-Path $Root 'skills\scripts\bootstrap-manifest.json'
|
|
$manifest = Get-Content $manifestPath -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
$capNames = @($manifest.capabilities | ForEach-Object { $_.name } | Sort-Object)
|
|
|
|
# --- Source of truth: Burp getToolList() ---
|
|
$javaPath = Join-Path $Root 'burp-mcp-full\src\main\java\com\burpmcp\McpHttpServer.java'
|
|
$java = Get-Content $javaPath -Raw
|
|
$def = [regex]::Match($java, 'String\s+getToolList\s*\([^)]*\)\s*\{')
|
|
if (-not $def.Success) { throw 'getToolList() not found in McpHttpServer.java' }
|
|
$endIdx = $java.IndexOf("`n }", $def.Index)
|
|
$body = $java.Substring($def.Index, $endIdx - $def.Index)
|
|
$burpTools = @([regex]::Matches($body, '\\"([a-z_0-9]+)\\"') | ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique)
|
|
$burpCount = $burpTools.Count
|
|
|
|
Write-Host "source-of-truth: $($capNames.Count) capabilities, Burp getToolList = $burpCount tools"
|
|
|
|
# --- Doc helpers ---
|
|
function Get-ListLine([string]$Text, [string]$Marker) {
|
|
$lines = $Text -split "`r?`n"
|
|
for ($i = 0; $i -lt $lines.Count; $i++) {
|
|
if ($lines[$i] -match [regex]::Escape($Marker)) {
|
|
$inline = [regex]::Match($lines[$i], '):(.+?)\s*$')
|
|
if ($inline.Success) { return $inline.Groups[1].Value }
|
|
if ($i + 1 -lt $lines.Count) { return $lines[$i + 1] }
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
function Test-ListHasAll([string]$ListText, [string[]]$Names) {
|
|
$tokens = @($ListText -split '[、,]+' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
|
|
if ($tokens.Count -ne $Names.Count) { return $false }
|
|
foreach ($n in $Names) { if ($tokens -notcontains $n) { return $false } }
|
|
return $true
|
|
}
|
|
|
|
$rulesEn = Get-Content (Join-Path $Root 'RULES.md') -Raw -Encoding UTF8
|
|
$rulesZh = Get-Content (Join-Path $Root 'RULES_zh.md') -Raw -Encoding UTF8
|
|
$skillMd = Get-Content (Join-Path $Root 'skills\SKILL.md') -Raw -Encoding UTF8
|
|
|
|
$enList = Get-ListLine $rulesEn 'Supported capability names'
|
|
$zhList = Get-ListLine $rulesZh '支持的能力名'
|
|
$skList = Get-ListLine $skillMd '支持的能力'
|
|
|
|
Check 'RULES.md capability list' (Test-ListHasAll $enList $capNames) "expected $($capNames.Count) capabilities: $($capNames -join ', ')"
|
|
Check 'RULES_zh.md capability list' (Test-ListHasAll $zhList $capNames) "expected $($capNames.Count) capabilities"
|
|
Check 'SKILL.md capability list' (Test-ListHasAll $skList $capNames) "expected $($capNames.Count) capabilities"
|
|
Check 'RULES_zh.md count text' ($rulesZh.Contains("共 $($capNames.Count) 项")) "expected 共 $($capNames.Count) 项"
|
|
|
|
# --- MCP ports from manifest servicePort / servicePortRange ---
|
|
foreach ($c in $manifest.capabilities) {
|
|
if (-not $c.PSObject.Properties['servicePort']) { continue }
|
|
$port = [string]$c.servicePort
|
|
Check "RULES.md port $($c.name)=$port" ($rulesEn.Contains($port)) "missing port $port for $($c.name)"
|
|
Check "RULES_zh.md port $($c.name)=$port" ($rulesZh.Contains($port)) "missing port $port for $($c.name)"
|
|
if ($c.PSObject.Properties['servicePortRange']) {
|
|
$range = @($c.servicePortRange) -join '-'
|
|
Check "RULES.md range $($c.name)=$range" ($rulesEn.Contains($range)) "missing range $range for $($c.name)"
|
|
Check "RULES_zh.md range $($c.name)=$range" ($rulesZh.Contains($range)) "missing range $range for $($c.name)"
|
|
}
|
|
}
|
|
|
|
# --- Burp tool count ---
|
|
Check 'RULES.md burp tool count' ($rulesEn.Contains("$burpCount-tool")) "expected '$burpCount-tool' in RULES.md"
|
|
Check 'RULES_zh.md burp tool count' ($rulesZh.Contains("$burpCount 工具全控制")) "expected '$burpCount 工具全控制' in RULES_zh.md"
|
|
|
|
Write-Host "verify-doc-facts: $fail failure(s)"
|
|
if ($fail -gt 0) { exit 1 }
|