Commit Graph

61 Commits (main)

Author SHA1 Message Date
mirivlad a19b3deb24 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>
2026-08-18 19:13:50 +08:00
mirivlad 59b57a4970 fix: make the windows zip independent of locale and timezone
With file modes normalized, the four tarballs reproduced byte for byte across
hosts but the Windows zip still did not. Two host properties were leaking into
it:

- Entry order. The archive is fed by `find | sort`, and sort honours the
  locale. A ru_RU.UTF-8 host emits docs/ before LICENSE; a C locale emits the
  reverse. Same files, different archive.
- Timestamps. zip records DOS local time with no zone attached, so building at
  UTC+08 embedded 19:06 where ubuntu-latest embedded 11:06 for the same commit.

Pin LC_ALL=C and TZ=UTC for the packaging subshell. Building the same commit
under ru_RU.UTF-8/Asia-Shanghai and under C/UTC now yields one hash.

The tarballs never had either problem: tar sorts internally by byte value and
stores Unix epochs, so neither locale nor zone reaches the output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 19:10:07 +08:00
mirivlad 878f7b4472 fix: normalize file modes when packaging a release
release.sh normalized entry order, ownership and mtimes, but not permissions,
so the archives inherited the builder's umask. A host with umask 002 packaged
664/775 while ubuntu-latest packaged 644/755, and the two archives hashed
differently even though every file inside was byte-identical:

  CI     -rw-r--r--  README.md   local  -rw-rw-r--  README.md
  CI     -rwxr-xr-x  sshkeeper   local  -rwxrwxr-x  sshkeeper

Force 755 on directories and the program, 644 on everything else. Building the
same commit under umask 002 and umask 022 now yields identical checksums.

Also correct the reproducibility claim in the release docs. What is reproducible
is the binary, given the same commit and Go version; the archive hash still
depends on the host tar and gzip, so the documented verification step now
compares the extracted binary instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 19:06:12 +08:00
mirivlad 0a02f0fc60 ci: add test, release and nightly workflows
The repository had no automation at all: every release was packaged and
published by hand, and nothing ran tests on a pull request.

- ci.yml runs gofmt, go vet and go test on Linux and macOS, and cross-builds
  all five release targets. macOS is a stated release target but was never
  actually exercised, only cross-compiled.
- release.yml publishes on a v* tag. It gates on `make release-check` so a red
  suite cannot ship, and builds through release.sh rather than duplicating the
  packaging rules, so CI archives stay byte-identical to local ones. A
  hand-written docs/releases/<tag>.md becomes the release body when present,
  otherwise notes are generated from history.
- nightly.yml rebuilds the tip of main on every push and replaces a rolling
  `nightly` prerelease. Prerelease is deliberate: it keeps GitHub's `Latest`
  badge on the newest real release rather than on an untested build.

The rolling tag is why version discovery was pinned to v* in the previous
commit; nightly.yml depends on that filter already being in place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 18:59:40 +08:00
mirivlad 19ffc4ba5e build: pin version discovery to v* tags
Nightly builds will move a rolling `nightly` tag across main. A plain
`git describe --tags` returns whichever tag is nearest, so once that tag exists
every build — including a real release build — would report its version as
"nightly" and lose the release lineage entirely.

Restrict discovery to `v*` so the rolling tag is invisible to versioning:

  with a nightly tag ahead of v0.3.1
    git describe --tags                → nightly
    git describe --tags --match 'v*'   → v0.3.1-1-gf940087

Land this before the nightly workflow exists, so no build is ever stamped from
the rolling tag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 18:56:45 +08:00
mirivlad cc83802244 fix: register the forward add local-port flag
`sshkeeper forward add` could never succeed. RunE read --local-port and init()
marked it required, but the flag was never registered on forwardAddCmd. Cobra
ignores MarkFlagRequired for an unknown flag, and GetInt returns 0 for one, so
every invocation failed validation with "invalid local port 0: must be
1-65535". There was no argument combination that worked.

Register the flag so both the read and the required annotation bind to a real
option. README and the guide already documented --local-port, so the intent was
there from the start; only the registration was missing.

The existing tests missed this because they build a throwaway cobra.Command,
register the flags on it themselves, and pass it to forwardAddCmd.RunE — the
real command's flag set was never exercised. Add a test that parses argv into
forwardAddCmd's own flags, plus one pinning the required annotation. Both fail
against the unfixed command with "unknown flag: --local-port".

Present since c2edaa4, so v0.2.0 and v0.3.0 both ship it broken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 18:46:08 +08:00
mirivlad 44156a11af docs: refresh unified tui screenshots
Complete the final task of the unified TUI shell plan, which had been left
undone: the code dropped F1 in favour of Ctrl+H, but README and the guide
still documented F1 as the full-help key in nine places, and the repository
screenshots still showed the pre-shell UI.

- Replace every F1 reference in README.md and docs/guide.md with Ctrl+H,
  including the two ASCII help blocks that mirror runtime output.
- Document the BS/DEL terminal constraint: Ctrl+H is BS (0x08) while xterm
  sends DEL (0x7F) for Backspace, so help and text editing do not collide.
- Recapture all five screenshots from the current binary in a real xterm at
  120x40, 80x24 and 60x16 using an isolated XDG profile.

Runtime verification in xterm confirms Ctrl+H opens full help while seven
Backspace presses correctly trim typed text, and that every captured screen
carries the header, framed content and bottom-anchored footer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 18:33:14 +08:00
mirivlad 84070d2721 fix: harden responsive tui layouts 2026-08-14 08:11:27 +08:00
mirivlad 5e83300ea8 feat: unify tui editor screens 2026-08-14 08:02:23 +08:00
mirivlad 18d7a7c07a feat: unify tui manager screens 2026-08-14 07:58:47 +08:00
mirivlad d8ae2d4236 feat: redesign port forward screens 2026-08-14 07:54:51 +08:00
mirivlad 762d14bb9b feat: add unified tui shell and ctrl-h help 2026-08-14 07:50:13 +08:00
mirivlad 4ba2bfce34 docs: plan unified tui shell 2026-08-14 07:44:35 +08:00
mirivlad 7b5919b6c1 docs: specify unified tui shell 2026-08-14 07:43:27 +08:00
mirivlad be800de90b fix: address tui redesign review findings 2026-08-14 04:04:10 +08:00
mirivlad dac7c7d37a docs: refresh tui guide and screenshots 2026-08-14 03:47:31 +08:00
mirivlad 460b4496a0 feat: add responsive tui layouts 2026-08-14 03:42:43 +08:00
mirivlad 16f4f9937f fix: validate tui forms and protect edits 2026-08-14 03:27:41 +08:00
mirivlad 37c4fd34a9 fix: keep tui status and help context truthful 2026-08-14 03:20:42 +08:00
mirivlad 84a61d4895 fix: make tui destructive actions safe 2026-08-14 03:16:50 +08:00
mirivlad 5391612a14 docs: plan tui ux redesign 2026-08-14 03:10:39 +08:00
mirivlad 10bcc07601 fix: allow digits in port forward fields 2026-08-13 22:26:19 +08:00
mirivlad 604a4ecde2 docs: clarify platform and repository status 2026-06-06 11:14:15 +08:00
mirivlad 8e59c3052e feat: add cross-platform release packaging 2026-06-06 10:49:56 +08:00
mirivlad 48c0057d11 docs: recapture screenshots in xfce terminal 2026-06-06 10:31:52 +08:00
mirivlad 90c9f053d4 docs: align guide and screenshots 2026-06-06 03:35:24 +08:00
mirivlad f49a5b5a94 fix: store forward cli metadata 2026-06-06 03:28:21 +08:00
mirivlad 86e5bb5f0c feat: replace tui action stubs 2026-06-06 03:26:17 +08:00
mirivlad 7e0a00ff43 feat: add tunnel background cli management 2026-06-06 03:21:30 +08:00
mirivlad 6991eab3c0 fix: complete forwards and search behavior 2026-06-06 03:17:26 +08:00
mirivlad a750b85412 docs: plan partial feature completion 2026-06-06 03:13:21 +08:00
mirivlad 94e10171d2 sshkeeper: v0.2.0 stabilization — dual help screens, route icons, forward UX, tests, docs
- Split help into two modes: ? (quick hotkeys) and F1 (full documentation)
- Add visual route icons: ● direct, → via, ⇒ chain
- Forward type selector: visible radio items with descriptions
- Forward delete: confirmation dialog
- Forward list: column headers (NAME/TYPE/LISTEN/TARGET/ON)
- Footer hints on all screens show ? and F1
- Comprehensive SSH command builder tests (18 new tests)
- Fix duplicate test functions
- Update README.md: install from source as primary, fix tables, repo links
- Update docs/guide.md: split help section, fix tables, fix typos
- All tests pass, build succeeds
2026-06-05 18:19:38 +08:00
mirivlad 216af78d4d sshkeeper: add comprehensive user guide (docs/guide.md) 2026-06-05 15:42:27 +08:00
mirivlad 087d7ba0dc sshkeeper: fix 4 UX issues
1. Forward type selector: visible radio items (1.Local 2.Remote 3.SOCKS) with descriptions
2. Forward list: column header row (NAME/TYPE/LISTEN/TARGET/ON)
3. Forward delete: confirmation dialog before deletion
4. Server route column: → icon for via/chain, spaces for direct
2026-06-05 10:00:22 +08:00
mirivlad 6cf281c349 sshkeeper: complete port forwarding UX redesign
- Forward form: type selector (Local/Remote/SOCKS) with radio items
- Dynamic fields: listen addr/port, target addr/port based on type
- Default listen: 127.0.0.1, warning for 0.0.0.0
- Forward list: table view NAME/TYPE/LISTEN/TARGET/ENABLED
- Forward edit: Enter/Ctrl+E opens pre-filled edit form
- Human explanation and OpenSSH preview for selected forward
- Tunnel state manager: PID tracking, start/stop, state file
- Tunnel manager screen: list running tunnels, stop, refresh
- Action menu: Connect/Connect with tunnels/Start tunnels only/Start tunnels in background/Manage port forwards/Manage tunnels/Manage route/Test/Edit/Delete
- Help screen: updated shortcuts
- CLI: tunnel --background for detached tunnel process
- README: updated with forward vs tunnel examples, new hotkeys
2026-06-03 18:27:05 +08:00
mirivlad 4726a6874c sshkeeper: redesign port forwarding UX
- Forward model: add Name, Description, Enabled fields
- DB migration 003: add name/description/enabled columns to forwards
- Forward type: radio selector (Local/Remote/SOCKS) instead of free text
- Forward form: dynamic fields based on type, 127.0.0.1 default, 0.0.0.0 warning
- Forward list: table view with NAME/TYPE/LISTEN/TARGET/ENABLED columns
- Forward edit: Enter/Ctrl+E opens edit form
- Human explanation and OpenSSH preview for selected forward
- Tunnel state manager: PID tracking, start/stop, state file
- Tunnel manager screen: list running tunnels, stop, refresh
- Action menu: reworked with Connect/Connect with tunnels/Start tunnels only/Start tunnels in background/Manage port forwards/Manage tunnels/Manage route/Test/Edit/Delete
- Help screen: updated with all shortcuts
- CLI: tunnel --background for detached tunnel process
- Default listen address: 127.0.0.1 instead of 0.0.0.0
- Validation: type required, ports 1-65535, target required for local/remote
2026-06-03 18:15:31 +08:00
mirivlad 741e9a836d shkeeper: simplify action bar (Enter/Ctrl+X/Ctrl+A/Ctrl+E/Ctrl+F/Ins/?/Ctrl+Q), move rest to help screen 2026-06-03 16:08:22 +08:00
mirivlad fa9b07e3d5 sshkeeper: add build.sh and release.sh scripts 2026-06-03 15:09:32 +08:00
mirivlad 709a317939 sshkeeper: fix forward save flow (saveDoneMsg handling) + tests 2026-06-03 12:37:39 +08:00
mirivlad 77a84a487f sshkeeper: v0.2.0 stabilization (route display, forward validation, tunnel UX, README) 2026-06-03 11:23:02 +08:00
mirivlad 21444d3826 sshkeeper: fix migration - route_hops via ensureSchema() to avoid duplicate column error 2026-06-03 10:48:19 +08:00
mirivlad 87f0d90f7b sshkeeper: v0.2.0 — Phase 6: README update (not-Ansible, route/forward examples, hotkeys) 2026-06-03 10:40:56 +08:00
mirivlad 98492799ea sshkeeper: v0.2.0 — Phase 5: Search improvements (notes, tags, route, context) 2026-06-03 10:36:44 +08:00
mirivlad c2edaa4224 sshkeeper: v0.2.0 — Phase 4: CLI route/forward/tunnel commands 2026-06-03 10:32:18 +08:00
mirivlad 912b17e1f1 sshkeeper: v0.2.0 — Phase 3: Port Forwarding Manager (DB, TUI screens, SSH args) 2026-06-03 10:15:55 +08:00
mirivlad 700724e93b sshkeeper: v0.2.0 — Phase 2: Route / ProxyJump UX (model, migration, DB, SSH args, TUI) 2026-06-03 10:00:12 +08:00
mirivlad 446f55f740 sshkeeper: v0.2.0 — Phase 1: Cleaner TUI action model (action bar, help screen, action menu) 2026-06-03 09:33:53 +08:00
mirivlad 31f26164cc sshkeeper: v0.2.0 — Phase 0: TUI refactoring (extract form, template_form, help into separate files) 2026-06-03 09:26:50 +08:00
mirivlad b2d8ea959f Document release installation 2026-05-29 11:33:43 +08:00
mirivlad 01eae01408 Ignore release artifacts 2026-05-29 11:25:17 +08:00