//===----------------------------------------------------------------------===// // 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 ContainerizationOS import Foundation /// A container registry resource representing a configured registry endpoint. /// /// Registry resources store authentication and configuration information for /// container registries such as Docker Hub, GitHub Container Registry, or /// private registries. public struct RegistryResource: ManagedResource { /// The registry hostname that uniquely identifies this resource. /// /// For registry resources, the identifier is the same as the hostname. public let id: String /// The hostname of the registry. /// /// This value must be a valid DNS hostname or IPv6 address, optionally /// followed by a port number (e.g., "docker.io", "localhost:5000", "[::1]:5000"). public let name: String /// The username used for authentication with this registry. public let username: String /// The time at which the system created this registry resource. public let creationDate: Date /// The time at which the registry resource was last modified. public let modificationDate: Date /// Key-value properties for the resource. /// /// The user and system may both make use of labels to read and write /// annotations or other metadata. public let labels: ResourceLabels /// Validates a registry hostname according to OCI distribution specification. /// /// This method validates that a registry hostname conforms to the domain pattern /// used by OCI image references. It supports DNS hostnames, IPv6 addresses, and /// optional port numbers. /// /// - Parameter name: The registry hostname to validate /// - Returns: `true` if the hostname is syntactically valid, `false` otherwise /// /// ## Valid Examples /// - `docker.io` /// - `registry.example.com` /// - `localhost:5000` /// - `[::1]:5000` /// /// ## Implementation Notes /// The validation logic is based on ContainerizationOCI's `Reference.domainPattern`. /// See public static func nameValid(_ name: String) -> Bool { // Domain validation logic based on ContainerizationOCI Reference.domainPattern // See: https://github.com/apple/containerization/blob/main/Sources/ContainerizationOCI/Reference.swift // TODO: if we have domain IP validation API, use that instead let domainNameComponent = "(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])" let optionalPort = "(?::[0-9]+)?" let ipv6address = "\\[(?:[a-fA-F0-9:]+)\\]" let domainName = "\(domainNameComponent)(?:\\.\(domainNameComponent))*" let host = "(?:\(domainName)|\(ipv6address))" let pattern = "^\(host)\(optionalPort)$" return name.range(of: pattern, options: .regularExpression) != nil } /// Creates a new registry resource. /// /// - Parameters: /// - hostname: The registry hostname (also used as the resource ID) /// - username: The username for authentication /// - creationDate: The time the resource was created /// - modificationDate: The time the resource was last modified /// - labels: Optional key-value labels for metadata (default: empty dictionary) public init( hostname: String, username: String, creationDate: Date, modificationDate: Date, labels: ResourceLabels = .init() ) { self.id = hostname self.name = hostname self.username = username self.creationDate = creationDate self.modificationDate = modificationDate self.labels = labels } } extension RegistryResource { /// Creates a registry resource from registry information. /// /// - Parameter registryInfo: The registry information to convert public init(from registryInfo: RegistryInfo) { self.init( hostname: registryInfo.hostname, username: registryInfo.username, creationDate: registryInfo.createdDate, modificationDate: registryInfo.modifiedDate ) } }