Skip to content

Attachment and NetworkStatus lack backward-compatible decoding (unlike NetworkConfiguration) #1196

@edsai

Description

@edsai

Summary

The Attachment and NetworkStatus structs in ContainerResource do not handle backward-compatible JSON decoding when communicating with older versions of container-apiserver. This causes keyNotFound decoding errors when a client built against v0.9.0 of this package talks to the v0.7.0 container-apiserver that ships with macOS 26.

NetworkConfiguration already handles this correctly with fallback decoding — Attachment and NetworkStatus should do the same.

Background

Between v0.7.0 and v0.9.0, several JSON field names were renamed:

Struct v0.7.0 field v0.9.0 field
Attachment address (String) ipv4Address (CIDRv4)
Attachment gateway (String) ipv4Gateway (IPv4Address)
NetworkStatus address (String) ipv4Subnet (CIDRv4)
NetworkStatus gateway (String) ipv4Gateway (IPv4Address)
NetworkConfiguration subnet (String?) ipv4Subnet (CIDRv4?)

NetworkConfiguration already has a custom init(from decoder:) that tries ipv4Subnet first and falls back to subnet:

// NetworkConfiguration.swift (already correct)
let subnetText =
    try container.decodeIfPresent(String.self, forKey: .ipv4Subnet)
    ?? container.decodeIfPresent(String.self, forKey: .subnet)

Attachment and NetworkStatus use the default synthesized Codable conformance, which only accepts the new field names and fails with keyNotFound when it encounters the old ones.

Impact

Any downstream project (e.g., socktainer) that builds against apple/container v0.9.0 but runs on a stock macOS 26 system (which ships container-apiserver v0.7.0) will crash when decoding network data.

Error:

keyNotFound(CodingKeys(stringValue: "ipv4Address", intValue: nil),
  Swift.DecodingError.Context(codingPath: [..., "networks", ...],
  debugDescription: "No value associated with key \"ipv4Address\""))

Suggested Fix

Add custom init(from decoder:) to Attachment and NetworkStatus, matching the pattern already used in NetworkConfiguration.

For Attachment (Sources/ContainerResource/Network/Attachment.swift):

public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.network = try container.decode(String.self, forKey: .network)
    self.hostname = try container.decode(String.self, forKey: .hostname)

    if let addr = try? container.decode(CIDRv4.self, forKey: .ipv4Address) {
        self.ipv4Address = addr
    } else {
        self.ipv4Address = try container.decode(CIDRv4.self, forKey: .address)
    }

    if let gw = try? container.decode(IPv4Address.self, forKey: .ipv4Gateway) {
        self.ipv4Gateway = gw
    } else {
        self.ipv4Gateway = try container.decode(IPv4Address.self, forKey: .gateway)
    }

    self.ipv6Address = try container.decodeIfPresent(CIDRv6.self, forKey: .ipv6Address)
    self.macAddress = try container.decodeIfPresent(MACAddress.self, forKey: .macAddress)
}

private enum CodingKeys: String, CodingKey {
    case network, hostname, ipv4Address, ipv4Gateway, ipv6Address, macAddress
    case address, gateway // v0.7.0 field names
}

Same pattern for NetworkStatus (Sources/ContainerResource/Network/NetworkState.swift).

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions