Skip to content

Commit

Permalink
Add support for UTF-16 encoded kubeconfig files (#1654)
Browse files Browse the repository at this point in the history
* support for utf16 files

Signed-off-by: goenning <me@goenning.net>

* add test cases for utf16

Signed-off-by: goenning <me@goenning.net>

---------

Signed-off-by: goenning <me@goenning.net>
  • Loading branch information
goenning authored Dec 11, 2024
1 parent 60d3ebc commit 9265aa2
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 3 deletions.
50 changes: 47 additions & 3 deletions kube-client/src/config/file_config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{
collections::HashMap,
fs,
fs, io,
path::{Path, PathBuf},
};

Expand Down Expand Up @@ -351,8 +351,8 @@ const KUBECONFIG: &str = "KUBECONFIG";
impl Kubeconfig {
/// Read a Config from an arbitrary location
pub fn read_from<P: AsRef<Path>>(path: P) -> Result<Kubeconfig, KubeconfigError> {
let data = fs::read_to_string(&path)
.map_err(|source| KubeconfigError::ReadConfig(source, path.as_ref().into()))?;
let data =
read_path(&path).map_err(|source| KubeconfigError::ReadConfig(source, path.as_ref().into()))?;

// Remap all files we read to absolute paths.
let mut merged_docs = None;
Expand Down Expand Up @@ -497,6 +497,33 @@ where
});
}

fn read_path<P: AsRef<Path>>(path: P) -> io::Result<String> {
let bytes = fs::read(&path)?;
match bytes.as_slice() {
[0xFF, 0xFE, ..] => {
let utf16_data: Vec<u16> = bytes[2..]
.chunks(2)
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
.collect();
String::from_utf16(&utf16_data)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-16 LE"))
}
[0xFE, 0xFF, ..] => {
let utf16_data: Vec<u16> = bytes[2..]
.chunks(2)
.map(|chunk| u16::from_be_bytes([chunk[0], chunk[1]]))
.collect();
String::from_utf16(&utf16_data)
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-16 BE"))
}
[0xEF, 0xBB, 0xBF, ..] => String::from_utf8(bytes[3..].to_vec())
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-8 BOM")),
_ => {
String::from_utf8(bytes).map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid UTF-8"))
}
}
}

fn to_absolute(dir: &Path, file: &str) -> Option<String> {
let path = Path::new(&file);
if path.is_relative() {
Expand Down Expand Up @@ -969,4 +996,21 @@ users:
json!({"audience": "foo", "other": "bar"})
);
}

#[tokio::test]
async fn parse_kubeconfig_encodings() {
let files = vec![
"kubeconfig_utf8.yaml",
"kubeconfig_utf16le.yaml",
"kubeconfig_utf16be.yaml",
];

for file_name in files {
let path = PathBuf::from(format!("{}/src/config/test_data/{}", env!("CARGO_MANIFEST_DIR"), file_name));
let cfg = Kubeconfig::read_from(path).unwrap();
assert_eq!(cfg.clusters[0].name, "k3d-promstack");
assert_eq!(cfg.contexts[0].name, "k3d-promstack");
assert_eq!(cfg.auth_infos[0].name, "admin@k3d-k3s-default");
}
}
}
Binary file not shown.
Binary file not shown.
19 changes: 19 additions & 0 deletions kube-client/src/config/test_data/kubeconfig_utf8.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: aGVsbG8K
server: https://0.0.0.0:6443
name: k3d-promstack
contexts:
- context:
cluster: k3d-promstack
user: admin@k3d-promstack
name: k3d-promstack
users:
- name: admin@k3d-k3s-default
user:
client-certificate-data: aGVsbG8K
client-key-data: aGVsbG8K
current-context: k3d-promstack
kind: Config
preferences: {}

0 comments on commit 9265aa2

Please sign in to comment.