# B13 — scripts/runTests.sh: wget -O - https://get.pharo.org/64/80 | bash

Bug ref      : always.md B.13 ; pharo.md §7
Severity     : CRITICAL (PR workflow executes attacker bash on any image change)
File         : scripts/runTests.sh
Lines (HEAD) : 31 (`fetch_image` body)

## Problem

```bash
fetch_image()
{
    case $APPNAME in
    *)
        wget -O - https://get.pharo.org/64/80 | bash
        echo 80 > pharo.version
        TEST_IMAGE_NAME=$(ls Pharo*.image)
        ;;
    esac
}
```

`runTests.sh` is invoked by `.github/workflows/continuous-integration-workflow.yaml`
on every `pull_request`, including PRs from forks. A fork PR can
rewrite this file to fetch attacker code. Even unchanged, the
piped-bash pattern means any compromise of `get.pharo.org` lets an
attacker run arbitrary code on every PR build with the workflow's
`GITHUB_TOKEN` scope.

## Fix

1. Download to a file.
2. Verify the file's sha256 against a value pinned in the repo
   (`scripts/pharo-image-80.sha256`).
3. Then `bash` it.

```diff
diff --git a/scripts/runTests.sh b/scripts/runTests.sh
index 93ecd3831..e80399b49 100644
--- a/scripts/runTests.sh
+++ b/scripts/runTests.sh
@@ -28,7 +28,24 @@ fetch_image()
 {
     case $APPNAME in
     *)
-        wget -O - https://get.pharo.org/64/80 | bash
+        # Download to a file rather than piping straight to bash; verify a
+        # pinned sha256 before executing. The operator must keep
+        # scripts/pharo-image-80.sha256 in sync with upstream releases.
+        wget -O pharo-installer.sh https://get.pharo.org/64/80
+        SHA_FILE="$(dirname "$0")/pharo-image-80.sha256"
+        if [ -f "$SHA_FILE" ]; then
+            EXPECTED=$(cat "$SHA_FILE")
+            ACTUAL=$(sha256sum pharo-installer.sh | awk '{print $1}')
+            if [ "$EXPECTED" != "$ACTUAL" ]; then
+                echo "pharo-installer.sh sha256 mismatch" >&2
+                echo "  expected: $EXPECTED" >&2
+                echo "  actual:   $ACTUAL"   >&2
+                exit 1
+            fi
+        else
+            echo "WARNING: no pinned sha256 file at $SHA_FILE; proceeding without verification" >&2
+        fi
+        bash pharo-installer.sh
         echo 80 > pharo.version
         TEST_IMAGE_NAME=$(ls Pharo*.image)
         ;;
```

Add `scripts/pharo-image-80.sha256` containing the current pinned
sha256 (single line, lowercase hex, no filename suffix).

## Test plan

- Run `scripts/runTests.sh` locally against a real pharo bootstrap:
  passes when the pinned hash matches.
- Modify the sha256 file by one byte: script aborts at the sha256
  check with a clear error message.
- Verify the CI workflow still triggers the script for PRs (no
  change to `.github/workflows/*` here).

## Risk notes

- This makes the bootstrap reproducible. Every upstream release of
  the Pharo image-build helper requires a corresponding update to
  `scripts/pharo-image-80.sha256`. That is deliberate — it forces a
  human to look at the new artifact.
- Combined with B21 (workflow `permissions:`) the blast radius of a
  compromised image bootstrap is reduced even if the sha check is
  bypassed.
