Skip to content

Commit 0a1ef32

Browse files
authored
bsc#1259485: handle nil user passwords when importing from AutoYaST (master) (#3272)
Bring #3266 fix to `master`.
2 parents 078af95 + 57f29f0 commit 0a1ef32

File tree

14 files changed

+129
-44
lines changed

14 files changed

+129
-44
lines changed

rust/agama-lib/src/http/base_http_client.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,25 @@ pub enum BaseHTTPClientError {
3434
InvalidURL(#[from] url::ParseError),
3535
#[error(transparent)]
3636
InvalidJSON(#[from] serde_json::Error),
37-
#[error("Backend call failed with status {0} and text '{1}'")]
37+
#[error("Backend responded with code {} and the following message:\n\n{}", .0, format_backend_error(.1))]
3838
BackendError(u16, String),
3939
}
4040

41+
fn format_backend_error(error: &String) -> String {
42+
let message: Result<serde_json::Value, _> = serde_json::from_str(error);
43+
44+
match message {
45+
Ok(message) => {
46+
if let Some(error) = message.get("error") {
47+
error.to_string().replace("\\n", "\n")
48+
} else {
49+
format!("{:?}", error)
50+
}
51+
}
52+
Err(_) => format!("{:?}", error),
53+
}
54+
}
55+
4156
/// Base that all HTTP clients should use.
4257
///
4358
/// It provides several features including automatic base URL switching,

rust/agama-lib/src/profile.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,35 +37,49 @@ pub use http_client::ProfileHTTPClient;
3737
pub const DEFAULT_SCHEMA_DIR: &str = "/usr/share/agama/schema";
3838
pub const DEFAULT_JSONNET_DIR: &str = "/usr/share/agama/jsonnet";
3939

40+
#[derive(thiserror::Error, Debug)]
41+
pub enum AutoyastError {
42+
#[error("I/O error: {0}")]
43+
IO(#[from] std::io::Error),
44+
#[error("Failed to run the agama-autoyast script: {0}")]
45+
Execute(#[source] std::io::Error),
46+
#[error("Failed to convert the AutoYaST profile: {0}")]
47+
Evaluation(String),
48+
#[error("Unsupported AutoYaST format at {0}")]
49+
UnsupportedFormat(Url),
50+
}
51+
4052
/// Downloads and converts autoyast profile.
4153
pub struct AutoyastProfileImporter {
4254
pub content: String,
4355
}
4456

4557
impl AutoyastProfileImporter {
46-
pub async fn read(url: &Url) -> anyhow::Result<Self> {
58+
pub async fn read(url: &Url) -> Result<Self, AutoyastError> {
4759
let path = url.path();
4860
if !path.ends_with(".xml") && !path.ends_with(".erb") && !path.ends_with('/') {
49-
let msg = format!("Unsupported AutoYaST format at {}", url);
50-
return Err(anyhow::Error::msg(msg));
61+
return Err(AutoyastError::UnsupportedFormat(url.clone()));
5162
}
5263

5364
const TMP_DIR_PREFIX: &str = "autoyast";
5465
const AUTOINST_JSON: &str = "autoinst.json";
5566

5667
let tmp_dir = TempDir::with_prefix(TMP_DIR_PREFIX)?;
57-
tokio::process::Command::new("agama-autoyast")
68+
let result = tokio::process::Command::new("agama-autoyast")
5869
.env("YAST_SKIP_PROFILE_FETCH_ERROR", "1")
5970
.args([url.as_str(), &tmp_dir.path().to_string_lossy()])
60-
.status()
71+
.output()
6172
.await
62-
.context("Failed to run agama-autoyast")?;
73+
.map_err(AutoyastError::Execute)?;
74+
75+
if !result.status.success() {
76+
return Err(AutoyastError::Evaluation(
77+
String::from_utf8_lossy(&result.stderr).to_string(),
78+
));
79+
}
6380

6481
let autoinst_json = tmp_dir.path().join(AUTOINST_JSON);
65-
let content = fs::read_to_string(&autoinst_json).context(format!(
66-
"agama-autoyast did not produce {:?}",
67-
autoinst_json
68-
))?;
82+
let content = fs::read_to_string(&autoinst_json)?;
6983
Ok(Self { content })
7084
}
7185
}

rust/agama-lib/src/profile/http_client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
// To contact SUSE LLC about this file by physical or electronic mail, you may
1919
// find current contact information at www.suse.com.
2020

21-
use crate::http::BaseHTTPClient;
21+
use crate::http::{BaseHTTPClient, BaseHTTPClientError};
2222
use crate::profile::ValidationOutcome;
2323
use fluent_uri::Uri;
2424
use serde::Serialize;
@@ -51,7 +51,7 @@ impl ProfileHTTPClient {
5151
/// Note that this client does not act on this *url*, it passes it as a parameter
5252
/// to our web backend.
5353
/// Return well-formed Agama JSON on success.
54-
pub async fn from_autoyast(&self, url: &Uri<String>) -> anyhow::Result<String> {
54+
pub async fn from_autoyast(&self, url: &Uri<String>) -> Result<String, BaseHTTPClientError> {
5555
let mut map = HashMap::new();
5656

5757
map.insert(String::from("url"), url.to_string());

rust/agama-manager/src/service.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,18 @@ use agama_utils::{
2929
self, event,
3030
manager::{self, LicenseContent},
3131
status::Stage,
32-
Action, Config, Event, FinishMethod, Issue, IssueMap, Proposal, Scope, Status, SystemInfo,
32+
Action, Config, Event, Issue, IssueMap, Proposal, Scope, Status, SystemInfo,
3333
},
3434
arch::Arch,
35-
issue,
36-
kernel_cmdline::KernelCmdline,
37-
licenses,
35+
issue, licenses,
3836
products::{self, ProductSpec},
3937
progress, question,
4038
};
4139
use async_trait::async_trait;
4240
use merge::Merge;
4341
use network::NetworkSystemClient;
4442
use serde_json::Value;
45-
use std::{collections::HashMap, str::FromStr, sync::Arc};
43+
use std::{collections::HashMap, sync::Arc};
4644
use tokio::sync::{broadcast, RwLock};
4745

4846
#[derive(Debug, thiserror::Error)]

rust/agama-manager/src/tasks/runner.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
// To contact SUSE LLC about this file by physical or electronic mail, you may
1919
// find current contact information at www.suse.com.
2020

21-
use std::str::FromStr;
22-
2321
use crate::{
2422
actions::{FinishAction, InstallAction, SetConfigAction},
2523
bootloader, files, hostname, iscsi, l10n, proxy, s390, security, service, software, storage,
@@ -30,9 +28,7 @@ use agama_network::NetworkSystemClient;
3028
use agama_utils::{
3129
actor::{Actor, Handler, MessageHandler},
3230
api::{FinishMethod, Scope},
33-
issue,
34-
kernel_cmdline::KernelCmdline,
35-
progress, question,
31+
issue, progress, question,
3632
};
3733
use async_trait::async_trait;
3834

rust/agama-server/src/profile/web.rs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// To contact SUSE LLC about this file by physical or electronic mail, you may
1919
// find current contact information at www.suse.com.
2020

21+
use agama_lib::profile::AutoyastError;
2122
use agama_transfer::Transfer;
2223
use anyhow::Context;
2324

@@ -50,6 +51,19 @@ impl std::fmt::Display for ProfileServiceError {
5051
}
5152
}
5253

54+
impl From<AutoyastError> for ProfileServiceError {
55+
fn from(e: AutoyastError) -> Self {
56+
let http_status = match e {
57+
AutoyastError::Execute(..) => StatusCode::INTERNAL_SERVER_ERROR,
58+
_ => StatusCode::BAD_REQUEST,
59+
};
60+
Self {
61+
source: e.into(),
62+
http_status,
63+
}
64+
}
65+
}
66+
5367
// Make a 400 response
5468
// ```
5569
// let r: Result<T, anyhow::Error> = foo();
@@ -208,15 +222,6 @@ async fn autoyast(body: String) -> Result<String, ProfileServiceError> {
208222
}
209223

210224
let url = Url::parse(profile.url.as_ref().unwrap()).map_err(anyhow::Error::new)?;
211-
let importer_res = AutoyastProfileImporter::read(&url).await;
212-
match importer_res {
213-
Ok(importer) => Ok(importer.content),
214-
Err(error) => {
215-
// anyhow can be only displayed, not so nice
216-
if format!("{}", error).contains("Failed to run") {
217-
return Err(make_internal(error));
218-
}
219-
Err(error.into())
220-
}
221-
}
225+
let importer = AutoyastProfileImporter::read(&url).await?;
226+
Ok(importer.content)
222227
}

rust/package/agama.changes

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
-------------------------------------------------------------------
2+
Thu Mar 12 13:20:48 UTC 2026 - Imobach Gonzalez Sosa <igonzalezsosa@suse.com>
3+
4+
- Add error reporting when working with AutoYaST profiles (related
5+
to bsc#1259434).
6+
17
-------------------------------------------------------------------
28
Thu Mar 12 13:05:51 UTC 2026 - Ladislav Slezák <lslezak@suse.com>
39

service/bin/agama-autoyast

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@ begin
5151
warn "Did not convert the profile (canceled by the user)."
5252
exit 2
5353
end
54-
rescue Agama::Commands::CouldNotFetchProfile
55-
warn "Could not fetch the AutoYaST profile."
54+
rescue Agama::Commands::CouldNotFetchProfile => e
55+
warn "Could not fetch the AutoYaST profile:\n\n"
56+
warn e.full_message
5657
exit 3
57-
rescue Agama::Commands::CouldNotWriteAgamaConfig
58-
warn "Could not write the Agama configuration."
58+
rescue Agama::Commands::CouldNotWriteAgamaConfig => e
59+
warn "Could not write the Agama configuration:\n\n"
60+
warn e.full_message
5961
exit 4
6062
end

service/lib/agama/autoyast/profile_reporter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def report(elements)
6262
)
6363

6464
questions_client.ask(question) do |answer|
65-
answer == :continue
65+
answer.action == :continue
6666
end
6767
end
6868

service/lib/agama/autoyast/root_reader.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,19 @@ def read
3838
root_user = config.users.find { |u| u.name == "root" }
3939
return {} unless root_user
4040

41-
hsh = { "password" => root_user.password.value.to_s }
42-
hsh["hashedPassword"] = true if root_user.password.value.encrypted?
41+
hsh = {}
42+
password = root_user.password
43+
44+
if password
45+
hsh["password"] = password.value.to_s
46+
hsh["hashedPassword"] = true if password.value.encrypted?
47+
end
4348

4449
public_key = root_user.authorized_keys.first
4550
hsh["sshPublicKey"] = public_key if public_key
51+
52+
return {} if hsh.empty?
53+
4654
{ "root" => hsh }
4755
end
4856

0 commit comments

Comments
 (0)