Skip to content

Releases: eggstack/eggup

0.2.0

Choose a tag to compare

@dbowm91 dbowm91 released this 24 Oct 13:54

Eggup 0.2.0

The lockstep 0.2.0 publication of every Eggup crate. Integrity evidence remains
SHA-256 checksum only — no crate in this release makes an authenticity or
signature claim, and no crate selects a release or authorizes a destination.

Why 0.2.0 and not 0.1.4

eggup-acquisition's next release had to be source-breaking: AcquisitionError::Io(String)
became Io { operation, source } with a live source() chain, and because
std::io::Error implements neither Clone nor PartialEq/Eq the enum now
derives Debug only. A source-breaking seam cannot ship as 0.1.4, and the
workspace is version-lockstep (version.workspace = true in all eight crates),
so the seam's version carried every crate forward with it.

Per-package publication source commits

All seven published from one commit — b612608, which is this tag:

Package Published from Registry checksum
eggup-core 0.2.0 b612608 (this tag) 2c86a0eb…eb23b8
eggup-archive 0.2.0 b612608 (this tag) ce35edd5…ff57ad
eggup-acquisition 0.2.0 b612608 (this tag) 2ef74b4d…299fc3
eggup-curl 0.2.0 b612608 (this tag) 15cf536f…90d3f7
eggup-eggfetch 0.2.0 b612608 (this tag) 9fc8f648…658721
eggup-service 0.2.0 b612608 (this tag) 31dd2e22…fe1b4a
eggup-eggpack 0.2.0 b612608 (this tag) 33dc1da4…14f1f6

The publication order was eggup-core → eggup-archive → eggup-acquisition
→ eggup-curl → eggup-eggfetch → eggup-service → eggup-eggpack,
because a crate is packaged only after every in-workspace dependency it names is
on the registry.

No existing tag was moved. The published 0.1.x versions are not withdrawn:
eggup-curl remains published through 0.1.2 and the other six through
0.1.3.

Three source breaks to plan for

  • eggup-acquisition: AcquisitionError::Io(String) is now
    AcquisitionError::Io { operation, source }, and the enum derives Debug
    only — Clone, PartialEq, and Eq are removed. A consumer that matched
    Io(_) must match the struct form; a consumer that cloned or compared whole
    error values must match on the variant and its fields instead.
    eggup-curl and eggup-eggfetch inherit this break transitively through
    their eggup-acquisition ^0.2 requirement, and eggup-eggpack inherits it
    through its exact =0.2.0 pin.
  • eggup-service: ServiceError::Manager(detail) is now
    ServiceError::Manager { kind, detail, os_code }, carrying a
    ManagerFailureKind. Match the struct form and branch on kind, not on the
    message text.
  • eggup-service: LifecycleUpdateReceipt gained the public field
    engine_policy. The struct has no Default impl, so a consumer that
    constructs it with a struct literal must add the field and stops
    compiling until it does. A consumer that only reads the receipt's fields is
    unaffected.

What the 0.2.0 line closes

  • eggup-service 0.1.3 misreported a successful stdin write as a failure.
    The bounded executor consumed the stdin writer's verdict with try_recv,
    which removes the message, so the writer's Ok(()) was discarded and the
    later receive observed an empty, disconnected channel. A crontab - install
    reported manager(Spawn, …) after a write that in fact succeeded. This is
    the first publication that carries the fix.
  • eggup-core 0.1.3 had no bounded stdin and an unbounded candidate
    deadline.
    run_bounded evaluated its documented wall-clock deadline only
    while the direct child was still alive, so a descendant that inherited the
    output pipe could pin the call indefinitely, and the timeout path left both
    reader threads unjoined. eggup-core 0.2.0 adds CommandSpec::stdin_data
    and MAX_STDIN_BYTES, makes the deadline an unconditional maximum bound on
    the whole bounded execution, and classifies a stdin failure by the instant the
    writer observed it.
  • eggup-archive's cleanup() success path was unreachable. The shared
    implementation emptied the owned tree and then unconditionally returned
    Err(CleanupFailed). All four entry points now share one truthful contract,
    and Ok(()) is reachable.
  • eggup-eggpack no longer runs a second SHA-256 implementation. It
    delegates to eggup_core::hash_file, and its direct sha2 runtime
    dependency is gone.

eggup-service also gained one behaviour change worth reading about: the cron
managed block body must now embed the absolute executable path of the spec, so
a desired_block that omits spec.executable() receives
ServiceError::InvalidInput from inspect, install, and uninstall.

Verification

Every crate was proven from outside this repository: a fresh fixture crate with
no path, git, or patch source, depending on =0.2.0, whose generated lockfile
resolves only from crates.io. The eggup-service fixture resolves
eggup-core 0.2.0 transitively, and the eggup-eggpack fixture resolves all
three of its exact pins at 0.2.0.

0.1.3

Choose a tag to compare

@dbowm91 dbowm91 released this 06 Oct 20:47

Eggup 0.1.3

Correctness and compatibility publication for the acquisition, archive, and core
subsystems. Integrity evidence remains SHA-256 checksum only — no crate in this
release makes an authenticity or signature claim.

Per-package publication source commits

These are not all the tag commit. eggup-acquisition 0.1.3 had to publish
first, because the other publications in this train resolve or exact-pin it, so
it was released from an earlier commit than the tag:

Package Published from Registry checksum
eggup-acquisition 0.1.3 bb8fe41 71ce1a0d…a285a7
eggup-eggfetch 0.1.3 bd43683 (this tag) e2bdffe9…56ada
eggup-archive 0.1.3 bd43683 (this tag) a28af652…9824c
eggup-core 0.1.3 bd43683 (this tag) 161b244b…789ad

bb8fe41 is an ancestor of this tag. No existing tag was moved.

eggup-acquisition 0.1.3 — the composed-transport deadline defect is closed

Published 0.1.2 was built from a commit that predated two workspace bug-audit
fixes. The reachable one: ComposedTransport handed the fallback adapter the
caller's full FetchLimits instead of the remaining budget, so a single
composed fetch could run for roughly twice the documented total_timeout — the
connect phase is part of that wall-clock budget. The fallback now receives only
what is left, with connect_timeout clamped alongside it so
connect_timeout <= total_timeout still holds, and an already-exhausted budget
reports Timeout without starting a doomed attempt. The second fix removes a
staged part file that could be left behind when its 0600 hardening failed.

eggup-curl 0.1.2 and eggup-eggfetch 0.1.2 keep caret requirements and now
receive the fix automatically on their next resolve.

Still open for eggup-eggpack 0.1.2: it exact-pins eggup-acquisition =0.1.2 and therefore still composes against the defective seam. Consumers of
that adapter must pin eggup-acquisition 0.1.3 themselves until
eggup-eggpack 0.1.3 publishes. This caveat is unchanged from the 0.1.2 notes.

eggup-eggfetch 0.1.3 — a fallible API no longer aborts the process

Runtime construction used .expect(), so a runtime-build failure (fd exhaustion,
driver creation failure) aborted the process from inside a fallible fetch; it now
returns AcquisitionError::Unavailable, which composition already knows how to
handle. The runtime is built once per calling thread rather than once per fetch,
which keeps EggfetchTransport Send + Sync — a stored runtime would make it
!Sync and break callers sharing one transport across threads. TooLarge now
reports the bound it actually enforces instead of 0.

eggup-archive 0.1.3 — Windows device aliases and truthful cleanup

validate_output_name rejected COM1..COM9 but accepted COM0/LPT0 and the
reserved console names CONIN$, CONOUT$, CLOCK$. All are now rejected.
Near misses such as com10 and console remain valid. residue_path() is now
truthful: a private root that still holds evidence is promoted to
CleanupFailed instead of being described as cleaned.

eggup-core 0.1.3 — self-update, stale-lock recovery, and a compatible error surface

First registry appearance of current-executable transaction parity (M010,
staging inside the installation root so a self-update never needs write authority
above the executable's own directory) and proof-authorized stale-lock recovery
(M011, opt-in; the default acquire still never recovers).

Compatibility. Error keeps exactly the seven variants 0.1.2
published, so an exhaustive match on it compiles unchanged across the upgrade.
This was verified by an external fixture that is byte-identical between the two
versions and that fails against the pre-correction tree. Retained evidence
moved to a new #[non_exhaustive] RecoveryError, used only by the new
opt-in recovery entry points; every previously published signature keeps
Result<T, Error>.

self-replace remains Windows-only, so the Unix/macOS dependency surface is
still sha2 only.

eggup-service 0.1.2 resolves and runs against this Core through its caret
requirement; that graph was proven from the registry with no path or Git
override.

Verification

Hosted Stable, MSRV (1.89), macOS, and Windows lanes green on the
publication commit. Every crate was additionally proven by registry-only
external fixtures that resolve from crates.io with no [patch], path, or Git
override — including control runs against the defective 0.1.2 packages to show
the fixtures actually detect the defects they claim to.

Publication is manual and is never performed by CI.

eggup-eggpack 0.1.3 — archive-member identity is now cross-checked

Added after the rest of the train; published from bd43683 (this tag), checksum
952e88b8…19c5.

Published 0.1.2 bound archive members to declared members positionally,
without cross-checking a bound member's recorded source_path/output_name
against the declaration it was about to represent. A mismatched or reordered
BoundExtraction could therefore bind bytes under a different member identity
whenever the content digests happened to match. Each bound member is now checked
against its declared counterpart and fails closed with
AdapterError::MapMismatch; identical-content members still cannot substitute for
one another.

This version also moves the adapter's exact Eggup dependency set to =0.1.3, which
closes the eggup-eggpack 0.1.2 caveat above: adapter consumers now receive
the acquisition composed-budget fix automatically, with no action required.

The adapter still selects no release, verifies no authenticity, and authorizes no
filesystem destination. Caller-bound destination APIs are unchanged.


Additional package publication — eggup-service 0.1.3 (2026-10-09)

Service M011 publishes the source-compatible M010 correction for stopping an
exact-owned failed systemd unit only after ownership, manager state, process IDs,
job state, and cgroup evidence prove quiescence. Foreign, malformed, restarting,
or still-populated units remain incomplete or denied. No public API migration is
required.

Package Source revision crates.io checksum Package size
eggup-service 0.1.3 feb6ae5aea4c9b61c4051957f3662ca49d845f9e 9f7f7ea854577158e66aa202709ab1c97a3aedcf00b06c1ab914d25b132124dc 72.7 KiB compressed; 396.0 KiB unpacked

The package-specific source is later than the shared v0.1.3 tag; that existing
tag remains unchanged. The exact-version registry-only fixture resolves
eggup-service = "=0.1.3" and eggup-core 0.1.3 from crates.io. Hosted run
37883703334 passed
Stable, Rust 1.89 MSRV, macOS, Windows, and the privileged Linux systemd lane,
including positive failed-unit quiescence and Foreign/malformed controls.

wg-basic Distribution M004 C001a adoption: change its service dependency to
eggup-service = "=0.1.3" and refresh the lockfile. The public API is unchanged;
the new runtime behavior lets its failed-candidate recovery path confirm an
owned failed unit is quiescent. M004 retains its independent rootful
qualification and production trust-root requirements.

Packaged changelog note: the immutable .crate includes the pre-upload
changelog snapshot from its recorded source revision, where 0.1.3 is labelled a
release candidate. The checked-in crate changelog and this release record now
reflect publication; the package bytes and checksum above are unchanged.

0.1.2

Choose a tag to compare

@dbowm91 dbowm91 released this 28 Sep 21:54

crates.io publication of the workspace 0.1.2 source version, in three steps.

Step 1 — 2026-09-28 (Verified Update Core M009), published in that order from
release-prep commit e8e07eb, tagged v0.1.2:

Step 2 — 2026-10-02 (Eggpack Manifest Interoperability M004), published in that
order from publication source 02a1d32:

Step 3 — 2026-10-04 (Acquisition Transport M009), published from release-prep
commit b485228:

Complete crates.io 0.1.2 publication set: eggup-core, eggup-archive,
eggup-acquisition, eggup-eggfetch, eggup-eggpack, eggup-curl.

eggup-service and eggup-transport-footprint share the 0.1.2 source version
and are still not published. eggup-transport-footprint is
publish = false by design and has no edge in the published adapter graph.

Step 3: the external-curl adapter promoted to the registry

eggup-curl implements AcquisitionTransport on top of an external curl
process, so a consumer can acquire artifacts without embedding an HTTP/TLS
stack in its binary. It was fully qualified under Acquisition M005–M008 but had
never been published, which left the lightweight path reachable only from a
local checkout. M009 published it as a package promotion; no transport
semantics changed, and no crates/ source, manifest, or version was edited.

What the published version carries:

  • Exact caller-selected URLs only. No discovery and no fallback inside the
    adapter; release/version/mirror policy stays caller-owned.
  • A caller-supplied curl executable invoked with no shell and no internal
    sudo. Transport fallback (curl <-> Eggfetch) lives in
    eggup-acquisition::ComposedTransport and is never release/source fallback.
  • Explicit connect/total ceilings as min(request, adapter) plus an
    independent parent wall deadline, serialized at microsecond precision so
    sub-second ceilings are passed truthfully instead of being widened.
  • Cancellation and timeout kill and reap the owned child before returning.
  • Exact HTTP 404 becomes FetchOutcome::NotFound; TLS/5xx/timeout/cancellation/
    size/staging failures stay hard acquisition failures.
  • Bounded streaming into Eggup-owned staging with a private temp sibling and
    race-safe no-clobber promotion. The temp pathname is never handed back to
    curl for reopening.
  • Redirect, protocol, and proxy policy are explicit. Diagnostics use category
    text plus the redacted URL, so raw curl output, command lines, and proxy
    credentials never appear in an error.

Two defects from the 2026-10-04 workspace bug audit are fixed in this
version
, because it was published after that commit: an https request could
previously follow a redirect down to cleartext http with no error and no
diagnostic (--proto-redir is now narrowed per request), and coincident
connect/total ceilings mislabelled a total-deadline timeout as a connect
timeout.

Platform note

Live local HTTP/curl evidence is carried by the Linux and macOS lanes. Hosted
Windows runners refused the historical spawned-curl loopback case, so the
Windows lane carries the portable adapter, process, and error-path fixtures
only. No Windows live HTTP/curl result is claimed for this release.

Known caveat: eggup-acquisition 0.1.2 published content

eggup-acquisition 0.1.2 was published from 02a1d32 on 2026-10-02 and does
not contain the two workspace bug-audit fixes that landed afterwards in
0b8cb98:

  • the owned .part file leaked when the permission-hardening step failed;
  • ComposedTransport handed the secondary adapter the caller's full
    FetchLimits instead of the remaining budget, so one composed fetch could run
    for roughly twice the caller's documented total deadline.

The second is reachable today by any consumer that composes two transports from
the registry. Until eggup-acquisition is republished with the fix, such
consumers should either pin a later version or set a total deadline that
tolerates the doubled composed window. This predates step 3 and is not
introduced by it. eggup-curl keeps a caret-compatible eggup-acquisition
requirement, so it inherits an eggup-acquisition 0.1.3 automatically once one
is published.

M004: producer manifest promoted to the registry

eggup-eggpack previously pinned eggpack-manifest to an immutable Eggpack Git
revision and was publish = false, so the adapter could not be consumed from a
registry at all. Eggpack published eggpack-manifest 0.1.0 on 2026-10-02
(https://crates.io/crates/eggpack-manifest/0.1.0), and M004 promoted the adapter
to the exact registry dependency eggpack-manifest = "=0.1.0".

The published eggpack-manifest 0.1.0 src/lib.rs is byte-identical to the
source at the revision the adapter used to pin, so this is a promotion of the
same bytes rather than a substitution of a source. No adapter requalification
was needed.

The adapter also gains the caller-bound destination seam:

  • ManifestProjection::default_destinations
  • materialize_artifact_set_with_destinations
  • core_plan_for_archive_with_destinations

Manifest install values remain producer default identity only. The adapter
still selects no release, verifies no authenticity, and authorizes no
filesystem destination.

Why the publication order matters

cargo package and cargo publish resolve the packaged manifest's
dependencies from crates.io, so the order is a hard constraint, not a
convention. Before eggup-acquisition 0.1.2 existed, eggup-eggfetch 0.1.2
could not pass its own package verification (two E0308 mismatches: the
published 0.1.1 seam types max_artifact_bytes as Option<u64> while the
0.1.2 finite-bounds seam types it as u64), and eggup-eggpack 0.1.2 could
not produce a package at all because its exact =0.1.2 pin had no registry
candidate. Publishing acquisition first resolved both. Step 3 was likewise
ordered after step 2 so that eggup-curl's packaged manifest had a registry
candidate for its eggup-acquisition requirement.

Verification

Hosted CI green on each publication source (Stable checks, MSRV check,
macOS tests, Windows archive/acquisition/service tests). cargo package and
cargo publish --dry-run clean for all six crates from a clean tree with no
--allow-dirty.

Three temporary external projects outside the repository, with only registry
dependencies and no [patch], path, or Git override, resolved exact =0.1.2
and passed smoke: the adapter-only graph, the Eggsact-shaped four-crate graph,
and the eggup-curl graph. The last one exercises the published package end to
end — public API construction, deadline-ceiling clamping, typed unavailability
for an unspawnable executable, typed cancellation, and live loopback HTTP where
200 is an ordinary success, exact 404 is NotFound, and an artifact stream is
promoted into caller-owned staging — 6/6 passing. All three lockfiles show one
registry source per package with no git+ or path entry, and the lockfile
checksums match the registry.

Source tag caveat

The v0.1.2 tag was not moved and still points at e8e07eb. As of the
2026-10-04 bug-audit commit, none of the six published crates is
reproducible from that tag any more; each has moved since it. Do not treat
v0.1.2 as a source reference for any published artifact. Each crates.io
version instead carries its own exact publication commit in
.cargo_vcs_info.json:

  • eggup-core, eggup-archive — e8e07eb
  • eggup-acquisition, eggup-eggfetch, eggup-eggpack — 02a1d32
  • eggup-curl — b485228

Contract

MSRV 1.89, edition 2021, MIT. Integrity is SHA-256 checksum evidence only; no
authenticity or signature verification is claimed by any crate in this release.
Egress archive/pair adoption (Consumer M006 / Egress Delivery M003) is
unblocked against the published packages. The producer manifest seam is now
registry-consumable; Eggsact's own Git-to-registry migration remains separately
authorized in eggstack/eggsact. The cargo-cleanme Phase 10 self-update path is
unblocked against the published eggup-curl; cargo-cleanme retains
release/version/fallback/install policy.

0.1.1

Choose a tag to compare

@dbowm91 dbowm91 released this 24 Sep 21:53

Lockstep patch release over 0.1.0, published to crates.io in seam-then-adapter order: eggup-acquisition, eggup-core, eggup-eggfetch, eggup-service (all 0.1.1). eggup-eggpack remains unpublished by design.

Highlights since 0.1.0 (see CHANGELOG.md for the full list):

  • core: canonical Absent | Owned | Foreign | Unknown ownership, staged-digest revalidation under lock, ADR-0002 post-commit KeepInstalled | RollBack policy
  • acquisition + eggfetch: effective min(request, adapter) timeouts, race-safe no-clobber promotion, credential redaction
  • service: Unix adapters (systemd/launchd/cron), M003 hardening, Windows SCM adapter, commit_with_lifecycle composition
  • consumer evidence: eggsact, stegoeggo, eggsearch, CodeGG M005

MSRV 1.89. Integrity is SHA-256 checksum evidence only; no authenticity claims.