The CloudKit credential configuration glue shared by MistKit's server-side
applications: read a container ID, key ID and private key from the command line or the
environment, validate them before they reach the network, and build a CloudKitService.
MistKit itself stays configuration-framework-free — the dependency arrow points one way, into MistKit, so adopting this package never changes MistKit's own surface.
- Raw → validated → service.
CloudKitConfiguration(all fields optional, reading never throws) →validated()→ValidatedCloudKitConfiguration→makeCloudKitService(). - Format validation you would otherwise discover at request time.
KeyIDValidator(64 hex characters) andPEMValidator(header, footer, base64 body), reachable standalone. - Keys and plumbing.
CloudKitConfigurationKeysparameterized by container default and environment prefix, areadCloudKitConfiguration(keys:)seam on anyConfigValueReading, andConfigurationSourcesfor the provider stack.
Nothing in this package conforms to LocalizedError. It throws structured, Equatable
enums and leaves every user-facing string to you — because only your application knows
which flag or environment variable supplied the value, and what advice to give.
do {
let service = try configuration.validated().makeCloudKitService()
} catch let error as CloudKitConfigurationError {
switch error {
case .missing(let field):
throw MyError.missingRequired(keys[field].key(for: .environment) ?? "")
case .invalidKeyID(.incorrectLength(let actual)):
throw MyError.badKeyID("expected \(KeyIDValidator.expectedLength), got \(actual)")
default:
throw MyError.configuration(String(describing: error))
}
}CloudKitConfigurationField names the offending field rather than a key string, because
the same field is spelled differently by different applications.
import Configuration
import MistKitConfiguration
let keys = CloudKitConfigurationKeys(defaultContainerID: "iCloud.com.example.MyApp")
let reader = ConfigurationSources.makeConfigReader(
secretCommandLineFlags: keys.secretCommandLineFlags
)
let service = try reader
.readCloudKitConfiguration(keys: keys)
.validated()
.makeCloudKitService()That resolves --cloudkit-container-id / CLOUDKIT_CONTAINER_ID, --cloudkit-key-id /
CLOUDKIT_KEY_ID, --cloudkit-private-key[-path] and --cloudkit-environment, with the
command line taking precedence over the environment.
The redaction list is derived from each key's isSecret, so it cannot drift from the
keys themselves — the drift that previously let a private key passed by flag be logged in
the clear.
- BushelCloud and CelestraCloud.
- MistDemo, inside MistKit.
.package(url: "https://github.com/brightdigit/MistKitConfiguration.git", from: "1.0.0-beta.1"),.target(
name: "MyApp",
dependencies: [
.product(name: "MistKitConfiguration", package: "MistKitConfiguration")
]
),MIT — see LICENSE.