Skip to content

fix(recipes): probe the escalation tool before python-dev uses it - #92

Merged
NovusEdge merged 2 commits into
mainfrom
fix/recipe-escalation-probe
Sep 6, 2026
Merged

fix(recipes): probe the escalation tool before python-dev uses it#92
NovusEdge merged 2 commits into
mainfrom
fix/recipe-escalation-probe

Conversation

@NovusEdge

@NovusEdge NovusEdge commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Two defects stopped stoat up on Alpine, both in the python-dev recipe's
as_user helper.

sudo is present and refuses everything. Alpine 3.24 ships /etc/sudoers
with no rule for root:

# See sudoers(5) for more information on "#include" directives:

# Added by cloud-init v. 26.1 on Sun, 06 Sep 2026 11:24:24 +0000
#includedir /etc/sudoers.d

sudo 1.9.17p2 is installed, so command -v sudo succeeded and as_user chose
it. Every call then failed with root is not in the sudoers file. as_user
now runs each candidate once and keeps the first that works.

busybox su eats options from the trailing arguments. Alpine's su is
/bin/bbsuid, which recognises options anywhere on its command line. Probed in
the guest:

$ su -s /bin/sh stoat -c 'echo "ARGS:[$*]"' stoat mkdir -p /tmp/probe-dir
ARGS:[mkdir /tmp/probe-dir]

The -p became su's own preserve-environment flag, so as_user mkdir -p /home/stoat ran without -p and failed on the existing directory. su_user
now shell-quotes the argument list into -c and passes nothing positional.

Either failure ends cloud-init in error, which fails the readiness wait added
by #86:

FAILED: cloud-init readiness: cloud-init readiness command exited with status 1

The four python-dev installers carry the same helper and all four change.

The su fake in the test harness matched -c against its -* case and kept
trailing arguments, so it modelled neither failure and the fallback branch
could never have passed a test. It now parses -c anywhere, drops dash
arguments the way busybox does, and passes nothing positional.

Live evidence

The five-guest recipe gate on this commit, one attempt per row:

Guest start verify stop
Alpine passed passed passed
Ubuntu 24.04 passed passed passed
Debian 13 passed passed passed
Fedora passed passed passed
Arch passed passed passed

Retained under common-recipes/live/c4. Earlier rows stay where they are: c2
failed at alpine up on the sudo defect, c3 failed at alpine up on the
busybox su defect.

The gate itself also required cloud-init status to exit 0. cloud-init exits 2
for a recoverable warning, and Alpine's image has no
write-ssh-key-fingerprints helper, so keys_to_console always warns. The
gate now accepts exit 2 when the status is done with no hard errors, which is
the contract internal/sshx already implements.

Alpine ships a sudoers file that grants root nothing. sudo is on PATH and
refuses every command, so as_user picked it, the runcmd failed, and
cloud-init ended in error. The readiness wait then failed stoat up.

as_user now runs each candidate once and keeps the first that works.

The su fake in the test harness matched -c against its -* case, so the
fallback branch could never pass. The fake now parses -c first and forwards
the remaining arguments.

Signed-off-by: NovusEdge <novusedge0@gmail.com>
@NovusEdge NovusEdge added the bug Something isn't working label Sep 6, 2026
@NovusEdge NovusEdge self-assigned this Sep 6, 2026
@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 45 seconds.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: f5dd63c3-84a4-46fa-a7c7-a1e349118a28

📥 Commits

Reviewing files that changed from the base of the PR and between 93f29ed and e27563f.

📒 Files selected for processing (5)
  • internal/recipes/bundled/python-dev/install-alpine.sh
  • internal/recipes/bundled/python-dev/install-arch.sh
  • internal/recipes/bundled/python-dev/install-debian.sh
  • internal/recipes/bundled/python-dev/install-rpm.sh
  • internal/recipes/samples_test.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…ments

busybox su recognises options anywhere on its command line. The -p in
"as_user mkdir -p /home/stoat" became su's own preserve-environment flag,
so mkdir ran without it and failed on an existing directory. The runcmd
failed and cloud-init ended in error on Alpine.

su_user now shell-quotes the argument list into -c and passes nothing
positional.

The su fake in the test harness kept trailing arguments, which busybox does
not. It now drops dash arguments anywhere and passes no positional
arguments.

Signed-off-by: NovusEdge <novusedge0@gmail.com>
@NovusEdge
NovusEdge merged commit 4f67ca3 into main Sep 6, 2026
6 of 7 checks passed
@NovusEdge
NovusEdge deleted the fix/recipe-escalation-probe branch September 6, 2026 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant