88 lines
3.4 KiB
Text
88 lines
3.4 KiB
Text
|
|
#!/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"
|
||
|
|
}
|