Skip to content

[Sprint] sprint-loop-4 - #6

Merged
scealiontach merged 6 commits into
mainfrom
sprint/2026-04-28-sprint-loop-4
Apr 28, 2026
Merged

scealiontach merged 6 commits into
mainfrom
sprint/2026-04-28-sprint-loop-4

Conversation

@scealiontach

Copy link
Copy Markdown
Owner

Sprint Plan — 2026-04-28 (loop 4)

Sprint goal

Land a focused, low-risk bug-fix sprint that hardens six bash/ command scripts against well-understood, narrowly-scoped defects: undefined-variable references, inverted conditionals, mis-assigned function arguments, garbled help text, hardcoded ports, and a small supply-chain hygiene fix. Each issue is small enough to ship as an independent commit on the sprint branch, all changes pass shellcheck/shfmt cleanly, and none introduce new abstractions or library APIs. The sprint deliberately avoids the larger structural cleanups (test infrastructure, namespace audits, Jenkins → GHA) so we can keep cycle time short and merge confidence high.

Selected issues

1. SUR-1820 — Bug: aliases — duplicate kl alias and ks/kss assign container=$1 (pod) by mistake

  • Title: Bug: aliases — duplicate kl alias and ks/kss assign container=$1 (pod) by mistake
  • Description summary: bash/aliases defines alias kl=... twice (lines 7 and 15), the second silently shadowing the first. Worse, ks / kss capture pod=$1, then in the [ -n "$2" ] branch set local container=$1 before shift, so container ends up equal to the pod. ks mypod mycontainer always runs kubectl exec -it mypod -c mypod -- bash, which fails. The command=(...) array is also not declared local, leaking into the caller's environment.
  • Rationale: ks <pod> <container> is part of the day-to-day interactive workflow; the multi-container form is unusable today. The fix is mechanical (use $2, declare local -a cmd) and well-scoped to a few lines.
  • Definition of Done:
    • The duplicate alias kl= line is removed (or converted to a distinct alias such as klf if a clear intent is recovered from git blame).
    • ks and kss correctly use $2 for the container argument.
    • The dispatch array is declared local -a inside both functions.
    • pre-commit run --all-files passes (shellcheck, shfmt, etc.).
    • Manual smoke: sourcing bash/aliases and running type ks / type kss shows the corrected body.
    • Commit message follows conventional-commits and references SUR-1820.
  • Dependencies / ordering: Must land before SUR-1837 because both touch bash/aliases; sequencing them avoids unnecessary merge resolution.

2. SUR-1837 — Bug: aliases — get_latest_btp_branch uses tail (last 10) instead of tail -n 1; curl|bash for helm; eksctl hardcoded amd64

  • Title: Bug: aliases — get_latest_btp_branch uses tail (last 10) instead of tail -n 1; curl|bash for helm
  • Description summary: Three independent defects in bash/aliases: (1) get_latest_btp_branch pipes to bare tail, which defaults to -n 10, so the loop checks out 10 branches sequentially and lands on a non-deterministic one; (2) update_helm does curl … | bash against master with no checksum — supply-chain risk; (3) update_eksctl hardcodes _amd64 in the download URL, producing broken installs on Apple Silicon / arm64.
  • Rationale: Same file as SUR-1820, so we sequence them to share review context. Each sub-fix is small; the helm and arch fixes have direct user-impact for anyone on arm64 or running these helpers in a hostile network.
  • Definition of Done:
    • get_latest_btp_branch uses tail -n 1 (or, equivalently, head -n 1 of a reverse sort) and is documented with a one-line comment explaining the intent.
    • update_helm pins a tagged helm version and downloads the official tarball (or, at minimum, drops | bash in favor of curl -fsSL -o /tmp/helm.tgz + tar xz flow). Document the chosen version in a comment so future bumps are obvious.
    • update_eksctl derives the architecture from uname -m (mapping x86_64→amd64, aarch64|arm64→arm64, with a clear error for unknown values).
    • shellcheck clean for bash/aliases.
    • Conventional-commit message references SUR-1837.
  • Dependencies / ordering: Land after SUR-1820 to keep diffs small and reviewable.

3. SUR-1832 — Bug: plantuml-from-k8s start() references undefined $ns; uses raw kubectl instead of k8s::

  • Title: Bug: plantuml-from-k8s start() references undefined $ns; uses raw kubectl instead of k8s::
  • Description summary: start() in bash/plantuml-from-k8s echoes @startuml "$ns", but $ns is never in scope inside start() — it is a loop variable in callers. The intent (per the rest of the file) is @startuml "$cluster". The same script also calls bare kubectl on lines 91 and 115 instead of k8s::ctl, bypassing the lib's logging/SIMULATE support, and shadows the item function with a loop variable of the same name.
  • Rationale: PlantUML output is currently emitted with no diagram name, so concatenated outputs are indistinguishable. The fix is local to one function and does not alter command-line surface.
  • Definition of Done:
    • start() echoes @startuml "$cluster" and uses local cluster=${1:?} to fail fast on a missing arg.
    • Bare kubectl calls in the file are replaced with k8s::ctl.
    • The loop variable in namespace() is renamed (e.g. for entry in …) so it no longer shadows the item function; alternatively item() adds local item at its top.
    • pre-commit run --all-files passes.
    • Manual smoke: bash/plantuml-from-k8s some-cluster (with SIMULATE=true) prints @startuml some-cluster as the first non-blank line.
    • Conventional-commit message references SUR-1832.
  • Dependencies / ordering: Independent.

4. SUR-1825 — Bug: trust-server references undefined openssl::cmd; CERT_GROUP logic inverted

  • Title: Bug: trust-server references undefined openssl::cmd; CERT_GROUP logic inverted
  • Description summary: bash/trust-server defines ::openssl but then invokes openssl::cmd (never defined), so the script aborts on first cert fetch. CERT_GROUP is initialized to "local", then overwritten to the empty $DOMAIN under an inverted [ -z "$DOMAIN" ] test. The Ubuntu branch also calls deprecated uppercase INFO, and mktemp -d is leaked with no cleanup trap.
  • Rationale: Script does not run today. The fix is essentially a typo (openssl::cmd → ::openssl) plus a one-character condition flip (-z → -n), so review burden is minimal.
  • Definition of Done:
    • openssl::cmd invocation is replaced with ::openssl (or, alternatively, ::openssl is renamed to openssl::cmd to match the namespacing convention from AGENTS.md — pick whichever is consistent with neighbours).
    • CERT_GROUP logic uses [ -n "$DOMAIN" ] and only assigns $DOMAIN when non-empty.
    • Ubuntu branch replaces INFO calls with log::info.
    • A trap 'rm -rf "$TMPDIR"' EXIT INT TERM is added after mktemp -d.
    • Manual smoke: bash/trust-server -h shows help; bash -n bash/trust-server parses cleanly; shellcheck passes.
    • Conventional-commit message references SUR-1825.
  • Dependencies / ordering: Independent.

5. SUR-1829 — Bug: fetch-all-pod-logs writes $pod..out when -c is empty; -c is mandatory yet handled as optional

  • Title: Bug: fetch-all-pod-logs writes "$pod..out" when -c is empty; -c is mandatory yet handled as optional
  • Description summary: bash/fetch-all-pod-logs declares -c mandatory (via -m) but still has an else branch for the empty case, which produces output filenames containing a literal .. (e.g. pod-abc..out) and breaks downstream globbing. The script also lacks a -n NAMESPACE flag and only works in the kubectl current-context default namespace.
  • Rationale: Internal inconsistency — either drop -m or remove the dead branch. The issue description recommends the former (the --all-containers branch suggests it was meant to be optional), so we'll treat -c as optional and use a sensible filename suffix.
  • Definition of Done:
    • options::add for -c drops -m and the description is updated to "container whose logs to dump (defaults to all)".
    • The else branch uses a suffix=${container:-all} so output filenames are $pod.$suffix.out (no double-dots).
    • Optionally (in scope): a new -n NAMESPACE flag piped through to k8s::ctl. If skipped, called out explicitly in the commit body as deferred.
    • Manual smoke: bash/fetch-all-pod-logs -h shows correct help; running with SIMULATE=true against a fake selector produces the expected log lines.
    • shellcheck clean.
    • Conventional-commit message references SUR-1829.
  • Dependencies / ordering: Independent.

6. SUR-1823 — Bug: kind-test-environment — garbled -P description and DOCKER_HOST hardcoded ignoring DIND_PORT

  • Title: Bug: kind-test-environment — garbled -P description and DOCKER_HOST hardcoded ignoring DIND_PORT
  • Description summary: The -P option help text in bash/kind-test-environment contains a botched sed replacement (fo::add_ingress_providerr). More importantly, ::use_dind initially honors $DIND_PORT via DOCKER_PORT=${DIND_PORT:-2375} but the if ::is_dind_running branch hardcodes tcp://localhost:2375, and the else branch unconditionally re-exports DOCKER_PORT=2375 — silently overriding the user's -P choice. There is also a sleep 30 masking startup races.
  • Rationale: Help text and the user-facing -P flag are visibly broken. The fix uses $DOCKER_PORT consistently and (optionally) replaces the sleep with a short readiness poll.
  • Definition of Done:
    • -P description reads "Use the specified port for the DinD daemon" (no garbled substring).
    • Both branches of ::use_dind use tcp://localhost:$DOCKER_PORT and never re-assign DOCKER_PORT=2375.
    • The sleep 30 is replaced by a bounded poll on docker -H tcp://localhost:$DOCKER_PORT info, with a clear timeout (e.g. 60s) and an error exit on timeout. If poll-replacement is deferred, the commit body must say so explicitly.
    • shellcheck and shfmt clean.
    • Conventional-commit message references SUR-1823.
  • Dependencies / ordering: Independent.

Risks + mitigations

  • Risk: Two issues (SUR-1820 and SUR-1837) modify the same file (bash/aliases). Concurrent or out-of-order commits cause merge churn.
    Mitigation: Sequence them on the same sprint branch (1820 first, then 1837). The implementation plan enforces ordering.
  • Risk: There is no test suite in the repo (acknowledged by AGENTS.md and SUR-1850). Verification is limited to bash -n, shellcheck, shfmt, and manual smoke.
    Mitigation: Each Definition of Done lists explicit smoke commands. Where the bug is visible from -h output (SUR-1823 garbled help, SUR-1825 typo), invoke -h post-fix to confirm. For SUR-1832, run with SIMULATE=true so no real cluster is needed.
  • Risk: Replacing sleep 30 with a poll in SUR-1823 may regress on hosts where docker takes longer to come up.
    Mitigation: Make the poll bounded (default 60s timeout) and document the override env var. If unable to test against a real DinD on the developer's machine, leave the sleep in place and explicitly defer that bullet — call it out in the commit body and reopen as a follow-up.
  • Risk: SUR-1837 changes update_helm and update_eksctl behavior, which a user may have memorized.
    Mitigation: Preserve the public function names and observable behavior (update_helm, update_eksctl still install the named tool); only the internal install mechanism changes. Add a one-line comment explaining the version pin so future maintainers don't roll back to curl | bash.
  • Risk: bash/aliases is sourced into interactive shells; a syntax error in the file breaks every new shell of users who source it.
    Mitigation: Run bash -n bash/aliases as part of the verification plan and confirm shellcheck has zero new findings before opening the PR.
  • Risk: pre-commit's no-commit-to-branch hook only allows feature/, fix/, refactor/ branch names. The sprint branch sprint/2026-04-28-sprint-loop-4 does not match.
    Mitigation: Create per-issue feature branches (feature/sur-1820, etc.) for actual commits, and use the sprint name only as an umbrella tracking concept (not a real git branch). The IMPLEMENTATION_PLAN documents both the umbrella name and the per-issue feature-branch names that comply with the hook.
  • Risk: Bypassing k8s::ctl (SUR-1832) currently works; switching to it requires the file to @include k8s (it already does, per the issue). If the include guard is missed the script will fail at runtime.
    Mitigation: Verify @include k8s is present at the top of the file before changing call sites; run bash -n after the edit.
  • Risk: trust-server and kind-test-environment interact with real network/docker resources; verifying the fix end-to-end requires environment access we may not have.
    Mitigation: Use static checks (bash -n, shellcheck) and -h output for surface validation; document any deferred end-to-end verification as a follow-up note in the commit body.

Out of scope

  • The larger anti-pattern, refactor, and test-infrastructure issues (SUR-1840, SUR-1841, SUR-1842, SUR-1850, SUR-1851, SUR-1852) — these are multi-file structural changes that need their own sprint.
  • The Jenkins → GitHub Actions migration (SUR-1853) — material CI work, separate sprint.
  • Documentation cleanups (SUR-1844, SUR-1845, SUR-1846, SUR-1847) — coherent as a docs-only sprint, not bundled here.
  • The daml-export hygiene refactor (SUR-1854) and PagerDuty improvements (SUR-1838, SUR-1821) — deferred.
  • Any new abstractions, library APIs, or namespace-rename refactors. Each fix in this sprint must keep the file's public surface stable.
  • Adding a real test framework (bats-core). Verification is limited to lint + manual smoke for this sprint.

Linear Evidence

  • Linear team verified: Surinis (id ce9ebfde-ff2b-4f54-90f1-c388591ca110).
  • Linear project used: shell-scripts (id a43901a0-b02b-4009-aae1-a6e8903d127d, url https://linear.app/surinis/project/shell-scripts-957861610a69).
  • Query / filter used: mcp__linear__list_issues with project="shell-scripts", team="Surinis", state="Backlog", includeArchived=false, limit=100.
  • Approx count of Backlog issues reviewed: 29.
  • Approx count of manual-labelled Backlog issues skipped: 0 (no issue in the result set carries a manual label; observed labels were Bug, Improvement, documentation, testing, 3 - medium).

Sub-issue Status

All six selected issues were checked for child issues via mcp__linear__list_issues parentId=<key>. None of them have any sub-issues, so the parent-vs-sub-issue dependency rule is automatically satisfied.

Parent Issue Sub-issue Sub-issue Status Eligible?
SUR-1820 (none) n/a Yes
SUR-1837 (none) n/a Yes
SUR-1832 (none) n/a Yes
SUR-1825 (none) n/a Yes
SUR-1829 (none) n/a Yes
SUR-1823 (none) n/a Yes

No parents were skipped because of incomplete sub-issues.

Linear State Transitions

Issue ID Previous State New State
SUR-1820 Backlog Todo
SUR-1837 Backlog Todo
SUR-1832 Backlog Todo
SUR-1825 Backlog Todo
SUR-1829 Backlog Todo
SUR-1823 Backlog Todo

…820)

ks and kss assigned local container=$1 (the pod) instead of $2, so
'ks pod container' executed 'kubectl exec -it pod -c pod -- bash'.
The dispatch array was also unscoped and named 'command', shadowing the
shell builtin. Use local -a cmd and read the container from $2.

Also remove the duplicate 'alias kl=' line; the second definition
silently shadowed the first.
…_btp_branch tail (SUR-1837)

- get_latest_btp_branch piped to bare 'tail' (default -n 10) so it
  checked out 10 branches sequentially; restrict to tail -n 1.
- update_helm replaced 'curl ... | bash' against helm/master with a
  pinned tarball download (currently v3.16.4) to /tmp + extract +
  install. Bump the version manually after release-note review.
- update_eksctl previously hardcoded amd64 in the URL; derive arch
  from uname -m and reject unknown values explicitly so arm64 hosts
  no longer install a broken binary.
…SUR-1832)

start() echoed @startuml "$ns", but $ns is never in scope here -
it's a loop variable in callers. The intent (matching the cluster()
function that calls it) is @startuml "$cluster". Use ${1:?} to
fail fast on a missing arg.

Replace bare 'kubectl describe' / 'kubectl get ns' calls with
k8s::ctl so logging and SIMULATE work consistently with the rest of
the file.

Inside namespace() the loop variable 'item' shadowed the item()
function, so each iteration tried to invoke the loop string instead
of the formatter. Rename to 'entry'.
…p trap (SUR-1825)

- The first call site invoked 'openssl::cmd', a function that is
  never defined; the only openssl wrapper in the file is '::openssl'.
  Use the existing wrapper so cert fetch actually runs.
- CERT_GROUP was guarded by '[ -z "$DOMAIN" ]', which assigned the
  empty DOMAIN whenever the FQDN was bare. Flip to '[ -n "$DOMAIN" ]'
  so the local default is preserved when no domain is parsed.
- Replace deprecated uppercase INFO calls in add-certs-ubuntu with
  log::info to match the rest of the script.
- Install a trap to remove the mktemp -d directory on EXIT/INT/TERM
  so failed runs don't leak working dirs.
…mes (SUR-1829)

The -c option was declared mandatory yet the body had a fully-formed
'else' branch for the empty case, which produced 'pod-abc..out'
filenames (and a misleading log line) and broke downstream globbing.

Drop the -m on -c so the empty case is reachable, and use a
suffix=${container:-all} fallback so output filenames are
'$pod.$suffix.out' with no double dots.

The -n NAMESPACE flag mentioned in the issue is deferred to a
follow-up; this change keeps the diff narrow.
…823)

The -P option help text contained a botched sed substitution
('fo::add_ingress_providerr'); restore the intended description.

::use_dind defined DOCKER_PORT from $DIND_PORT but the
::is_dind_running branch hardcoded tcp://localhost:2375 and the else
branch unconditionally re-exported DOCKER_PORT=2375, silently
overriding the user's -P. Use $DOCKER_PORT in both branches and
quote the -p mapping.

Replace 'sleep 30' with a bounded poll (DIND_READY_TIMEOUT, default
60s) on 'docker -H tcp://localhost:$DOCKER_PORT info' so startup
is gated on actual readiness instead of a fixed wait.
@scealiontach
scealiontach marked this pull request as ready for review April 28, 2026 18:50
@scealiontach
scealiontach merged commit b249a23 into main Apr 28, 2026
1 check passed
@scealiontach
scealiontach deleted the sprint/2026-04-28-sprint-loop-4 branch April 28, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant