Skip to content

Commit

Permalink
Fix #1540, due to the URL-nature a get with an empty name is processe…
Browse files Browse the repository at this point in the history
…d as a list call.

kube then fails to parse the result from the server.
Other HTTP METHODS, like "DELETE" are also affected and e.g. cause the deletion of ALL objects. See the issue for more info.

Signed-off-by: Marcel Märtens <marcel.cochem@googlemail.com>
  • Loading branch information
xMAC94x committed Jul 20, 2024
1 parent e57b060 commit dd45e6f
Showing 1 changed file with 26 additions and 1 deletion.
27 changes: 26 additions & 1 deletion kube-core/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ impl Request {

/// Get a single instance
pub fn get(&self, name: &str, gp: &GetParams) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
let urlstr = if let Some(rv) = &gp.resource_version {
let target = format!("{}/{}?", self.url_path, name);
form_urlencoded::Serializer::new(target)
Expand All @@ -106,6 +107,7 @@ impl Request {

/// Delete an instance of a resource
pub fn delete(&self, name: &str, dp: &DeleteParams) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
let target = format!("{}/{}?", self.url_path, name);
let mut qp = form_urlencoded::Serializer::new(target);
let urlstr = qp.finish();
Expand Down Expand Up @@ -149,6 +151,7 @@ impl Request {
pp: &PatchParams,
patch: &Patch<P>,
) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
pp.validate(patch)?;
let target = format!("{}/{}?", self.url_path, name);
let mut qp = form_urlencoded::Serializer::new(target);
Expand All @@ -171,6 +174,7 @@ impl Request {
pp: &PostParams,
data: Vec<u8>,
) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
let target = format!("{}/{}?", self.url_path, name);
let mut qp = form_urlencoded::Serializer::new(target);
pp.populate_qp(&mut qp);
Expand All @@ -188,6 +192,7 @@ impl Request {
subresource_name: &str,
name: &str,
) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
let target = format!("{}/{}/{}", self.url_path, name, subresource_name);
let mut qp = form_urlencoded::Serializer::new(target);
let urlstr = qp.finish();
Expand All @@ -203,6 +208,7 @@ impl Request {
pp: &PostParams,
data: Vec<u8>,
) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
let target = format!("{}/{}/{}?", self.url_path, name, subresource_name);
let mut qp = form_urlencoded::Serializer::new(target);
pp.populate_qp(&mut qp);
Expand All @@ -219,6 +225,7 @@ impl Request {
pp: &PatchParams,
patch: &Patch<P>,
) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
pp.validate(patch)?;
let target = format!("{}/{}/{}?", self.url_path, name, subresource_name);
let mut qp = form_urlencoded::Serializer::new(target);
Expand All @@ -240,6 +247,7 @@ impl Request {
pp: &PostParams,
data: Vec<u8>,
) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
let target = format!("{}/{}/{}?", self.url_path, name, subresource_name);
let mut qp = form_urlencoded::Serializer::new(target);
pp.populate_qp(&mut qp);
Expand All @@ -256,6 +264,7 @@ impl Request {
impl Request {
/// Get a single metadata instance for a named resource
pub fn get_metadata(&self, name: &str, gp: &GetParams) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
let urlstr = if let Some(rv) = &gp.resource_version {
let target = format!("{}/{}?", self.url_path, name);
form_urlencoded::Serializer::new(target)
Expand Down Expand Up @@ -310,6 +319,7 @@ impl Request {
pp: &PatchParams,
patch: &Patch<P>,
) -> Result<http::Request<Vec<u8>>, Error> {
validate_name(name)?;
pp.validate(patch)?;
let target = format!("{}/{}?", self.url_path, name);
let mut qp = form_urlencoded::Serializer::new(target);
Expand All @@ -324,14 +334,22 @@ impl Request {
}
}

/// Names must not be empty as otherwise API server would interpret a `get` as `list`, or a `delete` as `delete_collection`
fn validate_name(name: &str) -> Result<(), Error> {
if name.is_empty() {
return Err(Error::Validation("A non-empty name is required".into()));
}
Ok(())
}

/// Extensive tests for Request of k8s_openapi::Resource structs
///
/// Cheap sanity check to ensure type maps work as expected
#[cfg(test)]
mod test {
use crate::{
params::{GetParams, PostParams, VersionMatch, WatchParams},
request::Request,
request::{Error, Request},
resource::Resource,
};
use http::header;
Expand Down Expand Up @@ -490,6 +508,13 @@ mod test {
);
}

#[test]
fn get_empty_name() {
let url = appsv1::Deployment::url_path(&(), Some("ns"));
let req = Request::new(url).get("", &GetParams::any());
assert!(matches!(req, Err(Error::Validation(_))));
}

#[test]
fn list_path() {
let url = appsv1::Deployment::url_path(&(), Some("ns"));
Expand Down

0 comments on commit dd45e6f

Please sign in to comment.