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
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ A pull request should:
- update public documentation when behavior, maturity, safety, or claim boundaries change;
- preserve the GPL community license and separate commercial-licensing wording;
- document contribution authorship, origin, and required third-party rights; a DCO commit sign-off is not required.
- use vendor-neutral terminology in public PR titles, descriptions, comments and release notes, without changing recorded engineering measurements;

For UI changes, include the tested Windows scaling level, resolution, keyboard workflow, and any accessibility impact. For protocol, reporting, GOOSE, SMV, file-transfer, SCL, or control changes, state whether validation used unit tests, deterministic fixtures, loopback, simulator, or an authorized laboratory IED.

Expand Down
61 changes: 61 additions & 0 deletions scripts/test-source-clean-guard.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,65 @@ foreach ($case in $cases) {
Invoke-Case -RelativePath $case.Path -Content $case.Text -MustReject $true -Expected $case.Expected
}
Invoke-Case -RelativePath "docs/synthetic-reference.md" -Content "# ARSAS independent IEC 61850 synthetic evidence" -MustReject $false
# Verify the GitHub PR event gate without placing any disallowed identifier
# literally in this repository, and without changing the existing file fixtures.
function Invoke-PrMetadataCase {
param(
[Parameter(Mandatory=$true)][string]$Field,
[Parameter(Mandatory=$true)][string]$Value,
[Parameter(Mandatory=$true)][bool]$MustReject
)
$root = Join-Path ([IO.Path]::GetTempPath()) ("arsas-pr-metadata-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $root -Force | Out-Null
try {
& git -C $root init --quiet
if ($LASTEXITCODE -ne 0) { throw "Metadata fixture Git initialization failed." }
[IO.File]::WriteAllText(
(Join-Path $root "README.md"), "# Synthetic IEC 61850 metadata fixture",
[Text.UTF8Encoding]::new($false))
& git -C $root add README.md
if ($LASTEXITCODE -ne 0) { throw "Metadata fixture Git staging failed." }

$event = @{ pull_request = @{ title = "Synthetic ARSAS update"; body = "Independent engineering change" } }
$event.pull_request[$Field] = $Value
$eventPath = Join-Path $root "event.json"
[IO.File]::WriteAllText($eventPath, ($event | ConvertTo-Json -Depth 4),
[Text.UTF8Encoding]::new($false))

$startInfo = [System.Diagnostics.ProcessStartInfo]::new()
$startInfo.FileName = "powershell.exe"
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $true
$startInfo.RedirectStandardOutput = $true
$startInfo.RedirectStandardError = $true
$startInfo.EnvironmentVariables["GITHUB_EVENT_NAME"] = "pull_request"
$startInfo.EnvironmentVariables["GITHUB_EVENT_PATH"] = $eventPath
$startInfo.Arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$scanner`" -RepositoryRoot `"$root`" -ScanOnly"

$process = [System.Diagnostics.Process]::new()
$process.StartInfo = $startInfo
if (-not $process.Start()) { throw "PR metadata fixture scanner failed to start." }
$stdoutTask = $process.StandardOutput.ReadToEndAsync()
$stderrTask = $process.StandardError.ReadToEndAsync()
$process.WaitForExit()
$output = @($stdoutTask.GetAwaiter().GetResult(), $stderrTask.GetAwaiter().GetResult()) -join [Environment]::NewLine
$exitCode = $process.ExitCode
$process.Dispose()
if ($MustReject) {
if ($exitCode -eq 0 -or $output -notmatch ("Forbidden external identifier in PR " + $Field)) {
throw "Source-clean accepted a forbidden PR metadata fixture: $Field; exit=$exitCode; output=$output"
}
}
elseif ($exitCode -ne 0) {
throw "Source-clean rejected neutral PR metadata: $Field; exit=$exitCode; output=$output"
}
}
finally {
Remove-Item -LiteralPath $root -Recurse -Force -ErrorAction SilentlyContinue
}
}

Invoke-PrMetadataCase -Field "title" -Value $identifier -MustReject $true
Invoke-PrMetadataCase -Field "body" -Value ("Protocol evidence from " + $identifier) -MustReject $true
Invoke-PrMetadataCase -Field "title" -Value "Neutral engineering update" -MustReject $false
Write-Host "Source-clean negative and positive fixture tests PASS." -ForegroundColor Green
22 changes: 22 additions & 0 deletions scripts/verify-source-clean.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,28 @@ foreach ($relative in (Get-TrackedRelativePaths)) {
}
}

# A PR's public title and description are published before merge, so validate them
# through the same fingerprint matcher that protects Git-tracked paths and text.
if ($env:GITHUB_EVENT_NAME -eq "pull_request") {
if ([string]::IsNullOrWhiteSpace($env:GITHUB_EVENT_PATH) -or
-not (Test-Path -LiteralPath $env:GITHUB_EVENT_PATH -PathType Leaf)) {
$Problems.Add("Missing PR event metadata for public identifier verification")
}
else {
$eventPayload = Get-Content -LiteralPath $env:GITHUB_EVENT_PATH -Raw | ConvertFrom-Json
if ($null -eq $eventPayload.pull_request) {
$Problems.Add("Missing pull_request object in PR event metadata")
}
else {
foreach ($field in @("title", "body")) {
if (Test-ContainsForbiddenIdentifier ([string]$eventPayload.pull_request.$field)) {
$Problems.Add("Forbidden external identifier in PR $field")
}
}
}
}
}

if ($Problems.Count -gt 0) {
foreach ($problem in ($Problems | Sort-Object -Unique)) {
Write-Host "ERROR: $problem" -ForegroundColor Red
Expand Down
Loading