Reinstalling the package was slow because setup rebuilds pysim's
prerequisites (pyscard compiles from source on Linux), while a clone
updates with a plain `git pull`.
- tools/update.py (+ update.sh / update.bat in the package, and the
release workflow shipping them) updates a packaged install in place:
it downloads the latest release package, extracts it (zip-slip guard,
permission bits restored - zipfile drops them), replaces the app files
over the app directory and re-installs the app into the existing
.venv. The .venv and simple_lastrun.log are not in the package, so
pysim and its prerequisites survive: seconds, not a rebuild.
--check / --version / --zip (offline) / --no-pip / --force; the same
version is a no-op.
- CHANGELOG.md (Keep a Changelog, from the first packaged release;
earlier history is the git log). The release workflow now uses the
version's CHANGELOG section as the release body
(tools/changelog_section.py, falling back to generated notes).
- The READMEs document the update path and the `git clone --depth 1`
option for the clone path; setup prints the update hint.
- Version strings + the PWA cache bumped together (simple-v458).
Verified: 1007 Python + 953 frontend; the release-package test covers
the new files; the updater was exercised end to end (a v3.31.2 install
with a real venv updated to the 3.32.0 package: files replaced, the
venv marker kept, pip metadata 3.32.0, exec bits kept, a second run a
no-op, --check correct).
The READMEs now point users at a release package instead of a clone; this
adds the machinery behind it.
- tools/build_release.py builds dist/simple-<version>.zip: the runtime
tree (the server package incl. its bundled MCC/MNC list, the PWA
runtime files, docs/, tools/, the setup/start scripts, pyproject,
requirements-pysim.txt, the READMEs, LICENSE and THIRD-PARTY-NOTICES)
under a single top-level directory, with no tests, no frontend
sources/build config, no bytecode and no git metadata. The version
comes from server.py; --expect-version guards a mislabeled tag.
- .github/workflows/release.yml runs both test suites, builds the
package and publishes it on a v* tag (workflow_dispatch for an
existing tag); a re-run uploads with --clobber. pysim is checked out
next to the repo for the Python suite and is NOT bundled.
- tests/test_release_package.py pins the package's shape: the runtime
files, the absence of the development files, and that sw.js's
precache list is fully covered - so a new asset cannot silently go
missing.
- dist/ is gitignored; the READMEs name the artifact.
Verified: 997 Python + 953 frontend green; the built zip (53 files,
~0.95 MB) was unpacked in a clean directory and its setup.sh installed it
into a fresh venv - the console script runs and the installed server
resolves web_dir to the unpacked frontend/ (index.html, sw.js,
uicc_files.json present). The workflow YAML parses; GitHub-side
execution is unverified until the first tag is pushed.
- scp81.py: PSK TLS listener (stdlib ssl PSK callbacks) speaking the GP
HTTP administration dialog; configurable framing (chunked/Content-Length,
TLS record split, Apache-style/compact headers, Connection header,
keep-alive, Next-URI template with %d, TLS version/cipher, answer delay,
keylog for capture decryption)
- server.py: script responder + Response Scripting parsing (AF/AB, 80/23
TLVs), memory decoder, SCP81 start options, terminal-side timer
management, background-mode BIP events, permissive OPEN CHANNEL
- BIP fix: the RECEIVE DATA channel-data TLV length is BER long form
(36 81 <len>) above 127 bytes; a raw length byte is mis-parsed on the
card, so the large TLS records never reached its stack (a live card
fetched the script response and silently never processed it - endless
resume). The card now executes scripts and returns R-APDUs: memory
(13 applets, 50646 B NV free, 2402 B volatile), ISD, stored HTTP OTA
parameters, ELF and application registries
- frontend: SCP81 tab (listener, script selection, HTTP OTA log), phone
event forms, i18n; service worker v141
- docs: api.md, scp81-findings.md (attempt matrix + root cause analysis);
tools/scp81_decrypt.py decrypts listener captures via the keylog
- tests: 187 python + 337 frontend