Skip to content
Open
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
56 changes: 52 additions & 4 deletions src/commands/runtime/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,10 +701,33 @@ fi
# Extension dm-verity trees (<image_id>.verity) are not published by this path
# yet - only the images are - and a device given a root_hash without its tree
# refuses the extension. Refuse here instead, where the author can act on it.
if grep -q '"root_hash"' "$MANIFEST_FILE"; then
echo "ERROR: this runtime has extensions with image.verity: true; deploy does not publish their dm-verity hash trees yet, so the device would refuse them. Provision instead, or build without verity." >&2
exit 1
fi
# Only EXTENSION root hashes matter: the manifest's top-level root_hash is the
# rootfs verity hash, which travels in the boot FIT and needs no sidecar here.
# Exit 0: an extension carries root_hash (key present, as `connect upload`
# tests it). Exit 1: none does. Exit 2: the manifest could not be read or is
# not the expected shape - that must stop the deploy too, never pass as "no
# verity".
python3 -c '
import json, sys
try:
m = json.load(open(sys.argv[1]))
exts = m["extensions"]
if not isinstance(exts, list):
raise TypeError("extensions is not a list")
except Exception as e:
print("manifest %s: %s" % (sys.argv[1], e), file=sys.stderr)
sys.exit(2)
sys.exit(0 if any(isinstance(e, dict) and "root_hash" in e for e in exts) else 1)
' "$MANIFEST_FILE"
case $? in
0)
echo "ERROR: this runtime has extensions with image.verity: true; deploy does not publish their dm-verity hash trees yet, so the device would refuse them. Provision instead, or build without verity." >&2
exit 1 ;;
1) ;;
*)
echo "ERROR: could not read the runtime manifest to check for extension verity" >&2
exit 1 ;;
esac

# Read root.json
ROOT_JSON_FILE="$VAR_STAGING/lib/avocado/metadata/root.json"
Expand Down Expand Up @@ -1139,6 +1162,31 @@ async fn prepare_mac_deploy_net(

#[cfg(test)]
mod tests {
#[test]
fn hash_collection_refuses_only_extension_root_hashes() {
// A rootfs verity hash lives at the manifest's top level and needs no
// sidecar; only extensions[].root_hash must trip the refusal.
let cmd = RuntimeDeployCommand::new(
"dev".to_string(),
"avocado.yaml".to_string(),
false,
None,
"root@host".to_string(),
None,
None,
);
let s = cmd.create_hash_collection_script("x86_64");
assert!(
s.contains("\"root_hash\" in e for e in exts"),
"checks key presence on extensions, not the whole file"
);
assert!(
s.contains("sys.exit(2)"),
"an unreadable manifest is its own failure"
);
assert!(!s.contains("grep -q '\"root_hash\"'"), "no whole-file grep");
}

use super::*;

// --- DeviceSpec parsing tests ---
Expand Down
Loading