The marketplace publisher tool: packs containers/<slug>/ (the drop-in app contract, unchanged) into a deterministic tarball (commit-clamped mtimes + gzip -n; unchanged apps repack byte-identical and keep their published version), signs it, copies a sha256-pinned catalog icon, and upserts a type:"app" / payload.kind:"bundle" envelope into the same team-signed index hotfixes ride. Catalog metadata (title/category/descriptions) is parsed line-wise from the app's own .config — one source of truth with the App Center generators. auto:false is hard-forced: apps never auto-apply. The index-upsert/serial/freshness/publishers-map and signing logic is factored out of make_hotfix.sh into lib/release_index.sh, shared by both tools (make_hotfix.sh behavior preserved; regression-tested alongside an app entry: serial bump, both payload kinds coexist, valid_until refreshed). LP_INDEX_VALID_DAYS is the shared freshness knob (LP_HOTFIX_VALID_DAYS kept as a legacy alias). Verified: speedtest publish → deterministic repack (identical sha256) → served via local http.server → real lpFetchIndex/accessors harness 10/10. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
72 lines
3.6 KiB
Bash
72 lines
3.6 KiB
Bash
# Shared publisher-side helpers for the artifact index (sourced by
|
|
# make_hotfix.sh / make_app.sh — release tooling only, never the CLI tree).
|
|
#
|
|
# The index is the team-signed catalog every install fetches + verifies
|
|
# (scripts/source/artifacts.sh, docs/roadmap/updates-and-distribution.md §8).
|
|
# These helpers own the parts every publisher tool shares: signing when a key
|
|
# is configured, reading the publisher pubkey for the publishers map, and the
|
|
# upsert-entry + bump-serial + refresh-freshness index rewrite.
|
|
#
|
|
# Env (shared by all publisher tools):
|
|
# LP_MINISIGN_SECKEY offline secret key — set to SIGN (required for a real
|
|
# publish; unset = unsigned, local-testing only).
|
|
# LP_MINISIGN_PUBKEY public key file for the publishers map (default: repo
|
|
# libreportal.pub). Installs verify against the
|
|
# ROOT-OWNED footprint key, so this must be that key.
|
|
# LP_INDEX_VALID_DAYS freshness window written to valid_until (default 30;
|
|
# LP_HOTFIX_VALID_DAYS honoured as a legacy alias).
|
|
|
|
# releaseSignIfKeyed <file> <trusted-comment> — minisign-sign in place when a
|
|
# key is configured; a no-op otherwise (unsigned local-testing mode).
|
|
releaseSignIfKeyed() {
|
|
[[ -n "${LP_MINISIGN_SECKEY:-}" ]] || return 0
|
|
command -v minisign >/dev/null 2>&1 || { echo "release: LP_MINISIGN_SECKEY set but 'minisign' isn't installed" >&2; exit 1; }
|
|
minisign -Sm "$1" -s "$LP_MINISIGN_SECKEY" -t "$2" >/dev/null
|
|
}
|
|
|
|
# releaseSignedNote — the human-readable signing status for the summary line.
|
|
releaseSignedNote() {
|
|
if [[ -n "${LP_MINISIGN_SECKEY:-}" ]]; then echo "signed"; else
|
|
echo "unsigned (set LP_MINISIGN_SECKEY to sign — required for a real publish)"
|
|
fi
|
|
}
|
|
|
|
# releaseReadPubkey <pubkey-file> — echo the bare key line for the publishers
|
|
# map ("" when the file is missing; callers warn, signing still proceeds).
|
|
releaseReadPubkey() {
|
|
[[ -f "${1:-}" ]] || { echo ""; return 0; }
|
|
grep -v -i '^untrusted comment' "$1" | head -1 | tr -d ' \t\r\n'
|
|
}
|
|
|
|
# releaseIndexUpsert <envelope-json> <index-file> <publisher> <pubkey>
|
|
# Load-or-init the index, replace any same-id entry with the envelope, bump
|
|
# index_serial, refresh valid_until/generated_at, and upsert the publisher
|
|
# into the publishers map (role: official for "libreportal", else community).
|
|
# Echoes the new serial (callers sign the index with it in the comment).
|
|
releaseIndexUpsert() {
|
|
local envelope="$1" index="$2" publisher="$3" pubkey="$4"
|
|
local cur serial days valid_until now default_role
|
|
cur='{"schema":1,"index_serial":0,"publishers":{},"artifacts":[]}'
|
|
[[ -f "$index" ]] && cur="$(cat "$index")"
|
|
serial=$(( $(jq -r '.index_serial // 0' <<<"$cur") + 1 ))
|
|
days="${LP_INDEX_VALID_DAYS:-${LP_HOTFIX_VALID_DAYS:-30}}"
|
|
valid_until=$(( $(date +%s) + days * 86400 ))
|
|
now="$(date -Iseconds 2>/dev/null || date)"
|
|
default_role="community"; [[ "$publisher" == "libreportal" ]] && default_role="official"
|
|
|
|
jq \
|
|
--argjson env "$envelope" \
|
|
--arg pub "$publisher" --arg pubkey "$pubkey" --arg role "$default_role" \
|
|
--argjson serial "$serial" --argjson vu "$valid_until" --arg now "$now" '
|
|
.schema = 1
|
|
| .index_serial = $serial
|
|
| .valid_until = $vu
|
|
| .generated_at = $now
|
|
| .publishers = (.publishers // {})
|
|
| .publishers[$pub] = ((.publishers[$pub] // {display: $pub, role: $role})
|
|
+ (if $pubkey != "" then {key: $pubkey} else {} end))
|
|
| .artifacts = (((.artifacts // []) | map(select(.id != $env.id))) + [$env])
|
|
' <<<"$cur" > "$index"
|
|
echo "$serial"
|
|
}
|