Skip to content

v0.22.0

Choose a tag to compare

@github-actions github-actions released this 15 Jun 10:20
Immutable release. Only release title and notes can be modified.
v0.22.0
9ec1dc1

🚀 Features

  • (config) Reject unsupported strategy values - (35709f3) by @bchatard

    deploy hardcodes the atomic strategy, so a config with strategy: docker (or any
    non-atomic value) was silently accepted and ignored. Validate now rejects an
    explicit non-atomic strategy with a Config error (exit 2). An empty/unset strategy
    is still valid — it defaults to atomic. Part of M20 (S5).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (config) Reject empty hook cmd at load time - (bb39dbc) by @bchatard

    A hook with an empty cmd was accepted and would run 'sh -c ""' (a silent no-op).
    ValidateHookCmds now rejects any hook with a blank cmd at every config level, and
    Load reports it as a Config error (exit 2) alongside server-ref validation. Part of
    M20 (S6).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (deploy) Cancel the deploy on SIGINT via cmd.Context() - (c897858) by @bchatard

    deploy passed context.Background() to the deployer, so Ctrl-C couldn't interrupt a
    long artifact extraction. Now that forge v0.17.0 wires fang.WithNotifySignal,
    cmd.Context() is cancelled on SIGINT/SIGTERM; thread it into Deploy so cancellation
    reaches Extract (which honors ctx). A guard test confirms Extract aborts with
    context.Canceled. Other steps don't observe ctx yet — fuller cancellation is future
    work. Part of M20 (S3).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (deps) Bump forge to v0.17.0 - (2f285a8) by @bchatard

    cmd.Context() is now canceled on SIGINT/SIGTERM (forge cli.Run gains
    fang.WithNotifySignal); previously Ctrl-C killed the process via Go's
    default handler. exitcode.Interrupted (130) is also available for commands
    that surface context.Canceled.

    Co-Authored-By:Claude Sonnet 4.6 noreply@anthropic.com

🐛 Bug Fixes

  • (deploy) Log purge-plan errors instead of discarding them - (e26a80f) by @bchatard

    When PurgePlan failed, purgePlan was set to nil silently, so the dry-run preview
    and JSON purged list went empty with no indication why. Log the error via the
    operator-debug logger before discarding. The path is defensive (releases_root is
    valid by the purge step), so no dedicated test. Part of M20 (S10).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (transport) Bound agent downloads with an http.Client timeout - (5832a68) by @bchatard

    downloadAgent and verifyChecksum used http.Get with the default client (no
    timeout), so a hung GitHub could stall a deploy indefinitely. Route both through
    a shared http.Client with a 120s timeout. Part of M20 (S9).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (tui) Raise event-stream line limit above 64 KB - (7bad1af) by @bchatard

    A hook_output event carrying a large payload (e.g. a verbose migration log)
    exceeded bufio.Scanner's 64 KB default token, which dropped the line and aborted
    ForwardStream with 'token too long' — truncating the rest of the deploy stream.
    Raise the scanner buffer to 16 MB. Part of M20 (S7).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

🚜 Refactor

  • (cmd) Extract shared config-resolution and hook helpers - (59ba701) by @bchatard

    The flat-detect -> merge -> validate block was copied across deploy, release
    list/activate/rollback; writeTempFlatConfig, the env-map helper, and the
    interactive-confirm helper were each duplicated across the cmd and release
    packages. Consolidate them: cmdutil.ResolveMergedConfig and WriteTempFlatConfig,
    hooks.OSEnv, and tui.InteractiveHookConfirm. Behaviour-preserving — verified by
    the full unit suite plus local-deploy, client-deploy, and release E2E tests.
    Net -66 lines. Part of M20 (S1).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (deploy) Collapse the 8 hook-stage blocks into one helper - (eee16f7) by @bchatard

    The deploy pipeline repeated the same ~7-line hook block eight times (run the
    stage's hooks, wrap a failure with the stage name, render the step line). Extract
    a single runHookStage closure and call it per stage. Behavior-preserving — verified
    by the unit deploy tests and the hook-pipeline integration tests (firing, ordering,
    JSON and error events). Part of M20 (S2).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (hooks) Use errors.AsType to match ssh.go - (0d599a7) by @bchatard

    ssh.go uses the Go 1.26 errors.AsType generic; runner.go used the classic
    errors.As. Standardize on AsType (the modernize linter's preference) so the two
    error-inspection sites read the same. No behavior change. Part of M20 (S4).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (transport) Chmod the agent via SFTP, not a remote shell - (2c64e60) by @bchatard

    Making the uploaded agent executable shelled out 'chmod +x' over SSH. Add
    Staging.Chmod (delegating to the existing SFTP.Chmod) and use it instead — one
    fewer remote shell exec and no command string to quote. Verified by the deploy
    and release E2E tests (the agent must be executable to run). Part of M20 (S8).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

📚 Documentation

  • (testing) Allow t.TempDir in deployer FS-logic tests - (f476cd6) by @bchatard

    Constraint #1 forbade t.TempDir(), but the deployer's own logic tests
    (deploy_logging_test, deploy_hookoutput_test, deploy_exitcode_test) need a real
    local filesystem — afero is banned precisely because it can't model the symlinks
    the deployer relies on. Carve a narrow exception rather than leave three files
    silently contradicting a hard constraint. Co-Authored-By:Claude Fable 5 noreply@anthropic.com

🧪 Testing

  • (cmd) Assert hook output is visible over SSH (S11) - (2789e1d) by @bchatard

    Extract the deploy-over-SSH scaffolding (connect, stage, exec agent, forward the
    JSON stream) into testutil.DeployOverSSH so it isn't duplicated; refactor the
    existing client deploy E2E onto it. Add TestDeployCmd_HookOutputVisibleOverSSH:
    deploy over SSH with a post_extract hook that echoes a marker and assert the marker
    appears in the rendered output — the end-to-end proof of the M19 hook-output fix
    that was deferred. Closes M20 (S11).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (cmd) Confirm deploy error via stderr, not the exec exit code - (236e130) by @bchatard

    TestPlainOutput_NoColorCodes/TestNoColor_SuppressesColors asserted the deploy
    errored via the container-exec exit code. testcontainers can read that code as 0
    for a fast-exiting process under CI load (the attach EOFs before the exit status
    is finalized), so the tests flaked on CI even though 'bifrost deploy' exits 1
    deterministically. Confirm the error via non-empty stderr (read reliably to EOF)
    instead. The ANSI color-code assertions — the tests' real purpose — are unchanged.

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

  • (testutil) Unique known_hosts path to fix CI host-key race - (bca2aa2) by @bchatard

    WriteKnownHosts wrote to a fixed /tmp/bifrost-test-known-hosts. The CMD and
    RELEASE integration packages run in parallel and both write it, so under CI load
    one clobbered the other's host key, failing the release E2E with 'knownhosts: key
    is unknown'. S11's added SSH test raised the collision odds enough to trip it.
    Write a unique per-call path instead. Full integration suite green (252).

    Co-Authored-By:Claude Fable 5 noreply@anthropic.com

Commit Statistics

  • 15 commit(s) contributed to the release.
  • 1 day(s) passed between the first and last commit.
  • 15 commit(s) parsed as conventional.
  • 0 linked issue(s) detected in commits.
  • 1 day(s) passed between releases.