Documentation
¶
Overview ¶
Package hostedimage holds the ONE vocabulary for "can the control plane pull this hosted image": the push-base resolution rule, the off-base finding, and its wording.
It exists as its own package because the rule has three consumers that cannot import each other:
- internal/cli's build, which resolves a bare hosted image to the push base and refuses one it cannot resolve;
- internal/cli's `env render`, which refuses a host-bearing image it can prove is off-base;
- internal/cli/lint, which reports the same thing as a finding and must not import internal/cli.
Without a shared package the third consumer would restate the message, and a restated message is one that drifts — which matters here because the message IS the product: an author who misreads it declares the wrong registry and discovers it at publish time, which is the defect ADR-0003 F1 closes.
Everything here is pure and offline. No consumer of this package may make a call: a render that needed a credential would stop being the reproducible projection every other surface diffs against.
Index ¶
- Constants
- func DeniedHint(reference string) string
- func HasRegistryHost(reference string) bool
- func IsDenied(err error, output string) bool
- func Name(repository string) string
- func NormalizeBase(base string) string
- func PushBase(registryHost, organization, project string) string
- func Repository(image string) string
- func ResolveBase(base, image string) string
- func UnderBase(base, image string) bool
- type Finding
- type Item
Constants ¶
const DefaultRegistryHost = "registry.reliantapi.com"
DefaultRegistryHost is Reliant's hosted container registry — what `forge.ControlPlane {}` means when it names no registry_host.
One fact, twice: kcl/schema.k's RELIANT_REGISTRY_HOST is the KCL copy, which is what a render actually reads. This is the Go copy, for the surfaces that have no KCL in front of them. A test renders the schema and fails if the two disagree (TestRegistryDefault_KCLMatchesGo).
It is a HOST, with no scheme and no trailing slash, because it is joined into an image reference.
Variables ¶
This section is empty.
Functions ¶
func DeniedHint ¶
DeniedHint is the sentence to append to a refused push.
The registry's realm scopes a credential to its OWN organization's subtree, and forge composes the push address from that same organization (it asks the control plane which one the token acts for). So a denial here is never a mis-declared org: it is a credential that has expired, or one that holds deploy:read but not the deploy:write a push needs.
func HasRegistryHost ¶
HasRegistryHost reports whether a reference's first path component is a registry host — the same rule kcl/lib/images.k and v1alpha1.ValidateImage apply, so forge's three layers agree about what "bare" means.
func IsDenied ¶
IsDenied reports whether err is a registry refusal to let this credential write here — as opposed to a network fault, a missing credential store, or a bad reference.
Both transports forge pushes over are covered, because both reach the same registry and the author cannot be expected to care which one carried their image:
- oras (bundles, static-site releases) returns a typed *errcode.ErrorResponse, so the status is read rather than matched.
- `docker push` is a subprocess whose exit status is just "failed", so the only signal is the daemon's own message on the pipe. Matched on the OCI distribution error CODE (`denied`, `UNAUTHORIZED`), which is part of the spec rather than of docker's phrasing.
func Name ¶
Name is a repository's last path segment — the artifact name (`ghcr.io/acme/shop` → `shop`).
func NormalizeBase ¶
NormalizeBase trims the one difference that is not a difference: a trailing slash. Every join below is explicit.
func PushBase ¶
PushBase composes `<registryHost>/<organization>/<project>`.
It returns "" when any segment is missing, and that is deliberately not an error here: this function has no env to name and no opinion about whether the caller can proceed. The callers decide, and they decide differently — a build refuses a bare image it cannot resolve, a render reports what it could not compare.
registryHost defaults to DefaultRegistryHost when empty, so a control plane that names no registry resolves to Reliant's — the overwhelmingly common case.
func Repository ¶
Repository strips any `:tag` / `@digest`, keeping the registry host.
func ResolveBase ¶
ResolveBase is the resolution rule (ADR-0003 F1): a BARE image on a hosted item becomes `<base>/<image>`; a host-bearing one is returned verbatim.
base "" returns the image unchanged. That is deliberately not an error here — this function has no env to name and no opinion about whether the caller can proceed. The caller decides: a build refuses (it has nowhere to push), a render warns (it has nothing to compare).
Types ¶
type Finding ¶
type Finding struct {
Owner string
Image string
// Base is the subtree the platform admits, or "" when forge could not
// learn it. This is the field that decides how much the finding claims.
Base string
}
Finding is one host-bearing image on a hosted item.
func OffBase ¶
OffBase is every host-bearing image among items, judged against base when base is known.
A BARE image is never a finding: that is the resolved, correct shape. The caller that must refuse an unresolvable bare image does so separately (internal/cli: checkHostedImagesResolve), because the remedy differs — there the declaration cannot be shipped at all, here it can be shipped somewhere the platform will not pull from.
func (Finding) Message ¶
Message is the one sentence a reader acts on. The unverified wording claims strictly less, for the reason Verified documents.
func (Finding) Verified ¶
Verified reports whether forge actually COMPARED this image against a known base, as opposed to merely noticing that a host was declared.
The distinction is load-bearing, not cosmetic. A verified finding is a fact — forge holds the admitted subtree and this image is not in it, so the publish will be refused. An unverified one is an observation: a hosted author does not need to declare a host, and forge could not check the one they declared. Acting on the second as though it were the first means failing a render over an assertion forge never made, and on a project whose registry IS the platform's that assertion would be false.
type Item ¶
Item is one hosted thing that carries an image: a workload or a frontend. Owner is what the message names, because a project may declare several and only one of them is wrong.
func ScanTree ¶
ScanTree returns every hosted item it can see in the deploy KCL tree at dir, as (owner, image) pairs ready for OffBase.
It joins two facts that are frequently declared in different files: an image on a workload in `workloads.k`, and that workload's runtime binding in `deploy/kcl/<env>/main.k`. Reporting only same-literal declarations would miss the shape most real projects use.
A missing or unreadable tree yields no items and no error: a project without a deploy tree has nothing to judge, and a lint must not fail over a file it merely hoped to find.