Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions .github/workflows/package-image-row.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ jobs:
outputs:
package_base_image: ${{ steps.bases.outputs.package_base_image }}
runtime_base_image: ${{ steps.bases.outputs.runtime_base_image }}
registry_cache_selected: ${{ steps.bases.outputs.registry_cache_selected }}
depot_registry_host: ${{ steps.bases.outputs.depot_registry_host }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
Expand All @@ -54,8 +56,16 @@ jobs:
- name: Resolve exact package and runtime base images
id: bases
env:
CACHE_ENABLED: ${{ vars.DEPOT_REGISTRY_CACHE_ENABLED }}
DEPOT_REGISTRY_HOST: ${{ vars.DEPOT_REGISTRY_HOST }}
EVENT_NAME: ${{ github.event_name }}
PACKAGE_BASE: ${{ fromJSON(inputs.row_json).package_base_image }}
PACKAGE_CACHE_REPOSITORY: ${{ fromJSON(inputs.row_json).package_base_cache_repository }}
REPOSITORY: ${{ github.repository }}
RUNTIME_BASE: ${{ fromJSON(inputs.row_json).runtime_base_image }}
RUNTIME_CACHE_REPOSITORY: ${{ fromJSON(inputs.row_json).runtime_base_cache_repository }}
WORKFLOW_REF: ${{ github.workflow_ref }}
WORKFLOW_SOURCE_REF: ${{ github.ref }}
shell: bash
run: |
set -euo pipefail
Expand All @@ -75,10 +85,66 @@ jobs:
}
package_base_image="$(resolve_ref "$PACKAGE_BASE")"
runtime_base_image="$(resolve_ref "$RUNTIME_BASE")"
registry_cache_selected=false
depot_registry_host=

if [[ "$CACHE_ENABLED" == true &&
"$REPOSITORY" == Mesh-LLM/mesh-packaging &&
"$WORKFLOW_SOURCE_REF" == refs/heads/main &&
"$WORKFLOW_REF" == Mesh-LLM/mesh-packaging/.github/workflows/images-release.yml@refs/heads/main ]]; then
case "$EVENT_NAME" in
repository_dispatch|workflow_dispatch) ;;
*) echo "pull-through bases rejected event: $EVENT_NAME" >&2; exit 1 ;;
esac
[[ "$DEPOT_REGISTRY_HOST" =~ ^[a-z0-9-]+\.registry\.depot\.dev$ ]] || {
echo "DEPOT_REGISTRY_HOST is invalid" >&2
exit 1
}
for repository in "$PACKAGE_CACHE_REPOSITORY" "$RUNTIME_CACHE_REPOSITORY"; do
[[ "$repository" =~ ^[a-z0-9]+([._/-]?[a-z0-9]+)*$ &&
"$repository" != *..* ]] || {
echo "invalid pull-through repository: $repository" >&2
exit 1
}
done
package_base_image="$DEPOT_REGISTRY_HOST/$PACKAGE_CACHE_REPOSITORY@${package_base_image##*@}"
runtime_base_image="$DEPOT_REGISTRY_HOST/$RUNTIME_CACHE_REPOSITORY@${runtime_base_image##*@}"
registry_cache_selected=true
depot_registry_host="$DEPOT_REGISTRY_HOST"
fi
{
echo "package_base_image=$package_base_image"
echo "runtime_base_image=$runtime_base_image"
echo "registry_cache_selected=$registry_cache_selected"
echo "depot_registry_host=$depot_registry_host"
} >> "$GITHUB_OUTPUT"
- name: Authenticate pull-through base images
if: steps.bases.outputs.registry_cache_selected == 'true'
env:
DEPOT_REGISTRY_HOST: ${{ steps.bases.outputs.depot_registry_host }}
shell: bash
run: |
set -euo pipefail
depot pull-token --project "$DEPOT_PROJECT_ID" |
docker login "$DEPOT_REGISTRY_HOST" --username x-token --password-stdin
- name: Verify exact pull-through base manifests
if: steps.bases.outputs.registry_cache_selected == 'true'
env:
PACKAGE_BASE_IMAGE: ${{ steps.bases.outputs.package_base_image }}
RUNTIME_BASE_IMAGE: ${{ steps.bases.outputs.runtime_base_image }}
shell: bash
run: |
set -euo pipefail
for image in "$PACKAGE_BASE_IMAGE" "$RUNTIME_BASE_IMAGE"; do
raw="$(mktemp)"
docker buildx imagetools inspect "$image" --raw > "$raw"
actual_digest="sha256:$(sha256sum "$raw" | awk '{ print $1 }')"
rm -f "$raw"
[[ "$actual_digest" == "${image##*@}" ]] || {
echo "pull-through digest mismatch for $image" >&2
exit 1
}
done
- name: Build native package from verified upstream product bundle
id: package
uses: depot/build-push-action@98e78adca7817480b8185f474a400b451d74e287 # v1
Expand Down Expand Up @@ -205,6 +271,15 @@ jobs:
uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1
with:
version: 2.101.77
- name: Authenticate pull-through runtime base
if: needs.package.outputs.registry_cache_selected == 'true'
env:
DEPOT_REGISTRY_HOST: ${{ needs.package.outputs.depot_registry_host }}
shell: bash
run: |
set -euo pipefail
depot pull-token --project "$DEPOT_PROJECT_ID" |
docker login "$DEPOT_REGISTRY_HOST" --username x-token --password-stdin
- name: Read immutable product inputs
id: product
shell: bash
Expand Down Expand Up @@ -302,6 +377,15 @@ jobs:
uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1
with:
version: 2.101.77
- name: Authenticate pull-through runtime base
if: needs.package.outputs.registry_cache_selected == 'true'
env:
DEPOT_REGISTRY_HOST: ${{ needs.package.outputs.depot_registry_host }}
shell: bash
run: |
set -euo pipefail
depot pull-token --project "$DEPOT_PROJECT_ID" |
docker login "$DEPOT_REGISTRY_HOST" --username x-token --password-stdin
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
registry: ghcr.io
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ that exact local image without registry writes. Publishing runs push a
run-scoped staging image, test it by digest, assemble a canonical release
index, and promote the tested digest without rebuilding.

Trusted release runs may opt into Depot Registry pull-through mirrors for the
Ubuntu, CUDA, ROCm, and Arch base repositories. The mirror keeps the resolved
upstream digest and uses a short-lived Depot pull token; dry runs and other
contexts retain the public upstream reference. See
[`docs/publishing.md`](docs/publishing.md#depot-registry-pull-through-cache) for
the measurement gate, dashboard mapping, variables, and rollback procedure.

The upstream release repository must send this payload after its GitHub Release is published:

```json
Expand Down
10 changes: 10 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Production Readiness TODO

- [x] Add measured Depot Registry pull-through base-image support.
Final result: trusted image rows may substitute configured Depot mirrors for
Ubuntu, CUDA, ROCm, and Arch bases while retaining the original tag or digest;
dry runs and untrusted contexts keep public upstream references, and OIDC
creates only short-lived read-only pull credentials.
QA: the matrix validation, 100%-coverage matrix suite, full 90-test TypeScript
suite, representative Ubuntu/CUDA/ROCm/Arch expansions, actionlint,
shellcheck, workflow policy scans, and `git diff --check` pass. The optional
local Dockerfile check could not connect to Docker (`failed to build: EOF`).

- [x] Persist package-manager downloads independently of Docker layers.
Final result: the native package stage uses locked, stable BuildKit cache IDs
separated by distro and architecture. The runtime stage additionally
Expand Down
6 changes: 6 additions & 0 deletions docs/matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ backend-neutral host for its specific OS/architecture plus exactly one runtime.

Each active row declares its distro, backend display version, `upstream_flavor`, package format/base, runtime base, platforms, support level, and release track. Matrix expansion derives the upstream archive/checksum URLs, deduplicated archive artifact ID, package artifact name, GitHub-hosted runner, and OCI tags.

`depot_registry.repositories` also maps each canonical public base repository
to its independently configured Depot pull-through repository. Validation
requires mappings for both base images of every declared row, including rows
that are currently disabled, so a newly enabled target cannot silently select
an undefined mirror.

## Active rows

| Variant | Platforms | Upstream archive flavor | Package | Track |
Expand Down
34 changes: 34 additions & 0 deletions docs/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,37 @@ production payload sets `dry_run=false`, `publish_images=true`, and
`publish_release_assets=true`. Upstream's client Docker workflow remains
available only as manual, non-publishing validation. npm publication is
independently controlled by `publish_npm`.

## Depot Registry pull-through cache

Pull-through caching is an optional base-image optimization, not a release
requirement. Before enabling it, use the `mesh-llm` Depot Registry canary to
compare at least five cold and five warm pulls of the same digest. Adopt a
mapping only when the warm median saves both at least 20 percent and 10 seconds,
with every sample resolving to the upstream digest.

Create one Depot Registry pull-through repository for each upstream path. For
the Docker Hub upstream `https://registry-1.docker.io`, the checked-in mapping
in `packaging/images.json` expects:

- `library/ubuntu` -> `dockerhub-ubuntu`
- `nvidia/cuda` -> `dockerhub-nvidia-cuda`
- `rocm/dev-ubuntu-24.04` -> `dockerhub-rocm-dev-ubuntu-24-04`
- `library/archlinux` -> `dockerhub-archlinux`
- `library/alpine` -> `dockerhub-alpine` (reserved for the disabled Alpine row)

After every enabled mapping meets the threshold, set
`DEPOT_REGISTRY_HOST` to the organization host ending in
`.registry.depot.dev`, then set `DEPOT_REGISTRY_CACHE_ENABLED=true`. The reusable
row workflow selects mirrors only for exact `main` executions of the canonical
release caller and obtains a short-lived read-only pull token through GitHub
OIDC. No long-lived registry secret is required. It resolves public references
first, retains their exact digest in the Depot reference, and verifies the
mirrored manifest before building.

This cache can reduce cold base pulls and public-registry rate-limit delays. It
does not accelerate apt, Cargo, pnpm/npm, native compilation, or Docker layer
export. Keep the existing BuildKit and package-manager caches as the primary
optimizations. To roll back immediately, set
`DEPOT_REGISTRY_CACHE_ENABLED=false`; the workflow returns to the original
public references without changing the matrix.
9 changes: 9 additions & 0 deletions packaging/images.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
"default_name": "ghcr.io/mesh-llm/mesh-llm",
"source_repository": "Mesh-LLM/mesh-llm"
},
"depot_registry": {
"repositories": {
"docker.io/library/alpine": "dockerhub-alpine",
"docker.io/library/archlinux": "dockerhub-archlinux",
"docker.io/library/ubuntu": "dockerhub-ubuntu",
"docker.io/nvidia/cuda": "dockerhub-nvidia-cuda",
"docker.io/rocm/dev-ubuntu-24.04": "dockerhub-rocm-dev-ubuntu-24-04"
}
},
"homebrew": {
"arch": "arm64",
"runner": "macos-15",
Expand Down
53 changes: 53 additions & 0 deletions scripts/image-matrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ type ImageConfig = {
source_repository?: string;
};

type DepotRegistryConfig = {
repositories?: Record<string, string>;
};

type HomebrewConfig = {
arch?: string;
runner?: string;
Expand Down Expand Up @@ -57,6 +61,7 @@ export type Variant = {
export type Config = {
schema_version?: number;
image?: ImageConfig;
depot_registry?: DepotRegistryConfig;
homebrew?: HomebrewConfig;
npm?: NpmConfig;
platform_arches?: Record<string, string>;
Expand All @@ -81,9 +86,11 @@ export type MatrixRow = {
backend_version: string;
upstream_flavor: UpstreamFlavor;
package_base_image: string;
package_base_cache_repository: string;
package_manager: string;
package_format: string;
runtime_base_image: string;
runtime_base_cache_repository: string;
mesh_ref: string;
mesh_repository: string;
mesh_version: string;
Expand Down Expand Up @@ -147,6 +154,8 @@ const DISTRO_PACKAGE_FORMATS: Record<string, string> = {
arch: "pkg.tar.zst",
};

const DEPOT_REPOSITORY_PATTERN = /^[a-z0-9]+(?:[._/-]?[a-z0-9]+)*$/;

export function loadConfig(path: string): Config {
return JSON.parse(readFileSync(path, "utf8")) as Config;
}
Expand All @@ -166,6 +175,28 @@ export function backendSuffix(backend: string, backendVersion = ""): string {
return backendVersion ? `${backend}${backendVersion}` : backend;
}

export function baseRepository(reference: string): string {
let name = reference.trim().split("@", 1)[0];
const lastSlash = name.lastIndexOf("/");
const lastColon = name.lastIndexOf(":");
if (lastColon > lastSlash) name = name.slice(0, lastColon);
if (!name || /\s/.test(name)) throw new Error(`invalid base image: ${reference}`);
const components = name.split("/");
if (components.length === 1) return `docker.io/library/${name}`;
const registry = components[0];
if (registry.includes(".") || registry.includes(":") || registry === "localhost") {
return name;
}
return `docker.io/${name}`;
}

function depotRepositoryFor(config: Config, reference: string): string {
const upstream = baseRepository(reference);
const repository = config.depot_registry?.repositories?.[upstream];
if (!repository) throw new Error(`missing Depot pull-through repository for ${upstream}`);
return repository;
}

export function targetTriple(platform: string): string {
if (platform === "linux/amd64") return "x86_64-unknown-linux-gnu";
if (platform === "linux/arm64") return "aarch64-unknown-linux-gnu";
Expand Down Expand Up @@ -232,6 +263,19 @@ export function validate(config: Config): string[] {
if (config.schema_version !== 2) errors.push("schema_version must be 2");
if (!config.image?.default_name) errors.push("image.default_name is required");
if (!config.image?.source_repository) errors.push("image.source_repository is required");
const depotRepositories = config.depot_registry?.repositories;
if (!depotRepositories || Object.keys(depotRepositories).length === 0) {
errors.push("depot_registry.repositories must be a non-empty object");
} else {
for (const [upstream, repository] of Object.entries(depotRepositories)) {
if (baseRepository(upstream) !== upstream) {
errors.push(`depot_registry upstream must be canonical: ${upstream}`);
}
if (!DEPOT_REPOSITORY_PATTERN.test(repository) || repository.includes("..")) {
errors.push(`invalid Depot repository name for ${upstream}`);
}
}
}
if (!config.homebrew?.arch || !config.homebrew.runner || !config.homebrew.target || config.homebrew.upstream_flavor !== "metal") {
errors.push("homebrew must define arch, runner, target, and upstream_flavor=metal");
}
Expand Down Expand Up @@ -266,6 +310,13 @@ export function validate(config: Config): string[] {

for (const key of ["package_base_image", "runtime_base_image"] as const) {
if (!variant[key]) errors.push(`${prefix}.${key} is required`);
else {
try {
depotRepositoryFor(config, variant[key]);
} catch (error) {
errors.push(`${prefix}.${key}: ${(error as Error).message}`);
}
}
}
const packageFormat = variant.package_format ?? "";
if (!SUPPORTED_PACKAGE_FORMATS.includes(packageFormat)) {
Expand Down Expand Up @@ -430,9 +481,11 @@ export function matrixRows(
backend_version: variant.backend_version ?? "",
upstream_flavor: flavor,
package_base_image: requiredString(variant.package_base_image),
package_base_cache_repository: depotRepositoryFor(config, requiredString(variant.package_base_image)),
package_manager: variant.package_manager ?? PACKAGE_MANAGERS_BY_FORMAT[requiredString(variant.package_format)] ?? "",
package_format: requiredString(variant.package_format),
runtime_base_image: requiredString(variant.runtime_base_image),
runtime_base_cache_repository: depotRepositoryFor(config, requiredString(variant.runtime_base_image)),
mesh_ref: meshRef,
mesh_repository: meshRepository,
mesh_version: version,
Expand Down
Loading