mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-07 07:18:18 +00:00
The changelog said nothing had been released since 1.0.0. Twenty-two builds had shipped. Twenty-one entries sat under "## Unreleased" in a file with exactly two headings, so a reader at any tag found no section for the version they were holding. Which release carried which entry is DERIVED, not guessed: for every line in the region, the commit that introduced it, then the earliest tag containing that commit. That yields seven releases - .22, .21, .20, .19, .14, .8 and .0. No entry text changed. A verification pass compares the multiset of non-heading lines before and after and refuses to write if anything was lost, gained or duplicated; entries move under their release, so it compares as a multiset rather than in order. CHANGELOG.txt was kept BY HAND and drifted the moment the .md was reorganised, which is the failure the plain-text-twin rule exists to prevent. readme_txt.py becomes plaintext_twins.py and renders every pair. It also drops <!-- --> markers, invisible in markdown and stray punctuation in a text file - that is the whole of README.txt's diff. The --check that keeps twins honest was never run. readme_txt.py shipped one and its docstring claimed "the test suite runs --check"; nothing invoked it, so a twin could disagree with its markdown indefinitely. tests/PlainTextTwins.Tests.ps1 runs it. That test skipped on its first run while claiming to pass: -Skip is evaluated during DISCOVERY, before BeforeAll, so the python lookup left the flag $null. Resolved in BeforeDiscovery, and when python really is absent the result is INCONCLUSIVE rather than a green tick for a check that never happened. Mutation-checked: appending one line to CHANGELOG.txt fails "every twin is in sync with its markdown", and only that test. tests: 243 passed, 0 failed, 1 skipped (the no-python reporter, correctly).
313 lines
15 KiB
Plaintext
313 lines
15 KiB
Plaintext
Evomedia.net Token Savers — https://github.com/evomedia-net/evo.zscripts
|
|
Created by Kelly Michels · dev@evomedia.net
|
|
Licensed under the MIT License. See LICENSE.
|
|
|
|
Changelog
|
|
=========
|
|
|
|
Notable changes to the Evomedia.net Token Savers.
|
|
|
|
Unreleased
|
|
----------
|
|
|
|
Changed
|
|
-------
|
|
- Every release since 1.0.0 has its own section again - 21 entries had
|
|
piled up under Unreleased while 22 builds shipped, so this file said
|
|
nothing had been released since 1.0.0 and a reader at any tag found no
|
|
section for the version they were holding. Which release carried which
|
|
entry was derived from git, not guessed: for every line, the commit that
|
|
introduced it, then the earliest tag containing that commit. No entry text
|
|
changed - only headings were added and whole entries moved under the
|
|
release that carried them.
|
|
- **scripts/readme_txt.py is now scripts/plaintext_twins.py and covers
|
|
every markdown file that owes a twin**, CHANGELOG.txt included. It was
|
|
kept by hand, so it drifted the moment this file was reorganised. The
|
|
renderer also drops <!-- --> markers, which are invisible in markdown
|
|
and read as stray punctuation in a text file.
|
|
|
|
Fixed
|
|
-----
|
|
- The --check that keeps the twins honest is actually run now -
|
|
readme_txt.py shipped one and its docstring claimed "the test suite runs
|
|
--check", but nothing invoked it, so a twin could disagree with its
|
|
markdown indefinitely. tests/PlainTextTwins.Tests.ps1 runs it, and
|
|
reports inconclusive rather than passing when python is unavailable.
|
|
|
|
v1.0.0.0.22 - 2026-08-31
|
|
------------------------
|
|
|
|
Changed
|
|
-------
|
|
- The sanitization denylist moved to tests/sanitization-patterns.psd1,
|
|
so the test suite here and the publisher in the private toolkit read one
|
|
list instead of keeping two. They had two, and they disagreed: the
|
|
publisher's scan looked only for secrets, while these rules are about
|
|
identity — internal project names, product domains, private-only script
|
|
names, operator paths. It therefore reported "clean" on files this suite
|
|
rejects. No rule changed; only where they live.
|
|
|
|
v1.0.0.0.21 - 2026-08-31
|
|
------------------------
|
|
|
|
Added
|
|
-----
|
|
- tests/VerifyPlan.Tests.ps1 — the verification channel-selection rules
|
|
are pure functions in ZHelpers.ps1 (Get-VerifyAttempts,
|
|
Get-VerifyTimeout) and Pester pins them, including "a project with no
|
|
domain must never produce an edge attempt" and the PowerShell 5.1
|
|
one-element-unroll trap.
|
|
|
|
- scripts/readme_txt.py and README.txt — a generated plain-text twin
|
|
of the README for terminals and pagers. README.txt is generated, never
|
|
edited by hand.
|
|
|
|
Changed
|
|
-------
|
|
- **zdeploy verification picks its channel on every retry, and never asks
|
|
the bare IP** — the check used to choose its channel once, before the wait
|
|
loop, by probing; the probes raced the app restart the check exists to wait
|
|
through, so the whole window went to the edge fallback. For a project with
|
|
no domain that fallback had no Host header, and the proxy can then only
|
|
answer from its default vhost — a different product: that is how one
|
|
deploy's check compared another app's build number against its own. Now
|
|
channels are re-resolved each retry in trust order (docker-network
|
|
viaProxy → localhost:<port> → edge with the project's Host), the edge
|
|
is skipped entirely when there is no host to route by, and a project with
|
|
no trustworthy channel is reported as unverifiable instead of guessed at.
|
|
The final warning also says which failure happened: a version that never
|
|
matched (stale/failed build) reads differently from channels that never
|
|
answered (probably still booting). verify.timeoutSeconds joins the
|
|
config so a project that is slow to boot — e.g. one that runs database
|
|
migrations in its entrypoint — can widen its own window instead of
|
|
warning on every routine success.
|
|
|
|
- An interrupted deploy can no longer destroy server-side .env files —
|
|
the preserve/restore of operator files is transactional: the restore comes
|
|
from a tarball taken before the tree is replaced, so a deploy that dies
|
|
mid-flight leaves the previous files in place instead of an empty
|
|
directory.
|
|
|
|
- A successful deploy no longer reports failure — `docker compose
|
|
restart` writes routine progress to stderr, which PowerShell 5.1 turns
|
|
into a terminating error under $ErrorActionPreference = 'Stop'; four ssh
|
|
calls bypassed the wrapper that flattens this. All remote steps now run
|
|
through it and are judged by exit code alone.
|
|
|
|
v1.0.0.0.20 - 2026-08-30
|
|
------------------------
|
|
|
|
Changed
|
|
-------
|
|
- **zversion bump is once per release, not once per PR** — the usage text
|
|
and the bump help line both said "one per PR, one per defect fix". The
|
|
build number names something that shipped, so a release carrying five PRs
|
|
moves it by one; PRs that never shipped on their own were never separate
|
|
builds. Help text only here, but it is the wording people follow: it stamped
|
|
a single evo.www release as two builds. The historical entry below, which
|
|
records what the rule was when zversion shipped, is deliberately left as
|
|
written.
|
|
|
|
v1.0.0.0.19 - 2026-08-30
|
|
------------------------
|
|
|
|
Added
|
|
-----
|
|
- **Read a live build from inside the docker network, not through the public
|
|
proxy** — zdeploy, zec2 and zec2online now prefer
|
|
docker exec <viaProxy> curl http://<upstream>/api/build-version when a
|
|
project sets verify.viaProxy and verify.upstream.
|
|
|
|
Two problems it closes. A build stamp is something many sites deliberately
|
|
do not serve publicly, and a checker that reads it over the public URL stops
|
|
working the moment that endpoint is blocked — reporting "unknown", which is
|
|
indistinguishable from "could not reach it". And the proxy answers from
|
|
whichever vhost matches the Host header, so a container with no public route
|
|
was getting another site's version back and failing deploys that had
|
|
worked.
|
|
|
|
Reading it from a container on the shared network also exercises the real
|
|
HTTP path, so it proves the app is serving rather than that its database
|
|
knows a version. Purely additive: projects without those two keys behave
|
|
exactly as before.
|
|
|
|
v1.0.0.0.14 - 2026-08-20
|
|
------------------------
|
|
|
|
Fixed
|
|
-----
|
|
- scp no longer receives an ssh-only flag — the stdin-hang fix added
|
|
-n to Get-Ec2SshOpts, and the deploy path splats that same array into
|
|
scp as well as ssh. OpenSSH's scp has no -n: it exits 1 with
|
|
unknown option -- n and prints its usage block, so every upload failed.
|
|
Get-Ec2ScpOpts now supplies the shared connection options with -n
|
|
filtered out, derived from Get-Ec2SshOpts rather than duplicated so the
|
|
timeouts cannot drift apart between the two transports. All four scp
|
|
call sites use it, including the recursive directory upload.
|
|
The upload failure message also asserted "Likely server disk space"
|
|
without checking; it now points at scp's own output, where the real
|
|
diagnosis already was.
|
|
|
|
v1.0.0.0.8 - 2026-08-12
|
|
-----------------------
|
|
|
|
Fixed
|
|
-----
|
|
- Deploys can no longer hang forever on an ssh prompt — every
|
|
deploy-path ssh/scp now carries BatchMode=yes plus connect and
|
|
keepalive timeouts (Get-Ec2SshOpts in ZHelpers.ps1). Without
|
|
BatchMode, ssh prompts for a passphrase or password and waits
|
|
indefinitely; because the deploy pipes stderr through the pipeline, the
|
|
prompt never reaches the screen and the run just stops under whatever
|
|
step label printed last, with no explanation. Now it fails immediately —
|
|
there is no prompt on this path worth answering. ServerAlive* bounds a
|
|
session that dies mid-command (dropped VPN, sleeping laptop, rebooting
|
|
host) to about a minute instead of hanging.
|
|
|
|
- Vendored archives survive the archive filter — files under a
|
|
vendor/ directory are exempt from the "no archives in the zip" rule.
|
|
A project that vendors a dependency as vendor/*.tgz needs it in the
|
|
deploy zip; dropping it makes a Dockerfile's COPY vendor ./vendor
|
|
fail at image build, a confusing way to learn the filter ate a build
|
|
input.
|
|
|
|
- unzip install is idempotent — the remote step ran
|
|
apt-get update && apt-get install -y unzip on every deploy; it now
|
|
checks command -v unzip first and skips the apt round-trip when the
|
|
binary is already there.
|
|
|
|
- zdeploy edge kind now ships asset subdirectories (#42) — the edge
|
|
deploy uploaded top-level files only, so a project self-hosting assets
|
|
in folders (fonts/, vendor/) lost them on every deploy: docker
|
|
created empty root-owned mount points and nginx served 404s from them,
|
|
which shows up as fonts silently falling back and vendored JS never
|
|
loading. Every subdirectory except nginx-logs/ and .git/ now ships
|
|
recursively, and the ensure edge dir chown is recursive so scp into
|
|
docker-created root-owned dirs cannot fail.
|
|
|
|
v1.0.0.0.0 - 2026-07-28
|
|
-----------------------
|
|
|
|
Added
|
|
-----
|
|
- Versioned releases: zversion, zrelease, releases/ — the toolkit now
|
|
carries one version in a 5-segment scheme,
|
|
v{major}.{rc}.{beta}.{alpha}.{build}. zversion bump (one per PR / defect
|
|
fix) and zversion bump-stage release|rc|beta|alpha (zeroes every lower
|
|
segment) rewrite build-version.json, stamp # Version: into every script
|
|
header — so a lone copied script still says which release it came from — and
|
|
regenerate CHECKSUMS.txt in the same step. zrelease packages the current
|
|
version as releases/zscripts-<version>.zip with a .sha256 beside it: one
|
|
hash verifies the download, the bundled CHECKSUMS.txt verifies the
|
|
extracted contents, so nobody needs to clone the repo to get a verifiable
|
|
copy. Released zips are immutable — zrelease refuses to overwrite one.
|
|
|
|
- zchecksums + CHECKSUMS.txt — a SHA-256 manifest covering every .ps1
|
|
and .cmd, so a download can be verified before anything is run. zchecksums
|
|
checks them; zchecksums -Update regenerates after an intentional edit. The
|
|
manifest is sha256sum format, so sha256sum -c CHECKSUMS.txt works on
|
|
Linux/macOS/WSL too, and the hashes match on every platform because
|
|
.gitattributes pins these files to CRLF everywhere. Flags changed files,
|
|
missing files, and scripts present on disk but absent from the manifest.
|
|
It's an integrity check, not a signature — the manifest sits in the same repo
|
|
as the code, so it catches corruption and accidental drift, not a compromised
|
|
repo. A Pester test fails if the manifest ever goes stale.
|
|
|
|
- Test suite (Pester) — the toolkit now has automated coverage of its own
|
|
pure logic: Get-ArchiveExcludes (including the deploy-vs-backup rule that
|
|
keeps .env/uploads out of deploys but in backups), config and project
|
|
lookups, remote.composeDir fallback, EC2 target composition, and build-label
|
|
formatting. Run with Invoke-Pester .\tests (Pester 5+). Verified by mutation
|
|
testing — reintroducing each historical bug turns the suite red.
|
|
|
|
- ZCONFIG environment variable — overrides the path to zconfig.json, so
|
|
a run can target an alternate config. Also gives the test suite a seam for
|
|
injecting a fixture.
|
|
|
|
- zec2_rotatekeys — safely rotate/reset server-side secrets — a new
|
|
tool for when a secret leaks or a deploy overwrites a production .env
|
|
with dev values. -Rotate KEY regenerates a key on the server
|
|
(openssl rand -hex 32) so the new value never leaves the box; -Set KEY
|
|
takes an operator-known value (e.g. DATABASE_URL, ADMIN_EMAIL) from a
|
|
masked prompt and streams it over SSH stdin — never a command argument,
|
|
never echoed. Backs the server .env up to a timestamped .bak first,
|
|
updates the key atomically (matches or appends), auto-detects
|
|
backend/.env from deploy.preserve, and with -Restart recreates
|
|
the container (up -d --force-recreate, so the new values actually load —
|
|
a plain restart keeps the old environment). -WhatIf previews the plan
|
|
without touching anything.
|
|
|
|
- zkill all — zkill now accepts all, stopping the dev server of
|
|
every project that has a ports.dev (edge/docker stacks with no local dev
|
|
server are skipped). Brings it in line with zdeploy all / zbackup all;
|
|
the one-shot "stop everything I've got running locally".
|
|
|
|
- zdeploy server-side health verification (verify block) — projects
|
|
not published through the edge proxy can declare
|
|
"verify": { "port": ..., "path": "/health", "expect": "..." } and the
|
|
deploy is checked from the server itself (curl localhost:<port><path>
|
|
over SSH) instead of hitting the public IP. Fixes a false PASS where the
|
|
proxy's default vhost answered for apps that never started; projects
|
|
with neither domain nor verify are now reported as NOT verified.
|
|
|
|
- zdeploy optional deploy.gitPull — git pull --ff-only in the
|
|
project root before zipping. zdeploy zips the working tree and doesn't
|
|
otherwise pull, so a checkout left behind origin after a merged PR would
|
|
deploy stale code while still bumping the build number — success that
|
|
changes nothing. A failed pull aborts the deploy instead.
|
|
|
|
- Per-project start config block — zstart honors optional pre-start
|
|
steps from zconfig.json: "gitPull": true runs git pull --ff-only in
|
|
the project root before starting (never boot a stale checkout), and
|
|
"env": { ... } sets environment variables for the dev-server process.
|
|
Example added to zconfig.example.json.
|
|
|
|
- Switch-style argument tolerance — a leading dash on a project key is
|
|
ignored everywhere (zdeploy -myapp == zdeploy myapp), for hands that
|
|
grew up on per-project switches.
|
|
|
|
Changed
|
|
-------
|
|
- zbackup / zbackup_and_sync require an explicit target — running
|
|
them bare now shows usage instead of quietly backing up every project;
|
|
all does what bare invocation used to (matching zdeploy). The
|
|
scheduled task created by setup_backup_schedule.ps1 passes all —
|
|
re-run it if your task was registered before this change.
|
|
|
|
- zbackup parses more DATABASE_URL styles — double/single-quoted
|
|
values (Prisma convention), postgres:// and postgresql+driver://
|
|
schemes, and URLs without an explicit port (defaults to 5432) all work;
|
|
previously these skipped the Postgres dump with "Could not parse
|
|
DATABASE_URL".
|
|
|
|
- zkill / port cleanup kills the whole process tree — listeners on a
|
|
project's port are now terminated children-first. Auto-reloading servers
|
|
(uvicorn/watchfiles, nodemon) spawn workers that inherit the listening
|
|
socket; killing only the parent left orphans serving stale code.
|
|
|
|
- zbackup finds DATABASE_URL in backend\.env too — projects with a
|
|
frontend/backend split get their Postgres dump bundled without needing a
|
|
root-level .env.
|
|
|
|
Fixed
|
|
-----
|
|
- zdeploy no longer deletes operator-managed files on deploy (#2) —
|
|
the project-directory replacement preserved only ./.env, silently
|
|
destroying every other server-side file (.env.db, staged signing
|
|
keys, certs) on every deploy. All .env* files at the project root are
|
|
now preserved by default, plus anything listed in the new
|
|
deploy.preserve array (files or directories); the vite kind, which
|
|
previously preserved nothing, gets the same protection. Found the hard
|
|
way: a first production deploy of an auth service wiped its staged DB
|
|
credentials and RSA signing keys.
|
|
|
|
1.0.0
|
|
-----
|
|
|
|
Initial public release: zstart / zkill / zrestart (local dev servers),
|
|
zdeploy (zip → upload → compose build → live build-version verification,
|
|
with handlers for python / vite / nextjs / edge / docker project kinds),
|
|
zec2 / zec2online / zrepair (health checks and recovery), zbackup /
|
|
zbackup_ec2 / zsync (local, server-side, and offsite backups), all driven
|
|
by a single gitignored zconfig.json.
|