Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,8 @@ Upgrading the fabric binary under a running daemon — especially on a remote
machine reached only over `fabric shell` — must be done lockout-safe: a botched
restart can sever the only path back to the box. Follow this order.

Download a release asset directly, verify it against the release's combined
`SHA256SUMS` manifest, and stage both the old and new binaries with same-directory
Download a release asset directly, verify it against that asset's published
`.sha256`, and stage both the old and new binaries with same-directory
renames. A release archive contains exactly one member named literal `fabric`
(not `./fabric`); verify that shape before extracting:

Expand All @@ -377,9 +377,12 @@ download_dir="$(mktemp -d)"
trap 'rm -rf "$download_dir"' EXIT

curl --fail --location "$release_url/$asset" --output "$download_dir/$asset"
curl --fail --location "$release_url/SHA256SUMS" --output "$download_dir/SHA256SUMS"
curl --fail --location "$release_url/$asset.sha256" --output "$download_dir/$asset.sha256"

expected="$(awk -v asset="$asset" '$2 == asset { print $1 }' "$download_dir/SHA256SUMS")"
# The release publishes ONE .sha256 per asset, not a combined manifest. The file
# holds "<hash> dist/<archive>", with the builder's path still in it, so
# `shasum -c` fails here. Take field one and compare it ourselves.
expected="$(awk 'NR == 1 { print $1 }' "$download_dir/$asset.sha256")"
test -n "$expected"
if command -v sha256sum >/dev/null 2>&1; then
actual="$(sha256sum "$download_dir/$asset" | awk '{ print $1 }')"
Expand Down
20 changes: 18 additions & 2 deletions src/sync/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,24 @@ pub struct FileMeta {
pub hash: ContentHash,
/// File size in bytes (informational; the hash is the identity).
pub size: u64,
/// Whether the file is executable, the way git tracks it: a file is either
/// mode 644 or 755, and no other permission bit is replicated.
/// Whether the file is executable, the way git tracks it. ONLY this bit
/// replicates; no other permission bit crosses.
///
/// The resulting MODE is not fixed, and an earlier version of this comment
/// claimed it was. Materialization creates the file with `fs::write`, which
/// yields `0666 & ~umask`, and then ORs in `0o111`. So the mode depends on
/// the RECEIVING host's umask:
///
/// | receiver umask | plain file | executable file |
/// | --- | --- | --- |
/// | 022 | 0644 | 0755 |
/// | 002 | 0664 | 0775 |
///
/// Observed on hetz and droppy on 2026-08-23: 0664 and 0775, both umask
/// 002. Do NOT depend on an exact mode here; depend only on the executable
/// bit. st2's render deliberately differs: it writes an exact mode that is
/// immune to umask, so the two systems do not agree on the other bits and
/// are not meant to.
///
/// Defaulted so a peer that predates this field still parses. Note the
/// asymmetry: adding a field with a default is safe, removing one is not.
Expand Down
Loading