docs: add v0.3.2 release notes and reproducibility results
Exercise the release workflow end to end. v0.3.1 was tagged and published by hand before release.yml existed, so the tag-triggered path has never actually run; this tag is the first to go through it. Add docs/releases/v0.3.2.md, which release.yml picks up as the release body instead of falling back to generated notes. The notes cover the whole v0.2.0 range rather than just this tag, since v0.3.0 through v0.3.2 landed in quick succession and the F1 to Ctrl+H change is the one thing an upgrader must know. Also record the measured reproducibility result: with modes, locale and timezone pinned, ubuntu-latest and a workstation on a different umask, locale and timezone now produce identical checksums for all five archives. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
59b57a4970
commit
bca8e7b3fc
|
|
@ -137,16 +137,23 @@ byte for byte. `release.sh` pins everything that would otherwise vary:
|
||||||
- `normalize_package` forces 755 on directories and the program and 644 on
|
- `normalize_package` forces 755 on directories and the program and 644 on
|
||||||
everything else, so the builder's umask cannot leak into the archive.
|
everything else, so the builder's umask cannot leak into the archive.
|
||||||
|
|
||||||
To check a published build, compare the binary inside the archive rather than
|
- the Windows zip is packaged under `LC_ALL=C` and `TZ=UTC`, because `sort`
|
||||||
the archive hash:
|
orders entries by locale and zip stores DOS local time with no zone.
|
||||||
|
|
||||||
|
With those in place the archives themselves reproduce across hosts: a build on
|
||||||
|
`ubuntu-latest` (umask 022, C locale, UTC) and one on a workstation (umask 002,
|
||||||
|
`ru_RU.UTF-8`, UTC+08) produce identical checksums for all five archives.
|
||||||
|
|
||||||
|
The strongest check is still the binary, since it does not depend on the host's
|
||||||
|
`tar` and `gzip` at all:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tar -xzf sshkeeper_<version>_linux_amd64.tar.gz
|
tar -xzf sshkeeper_<version>_linux_amd64.tar.gz
|
||||||
sha256sum sshkeeper_<version>_linux_amd64/sshkeeper
|
sha256sum sshkeeper_<version>_linux_amd64/sshkeeper
|
||||||
```
|
```
|
||||||
|
|
||||||
The archive hash additionally depends on the `tar` and `gzip` implementations
|
Comparing whole-archive hashes works too, as long as both builds used the same
|
||||||
on the build host, so it is the weaker check of the two.
|
Go version.
|
||||||
|
|
||||||
## Publish in GitHub Release
|
## Publish in GitHub Release
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
Release automation and reproducible packaging. sshkeeper itself behaves exactly
|
||||||
|
as in v0.3.1 — no functional changes to the TUI or the CLI.
|
||||||
|
|
||||||
|
This is also the first release published by GitHub Actions rather than by hand.
|
||||||
|
|
||||||
|
## In this release
|
||||||
|
|
||||||
|
**Archives are now reproducible.** Rebuilding a tag on a different machine used
|
||||||
|
to produce different checksums even when every packaged file was byte-identical,
|
||||||
|
because three host properties leaked into the archives:
|
||||||
|
|
||||||
|
| Leak | Effect |
|
||||||
|
|------|--------|
|
||||||
|
| File modes followed the builder's umask | umask 002 packaged `664`/`775`, umask 022 packaged `644`/`755` |
|
||||||
|
| `sort` orders entries by locale | a `ru_RU.UTF-8` host emitted `docs/` before `LICENSE`, a C locale the reverse |
|
||||||
|
| zip stores DOS local time with no zone | the same commit embedded `19:06` at UTC+08 and `11:06` at UTC |
|
||||||
|
|
||||||
|
All three are pinned now. A build on `ubuntu-latest` and one on a workstation
|
||||||
|
with a different umask, locale and timezone produce identical checksums for all
|
||||||
|
five archives. The binaries were always reproducible; only the packaging varied.
|
||||||
|
|
||||||
|
**CI.** The repository previously had no automation. It now runs `gofmt`,
|
||||||
|
`go vet` and `go test` on Linux *and* macOS for every push and pull request,
|
||||||
|
plus a cross-build of all five release targets. macOS is a stated release
|
||||||
|
target that until now was only ever cross-compiled, never tested.
|
||||||
|
|
||||||
|
**Releases are automated.** Pushing a `v*` tag runs the release checks, builds
|
||||||
|
through the same `release.sh` used locally, and publishes. Nightly builds from
|
||||||
|
`main` are published as a separate `nightly` prerelease, so the `Latest` badge
|
||||||
|
always points at a real release.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Everything since v0.2.0
|
||||||
|
|
||||||
|
## Breaking change: full help moved off F1
|
||||||
|
|
||||||
|
**`Ctrl+H` opens full help. `F1` no longer has any binding.** `?` still opens
|
||||||
|
contextual quick help outside text editors. This landed in v0.3.0.
|
||||||
|
|
||||||
|
`Ctrl+H` is the BS control character (0x08). xterm and most modern emulators
|
||||||
|
send DEL (0x7F) for Backspace, so help and text editing do not collide. A
|
||||||
|
terminal configured to send BS for Backspace cannot tell them apart; switch it
|
||||||
|
to DEL (in xterm, `backarrowKey: false`).
|
||||||
|
|
||||||
|
Nothing else requires action when upgrading. Vaults, server profiles and stored
|
||||||
|
port forwards are unchanged, and no migration runs.
|
||||||
|
|
||||||
|
## The TUI was rebuilt around one shell (v0.3.0)
|
||||||
|
|
||||||
|
In v0.2.0 only the server dashboard had a real layout. Other screens rendered
|
||||||
|
free-form strings or the default Bubbles list frame, so they had no shared
|
||||||
|
width budget, no borders, and footers that floated wherever the content ended.
|
||||||
|
|
||||||
|
Every full-screen state now shares one contract: a header with breadcrumb and
|
||||||
|
truthful vault status, a separator, framed content panels, and a contextual
|
||||||
|
footer anchored to the last terminal row.
|
||||||
|
|
||||||
|
- Actions, search, tag input, confirmations and both help screens render inside
|
||||||
|
the shell.
|
||||||
|
- The port forward manager and editor use framed, width-budgeted layouts. Column
|
||||||
|
widths derive from the panel's inner width, so no row consumes the terminal's
|
||||||
|
last column.
|
||||||
|
- Tag, command template, template picker/mode/results and tunnel managers use
|
||||||
|
framed lists with a `>` selection marker, so selection never depends on colour
|
||||||
|
alone.
|
||||||
|
- Server and template editors use a framed form panel with the title moved into
|
||||||
|
the breadcrumb. Required markers, validation and dirty-state confirmation are
|
||||||
|
unchanged.
|
||||||
|
|
||||||
|
**Responsive layouts.** The supported floor is `60x16`. Wide (100+ columns)
|
||||||
|
shows two panels, medium (70–99) stacks them, narrow (60–69) keeps a single
|
||||||
|
compact panel. Below the floor only the minimum-size message renders. Long
|
||||||
|
ASCII, Cyrillic, CJK, combining and emoji content truncates by display cells
|
||||||
|
rather than byte count.
|
||||||
|
|
||||||
|
**Safety.** Destructive actions confirm with Cancel selected first and name the
|
||||||
|
exact target and its consequence. Status and help context stay truthful to
|
||||||
|
actual vault and connection state. Form validation prevents silent loss of
|
||||||
|
edits.
|
||||||
|
|
||||||
|
## `forward add` was completely broken (fixed in v0.3.1)
|
||||||
|
|
||||||
|
`sshkeeper forward add` could never succeed in v0.2.0 or v0.3.0. The command
|
||||||
|
read `--local-port` and marked it required, but the flag was never registered,
|
||||||
|
so cobra rejected it as unknown and the value fell back to 0:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sshkeeper forward add web --type local --local-port 15432 \
|
||||||
|
--remote-addr 127.0.0.1 --remote-port 5432
|
||||||
|
unknown flag: --local-port
|
||||||
|
```
|
||||||
|
|
||||||
|
No combination of arguments worked. Both documented forms work now:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sshkeeper forward add web --name "Local PostgreSQL" --type local \
|
||||||
|
--local-port 15432 --remote-addr db01.internal.example.com --remote-port 5432
|
||||||
|
✓ Forward added [1]
|
||||||
|
|
||||||
|
$ sshkeeper forward add web --name "SOCKS proxy" --type dynamic --local-port 1080
|
||||||
|
✓ Forward added [2]
|
||||||
|
```
|
||||||
|
|
||||||
|
Omitting the flag now reports `required flag(s) "local-port" not set` instead of
|
||||||
|
a misleading port-range error. The TUI (`Ctrl+W`) was never affected.
|
||||||
|
|
||||||
|
The command's tests had constructed their own throwaway cobra command and
|
||||||
|
registered the flags by hand, so the real command's registration was never
|
||||||
|
exercised and the suite passed against a broken command. Coverage now parses
|
||||||
|
argv into the actual command. An audit of every other command found no further
|
||||||
|
flag that is read but never registered.
|
||||||
|
|
||||||
|
## Also fixed since v0.2.0
|
||||||
|
|
||||||
|
- Port forward fields accept digits correctly (`10bcc07`).
|
||||||
|
- Platform and repository status are stated accurately in the docs: Linux and
|
||||||
|
macOS are primary release targets, Windows is experimental.
|
||||||
|
|
||||||
|
## Release-by-release
|
||||||
|
|
||||||
|
| Version | Contents |
|
||||||
|
|---------|----------|
|
||||||
|
| v0.3.0 | Unified TUI shell, responsive layouts, `F1` → `Ctrl+H` |
|
||||||
|
| v0.3.1 | `forward add` fix |
|
||||||
|
| v0.3.2 | Reproducible packaging, CI, automated releases |
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tar -xzf sshkeeper_v0.3.2_linux_amd64.tar.gz
|
||||||
|
sudo install -m 0755 sshkeeper_v0.3.2_linux_amd64/sshkeeper /usr/local/bin/sshkeeper
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify downloads against `checksums.txt`. Linux and macOS are the primary
|
||||||
|
release targets; the Windows build is experimental and needs OpenSSH Client
|
||||||
|
available as `ssh.exe` on `PATH`.
|
||||||
|
|
||||||
|
To verify a build yourself, check out the tag and run `./release.sh v0.3.2` —
|
||||||
|
the checksums should match this release exactly, given the same Go version.
|
||||||
Loading…
Reference in New Issue