Skip to content

Bootstrap with -a shell crashes with "component: unbound variable" under set -u #52

Description

@Zordrak

Summary

Running --bootstrap with -a shell aborts with component: unbound variable
under set -u, because component is only declared in the non-bootstrap branch
but the shell action references it bare at
bin/terraform.sh:936.

Root Cause

set -uo pipefail is enabled at bin/terraform.sh:8.

component is declared readonly only in the non-bootstrap branch:

bin/terraform.sh:316-326

if [ "${bootstrap}" == 'true' ]; then
  [ -n "${component_arg}" ] \
    && error_and_die 'The --bootstrap parameter and the -c/--component parameter are mutually exclusive';
  ...
else
  [ -n "${component_arg}" ] \
    || error_and_die 'Required argument missing: -c/--component';
  readonly component="${component_arg}";   # only set here
  ...
fi;

In bootstrap mode, -c is explicitly rejected, so component is intentionally
never set. But the shell action prints it bare:

bin/terraform.sh:936

echo -e "Here's a shell for the ${component} component. ...";

Under set -u, this aborts before the shell is ever launched.

This is the same root-cause class as #50 (bootstrap-mode reference to a variable
that is only declared in the non-bootstrap branch) — there it was
${environment}, here it is ${component}.

Evidence

Minimal reproduction of the mechanism (mirrors the conditional declaration then
a bootstrap-mode bare reference):

$ bash -c 'set -uo pipefail
bootstrap="true"; component_arg=""
[ "${bootstrap}" == "true" ] || readonly component="${component_arg}"
echo "before component use"
echo "component is ${component}"'
before component use
bash: line 1: component: unbound variable
# exit code 127

Expected: either a working shell for the bootstrap component, or a clear
error_and_die explaining that shell is not supported with --bootstrap.

Actual: aborts with component: unbound variable.

Reproduction Steps

bin/terraform.sh \
  -p myproject \
  -r eu-west-2 \
  --bootstrap \
  -a shell \
  -- -input=false

(The -- -input=false is required only to work around #49.) With valid AWS
credentials the run proceeds to the shell case and aborts at
bin/terraform.sh:936 with
line 936: component: unbound variable.

Suggested Fix

This is a niche path, so the fixer should decide the intended semantics:

  1. Preferred — make the message tolerant of bootstrap mode. Use
    ${component:-bootstrap} (or ${component_name}, which is set by
    bin/terraform.sh:443 to basename of the component
    path and equals bootstrap in bootstrap mode) in the line-936 message, so a
    bootstrap shell works.
  2. Or explicitly reject it. If a shell into the bootstrap component is not a
    supported workflow, add an early error_and_die when
    bootstrap == 'true' && action == 'shell'.

Note that ${component_name} is already the safe, always-set equivalent used
elsewhere (e.g. the backend filename at
bin/terraform.sh:680), so switching the message to it
is low-risk.

Affected Platforms

All platforms and all bash versions (verified on bash 5.1.16).

Related

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions