Files
container/Tests/ContainerNetworkServerTests/NetworkAliasProtocolTests.swift
T
J Logan b3eb70307a Add DNS aliases and subtree aliases for container network attachments (#2390)
- Closes #457.
- A container can now declare additional DNS names for
  a network attachment with a repeatable `alias` property
  on `--network`, including subtree aliases that match
  every name below a domain.
- With the default domain `test`, this container answers
  to `gateway.test` by its name, to `api.test` by the exact
  alias, and to `web.gateway.test`, `a.b.gateway.test`
  and every other name below `gateway.test` by the
  subtree alias. The motivating case is a gateway container
  in front of a local Kubernetes cluster that answers for
  `*.gateway.test`, with an ingress controller routing on
  the `Host` header.
- An alias is an exact name, or a name with a leading
  dot that matches every name below it. A name without
  a dot gets the default domain, as container names do.
  A subtree alias must be below a name the same
  attachment owns, and exact names are unique across
  all containers, so a container cannot claim another
  container's namespace. The rules for one attachment
  are checked when a container is created, again when
  a stored container starts, and again by the network
  helper when it registers the aliases. See
  `docs/architecture/dns.md` for the design, the
  invariants and the security considerations.
2026-10-14 10:11:00 -07:00

82 lines
2.5 KiB
Swift

//===----------------------------------------------------------------------===//
// Copyright © 2026 Apple Inc. and the container project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//
import ContainerXPC
import Testing
@testable import ContainerNetworkClient
@testable import ContainerNetworkServer
struct NetworkAliasProtocolTests {
private func message() -> XPCMessage {
XPCMessage(route: "test")
}
// MARK: - Aliases in messages
@Test func testAliasesRoundTrip() throws {
let message = message()
try message.setAliases(["api.example.test", ".example.test"])
#expect(try message.aliases() == ["api.example.test", ".example.test"])
}
@Test func testMessageWithoutAliasesHasNone() throws {
#expect(try message().aliases().isEmpty)
}
// MARK: - Match kind in messages
@Test func testMatchKindRoundTrip() throws {
let kinds: [NetworkMatchKind] = [.hostname, .alias, .subtree(baseLabelCount: 3)]
for kind in kinds {
let message = message()
message.setMatchKind(kind)
#expect(try message.matchKind() == kind)
}
}
@Test func testMessageWithoutMatchKindIsRejected() {
#expect(throws: (any Error).self) {
try message().matchKind()
}
}
@Test func testUnknownMatchKindIsRejected() throws {
let message = message()
message.set(key: NetworkKeys.matchKind.rawValue, value: "wildcard")
#expect(throws: (any Error).self) {
try message.matchKind()
}
}
// MARK: - Name in messages
@Test func testNameRoundTrip() throws {
let message = message()
message.set(key: NetworkKeys.name.rawValue, value: "web.example.test.")
#expect(try message.name() == "web.example.test.")
}
@Test func testMessageWithoutNameIsRejected() {
#expect(throws: (any Error).self) {
try message().name()
}
}
}