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
26 changes: 23 additions & 3 deletions Sources/Services/ContainerAPIService/Client/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ public struct Parser {
let rlimits = try Parser.rlimits(processFlags.ulimits)

return .init(
executable: commandToRun.first!,
executable: commandToRun[0],
arguments: [String](commandToRun.dropFirst()),
environment: envvars,
workingDirectory: workingDir,
Expand All @@ -340,11 +340,31 @@ public struct Parser {
public static let defaultDirectives = ["type": "virtiofs"]

public static func tmpfsMounts(_ mounts: [String]) throws -> [Filesystem] {
let mounts = mounts.dedupe()
var result: [Filesystem] = []
result.reserveCapacity(mounts.count)
var seenDestinations: Set<String> = []

for tmpfs in mounts {
let fs = Filesystem.tmpfs(destination: tmpfs, options: [])
let parts = tmpfs.split(separator: ":", maxSplits: 1, omittingEmptySubsequences: false)
let destination = String(parts[0])
let options = parts.count == 2 ? String(parts[1]).split(separator: ",").map(String.init) : []

if destination.isEmpty {
throw ContainerizationError(.invalidArgument, message: "mount destination cannot be empty")
}

let filePath = FilePath(destination)
guard filePath.isAbsolute else {
throw ContainerizationError(.invalidArgument, message: "\(destination) is not an absolute path")
}

let normalizedDest = filePath.lexicallyNormalized().string
if seenDestinations.contains(normalizedDest) {
continue
}
seenDestinations.insert(normalizedDest)

let fs = Filesystem.tmpfs(destination: destination, options: options)
try validateMount(.filesystem(fs))
result.append(fs)
}
Expand Down
27 changes: 27 additions & 0 deletions Tests/ContainerAPIClientTests/ParserTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,33 @@ struct ParserTest {
#expect(result.count == 20)
}

@Test("tmpfsMounts parses mount options and dedupes on destination path")
func testTmpfsMountsWithColons() throws {
let mounts = [
"/mnt/scratch:rw,exec",
"/mnt/scratch", // Should be deduped based on path
"/mnt/cache:ro",
]
let result = try Parser.tmpfsMounts(mounts)
#expect(result.count == 2)
#expect(result[0].destination == "/mnt/scratch")
#expect(result[0].options == ["rw", "exec"])
}

@Test("tmpfsMounts throws on empty destination")
func testTmpfsMountsEmptyDestination() throws {
#expect(throws: ContainerizationError.self) {
_ = try Parser.tmpfsMounts([""])
}
}

@Test("tmpfsMounts throws on non-absolute destination")
func testTmpfsMountsNonAbsoluteDestination() throws {
#expect(throws: ContainerizationError.self) {
_ = try Parser.tmpfsMounts(["relative/path:rw"])
}
}

@Test("volumes with large input")
func testVolumesLargeInput() throws {
let volumes = (0..<20).map { "vol\($0):/mnt/vol\($0)" }
Expand Down