Skip to content

Releases: Cd1s/ssm

v2.3.2

Choose a tag to compare

@github-actions github-actions released this 27 Oct 06:23
57639eb

This is a v2 patch release with a security-driven toolchain update from
PR #130. It adds no new feature and changes no command behavior. The official
exact-tag release workflow creates the stable v2.3.2 Release with
make_latest=false; v2.3.1 remains GitHub latest until the published-asset
audit and canaries pass and a separate promotion is made. Ordinary ssm update
stays within v2.

Security: toolchain

  • The build toolchain moves from Go 1.26.9 to Go 1.26.10, fixing GO-2026-6809
    reported by govulncheck.
  • The crypto/x509 fix stops trusting compromised intermediate certificates.
    SSM is affected because release provenance verification in
    internal/provenance reaches x509.Certificate.Verify through Sigstore
    bundle verification.

There is no request-schema or JSON-field breaking change. No request or result
field and no error code is added or removed. The request schema structure is
unchanged; only its version-bound $id and title are updated to v2.3.2.

Changes since v2.3.1

  • Updated the build toolchain from Go 1.26.9 to Go 1.26.10 to fix
    GO-2026-6809 in crypto/x509 (PR #130).

v2.3.1

Choose a tag to compare

@github-actions github-actions released this 15 Oct 20:27
87ffe21

This is a v2 patch release with a security-driven toolchain and dependency
update plus small fixes. It adds no new feature. The official exact-tag release
workflow creates the stable v2.3.1 Release with make_latest=false; v2.3.0
remains GitHub latest until published-asset canaries pass and a separate
promotion is made. Ordinary ssm update stays within v2.

Security: toolchain and dependencies

  • The build toolchain moves from Go 1.26.8 to Go 1.26.9.
  • golang.org/x/net moves to v0.60.0, which fixes GO-2026-6603,
    GO-2026-6610, GO-2026-6611, GO-2026-6612, and GO-2026-6617 reported by
    govulncheck. golang.org/x/crypto, golang.org/x/sys,
    golang.org/x/term, and the other golang.org/x modules are updated with it.

Static release binaries

All official release binaries are now built with CGO_ENABLED=0. The
linux-amd64 binary was previously dynamically linked against glibc and is now
statically linked, which benefits hosts with an older glibc and Alpine. This is
a user-visible change in how the binary is built; command behavior does not
change.

sshctl tunnel port parsing

  • -L 0:host:port and -L [bind:]0:host:port now correctly listen on port 0,
    so the operating system assigns the listening port.
  • A remote IPv6 target that contains a :0: segment is no longer altered.
  • Ports accept plain decimal digits only. +80 and -0 are now rejected; this
    tightens input that was previously accepted.
  • Remote target port 0 is still rejected.

Development script

scripts/ssh_matrix_test.sh now works with PAM public-key authentication when
run as root. It is a development and CI script only and is not part of the
release binaries.

There is no request-schema or JSON-field breaking change. No request or result
field and no error code is added or removed. The request schema structure is
unchanged; only its version-bound $id and title are updated to v2.3.1.

Changes since v2.3.0

  • Updated the build toolchain to Go 1.26.9 and golang.org/x/net to v0.60.0,
    clearing five govulncheck findings.
  • Built all official release binaries with CGO_ENABLED=0, so linux-amd64 is
    now statically linked.
  • Fixed sshctl tunnel listener port 0 handling and remote IPv6 targets
    containing :0:; ports now accept plain decimal digits only.
  • Fixed scripts/ssh_matrix_test.sh PAM public-key authentication when run as
    root.

v2.3.0

Choose a tag to compare

@github-actions github-actions released this 07 Oct 13:27
7e8ead3

This is a v2 minor release. The official exact-tag release workflow creates
the stable v2.3.0 Release with make_latest=false; v2.2.0 remains GitHub
latest until published-asset canaries pass and a separate promotion is made.
Ordinary ssm update stays within v2.

sshctl tunnel

  • sshctl tunnel provides foreground -L local port forwarding and -D
    dynamic forwarding. It reuses the existing connection path, so host-key
    verification and proxy_jump continue to apply.
  • Local listeners bind to loopback by default. A non-loopback bind requires
    both --allow-remote-bind and --yes.
  • --ready-file writes readiness state, and --duration bounds the
    foreground lifetime. Readiness and termination each produce one JSON line
    when JSON output is selected.
  • An SSH disconnect exits the tunnel; it does not reconnect automatically.
  • New error codes are tunnel_invalid_arguments, tunnel_bind_failed, and
    tunnel_remote_bind_refused.
  • This release does not include -R, a background daemon, or automatic
    reconnect.

Important update fix: Alpine and gcompat

Older ssm update versions could write the new version onto the system C
library on Alpine with gcompat (/lib/ld-musl-x86_64.so.1), causing most host
programs to crash with segmentation faults. The updater now replaces only a
file named ssm or sshctl; otherwise it refuses and explains the reason
without changing any file.

On Alpine, do not use ssm update to upgrade from v2.2.0 or earlier: those
versions contain this defect. Download the matching release asset manually,
verify its SHA-256, and replace the binary. After upgrading to v2.3.0,
ssm update is safe.

Sync server token history

Each account now retains 256 login-token hashes instead of 16. With 16
machines under one account, logging in on one more machine could evict another
machine's token and make its next sync fail with HTTP 401. Deploy the new
internal/syncserver server for this change to take effect.

There is no request-schema or JSON-field breaking change; no request schema or
JSON field has a newly added or changed breaking form.
The checked range has no request-schema file changes; request and result
additions remain additive. Error codes are additive: these tunnel codes are
new, and existing codes are unchanged.

Changes since v2.2.0

  • Added foreground SSH tunnel forwarding and its lifecycle/error contracts.
  • Fixed tunnel half-close handling so replies are not truncated.
  • Fixed updater executable lookup and refusal to replace foreign executables.
  • Increased sync-server login-token history from 16 to 256.

v2.2.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 21:16
fb5b065

This is a v2 minor release containing all fixes from PR #120 (the reviewed
commits in 6431cae..c77ffdf). It changes some default behavior and has a
vault-format compatibility requirement. The official exact-tag release
workflow creates the stable v2.2.0 Release with make_latest=false;
v2.1.0 remains GitHub latest until published-asset canaries pass and a separate
promotion is made. Ordinary ssm update stays within v2.

Upgrade before saving or publishing (read first)

  • Vault format v2 encryption. New vaults use an authenticated monotonic
    generation. Older clients (v2.1.0 and earlier) cannot read a v2-format vault;
    upgrade all machines to v2.2.0 before any machine saves or publishes one.
    v2.2.0 continues to read old-format vaults.
  • Conditional sync publication. The sync server now checks If-Match and
    If-None-Match preconditions on uploads. If two machines upload at once,
    only one succeeds and the other receives sync_conflict. A new client can
    still push to an old server, but that server cannot provide this protection.
    If the local remote.etag cache is missing while a remote vault exists, push
    first requires sync or pull.
  • Deploy the new internal/syncserver before relying on the upload checks.

User-visible changes

  • A push whose scope no longer matches an interrupted publication fails as
    sync_push_failed (exit 1), and it does not publish extra inventory.
  • A downloaded vault that fails authentication is rejected and the existing
    connections.enc.prev is retained.
  • A client that has never synchronized reports empty last_pull and
    last_sync values.
  • password_cache and vim_keys settings are ignored; put to an existing
    remote directory fails.
  • If the server returns an older vault (a rollback), the client reports
    sync_conflict; review it and use pull --adopt-remote to adopt it.
  • When HOME cannot be determined, startup errors and instructs the operator
    to set HOME or SSM_CONFIG_DIR.
  • Credential files passed with --password-file, --key-file, --secret, or
    --master-pass-file that are readable by other users produce a warning.
    Set SSM_NO_PERMISSION_WARNING=1 to suppress it; Windows does not warn.
  • get directory downloads reject device files and remove special permission
    bits. Cloud clients reject cross-host or downgrade redirects.
  • status reuses one unlock and completes faster.

There is no new error code and no request-schema or JSON-field breaking
change. The checked range has no request-schema file changes
(git diff 6431cae..c77ffdf --stat -- skills/agent-ssm/references/*.json is
empty); result and request additions remain additive.

v2.1.0

Choose a tag to compare

@github-actions github-actions released this 01 Oct 05:07
335ea4f

This is a v2 minor release. It fixes the agent-experience issues from the
2026-09 usage audit (tracking issue #89) and changes some default
behavior and some error codes
. Only some of the changes have a
compatibility switch; the lists below say which. The official exact-tag release workflow creates the stable v2.1.0
Release with make_latest=false; v2.0.2 remains GitHub latest until
published-asset canaries pass and a separate explicit latest-promotion
decision is made. Ordinary ssm update stays within v2, and once v2.1.0 is
promoted, same-major ssm update (including automatic update) adopts these
defaults on existing installs. If a fleet needs the old behavior, pin
sync_mode: strict and SSM_RUN_OUTPUT=buffered first.

Default behavior changes (read before upgrading)

  • Local-first inventory (#72). Read commands (run, map, get, put,
    check, doctor, list, host list|show, host-key, keys, status)
    read the local vault and no longer contact the sync server first; a sync
    server outage no longer fails them. Automatic sync runs in a detached
    background process, rate-limited (sync_interval, default 10m) with
    exponential backoff (30s doubling to 1h). status reports freshness
    (remote_state, last_successful_sync, last_sync_error,
    next_sync_attempt, cache_age_seconds, inventory_stale,
    inventory_unsynced); inventory older than stale_after (default 7d) is
    reported stale. run JSON adds inventory_stale, inventory_unsynced,
    inventory_sync_error. Restore the v2.0.2 behavior with
    "sync_mode": "strict" in settings.json or SSM_SYNC_MODE=strict.
    --offline is deprecated for reads (it now only suppresses background
    sync); SSM_OFFLINE=1 is equivalent. login now fetches the inventory
    immediately. Local vault mutations and every pull (explicit sync/pull,
    strict-mode refresh, background) take a short vault write lock; a
    concurrent writer can produce a bounded (5s) "vault is busy ... retry"
    failure.
  • Streaming human-mode run output (#71). Output is streamed as it
    arrives instead of being held until the command exits (no more 8 MiB
    per-stream limit); stdout is byte-exact, stderr is redacted line by line.
    --json still returns one complete value. SSM_RUN_OUTPUT=buffered
    restores the previous buffering. Local SIGINT/SIGTERM/SIGHUP are forwarded
    to the remote command (interrupted, exit 128+signal).
  • Connect timeout covers the SSH handshake (#73). --connect-timeout
    (default 15s) bounds TCP connect plus the SSH handshake and
    authentication; legacy --timeout on run/exec/plan/map/--stream is a
    deprecated alias of it (last flag wins; flags beat SSM_CONNECT_TIMEOUT /
    SSM_TIMEOUT). put/get/cp keep --timeout as the transfer timeout.
    See the lists below for the resulting error-code changes.
  • SSH keepalive on by default (#73). keepalive@openssh.com every 15s;
    the connection is closed after 3 unanswered probes (connection_lost).
    SSM_KEEPALIVE=0 disables it; SSM_KEEPALIVE=<duration> changes it and an
    invalid value falls back to 15s.

Error-code changes (affects automation that matches error)

These replace codes that were too generic (internal) or split out a specific
cause. None has a compatibility switch. Exit 255 is the transport-failure exit
(dial_*, connection_lost, handshake_failed, session_limit).

  • A dropped connection after the command was sent: connection_lost
    (stage remote_execution, exit 255, additive outcome:"unknown") instead
    of internal (exit 1); a put/get whose connection breaks midway is
    connection_lost (exit 255) instead of remote_write_failed /
    remote_read_failed (exit 1) (#79).
  • A handshake failure or stall after TCP connected: handshake_failed (stage
    handshake, exit 255) instead of internal or dial_timeout (#73, #79).
  • Windows refused connection: dial_refused (stage dial, exit 255) instead
    of internal (exit 1) (#85).
  • A session-limit wait that gives up: session_limit (stage session, exit
    255) instead of session_failed (#76).
  • New codes: exec_timeout (exit 124), remote_shell_unsupported (exit 1),
    sftp_unavailable (exit 1) and proxy_jump_invalid (exit 2); error
    values that v2.0.2 never produced.

Changes without a compatibility switch

Besides the error codes above:

  • --connect-timeout (and request timeout on run requests, --timeout on
    run/exec/plan/map) now also covers the SSH handshake and authentication,
    not only TCP connect. Mitigation: pass a larger --connect-timeout.
  • CLI duration flags reject integers with trailing text (30abc) and other
    malformed values.

Changes that do have a switch: sync_mode: strict / SSM_SYNC_MODE=strict
(local-first reads), SSM_RUN_OUTPUT=buffered (streaming run output),
SSM_KEEPALIVE=0 (keepalive), --no-stdin / SSM_FORWARD_STDIN=0
(stdin forwarding stays as before by default).

New features

  • --exec-timeout for run/exec/map/--stream and request-v1
    exec_timeout: SIGTERM at the deadline, 5s grace, exec_timeout, exit 124,
    timed_out:true, output so far kept (#73).
  • Explicit stdin forwarding: --stdin, --no-stdin, --stdin-file,
    request-v1 stdin_file, JSON stdin_forwarded; defaults unchanged (#77).
  • --interpreter for non-shell -f scripts and shebang-aware script errors (#81).
  • Command and flag suggestions instead of alias_not_found for typos (#82).
  • --retry-dial N[:backoff] (N at most 10, exponential backoff with jitter
    from backoff, default 250ms, capped at 30s) and sshctl wait <alias>
    (--timeout, --interval, --until ssh|tcp): retry only transport
    failures before the host key arrived; never retry authentication or
    host-key failures; one SSH connection per wait attempt (#85).
  • SFTP transfers for targets without a POSIX shell (#87): put/get --sftp,
    host setting --transfer auto|shell|sftp (host.transfer in request v1,
    default auto through the shell path) and a per-operation request
    transfer field. SFTP handles single regular files only. New error codes:
    remote_shell_unsupported (stage discovery) and sftp_unavailable
    (stage capability).
  • ProxyJump aliases (host ... --proxy-jump <alias>, host.proxy_jump in
    request v1; chains up to 5 hops, no cycles, otherwise proxy_jump_invalid,
    exit 2) with per-hop host-key verification and per-hop local credentials,
    an optional via field on failures, and sshctl cp <a>:<path> <b>:<path>
    (single regular file) relayed through this machine with three-way SHA-256
    verification. cp --direct is not implemented.
    Upgrade every client before using proxy_jump: v2.0.2 and older
    ignore the field and drop it if they re-save the synced vault.

Fixes

  • Security: Go 1.26.8, golang.org/x/crypto v0.56.0, grpc v1.83.1 (#69).
  • -h/--help and --json inside remote argv are no longer captured by
    sshctl; ssm pull --help no longer performs a pull (#70, #75).
  • host-key: a different recorded key type is no longer reported as a MITM
    mismatch; accept no longer deletes other key types (#74).
  • Sync failures keep and classify their cause (cause) without exposing the
    server address (#78).
  • Directory transfer error handling, --sha256 digest-tool detection,
    --dir-mode, get/put option parity (#80).
  • The connection pool keeps the shared connection when the server's session
    limit is reached and waits for a free slot (#76).
  • Help, README and agent skill aligned with the actual flags and environment
    variables, enforced by a contract test (#83).

Maintenance

  • The test suite no longer requires the pinned toolchain, CI triggers were
    cleaned up, and a weekly govulncheck runs (#84, #88).

Request schema (request v1, version stays 1)

Compared with v2.0.2, every change is additive, and no request that v2.0.2
accepted is now rejected (v2.0.2 already rejected unknown fields):

  • New run/plan fields: interpreter, exec_timeout, stdin_file
    (stdin_file is not valid with script_file; interpreter only with
    script_file; preflight:true is invalid with a non-shell interpreter).
  • New put/get fields: transfer (auto|shell|sftp); dir_mode on
    put. get now also accepts sha256 and timeout (v2.0.2 rejected them).
  • New host fields: transfer and proxy_jump (empty string clears it).
  • Run-only fields (interpreter, stdin_file, exec_timeout) stay invalid
    on put/get; transfer is invalid on run, check, doctor and host ops.
  • op:get itself is not new; it was added in v2.0.0.

There is no request-schema or JSON-field breaking change: new result fields
(inventory_*, stdin_forwarded, via, outcome, timed_out,
dial_attempts) are additive. The behavior changes are the default changes
and the error-code changes listed above; v2 compatibility behavior remains
available only through the switches named there.

v2.0.2

Choose a tag to compare

@github-actions github-actions released this 07 Aug 03:35
ed22162

This is a backward-compatible patch release containing the reviewed v2.0.2
repair work:

  • add explicit, identity-checked reviewed remote adoption for true
    no-transaction divergence;
  • honor SSM_CONFIG_DIR for the encrypted vault and private sidecars;
  • keep ordinary pull fail-closed and preserve the v2.0.1 public contract.

The official exact-tag release workflow creates the stable v2.0.2 Release with
make_latest=false; v2.0.1 remains GitHub latest until a separate explicit
latest-promotion decision and its canaries pass.

v2.0.1

Choose a tag to compare

@github-actions github-actions released this 06 Aug 00:13
379ce2d

This is a backward-compatible patch release. The official exact-tag release
workflow creates the stable v2.0.1 Release with make_latest=false; v2.0.0
remains GitHub latest until the published candidate assets and canaries pass
and a separate explicit promotion makes v2.0.1 latest.

  • Fix fresh installation with GitHub CLI 2.92.0. gh attestation verify
    requires attestation bundle files to have a .json or .jsonl suffix;
    install.sh now downloads the bundle into a private mktemp directory as
    attestation.json and removes the file and directory on both success and
    failure.
  • There is no protocol or schema breaking change, and v2 compatibility
    behavior remains unchanged.

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 04 Aug 13:11
10417d0

This section is prepared for the authorized stable v2.0.0 Release. The exact-tag
release workflow may publish it only with make_latest=false; v1.4.4 remains
GitHub latest. All child tickets through Issue #31 are closed and the #31 final readiness
proof is an executable, non-publishing verify release profile whose
final v2-readiness-report check validates the checked-in evidence map against
the live manifest. BC-1 through BC-10 are the approved compatibility migration
rows; their complete field-level old/new/action/machine/rollback matrix
is part of this release contract. Verification is non-mutating and does not publish
a tag or release. Only the official exact-tag release workflow may
publish after every source release blocker, migration review, pinned provenance
check, rollback rehearsal, native CI gate, and independent review passes.

Pinned release provenance

  • The updater contract requires automatic and manual same-major updates,
    explicitly authorized major migrations, and installer replacements to carry both the selected
    SHA-256 digest and keyless provenance for the exact downloaded asset.
  • Provenance is pinned to Cd1s/ssm, the reviewed release workflow identity,
    GitHub Actions' OIDC issuer, the supported six-target manifest, and the
    reviewed identity-rotation state. Missing, malformed, unverifiable,
    wrong-subject, or expired provenance leaves the existing executable intact.
  • The official release build publishes one adjacent Sigstore bundle per binary.
    Checksums remain an independent digest input but cannot authorize replacement alone.
  • Redirected and unknown-length release responses are streamed through exact
    1 MiB metadata/provenance, 16 KiB checksum, and 64 MiB binary ceilings.
  • The installer uses a same-directory staging template accepted by both
    GNU and macOS/BSD mktemp. Windows self-update renames the mapped old image
    aside under an exclusive same-directory update lock, installs the
    identity-checked sibling stage synchronously, and rolls back bytes and
    security on failure. Ordinary users preserve and verify owner, primary
    group, DACL, and DACL inheritance; tokens that can enable all three Windows
    backup/restore/security privileges also preserve the complete descriptor.
    A later launch removes only an identity-bound completed rollback image.
  • On a trust failure, keep using the preserved executable and wait for a
    repaired release through a reviewed identity. Installer users need a current
    GitHub CLI with attestation verification and head -c; there is no
    verification skip.

Reviewed saved-key publication

  • The v2 publication preflight rejects unsatisfied cross-alias saved-key
    create, replace, rename, delete, prune, and reference prerequisites before
    any sync request.
  • The safe failure message lists every required stable transaction ID in
    ledger order with alias, operation, key name, and reason. Publish those IDs
    explicitly in order, then retry the original transaction; SSM never adds
    prerequisites or unrelated pending mutations to the selected scope.
  • Modern direct and request-v1 host mutations retain their existing encrypted
    vault/ledger schema, transaction ID format, and typed success fields. Legacy
    remove, saved-key removal, and guarded import now append pending transactions
    without automatic publication.
  • A state-changing host mutation returns a stable transaction_id. An
    idempotent update/upsert can instead return changed:false,
    action:"unchanged", with transaction_id omitted; it creates no new
    transaction, so do not publish it.

Exact push scopes and empty-ledger safety

  • Bare push is invalid and is rejected before vault unlock or any sync HTTP
    request. Callers must choose sshctl --json push --only <transaction-id> or
    sshctl --json push --all.
  • sshctl --json push --all publishes only the invocation-start ordered pending-ID snapshot;
    later transactions remain pending.
  • An empty push --all performs one identity HEAD and no GET or PUT. Identical
    local, cached, and remote encrypted-blob identities return action:"noop";
    any missing or different identity returns a safe sync_conflict, preserves
    both blobs and private identity evidence, and never publishes a full blob.
  • English, Chinese, agent-skill, command-help, and recovery guidance now use
    only explicit publication scopes.
  • The empty-ledger sync_conflict hint recommends the guarded --merge
    recovery path. It does not suggest --replace --yes; the longer recovery
    guide permits replacement only after explicit full-replacement review.

Complete v2 compatibility migration

  • BC-1: a present malformed or unreadable cloud.json is a fatal
    sync_config_error for every online inventory operation. Missing remains
    unconfigured; explicit global --offline alone accepts cached state and
    performs no cloud parsing or network access.
  • BC-2: exact scoped publication preflights transitive alias and saved-key
    prerequisites without automatically adding them. Publish the listed stable
    IDs explicitly in ledger order.
  • BC-3: stream startup and terminal failures use compact NDJSON from the
    first byte. After initialization, each consumed non-empty input line has one
    ordered result; no ready, summary, or footer record is emitted.
  • BC-4: state-changing inventory entry points, including legacy remove,
    saved-key removal, and guarded import, create stable pending transactions and
    never auto-publish. A preserved idempotent host no-op has changed:false,
    action:"unchanged", omits transaction_id, and creates no transaction.
  • BC-5: bare push is invalid, non-empty --all fixes its ordered scope at
    invocation start, and empty --all never performs a PUT.
  • BC-6: online streams require a positive refresh interval. Zero refresh
    is valid only with explicit global offline mode and one fixed cached
    snapshot.
  • BC-7: direct and request-v1 file/directory put/get results have matching
    direction, kind, and stage. Directory operations report
    atomic:false, integrity:not_available, and resume:unsupported;
    directory get omits bytes_received rather than inventing a tar byte count.
  • BC-8: automatic and ordinary manual replacement remains within the
    installed major. ssm update --major reviews the migration and
    ssm update --major --yes is the sole non-interactive major authorization.
  • BC-9: checksums cannot authorize replacement without pinned keyless
    provenance and the exact 14-name release manifest.
  • BC-10: make check is the non-mutating go run ./cmd/verify ci adapter;
    verify release is a non-publishing strict superset.

The completed issues #2 through #11 remain preserved baselines rather than new
v2 features: non-interactive execution, scoped transactions, stable machine
errors, explicit offline/freshness, exact alias and host-key handling,
observable/resumable transfers, agent-safe invocation, and pre-unlock help all
remain compatible.

Migration and rollback

  • Back up the encrypted vault, remote.etag, publishing-intent.json,
    sync-conflict.json, pending ID order, and authenticated executable-recovery
    state without exposing their contents.
  • Run ssm --json update --major first. Require all automated checks and
    manually review bare-push consumers, zero-refresh online streams, and
    directory-transfer parsers before using --major --yes on a canary.
  • Authorization never bypasses digest/provenance verification. A failed trust,
    migration, or replacement gate preserves the old executable and evidence.
  • There is no automatic down-migration. Reinstall v1 only when the encrypted
    on-disk state is compatible, no publication/update recovery is outstanding,
    and remote identities and pending transactions have been reconciled. When
    state is uncertain, restore/recover v2 first and do not mutate further.
  • Verification does not merge, tag, install, upload, publish artifacts, or
    create a release. Only the official exact-tag workflow can publish after all
    migration, CI, provenance, rollback, and review blockers pass.

v1.4.4

Choose a tag to compare

@github-actions github-actions released this 04 Aug 03:02
767cdc9

These notes are prepared for the authorized official v1.4.4 maintenance bridge.
Publication is permitted only from the immutable v1.4.4 tag by the official
exact-tag release workflow. A source checkout or non-publishing candidate gate
does not create a tag or GitHub Release.

Major-version safety bridge

  • Make automatic update and ordinary ssm update same-major only. Seeing a v2
    GitHub Release never requests a v2 binary or replaces the running v1
    executable; same-major v1 maintenance updates remain available.
  • Add the sole explicit migration path: ssm update --major presents the
    BC-1..BC-10 review and release evidence without mutating state, while
    ssm update --major --yes authorizes replacement only after the approved
    read-only preflight succeeds.
  • Require the exact selected binary digest and pinned keyless provenance for
    repository Cd1s/ssm, the release workflow, the GitHub Actions issuer and
    hosted runner, one exact subject, and the exact selected tag ref. Missing,
    malformed, replayed, branch-based, or mismatched evidence fails closed.
  • Preserve the executable and encrypted v1 state on preflight, verification,
    or replacement failure. Use authenticated native Unix replacement and
    Windows deferred replacement/recovery semantics.

Staging and compatibility

  • Keep all legacy asset names, checksums.txt, and the install.sh asset so
    existing v1.4.3 clients can receive the official v1.4.4 bridge. The bridge
    installer now verifies the exact 14-entry selected-tag manifest, digest, and
    pinned provenance before replacement. For an existing installation it also
    refuses an older or cross-major selected release before any asset request;
    major migration remains solely ssm update --major --yes. Adjacent
    provenance also supports that later explicitly authorized v2 migration.
  • Document the reviewed identity overlap/expiry/removal gates and fail-closed
    emergency recovery. Rotation never permits checksum-only fallback or a
    verification bypass.
  • Use bridge-first staging: a v1 bridge decision must happen before any v2
    latest decision. v2 cannot become GitHub latest without a separate human
    release authorization after bridge rollout evidence is reviewed.
  • Add a credential-free, non-publishing candidate gate that verifies exact
    v1.4.3 ancestry, source version, release notes, all six platform builds,
    manifest/checksums, and synthetic exact-tag provenance.

v1.4.3

Choose a tag to compare

@github-actions github-actions released this 18 Jul 13:01

Fast agent execution

  • Keep one-shot literal commands on the direct sshctl --json run <alias> --argv ... path; typed request files remain the safer path for dynamic argv, scripts, secrets, and mutations.
  • Add sshctl run <alias> --stream, a headless NDJSON argv stream that syncs and decrypts once, reuses the SSH connection across commands, refreshes inventory every 30 seconds by default, and stops rather than using stale data after a refresh failure.
  • Reuse the already-validated decrypted vault for the command's first load, removing the duplicate Argon2 decrypt previously performed immediately after unlock while allowing later same-process loads to observe intervening saves.
  • Open the actual pooled SSH session directly instead of opening and closing a probe channel first. Serialize dials per destination rather than globally, allowing different fleet targets to establish SSH connections concurrently.

Validation

  • Add strict stream parsing/error tests and an in-process SSH regression proving that two commands use one connection and exactly two command sessions.