diff --git a/README.md b/README.md index 1d74d62..64ef9b5 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,25 @@ Fish You can then edit the `.git/hooks/pre-commit` file to customise the registered pre-commit hook. +--- +## Updating the launcher script +The launcher scripts no longer update themselves automatically on every run. To pull the latest launcher on demand, run the `self-update` subcommand — the download is checked against a published SHA-256 checksum (an integrity check against corruption in transit, not an authenticity signature, since the script and its checksum share one origin) and is only applied if it matches. + +Zsh +```zsh +./browserstack-a11y-scan-spm-zsh.sh self-update +``` + +Bash +```bash +./browserstack-a11y-scan-spm-bash.sh self-update +``` + +Fish +```bash +./browserstack-a11y-scan-spm-fish.sh self-update +``` + --- ## Support For any issues or feedback, reach out to support@browserstack.com \ No newline at end of file diff --git a/scripts/bash/cli.sh b/scripts/bash/cli.sh index 76f7b0b..4472c07 100644 --- a/scripts/bash/cli.sh +++ b/scripts/bash/cli.sh @@ -78,9 +78,10 @@ a11y_scan() { $BINARY_PATH a11y $EXTRA_ARGS } -# Self-update tracks the latest launcher on `main` so users always run the -# newest version. DEVA11Y-475/477/478: we deliberately follow main HEAD rather -# than a pinned revision (per maintainer intent: always take the latest). +# Self-update pulls the latest launcher from `main` on demand: it runs only via +# the explicit `self-update` subcommand (DEVA11Y-475), not automatically on every +# invocation. DEVA11Y-477/478: when it does run we deliberately follow main HEAD +# rather than a pinned revision (per maintainer intent: take the latest on demand). # Hardening retained from the pinning work: download to a temp dir, verify a # SHA-256 sidecar (a download-integrity check, NOT an authenticity signature -- # script and checksum share one origin), sanity-check the shebang, then @@ -183,16 +184,19 @@ download_binary() { bsdtar -xvf "$BINARY_ZIP_PATH" -O > "$BINARY_PATH" && chmod 0775 "$BINARY_PATH" } -# Best-effort auto-update: always fetch the latest launcher from main before -# running. Network/offline failures are silent (rc 0) and operational errors -# (rc 1) are non-fatal -- the existing script keeps working. An integrity -# failure (rc 2: checksum mismatch or non-script payload) leaves the verified -# on-disk script untouched and is surfaced loudly below, but still does not -# block the tool (per the always-run-latest, never-block design). -_self_update_rc=0 -script_self_update || _self_update_rc=$? -if [[ "$_self_update_rc" -eq 2 ]]; then - echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 +# Self-update is opt-in (DEVA11Y-475): it runs only via the explicit `self-update` +# subcommand, never automatically on every invocation. Running it unconditionally +# before subcommand parsing meant a single compromise of the fetched source silently +# replaced the running script on every developer's machine, with no way to opt out; +# gating it behind an explicit command removes that always-on side-effect. Integrity +# verification (SHA-256 check + atomic staging) still guards the download itself. +if [[ $SUBCOMMAND == "self-update" ]]; then + _self_update_rc=0 + script_self_update || _self_update_rc=$? + if [[ "$_self_update_rc" -eq 2 ]]; then + echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 + fi + exit "$_self_update_rc" fi if [[ $SUBCOMMAND == "register-pre-commit-hook" ]]; then diff --git a/scripts/bash/cli.sh.sha256 b/scripts/bash/cli.sh.sha256 index 7e28cdb..f6165bd 100644 --- a/scripts/bash/cli.sh.sha256 +++ b/scripts/bash/cli.sh.sha256 @@ -1 +1 @@ -2340d95e6ce35ea8656acb02e0b524eeccca02c12a940d44e8cd0c0032b0efdd cli.sh +e233e16b32a0ec18d24acf32e8c415d26c4eeecdc287452117fe51de2f4791dc cli.sh diff --git a/scripts/bash/spm.sh b/scripts/bash/spm.sh index 2b4f446..387daf2 100644 --- a/scripts/bash/spm.sh +++ b/scripts/bash/spm.sh @@ -146,9 +146,10 @@ EOF scan $EXTRA_ARGS } -# Self-update tracks the latest launcher on `main` so users always run the -# newest version. DEVA11Y-475/477/478: we deliberately follow main HEAD rather -# than a pinned revision (per maintainer intent: always take the latest). +# Self-update pulls the latest launcher from `main` on demand: it runs only via +# the explicit `self-update` subcommand (DEVA11Y-475), not automatically on every +# invocation. DEVA11Y-477/478: when it does run we deliberately follow main HEAD +# rather than a pinned revision (per maintainer intent: take the latest on demand). # Hardening retained from the pinning work: download to a temp dir, verify a # SHA-256 sidecar (a download-integrity check, NOT an authenticity signature -- # script and checksum share one origin), sanity-check the shebang, then @@ -246,16 +247,19 @@ script_self_update() { fi } -# Best-effort auto-update: always fetch the latest launcher from main before -# running. Network/offline failures are silent (rc 0) and operational errors -# (rc 1) are non-fatal -- the existing script keeps working. An integrity -# failure (rc 2: checksum mismatch or non-script payload) leaves the verified -# on-disk script untouched and is surfaced loudly below, but still does not -# block the tool (per the always-run-latest, never-block design). -_self_update_rc=0 -script_self_update || _self_update_rc=$? -if [[ "$_self_update_rc" -eq 2 ]]; then - echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 +# Self-update is opt-in (DEVA11Y-475): it runs only via the explicit `self-update` +# subcommand, never automatically on every invocation. Running it unconditionally +# before subcommand parsing meant a single compromise of the fetched source silently +# replaced the running script on every developer's machine, with no way to opt out; +# gating it behind an explicit command removes that always-on side-effect. Integrity +# verification (SHA-256 check + atomic staging) still guards the download itself. +if [[ $SUBCOMMAND == "self-update" ]]; then + _self_update_rc=0 + script_self_update || _self_update_rc=$? + if [[ "$_self_update_rc" -eq 2 ]]; then + echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 + fi + exit "$_self_update_rc" fi if [[ $SUBCOMMAND == "register-pre-commit-hook" ]]; then diff --git a/scripts/bash/spm.sh.sha256 b/scripts/bash/spm.sh.sha256 index f7c336d..c4f9ac6 100644 --- a/scripts/bash/spm.sh.sha256 +++ b/scripts/bash/spm.sh.sha256 @@ -1 +1 @@ -1987749e047ca43b15f10b0eb6a98d0adcfbf5f7de9f54f49831b486406c8ba1 spm.sh +b520c458bec538505c9ff9ca75a02ec901597fd66b3c2d951b928e58e58e60da spm.sh diff --git a/scripts/fish/cli.sh b/scripts/fish/cli.sh index 8848880..a069b36 100644 --- a/scripts/fish/cli.sh +++ b/scripts/fish/cli.sh @@ -90,9 +90,10 @@ a11y_scan() { $BINARY_PATH a11y $EXTRA_ARGS } -# Self-update tracks the latest launcher on `main` so users always run the -# newest version. DEVA11Y-475/477/478: we deliberately follow main HEAD rather -# than a pinned revision (per maintainer intent: always take the latest). +# Self-update pulls the latest launcher from `main` on demand: it runs only via +# the explicit `self-update` subcommand (DEVA11Y-475), not automatically on every +# invocation. DEVA11Y-477/478: when it does run we deliberately follow main HEAD +# rather than a pinned revision (per maintainer intent: take the latest on demand). # Hardening retained from the pinning work: download to a temp dir, verify a # SHA-256 sidecar (a download-integrity check, NOT an authenticity signature -- # script and checksum share one origin), sanity-check the shebang, then @@ -195,16 +196,19 @@ download_binary() { bsdtar -xvf "$BINARY_ZIP_PATH" -O > "$BINARY_PATH" && chmod 0775 "$BINARY_PATH" } -# Best-effort auto-update: always fetch the latest launcher from main before -# running. Network/offline failures are silent (rc 0) and operational errors -# (rc 1) are non-fatal -- the existing script keeps working. An integrity -# failure (rc 2: checksum mismatch or non-script payload) leaves the verified -# on-disk script untouched and is surfaced loudly below, but still does not -# block the tool (per the always-run-latest, never-block design). -_self_update_rc=0 -script_self_update || _self_update_rc=$? -if [[ "$_self_update_rc" -eq 2 ]]; then - echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 +# Self-update is opt-in (DEVA11Y-475): it runs only via the explicit `self-update` +# subcommand, never automatically on every invocation. Running it unconditionally +# before subcommand parsing meant a single compromise of the fetched source silently +# replaced the running script on every developer's machine, with no way to opt out; +# gating it behind an explicit command removes that always-on side-effect. Integrity +# verification (SHA-256 check + atomic staging) still guards the download itself. +if [[ $SUBCOMMAND == "self-update" ]]; then + _self_update_rc=0 + script_self_update || _self_update_rc=$? + if [[ "$_self_update_rc" -eq 2 ]]; then + echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 + fi + exit "$_self_update_rc" fi if [[ $SUBCOMMAND == "register-pre-commit-hook" ]]; then diff --git a/scripts/fish/cli.sh.sha256 b/scripts/fish/cli.sh.sha256 index 31f4280..1a6478f 100644 --- a/scripts/fish/cli.sh.sha256 +++ b/scripts/fish/cli.sh.sha256 @@ -1 +1 @@ -a2bf0be4a37272548c13a25714e42152de11c31590122880a6ce8c50a55c075b cli.sh +332c8583f95291bf72ac4199702697656d28f5b98eba3a6a724a0272ecf77f83 cli.sh diff --git a/scripts/fish/spm.sh b/scripts/fish/spm.sh index 9798b53..2842249 100644 --- a/scripts/fish/spm.sh +++ b/scripts/fish/spm.sh @@ -159,9 +159,10 @@ EOF scan $EXTRA_ARGS } -# Self-update tracks the latest launcher on `main` so users always run the -# newest version. DEVA11Y-475/477/478: we deliberately follow main HEAD rather -# than a pinned revision (per maintainer intent: always take the latest). +# Self-update pulls the latest launcher from `main` on demand: it runs only via +# the explicit `self-update` subcommand (DEVA11Y-475), not automatically on every +# invocation. DEVA11Y-477/478: when it does run we deliberately follow main HEAD +# rather than a pinned revision (per maintainer intent: take the latest on demand). # Hardening retained from the pinning work: download to a temp dir, verify a # SHA-256 sidecar (a download-integrity check, NOT an authenticity signature -- # script and checksum share one origin), sanity-check the shebang, then @@ -259,16 +260,19 @@ script_self_update() { fi } -# Best-effort auto-update: always fetch the latest launcher from main before -# running. Network/offline failures are silent (rc 0) and operational errors -# (rc 1) are non-fatal -- the existing script keeps working. An integrity -# failure (rc 2: checksum mismatch or non-script payload) leaves the verified -# on-disk script untouched and is surfaced loudly below, but still does not -# block the tool (per the always-run-latest, never-block design). -_self_update_rc=0 -script_self_update || _self_update_rc=$? -if [[ "$_self_update_rc" -eq 2 ]]; then - echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 +# Self-update is opt-in (DEVA11Y-475): it runs only via the explicit `self-update` +# subcommand, never automatically on every invocation. Running it unconditionally +# before subcommand parsing meant a single compromise of the fetched source silently +# replaced the running script on every developer's machine, with no way to opt out; +# gating it behind an explicit command removes that always-on side-effect. Integrity +# verification (SHA-256 check + atomic staging) still guards the download itself. +if [[ $SUBCOMMAND == "self-update" ]]; then + _self_update_rc=0 + script_self_update || _self_update_rc=$? + if [[ "$_self_update_rc" -eq 2 ]]; then + echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 + fi + exit "$_self_update_rc" fi if [[ $SUBCOMMAND == "register-pre-commit-hook" ]]; then diff --git a/scripts/fish/spm.sh.sha256 b/scripts/fish/spm.sh.sha256 index b812bfe..7aac3c4 100644 --- a/scripts/fish/spm.sh.sha256 +++ b/scripts/fish/spm.sh.sha256 @@ -1 +1 @@ -87bf749b365b86157934671d913b3e4bcdb2b54e43b765d0850218d442ca4e26 spm.sh +982bbb10bb9bd55428208454a766384fae58c41dacabb1e5b8a74d2366f0d1e7 spm.sh diff --git a/scripts/zsh/cli.sh b/scripts/zsh/cli.sh index 01892ad..8d11b0e 100644 --- a/scripts/zsh/cli.sh +++ b/scripts/zsh/cli.sh @@ -89,9 +89,10 @@ a11y_scan() { $BINARY_PATH a11y $EXTRA_ARGS } -# Self-update tracks the latest launcher on `main` so users always run the -# newest version. DEVA11Y-475/477/478: we deliberately follow main HEAD rather -# than a pinned revision (per maintainer intent: always take the latest). +# Self-update pulls the latest launcher from `main` on demand: it runs only via +# the explicit `self-update` subcommand (DEVA11Y-475), not automatically on every +# invocation. DEVA11Y-477/478: when it does run we deliberately follow main HEAD +# rather than a pinned revision (per maintainer intent: take the latest on demand). # Hardening retained from the pinning work: download to a temp dir, verify a # SHA-256 sidecar (a download-integrity check, NOT an authenticity signature -- # script and checksum share one origin), sanity-check the shebang, then @@ -194,16 +195,19 @@ download_binary() { bsdtar -xvf "$BINARY_ZIP_PATH" -O > "$BINARY_PATH" && chmod 0775 "$BINARY_PATH" } -# Best-effort auto-update: always fetch the latest launcher from main before -# running. Network/offline failures are silent (rc 0) and operational errors -# (rc 1) are non-fatal -- the existing script keeps working. An integrity -# failure (rc 2: checksum mismatch or non-script payload) leaves the verified -# on-disk script untouched and is surfaced loudly below, but still does not -# block the tool (per the always-run-latest, never-block design). -_self_update_rc=0 -script_self_update || _self_update_rc=$? -if [[ "$_self_update_rc" -eq 2 ]]; then - echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 +# Self-update is opt-in (DEVA11Y-475): it runs only via the explicit `self-update` +# subcommand, never automatically on every invocation. Running it unconditionally +# before subcommand parsing meant a single compromise of the fetched source silently +# replaced the running script on every developer's machine, with no way to opt out; +# gating it behind an explicit command removes that always-on side-effect. Integrity +# verification (SHA-256 check + atomic staging) still guards the download itself. +if [[ $SUBCOMMAND == "self-update" ]]; then + _self_update_rc=0 + script_self_update || _self_update_rc=$? + if [[ "$_self_update_rc" -eq 2 ]]; then + echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 + fi + exit "$_self_update_rc" fi if [[ $SUBCOMMAND == "register-pre-commit-hook" ]]; then diff --git a/scripts/zsh/cli.sh.sha256 b/scripts/zsh/cli.sh.sha256 index 7853e23..445f73c 100644 --- a/scripts/zsh/cli.sh.sha256 +++ b/scripts/zsh/cli.sh.sha256 @@ -1 +1 @@ -0a6efbbe2e0578b6e8037bb149145148d2767208636c3899d0b275a319073263 cli.sh +67edf6abb80741b1f723f07533448288de7652aba859499d287672e8c6c299b4 cli.sh diff --git a/scripts/zsh/spm.sh b/scripts/zsh/spm.sh index 13a9456..9619a0b 100644 --- a/scripts/zsh/spm.sh +++ b/scripts/zsh/spm.sh @@ -158,9 +158,10 @@ EOF scan $EXTRA_ARGS } -# Self-update tracks the latest launcher on `main` so users always run the -# newest version. DEVA11Y-475/477/478: we deliberately follow main HEAD rather -# than a pinned revision (per maintainer intent: always take the latest). +# Self-update pulls the latest launcher from `main` on demand: it runs only via +# the explicit `self-update` subcommand (DEVA11Y-475), not automatically on every +# invocation. DEVA11Y-477/478: when it does run we deliberately follow main HEAD +# rather than a pinned revision (per maintainer intent: take the latest on demand). # Hardening retained from the pinning work: download to a temp dir, verify a # SHA-256 sidecar (a download-integrity check, NOT an authenticity signature -- # script and checksum share one origin), sanity-check the shebang, then @@ -258,16 +259,19 @@ script_self_update() { fi } -# Best-effort auto-update: always fetch the latest launcher from main before -# running. Network/offline failures are silent (rc 0) and operational errors -# (rc 1) are non-fatal -- the existing script keeps working. An integrity -# failure (rc 2: checksum mismatch or non-script payload) leaves the verified -# on-disk script untouched and is surfaced loudly below, but still does not -# block the tool (per the always-run-latest, never-block design). -_self_update_rc=0 -script_self_update || _self_update_rc=$? -if [[ "$_self_update_rc" -eq 2 ]]; then - echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 +# Self-update is opt-in (DEVA11Y-475): it runs only via the explicit `self-update` +# subcommand, never automatically on every invocation. Running it unconditionally +# before subcommand parsing meant a single compromise of the fetched source silently +# replaced the running script on every developer's machine, with no way to opt out; +# gating it behind an explicit command removes that always-on side-effect. Integrity +# verification (SHA-256 check + atomic staging) still guards the download itself. +if [[ $SUBCOMMAND == "self-update" ]]; then + _self_update_rc=0 + script_self_update || _self_update_rc=$? + if [[ "$_self_update_rc" -eq 2 ]]; then + echo "Self-update: integrity verification FAILED; kept the existing verified script (possible corruption or tampering)." >&2 + fi + exit "$_self_update_rc" fi if [[ $SUBCOMMAND == "register-pre-commit-hook" ]]; then diff --git a/scripts/zsh/spm.sh.sha256 b/scripts/zsh/spm.sh.sha256 index 3702f78..0cac838 100644 --- a/scripts/zsh/spm.sh.sha256 +++ b/scripts/zsh/spm.sh.sha256 @@ -1 +1 @@ -c798dc6be53c1dfdfa5113697cfe1a23ef48ccf33206e9484feb671d84bad45c spm.sh +1f28d5b3025636d9b81299032f34886f8804b1c6c95b830204325b325bd1d84f spm.sh