From 25d6c10b924e6f7298e1401691498be5183276b6 Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Mon, 28 Sep 2026 00:49:42 -0400 Subject: [PATCH] fix(installer): stop after failed automatic conversion --- .github/workflows/check-tools.yml | 3 ++ scripts/install.sh | 15 ++++-- scripts/test-install-conversion-failure.sh | 54 ++++++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 scripts/test-install-conversion-failure.sh diff --git a/.github/workflows/check-tools.yml b/.github/workflows/check-tools.yml index ec13b3ec..bdafe49a 100644 --- a/.github/workflows/check-tools.yml +++ b/.github/workflows/check-tools.yml @@ -32,3 +32,6 @@ jobs: - name: Validate agent selection (install.sh --agent / --agents-file) run: bash scripts/test-agent-selection.sh + + - name: Reject partial installs after conversion failure + run: bash scripts/test-install-conversion-failure.sh diff --git a/scripts/install.sh b/scripts/install.sh index 50f46893..ddfdf989 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -361,9 +361,18 @@ ensure_converted() { # other than the README count as output. if [[ ! -d "$d" ]] || [[ -z "$(find "$d" -type f ! -name 'README.md' 2>/dev/null | head -1)" ]]; then warn "$tool: integration files missing — running convert.sh --tool $tool" - "$SCRIPT_DIR/convert.sh" --tool "$tool" >/dev/null 2>&1 \ - && ok "$tool: generated integration files" \ - || err "$tool: convert.sh failed; run it manually" + if "$SCRIPT_DIR/convert.sh" --tool "$tool" >/dev/null 2>&1; then + ok "$tool: generated integration files" + else + # A failed conversion may have written only part of the roster. Remove + # that partial output so the next install retries conversion instead of + # treating it as a complete generated integration. + if [[ -d "$d" ]]; then + find "$d" -mindepth 1 -maxdepth 1 ! -name 'README.md' -exec rm -rf {} + + fi + err "$tool: convert.sh failed; run it manually" + return 1 + fi fi } AUTO_CONVERT=true # --no-convert disables diff --git a/scripts/test-install-conversion-failure.sh b/scripts/test-install-conversion-failure.sh new file mode 100644 index 00000000..cec9cd52 --- /dev/null +++ b/scripts/test-install-conversion-failure.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# A failed automatic conversion must not install a partial generated roster. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +tmp="$(mktemp -d "${TMPDIR:-/tmp}/agency-convert-failure.XXXXXX")" +trap 'rm -rf "$tmp"' EXIT + +mkdir -p "$tmp/repo/scripts" "$tmp/repo/integrations/codex" "$tmp/repo/engineering" "$tmp/home" +cp "$SCRIPT_DIR/install.sh" "$SCRIPT_DIR/lib.sh" "$tmp/repo/scripts/" +cat > "$tmp/repo/divisions.json" <<'EOF' +{ + "divisions": { + "engineering": {} + } +} +EOF +for name in first second; do + cat > "$tmp/repo/engineering/$name.md" < "$tmp/repo/integrations/codex/README.md" + +# Simulate an interrupted converter that leaves one of two agents generated. +cat > "$tmp/repo/scripts/convert.sh" <<'EOF' +#!/usr/bin/env bash +mkdir -p "$(dirname "$0")/../integrations/codex/agents" +printf 'name = "first"\n' > "$(dirname "$0")/../integrations/codex/agents/first.toml" +exit 23 +EOF +chmod +x "$tmp/repo/scripts/convert.sh" + +if HOME="$tmp/home" bash "$tmp/repo/scripts/install.sh" --no-interactive --tool codex > "$tmp/output" 2>&1; then + echo 'FAIL: install succeeded after automatic conversion failed' >&2 + exit 1 +fi +if [[ -d "$tmp/home/.codex/agents" ]] && find "$tmp/home/.codex/agents" -type f | grep -q .; then + echo 'FAIL: install copied incomplete generated output' >&2 + exit 1 +fi +if [[ -e "$tmp/repo/integrations/codex/agents/first.toml" ]]; then + echo 'FAIL: partial generated output would be used on the next install' >&2 + exit 1 +fi +grep -q 'convert.sh failed' "$tmp/output" || { + echo 'FAIL: conversion failure was not reported' >&2 + exit 1 +} +echo 'PASS: failed conversion stops installation before copying partial output'