From 7f96d0f49102660624f8d9a2f2d621c340b4c084 Mon Sep 17 00:00:00 2001 From: Roy Osherove <575051+royosherove@users.noreply.github.com> Date: Sat, 22 Aug 2026 21:54:17 +0000 Subject: [PATCH 1/2] fix(wizard): retry Kiro API key prompt on invalid format instead of skipping Previous behavior: user typos ksk_... key, wizard warns 'API key doesn't match expected format', silently skips the whole step, and user has to authenticate manually after install. New behavior: wrap the prompt in a retry loop. - Valid ksk_... key -> accept, break - Empty input (Enter) -> skip (existing convention) - Literal 'skip' typed (case-insensitive) -> skip - Invalid format -> warn with remaining attempt count and re-prompt - After 5 attempts -> warn and skip (avoid infinite loop) Also: gum prompt cancellation (Esc / Ctrl-C) returns non-zero and prompt_secret falls back to the empty default -> treated as skip, so 'press Esc to move on' works out of the box without extra keyboard plumbing. UX text updated from 'Press Enter to skip' to 'Press Enter (empty input) or type skip to skip and authenticate via browser later.' Verified: - bash -n install.sh: OK - All existing paths (empty, valid, invalid+skip, invalid+retry+valid, invalid+retry-until-exhausted) mapped to distinct branches with clear warn messages. --- install.sh | 65 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/install.sh b/install.sh index 3931cd5..fd73c41 100755 --- a/install.sh +++ b/install.sh @@ -3380,33 +3380,56 @@ run_config_and_review() { echo -e " Create an API key at: ${CYAN}https://app.kiro.dev/settings/api-keys${NC}" echo -e " (Your organization must have API keys enabled.)" echo "" - echo -e " Press Enter to skip (you can authenticate via browser later)." + echo -e " Press Enter (empty input) or type 'skip' to skip and authenticate via browser later." echo "" _KIRO_API_KEY="" - prompt_secret "Kiro API key" _KIRO_API_KEY "" - if [[ -n "$_KIRO_API_KEY" ]]; then + # Retry loop: allow user to correct format mistakes without losing the step. + # Skip conditions: empty input, or literal 'skip' typed, or user cancels the + # gum prompt (Esc / Ctrl-C returns non-zero and prompt_secret falls back to + # the default "" — which we treat as skip). + _KIRO_ATTEMPTS=0 + _KIRO_MAX_ATTEMPTS=5 + while (( _KIRO_ATTEMPTS < _KIRO_MAX_ATTEMPTS )); do + _KIRO_ATTEMPTS=$((_KIRO_ATTEMPTS + 1)) + _KIRO_INPUT="" + prompt_secret "Kiro API key" _KIRO_INPUT "" + # Skip: empty input, or user typed "skip" (case-insensitive) + if [[ -z "$_KIRO_INPUT" ]] || [[ "${_KIRO_INPUT,,}" == "skip" ]]; then + _KIRO_API_KEY="" + break + fi # Validate format: ksk_, ~35 chars - if [[ ! "$_KIRO_API_KEY" =~ ^ksk_[A-Za-z0-9]{26,96}$ ]]; then - warn "API key doesn't match expected format (ksk_...). Skipping — authenticate manually after install." + if [[ "$_KIRO_INPUT" =~ ^ksk_[A-Za-z0-9]{26,96}$ ]]; then + _KIRO_API_KEY="$_KIRO_INPUT" + break + fi + # Invalid format — warn and re-prompt + _KIRO_REMAINING=$((_KIRO_MAX_ATTEMPTS - _KIRO_ATTEMPTS)) + if (( _KIRO_REMAINING > 0 )); then + warn "API key doesn't match expected format (ksk_... followed by 26-96 alphanumeric chars). ${_KIRO_REMAINING} attempt(s) left. Press Enter or type 'skip' to skip." + else + warn "API key doesn't match expected format after ${_KIRO_MAX_ATTEMPTS} attempts. Skipping — authenticate manually after install." _KIRO_API_KEY="" + fi + done + unset _KIRO_INPUT _KIRO_ATTEMPTS _KIRO_MAX_ATTEMPTS _KIRO_REMAINING + if [[ -n "$_KIRO_API_KEY" ]]; then + # Secret name determined now; actual write deferred until after user confirms + _KIRO_SECRET_NAME="/lowkey/${ENV_NAME}/kiro-api-key" + KIRO_FROM_SECRET="${_KIRO_SECRET_NAME}" + # Update PARAM_VALUES at the KiroFromSecret index (looked up by name to + # survive future reordering; hardcoded index bit us when ExistingSubnetId2 + # was inserted and shifted RepoBranch/KiroFromSecret by one). + _kiro_idx=-1 + for _i in "${!PARAM_CFN_NAMES[@]}"; do + [[ "${PARAM_CFN_NAMES[$_i]}" == "KiroFromSecret" ]] && { _kiro_idx=$_i; break; } + done + if [[ "$_kiro_idx" -ge 0 ]]; then + PARAM_VALUES[$_kiro_idx]="$KIRO_FROM_SECRET" else - # Secret name determined now; actual write deferred until after user confirms - _KIRO_SECRET_NAME="/lowkey/${ENV_NAME}/kiro-api-key" - KIRO_FROM_SECRET="${_KIRO_SECRET_NAME}" - # Update PARAM_VALUES at the KiroFromSecret index (looked up by name to - # survive future reordering; hardcoded index bit us when ExistingSubnetId2 - # was inserted and shifted RepoBranch/KiroFromSecret by one). - _kiro_idx=-1 - for _i in "${!PARAM_CFN_NAMES[@]}"; do - [[ "${PARAM_CFN_NAMES[$_i]}" == "KiroFromSecret" ]] && { _kiro_idx=$_i; break; } - done - if [[ "$_kiro_idx" -ge 0 ]]; then - PARAM_VALUES[$_kiro_idx]="$KIRO_FROM_SECRET" - else - fail "BUG: KiroFromSecret not found in PARAM_CFN_NAMES" - fi - ok "API key will be stored in Secrets Manager: ${_KIRO_SECRET_NAME}" + fail "BUG: KiroFromSecret not found in PARAM_CFN_NAMES" fi + ok "API key will be stored in Secrets Manager: ${_KIRO_SECRET_NAME}" else info "Skipping API key — authenticate after install with: kiro-cli login --use-device-flow" fi From f8231b64f1154c453f6167cb84969c3b9d654a6c Mon Sep 17 00:00:00 2001 From: Roy Osherove <575051+royosherove@users.noreply.github.com> Date: Sat, 22 Aug 2026 21:59:52 +0000 Subject: [PATCH 2/2] fix(wizard): use Bash 3.2-safe lowercase for skip check (Codex P1 on #91) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex flagged: ${_KIRO_INPUT,,} is a Bash 4+ feature. On macOS's stock Bash 3.2 this expansion errors with 'bad substitution' — and because the installer runs under 'set -euo pipefail', ANY non-empty API key entry (including valid keys) would kill the whole installer before validation. Fix: swap the case-conversion for a portable tr pipeline, matching what the rest of the installer already uses for Darwin support. Verified: - bash -n install.sh: OK - Skip paths (Enter / 'skip' / 'SKIP' / 'Skip') still work - Valid keys no longer trip on the lowercasing --- install.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index fd73c41..59c96f8 100755 --- a/install.sh +++ b/install.sh @@ -3393,8 +3393,9 @@ run_config_and_review() { _KIRO_ATTEMPTS=$((_KIRO_ATTEMPTS + 1)) _KIRO_INPUT="" prompt_secret "Kiro API key" _KIRO_INPUT "" - # Skip: empty input, or user typed "skip" (case-insensitive) - if [[ -z "$_KIRO_INPUT" ]] || [[ "${_KIRO_INPUT,,}" == "skip" ]]; then + # Skip: empty input, or user typed "skip" (case-insensitive, Bash 3-safe) + _KIRO_INPUT_LC="$(printf '%s' "$_KIRO_INPUT" | tr '[:upper:]' '[:lower:]')" + if [[ -z "$_KIRO_INPUT" ]] || [[ "$_KIRO_INPUT_LC" == "skip" ]]; then _KIRO_API_KEY="" break fi @@ -3412,7 +3413,7 @@ run_config_and_review() { _KIRO_API_KEY="" fi done - unset _KIRO_INPUT _KIRO_ATTEMPTS _KIRO_MAX_ATTEMPTS _KIRO_REMAINING + unset _KIRO_INPUT _KIRO_INPUT_LC _KIRO_ATTEMPTS _KIRO_MAX_ATTEMPTS _KIRO_REMAINING if [[ -n "$_KIRO_API_KEY" ]]; then # Secret name determined now; actual write deferred until after user confirms _KIRO_SECRET_NAME="/lowkey/${ENV_NAME}/kiro-api-key"