1+ #! /usr/bin/env bash
2+ set -euo pipefail
3+
4+ usage () {
5+ cat << EOF
6+ Usage:
7+ $0 --tag vX.Y.Z --workdir ./release_work --labels L1,L2 [--test-gnupg-home /tmp/secluso_test_gnupg]
8+
9+ Creates a realistic builder-style bundle with dummy binaries:
10+ <workdir>/<tag>/builder_out/manifest.json
11+ <workdir>/<tag>/builder_out/{aarch64-unknown-linux-gnu,x86_64-unknown-linux-gnu}/...
12+ <workdir>/<tag>/manifest.json + manifest.sha256 (manager copy + hash)
13+ <workdir>/<tag>/sigs/ (both .asc)
14+ <workdir>/<tag>/out/secluso-<tag>.zip (to be uploaded as test release)
15+
16+ Reuses the same two test keys across runs by keeping GNUPGHOME stable.
17+ EOF
18+ exit 1
19+ }
20+
21+ TAG=" "
22+ WORKDIR=" "
23+ LABELS=" "
24+ TEST_GNUPG_HOME=" /tmp/secluso_test_gnupg"
25+
26+ # Validate args
27+ while [[ $# -gt 0 ]]; do
28+ case " $1 " in
29+ --tag) TAG=" $2 " ; shift 2;;
30+ --workdir) WORKDIR=" $2 " ; shift 2;;
31+ --labels) LABELS=" $2 " ; shift 2;;
32+ --test-gnupg-home) TEST_GNUPG_HOME=" $2 " ; shift 2;;
33+ -h|--help) usage;;
34+ * ) echo " Unknown arg: $1 " >&2 ; usage;;
35+ esac
36+ done
37+
38+ [[ -n " $TAG " && -n " $WORKDIR " && -n " $LABELS " ]] || usage
39+ IFS=' ,' read -r L1 L2 <<< " $LABELS"
40+ [[ -n " ${L1:- } " && -n " ${L2:- } " ]] || { echo " Need --labels L1,L2" >&2 ; exit 1; }
41+ [[ " $L1 " != " $L2 " ]] || { echo " Labels must be distinct" >&2 ; exit 1; }
42+
43+ # Require a v-prefixed tag
44+ if [[ " $TAG " != v* ]]; then
45+ echo " Tag must start with 'v' (example: v0.1.0). Got: $TAG " >&2
46+ exit 1
47+ fi
48+
49+ REL_DIR=" $WORKDIR /$TAG "
50+ mkdir -p " $REL_DIR "
51+
52+ SCRIPT_DIR=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) " && pwd) "
53+
54+ # Stable test keyring
55+ GNUPG_HOME=" $TEST_GNUPG_HOME "
56+ mkdir -p " $GNUPG_HOME "
57+ chmod 700 " $GNUPG_HOME "
58+ export GNUPGHOME=" $GNUPG_HOME "
59+
60+ # Sha256 helper (mac + linux)
61+ sha256_file () {
62+ local f=" $1 "
63+ if command -v sha256sum > /dev/null 2>&1 ; then
64+ sha256sum " $f " | awk ' {print $1}'
65+ else
66+ shasum -a 256 " $f " | awk ' {print $1}'
67+ fi
68+ }
69+
70+ # Create fake "builder output" directory
71+ ARTIFACT_DIR=" $REL_DIR /builder_out"
72+ rm -rf " $ARTIFACT_DIR "
73+ mkdir -p " $ARTIFACT_DIR /aarch64-unknown-linux-gnu" " $ARTIFACT_DIR /x86_64-unknown-linux-gnu"
74+
75+ # Dummy binaries (make them executable, updater will install them)
76+ cat > " $ARTIFACT_DIR /aarch64-unknown-linux-gnu/secluso-config-tool" << EOF
77+ #!/usr/bin/env sh
78+ echo "dummy secluso-config-tool aarch64 for ${TAG} "
79+ EOF
80+ chmod +x " $ARTIFACT_DIR /aarch64-unknown-linux-gnu/secluso-config-tool"
81+
82+ cat > " $ARTIFACT_DIR /x86_64-unknown-linux-gnu/secluso-config-tool" << EOF
83+ #!/usr/bin/env sh
84+ echo "dummy secluso-config-tool x86_64 for ${TAG} "
85+ EOF
86+ chmod +x " $ARTIFACT_DIR /x86_64-unknown-linux-gnu/secluso-config-tool"
87+
88+ # Compute sha256s that will be embedded in the signed manifest
89+ SHA_A=" $( sha256_file " $ARTIFACT_DIR /aarch64-unknown-linux-gnu/secluso-config-tool" ) "
90+ SHA_X=" $( sha256_file " $ARTIFACT_DIR /x86_64-unknown-linux-gnu/secluso-config-tool" ) "
91+
92+ # Create builder-style manifest.json w/ per-artifact sha256
93+ cat > " $ARTIFACT_DIR /manifest.json" << EOF
94+ {
95+ "build": {
96+ "target": "test",
97+ "profile": "release",
98+ "run_id": "1",
99+ "timestamp": "$( date -u +" %Y-%m-%dT%H:%M:%SZ" ) "
100+ },
101+ "artifacts": [
102+ {
103+ "package": "config_tool",
104+ "target": "aarch64-unknown-linux-gnu",
105+ "bin": "secluso-config-tool",
106+ "bin_path": "aarch64-unknown-linux-gnu/secluso-config-tool",
107+ "crate": "config_tool",
108+ "version": "${TAG# v} ",
109+ "crate_lock_sha256": "test",
110+ "rust_digest": "test",
111+ "sha256": "${SHA_A} "
112+ },
113+ {
114+ "package": "config_tool",
115+ "target": "x86_64-unknown-linux-gnu",
116+ "bin": "secluso-config-tool",
117+ "bin_path": "x86_64-unknown-linux-gnu/secluso-config-tool",
118+ "crate": "config_tool",
119+ "version": "${TAG# v} ",
120+ "crate_lock_sha256": "test",
121+ "rust_digest": "test",
122+ "sha256": "${SHA_X} "
123+ }
124+ ]
125+ }
126+ EOF
127+
128+ echo " Created fake builder_out at: $ARTIFACT_DIR "
129+ echo " aarch64 sha256: $SHA_A "
130+ echo " x86_64 sha256: $SHA_X "
131+ echo
132+
133+ # Manager step: copy builder manifest into <workdir>/<tag>/manifest.json + write manifest.sha256
134+ " $SCRIPT_DIR /secluso_prepare_release_dir.sh" \
135+ --tag " $TAG " \
136+ --workdir " $WORKDIR " \
137+ --labels " $LABELS " \
138+ --artifact-dir " $ARTIFACT_DIR "
139+
140+ MANIFEST=" $REL_DIR /manifest.json"
141+ SHA_FILE=" $REL_DIR /manifest.sha256"
142+ SIG_DIR=" $REL_DIR /sigs"
143+ mkdir -p " $SIG_DIR "
144+
145+ # Find an existing key by UID fragment, otherwisewe can create it.
146+ ensure_key () {
147+ local uid=" $1 "
148+ local existing
149+ existing=" $( gpg --with-colons --list-keys " $uid " 2> /dev/null | awk -F: ' $1=="fpr" {print $10; exit}' || true) "
150+ if [[ -n " $existing " ]]; then
151+ echo " $existing "
152+ return
153+ fi
154+
155+ gpg --batch --pinentry-mode loopback --passphrase " " \
156+ --quick-generate-key " $uid " ed25519 sign 5y > /dev/null
157+
158+ gpg --with-colons --fingerprint " $uid " | awk -F: ' $1=="fpr" {print $10; exit}'
159+ }
160+
161+ UID1=" secluso-test-${L1} <secluso-test-${L1} @example.invalid>"
162+ UID2=" secluso-test-${L2} <secluso-test-${L2} @example.invalid>"
163+
164+ FPR1=" $( ensure_key " $UID1 " ) "
165+ FPR2=" $( ensure_key " $UID2 " ) "
166+
167+ if [[ " $FPR1 " == " $FPR2 " ]]; then
168+ echo " ERROR: both labels resolved to the same key fingerprint; aborting" >&2
169+ exit 1
170+ fi
171+
172+ echo " Using test keys from GNUPGHOME=$GNUPG_HOME "
173+ echo " $L1 -> $FPR1 "
174+ echo " $L2 -> $FPR2 "
175+ echo
176+
177+ # Sign as each label (signer script verifies sha-file etc)
178+ " $SCRIPT_DIR /secluso_sign_manifest.sh" \
179+ --manifest " $MANIFEST " \
180+ --sha-file " $SHA_FILE " \
181+ --label " $L1 " \
182+ --key " $FPR1 " \
183+ --outdir " $SIG_DIR "
184+
185+ " $SCRIPT_DIR /secluso_sign_manifest.sh" \
186+ --manifest " $MANIFEST " \
187+ --sha-file " $SHA_FILE " \
188+ --label " $L2 " \
189+ --key " $FPR2 " \
190+ --outdir " $SIG_DIR "
191+
192+ # Build a real bundle (copies builder_out, overlays the signed manifest + signature files)
193+ " $SCRIPT_DIR /secluso_build_bundle.sh" \
194+ --tag " $TAG " \
195+ --workdir " $WORKDIR " \
196+ --labels " $LABELS " \
197+ --sig-a " $SIG_DIR /manifest.json.${L1} .asc" \
198+ --sig-b " $SIG_DIR /manifest.json.${L2} .asc" \
199+ --artifact-dir " $ARTIFACT_DIR "
200+
201+ echo
202+ echo " Test bundle ready at: $REL_DIR /out/secluso-${TAG} .zip"
203+ echo " Keys are persisted at: $GNUPG_HOME "
204+ echo
205+ echo " If you want the updater to accept these via GitHub keys, export + add them to your GitHub account:"
206+ echo " gpg --armor --export $FPR1 "
207+ echo " gpg --armor --export $FPR2 "
0 commit comments