Container Registry Pull Reachability and Rate-Budget Ledger
Pricing
from $20.00 / 1,000 reachability run starts
Container Registry Pull Reachability and Rate-Budget Ledger
Pulls the manifest of every pinned image reference over HTTPS and reports whether the pull works now, why it would fail, which platforms the manifest holds, the TLS name-match verdict, and how much anonymous rate budget the registry has left. HTTP only, n
Pricing
from $20.00 / 1,000 reachability run starts
Rating
0.0
(0)
Developer
kingii98
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Your build pulls the same images every time. When one pull stops to work, every build stops. You look at your own code first, then at the runner, and only at the end at the registry. That search costs an hour.
This Actor holds the registry answer before you need it. It pulls the manifest of every pinned reference over HTTPS and tells you three things:
- Would the pull work now? Yes, or the exact reason for no.
- What changed since the last run? The ledger holds the previous status and the previous digest of each reference.
- How much pull budget is left? The Actor reads the
RateLimit-LimitandRateLimit-Remainingheaders of each registry host.
HTTP and TLS only. No browser. No proxy. No database. No container runtime.
What it does for each reference
The Actor walks the same path as a container runtime.
| Step | Call | What it records |
|---|---|---|
| 1 | GET /v2/<repository>/manifests/<reference> | The challenge, or the answer at once. |
| 2 | The token endpoint of the challenge | Is the token endpoint reachable? |
| 3 | The manifest call again, with the token | Status, digest, media type, rate budget. |
| 4 | The manifest body | The platform list of the image index. |
The Actor follows each redirect by hand. It records the host chain, and it
removes the Authorization header as soon as the host or the port changes, so
a token never reaches a content delivery network. A redirect to a scheme other
than HTTPS stops the probe with an unreachable verdict, because a cleartext
hop would show the token, or your registry password, to every device on the
path.
A blocked pull gets more work: one more attempt, and a TLS handshake inspection of the host that failed. That inspection answers the question that costs the most time in an incident:
tls: failed to verify certificate: x509: certificate is not valid for any names, but wanted to match docker-images-prod.<hash>.r2.cloudflarestorage.com
The Actor reports the certificate subject, the subject alternative names and
one clear verdict: match, mismatch or unknown.
Input
Give the Actor the reference list of your pipeline, or paste your Dockerfile.
{"imageRefs": ["alpine:3.20", "ghcr.io/org/app:1.4.2"],"dockerfile": "FROM golang:1.23 AS build\nFROM alpine:3.20\n","expectedPlatform": "linux/amd64","failOn": ["unreachable", "unauthorized", "tls_name_mismatch"]}
| Field | Meaning |
|---|---|
imageRefs | 1 to 100 references. A reference without a host goes to Docker Hub. |
dockerfile | Optional. The Actor reads the image of each FROM line. |
expectedPlatform | Optional, for example linux/amd64. |
failOn | The failure classes that make the run verdict fail. |
registryToken, registryUsername, registryPassword | Optional credentials for a private repository that you own. |
credentialHosts | The hosts that may receive those credentials. |
ledgerStoreName | The named key-value store that holds the ledger. |
concurrency, timeoutSeconds, maxRedirects, maxResponseBytes | The bounds of the run. |
Every required field has a default, so a run with the empty input {} works.
The Actor reads the Dockerfile carefully. It skips scratch, it skips a FROM
line that points at an earlier build stage, and it skips a line that still holds
an unexpanded ARG.
Private repositories
Put your token in registryToken, or your user name and password in
registryUsername and registryPassword. Then name the host in
credentialHosts, for example ["ghcr.io"]. The Actor sends the credentials
only to the token endpoint of a named host. An empty credentialHosts list
sends them to every host in your reference list, so fill the list in when the
list mixes a private registry with public ones.
Failure classes
| Class | Meaning |
|---|---|
ok | The pull works now. |
unreachable | The registry or the token endpoint does not answer. |
unauthorized | The registry refuses the credentials. |
rate_limited | The registry answered 429, or it reports no pull budget left. |
not_found | The repository or the tag does not exist. |
server_error | The registry answers 5xx. |
tls_name_mismatch | The certificate is valid, but not for the host that was asked. |
tls_error | Another TLS or certificate chain fault. |
platform_missing | The manifest list does not hold expectedPlatform. |
invalid_reference | The text is not a reference, or it points at a private address. |
A registry that answers a status with no better class gets unreachable, and
the detail field names the status.
Output
Three record types go to the dataset.
| Record type | Count | Holds |
|---|---|---|
reference | One for each reference | Host, repository, status, digest, media type, platforms, redirect chain, TLS verdict, response time, failure class, and the change since the last run. |
rate-budget | One for each registry host | RateLimit-Limit, RateLimit-Remaining, the time to reset, and the use since the last run. |
run-summary | One | The pass or fail verdict against failOn, the counts, and the list of references that changed. |
The verdict never fails the run
A blocked pull is the answer that you paid for. The Actor writes the verdict
into the run-summary record and into the run status message, and the Apify
run ends SUCCEEDED. A FAILED run means a malfunction of the Actor, nothing
else. Read verdict in the summary record, or read the status message, to gate
your pipeline.
The ledger
The Actor keeps one record for each reference and a short rate-budget history
for each host in a named key-value store. Every run with the same
ledgerStoreName compares against the same ledger. This gives you the sentence
that a single run cannot give:
This reference became "tls_name_mismatch" since the last run.
The first run writes the ledger and reports the current status only.
How to use it
- Put your pipeline reference list into
imageRefs. - Add an Apify schedule. One run each hour is the usual cadence. You can also start the Actor before each deployment.
- Read
verdictof therun-summaryrecord, or read the status message.
Pricing
The Actor uses pay per event.
| Event | Unit | Price | When |
|---|---|---|---|
reachability-run-start | run | 0.02 | Once for each run, after the input is read. |
image-ref-probed | image reference probed | 0.006 | Once for each reference that the Actor called a registry for. |
blocked-pull-diagnosed | blocked reference | 0.02 | Once for each reference that stays blocked after the second attempt and the TLS trace. |
Two references are not charged as a probe: a reference that cannot be parsed, and a reference that points at a private or reserved address. The Actor makes no call for them. A reference that fails once and works on the second attempt is not charged as a diagnosis, because you receive a working pull.
The default cap maxTotalChargeUsd is 8.00 for one run. A run over 100
references costs at most 0.02 + 0.60 + 2.00 = 2.62, so the cap holds the worst
case, when a whole registry is down and every reference takes the expensive
path.
What one month costs
20 healthy references, one run each hour, 30 days:
| Event | Count | Price | Cost |
|---|---|---|---|
reachability-run-start | 24 runs x 30 days = 720 | 0.02 | 14.40 |
image-ref-probed | 20 refs x 24 runs x 30 days = 14400 | 0.006 | 86.40 |
blocked-pull-diagnosed | 0 blocked = 0 | 0.02 | 0.00 |
| Total | 100.80 |
The cadence drives the bill, not the reference count alone. Select the schedule that your pipeline needs:
| Schedule | Runs each day | 20 references | For each reference |
|---|---|---|---|
| Every hour | 24 | 100.80 | 5.04 |
| Every 6 hours | 4 | 16.80 | 0.84 |
| Once each day | 1 | 4.20 | 0.21 |
A blocked reference adds 0.02 for each run while it stays blocked.
Limits and rules
- The Actor refuses loopback, private, link-local and reserved addresses, for the registry host and for every redirect hop.
- Only HTTPS, for the first call and for every redirect hop. A reference carries no URL scheme.
- 1 to 100 references for each run.
- The Actor reads at most
maxResponseBytesfrom one answer. - The Actor does not download image layers. It reads the manifest, and it reads
the image config blob only when you set
expectedPlatformand the reference resolves to a single-platform manifest.
Develop
uv syncuv run pytestuv run ruff check .