From 8113a357a6cc65527af3fffe4436b41d697ff469 Mon Sep 17 00:00:00 2001 From: Edward Twumasi <45181928+teckedd-code2save@users.noreply.github.com> Date: Sat, 19 Sep 2026 21:16:43 +0000 Subject: [PATCH 1/4] fix(distribution): unify installer claim JSON parsing --- scripts/install | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/scripts/install b/scripts/install index 7d4fcde..a7ba685 100644 --- a/scripts/install +++ b/scripts/install @@ -39,6 +39,12 @@ json_escape() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\r/\\r/g; s/\n/\\n/g' } +json_string_field() { + local json="$1" + local field="$2" + printf '%s' "$json" | sed -n "s/.*\"${field}\":\"\\([^\"]*\\)\".*/\\1/p" +} + usage() { cat <<'USAGE' GroundControl installer @@ -327,10 +333,10 @@ if [ "$EXISTING_HEALTHY" -eq 1 ] && [ "$UPGRADE" -eq 0 ]; then CLAIM_JSON="$(docker exec groundcontrol-web node /app/scripts/create-install-claim.cjs --ttl-minutes "$CLAIM_TTL_MINUTES" 2>/dev/null)" || { fail "Existing GroundControl predates the claim installer. Re-run with --upgrade to install the current claim-capable image." } - STAGE="$(printf '%s' "$CLAIM_JSON" | sed -n 's/.*"stage":"\\([^"]*\\)".*/\\1/p')" - INSTANCE_ID="$(printf '%s' "$CLAIM_JSON" | sed -n 's/.*"instanceId":"\\([^"]*\\)".*/\\1/p')" - CLAIM_TOKEN="$(printf '%s' "$CLAIM_JSON" | sed -n 's/.*"claimToken":"\\([^"]*\\)".*/\\1/p')" - EXPIRES_AT="$(printf '%s' "$CLAIM_JSON" | sed -n 's/.*"expiresAt":"\\([^"]*\\)".*/\\1/p')" + STAGE="$(json_string_field "$CLAIM_JSON" "stage")" + INSTANCE_ID="$(json_string_field "$CLAIM_JSON" "instanceId")" + CLAIM_TOKEN="$(json_string_field "$CLAIM_JSON" "claimToken")" + EXPIRES_AT="$(json_string_field "$CLAIM_JSON" "expiresAt")" if [ "$STAGE" = "already_claimed" ]; then if [ "$JSON_MODE" -eq 1 ]; then @@ -488,10 +494,10 @@ fi CLAIM_JSON="$(docker exec groundcontrol-web node /app/scripts/create-install-claim.cjs --ttl-minutes "$CLAIM_TTL_MINUTES")" || fail "GroundControl is healthy but could not create the installation claim" -STAGE="$(printf '%s' "$CLAIM_JSON" | sed -n 's/.*"stage":"\([^"]*\)".*/\1/p')" -INSTANCE_ID="$(printf '%s' "$CLAIM_JSON" | sed -n 's/.*"instanceId":"\([^"]*\)".*/\1/p')" -CLAIM_TOKEN="$(printf '%s' "$CLAIM_JSON" | sed -n 's/.*"claimToken":"\([^"]*\)".*/\1/p')" -EXPIRES_AT="$(printf '%s' "$CLAIM_JSON" | sed -n 's/.*"expiresAt":"\([^"]*\)".*/\1/p')" +STAGE="$(json_string_field "$CLAIM_JSON" "stage")" +INSTANCE_ID="$(json_string_field "$CLAIM_JSON" "instanceId")" +CLAIM_TOKEN="$(json_string_field "$CLAIM_JSON" "claimToken")" +EXPIRES_AT="$(json_string_field "$CLAIM_JSON" "expiresAt")" [ -n "$STAGE" ] || fail "Unexpected claim generator response" From 60a6eb8b1ce89277b827de7f3b396caf238d9eb2 Mon Sep 17 00:00:00 2001 From: Edward Twumasi <45181928+teckedd-code2save@users.noreply.github.com> Date: Sat, 19 Sep 2026 21:16:47 +0000 Subject: [PATCH 2/4] test(distribution): guard idempotent claim parser --- src/lib/distribution-installer.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/distribution-installer.test.ts b/src/lib/distribution-installer.test.ts index 54e6cc0..30cf9e6 100644 --- a/src/lib/distribution-installer.test.ts +++ b/src/lib/distribution-installer.test.ts @@ -47,6 +47,12 @@ describe("GroundControl distribution installer contract", () => { expect(installer).not.toContain("docker compose down -v"); }); + it("uses one claim JSON parser across fresh and idempotent paths", () => { + expect(installer).toContain("json_string_field()"); + expect(installer.match(/json_string_field "\\$CLAIM_JSON"/g)?.length).toBeGreaterThanOrEqual(8); + expect(installer).not.toContain('sed -n \'s/.*"stage":"\\\\('); + }); + it("keeps the management port loopback-only", () => { expect(installer).toContain('127.0.0.1:'); expect(installer).not.toContain("/root/.ssh"); From 24e817be0349045cde978f0df34248a0a9968665 Mon Sep 17 00:00:00 2001 From: Edward Twumasi <45181928+teckedd-code2save@users.noreply.github.com> Date: Sat, 19 Sep 2026 21:17:12 +0000 Subject: [PATCH 3/4] chore(distribution): update installer checksum after parser fix --- scripts/install.sha256 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install.sha256 b/scripts/install.sha256 index a087f69..2940e0a 100644 --- a/scripts/install.sha256 +++ b/scripts/install.sha256 @@ -1 +1 @@ -f7fc493e177ad5f03450bc16647022717510db29e5ed5ca0ea03976fe1af5587 install +861c1ede763a302aa988f0b108853a3198b1ef8d4d6347ff8418e58c4c57f6f8 install From 99cdd0f2249a1405b149b04460d57167738715e9 Mon Sep 17 00:00:00 2001 From: Edward Twumasi <45181928+teckedd-code2save@users.noreply.github.com> Date: Sat, 19 Sep 2026 21:19:44 +0000 Subject: [PATCH 4/4] fix(test): match installer claim parser calls correctly --- src/lib/distribution-installer.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/distribution-installer.test.ts b/src/lib/distribution-installer.test.ts index 30cf9e6..15f3810 100644 --- a/src/lib/distribution-installer.test.ts +++ b/src/lib/distribution-installer.test.ts @@ -49,7 +49,7 @@ describe("GroundControl distribution installer contract", () => { it("uses one claim JSON parser across fresh and idempotent paths", () => { expect(installer).toContain("json_string_field()"); - expect(installer.match(/json_string_field "\\$CLAIM_JSON"/g)?.length).toBeGreaterThanOrEqual(8); + expect(installer.match(/json_string_field "\$CLAIM_JSON"/g)?.length).toBeGreaterThanOrEqual(8); expect(installer).not.toContain('sed -n \'s/.*"stage":"\\\\('); });