Skip to content

Fix Encoding::CompatibilityError in hostnamectl plugin - #1964

Merged
tpowell-progress merged 1 commit into
chef:mainfrom
slac-chef-ci-cd:fix-hostnamectl-encoding
Aug 11, 2026
Merged

Fix Encoding::CompatibilityError in hostnamectl plugin#1964
tpowell-progress merged 1 commit into
chef:mainfrom
slac-chef-ci-cd:fix-hostnamectl-encoding

Conversation

@slac-chef-ci-cd

@slac-chef-ci-cd slac-chef-ci-cd commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

The Hostnamectl plugin crashes with Encoding::CompatibilityError whenever
hostnamectl emits a non-ASCII character, silently truncating the attribute
mash to whatever keys preceded the offending line.

The plugin already had eight test cases covering exactly this input — one per
chassis icon, added alongside #1909. All eight pass against the broken code.
The heredoc fixtures are UTF-8-tagged, while Mixlib::ShellOut returns stdout as
ASCII-8BIT, so the specs never exercised the encoding path they were written
to cover.

Verified on Ubuntu 24.04.4, ohai 18.2.20 (Chef Infra Client 18.11.11):

$ ruby -e '
require "mixlib/shellout"
s = Mixlib::ShellOut.new("hostnamectl"); s.run_command
warn "encoding: #{s.stdout.encoding}"
s.stdout.split("\n").each { |l| _k, v = l.split(": ", 2); v.gsub(/[^\p{ASCII}]/u, "") }
'
encoding: ASCII-8BIT
-e:5:in `gsub': incompatible encoding regexp match (UTF-8 regexp with ASCII-8BIT string) (Encoding::CompatibilityError)

A UTF-8 regexp is only compatible with an ASCII-8BIT string while that string
holds pure 7-bit bytes. The first line containing a multibyte character — for
example Chassis: laptop 💻 — raises, aborting the parse loop. Ohai::Runner#run_plugin
re-raises Ohai::Exceptions::Error but catches bare Exception and logs at trace
level, so the plugin's partial mash is retained and the failure surfaces only as
missing attributes:

$ ohai hostnamectl        # 18.2.20
{
  "static_hostname": "myhostname",
  "icon_name": "computer-laptop"
}

$ ohai hostnamectl        # 18.2.8, and with this patch applied
{
  "static_hostname": "myhostname",
  "icon_name": "computer-laptop",
  "chassis": "laptop",
  "machine_id": "...",
  "boot_id": "...",
  "operating_system": "Ubuntu 24.04.4 LTS",
  "kernel": "Linux 7.0.0-28-generic",
  "architecture": "x86-64",
  "hardware_vendor": "System76",
  "hardware_model": "Darter Pro",
  "firmware_version": "...",
  "firmware_date": "...",
  "firmware_age": "..."
}

This is silent in a chef-client run — cookbooks reading node['hostnamectl']['chassis']
(laptop detection, disk-encryption enforcement, and similar) misbehave with no error
surfaced.

Changes

Plugin — coerce the encoding before the icon-stripping regexp runs. dup because
force_encoding mutates the Mixlib::ShellOut object's own @stdout; scrub guards
against genuinely invalid byte sequences under a non-UTF-8 locale, and its U+FFFD
replacements are removed by the existing gsub on the next line.

-      shell_out(hostnamectl_path).stdout.split("\n").each do |line|
+      shell_out(hostnamectl_path).stdout.dup.force_encoding("UTF-8").scrub.split("\n").each do |line|

Spec — make the fixtures binary so they reflect what Mixlib::ShellOut actually
returns. This converts the eight existing emoji cases into genuine regression tests.

-    ...and_return(mock_shell_out(0, hostnamectl_out, ""))
+    ...and_return(mock_shell_out(0, hostnamectl_out.b, ""))

With the spec change alone (plugin reverted), the eight emoji cases fail.

With both changes, the full suite is green and rake style reports no offenses.

Backport

18-stable carries the same code and ships in Chef Infra Client 18.11.11, so this
needs a cherry-pick there as well.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I have read the CONTRIBUTING document
  • I have added tests to cover my changes
  • All new and existing tests passed

@slac-chef-ci-cd
slac-chef-ci-cd requested review from a team and jaymzh as code owners August 6, 2026 03:45
@karlamrhein

Copy link
Copy Markdown
Contributor

Hi, this was submitted by me.

The broken ohai produces a truncated 'ohai hostnamectl' output:

ohai hostnamectl
{
"static_hostname": "myhost",
"icon_name": "computer-laptop"
}

the attached fix corrects that, and removes the icon as intended:

{
"static_hostname": "myhost",
"icon_name": "computer-laptop",
"chassis": "laptop",
"machine_id": "20fbfc5050f7[...]",
"boot_id": "747b426be2984d2b[...]",
"operating_system": "Ubuntu 24.04.4 LTS",
"kernel": "Linux 7.0.0-28-generic",
"architecture": "x86-64",
"hardware_vendor": "Dell Inc.",
"hardware_model": "Dell Pro Max 18 Plus MB18250",
"firmware_version": "2.6.1",
"firmware_date": "Mon 2026-03-16",
"firmware_age": "4month 2d"
}

Karl Amrhein

Mixlib::ShellOut returns stdout as ASCII-8BIT, so matching the UTF-8
icon-stripping regexp against it raises as soon as hostnamectl emits a
multibyte character, truncating the attribute mash.

Coerce the encoding before the gsub, and make the existing emoji spec
fixtures binary so they exercise the path they were written to cover.

Signed-off-by: Karl Amrhein <karlamrhein@gmail.com>
@tpowell-progress
tpowell-progress force-pushed the fix-hostnamectl-encoding branch from 00a3b86 to a254f44 Compare August 11, 2026 20:51
@tpowell-progress
tpowell-progress merged commit 54b17dd into chef:main Aug 11, 2026
64 of 66 checks passed
tpowell-progress added a commit that referenced this pull request Aug 12, 2026
Mixlib::ShellOut returns stdout as ASCII-8BIT, so matching the UTF-8
icon-stripping regexp against it raises as soon as hostnamectl emits a
multibyte character, truncating the attribute mash.

Coerce the encoding before the gsub, and make the existing emoji spec
fixtures binary so they exercise the path they were written to cover.



(cherry picked from commit 54b17dd)

Signed-off-by: Karl Amrhein <karlamrhein@gmail.com>
Signed-off-by: Thomas Powell <104777878+tpowell-progress@users.noreply.github.com>
Co-authored-by: slac-chef-ci-cd <karlamrhein+cicd@gmail.com>
Co-authored-by: Karl Amrhein <karlamrhein@gmail.com>
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.

3 participants