provisioning-core/nulib/platform/oci/contract_cli.nu

88 lines
3.4 KiB
Text
Raw Permalink Normal View History

#!/usr/bin/env nu
# CLI entry for the catalog contract content-addressing process (ADR-046).
# Wrapped by justfiles/catalog-contract.just. Subcommands automate the producer
# side (publish anchor + per-version referrer) and the consumer side (resolve a
# catalog's requires.contract to an immutable digest pinned in catalog.lock.ncl).
use platform/oci/contract_resolver.nu *
use platform/oci/push_registry.nu *
# Select the push registry from a pluggable source and emit shell export lines.
# Apply with: eval "$(... select-registry --kind sops --value <path> ...)"
def "main select-registry" [
--kind: string = "" # sops | api | literal | env
--value: string = "" # literal endpoint | env var | sops path | api url
--endpoint-key: string = "endpoint"
--user-key: string = "username"
--pass-key: string = "password"
--vault-id: string = ""
--age-key: string = ""
--auth-header: string = ""
] {
select-push-registry --kind $kind --value $value --endpoint-key $endpoint_key --user-key $user_key --pass-key $pass_key --vault-id $vault_id --age-key $age_key --auth-header $auth_header
}
# Publish the immutable referrers anchor for a contract id (run once per id).
# Prints the subject digest to record in requires.contract.subject.
def "main publish-anchor" [
id: string # contract id, e.g. catalog-manifest
--participant: string = "provisioning"
--registry: string = ""
--registry-id: string = ""
] {
let r = (publish-contract-anchor $participant $id --registry $registry --registry-id $registry_id)
print $"anchor published: ($r.ref)"
print $"subject digest → set requires.contract.subject = \"($r.digest)\""
$r
}
# Attach a contract version as a referrer to the anchor.
def "main publish-version" [
contract_file: string # path to contract.ncl (the manifest schema)
id: string
version: string
subject: string # anchor digest from publish-anchor
--participant: string = "provisioning"
--registry: string = ""
--registry-id: string = ""
] {
let r = (publish-contract-version $contract_file $participant $id $version $subject --registry $registry --registry-id $registry_id)
print $"attached ($id) v($version) → ($r.digest)"
$r
}
# Resolve a catalog's requires.contract → digest and pin catalog.lock.ncl.
def "main resolve" [
catalog_root: string # catalog dir to write catalog.lock.ncl into
manifest: string # manifest file declaring requires.contract
] {
let decl = (read-contract-decl $manifest)
if $decl == null {
print "no requires.contract declared — nothing to resolve"
return
}
let r = (resolve-contract-and-lock $catalog_root $decl)
print $"resolved ($r.id) → ($r.version) @ ($r.digest)"
print $"lock: ($r.lock)"
$r
}
# Validate a manifest against its declared contract (resolve + typecheck).
# Intended as a CI gate before any automated load.
def "main validate" [
manifest: string
--catalog-root: string = ""
] {
let result = (validate-manifest-against-contract $manifest --catalog-root $catalog_root)
print $result
if not $result.typechecks {
exit 1
}
$result
}
def main [] {
print "catalog contract process (ADR-046)."
print "subcommands: publish-anchor | publish-version | resolve | validate"
}