Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions Sources/ContainerizationOCI/Spec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,22 @@ public struct Linux: Codable, Sendable {
public var mountLabel: String
public var personality: LinuxPersonality?

public enum CodingKeys: String, CodingKey {
case uidMappings
case gidMappings
case sysctl
case resources
case cgroupsPath
case namespaces
case devices
case seccomp
case rootfsPropagation
case maskedPaths
case readonlyPaths
case mountLabel
case personality
}

public init(
uidMappings: [LinuxIDMapping] = [],
gidMappings: [LinuxIDMapping] = [],
Expand Down Expand Up @@ -455,6 +471,43 @@ public struct Linux: Codable, Sendable {
self.mountLabel = mountLabel
self.personality = personality
}

public init(from decoder: Decoder) throws {
self.init()

let container = try decoder.container(keyedBy: CodingKeys.self)
if let uidMappings = try container.decodeIfPresent([LinuxIDMapping].self, forKey: .uidMappings) {
self.uidMappings = uidMappings
}
if let gidMappings = try container.decodeIfPresent([LinuxIDMapping].self, forKey: .gidMappings) {
self.gidMappings = gidMappings
}
self.sysctl = try container.decodeIfPresent([String: String].self, forKey: .sysctl)
self.resources = try container.decodeIfPresent(LinuxResources.self, forKey: .resources)
if let cgroupsPath = try container.decodeIfPresent(String.self, forKey: .cgroupsPath) {
self.cgroupsPath = cgroupsPath
}
if let namespaces = try container.decodeIfPresent([LinuxNamespace].self, forKey: .namespaces) {
self.namespaces = namespaces
}
if let devices = try container.decodeIfPresent([LinuxDevice].self, forKey: .devices) {
self.devices = devices
}
self.seccomp = try container.decodeIfPresent(LinuxSeccomp.self, forKey: .seccomp)
if let rootfsPropagation = try container.decodeIfPresent(String.self, forKey: .rootfsPropagation) {
self.rootfsPropagation = rootfsPropagation
}
if let maskedPaths = try container.decodeIfPresent([String].self, forKey: .maskedPaths) {
self.maskedPaths = maskedPaths
}
if let readonlyPaths = try container.decodeIfPresent([String].self, forKey: .readonlyPaths) {
self.readonlyPaths = readonlyPaths
}
if let mountLabel = try container.decodeIfPresent(String.self, forKey: .mountLabel) {
self.mountLabel = mountLabel
}
self.personality = try container.decodeIfPresent(LinuxPersonality.self, forKey: .personality)
}
}

public struct LinuxNamespace: Codable, Sendable {
Expand Down
22 changes: 22 additions & 0 deletions Tests/ContainerizationOCITests/OCISpecTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,26 @@ struct OCISpecTests {
#expect(decodedSpec.uidMappings == nil)
#expect(decodedSpec.gidMappings == nil)
}

@Test func minimalCapabilitiesDecode() throws {
let minCapabilitiesSpec =
"""
{
"ociVersion": "1.1.0",
"capabilities": {
"permitted": [
"CAP_SYS_ADMIN"
]
},
"linux": {}
}
"""

guard let data = minCapabilitiesSpec.data(using: .utf8) else {
Issue.record("test capabilities spec is not valid: \(minCapabilitiesSpec)")
return
}

let _ = try JSONDecoder().decode(ContainerizationOCI.Spec.self, from: data)
}
}