From b478d3dc22aa91c0a533d444f8ce934dab3b395a Mon Sep 17 00:00:00 2001 From: Atirna <288419661+atirna@users.noreply.github.com> Date: Tue, 11 Aug 2026 03:51:53 +0530 Subject: [PATCH 1/2] fix(case): support network profiles on Bash 3.2 Assisted-by: Codex --- .github/workflows/ci.yml | 9 +++++++++ skills/scripts/case-init.sh | 8 +++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b9cb6e..f2ce9e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,6 +114,15 @@ jobs: grep -Eq '^- ready_for_act: true$' "$scratch/project/work/network-default/scope.md" bash skills/scripts/case-guard.sh --case-root "$scratch/project/work/network-default" + bash skills/scripts/case-init.sh \ + --hint "authorized web review" \ + --case-name "uppercase-network" \ + --package-root "$scratch/project" \ + --auth-granted \ + --network-profile "AUTHORIZED_TARGET_ONLY" \ + --target-url "https://example.test/" + grep -Eq '^- mode: authorized_target_only$' "$scratch/project/work/uppercase-network/scope.md" + bash skills/scripts/case-init.sh \ --hint "pending review" \ --case-name "guard-section" \ diff --git a/skills/scripts/case-init.sh b/skills/scripts/case-init.sh index 8e8e6e0..c3b4c6c 100755 --- a/skills/scripts/case-init.sh +++ b/skills/scripts/case-init.sh @@ -94,7 +94,8 @@ if [[ -z "$CASE_NAME" || "$case_name_length" -gt 80 || exit 2 fi if [[ -n "$NETWORK_PROFILE" ]]; then - case "${NETWORK_PROFILE,,}" in + network_profile_normalized="$(printf '%s' "$NETWORK_PROFILE" | tr '[:upper:]' '[:lower:]')" + case "$network_profile_normalized" in offline|lab_only|authorized_target_only|unrestricted_lab|lab|authorized|auth|offline_only) ;; *) echo "Invalid --network-profile '$NETWORK_PROFILE'. Allowed: offline, lab_only, authorized_target_only, unrestricted_lab (aliases: lab, authorized, auth, offline_only)." >&2 @@ -146,11 +147,12 @@ elif [[ "$auth_status_resolved" == "granted" && ${#ASSETS[@]} -gt 0 && -z "$SAMP else network_mode="offline" fi -case "${network_mode,,}" in +network_mode="$(printf '%s' "$network_mode" | tr '[:upper:]' '[:lower:]')" +case "$network_mode" in lab) network_mode="lab_only" ;; authorized|auth) network_mode="authorized_target_only" ;; offline_only) network_mode="offline" ;; - offline|lab_only|authorized_target_only|unrestricted_lab) network_mode="${network_mode,,}" ;; + offline|lab_only|authorized_target_only|unrestricted_lab) ;; *) echo "Invalid --network-profile '$network_mode'. Allowed: offline, lab_only, authorized_target_only, unrestricted_lab (aliases: lab, authorized, auth, offline_only)." >&2 exit 2 From a89ec4bfbe3ec95d0e2502a3da16eca5554fde12 Mon Sep 17 00:00:00 2001 From: jhuang-tw <77732008+jhuang-tw@users.noreply.github.com> Date: Tue, 11 Aug 2026 00:37:21 -0700 Subject: [PATCH 2/2] fix(evidence): preserve immutable Evidence records --- skills/scripts/append-evidence.ps1 | 26 +++++++++++++++++- skills/scripts/smoke.ps1 | 42 ++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/skills/scripts/append-evidence.ps1 b/skills/scripts/append-evidence.ps1 index e9b52cc..a2769ed 100644 --- a/skills/scripts/append-evidence.ps1 +++ b/skills/scripts/append-evidence.ps1 @@ -155,7 +155,31 @@ $notesBlock "@ $utf8 = New-Object System.Text.UTF8Encoding $false -[System.IO.File]::WriteAllText($path, $body, $utf8) +$stream = $null +$writer = $null +try { + try { + $stream = [System.IO.File]::Open( + $path, + [System.IO.FileMode]::CreateNew, + [System.IO.FileAccess]::Write, + [System.IO.FileShare]::None + ) + } catch [System.IO.IOException] { + if (Test-Path -LiteralPath $path) { + throw ("Evidence record already exists and is immutable: {0}. Use a new -Id." -f $fileName) + } + throw + } + $writer = [System.IO.StreamWriter]::new($stream, $utf8) + $writer.Write($body) +} finally { + if ($null -ne $writer) { + $writer.Dispose() + } elseif ($null -ne $stream) { + $stream.Dispose() + } +} $index = Join-Path $evDir 'INDEX.md' $line = "- $idSafe | $sev | $st | $titleLine | $fileName" diff --git a/skills/scripts/smoke.ps1 b/skills/scripts/smoke.ps1 index b057bc4..de25355 100644 --- a/skills/scripts/smoke.ps1 +++ b/skills/scripts/smoke.ps1 @@ -121,6 +121,48 @@ if (-not (Test-Path -LiteralPath $mr)) { } $routeSummary -join [Environment]::NewLine | Set-Content (Join-Path $LogDir '03-route-summary.txt') -Encoding UTF8 +# --- 4) Evidence ID immutability --- +$appendEvidence = Join-Path $scriptDir 'append-evidence.ps1' +$evidenceCase = Join-Path $LogDir 'evidence-immutability' +if (-not (Test-Path -LiteralPath $appendEvidence)) { + Bad 'append-evidence.ps1 missing for immutability check' +} else { + New-Item -ItemType Directory -Path $evidenceCase -Force | Out-Null + & powershell -NoProfile -ExecutionPolicy Bypass -File $appendEvidence ` + -CaseRoot $evidenceCase ` + -Id 'E-IMMUTABLE' ` + -Title 'first write' ` + -ReproCommand 'echo first' 2>&1 | Out-Null + $firstEvidenceExit = $LASTEXITCODE + if ($firstEvidenceExit -ne 0) { + Bad ("initial Evidence append exit {0}" -f $firstEvidenceExit) + } else { + $evidencePath = Join-Path $evidenceCase 'evidence\E-IMMUTABLE.md' + $indexPath = Join-Path $evidenceCase 'evidence\INDEX.md' + $beforeEvidence = (Get-FileHash -LiteralPath $evidencePath -Algorithm SHA256).Hash + $beforeIndex = (Get-FileHash -LiteralPath $indexPath -Algorithm SHA256).Hash + + & powershell -NoProfile -ExecutionPolicy Bypass -File $appendEvidence ` + -CaseRoot $evidenceCase ` + -Id 'E-IMMUTABLE' ` + -Title 'second write' ` + -ReproCommand 'echo second' 2>&1 | Out-Null + $duplicateEvidenceExit = $LASTEXITCODE + + $afterEvidence = (Get-FileHash -LiteralPath $evidencePath -Algorithm SHA256).Hash + $afterIndex = (Get-FileHash -LiteralPath $indexPath -Algorithm SHA256).Hash + if ($duplicateEvidenceExit -eq 0) { + Bad 'duplicate Evidence ID was accepted' + } elseif ($beforeEvidence -ne $afterEvidence) { + Bad 'existing Evidence changed after duplicate append' + } elseif ($beforeIndex -ne $afterIndex) { + Bad 'Evidence index changed after duplicate append' + } else { + Ok 'duplicate Evidence ID rejected without mutation' + } + } +} + # --- summary --- $summary = @( "VERIFY_EXIT=$verifyExit",