Skip to content

Conversation

@frhuelsz
Copy link
Contributor

🔍 Description

  • Remove deny_unknown_fields for forwards compatibility
  • Introduce an enum of known cosi versions to ensure we keep track of what is expected of each
  • Parse spec enums as rust enums.

Copilot AI review requested due to automatic review settings December 11, 2025 01:23
@frhuelsz frhuelsz requested a review from a team as a code owner December 11, 2025 01:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves COSI metadata parsing by enhancing type safety and forward compatibility. The changes introduce strongly-typed enums for bootloader types and versions, replace string comparisons with enum matching, and remove deny_unknown_fields to allow graceful handling of future metadata fields.

Key changes:

  • Introduced KnownMetadataVersion enum to track supported COSI specification versions
  • Replaced string-based bootloader type checks with BootloaderType and SystemdBootLoaderType enums
  • Removed deny_unknown_fields from all structs for forward compatibility

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

// Valid combination
_ => {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the wildcard for all non-error conditions, this whole statement is only trying to match on error conditions


// Unknown bootloader type is invalid
(BootloaderType::Unknown(bootloader_type), _) => {
bail!("Unsupported bootloader type: {}", bootloader_type);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should only bail if the version is equal to 1.1. Otherwise we can't add new bootloader types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more about this version of trident not recognizing this bootloader type. If we see something we don't recognize then we have no idea what to do with it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd feel better about running this once we know the specific operation we're doing with the COSI. Perhaps directly in the validate() method of the subsystem that is using the bootloader field?

For something like trident stream-image it might not matter and would present a forward compatibility concern

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair. This is the existing logic that was implemented before, but happy to revise for forward compat.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some extra future proofing, basically we will always validate the metadata as long as it's technically valid, regardless of the support offered by the version of Trident.

Copilot AI review requested due to automatic review settings December 11, 2025 22:45
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

#[serde(untagged)]
Unknown(String),
}

Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BootloaderType enum should derive Display like SystemdBootloaderType does (line 367) for consistency and to enable more ergonomic error messages. Currently, line 148 uses the inner String value from the Unknown variant, but with Display, the enum could be used directly in format strings for all variants.

Suggested change
use std::fmt;
impl fmt::Display for BootloaderType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BootloaderType::SystemdBoot => write!(f, "systemd-boot"),
BootloaderType::Grub => write!(f, "grub"),
BootloaderType::Unknown(s) => write!(f, "{s}"),
}
}
}

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings December 12, 2025 01:15
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

match systemd_boot.entries.as_slice() {
// No entries is invalid
[] => bail!("Bootloader type 'systemd-boot' must not be empty"),

Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's trailing whitespace on line 129 after the pattern match. Consider removing it for code cleanliness.

Suggested change

Copilot uses AI. Check for mistakes.
Comment on lines +210 to +223
impl PartialOrd for MetadataVersion {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for MetadataVersion {
fn cmp(&self, other: &Self) -> Ordering {
match self.major.cmp(&other.major) {
Ordering::Equal => self.minor.cmp(&other.minor),
ord => ord,
}
}
}
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new Ord and PartialOrd implementations for MetadataVersion lack test coverage. Consider adding tests to verify the comparison behavior works correctly, especially for edge cases like comparing different major versions and different minor versions.

Copilot uses AI. Check for mistakes.
Comment on lines +332 to +341
pub(crate) enum BootloaderType {
#[serde(rename = "systemd-boot")]
SystemdBoot,

#[serde(rename = "grub")]
Grub,

#[serde(untagged)]
Unknown(String),
}
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new BootloaderType enum and its deserialization behavior (especially the Unknown variant) lacks test coverage. Consider adding tests to verify that known bootloader types deserialize correctly and unknown types are properly captured in the Unknown variant.

Copilot uses AI. Check for mistakes.
Comment on lines +368 to +384
pub(crate) enum SystemdBootloaderType {
#[serde(rename = "uki-standalone")]
#[strum(to_string = "uki-standalone")]
UkiStandalone,

#[serde(rename = "uki-config")]
#[strum(to_string = "uki-config")]
UkiConfig,

#[serde(rename = "config")]
#[strum(to_string = "config")]
Config,

#[serde(untagged)]
#[strum(to_string = "{0}")]
Unknown(String),
}
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new SystemdBootloaderType enum and its deserialization behavior (especially the Unknown variant and the Display trait) lacks test coverage. Consider adding tests to verify that known boot types deserialize correctly, unknown types are captured properly, and the Display trait produces the expected string representations.

Copilot uses AI. Check for mistakes.
Comment on lines 107 to 154
// Validate bootloader on COSI version >= 1.1
if self.version >= KnownMetadataVersion::V1_1.as_version() {
let Some(bootloader) = self.bootloader.as_ref() else {
bail!("Bootloader metadata is required for COSI version >= 1.1, but not provided");
};

match (&bootloader.bootloader_type, &bootloader.systemd_boot) {
// Grub with systemd-boot entries is invalid
(BootloaderType::Grub, Some(_)) => {
bail!("Bootloader type 'grub' cannot have systemd-boot entries");
}

// Systemd-boot without entries is invalid
(BootloaderType::SystemdBoot, None) => {
bail!("Bootloader type 'systemd-boot' requires systemd-boot entries");
}

// Systemd-boot with not exactly 1 UKI entry is invalid for this version of Trident
(BootloaderType::SystemdBoot, Some(systemd_boot)) => {
match systemd_boot.entries.as_slice() {
// No entries is invalid
[] => bail!("Bootloader type 'systemd-boot' must not be empty"),

// More than one entry, is not allowed in this version of Trident.
[_, _, ..] => {
bail!("Multiple bootloader entries are not supported for bootloader type 'systemd-boot' in this version of Trident");
}

// One entry of type other than uki-standalone is invalid
[entry] if !entry.boot_type.eq(&SystemdBootloaderType::UkiStandalone) => bail!(
"Bootloader type 'systemd-boot' only supports 'uki-standalone' entry type, found: {}",
entry.boot_type
),

// Exactly one uki-standalone entry is valid
[ _ ] => {}
}
_ => bail!("Unsupported bootloader type: {}", bootloader_type),
}
}
None => {
if self.version.major > 1 || (self.version.major == 1 && self.version.minor > 0) {
bail!("Bootloader is required for COSI version >= 1.1, but not provided");

// Unknown bootloader type is invalid
(BootloaderType::Unknown(bootloader_type), _) => {
bail!("Unsupported bootloader type: {}", bootloader_type);
}

// Valid combination
_ => {}
}
}
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The refactored bootloader validation logic lacks test coverage for the various edge cases, including: validation with COSI version >= 1.1, Grub with systemd-boot entries, systemd-boot without entries, systemd-boot with empty entries, systemd-boot with multiple entries, systemd-boot with non-UKI entry types, and unknown bootloader types. Consider adding comprehensive tests for these validation scenarios.

Copilot uses AI. Check for mistakes.
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.

4 participants