Initial commit: OCI image mounting via containers-storage

slocker-lite validates an OCI Image Layout tar, imports its layers into
containers-storage's layer store in order, and mounts the assembled image
using fuse-overlayfs, printing the resulting merged path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 08:12:50 +00:00
commit a301dfb44f
16 changed files with 1141 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""Writes a minimal one-layer OCI Image Layout tar to the path given as argv[1].
Used by meson.build to produce a fixture for the `meson test` smoke test.
"""
import gzip
import hashlib
import io
import json
import sys
import tarfile
def sha256_hex(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
def add_bytes(tar: tarfile.TarFile, name: str, data: bytes) -> None:
info = tarfile.TarInfo(name=name)
info.size = len(data)
tar.addfile(info, io.BytesIO(data))
def main() -> None:
out_path = sys.argv[1]
# Uncompressed layer content: a tiny tar with a single file.
layer_tar_buf = io.BytesIO()
with tarfile.open(fileobj=layer_tar_buf, mode="w") as layer_tar:
add_bytes(layer_tar, "hello.txt", b"hello from slocker-lite fixture\n")
layer_tar_bytes = layer_tar_buf.getvalue()
diff_id = sha256_hex(layer_tar_bytes)
layer_gz_bytes = gzip.compress(layer_tar_bytes)
layer_digest = sha256_hex(layer_gz_bytes)
config = {
"architecture": "amd64",
"os": "linux",
"config": {},
"rootfs": {"type": "layers", "diff_ids": [f"sha256:{diff_id}"]},
}
config_bytes = json.dumps(config).encode()
config_digest = sha256_hex(config_bytes)
manifest = {
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": f"sha256:{config_digest}",
"size": len(config_bytes),
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": f"sha256:{layer_digest}",
"size": len(layer_gz_bytes),
}
],
}
manifest_bytes = json.dumps(manifest).encode()
manifest_digest = sha256_hex(manifest_bytes)
index = {
"schemaVersion": 2,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": f"sha256:{manifest_digest}",
"size": len(manifest_bytes),
}
],
}
index_bytes = json.dumps(index).encode()
oci_layout_bytes = json.dumps({"imageLayoutVersion": "1.0.0"}).encode()
with tarfile.open(out_path, mode="w") as tar:
add_bytes(tar, "oci-layout", oci_layout_bytes)
add_bytes(tar, "index.json", index_bytes)
add_bytes(tar, f"blobs/sha256/{config_digest}", config_bytes)
add_bytes(tar, f"blobs/sha256/{manifest_digest}", manifest_bytes)
add_bytes(tar, f"blobs/sha256/{layer_digest}", layer_gz_bytes)
if __name__ == "__main__":
main()