From 91b638ac31a99b9ad41f9f5d1c1128abb75ad20c Mon Sep 17 00:00:00 2001 From: kellymichels Date: Tue, 28 Jul 2026 13:47:25 -0500 Subject: [PATCH] feat: checksums, toolkit versioning (v{major}.{rc}.{beta}.{alpha}.{build}), and downloadable release zips (#35) * feat(zchecksums): SHA-256 manifest so a download can be verified before it's run CHECKSUMS.txt lists a SHA-256 for every top-level .ps1 and .cmd - the files a user actually executes. zchecksums verifies them; zchecksums -Update regenerates after an intentional edit. The manifest is sha256sum format, so 'sha256sum -c CHECKSUMS.txt' works on Linux/macOS/WSL as well as the PowerShell path on Windows. Hashes are identical on every platform because .gitattributes pins .ps1/.cmd to CRLF everywhere - that pin is now load-bearing, so it is commented as such. Beyond changed and missing files it also reports a script that is on disk but NOT in the manifest, so something added outside a commit still gets noticed. Exits non-zero on any of the three. Honest about its limits, in the header and the README: the manifest lives in the same repo as the code, so it is an integrity check rather than a signature. It catches a truncated clone, a forgotten local edit, or an unlisted file - not a compromised repo. CHECKSUMS.txt is pinned to LF: sha256sum treats a trailing CR as part of the filename and would report every entry as missing on Linux. tests/Checksums.Tests.ps1 keeps it from rotting - a stale manifest is worse than none, since it either cries wolf until people ignore it or quietly stops covering a new script. The tests assert the format, LF endings, sort order, full coverage of on-disk scripts, current hashes, and that zchecksums itself exits 1 on a tampered file (proved by appending a byte and restoring it). * feat(zversion, zrelease): toolkit versioning + downloadable release zips Implements the versioning rule (SmartPlant's 5-segment scheme, now the global standard; currently only sp and zscripts are on it at v1.x): v{major}.{rc}.{beta}.{alpha}.{build} zversion: get / bump / bump-stage / set. A stage bump zeroes every lower segment including build. 'bump' is one per PR and one per defect fix, not per file. Any write rewrites three things together, because they are only useful when they agree: build-version.json (source of truth), a '# Version:' line in all 42 script headers (a lone copied script still says which release it came from), and CHECKSUMS.txt (stamping changes every file). zrelease: packages the current version as releases/zscripts-.zip with a sibling .sha256, for people who want the toolkit without cloning. One hash verifies the download; the bundled CHECKSUMS.txt verifies the extracted contents. Refuses to overwrite an existing version's zip (released = immutable; bump instead), and refuses to package when zchecksums fails. tests/ excluded from the zip; releases/ never packages itself. First release included: releases/zscripts-v1.0.0.0.0.zip (42 scripts + 7 support files) and its .sha256. .gitattributes: releases/*.sha256 pinned LF (sha256sum treats a trailing CR as part of the filename), releases/*.zip marked binary. Verified end-to-end as a downloader would experience it, in WSL: sha256sum -c on the zip passes, unzip, sha256sum -c CHECKSUMS.txt inside gives 42 OK / 0 FAILED, and the extracted zdeploy.ps1 header and build-version.json both read v1.0.0.0.0. Double-release guard and -Verify mode exercised. Full Pester suite 219/219 (the checksum tests absorb the new files automatically). --- .gitattributes | 12 +- CHANGELOG.md | 21 ++++ CHECKSUMS.txt | 42 +++++++ README.md | 41 +++++++ ZHelpers.ps1 | 1 + ZKillOnly.ps1 | 1 + ZKiller.ps1 | 1 + build-version.json | 3 + releases/zscripts-v1.0.0.0.0.zip | Bin 0 -> 89532 bytes releases/zscripts-v1.0.0.0.0.zip.sha256 | 1 + setup_backup_schedule.ps1 | 1 + tests/Checksums.Tests.ps1 | 111 +++++++++++++++++ token-count.ps1 | 1 + zbackup.cmd | 1 + zbackup.ps1 | 1 + zbackup_and_sync.ps1 | 1 + zbackup_ec2.cmd | 1 + zbackup_ec2.ps1 | 1 + zchecksums.cmd | 7 ++ zchecksums.ps1 | 144 ++++++++++++++++++++++ zdeploy.cmd | 1 + zdeploy.ps1 | 1 + zec2.cmd | 1 + zec2.ps1 | 1 + zec2_rotatekeys.cmd | 1 + zec2_rotatekeys.ps1 | 1 + zec2online.cmd | 1 + zec2online.ps1 | 1 + zkill.cmd | 1 + zkill.ps1 | 1 + zrelease.cmd | 7 ++ zrelease.ps1 | 146 ++++++++++++++++++++++ zrepair.cmd | 1 + zrepair.ps1 | 1 + zrestart.cmd | 1 + zrestart.ps1 | 1 + zrestartd.cmd | 1 + zsetup.cmd | 1 + zsetup.ps1 | 1 + zsetup_mail.ps1 | 1 + zstart.cmd | 1 + zstart.ps1 | 1 + zstart_docker.cmd | 1 + zstart_docker.ps1 | 1 + zstartd.cmd | 1 + zstop.ps1 | 1 + zsync.cmd | 1 + zsync.ps1 | 1 + zversion.cmd | 7 ++ zversion.ps1 | 154 ++++++++++++++++++++++++ 50 files changed, 731 insertions(+), 1 deletion(-) create mode 100644 CHECKSUMS.txt create mode 100644 build-version.json create mode 100644 releases/zscripts-v1.0.0.0.0.zip create mode 100644 releases/zscripts-v1.0.0.0.0.zip.sha256 create mode 100644 tests/Checksums.Tests.ps1 create mode 100644 zchecksums.cmd create mode 100644 zchecksums.ps1 create mode 100644 zrelease.cmd create mode 100644 zrelease.ps1 create mode 100644 zversion.cmd create mode 100644 zversion.ps1 diff --git a/.gitattributes b/.gitattributes index 0a2bf76..fe1a4b9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,13 @@ -# PowerShell/cmd are happiest with CRLF on Windows. +# PowerShell/cmd are happiest with CRLF on Windows. The pin matters beyond +# convenience: it makes these files byte-identical on every platform, which is +# what lets CHECKSUMS.txt hold one hash per file rather than one per OS. *.ps1 text eol=crlf *.cmd text eol=crlf + +# The checksum manifest must stay LF: `sha256sum -c` treats a trailing CR as +# part of the filename and reports every entry as missing. +CHECKSUMS.txt text eol=lf +releases/*.sha256 text eol=lf + +# Release zips are binary and immutable. +releases/*.zip binary diff --git a/CHANGELOG.md b/CHANGELOG.md index 70f17d4..fa35f39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,27 @@ Notable changes to the Evomedia.net Token Savers. credentials and RSA signing keys. ### Added +- **Versioned releases: `zversion`, `zrelease`, `releases/`** — the toolkit now + carries one version in the SmartPlant 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-.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 diff --git a/CHECKSUMS.txt b/CHECKSUMS.txt new file mode 100644 index 0000000..cc7c9cd --- /dev/null +++ b/CHECKSUMS.txt @@ -0,0 +1,42 @@ +90e4105107d27a44ee7199e459f86941013d5e29d2a7a53882d48347e05b1530 setup_backup_schedule.ps1 +00ea2054ca36dd84133aaaa381437d39374407b1fcd33caecbdea09b4967247f token-count.ps1 +4903f0194fe749269bb61ffacace6e957ce44503522d625560dcc882b69f91b4 zbackup.cmd +7d8446fc5f04ec1d0f695b6390db5bbfb86f410f6d8aac14720fd3aa4bfa3525 zbackup.ps1 +8b375c8a759e37b812293ae168dcf19ae1ca0c136c9d3f2d7ae90a84c1e26f3f zbackup_and_sync.ps1 +c336a61cb8563736bd6550671d7dc90b14702a43f25a97b1ac15ffd64605fbf6 zbackup_ec2.cmd +47ccde67ba8502997105c995e509c1ed1016ffac264df60c6ac539a5b99eda08 zbackup_ec2.ps1 +20e6282901a919aa32ea717c739ba2dc9657426dff860f0e5fce201edefd99da zchecksums.cmd +692b7b0ff9e51e5d9b880358b33c54d2db4f967297a5350e154df1ce6f06ebc6 zchecksums.ps1 +b56085112e7c573926a70a58872163b71416d58ce91ea7114b1f5de5fc96c982 zdeploy.cmd +8f52b2114c8d84e397b7a4f4e1f45ea7201c59fe3e1b4147fa08ad26d0325035 zdeploy.ps1 +fa817d3bd7bba98b03b411d3c5a82b210d3cca316ac0c9785afa5b4ac5fe0766 zec2.cmd +5f70432af23df3459a98d9ad6a0da723783f2269dd5f5ab8ecdd6366ebc84942 zec2.ps1 +4df94eda29b6f5b2cb6bfa63e0add4d90ea24d936305f36a69988e8dd5d69154 zec2_rotatekeys.cmd +cc980bec4a9205a774c05ee1a7e0473e604adf5370b548015a5cb47412dd5853 zec2_rotatekeys.ps1 +fae88c3d77efaef1a60d8d74bd0ca880ca67f85a2ab302fd182dfeb33e9465ce zec2online.cmd +daf58f09cf118128c69282d51bbcece71cdeb1ce423737f6583ed00be460d98f zec2online.ps1 +2cb21bc7c18ab18e05403b10ca6316b334215ecf359796d53e1b3fe295ac88f2 ZHelpers.ps1 +bace82f5efc0cf63f260ccd5e134032029b70fe633900d3a6345f7eb079c121e zkill.cmd +443af456a5ababda04d882abf28f18079473708a90249c7294d03f8120db60f6 zkill.ps1 +0e95bebabe8e56894c19519b38f57544bfb6903a3fe2f093fb7bf592c68b86da ZKiller.ps1 +957784b0261010baec0966319fddf887171b7835770cd0d4f55fb0c58ee70db2 ZKillOnly.ps1 +70330253df23a140ca4c87a10107eb6dde86fa66292de6a56cda300889b8f329 zrelease.cmd +e29782135c4ca25eeff9655751a80fecda6c8fa8031a478a263ececb29a14937 zrelease.ps1 +8031864bc4ad92e1fc23a6f9ff1886e2b54bde5cda48658f3e4b60b90846937e zrepair.cmd +51ca23196efefa8482a8be88f66239830dbce9e1dcabb98e7c5edf493dc30a2e zrepair.ps1 +b45c4ce12cb0d907cb2bb53a6fb1b4a0e0cfd61d8cc54f14a1badc73a953befb zrestart.cmd +2cb349166a8cc93353fec4b59bbe4b3d9acb10597a06ae6f7317ebd5287a17b1 zrestart.ps1 +7e760b07cbcc0599afc7cbf2a45a05818300e6c1a96c1df7ce835f6d502e080e zrestartd.cmd +f4808922ba1529a50d0f6b69fa1b73c02edbeeba48bd4bb2ada7790d220413d6 zsetup.cmd +f669146bd46a3bebeb66b1cde8ed451557e7528282e4d7f5a04563a23572179f zsetup.ps1 +634a9376513846ba2ee3635afdf515d68626e0144e731d045cbfd7ea60018923 zsetup_mail.ps1 +85f3301616f7409720e4eeb3f3f4e367f0bb1d336fe13123b9ce6674361a6251 zstart.cmd +2e353bee9e7bf78d39c32b98b3375eebff89d5b9c2313fa05b3ff3161e836b91 zstart.ps1 +f6107ca1d887ef1b3f94f51a40772a59d01fa1a582420a74766a2acc68bbe01f zstart_docker.cmd +5f15a05f5972dd8a3d33efa224db2d2640f3562436ec1bc2efb7354fc9b4653f zstart_docker.ps1 +92bd61afa382b1c38bbd33cf19661084ba64cdb8b2ca6690d44c9ea1ee85a6af zstartd.cmd +ecd3bad1348fcd31c15b7365a9bb48742066cf98f0b1dd0aace4c4ce7a384242 zstop.ps1 +8f75cd61112cec34a504073cd6086c18ad5c1c368cd62f9603c04bcd50156189 zsync.cmd +10e22effc5425d29ef3dc6eec9d69709dd02754a3baa5276ffdb1bbfe03a4dde zsync.ps1 +2746c4e003c744f860cec2356844409304c2e9d577bbe6f895f39bc3140ca7d7 zversion.cmd +529d4b2ae72603d2591475d65969bccd3f629522234315051ac95a88f6290a51 zversion.ps1 diff --git a/README.md b/README.md index e700831..bb7d197 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,9 @@ The `.cmd` wrappers are the everyday interface. Every command takes one or more | `zbackup_ec2 [ ...]` | Pull DB dumps + server-side data files down from the server | | `zsync []` | Copy new backups offsite (or build + mirror a vite dist) | | `zstart_docker` | Run a local docker compose stack from `scriptsRoot\docker\` | +| `zchecksums [-Update]` | Verify every script against `CHECKSUMS.txt` (SHA-256) | +| `zversion [bump \| bump-stage \| set ]` | Show or advance the toolkit version (stamps every header) | +| `zrelease [-Verify]` | Package the current version as `releases/zscripts-.zip` + `.sha256` | ### Local development @@ -385,6 +388,44 @@ Give the project a `verify` block instead, and `zdeploy` checks the app **from t 2. That's it: `zstart`, `zkill`, `zrestart`, `zbackup`, `zdeploy`, `zec2`, `zec2online`, `zrepair`, `zstop` all accept the new key immediately. 3. A project whose deploy doesn't fit the python/vite/nextjs/edge/docker patterns needs its own `Invoke-Deploy` function in `zdeploy.ps1` — copy an existing handler; they're all variations on zip → upload → compose up → verify. +## Downloading without cloning + +Each release is packaged as a zip in [`releases/`](releases/) — grab the latest `zscripts-v*.zip`, check it, unzip, done: + +```bash +sha256sum -c zscripts-v1.0.0.0.0.zip.sha256 # verify the download +unzip zscripts-v1.0.0.0.0.zip -d zscripts # extract +cd zscripts && sha256sum -c CHECKSUMS.txt # verify the contents +``` + +The zip contains every command, `CHECKSUMS.txt`, `zconfig.example.json`, and the docs. Versions follow `v{major}.{rc}.{beta}.{alpha}.{build}`; every script header carries the release version it shipped in, so even a single copied file can be traced to its release. + +## Verifying what you downloaded + +`CHECKSUMS.txt` holds a SHA-256 for every `.ps1` and `.cmd` in the repo. Check them before running anything: + +```powershell +zchecksums +``` + +Or with the standard tool on Linux/macOS/WSL — the manifest is `sha256sum` format: + +```bash +sha256sum -c CHECKSUMS.txt +``` + +The hashes are identical on every platform: `.gitattributes` pins `.ps1`/`.cmd` to CRLF everywhere, so a file is byte-for-byte the same whether you cloned on Windows or Linux. + +`zchecksums` flags three things — a file whose contents changed, a listed file that's gone, and a script on disk that **isn't** in the manifest (so something added quietly still gets noticed). It exits non-zero on any of them. + +If you edit a script yourself, regenerate and commit the manifest with it: + +```powershell +zchecksums -Update +``` + +**What this does and doesn't prove.** `CHECKSUMS.txt` lives in the same repo as the scripts, so anyone who could alter a script could alter the manifest too. It's an integrity check, not a signature: it reliably catches a truncated clone, a local edit you forgot about, or a file added outside a commit. It does *not* prove the code came from this project — for that you'd need a signature or a hash published outside this repo. + ## Tests The toolkit has its own [Pester](https://pester.dev) suite covering the pure logic — the exclude lists, config lookups, and version-label formatting that the deploy and backup paths depend on: diff --git a/ZHelpers.ps1 b/ZHelpers.ps1 index 4295bb9..e497c20 100644 --- a/ZHelpers.ps1 +++ b/ZHelpers.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # ZHelpers.ps1 — shared library dot-sourced by every z script. Not run directly. diff --git a/ZKillOnly.ps1 b/ZKillOnly.ps1 index e4a2f1e..4277e20 100644 --- a/ZKillOnly.ps1 +++ b/ZKillOnly.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # ZKillOnly.ps1 — stop local dev server listeners for any project in zconfig.json. # diff --git a/ZKiller.ps1 b/ZKiller.ps1 index 4af1689..bb2f90c 100644 --- a/ZKiller.ps1 +++ b/ZKiller.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # ZKiller.ps1 — kill then restart dev servers for any project in zconfig.json. # diff --git a/build-version.json b/build-version.json new file mode 100644 index 0000000..b3930d1 --- /dev/null +++ b/build-version.json @@ -0,0 +1,3 @@ +{ + "version": "v1.0.0.0.0" +} diff --git a/releases/zscripts-v1.0.0.0.0.zip b/releases/zscripts-v1.0.0.0.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..32387f55c3e9cf21c70836a31c746e53827478fb GIT binary patch literal 89532 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 LCC&hNV}Sh+GYsWs literal 0 HcmV?d00001 diff --git a/releases/zscripts-v1.0.0.0.0.zip.sha256 b/releases/zscripts-v1.0.0.0.0.zip.sha256 new file mode 100644 index 0000000..0e1e2e7 --- /dev/null +++ b/releases/zscripts-v1.0.0.0.0.zip.sha256 @@ -0,0 +1 @@ +17202e39be7b4a5f46418b9f2d1bbfc58c356f591abf416a1c9348b85241f006 zscripts-v1.0.0.0.0.zip diff --git a/setup_backup_schedule.ps1 b/setup_backup_schedule.ps1 index 90e904f..5313c87 100644 --- a/setup_backup_schedule.ps1 +++ b/setup_backup_schedule.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # setup_backup_schedule.ps1 — create a scheduled task for daily backups + OneDrive sync # diff --git a/tests/Checksums.Tests.ps1 b/tests/Checksums.Tests.ps1 new file mode 100644 index 0000000..95d7c0c --- /dev/null +++ b/tests/Checksums.Tests.ps1 @@ -0,0 +1,111 @@ +# Evomedia.net Token Savers - https://github.com/kellymichels/zscripts-token-savers +# Created by Kelly Michels - dev@evomedia.net +# Licensed under the MIT License. See LICENSE. + +# Checksums.Tests.ps1 - keeps CHECKSUMS.txt honest. +# +# Invoke-Pester .\tests +# +# A checksum manifest is worse than useless once it drifts: it either cries wolf +# on every run until people stop reading it, or it quietly stops covering a new +# script. These tests fail the moment the manifest and the scripts disagree, so +# "forgot to run zchecksums -Update" surfaces here rather than in a user's +# verification run. + +BeforeAll { + $script:RepoRoot = Split-Path -Parent $PSScriptRoot + $script:Manifest = Join-Path $script:RepoRoot "CHECKSUMS.txt" + + # Same set zchecksums.ps1 covers: top-level executables. + $script:Covered = @( + Get-ChildItem -LiteralPath $script:RepoRoot -File | + Where-Object { $_.Extension -in @('.ps1', '.cmd') } | + Sort-Object Name + ) + + $script:Listed = [ordered]@{} + if (Test-Path -LiteralPath $script:Manifest) { + foreach ($line in [IO.File]::ReadAllLines($script:Manifest)) { + if ($line -match '^([0-9a-fA-F]{64})\s+(.+)$') { + $script:Listed[$Matches[2].Trim()] = $Matches[1].ToLowerInvariant() + } + } + } +} + +Describe "CHECKSUMS.txt" { + It "exists" { + Test-Path -LiteralPath $script:Manifest | Should -BeTrue + } + + # NOTE: no angle brackets in It names - Pester treats them as -ForEach data + # placeholders and tries to evaluate the contents as an expression. + It "is sha256sum-compatible: 64 hex chars, two spaces, then the filename" { + # Anything else and `sha256sum -c CHECKSUMS.txt` warns or bails, which + # is half the point of publishing it. + foreach ($line in [IO.File]::ReadAllLines($script:Manifest)) { + if (-not $line.Trim()) { continue } + $line | Should -Match '^[0-9a-f]{64} \S.*$' + } + } + + It "uses LF line endings" { + # A trailing CR becomes part of the filename for sha256sum, so every + # entry would report as missing on Linux/macOS. + ([IO.File]::ReadAllText($script:Manifest)) | Should -Not -Match "`r" + } + + It "is sorted by filename" { + $names = @($script:Listed.Keys) + ($names -join ',') | Should -Be (($names | Sort-Object) -join ',') + } +} + +Describe "manifest matches what is on disk" { + It "lists every top-level .ps1 / .cmd (nothing silently uncovered)" { + $missingFromManifest = @($script:Covered.Name | Where-Object { -not $script:Listed.Contains($_) }) + $missingFromManifest -join ', ' | Should -BeNullOrEmpty -Because "these scripts are not in CHECKSUMS.txt - run 'zchecksums -Update'" + } + + It "lists nothing that no longer exists" { + $onDisk = @($script:Covered.Name) + $stale = @($script:Listed.Keys | Where-Object { $onDisk -notcontains $_ }) + $stale -join ', ' | Should -BeNullOrEmpty -Because "these entries point at files that are gone - run 'zchecksums -Update'" + } + + It "records the current hash of <_>" -ForEach @( + (Get-ChildItem -LiteralPath (Split-Path -Parent $PSScriptRoot) -File | + Where-Object { $_.Extension -in @('.ps1', '.cmd') } | + Sort-Object Name | Select-Object -ExpandProperty Name) + ) { + $name = $_ + $script:Listed.Contains($name) | Should -BeTrue -Because "$name is missing from CHECKSUMS.txt" + $actual = (Get-FileHash -LiteralPath (Join-Path $script:RepoRoot $name) -Algorithm SHA256).Hash.ToLowerInvariant() + $actual | Should -Be $script:Listed[$name] -Because "$name changed since CHECKSUMS.txt was written - run 'zchecksums -Update'" + } +} + +Describe "zchecksums.ps1" { + It "verifies clean and exits 0 against the committed manifest" { + $out = & powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $script:RepoRoot "zchecksums.ps1") -Quiet 2>&1 + $LASTEXITCODE | Should -Be 0 -Because ($out -join "`n") + } + + It "exits non-zero when a covered file has been tampered with" { + # Proves the check actually detects a modified script rather than always + # passing. Appends a byte to a real script, verifies, then restores it. + $victim = Join-Path $script:RepoRoot "zchecksums.cmd" + $original = [IO.File]::ReadAllBytes($victim) + try { + [IO.File]::AppendAllText($victim, "REM tampered`r`n") + & powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $script:RepoRoot "zchecksums.ps1") -Quiet *> $null + $LASTEXITCODE | Should -Be 1 + } + finally { + [IO.File]::WriteAllBytes($victim, $original) + } + # Restored, so a normal verify passes again. + & powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $script:RepoRoot "zchecksums.ps1") -Quiet *> $null + $LASTEXITCODE | Should -Be 0 + } +} diff --git a/token-count.ps1 b/token-count.ps1 index c6667bc..849944c 100644 --- a/token-count.ps1 +++ b/token-count.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # token-count.ps1 — measure script output volume to estimate AI agent token costs. # diff --git a/zbackup.cmd b/zbackup.cmd index e29f314..983002e 100644 --- a/zbackup.cmd +++ b/zbackup.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zbackup.ps1" %* diff --git a/zbackup.ps1 b/zbackup.ps1 index a030764..a709384 100644 --- a/zbackup.ps1 +++ b/zbackup.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zbackup.ps1 — local backups: zip project sources (plus a Postgres dump when the # project's .env has a DATABASE_URL) into the backups folder. diff --git a/zbackup_and_sync.ps1 b/zbackup_and_sync.ps1 index 19d9af1..76c38a2 100644 --- a/zbackup_and_sync.ps1 +++ b/zbackup_and_sync.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zbackup_and_sync.ps1 — run backups, then sync the backups folder offsite. # diff --git a/zbackup_ec2.cmd b/zbackup_ec2.cmd index 5d01bfa..c99a0cb 100644 --- a/zbackup_ec2.cmd +++ b/zbackup_ec2.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zbackup_ec2.ps1" %* diff --git a/zbackup_ec2.ps1 b/zbackup_ec2.ps1 index 7d017bd..9de5b54 100644 --- a/zbackup_ec2.ps1 +++ b/zbackup_ec2.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zbackup_ec2.ps1 — pull backups down from the server: a Postgres dump for projects # with a "db" config block, plus a zip of server-side data dirs (uploads/archive/dist). diff --git a/zchecksums.cmd b/zchecksums.cmd new file mode 100644 index 0000000..19c6ebb --- /dev/null +++ b/zchecksums.cmd @@ -0,0 +1,7 @@ +REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers +REM Created by Kelly Michels · dev@evomedia.net +REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 + +@echo off +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zchecksums.ps1" %* diff --git a/zchecksums.ps1 b/zchecksums.ps1 new file mode 100644 index 0000000..c33fcd0 --- /dev/null +++ b/zchecksums.ps1 @@ -0,0 +1,144 @@ +# Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers +# Created by Kelly Michels · dev@evomedia.net +# Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 + +# zchecksums.ps1 - verify (or regenerate) SHA-256 checksums for the scripts. +# +# Usage: +# zchecksums verify every script against CHECKSUMS.txt +# zchecksums -Update regenerate CHECKSUMS.txt after changing a script +# zchecksums -Quiet verify, print only the summary line +# +# Exit codes: 0 = everything matches, 1 = a mismatch, missing or unlisted file. +# +# WHAT THIS DOES AND DOES NOT PROTECT AGAINST +# ------------------------------------------- +# CHECKSUMS.txt lives in the same repo as the scripts, so anyone able to modify +# a script can also modify the manifest. This is an integrity check, not a +# signature. It reliably catches: +# +# * a truncated or corrupted download / clone +# * a file edited locally that you forgot about +# * a script added or removed without going through a commit +# +# It does NOT prove the code came from this project - only a signature (GPG, +# Sigstore) or a hash published somewhere outside this repo can do that. Compare +# against the copy on GitHub if you need that assurance. +# +# Only *.ps1 and *.cmd are covered: they are what you actually execute, and +# .gitattributes pins them to CRLF on every platform, so their hashes are +# identical on Windows, Linux and macOS. Files without that pin would hash +# differently per platform and are deliberately left out. +# +# RUN -Update ON A CLEAN CHECKOUT +# ------------------------------ +# Hash whatever is on disk. That is only the same as what a user clones if the +# working copy matches git's normalised form. An editor that writes LF leaves a +# file git still considers unchanged (it normalises to LF in the index either +# way), so the file sits there with LF while every clone gets CRLF - and the +# manifest generated from it fails for everyone else. If in doubt: +# +# git status --short # must be clean +# git rm -r --cached . ; git reset --hard # or delete the scripts and +# # `git checkout -- .` +# +# then re-run -Update. The surest check is to clone the repo somewhere else and +# run `sha256sum -c CHECKSUMS.txt` there. + +[CmdletBinding()] +param( + [switch]$Update, + [switch]$Quiet +) + +$ErrorActionPreference = "Stop" + +$ManifestName = "CHECKSUMS.txt" +$Manifest = Join-Path $PSScriptRoot $ManifestName + +# The covered set: executable scripts, top level only. Sorted for a stable file. +function Get-CoveredFiles { + Get-ChildItem -LiteralPath $PSScriptRoot -File | + Where-Object { $_.Extension -in @('.ps1', '.cmd') } | + Sort-Object Name +} + +function Get-Sha256([string]$Path) { + return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() +} + +# sha256sum-compatible: " ", LF endings, so `sha256sum -c` works on +# Linux/macOS as well as this script on Windows. +function Write-Manifest($Files) { + $lines = foreach ($f in $Files) { "{0} {1}" -f (Get-Sha256 $f.FullName), $f.Name } + $text = ($lines -join "`n") + "`n" + [IO.File]::WriteAllText($Manifest, $text, (New-Object Text.UTF8Encoding($false))) +} + +function Read-Manifest { + if (-not (Test-Path -LiteralPath $Manifest)) { return $null } + $map = [ordered]@{} + foreach ($line in [IO.File]::ReadAllLines($Manifest)) { + $t = $line.Trim() + if (-not $t -or $t.StartsWith('#')) { continue } + # "<64 hex> " - two spaces is the sha256sum convention, but accept + # any run of whitespace so a hand-edited file still parses. + if ($t -match '^([0-9a-fA-F]{64})\s+(.+)$') { + $map[$Matches[2].Trim()] = $Matches[1].ToLowerInvariant() + } + } + return $map +} + +$files = @(Get-CoveredFiles) + +if ($Update) { + Write-Manifest $files + Write-Host "" + Write-Host "=== zchecksums (updated) ===" -ForegroundColor Cyan + Write-Host (" Wrote {0} with {1} entries." -f $ManifestName, $files.Count) -ForegroundColor Green + Write-Host " Commit it alongside the script change, or verification will fail." -ForegroundColor DarkGray + Write-Host "" + exit 0 +} + +$expected = Read-Manifest +if ($null -eq $expected) { + Write-Host "ERROR: $ManifestName not found. Run 'zchecksums -Update' to create it." -ForegroundColor Red + exit 1 +} + +$ok = 0 +$changed = @() +$missing = @() +$unlisted = @() + +foreach ($f in $files) { + if (-not $expected.Contains($f.Name)) { $unlisted += $f.Name; continue } + if ((Get-Sha256 $f.FullName) -eq $expected[$f.Name]) { $ok++ } else { $changed += $f.Name } +} +foreach ($name in $expected.Keys) { + if (-not (Test-Path -LiteralPath (Join-Path $PSScriptRoot $name))) { $missing += $name } +} + +$bad = $changed.Count + $missing.Count + $unlisted.Count + +if (-not $Quiet) { + Write-Host "" + Write-Host "=== zchecksums ===" -ForegroundColor Cyan + foreach ($n in $changed) { Write-Host " CHANGED $n" -ForegroundColor Red } + foreach ($n in $missing) { Write-Host " MISSING $n (listed but not on disk)" -ForegroundColor Red } + foreach ($n in $unlisted) { Write-Host " UNLISTED $n (on disk but not in $ManifestName)" -ForegroundColor Yellow } +} + +if ($bad -eq 0) { + Write-Host (" OK - {0} file(s) match {1}." -f $ok, $ManifestName) -ForegroundColor Green + Write-Host "" + exit 0 +} + +Write-Host (" FAILED - {0} ok, {1} changed, {2} missing, {3} unlisted." -f $ok, $changed.Count, $missing.Count, $unlisted.Count) -ForegroundColor Red +Write-Host " If you changed a script on purpose, run: zchecksums -Update" -ForegroundColor DarkGray +Write-Host "" +exit 1 diff --git a/zdeploy.cmd b/zdeploy.cmd index 21928fb..55e7331 100644 --- a/zdeploy.cmd +++ b/zdeploy.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zdeploy.ps1" %* diff --git a/zdeploy.ps1 b/zdeploy.ps1 index 5092170..60103ea 100644 --- a/zdeploy.ps1 +++ b/zdeploy.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zdeploy.ps1 — deploy any project defined in zconfig.json to the server. # Each project runs its own docker compose stack; the handler is picked by the diff --git a/zec2.cmd b/zec2.cmd index 5e068b7..c49c9a9 100644 --- a/zec2.cmd +++ b/zec2.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zec2.ps1" %* diff --git a/zec2.ps1 b/zec2.ps1 index d5ecbe0..5d20a8e 100644 --- a/zec2.ps1 +++ b/zec2.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zec2.ps1 — quick reachability check (TCP + HTTP + live build version) for deployed projects. # diff --git a/zec2_rotatekeys.cmd b/zec2_rotatekeys.cmd index 4354967..7ab1d2b 100644 --- a/zec2_rotatekeys.cmd +++ b/zec2_rotatekeys.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zec2_rotatekeys.ps1" %* diff --git a/zec2_rotatekeys.ps1 b/zec2_rotatekeys.ps1 index a4dbc7e..728f49f 100644 --- a/zec2_rotatekeys.ps1 +++ b/zec2_rotatekeys.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zec2_rotatekeys.ps1 - rotate / reset secret keys in a project's SERVER-SIDE # .env, in place, without the values ever passing through this machine's shell diff --git a/zec2online.cmd b/zec2online.cmd index f0afb45..31672e4 100644 --- a/zec2online.cmd +++ b/zec2online.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zec2online.ps1" %* diff --git a/zec2online.ps1 b/zec2online.ps1 index 4143eea..85f9310 100644 --- a/zec2online.ps1 +++ b/zec2online.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zec2online.ps1 — deep health check: verify apps are live AND running the expected # build; auto-start downed stacks via docker compose and stream diagnostics. diff --git a/zkill.cmd b/zkill.cmd index fd3fb33..8a9148a 100644 --- a/zkill.cmd +++ b/zkill.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0ZKillOnly.ps1" %* diff --git a/zkill.ps1 b/zkill.ps1 index 67aded4..08c52c0 100644 --- a/zkill.ps1 +++ b/zkill.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zkill.ps1 — alias for ZKillOnly.ps1 (kept so both names work). All args pass through. & (Join-Path $PSScriptRoot "ZKillOnly.ps1") @args diff --git a/zrelease.cmd b/zrelease.cmd new file mode 100644 index 0000000..64293cd --- /dev/null +++ b/zrelease.cmd @@ -0,0 +1,7 @@ +REM Evomedia.net — https://github.com/kellymichels/zscripts-token-savers +REM Created by Kelly Michels · dev@evomedia.net +REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 + +@echo off +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zrelease.ps1" %* diff --git a/zrelease.ps1 b/zrelease.ps1 new file mode 100644 index 0000000..4fcae24 --- /dev/null +++ b/zrelease.ps1 @@ -0,0 +1,146 @@ +# Evomedia.net — https://github.com/kellymichels/zscripts-token-savers +# Created by Kelly Michels · dev@evomedia.net +# Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 + +# zrelease.ps1 - package the current version as a downloadable zip. +# +# Usage: +# zrelease build releases/zscripts-.zip +# zrelease -Force overwrite an existing zip for this version +# zrelease -Verify re-check the zip already on disk for this version +# +# For people who want the toolkit without cloning: one zip, one hash to check. +# +# WHAT GOES IN +# ------------ +# every *.ps1 / *.cmd the commands themselves +# CHECKSUMS.txt per-file manifest, so the contents can be +# re-verified after unzipping +# zconfig.example.json you need it to configure anything +# README.md, CHANGELOG.md, LICENSE, TOKEN_SAVINGS.md +# build-version.json which release this is +# +# Left out: tests/ (a user does not need the suite to run the commands) and +# releases/ (never package the packages). +# +# WHAT COMES OUT +# releases/zscripts-v1.0.0.0.1.zip +# releases/zscripts-v1.0.0.0.1.zip.sha256 <- sha256sum format, one line +# +# Two layers on purpose: the .sha256 verifies you downloaded the zip intact, +# and CHECKSUMS.txt inside verifies the individual scripts after extraction. +# Both are integrity checks, not signatures - see the note in zchecksums.ps1. + +[CmdletBinding()] +param( + [switch]$Force, + [switch]$Verify +) + +$ErrorActionPreference = "Stop" + +$ReleasesDir = Join-Path $PSScriptRoot "releases" +$VersionFile = Join-Path $PSScriptRoot "build-version.json" + +if (-not (Test-Path -LiteralPath $VersionFile)) { + Write-Host "ERROR: build-version.json not found. Run 'zversion set v1.0.0.0.0' first." -ForegroundColor Red + exit 1 +} +$version = (Get-Content -LiteralPath $VersionFile -Raw -Encoding UTF8 | ConvertFrom-Json).version +if ($version -notmatch '^v\d+\.\d+\.\d+\.\d+\.\d+$') { + Write-Host "ERROR: build-version.json holds an invalid version '$version'." -ForegroundColor Red + exit 1 +} + +$zipName = "zscripts-$version.zip" +$zipPath = Join-Path $ReleasesDir $zipName +$shaPath = "$zipPath.sha256" + +function Get-Sha256([string]$Path) { + return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() +} + +# ---- verify mode ------------------------------------------------------------- +if ($Verify) { + if (-not (Test-Path -LiteralPath $zipPath)) { + Write-Host "ERROR: $zipName not found in releases/." -ForegroundColor Red + exit 1 + } + if (-not (Test-Path -LiteralPath $shaPath)) { + Write-Host "ERROR: $zipName.sha256 not found." -ForegroundColor Red + exit 1 + } + $expected = ((Get-Content -LiteralPath $shaPath -Raw) -split '\s+')[0].ToLowerInvariant() + $actual = Get-Sha256 $zipPath + Write-Host "" + Write-Host "=== zrelease (verify) ===" -ForegroundColor Cyan + if ($actual -eq $expected) { + Write-Host " OK - $zipName matches its .sha256." -ForegroundColor Green + Write-Host "" + exit 0 + } + Write-Host " FAILED - $zipName does not match its .sha256." -ForegroundColor Red + Write-Host "" + exit 1 +} + +# ---- build mode -------------------------------------------------------------- +if ((Test-Path -LiteralPath $zipPath) -and -not $Force) { + Write-Host "" + Write-Host "ERROR: releases/$zipName already exists." -ForegroundColor Red + Write-Host " A released version is immutable - bump instead: zversion bump" -ForegroundColor DarkGray + Write-Host " (or pass -Force if you are rebuilding one that was never published)" -ForegroundColor DarkGray + Write-Host "" + exit 1 +} + +# Refuse to package scripts that disagree with the manifest. +& (Join-Path $PSScriptRoot "zchecksums.ps1") -Quiet | Out-Null +if ($LASTEXITCODE -ne 0) { + Write-Host "" + Write-Host "ERROR: checksum verification failed - refusing to package." -ForegroundColor Red + Write-Host " Run 'zchecksums' to see what differs, then 'zversion bump' to restamp." -ForegroundColor DarkGray + Write-Host "" + exit 1 +} + +New-Item -ItemType Directory -Force -Path $ReleasesDir | Out-Null + +$staging = Join-Path ([IO.Path]::GetTempPath()) ("zrel-" + [guid]::NewGuid().ToString("N")) +New-Item -ItemType Directory -Path $staging -Force | Out-Null +try { + $scripts = @(Get-ChildItem -LiteralPath $PSScriptRoot -File | Where-Object { $_.Extension -in @('.ps1', '.cmd') }) + foreach ($f in $scripts) { Copy-Item -LiteralPath $f.FullName -Destination $staging } + + $extras = @('CHECKSUMS.txt', 'zconfig.example.json', 'README.md', 'CHANGELOG.md', 'LICENSE', 'TOKEN_SAVINGS.md', 'build-version.json') + $included = @() + foreach ($name in $extras) { + $p = Join-Path $PSScriptRoot $name + if (Test-Path -LiteralPath $p) { Copy-Item -LiteralPath $p -Destination $staging; $included += $name } + } + + if (Test-Path -LiteralPath $zipPath) { Remove-Item -LiteralPath $zipPath -Force } + Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction SilentlyContinue + [IO.Compression.ZipFile]::CreateFromDirectory($staging, $zipPath, [IO.Compression.CompressionLevel]::Optimal, $false) +} +finally { + Remove-Item -LiteralPath $staging -Recurse -Force -ErrorAction SilentlyContinue +} + +$hash = Get-Sha256 $zipPath +# sha256sum format, LF ending, so `sha256sum -c` works on Linux/macOS. +[IO.File]::WriteAllText($shaPath, "$hash $zipName`n", (New-Object Text.UTF8Encoding($false))) + +$sizeKb = [math]::Round((Get-Item -LiteralPath $zipPath).Length / 1KB, 1) + +Write-Host "" +Write-Host "=== zrelease ===" -ForegroundColor Cyan +Write-Host " Version: $version" -ForegroundColor Green +Write-Host " Zip: releases/$zipName ($sizeKb KB, $($scripts.Count) scripts + $($included.Count) support file(s))" -ForegroundColor Gray +Write-Host " SHA-256: $hash" -ForegroundColor Gray +Write-Host " Digest: releases/$zipName.sha256" -ForegroundColor Gray +Write-Host "" +Write-Host " Commit both files - a release lives in the repo under releases/." -ForegroundColor DarkGray +Write-Host "" +exit 0 diff --git a/zrepair.cmd b/zrepair.cmd index 534c11e..6e06d6b 100644 --- a/zrepair.cmd +++ b/zrepair.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zrepair.ps1" %* diff --git a/zrepair.ps1 b/zrepair.ps1 index 23e2a15..8c7ce52 100644 --- a/zrepair.ps1 +++ b/zrepair.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zrepair.ps1 — audit and repair container/proxy routing on the server, then smoke test. # diff --git a/zrestart.cmd b/zrestart.cmd index 92f7cd3..ff41d9f 100644 --- a/zrestart.cmd +++ b/zrestart.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0ZKiller.ps1" %* diff --git a/zrestart.ps1 b/zrestart.ps1 index 1554cf2..2f1b38b 100644 --- a/zrestart.ps1 +++ b/zrestart.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zrestart.ps1 — alias for ZKiller.ps1 (kept so both names work). All args pass through. & (Join-Path $PSScriptRoot "ZKiller.ps1") @args diff --git a/zrestartd.cmd b/zrestartd.cmd index fc4f5ab..9d1e417 100644 --- a/zrestartd.cmd +++ b/zrestartd.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0ZKiller.ps1" -Detached %* diff --git a/zsetup.cmd b/zsetup.cmd index 4d645bd..2584dad 100644 --- a/zsetup.cmd +++ b/zsetup.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zsetup.ps1" %* diff --git a/zsetup.ps1 b/zsetup.ps1 index 84e95d9..bf7e9dc 100644 --- a/zsetup.ps1 +++ b/zsetup.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zsetup.ps1 — prepare a project for local dev: create its Python venv and install # dependencies (python kind), or run `npm install` (vite/nextjs). Idempotent - diff --git a/zsetup_mail.ps1 b/zsetup_mail.ps1 index 35c1579..887b11d 100644 --- a/zsetup_mail.ps1 +++ b/zsetup_mail.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zsetup_mail.ps1 — create admin@ and noreply@ mailboxes in a docker-mailserver # container on the server, and print the DNS records + SMTP/IMAP settings to use. diff --git a/zstart.cmd b/zstart.cmd index c5ef5e9..5bad45c 100644 --- a/zstart.cmd +++ b/zstart.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0ZStart.ps1" %* diff --git a/zstart.ps1 b/zstart.ps1 index 363d23d..b19a106 100644 --- a/zstart.ps1 +++ b/zstart.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zstart.ps1 — start local dev servers for any project defined in zconfig.json. # diff --git a/zstart_docker.cmd b/zstart_docker.cmd index b97487f..f96091d 100644 --- a/zstart_docker.cmd +++ b/zstart_docker.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zstart_docker.ps1" %* diff --git a/zstart_docker.ps1 b/zstart_docker.ps1 index 7834ec9..347e64a 100644 --- a/zstart_docker.ps1 +++ b/zstart_docker.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zstart_docker.ps1 — bring up a local docker compose stack from \docker\. # diff --git a/zstartd.cmd b/zstartd.cmd index a4c9b65..2013960 100644 --- a/zstartd.cmd +++ b/zstartd.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0ZStart.ps1" -Detached %* diff --git a/zstop.ps1 b/zstop.ps1 index 891ca44..cbd2ddd 100644 --- a/zstop.ps1 +++ b/zstop.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zstop.ps1 — stop docker compose stacks on the server without removing data or files. # diff --git a/zsync.cmd b/zsync.cmd index c13b346..aa821ea 100644 --- a/zsync.cmd +++ b/zsync.cmd @@ -1,6 +1,7 @@ REM Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers REM Created by Kelly Michels · dev@evomedia.net REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 @echo off powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zsync.ps1" %* diff --git a/zsync.ps1 b/zsync.ps1 index 057e6b0..2cab3ec 100644 --- a/zsync.ps1 +++ b/zsync.ps1 @@ -1,6 +1,7 @@ # Evomedia.net Token Savers — https://github.com/kellymichels/zscripts-token-savers # Created by Kelly Michels · dev@evomedia.net # Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 # zsync.ps1 — copy new backup files offsite; or build + mirror a vite project's dist. # diff --git a/zversion.cmd b/zversion.cmd new file mode 100644 index 0000000..961a178 --- /dev/null +++ b/zversion.cmd @@ -0,0 +1,7 @@ +REM Evomedia.net — https://github.com/kellymichels/zscripts-token-savers +REM Created by Kelly Michels · dev@evomedia.net +REM Licensed under the MIT License. See LICENSE. +REM Version: v1.0.0.0.0 + +@echo off +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0zversion.ps1" %* diff --git a/zversion.ps1 b/zversion.ps1 new file mode 100644 index 0000000..14f2840 --- /dev/null +++ b/zversion.ps1 @@ -0,0 +1,154 @@ +# Evomedia.net — https://github.com/kellymichels/zscripts-token-savers +# Created by Kelly Michels · dev@evomedia.net +# Licensed under the MIT License. See LICENSE. +# Version: v1.0.0.0.0 + +# zversion.ps1 - manage the toolkit version. +# +# Usage: +# zversion print the current version +# zversion bump build + 1 (one bump per PR / per defect fix) +# zversion bump-stage alpha alpha + 1, build -> 0 +# zversion bump-stage beta beta + 1, alpha/build -> 0 +# zversion bump-stage rc rc + 1, beta/alpha/build -> 0 +# zversion bump-stage release major + 1, everything below -> 0 +# zversion set v1.2.0.0.5 set an exact version +# +# THE SCHEME +# ---------- +# v{major}.{rc}.{beta}.{alpha}.{build} +# +# Priority runs left to right, and bumping any stage zeroes every lower segment +# including build. One version for the whole toolkit, not per script. +# +# WHAT A BUMP TOUCHES +# ------------------- +# Anything other than a plain read rewrites three things together, because they +# are only useful if they agree: +# 1. build-version.json - the source of truth +# 2. the "# Version:" line in every .ps1 / .cmd header, so a script that has +# been copied out of the repo still says which release it came from +# 3. CHECKSUMS.txt - stamping changes every file, so the manifest must +# be regenerated or verification fails immediately +# +# Run this on a clean checkout: it hashes files as they sit on disk, and an +# editor that writes LF leaves a file git still considers unchanged. See the +# note in zchecksums.ps1. + +[CmdletBinding()] +param( + [Parameter(Position = 0)][string]$Command = "get", + [Parameter(Position = 1)][string]$Value +) + +$ErrorActionPreference = "Stop" + +$VersionFile = Join-Path $PSScriptRoot "build-version.json" +$VersionRe = '^v(\d+)\.(\d+)\.(\d+)\.(\d+)\.(\d+)$' +$DefaultVersion = "v1.0.0.0.0" + +function Read-Version { + if (-not (Test-Path -LiteralPath $VersionFile)) { return $DefaultVersion } + try { + $v = (Get-Content -LiteralPath $VersionFile -Raw -Encoding UTF8 | ConvertFrom-Json).version + if ($v -match $VersionRe) { return $v } + } catch { } + return $DefaultVersion +} + +function Write-Version([string]$Version) { + $json = [ordered]@{ version = $Version } | ConvertTo-Json + [IO.File]::WriteAllText($VersionFile, $json + "`n", (New-Object Text.UTF8Encoding($false))) +} + +function Split-Version([string]$Version) { + if ($Version -notmatch $VersionRe) { + throw "Invalid version '$Version'. Expected v{major}.{rc}.{beta}.{alpha}.{build}, e.g. v1.0.0.0.3." + } + return [int[]]@($Matches[1], $Matches[2], $Matches[3], $Matches[4], $Matches[5]) +} + +# Rewrite (or insert) the "# Version:" header line in every covered script. +function Set-ScriptVersionHeaders([string]$Version) { + $stamped = 0 + foreach ($f in Get-ChildItem -LiteralPath $PSScriptRoot -File | Where-Object { $_.Extension -in @('.ps1', '.cmd') }) { + $text = [IO.File]::ReadAllText($f.FullName) + # Keep each file's own comment marker: # for PowerShell, REM for cmd. + $marker = if ($f.Extension -eq '.cmd') { 'REM' } else { '#' } + $line = "$marker Version: $Version" + if ($text -match "(?m)^(#|REM) Version: v[\d\.]+\r?$") { + $new = [regex]::Replace($text, "(?m)^(#|REM) Version: v[\d\.]+\r?$", [System.Text.RegularExpressions.MatchEvaluator] { param($m) $line }) + } else { + # Insert directly after the licence line, which every header carries. + $pattern = "(?m)^((#|REM) Licensed under the MIT License\. See LICENSE\.)\r?$" + if ($text -notmatch $pattern) { continue } + $new = [regex]::Replace($text, $pattern, [System.Text.RegularExpressions.MatchEvaluator] { param($m) $m.Groups[1].Value + "`r`n" + $line }, 1) + } + if ($new -ne $text) { + # .ps1/.cmd are pinned to CRLF by .gitattributes - write them that + # way or every stamped file shows up as changed on the next clone. + $new = ($new -replace "`r`n", "`n") -replace "`n", "`r`n" + [IO.File]::WriteAllText($f.FullName, $new, (New-Object Text.UTF8Encoding($false))) + $stamped++ + } + } + return $stamped +} + +function Update-Everything([string]$Version) { + Write-Version $Version + $n = Set-ScriptVersionHeaders $Version + & (Join-Path $PSScriptRoot "zchecksums.ps1") -Update | Out-Null + Write-Host "" + Write-Host "=== zversion ===" -ForegroundColor Cyan + Write-Host " Version: $Version" -ForegroundColor Green + Write-Host " Stamped: $n script header(s)" -ForegroundColor Gray + Write-Host " Refreshed: CHECKSUMS.txt" -ForegroundColor Gray + Write-Host " Commit build-version.json, the stamped scripts and CHECKSUMS.txt together." -ForegroundColor DarkGray + Write-Host "" +} + +$current = Read-Version + +switch ($Command.ToLowerInvariant().TrimStart('-')) { + "get" { + Write-Host $current + exit 0 + } + "bump" { + $p = Split-Version $current + Update-Everything ("v{0}.{1}.{2}.{3}.{4}" -f $p[0], $p[1], $p[2], $p[3], ($p[4] + 1)) + exit 0 + } + "bump-stage" { + $p = Split-Version $current + $major, $rc, $beta, $alpha = $p[0], $p[1], $p[2], $p[3] + switch (("$Value").ToLowerInvariant()) { + "release" { $major++; $rc = 0; $beta = 0; $alpha = 0 } + "rc" { $rc++; $beta = 0; $alpha = 0 } + "beta" { $beta++; $alpha = 0 } + "alpha" { $alpha++ } + default { + Write-Host "ERROR: stage must be one of: release, rc, beta, alpha" -ForegroundColor Red + exit 1 + } + } + # Bumping a stage zeroes every lower segment, build included. + Update-Everything ("v{0}.{1}.{2}.{3}.0" -f $major, $rc, $beta, $alpha) + exit 0 + } + "set" { + [void](Split-Version $Value) + Update-Everything $Value + exit 0 + } + default { + Write-Host "" + Write-Host "Usage: zversion [get | bump | bump-stage | set ]" -ForegroundColor Yellow + Write-Host " Scheme: v{major}.{rc}.{beta}.{alpha}.{build} (current: $current)" -ForegroundColor Gray + Write-Host " bump build + 1 - one per PR, one per defect fix" -ForegroundColor Gray + Write-Host " bump-stage raise a stage; every lower segment resets to 0" -ForegroundColor Gray + Write-Host "" + exit 1 + } +}