Files
PS5_RetroArch/tools/lint-shell.sh
T
Mihawk cfad33bc2e Scraping: ScreenScraper as a source, with a sign-in that stays on the console
- Sign-in: clicking ScreenScraper opens a login form. The name and password go to the
  console in a request body, are checked with ScreenScraper (ssuserInfos), then kept in
  config/private/screenscraper.cfg (0600, folder 0700, out of the 0777 repair, never
  served). No answer carries the password. A green check on the chip when signed in;
  Manage shows the quota, switches account or signs out.
- Engine: jeuInfos by CRC, file name and size, then jeuRecherche ("Name [id]"
  candidates; the same title taken unasked, others resolved from the page). Details in
  the language asked for (description, genre, developer, publisher, players, rating
  0-1, release date); media per kind and region; the account's maxthreads kept; 429
  waits; 401/403/423/426/430/431 pause the job with a message, resumable.
- The developer account: generated scrambled into build/screenscraper_dev.h from .env;
  releases carry it scrambled (owner's decision), PS5_SCREENSCRAPER_EXCLUDE=1 leaves it
  out. https only (media links upgraded, no https->http redirects). PC mode is refused
  for ScreenScraper: its media links carry the developer account, which never leaves
  the console. lint-shell fails on a plain copy in any tracked or shipped file.
- ES-DE: release dates become YYYYMMDDT000000.
- Systems table generated from ES-DE's ScreenScraper ids (MIT notice kept).

Evidence: evidence/scraper-screenscraper (6 host tests against a fake ScreenScraper API,
fake accounts, plus the leak check); reproduce with
  python3 -m unittest -v tests.test_scraper_screenscraper; bash tools/lint-shell.sh
tools/verify.sh: PASS (format unit build integration evidence).
Not verified: a live sign-in and job against api.screenscraper.fr (owner's run).
2026-10-07 12:02:10 -04:00

102 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# PS5 RetroArch - the format gate's first half: syntax, and the Python side.
#
# bash tools/lint-shell.sh
#
# What this checks, and what it deliberately does not. There is no shellcheck and
# no shfmt on the machine this was written on, so this gate is not a style check;
# it is the check that a script parses. That is worth having on its own: a
# malformed tools/*.sh is discovered by whichever build step runs it, which on
# this project is often a 60-second compile or a deploy, and the failure then
# looks like a build failure rather than a typo in a file nobody was editing.
#
# The Python half is the same idea with `ast`, which imports nothing and runs
# nothing - a tool that has a syntax error and a side effect on import does not
# get to have the side effect here.
#
# Secrets are checked for, not read: .env is git-ignored and no committed file may
# name a console address or a credential. The rule is in AGENTS.md, and a grep is
# the cheapest way to keep it true.
set -euo pipefail
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
cd "$root"
failures=0
note() { printf ' %s\n' "$*"; }
bad() { printf ' FAIL %s\n' "$*" >&2; failures=$((failures + 1)); }
# Files this project maintains. vendor/ and build/ are fetched or generated, and
# their syntax is not this project's responsibility.
mapfile -t shells < <(find tools -maxdepth 1 -type f -name '*.sh' | sort)
(( ${#shells[@]} )) || bad 'no shell scripts found under tools/'
echo "==> [lint-shell] syntax of ${#shells[@]} scripts"
for script in "${shells[@]}"; do
if bash -n "$script" 2>/tmp/lint-shell.error; then
note "ok $script"
else
bad "$script: $(head -1 /tmp/lint-shell.error)"
fi
done
mapfile -t pythons < <(find tools tests -maxdepth 1 -type f -name '*.py' 2>/dev/null | sort)
echo "==> [lint-shell] syntax of ${#pythons[@]} python tools"
for script in "${pythons[@]}"; do
if python3 -c 'import ast,sys; ast.parse(open(sys.argv[1], encoding="utf-8").read())' "$script" 2>/tmp/lint-python.error; then
note "ok $script"
else
bad "$script: $(tail -1 /tmp/lint-python.error)"
fi
done
echo "==> [lint-shell] editors and line endings"
# A script with CRLF or a stray byte-order mark fails on the console-facing side
# of this project in ways that read as "command not found" with no obvious cause.
while IFS= read -r file; do
if LC_ALL=C grep -q $'\r' "$file"; then
bad "$file: contains a carriage return (CRLF line ending)"
fi
if head -c 3 "$file" | LC_ALL=C grep -q $'\xef\xbb\xbf'; then
bad "$file: starts with a byte-order mark"
fi
done < <(find tools patches -type f \( -name '*.sh' -o -name '*.py' -o -name 'series' \) 2>/dev/null | sort)
note 'checked for CRLF and byte-order marks'
echo "==> [lint-shell] no committed console address or credential"
# The value itself is not printed: a gate that echoes a secret into a log has
# published it. Only the file and the key are named.
leaks=0
while IFS= read -r hit; do
printf ' FAIL %s\n' "$hit" >&2
leaks=$((leaks + 1))
done < <(grep -rlnE '(PS5_HOST|PS5_FTP_PASSWORD|KLOG_PORT|PS5_CTL_PORT)[[:space:]]*=[[:space:]]*[^[:space:]]' \
--include='*.sh' --include='*.py' --include='*.md' --include='*.json' --include='*.yml' \
tools docs patches README.md AGENTS.md Makefile 2>/dev/null | sort)
(( leaks == 0 )) || failures=$((failures + leaks))
echo "==> [lint-shell] the ScreenScraper developer account is in no tracked or shipped file"
# The account lives in .env alone (git-ignored); local builds carry it scrambled
# (tools/build-webui-daemon.sh), release builds not at all. Its values are searched
# for, never printed: in every tracked file, and in the shipped tree under dist/.
env_file=${LINT_ENV:-.env} # LINT_ENV: a fake one, to test this check
if [[ -f $env_file ]]; then
while IFS= read -r key; do
value=$(sed -n "s/^${key}=//p" "$env_file" | tail -1 | tr -d '"')
[[ -n $value ]] || continue
while IFS= read -r hit; do
printf ' FAIL %s holds %s\n' "$hit" "$key" >&2
failures=$((failures + 1))
# Each search may find nothing (status 1): under set -e it must not end the rest.
done < <({ git ls-files -z | xargs -0 grep -lF -- "$value" 2>/dev/null || true
if [[ -d dist ]]; then grep -rlF -- "$value" dist 2>/dev/null || true; fi; } | sort -u)
done < <(printf '%s\n' PS5_SCREENSCRAPER_DEVID PS5_SCREENSCRAPER_DEVPASSWORD)
fi
if (( failures > 0 )); then
printf 'lint-shell: %s problem(s)\n' "$failures" >&2
exit 1
fi
echo "lint-shell: PASS"