├── .aspect └── workflows │ └── config.yaml ├── .bazelignore ├── .bazelrc ├── .bazelrc.common ├── .bcr ├── config.yml ├── img_tool │ ├── metadata.template.json │ ├── presubmit.yml │ └── source.template.json ├── metadata.template.json ├── presubmit.yml ├── pull_tool │ ├── metadata.template.json │ ├── presubmit.yml │ └── source.template.json └── source.template.json ├── .envrc ├── .github ├── logo │ ├── dark_hero.jpg │ ├── dark_text.png │ ├── light_hero.jpg │ └── light_text.png ├── release.yml └── workflows │ ├── ci.bazelrc │ ├── ci.yml │ ├── publish.yaml │ ├── release.yaml │ └── release_prep.sh ├── .gitignore ├── .pre-commit-config.yaml ├── BUILD.bazel ├── CONTRIBUTING.md ├── HACKING.md ├── LICENSE ├── MODULE.bazel ├── README.md ├── docs ├── BUILD.bazel ├── image.md ├── layer.md ├── load.md ├── multi_deploy.md ├── pull.md ├── push-strategies.md ├── push.md ├── templating.md └── visuals │ ├── bes-dark.svg │ ├── bes-light.svg │ ├── cas-registry-dark.svg │ ├── cas-registry-light.svg │ ├── eager-push-dark.svg │ ├── eager-push-light.svg │ ├── lazy-push-dark.svg │ ├── lazy-push-light.svg │ ├── tweag_dark_mode.svg │ └── tweag_light_mode.svg ├── e2e ├── BUILD.bazel ├── cc │ ├── .bazelrc │ ├── .bazelrc.common │ ├── BUILD.bazel │ ├── MODULE.bazel │ ├── README.md │ ├── WORKSPACE.bazel │ ├── base │ │ └── BUILD.bazel │ ├── custom_standard_library │ │ └── BUILD.bazel │ ├── main.cc │ ├── patches │ │ ├── BUILD.bazel │ │ ├── toolchains_llvm.patch │ │ └── toolchains_llvm_libc++.patch │ ├── platform │ │ └── BUILD.bazel │ └── toolchain.MODULE.bazel ├── generic │ ├── .bazelrc │ ├── .bazelrc.common │ ├── BUILD.bazel │ ├── MODULE.bazel │ ├── README.md │ ├── WORKSPACE.bazel │ ├── build_settings │ │ └── BUILD.bazel │ ├── extend │ │ ├── BUILD.bazel │ │ ├── defs.bzl │ │ └── hello.txt │ ├── load │ │ ├── BUILD.bazel │ │ └── hello.txt │ ├── multi_deploy │ │ └── BUILD.bazel │ └── platform │ │ └── BUILD.bazel ├── go │ ├── .bazelrc │ ├── .bazelrc.common │ ├── BUILD.bazel │ ├── MODULE.bazel │ ├── README.md │ ├── WORKSPACE.bazel │ ├── customization │ │ └── BUILD.bazel │ ├── image │ │ └── BUILD.bazel │ ├── main.go │ ├── multiarch │ │ └── BUILD.bazel │ └── tools │ │ └── workspace_status.sh ├── js │ ├── .bazelignore │ ├── .bazelrc │ ├── .bazelrc.common │ ├── .npmrc │ ├── BUILD.bazel │ ├── MODULE.bazel │ ├── WORKSPACE.bazel │ ├── app │ │ ├── BUILD.bazel │ │ └── main.js │ ├── package.json │ ├── platform │ │ └── BUILD.bazel │ └── pnpm-lock.yaml ├── python │ ├── .bazelrc │ ├── .bazelrc.common │ ├── BUILD.bazel │ ├── MODULE.bazel │ ├── README.md │ ├── WORKSPACE.bazel │ ├── __init__.py │ ├── __main__.py │ ├── app.py │ ├── platform │ │ └── BUILD.bazel │ └── requirements │ │ ├── BUILD.bazel │ │ ├── requirements.in │ │ └── requirements_lock.txt └── workspace │ ├── .bazelrc │ ├── .bazelrc.common │ ├── BUILD.bazel │ └── WORKSPACE.bazel ├── flake.lock ├── flake.nix ├── img ├── BUILD.bazel ├── constraints │ └── BUILD.bazel ├── dependencies.bzl ├── image.bzl ├── image_toolchain.bzl ├── layer.bzl ├── load.bzl ├── multi_deploy.bzl ├── private │ ├── BUILD.bazel │ ├── common │ │ ├── BUILD.bazel │ │ ├── build.bzl │ │ ├── layer_helper.bzl │ │ ├── transitions.bzl │ │ └── write_index_json.bzl │ ├── config │ │ ├── BUILD.bazel │ │ └── defs.bzl │ ├── download_blobs.bzl │ ├── file_metadata.bzl │ ├── image_toolchain.bzl │ ├── import.bzl │ ├── index.bzl │ ├── integration_test_runner │ │ ├── BUILD.bazel │ │ └── integration_test_runner.go │ ├── layer.bzl │ ├── layer_from_tar.bzl │ ├── load.bzl │ ├── manifest.bzl │ ├── multi_deploy.bzl │ ├── platforms │ │ ├── BUILD.bazel │ │ └── platforms.bzl │ ├── prebuilt │ │ ├── BUILD.bazel │ │ └── prebuilt.bzl │ ├── providers │ │ ├── BUILD.bazel │ │ ├── deploy_info.bzl │ │ ├── image_toolchain_info.bzl │ │ ├── index_info.bzl │ │ ├── layer_info.bzl │ │ ├── load_settings_info.bzl │ │ ├── manifest_info.bzl │ │ ├── oci_layout_settings_info.bzl │ │ ├── pull_info.bzl │ │ ├── push_settings_info.bzl │ │ └── stamp_setting_info.bzl │ ├── push.bzl │ ├── release │ │ ├── BUILD.bazel │ │ ├── bcr │ │ │ ├── BUILD.bazel │ │ │ └── bcr.go │ │ ├── defs.bzl │ │ ├── distdir │ │ │ ├── BUILD.bazel │ │ │ └── distdir.go │ │ ├── gazelle_plugin │ │ │ ├── BUILD.bazel │ │ │ ├── all_files.go │ │ │ ├── cmd │ │ │ │ └── update_release_files │ │ │ │ │ ├── BUILD.bazel │ │ │ │ │ └── main.go │ │ │ ├── release_files_updated.bzl │ │ │ └── test_wrapper.sh │ │ ├── lockfile │ │ │ ├── BUILD.bazel │ │ │ └── lockfile.go │ │ ├── release_notes │ │ │ ├── BUILD.bazel │ │ │ └── release_notes.go │ │ └── source_files │ │ │ └── BUILD.bazel │ ├── repository_rules │ │ ├── BUILD.bazel │ │ ├── download.bzl │ │ ├── pull.bzl │ │ ├── pull_blob.bzl │ │ └── toolchains_repo.bzl │ ├── resolved_toolchain.bzl │ ├── root_symlinks.bzl │ ├── settings │ │ ├── BUILD.bazel │ │ ├── load.bzl │ │ ├── oci_layout.bzl │ │ ├── settings.bzl │ │ └── stamp.bzl │ └── stamp.bzl ├── providers.bzl ├── pull.bzl ├── push.bzl ├── repositories.bzl └── settings │ └── BUILD.bazel ├── img_tool ├── .bazelrc ├── .bazelrc.common ├── BUILD.bazel ├── MODULE.bazel ├── cmd │ ├── BUILD.bazel │ ├── bes │ │ ├── BUILD.bazel │ │ └── bes.go │ ├── compress │ │ ├── BUILD.bazel │ │ ├── compress.go │ │ └── flagtypes.go │ ├── deploy │ │ ├── BUILD.bazel │ │ ├── merge.go │ │ └── metadata.go │ ├── dockersave │ │ ├── BUILD.bazel │ │ ├── dockersave.go │ │ ├── flags.go │ │ └── sink.go │ ├── downloadblob │ │ ├── BUILD.bazel │ │ └── downloadblob.go │ ├── expandtemplate │ │ ├── BUILD.bazel │ │ └── expandtemplate.go │ ├── img │ │ ├── BUILD.bazel │ │ └── img.go │ ├── index │ │ ├── BUILD.bazel │ │ ├── flags.go │ │ └── index.go │ ├── layer │ │ ├── BUILD.bazel │ │ ├── flagtypes.go │ │ ├── layer.go │ │ ├── metadata.go │ │ └── paramfile.go │ ├── layermeta │ │ ├── BUILD.bazel │ │ ├── flagtypes.go │ │ └── layermeta.go │ ├── manifest │ │ ├── BUILD.bazel │ │ ├── flagtypes.go │ │ └── manifest.go │ ├── ocilayout │ │ ├── BUILD.bazel │ │ ├── copy_linux.go │ │ ├── copy_other.go │ │ ├── flags.go │ │ ├── ocilayout.go │ │ └── sink.go │ ├── push │ │ ├── BUILD.bazel │ │ └── push.go │ ├── registry │ │ ├── BUILD.bazel │ │ ├── flagtypes.go │ │ └── registry.go │ └── validate │ │ ├── BUILD.bazel │ │ ├── layer-presence │ │ ├── BUILD.bazel │ │ ├── flags.go │ │ └── layerpresence.go │ │ └── validate.go ├── go.mod ├── go.sum ├── go_proto_library.bzl ├── pkg │ ├── api │ │ ├── BUILD.bazel │ │ ├── api.go │ │ ├── binary.go │ │ ├── commands.go │ │ └── deploy.go │ ├── auth │ │ ├── credential │ │ │ ├── BUILD.bazel │ │ │ ├── credentialhelper.go │ │ │ └── credentialhelper_test.go │ │ ├── grpcheaderinterceptor │ │ │ ├── BUILD.bazel │ │ │ └── grpcheaderinterceptor.go │ │ ├── protohelper │ │ │ ├── BUILD.bazel │ │ │ └── protohelper.go │ │ └── registry │ │ │ ├── BUILD.bazel │ │ │ └── registry.go │ ├── cas │ │ ├── BUILD.bazel │ │ ├── error.go │ │ ├── read.go │ │ └── write.go │ ├── compress │ │ ├── BUILD.bazel │ │ ├── compress.go │ │ ├── estargz.go │ │ ├── factory.go │ │ ├── options.go │ │ └── util │ │ │ ├── BUILD.bazel │ │ │ └── util.go │ ├── containerd │ │ ├── BUILD.bazel │ │ ├── client.go │ │ ├── content.go │ │ ├── images.go │ │ ├── lease.go │ │ ├── namespace.go │ │ └── support.go │ ├── contentmanifest │ │ ├── BUILD.bazel │ │ ├── contentmanifest.go │ │ ├── multiimporter.go │ │ └── nopexporter.go │ ├── deployvfs │ │ ├── BUILD.bazel │ │ ├── deployvfs.go │ │ ├── image.go │ │ └── index.go │ ├── digestfs │ │ ├── BUILD.bazel │ │ ├── digestfs.go │ │ └── precacher.go │ ├── docker │ │ ├── BUILD.bazel │ │ ├── load.go │ │ └── stream.go │ ├── fileopener │ │ ├── BUILD.bazel │ │ └── fileopener.go │ ├── load │ │ ├── BUILD.bazel │ │ ├── load.go │ │ └── loader.go │ ├── proto │ │ ├── bazel │ │ │ ├── BUILD.bazel │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── google │ │ │ │ │ └── devtools │ │ │ │ │ └── build │ │ │ │ │ └── lib │ │ │ │ │ ├── buildeventstream │ │ │ │ │ ├── BUILD.bazel │ │ │ │ │ ├── build_event_stream.pb.go │ │ │ │ │ └── build_event_stream.proto │ │ │ │ │ └── packages │ │ │ │ │ └── metrics │ │ │ │ │ ├── BUILD.bazel │ │ │ │ │ ├── package_load_metrics.pb.go │ │ │ │ │ └── package_load_metrics.proto │ │ │ │ └── protobuf │ │ │ │ ├── BUILD.bazel │ │ │ │ ├── action_cache.pb.go │ │ │ │ ├── action_cache.proto │ │ │ │ ├── command_line.pb.go │ │ │ │ ├── command_line.proto │ │ │ │ ├── failure_details.pb.go │ │ │ │ ├── failure_details.proto │ │ │ │ ├── invocation_policy.pb.go │ │ │ │ ├── invocation_policy.proto │ │ │ │ ├── option_filters.pb.go │ │ │ │ ├── option_filters.proto │ │ │ │ ├── strategy_policy.pb.go │ │ │ │ └── strategy_policy.proto │ │ ├── blobcache │ │ │ ├── BUILD.bazel │ │ │ ├── blobcache.pb.go │ │ │ ├── blobcache.proto │ │ │ └── blobcache_grpc.pb.go │ │ ├── build_event_service │ │ │ ├── BUILD.bazel │ │ │ ├── build_events.pb.go │ │ │ ├── build_status.pb.go │ │ │ └── publish_build_event.pb.go │ │ └── remote-apis │ │ │ ├── BUILD.bazel │ │ │ └── build │ │ │ └── bazel │ │ │ ├── remote │ │ │ └── execution │ │ │ │ └── v2 │ │ │ │ ├── BUILD.bazel │ │ │ │ ├── remote_execution.pb.go │ │ │ │ ├── remote_execution.proto │ │ │ │ └── remote_execution_grpc.pb.go │ │ │ └── semver │ │ │ ├── BUILD.bazel │ │ │ ├── semver.pb.go │ │ │ └── semver.proto │ ├── push │ │ ├── BUILD.bazel │ │ └── push.go │ ├── serve │ │ ├── bes │ │ │ ├── BUILD.bazel │ │ │ ├── bes.go │ │ │ └── syncer │ │ │ │ ├── BUILD.bazel │ │ │ │ └── syncer.go │ │ ├── blobcache │ │ │ ├── BUILD.bazel │ │ │ └── blobcache.go │ │ └── registry │ │ │ ├── BUILD.bazel │ │ │ ├── blobsizecache.go │ │ │ ├── combined.go │ │ │ ├── reapi │ │ │ ├── BUILD.bazel │ │ │ └── reapi.go │ │ │ ├── s3 │ │ │ ├── BUILD.bazel │ │ │ └── s3.go │ │ │ └── upstream │ │ │ ├── BUILD.bazel │ │ │ └── upstream.go │ ├── tarcas │ │ ├── BUILD.bazel │ │ ├── factory.go │ │ ├── options.go │ │ ├── tarcas.go │ │ └── tarmetadata.go │ └── tree │ │ ├── BUILD.bazel │ │ ├── merkle │ │ ├── BUILD.bazel │ │ ├── merkle.go │ │ ├── treehasher.go │ │ └── types.go │ │ ├── recorder.go │ │ ├── runfiles │ │ ├── BUILD.bazel │ │ └── runfiles.go │ │ └── treeartifact │ │ ├── BUILD.bazel │ │ └── treeartifact.go ├── toolchain │ └── BUILD.bazel └── tools │ ├── BUILD.bazel │ ├── gopackagesdriver-nix.sh │ └── gopackagesdriver.sh ├── prebuilt_lockfile.json ├── pull_tool ├── .bazelrc ├── .bazelrc.common ├── BUILD.bazel ├── MODULE.bazel ├── cmd │ ├── downloadblob │ │ ├── BUILD.bazel │ │ └── downloadblob.go │ ├── internal │ │ └── pull │ │ │ ├── BUILD.bazel │ │ │ └── pull.go │ └── pull_tool │ │ ├── BUILD.bazel │ │ └── pull_tool.go ├── go.mod ├── go.sum ├── pkg │ └── auth │ │ └── registry │ │ ├── BUILD.bazel │ │ └── registry.go └── pull │ └── private │ ├── BUILD.bazel │ └── pull_bootstrap.bzl ├── pull_tool_lockfile.json ├── renovate.json ├── testdata ├── BUILD.bazel └── ubuntu │ ├── blobs │ └── sha256 │ │ ├── 007954392b50fbb4d9669775b8a5da9815347b7a44e1f6fee3d79eb9b5e889c4 │ │ ├── 1dca63d9115cd113e9ec3bbf54d1df6e6a30b45c0c3e31f0f259167cd9b8a074 │ │ ├── 1e622c5f073b4f6bfad6632f2616c7f59ef256e96fe78bf6a595d1dc4376ac02 │ │ ├── 21818a28a0ba9b93003d382b6165aa8e222e80e0c514df32b8cc8849c5d5b0bf │ │ ├── 2abc3421f7c2f72a04e5c749eb23d6d834470cc8e7e2a8b4f4ffb2460a1c92e9 │ │ ├── 48d9fe745f1a71878d49aab1623a62782bd5d200d259b1502f4ed1591e8d6004 │ │ ├── 5a71a5244bb433561f8bc908e1ed5c0ab81d28a63d1f50a489a619cd60d89733 │ │ ├── 602eb6fb314b5fafad376a32ab55194e535e533dec6552f82b70d7ac0e554b1c │ │ ├── 66f54a86848b28b65d2e043af21bede6e0b731fda40bd7e401f5fd06113db84e │ │ ├── 6ef9ec95193a604ccbbdbcbd67c61add101017bb776387c667dfbb87ff5319f5 │ │ ├── 74f38fa7c32fd13263ce430206bc5d046dce1543e5263d47919b85a64ccd128b │ │ ├── 7fc8925289a890695754108847a52df143c50fb950d185b28ec19be502d09071 │ │ ├── 8fe30db6f4cded743d10faed55c5b7d1c49b3a56b55967923fd738e66153e5a0 │ │ ├── 92c447e8272fc77dae7baa83d526200d696d536bb6efab11056e2c07c7041032 │ │ ├── 97b5e4984a1c353da6a9406c84554aab0422735a1335427a9e883ac477bd71df │ │ ├── b416553149aff82057bd12e41752a0a9040f1271f20886c698f7dcc9b3bad3c4 │ │ ├── b78100d465e7747e775812b96e0fd23d8aa655ec884b0de56038f4584e1f0571 │ │ ├── b8e917dce6fe31d9f6804908aa9cf2c5366aa5286e6a71e9ce75f58497f546fa │ │ ├── d10afaaf8670c9229d902bab8f43945d9a22b14f3c98c7b5d39d6530066027c2 │ │ ├── d25a22bccb9b10015295a27960b618910e90c41a843db543fdc192e74fded660 │ │ ├── d776fa41f2cdbe0504029636136c7756e3a743f8de66cef72e9d7aa5d220061a │ │ ├── e0e13023bde260c25f24c8efabd322adc745a16c0d6fb2a2714393071b4e5946 │ │ ├── e5719e2a817892a6751f019335bbbdf9e52bfa1019645da48495d05952f86195 │ │ ├── f8b860e4f9036f2694571770da292642eebcc4c2ea0c70a1a9244c2a1d436cd9 │ │ └── faeeccc166857094a7089a1b67813f4b0fe18a3195c3a47da6f1e8d0ca4b26ef │ ├── config │ ├── manifest │ └── root ├── tests ├── compression │ ├── BUILD.bazel │ └── defs.bzl └── img_toolchain │ ├── BUILD.bazel │ ├── README.md │ ├── framework.go │ ├── img_toolchain_test.go │ └── testcases │ ├── compress_ubuntu_blob.ini │ ├── compress_with_annotations.ini │ ├── dockersave_directory.ini │ ├── dockersave_format_validation.ini │ ├── dockersave_tar.ini │ ├── expandtemplate_with_stamps.ini │ ├── layer_comprehensive.ini │ ├── layer_gzip_level1_singlethread.ini │ ├── layer_gzip_level9_singlethread.ini │ ├── layer_help.ini │ ├── layer_pgzip_auto.ini │ ├── layer_pgzip_jobs2.ini │ ├── layer_real_ubuntu_config.ini │ ├── layer_simple.ini │ ├── layer_tar_assertions.ini │ ├── layer_unused_metadata_error.ini │ ├── layer_unused_metadata_single_error.ini │ ├── layer_with_file_metadata.ini │ ├── layer_with_ubuntu_blobs.ini │ ├── manifest_basic.ini │ ├── manifest_comprehensive.ini │ ├── manifest_layer_integration.ini │ ├── manifest_with_testdata.ini │ ├── ocilayout_basic.ini │ ├── ocilayout_directory.ini │ ├── ocilayout_format_validation.ini │ └── ocilayout_tar.ini └── util └── BUILD.bazel /.aspect/workflows/config.yaml: -------------------------------------------------------------------------------- 1 | # See https://docs.aspect.build/workflows/configuration 2 | --- 3 | tasks: 4 | # Note: we don't support Bazel 6 or earlier 5 | - test: 6 | name: Bazel 8 7 | id: bazel-8 8 | env: 9 | USE_BAZEL_VERSION: 8.x 10 | targets: 11 | - "//..." 12 | - "@rules_img_tool//..." 13 | - "@rules_img_pull_tool//..." 14 | - test: 15 | name: Integration Tests 16 | id: integration-tests 17 | targets: ["//e2e:integration_tests"] 18 | # TODO(malte): enable Bazel 9 when green 19 | # - test: 20 | # name: Bazel 9 21 | # id: bazel-9 22 | # env: 23 | # USE_BAZEL_VERSION: rolling 24 | - buildifier: 25 | queue: aspect-small 26 | target: //util:buildifier.check 27 | notifications: 28 | github: {} 29 | -------------------------------------------------------------------------------- /.bazelignore: -------------------------------------------------------------------------------- 1 | .direnv 2 | benchmark 3 | e2e/cc/bazel-bin 4 | e2e/cc/bazel-cc 5 | e2e/cc/bazel-out 6 | e2e/cc/bazel-testlogs 7 | e2e/generic/bazel-bin 8 | e2e/generic/bazel-generic 9 | e2e/generic/bazel-out 10 | e2e/generic/bazel-testlogs 11 | e2e/go/bazel-bin 12 | e2e/go/bazel-go 13 | e2e/go/bazel-out 14 | e2e/go/bazel-testlogs 15 | e2e/js/bazel-bin 16 | e2e/js/bazel-js 17 | e2e/js/bazel-out 18 | e2e/js/bazel-testlogs 19 | e2e/python/bazel-bin 20 | e2e/python/bazel-out 21 | e2e/python/bazel-python 22 | e2e/python/bazel-testlogs 23 | e2e/workspace/bazel-bin 24 | e2e/workspace/bazel-out 25 | e2e/workspace/bazel-testlogs 26 | e2e/workspace/bazel-workspace 27 | img_tool/bazel-bin 28 | img_tool/bazel-img_tool 29 | img_tool/bazel-out 30 | img_tool/bazel-testlogs 31 | pull_tool/bazel-bin 32 | pull_tool/bazel-out 33 | pull_tool/bazel-pull_tool 34 | pull_tool/bazel-rules_img_pull_tool 35 | pull_tool/bazel-testlogs 36 | -------------------------------------------------------------------------------- /.bazelrc.common: -------------------------------------------------------------------------------- 1 | # avoid writing a lockfile in this repo. 2 | # docs: https://bazel.build/reference/command-line-reference#flag--lockfile_mode 3 | common --lockfile_mode=off 4 | 5 | # normalize environment variables for hermeticity and reproducibility 6 | # docs: https://bazel.build/reference/command-line-reference#flag--incompatible_strict_action_env 7 | build --incompatible_strict_action_env 8 | 9 | # prevent actions from accidentaly depending on the network 10 | # docs: https://bazel.build/reference/command-line-reference#flag--sandbox_default_allow_network 11 | build --sandbox_default_allow_network=false 12 | 13 | # docs: https://bazel.build/reference/command-line-reference#flag--test_output 14 | test --test_output=errors 15 | # docs: https://bazel.build/reference/command-line-reference#flag--test_verbose_timeout_warnings 16 | test --test_verbose_timeout_warnings 17 | 18 | # make Bazel integration tests work on Windows 19 | # docs: https://bazel.build/reference/command-line-reference#flag--enable_runfiles 20 | common --enable_runfiles 21 | # docs: https://bazel.build/reference/command-line-reference#startup_options-flag--windows_enable_symlinks 22 | startup --windows_enable_symlinks 23 | 24 | # ensure correct config_setting visibility 25 | # docs: https://bazel.build/reference/command-line-reference#build-flag--incompatible_config_setting_private_default_visibility 26 | build --incompatible_config_setting_private_default_visibility 27 | 28 | # enable rule extension API (needed prior to Bazel 8) 29 | # docs: https://bazel.build/versions/7.4.0/reference/command-line-reference#flag--experimental_rule_extension_api 30 | build --experimental_rule_extension_api 31 | 32 | # enable protobuf toolchain resolution 33 | # docs: https://bazel.build/reference/command-line-reference#common_options-flag--incompatible_enable_proto_toolchain_resolution 34 | common --incompatible_enable_proto_toolchain_resolution 35 | -------------------------------------------------------------------------------- /.bcr/config.yml: -------------------------------------------------------------------------------- 1 | moduleRoots: 2 | - "." 3 | - "img_tool" 4 | - "pull_tool" 5 | -------------------------------------------------------------------------------- /.bcr/img_tool/metadata.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "homepage": "https://github.com/bazel-contrib/rules_img", 3 | "maintainers": [ 4 | { 5 | "name": "Malte Poll", 6 | "email": "malte.poll@moduscreate.com", 7 | "github": "malt3" 8 | } 9 | ], 10 | "repository": [ 11 | "github:bazel-contrib/rules_img" 12 | ], 13 | "versions": [], 14 | "yanked_versions": {} 15 | } 16 | -------------------------------------------------------------------------------- /.bcr/img_tool/presubmit.yml: -------------------------------------------------------------------------------- 1 | bcr_test_module: 2 | module_path: "." 3 | matrix: 4 | platform: ["debian10", "ubuntu2004", "macos", "macos_arm64", "windows", "windows_arm64"] 5 | bazel: [8.x] 6 | tasks: 7 | run_tests: 8 | name: "Run test module" 9 | platform: ${{ platform }} 10 | bazel: ${{ bazel }} 11 | build_targets: 12 | - "//..." 13 | test_targets: 14 | - "//..." 15 | -------------------------------------------------------------------------------- /.bcr/img_tool/source.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "integrity": "", 3 | "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/rules_img_tool-{TAG}.tar.gz" 4 | } 5 | -------------------------------------------------------------------------------- /.bcr/metadata.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "homepage": "https://github.com/bazel-contrib/rules_img", 3 | "maintainers": [ 4 | { 5 | "name": "Malte Poll", 6 | "email": "malte.poll@moduscreate.com", 7 | "github": "malt3" 8 | } 9 | ], 10 | "repository": [ 11 | "github:bazel-contrib/rules_img" 12 | ], 13 | "versions": [], 14 | "yanked_versions": {} 15 | } 16 | -------------------------------------------------------------------------------- /.bcr/presubmit.yml: -------------------------------------------------------------------------------- 1 | bcr_test_module: 2 | module_path: "." 3 | matrix: 4 | platform: ["debian10", "ubuntu2004", "macos", "macos_arm64", "windows", "windows_arm64"] 5 | bazel: [7.x, 8.x, rolling] 6 | tasks: 7 | run_tests: 8 | name: "Run test module" 9 | platform: ${{ platform }} 10 | bazel: ${{ bazel }} 11 | build_targets: 12 | - "//..." 13 | -------------------------------------------------------------------------------- /.bcr/pull_tool/metadata.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "homepage": "https://github.com/bazel-contrib/rules_img", 3 | "maintainers": [ 4 | { 5 | "name": "Malte Poll", 6 | "email": "malte.poll@moduscreate.com", 7 | "github": "malt3" 8 | } 9 | ], 10 | "repository": [ 11 | "github:bazel-contrib/rules_img" 12 | ], 13 | "versions": [], 14 | "yanked_versions": {} 15 | } 16 | -------------------------------------------------------------------------------- /.bcr/pull_tool/presubmit.yml: -------------------------------------------------------------------------------- 1 | bcr_test_module: 2 | module_path: "." 3 | matrix: 4 | platform: ["debian10", "ubuntu2004", "macos", "macos_arm64", "windows", "windows_arm64"] 5 | bazel: [7.x, 8.x] 6 | tasks: 7 | run_tests: 8 | name: "Run test module" 9 | platform: ${{ platform }} 10 | bazel: ${{ bazel }} 11 | build_targets: 12 | - "//..." 13 | test_targets: 14 | - "//..." 15 | -------------------------------------------------------------------------------- /.bcr/pull_tool/source.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "integrity": "", 3 | "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/rules_img_pull_tool-{TAG}.tar.gz" 4 | } 5 | -------------------------------------------------------------------------------- /.bcr/source.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "integrity": "", 3 | "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/rules_img-{TAG}.tar.gz", 4 | "docs_url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/rules_img-{TAG}.docs.tar.gz" 5 | } 6 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use flake 2 | -------------------------------------------------------------------------------- /.github/logo/dark_hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bazel-contrib/rules_img/b090f01e0de59675ce0bc808c44e73c6d0c016ca/.github/logo/dark_hero.jpg -------------------------------------------------------------------------------- /.github/logo/dark_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bazel-contrib/rules_img/b090f01e0de59675ce0bc808c44e73c6d0c016ca/.github/logo/dark_text.png -------------------------------------------------------------------------------- /.github/logo/light_hero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bazel-contrib/rules_img/b090f01e0de59675ce0bc808c44e73c6d0c016ca/.github/logo/light_hero.jpg -------------------------------------------------------------------------------- /.github/logo/light_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bazel-contrib/rules_img/b090f01e0de59675ce0bc808c44e73c6d0c016ca/.github/logo/light_text.png -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | categories: 3 | - title: ⭐ Highlights 4 | labels: 5 | - highlight 6 | - title: What's Changed 7 | labels: 8 | - "*" 9 | - title: 🏗️ Dependencies 10 | labels: 11 | - dependencies 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.bazelrc: -------------------------------------------------------------------------------- 1 | common --show_progress_rate_limit=5 2 | common --curses=no 3 | common --color=yes 4 | common --terminal_columns=120 5 | common --show_timestamps 6 | build --verbose_failures 7 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | # Publish new releases to Bazel Central Registry. 2 | name: Publish to BCR 3 | on: 4 | # Run the publish workflow after a successful release 5 | # Will be triggered from the release.yaml workflow 6 | workflow_call: 7 | inputs: 8 | tag_name: 9 | required: true 10 | type: string 11 | secrets: 12 | publish_token: 13 | required: true 14 | # In case of problems, let release engineers retry by manually dispatching 15 | # the workflow from the GitHub UI 16 | workflow_dispatch: 17 | inputs: 18 | tag_name: 19 | description: git tag being released 20 | required: true 21 | type: string 22 | jobs: 23 | publish: 24 | uses: bazel-contrib/publish-to-bcr/.github/workflows/publish.yaml@v1.0.0 25 | with: 26 | tag_name: ${{ inputs.tag_name }} 27 | # GitHub repository which is a fork of the upstream where the Pull Request will be opened. 28 | registry_fork: bazel-contrib/bazel-central-registry 29 | draft: false 30 | permissions: 31 | attestations: write 32 | contents: write 33 | id-token: write 34 | secrets: 35 | # Necessary to push to the BCR fork, and to open a pull request against a registry 36 | publish_token: ${{ secrets.publish_token || secrets.BCR_PUBLISH_TOKEN }} 37 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | # Cut a release whenever a new tag is pushed to the repo. 2 | name: Release 3 | on: 4 | # Can be triggered from the tag.yaml workflow 5 | workflow_call: 6 | inputs: 7 | tag_name: 8 | required: true 9 | type: string 10 | secrets: 11 | publish_token: 12 | required: true 13 | # Or, developers can manually push a tag from their clone 14 | push: 15 | tags: 16 | - "v*.*.*" 17 | permissions: 18 | id-token: write 19 | attestations: write 20 | contents: write 21 | jobs: 22 | release: 23 | uses: bazel-contrib/.github/.github/workflows/release_ruleset.yaml@v7.2.3 24 | with: 25 | release_files: | 26 | dist/rules_img-*.tar.gz 27 | dist/rules_img_tool-*.tar.gz 28 | dist/rules_img_pull_tool-*.tar.gz 29 | dist/img_linux_* 30 | dist/img_darwin_* 31 | dist/img_windows_*.exe 32 | dist/pull_tool_linux_* 33 | dist/pull_tool_darwin_* 34 | dist/pull_tool_windows_*.exe 35 | dist/*.docs.tar.gz 36 | prerelease: false 37 | tag_name: ${{ inputs.tag_name || github.ref_name }} 38 | secrets: 39 | inherit 40 | publish: 41 | needs: release 42 | uses: ./.github/workflows/publish.yaml 43 | with: 44 | tag_name: ${{ inputs.tag_name || github.ref_name }} 45 | secrets: 46 | publish_token: ${{ secrets.publish_token || secrets.BCR_PUBLISH_TOKEN }} 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | MODULE.bazel.lock 3 | bazel-* 4 | .bazelrc.user 5 | .vscode 6 | .direnv 7 | .env 8 | node_modules 9 | prebuilt_lockfile.json 10 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 4 | hooks: 5 | - id: check-yaml 6 | - id: end-of-file-fixer 7 | exclude: ^(testdata/|docs/.*\.md$) 8 | - id: trailing-whitespace 9 | exclude: ^docs/.*\.md$ 10 | # Check formatting and lint for starlark code 11 | - repo: https://github.com/keith/pre-commit-buildifier 12 | rev: 8.0.3 13 | hooks: 14 | - id: buildifier 15 | - id: buildifier-lint 16 | # Enforce that commit messages allow for later changelog generation 17 | - repo: https://github.com/commitizen-tools/commitizen 18 | rev: v4.7.1 19 | hooks: 20 | # Requires that commitizen is already installed 21 | - id: commitizen 22 | stages: [commit-msg] 23 | # Check validity of GitHub actions configuration 24 | - repo: https://github.com/mpalmer/action-validator 25 | rev: v0.6.0 26 | hooks: 27 | - id: action-validator 28 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | exports_files(["MODULE.bazel"]) 2 | 3 | # gazelle:prefix github.com/bazel-contrib/rules_img 4 | 5 | filegroup( 6 | name = "all_files", 7 | srcs = [ 8 | "BUILD.bazel", 9 | "LICENSE", 10 | "MODULE.bazel", 11 | ], 12 | visibility = ["//img/private/release:__subpackages__"], 13 | ) 14 | 15 | filegroup( 16 | name = "tool_source_files", 17 | srcs = glob( 18 | ["img_tool/**"], 19 | allow_empty = True, 20 | exclude = [ 21 | "img_tool/.bazelrc.common", 22 | "img_tool/.bazelrc", 23 | "img_tool/.vscode/**", 24 | "img_tool/tools/**", 25 | ], 26 | ), 27 | visibility = ["//img/private/release:__subpackages__"], 28 | ) 29 | 30 | filegroup( 31 | name = "pull_tool_source_files", 32 | srcs = glob( 33 | ["pull_tool/**"], 34 | allow_empty = True, 35 | exclude = [ 36 | "pull_tool/.bazelrc.common", 37 | "pull_tool/.bazelrc", 38 | "pull_tool/.vscode/**", 39 | "pull_tool/tools/**", 40 | ], 41 | ), 42 | visibility = ["//img/private/release:__subpackages__"], 43 | ) 44 | 45 | exports_files([ 46 | ".bcr/metadata.template.json", 47 | ".bcr/pull_tool/metadata.template.json", 48 | "prebuilt_lockfile.json", 49 | "pull_tool_lockfile.json", 50 | ]) 51 | -------------------------------------------------------------------------------- /docs/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@aspect_bazel_lib//lib:docs.bzl", "stardoc_with_diff_test", "update_docs") 2 | 3 | # gazelle:exclude_from_release 4 | 5 | stardoc_with_diff_test( 6 | name = "image", 7 | bzl_library_target = "//img:image", 8 | ) 9 | 10 | stardoc_with_diff_test( 11 | name = "layer", 12 | bzl_library_target = "//img:layer", 13 | ) 14 | 15 | stardoc_with_diff_test( 16 | name = "load", 17 | bzl_library_target = "//img:load", 18 | ) 19 | 20 | stardoc_with_diff_test( 21 | name = "push", 22 | bzl_library_target = "//img:push", 23 | ) 24 | 25 | stardoc_with_diff_test( 26 | name = "pull", 27 | bzl_library_target = "//img:pull", 28 | ) 29 | 30 | stardoc_with_diff_test( 31 | name = "multi_deploy", 32 | bzl_library_target = "//img:multi_deploy", 33 | ) 34 | 35 | # Update all generated documentation 36 | update_docs(name = "update") 37 | -------------------------------------------------------------------------------- /e2e/cc/.bazelrc: -------------------------------------------------------------------------------- 1 | common --enable_platform_specific_config 2 | 3 | import %workspace%/.bazelrc.common 4 | 5 | try-import %workspace%/.bazelrc.user 6 | -------------------------------------------------------------------------------- /e2e/cc/.bazelrc.common: -------------------------------------------------------------------------------- 1 | ../../.bazelrc.common -------------------------------------------------------------------------------- /e2e/cc/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@rules_cc//cc:defs.bzl", "cc_binary") 3 | load("@rules_img//img:image.bzl", "image_index", "image_manifest") 4 | load("@rules_img//img:layer.bzl", "image_layer") 5 | load("@rules_img//img:push.bzl", "image_push") 6 | 7 | cc_binary( 8 | name = "app", 9 | srcs = ["main.cc"], 10 | visibility = ["//visibility:public"], 11 | ) 12 | 13 | image_layer( 14 | name = "cc_layer", 15 | srcs = { 16 | "/bin/app": "//:app", 17 | }, 18 | ) 19 | 20 | image_manifest( 21 | name = "cc_image", 22 | base = "@distroless_cc", 23 | entrypoint = ["/bin/app"], 24 | layers = [ 25 | ":cc_layer", 26 | ], 27 | ) 28 | 29 | image_index( 30 | name = "cc_index", 31 | manifests = [":cc_image"], 32 | platforms = [ 33 | "//platform:linux_amd64_libstdc++", 34 | "//platform:linux_arm64_libstdc++", 35 | ], 36 | ) 37 | 38 | image_push( 39 | name = "push", 40 | image = ":cc_index", 41 | registry = "ghcr.io", 42 | repository = "malt3/rules_img/cc", 43 | tag = "libstdcxx", 44 | ) 45 | 46 | build_test( 47 | name = "test", 48 | targets = [ 49 | ":app", 50 | ":cc_layer", 51 | ":cc_image", 52 | ":cc_index", 53 | ":push", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /e2e/cc/MODULE.bazel: -------------------------------------------------------------------------------- 1 | module(name = "cc_e2e") 2 | 3 | # BEGIN BAZEL_DEP 4 | bazel_dep(name = "rules_img") 5 | local_path_override( 6 | module_name = "rules_img", 7 | path = "../..", 8 | ) 9 | 10 | bazel_dep(name = "rules_img_pull_tool") 11 | local_path_override( 12 | module_name = "rules_img_pull_tool", 13 | path = "../../pull_tool", 14 | ) 15 | 16 | bazel_dep(name = "rules_img_tool") 17 | local_path_override( 18 | module_name = "rules_img_tool", 19 | path = "../../img_tool", 20 | ) 21 | 22 | register_toolchains("@rules_img_tool//toolchain:all") 23 | # END BAZEL_DEP 24 | 25 | bazel_dep(name = "bazel_skylib", version = "1.8.1") 26 | bazel_dep(name = "platforms", version = "0.0.11") 27 | 28 | bazel_dep(name = "rules_cc", version = "0.2.9", dev_dependency = True) 29 | 30 | # All of the hermetic C++ toolchain setup is done in a separate MODULE.bazel file. 31 | # This setup is not important for the e2e tests and it is hard to read. 32 | include("//:toolchain.MODULE.bazel") 33 | 34 | pull = use_repo_rule("@rules_img//img:pull.bzl", "pull") 35 | 36 | pull( 37 | name = "distroless_cc", 38 | digest = "sha256:d1b8e4c52be1111aa108e959ef2a822299bb70fd1819dd250871a2601ca1e4b6", 39 | registry = "gcr.io", 40 | repository = "distroless/cc-debian12", 41 | tag = "nonroot", 42 | ) 43 | -------------------------------------------------------------------------------- /e2e/cc/WORKSPACE.bazel: -------------------------------------------------------------------------------- 1 | # this example uses MODULE.bazel 2 | -------------------------------------------------------------------------------- /e2e/cc/base/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_img//img:image.bzl", "image_index", "image_manifest") 2 | load("@rules_img//img:layer.bzl", "layer_from_tar") 3 | 4 | layer_from_tar( 5 | name = "layer_libc++", 6 | src = select({ 7 | "@platforms//cpu:arm64": "@base_image_arm64_libcxx//file", 8 | "@platforms//cpu:x86_64": "@base_image_amd64_libcxx//file", 9 | }), 10 | tags = ["manual"], 11 | target_compatible_with = select({ 12 | "@platforms//cpu:arm64": [], 13 | "@platforms//cpu:x86_64": [], 14 | }), 15 | ) 16 | 17 | layer_from_tar( 18 | name = "layer_libstdc++", 19 | src = select({ 20 | "@platforms//cpu:arm64": "@base_image_arm64_libstdcxx//file", 21 | "@platforms//cpu:x86_64": "@base_image_amd64_libstdcxx//file", 22 | }), 23 | tags = ["manual"], 24 | target_compatible_with = select({ 25 | "@platforms//cpu:arm64": [], 26 | "@platforms//cpu:x86_64": [], 27 | }), 28 | ) 29 | 30 | image_manifest( 31 | name = "manifest", 32 | layers = select({ 33 | "//platform:libc++": [":layer_libc++"], 34 | "//platform:libstdc++": [":layer_libstdc++"], 35 | }), 36 | tags = ["manual"], 37 | ) 38 | 39 | image_index( 40 | name = "base", 41 | manifests = [":manifest"], 42 | platforms = select({ 43 | "//platform:libc++": [ 44 | "//platform:linux_amd64_libc++", 45 | "//platform:linux_arm64_libc++", 46 | ], 47 | "//platform:libstdc++": [ 48 | "//platform:linux_amd64_libstdc++", 49 | "//platform:linux_arm64_libstdc++", 50 | ], 51 | }), 52 | tags = ["manual"], 53 | target_compatible_with = select({ 54 | "//platform:libc++": [], 55 | "//platform:libstdc++": [], 56 | }), 57 | visibility = ["//:__subpackages__"], 58 | ) 59 | -------------------------------------------------------------------------------- /e2e/cc/custom_standard_library/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@rules_img//img:image.bzl", "image_index", "image_manifest") 3 | load("@rules_img//img:layer.bzl", "image_layer") 4 | load("@rules_img//img:push.bzl", "image_push") 5 | 6 | image_layer( 7 | name = "cc_layer", 8 | srcs = { 9 | "/bin/app": "//:app", 10 | }, 11 | ) 12 | 13 | image_manifest( 14 | name = "cc_image", 15 | base = select({ 16 | "//platform:libc++": "//base", 17 | "//platform:libstdc++": "//base", 18 | "//conditions:default": None, 19 | }), 20 | entrypoint = ["/bin/app"], 21 | layers = [ 22 | ":cc_layer", 23 | ], 24 | ) 25 | 26 | image_index( 27 | name = "cc_index_libc++", 28 | manifests = [":cc_image"], 29 | platforms = [ 30 | "//platform:linux_amd64_libc++", 31 | "//platform:linux_arm64_libc++", 32 | ], 33 | ) 34 | 35 | image_index( 36 | name = "cc_index_libstdc++", 37 | manifests = [":cc_image"], 38 | platforms = [ 39 | "//platform:linux_amd64_libstdc++", 40 | "//platform:linux_arm64_libstdc++", 41 | ], 42 | ) 43 | 44 | image_push( 45 | name = "push_libc++", 46 | image = ":cc_index_libc++", 47 | registry = "ghcr.io", 48 | repository = "malt3/rules_img/cc", 49 | tag = "libcxx", 50 | ) 51 | 52 | image_push( 53 | name = "push_libstdc++", 54 | image = ":cc_index_libstdc++", 55 | registry = "ghcr.io", 56 | repository = "malt3/rules_img/cc", 57 | tag = "libstdcxx", 58 | ) 59 | 60 | build_test( 61 | name = "test", 62 | targets = [ 63 | ":cc_layer", 64 | ":cc_image", 65 | ":cc_index_libc++", 66 | ":cc_index_libstdc++", 67 | ":push_libc++", 68 | ":push_libstdc++", 69 | ], 70 | ) 71 | -------------------------------------------------------------------------------- /e2e/cc/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello, World!" << std::endl; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /e2e/cc/patches/BUILD.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bazel-contrib/rules_img/b090f01e0de59675ce0bc808c44e73c6d0c016ca/e2e/cc/patches/BUILD.bazel -------------------------------------------------------------------------------- /e2e/cc/patches/toolchains_llvm_libc++.patch: -------------------------------------------------------------------------------- 1 | From b6cd132a1565ef59b9c63fc1b117ca8aa88a3e6e Mon Sep 17 00:00:00 2001 2 | From: Malte Poll <1780588+malt3@users.noreply.github.com> 3 | Date: Wed, 14 May 2025 17:39:20 +0200 4 | Subject: [PATCH] toolchain config: use "-l:libc++.a" and "-l:libc++abi.a" in 5 | sysroot 6 | 7 | When cross compiling with a sysroot, the toolchain defaults to 8 | libstdc++. 9 | However, if a user specifically select libc++ like so: 10 | 11 | ``` 12 | stdlib = { 13 | "linux-aarch64": "libc++", 14 | "linux-x86_64": "libc++", 15 | }, 16 | 17 | ``` 18 | 19 | ... we emit invalid linker flags. For all sysroots I could find, 20 | the name of the archive is "libc++.a" and "libc++abi.a", not "c++.a". 21 | --- 22 | toolchain/cc_toolchain_config.bzl | 4 ++-- 23 | 1 file changed, 2 insertions(+), 2 deletions(-) 24 | 25 | diff --git a/toolchain/cc_toolchain_config.bzl b/toolchain/cc_toolchain_config.bzl 26 | index 7e6a38e..b3d692c 100644 27 | --- a/toolchain/cc_toolchain_config.bzl 28 | +++ b/toolchain/cc_toolchain_config.bzl 29 | @@ -241,8 +241,8 @@ def cc_toolchain_config( 30 | ] 31 | 32 | link_flags.extend([ 33 | - "-l:c++.a", 34 | - "-l:c++abi.a", 35 | + "-l:libc++.a", 36 | + "-l:libc++abi.a", 37 | ]) 38 | elif stdlib == "stdc++": 39 | cxx_flags = [ 40 | -- 41 | 2.47.2 42 | -------------------------------------------------------------------------------- /e2e/cc/platform/BUILD.bazel: -------------------------------------------------------------------------------- 1 | package( 2 | default_visibility = ["//visibility:public"], 3 | ) 4 | 5 | platform( 6 | name = "linux_amd64_libstdc++", 7 | constraint_values = [ 8 | "@platforms//os:linux", 9 | "@platforms//cpu:x86_64", 10 | ":libstdc++", 11 | ], 12 | ) 13 | 14 | platform( 15 | name = "linux_amd64_libc++", 16 | constraint_values = [ 17 | "@platforms//os:linux", 18 | "@platforms//cpu:x86_64", 19 | ":libc++", 20 | ], 21 | ) 22 | 23 | platform( 24 | name = "linux_arm64_libstdc++", 25 | constraint_values = [ 26 | "@platforms//os:linux", 27 | "@platforms//cpu:aarch64", 28 | ":libstdc++", 29 | ], 30 | ) 31 | 32 | platform( 33 | name = "linux_arm64_libc++", 34 | constraint_values = [ 35 | "@platforms//os:linux", 36 | "@platforms//cpu:aarch64", 37 | ":libc++", 38 | ], 39 | ) 40 | 41 | constraint_setting(name = "stdlib") 42 | 43 | constraint_value( 44 | name = "libstdc++", 45 | constraint_setting = ":stdlib", 46 | ) 47 | 48 | constraint_value( 49 | name = "libc++", 50 | constraint_setting = ":stdlib", 51 | ) 52 | -------------------------------------------------------------------------------- /e2e/generic/.bazelrc: -------------------------------------------------------------------------------- 1 | import %workspace%/.bazelrc.common 2 | 3 | try-import %workspace%/.bazelrc.user 4 | -------------------------------------------------------------------------------- /e2e/generic/.bazelrc.common: -------------------------------------------------------------------------------- 1 | ../../.bazelrc.common -------------------------------------------------------------------------------- /e2e/generic/WORKSPACE.bazel: -------------------------------------------------------------------------------- 1 | # This file marks this directory as a bazel workspace. 2 | # This file is intentionally empty. 3 | -------------------------------------------------------------------------------- /e2e/generic/build_settings/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:common_settings.bzl", "string_flag") 2 | 3 | package(default_visibility = ["//visibility:public"]) 4 | 5 | string_flag( 6 | name = "registry", 7 | build_setting_default = "ghcr.io", 8 | ) 9 | 10 | string_flag( 11 | name = "user", 12 | build_setting_default = "malt3", 13 | ) 14 | 15 | string_flag( 16 | name = "tag", 17 | build_setting_default = "templated_tag", 18 | ) 19 | -------------------------------------------------------------------------------- /e2e/generic/extend/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@rules_img//img:push.bzl", "image_push") 3 | load(":defs.bzl", "customized_image_index", "customized_image_layer", "customized_image_manifest") 4 | 5 | customized_image_layer( 6 | name = "layer", 7 | srcs = { 8 | "/hello.txt": ":hello.txt", 9 | }, 10 | comment = "This is a customized layer", 11 | ) 12 | 13 | customized_image_manifest( 14 | name = "image", 15 | base = "@alpine", 16 | comment = "This is a customized image", 17 | layers = [":layer"], 18 | ) 19 | 20 | customized_image_index( 21 | name = "index", 22 | comment = "This is a customized image index", 23 | manifests = [":image"], 24 | ) 25 | 26 | image_push( 27 | name = "push", 28 | image = ":index", 29 | registry = "ghcr.io", 30 | repository = "malt3/rules_img/e2e-generic-extend", 31 | visibility = ["//visibility:public"], 32 | ) 33 | 34 | build_test( 35 | name = "test", 36 | targets = [ 37 | ":layer", 38 | ":image", 39 | ":index", 40 | ":push", 41 | ], 42 | ) 43 | -------------------------------------------------------------------------------- /e2e/generic/extend/hello.txt: -------------------------------------------------------------------------------- 1 | Hello from rules_img extension test! 2 | -------------------------------------------------------------------------------- /e2e/generic/load/hello.txt: -------------------------------------------------------------------------------- 1 | Hello from rules_img load test! 2 | -------------------------------------------------------------------------------- /e2e/generic/multi_deploy/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_img//img:multi_deploy.bzl", "multi_deploy") 2 | load("@rules_img//img:push.bzl", "image_push") 3 | 4 | image_push( 5 | name = "nginx", 6 | image = "@nginx", 7 | registry = "ghcr.io", 8 | repository = "malt3/nginx", 9 | ) 10 | 11 | multi_deploy( 12 | name = "multi_deploy", 13 | operations = [ 14 | ":nginx", 15 | "//extend:push", 16 | "//load:load_image", 17 | "//load:load_image_templated", 18 | "//load:load_index", 19 | "//load:load_alpine", 20 | "//:push_single_layer", 21 | "//:push_multi_layer", 22 | "//:push_annotated", 23 | "//:push_index", 24 | "//:push_complex", 25 | ], 26 | ) 27 | -------------------------------------------------------------------------------- /e2e/generic/platform/BUILD.bazel: -------------------------------------------------------------------------------- 1 | package( 2 | default_visibility = ["//visibility:public"], 3 | ) 4 | 5 | platform( 6 | name = "linux_amd64", 7 | constraint_values = [ 8 | "@platforms//os:linux", 9 | "@platforms//cpu:x86_64", 10 | ], 11 | ) 12 | 13 | platform( 14 | name = "linux_arm64", 15 | constraint_values = [ 16 | "@platforms//os:linux", 17 | "@platforms//cpu:aarch64", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /e2e/go/.bazelrc: -------------------------------------------------------------------------------- 1 | common --enable_platform_specific_config 2 | 3 | # enable pathmapping for supported platforms 4 | # this will speed up multi-platform builds 5 | common:macos --experimental_output_paths=strip 6 | common:linux --experimental_output_paths=strip 7 | 8 | common:stamp --stamp 9 | common:stamp --@rules_img//img/settings:stamp=enabled 10 | common:stamp --workspace_status_command=tools/workspace_status.sh 11 | 12 | import %workspace%/.bazelrc.common 13 | 14 | try-import %workspace%/.bazelrc.user 15 | -------------------------------------------------------------------------------- /e2e/go/.bazelrc.common: -------------------------------------------------------------------------------- 1 | ../../.bazelrc.common -------------------------------------------------------------------------------- /e2e/go/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 2 | load("@rules_img//img:multi_deploy.bzl", "multi_deploy") 3 | 4 | go_library( 5 | name = "app_lib", 6 | srcs = ["main.go"], 7 | importpath = "github.com/bazel-contrib/rules_img/e2e/go/image", 8 | visibility = ["//visibility:private"], 9 | ) 10 | 11 | go_binary( 12 | name = "app", 13 | embed = [":app_lib"], 14 | pure = "on", 15 | visibility = ["//visibility:public"], 16 | ) 17 | 18 | multi_deploy( 19 | name = "deploy_all", 20 | operations = [ 21 | "//customization:push", 22 | "//image:load", 23 | "//image:push", 24 | "//multiarch:push", 25 | ], 26 | ) 27 | -------------------------------------------------------------------------------- /e2e/go/MODULE.bazel: -------------------------------------------------------------------------------- 1 | module(name = "go_e2e") 2 | 3 | # BEGIN BAZEL_DEP 4 | bazel_dep(name = "rules_img") 5 | local_path_override( 6 | module_name = "rules_img", 7 | path = "../..", 8 | ) 9 | 10 | bazel_dep(name = "rules_img_pull_tool") 11 | local_path_override( 12 | module_name = "rules_img_pull_tool", 13 | path = "../../pull_tool", 14 | ) 15 | 16 | bazel_dep(name = "rules_img_tool") 17 | local_path_override( 18 | module_name = "rules_img_tool", 19 | path = "../../img_tool", 20 | ) 21 | 22 | register_toolchains("@rules_img_tool//toolchain:all") 23 | # END BAZEL_DEP 24 | 25 | bazel_dep(name = "rules_go", version = "0.57.0") 26 | bazel_dep(name = "bazel_skylib", version = "1.8.1") 27 | -------------------------------------------------------------------------------- /e2e/go/README.md: -------------------------------------------------------------------------------- 1 | # Go Container Image Examples 2 | 3 | This directory contains examples demonstrating different ways of building container images for Go applications using `rules_img`. The examples are ordered by increasing complexity, showcasing various features and use cases. 4 | 5 | ## Examples 6 | 7 | ### 1. [image/](./image/BUILD.bazel) - Basic Single-Platform Image 8 | 9 | The simplest example showing how to build a container image for a Go application: 10 | - Creates a single-platform container image with a Go binary 11 | - Uses the native platform (whatever platform Bazel is running on) 12 | - Demonstrates basic `image_layer` and `image_manifest` usage 13 | - Shows how to push images to a registry 14 | 15 | ### 3. [multiarch/](./multiarch/BUILD.bazel) - Automated Multi-Architecture Images 16 | 17 | The recommended approach for multi-platform container images: 18 | - Uses Bazel's platform transitions for automatic multi-platform builds 19 | - Creates an `image_index` containing both ARM64 and AMD64 variants 20 | - Minimal configuration - Bazel handles the platform-specific builds automatically 21 | 22 | ### 5. [customization/](./customization/BUILD.bazel) - Image Metadata and Configuration 23 | 24 | Demonstrates comprehensive image customization options: 25 | - Sets custom entrypoint with command arguments 26 | - Configures environment variables for the container 27 | - Adds OCI annotations for image metadata 28 | - Applies labels for compatibility with label-schema 29 | - Customizes runtime behavior (user, stop signal) 30 | - Shows all available configuration options in `image_manifest` 31 | 32 | ## Running the Examples 33 | 34 | Each example can be built and pushed using standard Bazel commands: 35 | 36 | ```bash 37 | # Build an image 38 | bazel build //image:go_image 39 | 40 | # Push to a registry 41 | bazel run //image:go_push 42 | 43 | # Build all examples 44 | bazel build //... 45 | ``` 46 | -------------------------------------------------------------------------------- /e2e/go/WORKSPACE.bazel: -------------------------------------------------------------------------------- 1 | # this example uses MODULE.bazel 2 | -------------------------------------------------------------------------------- /e2e/go/image/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@rules_img//img:image.bzl", "image_manifest") 3 | load("@rules_img//img:layer.bzl", "image_layer") 4 | load("@rules_img//img:load.bzl", "image_load") 5 | load("@rules_img//img:push.bzl", "image_push") 6 | 7 | image_layer( 8 | name = "go_layer", 9 | srcs = { 10 | "/bin/app": "//:app", 11 | }, 12 | ) 13 | 14 | image_manifest( 15 | name = "go_image", 16 | entrypoint = ["/bin/app"], 17 | layers = [ 18 | ":go_layer", 19 | ], 20 | ) 21 | 22 | image_push( 23 | name = "push", 24 | image = ":go_image", 25 | registry = "ghcr.io", 26 | repository = "malt3/rules_img/go", 27 | tag = "native", 28 | visibility = ["//:__pkg__"], 29 | ) 30 | 31 | image_load( 32 | name = "load", 33 | image = ":go_image", 34 | tag = "foobar:baz", 35 | visibility = ["//:__pkg__"], 36 | ) 37 | 38 | filegroup( 39 | name = "oci_layout", 40 | srcs = [":go_image"], 41 | output_group = "oci_layout", 42 | ) 43 | 44 | filegroup( 45 | name = "oci_tarball", 46 | srcs = [":go_image"], 47 | output_group = "oci_tarball", 48 | ) 49 | 50 | filegroup( 51 | name = "docker_tarball", 52 | srcs = [":load"], 53 | output_group = "tarball", 54 | ) 55 | 56 | build_test( 57 | name = "test", 58 | targets = [ 59 | ":go_layer", 60 | ":go_image", 61 | ":push", 62 | ":load", 63 | ":oci_layout", 64 | ":oci_tarball", 65 | ":docker_tarball", 66 | ], 67 | ) 68 | -------------------------------------------------------------------------------- /e2e/go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func main() { 9 | fmt.Printf("Hello, world from %s %s!\n", runtime.GOOS, runtime.GOARCH) 10 | } 11 | -------------------------------------------------------------------------------- /e2e/go/multiarch/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@rules_img//img:image.bzl", "image_index", "image_manifest") 3 | load("@rules_img//img:layer.bzl", "image_layer") 4 | load("@rules_img//img:push.bzl", "image_push") 5 | 6 | image_layer( 7 | name = "go_layer", 8 | srcs = { 9 | "/bin/app": "//:app", 10 | }, 11 | ) 12 | 13 | image_manifest( 14 | name = "go_image", 15 | entrypoint = ["/bin/app"], 16 | layers = [ 17 | ":go_layer", 18 | ], 19 | ) 20 | 21 | image_index( 22 | name = "multiarch_image", 23 | manifests = [":go_image"], 24 | platforms = [ 25 | "@rules_go//go/toolchain:linux_arm64", 26 | "@rules_go//go/toolchain:linux_amd64", 27 | ], 28 | ) 29 | 30 | image_push( 31 | name = "push", 32 | image = ":multiarch_image", 33 | registry = "ghcr.io", 34 | repository = "malt3/rules_img/go", 35 | tag = "multiarch", 36 | visibility = ["//:__pkg__"], 37 | ) 38 | 39 | build_test( 40 | name = "test", 41 | targets = [ 42 | ":go_layer", 43 | ":go_image", 44 | ":multiarch_image", 45 | ":push", 46 | ], 47 | ) 48 | -------------------------------------------------------------------------------- /e2e/go/tools/workspace_status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "STABLE_CONTAINER_VERSION_TAG v1.2.3.4" 3 | -------------------------------------------------------------------------------- /e2e/js/.bazelignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /e2e/js/.bazelrc: -------------------------------------------------------------------------------- 1 | import %workspace%/.bazelrc.common 2 | 3 | try-import %workspace%/.bazelrc.user 4 | -------------------------------------------------------------------------------- /e2e/js/.bazelrc.common: -------------------------------------------------------------------------------- 1 | ../../.bazelrc.common -------------------------------------------------------------------------------- /e2e/js/.npmrc: -------------------------------------------------------------------------------- 1 | # Disabling pnpm [hoisting](https://pnpm.io/npmrc#hoist) by setting `hoist=false` is recommended on 2 | # projects using rules_js so that pnpm outside of Bazel lays out a node_modules tree similar to what 3 | # rules_js lays out under Bazel (without a hidden node_modules/.pnpm/node_modules) 4 | hoist=false 5 | -------------------------------------------------------------------------------- /e2e/js/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@npm//:defs.bzl", "npm_link_all_packages") 2 | 3 | npm_link_all_packages(name = "node_modules") 4 | -------------------------------------------------------------------------------- /e2e/js/MODULE.bazel: -------------------------------------------------------------------------------- 1 | module(name = "js_e2e") 2 | 3 | # BEGIN BAZEL_DEP 4 | bazel_dep(name = "rules_img") 5 | local_path_override( 6 | module_name = "rules_img", 7 | path = "../..", 8 | ) 9 | 10 | bazel_dep(name = "rules_img_pull_tool") 11 | local_path_override( 12 | module_name = "rules_img_pull_tool", 13 | path = "../../pull_tool", 14 | ) 15 | 16 | bazel_dep(name = "rules_img_tool") 17 | local_path_override( 18 | module_name = "rules_img_tool", 19 | path = "../../img_tool", 20 | ) 21 | 22 | register_toolchains("@rules_img_tool//toolchain:all") 23 | # END BAZEL_DEP 24 | 25 | bazel_dep(name = "aspect_bazel_lib", version = "2.21.2") 26 | bazel_dep(name = "aspect_rules_js", version = "2.6.0") 27 | bazel_dep(name = "platforms", version = "0.0.11") 28 | bazel_dep(name = "bazel_skylib", version = "1.8.1") 29 | bazel_dep(name = "rules_nodejs", version = "6.5.2") 30 | 31 | npm = use_extension("@aspect_rules_js//npm:extensions.bzl", "npm", dev_dependency = True) 32 | npm.npm_translate_lock( 33 | name = "npm", 34 | npmrc = "//:.npmrc", 35 | pnpm_lock = "//:pnpm-lock.yaml", 36 | verify_node_modules_ignored = "//:.bazelignore", 37 | ) 38 | use_repo(npm, "npm") 39 | 40 | node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node", dev_dependency = True) 41 | use_repo(node, "nodejs_toolchains") 42 | 43 | pull = use_repo_rule("@rules_img//img:pull.bzl", "pull") 44 | 45 | pull( 46 | name = "debian", 47 | digest = "sha256:833c135acfe9521d7a0035a296076f98c182c542a2b6b5a0fd7063d355d696be", 48 | registries = [ 49 | "mirror.gcr.io", 50 | "index.docker.io", 51 | ], 52 | repository = "library/debian", 53 | tag = "latest", 54 | ) 55 | -------------------------------------------------------------------------------- /e2e/js/WORKSPACE.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bazel-contrib/rules_img/b090f01e0de59675ce0bc808c44e73c6d0c016ca/e2e/js/WORKSPACE.bazel -------------------------------------------------------------------------------- /e2e/js/app/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_image_layer") 2 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 3 | load("@rules_img//img:image.bzl", "image_index", "image_manifest") 4 | load("@rules_img//img:load.bzl", "image_load") 5 | load("@rules_img//img:push.bzl", "image_push") 6 | 7 | js_binary( 8 | name = "bin", 9 | chdir = package_name(), 10 | data = ["//:node_modules/meaning-of-life"], 11 | entry_point = "main.js", 12 | ) 13 | 14 | js_image_layer( 15 | name = "layers", 16 | binary = ":bin", 17 | platform = select({ 18 | "@platforms//cpu:arm64": "//platform:linux_arm64", 19 | "@platforms//cpu:x86_64": "//platform:linux_amd64", 20 | }), 21 | ) 22 | 23 | image_manifest( 24 | name = "image", 25 | base = "@debian", 26 | entrypoint = ["/app/bin"], 27 | layers = [":layers"], 28 | visibility = ["//visibility:public"], 29 | working_dir = "/app/bin.runfiles/_main", 30 | ) 31 | 32 | image_index( 33 | name = "multiarch_image", 34 | manifests = [":image"], 35 | platforms = [ 36 | "//platform:linux_arm64", 37 | "//platform:linux_amd64", 38 | ], 39 | ) 40 | 41 | image_load( 42 | name = "load", 43 | image = ":multiarch_image", 44 | tag = "302232432727.dkr.ecr.us-east-2.amazonaws.com/account_access_app:latest", 45 | ) 46 | 47 | image_push( 48 | name = "push", 49 | image = ":multiarch_image", 50 | registry = "ghcr.io", 51 | repository = "malt3/rules_img/js", 52 | tag = "latest", 53 | ) 54 | 55 | build_test( 56 | name = "test", 57 | targets = [ 58 | ":bin", 59 | ":layers", 60 | ":image", 61 | ":multiarch_image", 62 | ":load", 63 | ":push", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /e2e/js/app/main.js: -------------------------------------------------------------------------------- 1 | meaningOfLife = require('meaning-of-life'); 2 | console.log(`Hello! This JS code running inside a rules_img image. The meaning of life is ${meaningOfLife}.`); 3 | -------------------------------------------------------------------------------- /e2e/js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "image", 3 | "dependencies": { 4 | "meaning-of-life": "1.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /e2e/js/platform/BUILD.bazel: -------------------------------------------------------------------------------- 1 | package( 2 | default_visibility = ["//visibility:public"], 3 | ) 4 | 5 | platform( 6 | name = "linux_amd64", 7 | constraint_values = [ 8 | "@platforms//os:linux", 9 | "@platforms//cpu:x86_64", 10 | ], 11 | ) 12 | 13 | platform( 14 | name = "linux_arm64", 15 | constraint_values = [ 16 | "@platforms//os:linux", 17 | "@platforms//cpu:arm64", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /e2e/js/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | dependencies: 8 | meaning-of-life: 9 | specifier: 1.0.0 10 | version: 1.0.0 11 | 12 | packages: 13 | 14 | /meaning-of-life@1.0.0: 15 | resolution: {integrity: sha512-fVA4xSydqtK9owabGcYw1r4EKEsMOVVeYQLeCXPu77Z+8Y2j2B2I16UqZlKIOHnYkJ4RSvpJ00ywy9IWjmuxYw==} 16 | dev: false 17 | -------------------------------------------------------------------------------- /e2e/python/.bazelrc: -------------------------------------------------------------------------------- 1 | import %workspace%/.bazelrc.common 2 | 3 | try-import %workspace%/.bazelrc.user 4 | -------------------------------------------------------------------------------- /e2e/python/.bazelrc.common: -------------------------------------------------------------------------------- 1 | ../../.bazelrc.common -------------------------------------------------------------------------------- /e2e/python/MODULE.bazel: -------------------------------------------------------------------------------- 1 | module(name = "python_e2e") 2 | 3 | # BEGIN BAZEL_DEP 4 | bazel_dep(name = "rules_img") 5 | local_path_override( 6 | module_name = "rules_img", 7 | path = "../..", 8 | ) 9 | 10 | bazel_dep(name = "rules_img_pull_tool") 11 | local_path_override( 12 | module_name = "rules_img_pull_tool", 13 | path = "../../pull_tool", 14 | ) 15 | 16 | bazel_dep(name = "rules_img_tool") 17 | local_path_override( 18 | module_name = "rules_img_tool", 19 | path = "../../img_tool", 20 | ) 21 | 22 | register_toolchains("@rules_img_tool//toolchain:all") 23 | # END BAZEL_DEP 24 | 25 | bazel_dep(name = "rules_python", version = "1.6.3") 26 | bazel_dep(name = "aspect_bazel_lib", version = "2.21.2") 27 | bazel_dep(name = "aspect_rules_py", version = "1.6.3") 28 | bazel_dep(name = "bazel_skylib", version = "1.8.1") 29 | bazel_dep(name = "platforms", version = "0.0.11") 30 | 31 | python = use_extension("@rules_python//python/extensions:python.bzl", "python") 32 | python.toolchain( 33 | python_version = "3.13", 34 | ) 35 | use_repo(python, "python_3_13") 36 | 37 | pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") 38 | pip.parse( 39 | download_only = True, 40 | hub_name = "pip", 41 | python_version = "3.13", 42 | requirements_lock = "//requirements:requirements_lock.txt", 43 | ) 44 | use_repo(pip, "pip") 45 | 46 | pull = use_repo_rule("@rules_img//img:pull.bzl", "pull") 47 | 48 | pull( 49 | name = "ubuntu", 50 | digest = "sha256:9cbed754112939e914291337b5e554b07ad7c392491dba6daf25eef1332a22e8", 51 | registries = [ 52 | "mirror.gcr.io", 53 | "index.docker.io", 54 | ], 55 | repository = "library/ubuntu", 56 | tag = "latest", 57 | ) 58 | -------------------------------------------------------------------------------- /e2e/python/README.md: -------------------------------------------------------------------------------- 1 | # Python e2e example 2 | 3 | This directory contains an example of creating OCI container images for Python applications using `rules_img`. 4 | 5 | ## Building 6 | 7 | ```bash 8 | bazel build //:image 9 | ``` 10 | 11 | ## Pushing to registry 12 | 13 | ```bash 14 | bazel run //:push 15 | ``` 16 | 17 | ## Running locally 18 | 19 | ```bash 20 | bazel run //:load 21 | docker run --rm ghcr.io/malt3/rules_img/python:sideloaded 22 | ``` 23 | 24 | See the BUILD files for more details. 25 | -------------------------------------------------------------------------------- /e2e/python/WORKSPACE.bazel: -------------------------------------------------------------------------------- 1 | # This file marks the root of the Bazel workspace. 2 | # See MODULE.bazel for dependencies and setup. 3 | -------------------------------------------------------------------------------- /e2e/python/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bazel-contrib/rules_img/b090f01e0de59675ce0bc808c44e73c6d0c016ca/e2e/python/__init__.py -------------------------------------------------------------------------------- /e2e/python/__main__.py: -------------------------------------------------------------------------------- 1 | from app import Cow 2 | 3 | if __name__ == "__main__": 4 | app = Cow("John") 5 | app.say_hello() 6 | -------------------------------------------------------------------------------- /e2e/python/app.py: -------------------------------------------------------------------------------- 1 | import cowsay 2 | 3 | class Cow: 4 | def __init__(self, name): 5 | self.name = name 6 | 7 | def say_hello(self): 8 | cowsay.cow(f"Hello I'm {self.name} from rules_img! Moooh.") 9 | -------------------------------------------------------------------------------- /e2e/python/platform/BUILD.bazel: -------------------------------------------------------------------------------- 1 | package( 2 | default_visibility = ["//visibility:public"], 3 | ) 4 | 5 | platform( 6 | name = "linux_amd64", 7 | constraint_values = [ 8 | "@platforms//os:linux", 9 | "@platforms//cpu:x86_64", 10 | ], 11 | ) 12 | 13 | platform( 14 | name = "linux_arm64", 15 | constraint_values = [ 16 | "@platforms//os:linux", 17 | "@platforms//cpu:arm64", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /e2e/python/requirements/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_python//python:pip.bzl", "compile_pip_requirements") 2 | 3 | compile_pip_requirements( 4 | name = "requirements", 5 | src = "requirements.in", 6 | requirements_txt = "requirements_lock.txt", 7 | ) 8 | -------------------------------------------------------------------------------- /e2e/python/requirements/requirements.in: -------------------------------------------------------------------------------- 1 | cowsay==6.1 2 | -------------------------------------------------------------------------------- /e2e/python/requirements/requirements_lock.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.13 3 | # by the following command: 4 | # 5 | # bazel run //requirements:requirements.update 6 | # 7 | cowsay==6.1 \ 8 | --hash=sha256:274b1e6fc1b966d53976333eb90ac94cb07a450a700b455af9fbdf882244b30a 9 | # via -r requirements/requirements.in 10 | -------------------------------------------------------------------------------- /e2e/workspace/.bazelrc: -------------------------------------------------------------------------------- 1 | import %workspace%/.bazelrc.common 2 | 3 | # explicitly disable bzlmod for this workspace 4 | # to test WORKSPACE mode 5 | common --noenable_bzlmod 6 | common --enable_workspace 7 | 8 | try-import %workspace%/.bazelrc.user 9 | -------------------------------------------------------------------------------- /e2e/workspace/.bazelrc.common: -------------------------------------------------------------------------------- 1 | ../../.bazelrc.common -------------------------------------------------------------------------------- /e2e/workspace/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@bazel_skylib//rules:write_file.bzl", "write_file") 3 | load("@rules_img//img:image.bzl", "image_manifest") 4 | load("@rules_img//img:layer.bzl", "image_layer") 5 | 6 | # Simple test file for the workspace e2e test 7 | write_file( 8 | name = "hello_file", 9 | out = "hello.txt", 10 | content = ["Hello from WORKSPACE mode!\n"], 11 | ) 12 | 13 | # Create a simple layer with the test file 14 | image_layer( 15 | name = "hello_layer", 16 | srcs = { 17 | "hello.txt": ":hello_file", 18 | }, 19 | ) 20 | 21 | # Create a simple manifest with the layer (without base) 22 | image_manifest( 23 | name = "hello_image", 24 | entrypoint = [ 25 | "/bin/cat", 26 | "/hello.txt", 27 | ], 28 | labels = { 29 | "description": "Simple test image built with WORKSPACE mode", 30 | "version": "1.0.0", 31 | }, 32 | layers = [":hello_layer"], 33 | ) 34 | 35 | # Create an image based on Alpine Linux (with pulled base image) 36 | image_manifest( 37 | name = "alpine_based_image", 38 | base = "@alpine", 39 | cmd = [ 40 | "/bin/cat", 41 | "/hello.txt", 42 | ], 43 | labels = { 44 | "description": "WORKSPACE mode test image based on Alpine Linux", 45 | "version": "1.0.0", 46 | "base": "alpine:3.22", 47 | }, 48 | layers = [":hello_layer"], 49 | ) 50 | 51 | # Build test to ensure both images can be built 52 | build_test( 53 | name = "workspace_test", 54 | targets = [ 55 | ":hello_image", 56 | ":alpine_based_image", 57 | ], 58 | ) 59 | -------------------------------------------------------------------------------- /e2e/workspace/WORKSPACE.bazel: -------------------------------------------------------------------------------- 1 | # WORKSPACE file for testing rules_img with WORKSPACE mode 2 | # This file marks this directory as a bazel workspace. 3 | 4 | # BEGIN BAZEL_DEP 5 | local_repository( 6 | name = "rules_img", 7 | path = "../../", 8 | ) 9 | # END BAZEL_DEP 10 | 11 | # Load rules_img dependencies and prebuilt toolchains 12 | load("@rules_img//img:dependencies.bzl", "rules_img_dependencies") 13 | load("@rules_img//img:repositories.bzl", "img_register_prebuilt_toolchains", "pull_tool_register_prebuilt_repositories") 14 | 15 | rules_img_dependencies() 16 | 17 | # Register prebuilt img toolchains for WORKSPACE mode 18 | img_register_prebuilt_toolchains() 19 | 20 | register_toolchains("@img_toolchain//:all") 21 | 22 | # Register prebuilt pull_tool repositories for WORKSPACE mode 23 | pull_tool_register_prebuilt_repositories() 24 | 25 | # Pull Alpine Linux as base image for WORKSPACE mode test 26 | load("@rules_img//img:pull.bzl", "pull") 27 | 28 | pull( 29 | name = "alpine", 30 | digest = "sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1", 31 | registries = [ 32 | "mirror.gcr.io", 33 | "index.docker.io", 34 | ], 35 | repository = "library/alpine", 36 | tag = "3.22", 37 | ) 38 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "rules_img"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | bazel-env.url = "github:malt3/bazel-env"; 7 | bazel-env.inputs.nixpkgs.follows = "nixpkgs"; 8 | flake-utils.url = "github:numtide/flake-utils"; 9 | }; 10 | 11 | outputs = { nixpkgs, flake-utils, bazel-env, ... }: 12 | flake-utils.lib.eachDefaultSystem (system: 13 | let 14 | pkgs = import nixpkgs { 15 | inherit system; 16 | }; 17 | bazel_pkgs = bazel-env.packages.${system}; 18 | in 19 | rec { 20 | packages.dev = (bazel_pkgs.bazel-full-env.override { 21 | name = "dev"; 22 | extraPkgs = [ 23 | pkgs.pre-commit 24 | ]; 25 | }); 26 | packages.bazel-fhs = bazel_pkgs.bazel-full; 27 | devShells.dev = packages.dev.env; 28 | devShells.default = pkgs.mkShell { 29 | packages = [ packages.dev bazel_pkgs.bazel-full pkgs.pre-commit ]; 30 | }; 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /img/constraints/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//lib:selects.bzl", "selects") 2 | load("//img/private/platforms:platforms.bzl", "CONFIG_SETTINGS") 3 | 4 | package( 5 | default_visibility = ["//visibility:public"], 6 | ) 7 | 8 | [ 9 | selects.config_setting_group( 10 | name = config.name, 11 | match_all = config.match_all, 12 | ) 13 | for config in CONFIG_SETTINGS 14 | ] 15 | 16 | filegroup( 17 | name = "all_files", 18 | srcs = glob(["**"]), 19 | visibility = ["//img/private/release:__subpackages__"], 20 | ) 21 | -------------------------------------------------------------------------------- /img/dependencies.bzl: -------------------------------------------------------------------------------- 1 | """Declare runtime dependencies 2 | 3 | These are needed for local dev, and users must install them as well. 4 | See https://docs.bazel.build/versions/main/skylark/deploying.html#dependencies 5 | """ 6 | 7 | load("@bazel_tools//tools/build_defs/repo:http.bzl", _http_archive = "http_archive") 8 | load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") 9 | 10 | def http_archive(**kwargs): 11 | maybe(_http_archive, **kwargs) 12 | 13 | def rules_img_dependencies(): 14 | http_archive( 15 | name = "bazel_skylib", 16 | sha256 = "bc283cdfcd526a52c3201279cda4bc298652efa898b10b4db0837dc51652756f", 17 | urls = [ 18 | "https://github.com/bazelbuild/bazel-skylib/releases/download/1.7.1/bazel-skylib-1.7.1.tar.gz", 19 | "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.7.1/bazel-skylib-1.7.1.tar.gz", 20 | ], 21 | ) 22 | 23 | http_archive( 24 | name = "platforms", 25 | urls = [ 26 | "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.11/platforms-0.0.11.tar.gz", 27 | "https://github.com/bazelbuild/platforms/releases/download/0.0.11/platforms-0.0.11.tar.gz", 28 | ], 29 | sha256 = "29742e87275809b5e598dc2f04d86960cc7a55b3067d97221c9abbc9926bff0f", 30 | ) 31 | -------------------------------------------------------------------------------- /img/image.bzl: -------------------------------------------------------------------------------- 1 | """Rules to build container images from layers. 2 | 3 | Use `image_manifest` to create a single-platform container image, 4 | and `image_index` to compose a multi-platform container image index. 5 | """ 6 | 7 | load("//img/private:index.bzl", _image_index = "image_index") 8 | load("//img/private:manifest.bzl", _image_manifest = "image_manifest") 9 | 10 | image_manifest = _image_manifest 11 | image_index = _image_index 12 | -------------------------------------------------------------------------------- /img/image_toolchain.bzl: -------------------------------------------------------------------------------- 1 | """Rules to define and register the img toolchain.""" 2 | 3 | load("//img/private:image_toolchain.bzl", _TOOLCHAIN_TYPE = "TOOLCHAIN_TYPE", _image_toolchain = "image_toolchain") 4 | 5 | image_toolchain = _image_toolchain 6 | TOOLCHAIN_TYPE = _TOOLCHAIN_TYPE 7 | -------------------------------------------------------------------------------- /img/layer.bzl: -------------------------------------------------------------------------------- 1 | """Public API for container image layer rules.""" 2 | 3 | load("//img/private:file_metadata.bzl", _file_metadata = "file_metadata") 4 | load("//img/private:layer.bzl", _image_layer = "image_layer") 5 | load("//img/private:layer_from_tar.bzl", _layer_from_tar = "layer_from_tar") 6 | 7 | image_layer = _image_layer 8 | layer_from_tar = _layer_from_tar 9 | file_metadata = _file_metadata 10 | -------------------------------------------------------------------------------- /img/load.bzl: -------------------------------------------------------------------------------- 1 | """Public API for loading container images into a daemon. 2 | 3 | The `image_load` rule creates an executable target that loads container images into a local daemon (containerd or Docker). 4 | 5 | ## Example 6 | 7 | ```python 8 | load("@rules_img//img:image.bzl", "image_manifest") 9 | load("@rules_img//img:load.bzl", "image_load") 10 | load("@rules_img//img:layer.bzl", "image_layer") 11 | 12 | # Create a simple layer 13 | image_layer( 14 | name = "app_layer", 15 | srcs = { 16 | "/app/hello.txt": "hello.txt", 17 | }, 18 | ) 19 | 20 | # Build an image 21 | image_manifest( 22 | name = "my_image", 23 | base = "@alpine", 24 | layers = [":app_layer"], 25 | ) 26 | 27 | # Create a load target 28 | image_load( 29 | name = "load", 30 | image = ":my_image", 31 | tag = "my-app:latest", 32 | ) 33 | ``` 34 | 35 | Then run: 36 | ```bash 37 | # Load the image into your local daemon 38 | bazel run //:load 39 | ``` 40 | 41 | ## Platform Selection 42 | 43 | When running the load target, you can use the `--platform` flag to filter which platforms to load from multi-platform images: 44 | 45 | ```bash 46 | # Load all platforms (default) 47 | bazel run //path/to:load_target 48 | 49 | # Load only linux/amd64 50 | bazel run //path/to:load_target -- --platform linux/amd64 51 | ``` 52 | 53 | **Note**: Docker daemon only supports loading a single platform at a time. If multiple platforms are specified with Docker, an error will be returned. 54 | """ 55 | 56 | load("//img/private:load.bzl", _image_load = "image_load") 57 | 58 | image_load = _image_load 59 | -------------------------------------------------------------------------------- /img/multi_deploy.bzl: -------------------------------------------------------------------------------- 1 | """Public API for container image multi deploy rule.""" 2 | 3 | load("//img/private:multi_deploy.bzl", _multi_deploy = "multi_deploy") 4 | 5 | multi_deploy = _multi_deploy 6 | -------------------------------------------------------------------------------- /img/private/common/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | 3 | bzl_library( 4 | name = "layer_helper", 5 | srcs = ["layer_helper.bzl"], 6 | visibility = ["//img:__subpackages__"], 7 | deps = ["//img:providers"], 8 | ) 9 | 10 | bzl_library( 11 | name = "write_index_json", 12 | srcs = ["write_index_json.bzl"], 13 | visibility = ["//img:__subpackages__"], 14 | deps = [":build"], 15 | ) 16 | 17 | filegroup( 18 | name = "all_files", 19 | srcs = glob(["**"]), 20 | visibility = ["//img/private/release:__subpackages__"], 21 | ) 22 | 23 | bzl_library( 24 | name = "build", 25 | srcs = ["build.bzl"], 26 | visibility = ["//img:__subpackages__"], 27 | ) 28 | 29 | bzl_library( 30 | name = "transitions", 31 | srcs = ["transitions.bzl"], 32 | visibility = ["//img:__subpackages__"], 33 | ) 34 | -------------------------------------------------------------------------------- /img/private/common/build.bzl: -------------------------------------------------------------------------------- 1 | """Common build utilities for container image rules.""" 2 | 3 | TOOLCHAIN = str(Label("//img:toolchain_type")) 4 | TOOLCHAINS = [TOOLCHAIN] 5 | -------------------------------------------------------------------------------- /img/private/common/write_index_json.bzl: -------------------------------------------------------------------------------- 1 | """Utilities for writing index.json files.""" 2 | 3 | load("//img/private/common:build.bzl", "TOOLCHAIN") 4 | 5 | def _annotation_arg(tup): 6 | return "{}={}".format(tup[0], tup[1]) 7 | 8 | def write_index_json(ctx, *, output, digest, manifests, config_json = None): 9 | """Write an index.json file for a multi-platform image. 10 | 11 | Args: 12 | ctx: Rule context. 13 | output: Output file to write. 14 | digest: Digest file to write. 15 | manifests: List of manifests to include in the index. 16 | config_json: Optional config JSON file with template expansions. 17 | """ 18 | manifest_descriptors = [manifest.descriptor for manifest in manifests] 19 | args = ctx.actions.args() 20 | args.add("index") 21 | args.add("--digest", digest.path) 22 | args.add_all(manifest_descriptors, format_each = "--manifest-descriptor=%s") 23 | 24 | inputs = manifest_descriptors 25 | 26 | if config_json: 27 | args.add("--config-templates", config_json.path) 28 | inputs.append(config_json) 29 | else: 30 | args.add_all(ctx.attr.annotations.items(), map_each = _annotation_arg, format_each = "--annotation=%s") 31 | 32 | args.add(output.path) 33 | img_toolchain_info = ctx.toolchains[TOOLCHAIN].imgtoolchaininfo 34 | ctx.actions.run( 35 | outputs = [output, digest], 36 | inputs = inputs, 37 | executable = img_toolchain_info.tool_exe, 38 | arguments = [args], 39 | mnemonic = "ImageIndex", 40 | ) 41 | -------------------------------------------------------------------------------- /img/private/config/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | load(":defs.bzl", "os_cpu") 3 | 4 | os_cpu( 5 | name = "target_os_cpu", 6 | cpu = select({ 7 | "@platforms//cpu:arm64": "arm64", 8 | "@platforms//cpu:mips64": "mips64", 9 | "@platforms//cpu:ppc64le": "ppc64le", 10 | "@platforms//cpu:riscv64": "riscv64", 11 | "@platforms//cpu:x86_32": "386", 12 | "@platforms//cpu:x86_64": "amd64", 13 | }), 14 | os = select({ 15 | "@platforms//os:android": "android", 16 | "@platforms//os:freebsd": "freebsd", 17 | "@platforms//os:ios": "ios", 18 | "@platforms//os:linux": "linux", 19 | "@platforms//os:macos": "darwin", 20 | "@platforms//os:netbsd": "netbsd", 21 | "@platforms//os:openbsd": "openbsd", 22 | "@platforms//os:wasi": "wasip1", 23 | "@platforms//os:windows": "windows", 24 | }), 25 | visibility = ["//visibility:public"], 26 | ) 27 | 28 | filegroup( 29 | name = "all_files", 30 | srcs = glob(["**"]), 31 | visibility = ["//img/private/release:__subpackages__"], 32 | ) 33 | 34 | bzl_library( 35 | name = "defs", 36 | srcs = ["defs.bzl"], 37 | visibility = ["//img:__subpackages__"], 38 | ) 39 | -------------------------------------------------------------------------------- /img/private/file_metadata.bzl: -------------------------------------------------------------------------------- 1 | """Helper functions for creating file metadata for image layers.""" 2 | 3 | def file_metadata( 4 | *, 5 | mode = None, 6 | uid = None, 7 | gid = None, 8 | uname = None, 9 | gname = None, 10 | mtime = None, 11 | pax_records = None): 12 | """Creates a JSON-encoded file metadata string for use with image_layer rules. 13 | 14 | This function generates JSON metadata that can be used to customize file attributes 15 | in container image layers, such as permissions, ownership, and timestamps. 16 | 17 | Args: 18 | mode: File permission mode (e.g., "0755", "0644"). String format. 19 | uid: User ID of the file owner. Integer. 20 | gid: Group ID of the file owner. Integer. 21 | uname: User name of the file owner. String. 22 | gname: Group name of the file owner. String. 23 | mtime: Modification time in RFC3339 format (e.g., "2023-01-01T00:00:00Z"). String. 24 | pax_records: Dict of extended attributes to set via PAX records. 25 | 26 | Returns: 27 | JSON-encoded string containing the file metadata. 28 | """ 29 | metadata = {} 30 | 31 | if mode != None: 32 | metadata["mode"] = mode 33 | if uid != None: 34 | metadata["uid"] = uid 35 | if gid != None: 36 | metadata["gid"] = gid 37 | if uname != None: 38 | metadata["uname"] = uname 39 | if gname != None: 40 | metadata["gname"] = gname 41 | if mtime != None: 42 | metadata["mtime"] = mtime 43 | if pax_records != None: 44 | metadata["pax_records"] = pax_records 45 | 46 | return json.encode(metadata) 47 | -------------------------------------------------------------------------------- /img/private/image_toolchain.bzl: -------------------------------------------------------------------------------- 1 | """Implementation of the image_toolchain rule.""" 2 | 3 | load("//img/private/common:transitions.bzl", "reset_platform_transition") 4 | load("//img/private/providers:image_toolchain_info.bzl", "ImageToolchainInfo") 5 | 6 | DOC = """\ 7 | Defines an image builder toolchain. 8 | 9 | The image build tool can natively target any platform, 10 | so it only has exec platform constraints. 11 | 12 | See https://bazel.build/extending/toolchains#defining-toolchains. 13 | """ 14 | 15 | ATTRS = dict( 16 | tool_exe = attr.label( 17 | doc = "An image build tool executable.", 18 | allow_single_file = True, 19 | ), 20 | ) 21 | 22 | TOOLCHAIN_TYPE = str(Label("//img:toolchain_type")) 23 | 24 | def _image_toolchain_impl(ctx): 25 | image_toolchain_info = ImageToolchainInfo( 26 | tool_exe = ctx.file.tool_exe, 27 | ) 28 | toolchain_info = platform_common.ToolchainInfo( 29 | imgtoolchaininfo = image_toolchain_info, 30 | ) 31 | 32 | return [toolchain_info] 33 | 34 | image_toolchain = rule( 35 | implementation = _image_toolchain_impl, 36 | attrs = ATTRS, 37 | doc = DOC, 38 | cfg = reset_platform_transition, 39 | ) 40 | -------------------------------------------------------------------------------- /img/private/integration_test_runner/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | # gazelle:exclude_from_release 4 | 5 | go_library( 6 | name = "integration_test_runner_lib", 7 | srcs = ["integration_test_runner.go"], 8 | importpath = "github.com/bazel-contrib/rules_img/img/private/integration_test_runner", 9 | visibility = ["//visibility:private"], 10 | deps = ["@rules_go//go/runfiles"], 11 | ) 12 | 13 | go_binary( 14 | name = "integration_test_runner", 15 | data = [ 16 | ":bazel_dep_rules_img", 17 | "//img/private/release:airgapped", 18 | "//img/private/release:bcr", 19 | ], 20 | embed = [":integration_test_runner_lib"], 21 | pure = "on", 22 | visibility = ["//visibility:public"], 23 | ) 24 | 25 | filegroup( 26 | name = "bazel_dep_rules_img", 27 | srcs = [ 28 | "//img/private/release:bcr", 29 | ], 30 | output_group = "rules_img", 31 | ) 32 | 33 | go_library( 34 | name = "lib", 35 | srcs = ["integration_test_runner.go"], 36 | importpath = "", 37 | visibility = ["//visibility:private"], 38 | deps = ["@rules_go//go/runfiles"], 39 | ) 40 | -------------------------------------------------------------------------------- /img/private/platforms/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | load(":platforms.bzl", "PLATFORMS") 3 | 4 | package( 5 | default_visibility = ["//visibility:public"], 6 | ) 7 | 8 | [ 9 | platform( 10 | name = name, 11 | constraint_values = info.constraints, 12 | ) 13 | for name, info in PLATFORMS.items() 14 | ] 15 | 16 | filegroup( 17 | name = "all_files", 18 | srcs = glob(["**"]), 19 | visibility = ["//img/private/release:__subpackages__"], 20 | ) 21 | 22 | bzl_library( 23 | name = "platforms", 24 | srcs = ["platforms.bzl"], 25 | ) 26 | -------------------------------------------------------------------------------- /img/private/prebuilt/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | 3 | bzl_library( 4 | name = "prebuilt", 5 | srcs = ["prebuilt.bzl"], 6 | visibility = ["//visibility:public"], 7 | deps = ["//img/private/platforms"], 8 | ) 9 | 10 | filegroup( 11 | name = "all_files", 12 | srcs = glob(["**"]), 13 | visibility = ["//img/private/release:__subpackages__"], 14 | ) 15 | -------------------------------------------------------------------------------- /img/private/providers/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | 3 | filegroup( 4 | name = "all_files", 5 | srcs = glob(["**"]), 6 | visibility = ["//img/private/release:__subpackages__"], 7 | ) 8 | 9 | bzl_library( 10 | name = "deploy_info", 11 | srcs = ["deploy_info.bzl"], 12 | visibility = ["//img:__subpackages__"], 13 | ) 14 | 15 | bzl_library( 16 | name = "image_toolchain_info", 17 | srcs = ["image_toolchain_info.bzl"], 18 | visibility = ["//img:__subpackages__"], 19 | ) 20 | 21 | bzl_library( 22 | name = "index_info", 23 | srcs = ["index_info.bzl"], 24 | visibility = ["//img:__subpackages__"], 25 | ) 26 | 27 | bzl_library( 28 | name = "layer_info", 29 | srcs = ["layer_info.bzl"], 30 | visibility = ["//img:__subpackages__"], 31 | ) 32 | 33 | bzl_library( 34 | name = "load_settings_info", 35 | srcs = ["load_settings_info.bzl"], 36 | visibility = ["//img:__subpackages__"], 37 | ) 38 | 39 | bzl_library( 40 | name = "manifest_info", 41 | srcs = ["manifest_info.bzl"], 42 | visibility = ["//img:__subpackages__"], 43 | ) 44 | 45 | bzl_library( 46 | name = "oci_layout_settings_info", 47 | srcs = ["oci_layout_settings_info.bzl"], 48 | visibility = ["//img:__subpackages__"], 49 | ) 50 | 51 | bzl_library( 52 | name = "pull_info", 53 | srcs = ["pull_info.bzl"], 54 | visibility = ["//img:__subpackages__"], 55 | ) 56 | 57 | bzl_library( 58 | name = "push_settings_info", 59 | srcs = ["push_settings_info.bzl"], 60 | visibility = ["//img:__subpackages__"], 61 | ) 62 | 63 | bzl_library( 64 | name = "stamp_setting_info", 65 | srcs = ["stamp_setting_info.bzl"], 66 | visibility = ["//img:__subpackages__"], 67 | ) 68 | -------------------------------------------------------------------------------- /img/private/providers/deploy_info.bzl: -------------------------------------------------------------------------------- 1 | """Defines providers for the push, load, and deploy rules.""" 2 | 3 | DOC = """\ 4 | Information required to push or load an image or image index to a registry or 5 | container runtime. 6 | """ 7 | 8 | FIELDS = dict( 9 | image = "ImageManifestInfo or ImageIndexInfo of the image or image index to push or load.", 10 | deploy_manifest = "File containing the deploy manifest (JSON).", 11 | ) 12 | 13 | DeployInfo = provider( 14 | doc = DOC, 15 | fields = FIELDS, 16 | ) 17 | -------------------------------------------------------------------------------- /img/private/providers/image_toolchain_info.bzl: -------------------------------------------------------------------------------- 1 | """Defines providers for a container image builder toolchain.""" 2 | 3 | DOC = """\ 4 | Information about how to invoke the container image builder tool. 5 | """ 6 | 7 | FIELDS = dict( 8 | tool_exe = "The builder executable (File).", 9 | ) 10 | 11 | ImageToolchainInfo = provider( 12 | doc = DOC, 13 | fields = FIELDS, 14 | ) 15 | -------------------------------------------------------------------------------- /img/private/providers/index_info.bzl: -------------------------------------------------------------------------------- 1 | """Defines providers for the image_index rule.""" 2 | 3 | DOC = """\ 4 | Information about a (multi-platform) image index (a collection of images). 5 | """ 6 | 7 | FIELDS = dict( 8 | index = "File containing the raw image index (application/vnd.oci.image.index.v1+json).", 9 | manifests = "ImageManifestInfo of the images.", 10 | ) 11 | 12 | ImageIndexInfo = provider( 13 | doc = DOC, 14 | fields = FIELDS, 15 | ) 16 | -------------------------------------------------------------------------------- /img/private/providers/layer_info.bzl: -------------------------------------------------------------------------------- 1 | """Defines providers for the image_layer rule.""" 2 | 3 | DOC = """\ 4 | Information about a single layer as a component of a container image. 5 | """ 6 | 7 | _metadata_doc = """\ 8 | File containing metadata about the layer blob as a JSON file with the following keys: 9 | - name: A human readable name for this layer. This includes the label of the layer or another descriptor (for anonymous layers, including those coming from pulled images). 10 | - diff_id: The diff ID of the layer as a string. Example: sha256:1234567890abcdef. 11 | - mediaType: The media type of the layer as a string. Example: application/vnd.oci.image.layer.v1.tar+gzip. 12 | - digest: The sha256 hash of the layer as a string. Example: sha256:1234567890abcdef. 13 | - size: The size of the layer in bytes as an int. 14 | """ 15 | 16 | FIELDS = dict( 17 | blob = "File containing the raw layer or None (for shallow base images).", 18 | metadata = _metadata_doc, 19 | media_type = "The media type of the layer as a string. Example: application/vnd.oci.image.layer.v1.tar+gzip.", 20 | estargz = "Boolean indicating whether the layer is an estargz layer.", 21 | ) 22 | 23 | LayerInfo = provider( 24 | doc = DOC, 25 | fields = FIELDS, 26 | ) 27 | -------------------------------------------------------------------------------- /img/private/providers/load_settings_info.bzl: -------------------------------------------------------------------------------- 1 | """Provider for load settings.""" 2 | 3 | DOC = """\ 4 | Collection of active load settings. 5 | """ 6 | 7 | FIELDS = dict( 8 | strategy = "The default load strategy to use", 9 | daemon = "The daemon to target by default", 10 | remote_cache = "Bazel remote cache to use for the push rule as part of the lazy push strategy. Uses the same format as Bazel's --remote_cache flag. Uses $IMG_REAPI_ENDPOINT env var if not set.", 11 | credential_helper = "Credential helper to use for the push rule. This can be the same as Bazel's credential helper. Uses $IMG_CREDENTIAL_HELPER env var or tools/credential-helper if not set.", 12 | ) 13 | 14 | LoadSettingsInfo = provider( 15 | doc = DOC, 16 | fields = FIELDS, 17 | ) 18 | -------------------------------------------------------------------------------- /img/private/providers/manifest_info.bzl: -------------------------------------------------------------------------------- 1 | """Defines providers for the image_manifest rule.""" 2 | 3 | DOC = """\ 4 | Information about a single-platform container image (manifest, config, and layers). 5 | """ 6 | 7 | FIELDS = dict( 8 | base_image = "ImageManifestInfo or ImageIndexInfo of the base image (or None).", 9 | descriptor = "File containing the descriptor of the manifest.", 10 | manifest = "File containing the raw image manifest (application/vnd.oci.image.index.v1+json).", 11 | config = "File containing the raw image config (application/vnd.oci.image.config.v1+json).", 12 | structured_config = "(Partial) image config with values known in the analysis phase.", 13 | architecture = "The CPU architecture this image runs on.", 14 | os = "The operating system this image runs on.", 15 | platform = "Dict containing additional runtime requirements of the image.", 16 | layers = "Layers of the image as list of LayerInfo.", 17 | missing_blobs = """List of hex-encoded sha256 hashes. 18 | Used to convey information lost during shallow image pulling, where the base image layers are referenced, but never materialized. 19 | """, 20 | ) 21 | 22 | ImageManifestInfo = provider( 23 | doc = DOC, 24 | fields = FIELDS, 25 | ) 26 | -------------------------------------------------------------------------------- /img/private/providers/oci_layout_settings_info.bzl: -------------------------------------------------------------------------------- 1 | """Provider for oci layout settings.""" 2 | 3 | DOC = """\ 4 | Collection of active oci layout settings. 5 | """ 6 | 7 | FIELDS = dict( 8 | allow_shallow_oci_layout = "Whether to allow shallow oci layout. This is a non-standard layout where some blobs are missing.", 9 | ) 10 | 11 | OCILayoutSettingsInfo = provider( 12 | doc = DOC, 13 | fields = FIELDS, 14 | ) 15 | -------------------------------------------------------------------------------- /img/private/providers/pull_info.bzl: -------------------------------------------------------------------------------- 1 | """Defines providers for about pulled base images.""" 2 | 3 | DOC = """\ 4 | Information corresponding to a pulled image. 5 | """ 6 | 7 | FIELDS = dict( 8 | registries = "List of registry mirrors used to pull the image.", 9 | repository = "Repository name of the image.", 10 | tag = "Tag of the image.", 11 | digest = "Digest of the image.", 12 | ) 13 | 14 | PullInfo = provider( 15 | doc = DOC, 16 | fields = FIELDS, 17 | ) 18 | -------------------------------------------------------------------------------- /img/private/providers/push_settings_info.bzl: -------------------------------------------------------------------------------- 1 | """Defines providers for settings of push rules.""" 2 | 3 | DOC = """\ 4 | Collection of active push settings. 5 | """ 6 | 7 | FIELDS = dict( 8 | strategy = "The strategy of the push rule. This can be one of the following: 'eager', 'lazy', 'cas_registry', or 'bes'.", 9 | remote_cache = "Bazel remote cache to use for the push rule as part of the lazy push strategy. Uses the same format as Bazel's --remote_cache flag. Uses $IMG_REAPI_ENDPOINT env var if not set.", 10 | credential_helper = "Credential helper to use for the push rule. This can be the same as Bazel's credential helper. Uses $IMG_CREDENTIAL_HELPER env var or tools/credential-helper if not set.", 11 | ) 12 | 13 | PushSettingsInfo = provider( 14 | doc = DOC, 15 | fields = FIELDS, 16 | ) 17 | -------------------------------------------------------------------------------- /img/private/providers/stamp_setting_info.bzl: -------------------------------------------------------------------------------- 1 | """Defines providers for about stamping.""" 2 | 3 | DOC = """\ 4 | Information on stamping configuration. 5 | """ 6 | 7 | FIELDS = dict( 8 | bazel_setting = "bool: Whether or not the `--stamp` flag was enabled", 9 | user_preference = "bool: Whether volatile-status.txt and version.txt should be used if present", 10 | ) 11 | 12 | StampSettingInfo = provider( 13 | doc = DOC, 14 | fields = FIELDS, 15 | ) 16 | -------------------------------------------------------------------------------- /img/private/release/bcr/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | # gazelle:exclude_from_release 4 | 5 | go_library( 6 | name = "bcr_lib", 7 | srcs = ["bcr.go"], 8 | importpath = "github.com/bazel-contrib/rules_img/img/private/release/bcr", 9 | visibility = ["//visibility:private"], 10 | ) 11 | 12 | go_binary( 13 | name = "bcr", 14 | embed = [":bcr_lib"], 15 | pure = "on", 16 | visibility = ["//visibility:public"], 17 | ) 18 | 19 | go_library( 20 | name = "lib", 21 | srcs = ["bcr.go"], 22 | importpath = "", 23 | visibility = ["//visibility:private"], 24 | ) 25 | -------------------------------------------------------------------------------- /img/private/release/distdir/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | # gazelle:exclude_from_release 4 | 5 | go_library( 6 | name = "distdir_lib", 7 | srcs = ["distdir.go"], 8 | importpath = "github.com/bazel-contrib/rules_img/img/private/release/distdir", 9 | visibility = ["//visibility:private"], 10 | ) 11 | 12 | go_binary( 13 | name = "distdir", 14 | embed = [":distdir_lib"], 15 | visibility = ["//visibility:public"], 16 | ) 17 | 18 | go_library( 19 | name = "lib", 20 | srcs = ["distdir.go"], 21 | importpath = "", 22 | visibility = ["//visibility:private"], 23 | ) 24 | -------------------------------------------------------------------------------- /img/private/release/gazelle_plugin/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | load("@rules_go//go:def.bzl", "go_library") 3 | load(":release_files_updated.bzl", "release_files_test") 4 | 5 | # gazelle:exclude_from_release 6 | 7 | go_library( 8 | name = "gazelle_plugin", 9 | srcs = ["all_files.go"], 10 | importpath = "github.com/bazel-contrib/rules_img/img/private/release/gazelle_plugin", 11 | visibility = ["//visibility:public"], 12 | deps = [ 13 | "@gazelle//config", 14 | "@gazelle//label", 15 | "@gazelle//language", 16 | "@gazelle//repo", 17 | "@gazelle//resolve", 18 | "@gazelle//rule", 19 | ], 20 | ) 21 | 22 | exports_files([ 23 | "test_wrapper.sh", 24 | ]) 25 | 26 | release_files_test( 27 | name = "release_files_test", 28 | target_compatible_with = select({ 29 | # skip windows, since we are using a bash script 30 | "@platforms//os:windows": ["@platforms//:incompatible"], 31 | "//conditions:default": [], 32 | }), 33 | update_release_files_binary = "//img/private/release/gazelle_plugin/cmd/update_release_files", 34 | ) 35 | 36 | go_library( 37 | name = "all_files", 38 | srcs = ["all_files.go"], 39 | importpath = "", 40 | visibility = ["//visibility:public"], 41 | deps = [ 42 | "@gazelle//config", 43 | "@gazelle//label", 44 | "@gazelle//language", 45 | "@gazelle//repo", 46 | "@gazelle//resolve", 47 | "@gazelle//rule", 48 | ], 49 | ) 50 | 51 | bzl_library( 52 | name = "release_files_updated", 53 | srcs = ["release_files_updated.bzl"], 54 | visibility = ["//img:__subpackages__"], 55 | ) 56 | -------------------------------------------------------------------------------- /img/private/release/gazelle_plugin/cmd/update_release_files/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | # gazelle:exclude_from_release 4 | 5 | go_library( 6 | name = "update_release_files_lib", 7 | srcs = ["main.go"], 8 | importpath = "github.com/bazel-contrib/rules_img/img/private/release/gazelle_plugin/cmd/update_release_files", 9 | visibility = ["//visibility:private"], 10 | ) 11 | 12 | go_binary( 13 | name = "update_release_files", 14 | embed = [":update_release_files_lib"], 15 | visibility = ["//visibility:public"], 16 | ) 17 | 18 | go_library( 19 | name = "lib", 20 | srcs = ["main.go"], 21 | importpath = "", 22 | visibility = ["//visibility:private"], 23 | ) 24 | -------------------------------------------------------------------------------- /img/private/release/gazelle_plugin/test_wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # This script is used by the release_files test to run the update tool in test mode 5 | TOOL="@@TOOL@@" 6 | 7 | # MODULE.bazel 8 | MODULE_ROOT=$(dirname "$(realpath "MODULE.bazel")") 9 | 10 | # The test runs with no-sandbox, so we should be able to access the source tree 11 | # We need to find the actual source workspace root, not the execroot 12 | 13 | # First, check if we have BUILD_WORKSPACE_DIRECTORY set (when run with `bazel run`) 14 | if [[ -n "${BUILD_WORKSPACE_DIRECTORY:-}" ]]; then 15 | WORKSPACE_ROOT="$BUILD_WORKSPACE_DIRECTORY" 16 | else 17 | WORKSPACE_ROOT="$MODULE_ROOT" 18 | fi 19 | 20 | echo "Running release_files test in workspace: $WORKSPACE_ROOT" 21 | 22 | # Verify we found the right location 23 | if [[ ! -f "$WORKSPACE_ROOT/MODULE.bazel" ]]; then 24 | echo "ERROR: Could not find MODULE.bazel in $WORKSPACE_ROOT" 25 | echo "Current directory: $(pwd)" 26 | echo "Environment variables:" 27 | echo " BUILD_WORKSPACE_DIRECTORY=${BUILD_WORKSPACE_DIRECTORY:-not set}" 28 | echo " TOOL=${TOOL:-not set}" 29 | echo " MODULE_ROOT=${MODULE_ROOT:-not set}" 30 | exit 1 31 | fi 32 | 33 | # Run the tool in test mode 34 | exec "$TOOL" -repo_root="$WORKSPACE_ROOT" -test 35 | -------------------------------------------------------------------------------- /img/private/release/lockfile/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | # gazelle:exclude_from_release 4 | 5 | go_library( 6 | name = "lockfile_lib", 7 | srcs = ["lockfile.go"], 8 | importpath = "github.com/bazel-contrib/rules_img/img/private/release/lockfile", 9 | visibility = ["//visibility:private"], 10 | ) 11 | 12 | go_binary( 13 | name = "lockfile", 14 | embed = [":lockfile_lib"], 15 | visibility = ["//visibility:public"], 16 | ) 17 | 18 | go_library( 19 | name = "lib", 20 | srcs = ["lockfile.go"], 21 | importpath = "", 22 | visibility = ["//visibility:private"], 23 | ) 24 | -------------------------------------------------------------------------------- /img/private/release/release_notes/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | # gazelle:exclude_from_release 4 | 5 | go_binary( 6 | name = "release_notes", 7 | embed = [":release_notes_lib"], 8 | visibility = ["//img/private/release:__pkg__"], 9 | ) 10 | 11 | go_library( 12 | name = "release_notes_lib", 13 | srcs = ["release_notes.go"], 14 | importpath = "github.com/bazel-contrib/rules_img/img/private/release/release_notes", 15 | visibility = ["//visibility:private"], 16 | ) 17 | -------------------------------------------------------------------------------- /img/private/release/source_files/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # gazelle:exclude_from_release 2 | 3 | # List of files to include in the release tarball 4 | release_files = [ 5 | "//:all_files", 6 | "//img:all_files", 7 | "//img/constraints:all_files", 8 | "//img/private:all_files", 9 | "//img/private/common:all_files", 10 | "//img/private/config:all_files", 11 | "//img/private/platforms:all_files", 12 | "//img/private/prebuilt:all_files", 13 | "//img/private/providers:all_files", 14 | "//img/private/repository_rules:all_files", 15 | "//img/private/settings:all_files", 16 | "//img/settings:all_files", 17 | ] 18 | 19 | filegroup( 20 | name = "release_src_files", 21 | srcs = release_files, 22 | visibility = [ 23 | "//e2e:__pkg__", 24 | "//img/private/release:__subpackages__", 25 | ], 26 | ) 27 | 28 | filegroup( 29 | name = "all_files", 30 | srcs = glob(["*"]), 31 | visibility = ["//img/private/release:__subpackages__"], 32 | ) 33 | -------------------------------------------------------------------------------- /img/private/repository_rules/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | 3 | filegroup( 4 | name = "all_files", 5 | srcs = glob(["**"]), 6 | visibility = ["//img/private/release:__subpackages__"], 7 | ) 8 | 9 | bzl_library( 10 | name = "pull", 11 | srcs = ["pull.bzl"], 12 | visibility = ["//img:__subpackages__"], 13 | deps = [ 14 | ":download", 15 | "//img/private/platforms", 16 | "@bazel_skylib//lib:sets", 17 | "@pull_hub_repo//:defs", 18 | ], 19 | ) 20 | 21 | bzl_library( 22 | name = "pull_blob", 23 | srcs = ["pull_blob.bzl"], 24 | visibility = ["//img:__subpackages__"], 25 | deps = ["@pull_hub_repo//:defs"], 26 | ) 27 | 28 | bzl_library( 29 | name = "download", 30 | srcs = ["download.bzl"], 31 | visibility = ["//img:__subpackages__"], 32 | ) 33 | 34 | bzl_library( 35 | name = "toolchains_repo", 36 | srcs = ["toolchains_repo.bzl"], 37 | visibility = ["//img:__subpackages__"], 38 | ) 39 | -------------------------------------------------------------------------------- /img/private/repository_rules/toolchains_repo.bzl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bazel-contrib/rules_img/b090f01e0de59675ce0bc808c44e73c6d0c016ca/img/private/repository_rules/toolchains_repo.bzl -------------------------------------------------------------------------------- /img/private/resolved_toolchain.bzl: -------------------------------------------------------------------------------- 1 | """This module implements an alias rule to the resolved toolchain.""" 2 | 3 | load("//img/private:image_toolchain.bzl", "TOOLCHAIN_TYPE") 4 | 5 | DOC = """\ 6 | Exposes a concrete toolchain which is the result of Bazel resolving the 7 | toolchain for the execution or target platform. 8 | Workaround for https://github.com/bazelbuild/bazel/issues/14009 9 | """ 10 | 11 | # Forward all the providers 12 | def _resolved_toolchain_impl(ctx): 13 | toolchain_info = ctx.toolchains[TOOLCHAIN_TYPE] 14 | return [ 15 | toolchain_info, 16 | toolchain_info.imgtoolchaininfo, 17 | ] 18 | 19 | # Copied from java_toolchain_alias 20 | # https://cs.opensource.google/bazel/bazel/+/master:tools/jdk/java_toolchain_alias.bzl 21 | resolved_toolchain = rule( 22 | implementation = _resolved_toolchain_impl, 23 | toolchains = [TOOLCHAIN_TYPE], 24 | doc = DOC, 25 | ) 26 | -------------------------------------------------------------------------------- /img/private/settings/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | load("@bazel_skylib//rules:common_settings.bzl", "string_setting") 3 | load(":load.bzl", "load_settings") 4 | load(":oci_layout.bzl", "oci_layout_settings") 5 | load(":settings.bzl", "push_settings") 6 | load(":stamp.bzl", "stamp_build_setting") 7 | 8 | string_setting( 9 | name = "original_platforms", 10 | build_setting_default = "", 11 | visibility = ["//visibility:private"], 12 | ) 13 | 14 | push_settings( 15 | name = "push", 16 | visibility = ["//visibility:public"], 17 | ) 18 | 19 | load_settings( 20 | name = "load", 21 | visibility = ["//visibility:public"], 22 | ) 23 | 24 | oci_layout_settings( 25 | name = "oci_layout", 26 | visibility = ["//visibility:public"], 27 | ) 28 | 29 | bzl_library( 30 | name = "settings", 31 | srcs = ["settings.bzl"], 32 | visibility = ["//img:__subpackages__"], 33 | deps = [ 34 | "//img/private/providers:push_settings_info", 35 | "@bazel_skylib//rules:common_settings", 36 | ], 37 | ) 38 | 39 | config_setting( 40 | name = "stamp_detect", 41 | values = {"stamp": "1"}, 42 | visibility = ["//img:__subpackages__"], 43 | ) 44 | 45 | config_setting( 46 | name = "stamp_user_preference_enabled", 47 | flag_values = {"//img/settings:stamp": "enabled"}, 48 | ) 49 | 50 | stamp_build_setting( 51 | name = "stamp", 52 | bazel_setting = select({ 53 | ":stamp_detect": True, 54 | "//conditions:default": False, 55 | }), 56 | user_preference = select({ 57 | ":stamp_user_preference_enabled": True, 58 | "//conditions:default": False, 59 | }), 60 | visibility = ["//visibility:public"], 61 | ) 62 | 63 | filegroup( 64 | name = "all_files", 65 | srcs = glob(["**"]), 66 | visibility = ["//img/private/release:__subpackages__"], 67 | ) 68 | -------------------------------------------------------------------------------- /img/private/settings/load.bzl: -------------------------------------------------------------------------------- 1 | """Load settings rule.""" 2 | 3 | load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 4 | load("//img/private/providers:load_settings_info.bzl", "LoadSettingsInfo") 5 | 6 | def _load_settings_impl(ctx): 7 | return [LoadSettingsInfo( 8 | strategy = ctx.attr._load_strategy[BuildSettingInfo].value, 9 | daemon = ctx.attr._load_daemon[BuildSettingInfo].value, 10 | remote_cache = ctx.attr._remote_cache[BuildSettingInfo].value, 11 | credential_helper = ctx.attr._credential_helper[BuildSettingInfo].value, 12 | )] 13 | 14 | load_settings = rule( 15 | implementation = _load_settings_impl, 16 | attrs = { 17 | "_load_strategy": attr.label( 18 | default = Label("//img/settings:load_strategy"), 19 | providers = [BuildSettingInfo], 20 | ), 21 | "_load_daemon": attr.label( 22 | default = Label("//img/settings:load_daemon"), 23 | providers = [BuildSettingInfo], 24 | ), 25 | "_remote_cache": attr.label( 26 | default = Label("//img/settings:remote_cache"), 27 | providers = [BuildSettingInfo], 28 | ), 29 | "_credential_helper": attr.label( 30 | default = Label("//img/settings:credential_helper"), 31 | providers = [BuildSettingInfo], 32 | ), 33 | }, 34 | ) 35 | -------------------------------------------------------------------------------- /img/private/settings/oci_layout.bzl: -------------------------------------------------------------------------------- 1 | """Load settings rule.""" 2 | 3 | load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 4 | load("//img/private/providers:oci_layout_settings_info.bzl", "OCILayoutSettingsInfo") 5 | 6 | def _oci_layout_settings_impl(ctx): 7 | return [OCILayoutSettingsInfo( 8 | allow_shallow_oci_layout = ctx.attr._shallow_oci_layout[BuildSettingInfo].value == "i_know_what_i_am_doing", 9 | )] 10 | 11 | oci_layout_settings = rule( 12 | implementation = _oci_layout_settings_impl, 13 | attrs = { 14 | "_shallow_oci_layout": attr.label( 15 | default = Label("//img/settings:shallow_oci_layout"), 16 | providers = [BuildSettingInfo], 17 | ), 18 | }, 19 | ) 20 | -------------------------------------------------------------------------------- /img/private/settings/settings.bzl: -------------------------------------------------------------------------------- 1 | """Build settings for container image rules.""" 2 | 3 | load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") 4 | load("//img/private/providers:push_settings_info.bzl", "PushSettingsInfo") 5 | 6 | def _push_settings_impl(ctx): 7 | strategy = ctx.attr._push_strategy[BuildSettingInfo].value 8 | remote_cache = ctx.attr._remote_cache[BuildSettingInfo].value 9 | credential_helper = ctx.attr._credential_helper[BuildSettingInfo].value 10 | 11 | return [PushSettingsInfo( 12 | strategy = strategy, 13 | remote_cache = remote_cache, 14 | credential_helper = credential_helper, 15 | )] 16 | 17 | push_settings = rule( 18 | implementation = _push_settings_impl, 19 | attrs = { 20 | "_push_strategy": attr.label( 21 | default = Label("//img/settings:push_strategy"), 22 | providers = [BuildSettingInfo], 23 | ), 24 | "_remote_cache": attr.label( 25 | default = Label("//img/settings:remote_cache"), 26 | providers = [BuildSettingInfo], 27 | ), 28 | "_credential_helper": attr.label( 29 | default = Label("//img/settings:credential_helper"), 30 | providers = [BuildSettingInfo], 31 | ), 32 | }, 33 | ) 34 | -------------------------------------------------------------------------------- /img/private/settings/stamp.bzl: -------------------------------------------------------------------------------- 1 | """This file defines the stamp build setting for Bazel.""" 2 | 3 | load("//img/private/providers:stamp_setting_info.bzl", "StampSettingInfo") 4 | 5 | def _stamp_build_setting_impl(ctx): 6 | return StampSettingInfo( 7 | bazel_setting = ctx.attr.bazel_setting, 8 | user_preference = ctx.attr.user_preference, 9 | ) 10 | 11 | stamp_build_setting = rule( 12 | implementation = _stamp_build_setting_impl, 13 | attrs = { 14 | "bazel_setting": attr.bool( 15 | doc = "The value of the stamp build flag", 16 | mandatory = True, 17 | ), 18 | "user_preference": attr.bool( 19 | doc = "Whether the user prefers to use volatile-status.txt and version.txt if present", 20 | mandatory = True, 21 | ), 22 | }, 23 | ) 24 | -------------------------------------------------------------------------------- /img/providers.bzl: -------------------------------------------------------------------------------- 1 | """Provider definitions""" 2 | 3 | load("//img/private/providers:index_info.bzl", _ImageIndexInfo = "ImageIndexInfo") 4 | load("//img/private/providers:layer_info.bzl", _LayerInfo = "LayerInfo") 5 | load("//img/private/providers:manifest_info.bzl", _ImageManifestInfo = "ImageManifestInfo") 6 | load("//img/private/providers:pull_info.bzl", _PullInfo = "PullInfo") 7 | 8 | # providers describing images and their components 9 | LayerInfo = _LayerInfo 10 | ImageManifestInfo = _ImageManifestInfo 11 | ImageIndexInfo = _ImageIndexInfo 12 | 13 | # providers with metadata about pulled base images 14 | PullInfo = _PullInfo 15 | -------------------------------------------------------------------------------- /img/pull.bzl: -------------------------------------------------------------------------------- 1 | """Public API for pulling base container images.""" 2 | 3 | load("//img/private/repository_rules:pull.bzl", _pull = "pull") 4 | 5 | pull = _pull 6 | -------------------------------------------------------------------------------- /img/push.bzl: -------------------------------------------------------------------------------- 1 | """Public API for container image push rules.""" 2 | 3 | load("//img/private:push.bzl", _image_push = "image_push") 4 | 5 | image_push = _image_push 6 | -------------------------------------------------------------------------------- /img_tool/.bazelrc: -------------------------------------------------------------------------------- 1 | common --override_module=rules_img=%workspace%/.. 2 | 3 | import %workspace%/.bazelrc.common 4 | 5 | try-import %workspace%/.bazelrc.user 6 | -------------------------------------------------------------------------------- /img_tool/.bazelrc.common: -------------------------------------------------------------------------------- 1 | ../.bazelrc.common -------------------------------------------------------------------------------- /img_tool/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # gazelle:lang go,proto,bzl 2 | # gazelle:resolve_regexp go github.com/bazel-contrib/rules_img/img_tool/(.*) //$1 3 | # gazelle:map_kind go_proto_library go_proto_library //:go_proto_library.bzl 4 | -------------------------------------------------------------------------------- /img_tool/MODULE.bazel: -------------------------------------------------------------------------------- 1 | module( 2 | name = "rules_img_tool", 3 | version = "0.2.6", 4 | compatibility_level = 1, 5 | ) 6 | 7 | # needs to be placed at the top to ensure the proto toolchain is registered first 8 | bazel_dep(name = "toolchains_protoc", version = "0.5.0", dev_dependency = True) 9 | 10 | bazel_dep(name = "rules_img", version = "0.2.6") 11 | bazel_dep(name = "bazel_lib", version = "3.0.0-beta.1") 12 | bazel_dep(name = "bazel_skylib", version = "1.7.1") 13 | bazel_dep(name = "gazelle", version = "0.45.0") 14 | bazel_dep(name = "googleapis", version = "0.0.0-20250826-a92cee39") 15 | bazel_dep(name = "protobuf", version = "29.5") 16 | bazel_dep(name = "rules_go", version = "0.57.0") 17 | bazel_dep(name = "rules_proto", version = "7.1.0") 18 | 19 | go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") 20 | go_sdk.from_file( 21 | go_mod = "//:go.mod", 22 | ) 23 | 24 | go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") 25 | go_deps.from_file(go_mod = "//:go.mod") 26 | use_repo(go_deps, "com_github_aws_aws_sdk_go_v2", "com_github_aws_aws_sdk_go_v2_config", "com_github_aws_aws_sdk_go_v2_service_s3", "com_github_containerd_containerd_api", "com_github_containerd_stargz_snapshotter_estargz", "com_github_google_uuid", "com_github_klauspost_compress", "com_github_klauspost_pgzip", "com_github_malt3_go_containerregistry", "com_github_opencontainers_go_digest", "com_github_opencontainers_image_spec", "com_google_cloud_go_longrunning", "org_golang_google_genproto_googleapis_api", "org_golang_google_genproto_googleapis_bytestream", "org_golang_google_genproto_googleapis_rpc", "org_golang_google_grpc", "org_golang_google_protobuf", "org_golang_x_sync") 27 | -------------------------------------------------------------------------------- /img_tool/cmd/BUILD.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bazel-contrib/rules_img/b090f01e0de59675ce0bc808c44e73c6d0c016ca/img_tool/cmd/BUILD.bazel -------------------------------------------------------------------------------- /img_tool/cmd/bes/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 3 | 4 | go_library( 5 | name = "bes_lib", 6 | srcs = ["bes.go"], 7 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/bes", 8 | visibility = ["//visibility:private"], 9 | deps = [ 10 | "//pkg/auth/credential", 11 | "//pkg/auth/protohelper", 12 | "//pkg/cas", 13 | "//pkg/proto/build_event_service", 14 | "//pkg/serve/bes", 15 | "//pkg/serve/bes/syncer", 16 | "@org_golang_google_grpc//:grpc", 17 | ], 18 | ) 19 | 20 | go_binary( 21 | name = "bes", 22 | embed = [":bes_lib"], 23 | visibility = ["//visibility:public"], 24 | ) 25 | 26 | build_test( 27 | name = "test", 28 | targets = [":bes"], 29 | ) 30 | -------------------------------------------------------------------------------- /img_tool/cmd/compress/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "compress", 5 | srcs = [ 6 | "compress.go", 7 | "flagtypes.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/compress", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "//pkg/api", 13 | "//pkg/compress", 14 | "//pkg/fileopener", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /img_tool/cmd/compress/flagtypes.go: -------------------------------------------------------------------------------- 1 | package compress 2 | 3 | import ( 4 | "fmt" 5 | "slices" 6 | "strings" 7 | ) 8 | 9 | // annotationsFlag implements flag.Value for key-value pairs 10 | type annotationsFlag map[string]string 11 | 12 | func (a annotationsFlag) String() string { 13 | var keys []string 14 | for k := range a { 15 | keys = append(keys, k) 16 | } 17 | slices.Sort(keys) 18 | var pairs []string 19 | for _, k := range keys { 20 | pairs = append(pairs, fmt.Sprintf("%s=%s", k, a[k])) 21 | } 22 | return strings.Join(pairs, ",") 23 | } 24 | 25 | func (a annotationsFlag) Set(value string) error { 26 | parts := strings.SplitN(value, "=", 2) 27 | if len(parts) != 2 { 28 | return fmt.Errorf("annotation must be in format key=value, got: %s", value) 29 | } 30 | key := strings.TrimSpace(parts[0]) 31 | val := strings.TrimSpace(parts[1]) 32 | if key == "" { 33 | return fmt.Errorf("annotation key cannot be empty") 34 | } 35 | a[key] = val 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /img_tool/cmd/deploy/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "deploy", 5 | srcs = [ 6 | "merge.go", 7 | "metadata.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/deploy", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "//pkg/api", 13 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /img_tool/cmd/dockersave/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "dockersave", 5 | srcs = [ 6 | "dockersave.go", 7 | "flags.go", 8 | "sink.go", 9 | ], 10 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/dockersave", 11 | visibility = ["//visibility:public"], 12 | deps = [ 13 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /img_tool/cmd/dockersave/flags.go: -------------------------------------------------------------------------------- 1 | package dockersave 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // stringSliceFlag is a custom flag type for string slices 9 | type stringSliceFlag []string 10 | 11 | func (s *stringSliceFlag) String() string { 12 | return fmt.Sprintf("%v", *s) 13 | } 14 | 15 | func (s *stringSliceFlag) Set(value string) error { 16 | *s = append(*s, value) 17 | return nil 18 | } 19 | 20 | // layerMapping represents a metadata file to blob file mapping 21 | type layerMapping struct { 22 | metadata string 23 | blob string 24 | } 25 | 26 | // layerMappingFlag is a custom flag type for layer mappings 27 | type layerMappingFlag []layerMapping 28 | 29 | func (l *layerMappingFlag) String() string { 30 | var parts []string 31 | for _, m := range *l { 32 | parts = append(parts, fmt.Sprintf("%s=%s", m.metadata, m.blob)) 33 | } 34 | return strings.Join(parts, ",") 35 | } 36 | 37 | func (l *layerMappingFlag) Set(value string) error { 38 | parts := strings.SplitN(value, "=", 2) 39 | if len(parts) != 2 { 40 | return fmt.Errorf("invalid layer format, expected metadata=blob, got %s", value) 41 | } 42 | *l = append(*l, layerMapping{metadata: parts[0], blob: parts[1]}) 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /img_tool/cmd/downloadblob/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "downloadblob", 5 | srcs = ["downloadblob.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/downloadblob", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/auth/registry", 10 | "@com_github_malt3_go_containerregistry//pkg/name", 11 | "@com_github_malt3_go_containerregistry//pkg/v1/remote", 12 | ], 13 | ) 14 | -------------------------------------------------------------------------------- /img_tool/cmd/expandtemplate/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "expandtemplate", 5 | srcs = ["expandtemplate.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/expandtemplate", 7 | visibility = ["//cmd:__subpackages__"], 8 | ) 9 | -------------------------------------------------------------------------------- /img_tool/cmd/img/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 3 | 4 | go_library( 5 | name = "img_lib", 6 | srcs = ["img.go"], 7 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/img", 8 | visibility = ["//visibility:private"], 9 | deps = [ 10 | "//cmd/compress", 11 | "//cmd/deploy", 12 | "//cmd/dockersave", 13 | "//cmd/downloadblob", 14 | "//cmd/expandtemplate", 15 | "//cmd/index", 16 | "//cmd/layer", 17 | "//cmd/layermeta", 18 | "//cmd/manifest", 19 | "//cmd/ocilayout", 20 | "//cmd/push", 21 | "//cmd/validate", 22 | "@rules_go//go/runfiles", 23 | ], 24 | ) 25 | 26 | go_binary( 27 | name = "img", 28 | embed = [":img_lib"], 29 | pure = "on", 30 | visibility = ["//visibility:public"], 31 | ) 32 | 33 | build_test( 34 | name = "test", 35 | targets = [":img"], 36 | ) 37 | -------------------------------------------------------------------------------- /img_tool/cmd/index/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "index", 5 | srcs = [ 6 | "flags.go", 7 | "index.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/index", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "@com_github_opencontainers_image_spec//specs-go", 13 | "@com_github_opencontainers_image_spec//specs-go/v1:specs-go", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /img_tool/cmd/index/flags.go: -------------------------------------------------------------------------------- 1 | package index 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "maps" 7 | "os" 8 | "slices" 9 | "strings" 10 | 11 | specsv1 "github.com/opencontainers/image-spec/specs-go/v1" 12 | ) 13 | 14 | type manifestDescriptors []specsv1.Descriptor 15 | 16 | func (d *manifestDescriptors) String() string { 17 | if d == nil { 18 | return "" 19 | } 20 | var sb strings.Builder 21 | for i, d := range *d { 22 | if i > 0 { 23 | sb.WriteString(", ") 24 | } 25 | sb.WriteString(string(d.Digest)) 26 | } 27 | return sb.String() 28 | } 29 | 30 | func (d *manifestDescriptors) Set(value string) error { 31 | rawDescriptor, err := os.ReadFile(value) 32 | if err != nil { 33 | return err 34 | } 35 | var descriptor specsv1.Descriptor 36 | if err := json.Unmarshal(rawDescriptor, &descriptor); err != nil { 37 | return err 38 | } 39 | *d = append(*d, descriptor) 40 | return nil 41 | } 42 | 43 | type annotations map[string]string 44 | 45 | func (a *annotations) String() string { 46 | if a == nil { 47 | return "" 48 | } 49 | var sb strings.Builder 50 | keys := slices.Collect(maps.Keys(*a)) 51 | slices.Sort(keys) 52 | for i, key := range keys { 53 | if i > 0 { 54 | sb.WriteString(", ") 55 | } 56 | sb.WriteString(key) 57 | sb.WriteString("=") 58 | sb.WriteString((*a)[key]) 59 | } 60 | return sb.String() 61 | } 62 | 63 | func (a *annotations) Set(value string) error { 64 | if *a == nil { 65 | *a = make(annotations) 66 | } 67 | kv := strings.SplitN(value, "=", 2) 68 | if len(kv) != 2 { 69 | return fmt.Errorf("expected annoation as key-value pair separated by equals, but got %s", kv) 70 | } 71 | (*a)[kv[0]] = kv[1] 72 | return nil 73 | } 74 | -------------------------------------------------------------------------------- /img_tool/cmd/layer/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "layer", 5 | srcs = [ 6 | "flagtypes.go", 7 | "layer.go", 8 | "metadata.go", 9 | "paramfile.go", 10 | ], 11 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/layer", 12 | visibility = ["//visibility:public"], 13 | deps = [ 14 | "//pkg/api", 15 | "//pkg/compress", 16 | "//pkg/contentmanifest", 17 | "//pkg/digestfs", 18 | "//pkg/tarcas", 19 | "//pkg/tree", 20 | "//pkg/tree/runfiles", 21 | "//pkg/tree/treeartifact", 22 | ], 23 | ) 24 | -------------------------------------------------------------------------------- /img_tool/cmd/layermeta/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "layermeta", 5 | srcs = [ 6 | "flagtypes.go", 7 | "layermeta.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/layermeta", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "//pkg/api", 13 | "//pkg/fileopener", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /img_tool/cmd/layermeta/flagtypes.go: -------------------------------------------------------------------------------- 1 | package layermeta 2 | 3 | import ( 4 | "fmt" 5 | "slices" 6 | "strings" 7 | ) 8 | 9 | // annotationsFlag implements flag.Value for key-value pairs 10 | type annotationsFlag map[string]string 11 | 12 | func (a annotationsFlag) String() string { 13 | var keys []string 14 | for k := range a { 15 | keys = append(keys, k) 16 | } 17 | slices.Sort(keys) 18 | var pairs []string 19 | for _, k := range keys { 20 | pairs = append(pairs, fmt.Sprintf("%s=%s", k, a[k])) 21 | } 22 | return strings.Join(pairs, ",") 23 | } 24 | 25 | func (a annotationsFlag) Set(value string) error { 26 | parts := strings.SplitN(value, "=", 2) 27 | if len(parts) != 2 { 28 | return fmt.Errorf("annotation must be in format key=value, got: %s", value) 29 | } 30 | key := strings.TrimSpace(parts[0]) 31 | val := strings.TrimSpace(parts[1]) 32 | if key == "" { 33 | return fmt.Errorf("annotation key cannot be empty") 34 | } 35 | a[key] = val 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /img_tool/cmd/manifest/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "manifest", 5 | srcs = [ 6 | "flagtypes.go", 7 | "manifest.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/manifest", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "//pkg/api", 13 | "@com_github_opencontainers_go_digest//:go-digest", 14 | "@com_github_opencontainers_image_spec//specs-go", 15 | "@com_github_opencontainers_image_spec//specs-go/v1:specs-go", 16 | ], 17 | ) 18 | -------------------------------------------------------------------------------- /img_tool/cmd/manifest/flagtypes.go: -------------------------------------------------------------------------------- 1 | package manifest 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strings" 7 | ) 8 | 9 | type fileList []string 10 | 11 | func (l *fileList) String() string { 12 | return strings.Join(*l, ", ") 13 | } 14 | 15 | func (l *fileList) Set(value string) error { 16 | if _, err := os.Stat(value); err != nil { 17 | return fmt.Errorf("file %s does not exist: %w", value, err) 18 | } 19 | *l = append(*l, value) 20 | return nil 21 | } 22 | 23 | type stringList []string 24 | 25 | func (l *stringList) String() string { 26 | return strings.Join(*l, ", ") 27 | } 28 | 29 | func (l *stringList) Set(value string) error { 30 | *l = append(*l, value) 31 | return nil 32 | } 33 | 34 | type stringMap map[string]string 35 | 36 | func (m *stringMap) String() string { 37 | var parts []string 38 | for k, v := range *m { 39 | parts = append(parts, fmt.Sprintf("%s=%s", k, v)) 40 | } 41 | return strings.Join(parts, ", ") 42 | } 43 | 44 | func (m *stringMap) Set(value string) error { 45 | if *m == nil { 46 | *m = make(map[string]string) 47 | } 48 | parts := strings.SplitN(value, "=", 2) 49 | if len(parts) != 2 { 50 | return fmt.Errorf("invalid key=value format: %s", value) 51 | } 52 | (*m)[parts[0]] = parts[1] 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /img_tool/cmd/ocilayout/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "ocilayout", 5 | srcs = [ 6 | "copy_linux.go", 7 | "copy_other.go", 8 | "flags.go", 9 | "ocilayout.go", 10 | "sink.go", 11 | ], 12 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/ocilayout", 13 | visibility = ["//visibility:public"], 14 | deps = [ 15 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 16 | ], 17 | ) 18 | -------------------------------------------------------------------------------- /img_tool/cmd/ocilayout/copy_linux.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | 3 | package ocilayout 4 | 5 | import ( 6 | "fmt" 7 | "io" 8 | "os" 9 | "syscall" 10 | ) 11 | 12 | // tryReflink attempts to use FICLONE ioctl for efficient copying on Linux 13 | // This creates a reflink (copy-on-write) copy when supported by the filesystem 14 | func tryReflink(src, dst string) error { 15 | srcFile, err := os.Open(src) 16 | if err != nil { 17 | return err 18 | } 19 | defer srcFile.Close() 20 | 21 | dstFile, err := os.Create(dst) 22 | if err != nil { 23 | return err 24 | } 25 | defer dstFile.Close() 26 | 27 | // Try FICLONE ioctl for reflink copy 28 | // FICLONE = 0x40049409 29 | _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, dstFile.Fd(), 0x40049409, srcFile.Fd()) 30 | if errno == 0 { 31 | return nil 32 | } 33 | 34 | // If FICLONE is not supported (e.g., different filesystem, not btrfs/xfs), 35 | // fall back to regular copy 36 | if errno == syscall.ENOTSUP || errno == syscall.EXDEV || errno == syscall.EINVAL { 37 | _, err = io.Copy(dstFile, srcFile) 38 | return err 39 | } 40 | 41 | return fmt.Errorf("FICLONE ioctl failed: %v", errno) 42 | } 43 | -------------------------------------------------------------------------------- /img_tool/cmd/ocilayout/copy_other.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | 3 | package ocilayout 4 | 5 | import ( 6 | "io" 7 | "os" 8 | ) 9 | 10 | // tryReflink is not supported on non-Linux platforms, so it just does a regular copy 11 | func tryReflink(src, dst string) error { 12 | srcFile, err := os.Open(src) 13 | if err != nil { 14 | return err 15 | } 16 | defer srcFile.Close() 17 | 18 | dstFile, err := os.Create(dst) 19 | if err != nil { 20 | return err 21 | } 22 | defer dstFile.Close() 23 | 24 | _, err = io.Copy(dstFile, srcFile) 25 | return err 26 | } 27 | -------------------------------------------------------------------------------- /img_tool/cmd/ocilayout/flags.go: -------------------------------------------------------------------------------- 1 | package ocilayout 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | // stringSliceFlag is a custom flag type for string slices 9 | type stringSliceFlag []string 10 | 11 | func (s *stringSliceFlag) String() string { 12 | return fmt.Sprintf("%v", *s) 13 | } 14 | 15 | func (s *stringSliceFlag) Set(value string) error { 16 | *s = append(*s, value) 17 | return nil 18 | } 19 | 20 | // layerMapping represents a metadata file to blob file mapping 21 | type layerMapping struct { 22 | metadata string 23 | blob string 24 | } 25 | 26 | // layerMappingFlag is a custom flag type for layer mappings 27 | type layerMappingFlag []layerMapping 28 | 29 | func (l *layerMappingFlag) String() string { 30 | var parts []string 31 | for _, m := range *l { 32 | parts = append(parts, fmt.Sprintf("%s=%s", m.metadata, m.blob)) 33 | } 34 | return strings.Join(parts, ",") 35 | } 36 | 37 | func (l *layerMappingFlag) Set(value string) error { 38 | parts := strings.SplitN(value, "=", 2) 39 | if len(parts) != 2 { 40 | return fmt.Errorf("invalid layer format, expected metadata=blob, got %s", value) 41 | } 42 | *l = append(*l, layerMapping{metadata: parts[0], blob: parts[1]}) 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /img_tool/cmd/push/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "push", 5 | srcs = ["push.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/push", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/api", 10 | "//pkg/auth/credential", 11 | "//pkg/auth/protohelper", 12 | "//pkg/auth/registry", 13 | "//pkg/cas", 14 | "//pkg/deployvfs", 15 | "//pkg/load", 16 | "//pkg/proto/blobcache", 17 | "//pkg/push", 18 | "@org_golang_x_sync//errgroup", 19 | ], 20 | ) 21 | -------------------------------------------------------------------------------- /img_tool/cmd/registry/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 3 | 4 | go_library( 5 | name = "registry_lib", 6 | srcs = [ 7 | "flagtypes.go", 8 | "registry.go", 9 | ], 10 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/registry", 11 | visibility = ["//visibility:private"], 12 | deps = [ 13 | "//pkg/auth/credential", 14 | "//pkg/auth/protohelper", 15 | "//pkg/proto/blobcache", 16 | "//pkg/serve/blobcache", 17 | "//pkg/serve/registry", 18 | "//pkg/serve/registry/reapi", 19 | "//pkg/serve/registry/s3", 20 | "//pkg/serve/registry/upstream", 21 | "@com_github_aws_aws_sdk_go_v2_config//:config", 22 | "@com_github_malt3_go_containerregistry//pkg/registry", 23 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 24 | "@org_golang_google_grpc//:grpc", 25 | ], 26 | ) 27 | 28 | go_binary( 29 | name = "registry", 30 | embed = [":registry_lib"], 31 | pure = "on", 32 | visibility = ["//visibility:public"], 33 | ) 34 | 35 | build_test( 36 | name = "test", 37 | targets = [":registry"], 38 | ) 39 | -------------------------------------------------------------------------------- /img_tool/cmd/registry/flagtypes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "strings" 6 | ) 7 | 8 | type blobStores []string 9 | 10 | func (s *blobStores) String() string { 11 | if s == nil || len(*s) == 0 { 12 | return "" 13 | } 14 | return strings.Join(*s, ", ") 15 | } 16 | 17 | func (s *blobStores) Set(value string) error { 18 | switch strings.ToLower(value) { 19 | case "s3", "reapi", "upstream": 20 | // Valid values, do nothing. 21 | default: 22 | return errors.New("invalid blob store type: " + value) 23 | } 24 | *s = append(*s, value) 25 | return nil 26 | } 27 | -------------------------------------------------------------------------------- /img_tool/cmd/validate/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "validate", 5 | srcs = ["validate.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/validate", 7 | visibility = ["//visibility:public"], 8 | deps = ["//cmd/validate/layer-presence"], 9 | ) 10 | -------------------------------------------------------------------------------- /img_tool/cmd/validate/layer-presence/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "layer-presence", 5 | srcs = [ 6 | "flags.go", 7 | "layerpresence.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/cmd/validate/layer-presence", 10 | visibility = ["//visibility:public"], 11 | deps = ["//pkg/api"], 12 | ) 13 | -------------------------------------------------------------------------------- /img_tool/cmd/validate/validate.go: -------------------------------------------------------------------------------- 1 | package validate 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | 8 | layerpresence "github.com/bazel-contrib/rules_img/img_tool/cmd/validate/layer-presence" 9 | ) 10 | 11 | const usage = `Usage img validate [COMMAND] [ARGS...] 12 | 13 | Commands: 14 | layer-presence Checks that layers used for deduplication are present in a final image.` 15 | 16 | func ValidationProcess(ctx context.Context, args []string) { 17 | if len(args) < 1 { 18 | fmt.Fprintln(os.Stderr, usage) 19 | os.Exit(1) 20 | } 21 | 22 | command := args[0] 23 | switch command { 24 | case "layer-presence": 25 | layerpresence.LayerPresenceProcess(ctx, args[1:]) 26 | default: 27 | fmt.Fprintln(os.Stderr, usage) 28 | os.Exit(1) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /img_tool/pkg/api/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "api", 5 | srcs = [ 6 | "api.go", 7 | "binary.go", 8 | "commands.go", 9 | "deploy.go", 10 | ], 11 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/api", 12 | visibility = ["//visibility:public"], 13 | ) 14 | -------------------------------------------------------------------------------- /img_tool/pkg/api/commands.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | const ( 4 | PushCommand = "push" 5 | LoadCommand = "load" 6 | ) 7 | -------------------------------------------------------------------------------- /img_tool/pkg/auth/credential/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library", "go_test") 2 | 3 | go_library( 4 | name = "credential", 5 | srcs = ["credentialhelper.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/auth/credential", 7 | visibility = ["//visibility:public"], 8 | ) 9 | 10 | go_test( 11 | name = "credential_test", 12 | srcs = ["credentialhelper_test.go"], 13 | embed = [":credential"], 14 | ) 15 | -------------------------------------------------------------------------------- /img_tool/pkg/auth/credential/credentialhelper_test.go: -------------------------------------------------------------------------------- 1 | package credential 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | ) 7 | 8 | func TestNew_ReplacesWorkspacePlaceholder(t *testing.T) { 9 | // Set up environment variable 10 | orig := os.Getenv("BUILD_WORKSPACE_DIRECTORY") 11 | defer os.Setenv("BUILD_WORKSPACE_DIRECTORY", orig) 12 | os.Setenv("BUILD_WORKSPACE_DIRECTORY", "/tmp/workspace") 13 | 14 | helper := New("%workspace%/bin/helper") 15 | extHelper, ok := helper.(*externalCredentialHelper) 16 | if !ok { 17 | t.Fatalf("expected *externalCredentialHelper, got %T", helper) 18 | } 19 | expected := "/tmp/workspace/bin/helper" 20 | if extHelper.helperBinary != expected { 21 | t.Errorf("expected helperBinary to be %q, got %q", expected, extHelper.helperBinary) 22 | } 23 | } 24 | 25 | func TestNew_WithoutWorkspacePlaceholder(t *testing.T) { 26 | orig := os.Getenv("BUILD_WORKSPACE_DIRECTORY") 27 | defer os.Setenv("BUILD_WORKSPACE_DIRECTORY", orig) 28 | os.Setenv("BUILD_WORKSPACE_DIRECTORY", "/tmp/workspace") 29 | 30 | helper := New("/usr/local/bin/helper") 31 | extHelper, ok := helper.(*externalCredentialHelper) 32 | if !ok { 33 | t.Fatalf("expected *externalCredentialHelper, got %T", helper) 34 | } 35 | expected := "/usr/local/bin/helper" 36 | if extHelper.helperBinary != expected { 37 | t.Errorf("expected helperBinary to be %q, got %q", expected, extHelper.helperBinary) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /img_tool/pkg/auth/grpcheaderinterceptor/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "grpcheaderinterceptor", 5 | srcs = ["grpcheaderinterceptor.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/auth/grpcheaderinterceptor", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/auth/credential", 10 | "@org_golang_google_grpc//:grpc", 11 | "@org_golang_google_grpc//metadata", 12 | ], 13 | ) 14 | -------------------------------------------------------------------------------- /img_tool/pkg/auth/protohelper/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "protohelper", 5 | srcs = ["protohelper.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/auth/protohelper", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/auth/credential", 10 | "//pkg/auth/grpcheaderinterceptor", 11 | "@org_golang_google_grpc//:grpc", 12 | "@org_golang_google_grpc//credentials", 13 | "@org_golang_google_grpc//credentials/insecure", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /img_tool/pkg/auth/protohelper/protohelper.go: -------------------------------------------------------------------------------- 1 | package protohelper 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "slices" 7 | "strings" 8 | "sync" 9 | 10 | "google.golang.org/grpc" 11 | "google.golang.org/grpc/credentials" 12 | "google.golang.org/grpc/credentials/insecure" 13 | 14 | credhelper "github.com/bazel-contrib/rules_img/img_tool/pkg/auth/credential" 15 | "github.com/bazel-contrib/rules_img/img_tool/pkg/auth/grpcheaderinterceptor" 16 | ) 17 | 18 | func Client(uri string, helper credhelper.Helper, opts ...grpc.DialOption) (*grpc.ClientConn, error) { 19 | opts = slices.Clone(opts) 20 | schemeAndRest := strings.SplitN(uri, "://", 2) 21 | if len(schemeAndRest) != 2 { 22 | return nil, fmt.Errorf("invalid uri for grpc: %s", uri) 23 | } 24 | switch schemeAndRest[0] { 25 | case "grpc": 26 | // unencrypted grpc 27 | warnUnencryptedGRPC(uri) 28 | opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) 29 | case "grpcs": 30 | opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(nil))) 31 | default: 32 | return nil, fmt.Errorf("unsupported scheme for grpc: %s", schemeAndRest[0]) 33 | } 34 | 35 | target := fmt.Sprintf("dns:%s", schemeAndRest[1]) 36 | 37 | opts = append(opts, grpcheaderinterceptor.DialOptions(helper)...) 38 | 39 | return grpc.NewClient(target, opts...) 40 | } 41 | 42 | func warnUnencryptedGRPC(uri string) { 43 | warnMutex.Lock() 44 | defer warnMutex.Unlock() 45 | 46 | if _, warned := WarnedURIs[uri]; warned { 47 | return 48 | } 49 | WarnedURIs[uri] = struct{}{} 50 | fmt.Fprintf(os.Stderr, "WARNING: using unencrypted grpc connection to %s - please consider using grpcs instead", uri) 51 | } 52 | 53 | // WarnedURIs is a set of URIs that have already been warned about. 54 | // It is protected by warnMutex, which must be held when accessing it. 55 | var ( 56 | WarnedURIs = make(map[string]struct{}) 57 | warnMutex sync.Mutex 58 | ) 59 | -------------------------------------------------------------------------------- /img_tool/pkg/auth/registry/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "registry", 5 | srcs = ["registry.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/auth/registry", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "@com_github_malt3_go_containerregistry//pkg/authn", 10 | "@com_github_malt3_go_containerregistry//pkg/v1/google", 11 | "@com_github_malt3_go_containerregistry//pkg/v1/remote", 12 | ], 13 | ) 14 | -------------------------------------------------------------------------------- /img_tool/pkg/auth/registry/registry.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | import ( 4 | "github.com/malt3/go-containerregistry/pkg/authn" 5 | "github.com/malt3/go-containerregistry/pkg/v1/google" 6 | "github.com/malt3/go-containerregistry/pkg/v1/remote" 7 | ) 8 | 9 | // WithAuthFromMultiKeychain returns a remote.Option that uses a MultiKeychain 10 | // combining the default keychain and the Google keychain for authentication. 11 | // WARNING: keep in sync with the same function in img_tool/pkg/auth/registry/registry.go. 12 | func WithAuthFromMultiKeychain() remote.Option { 13 | kc := authn.NewMultiKeychain( 14 | authn.DefaultKeychain, 15 | google.Keychain, 16 | ) 17 | 18 | return remote.WithAuthFromKeychain(kc) 19 | } 20 | -------------------------------------------------------------------------------- /img_tool/pkg/cas/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "cas", 5 | srcs = [ 6 | "error.go", 7 | "read.go", 8 | "write.go", 9 | ], 10 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/cas", 11 | visibility = ["//visibility:public"], 12 | deps = [ 13 | "//pkg/proto/remote-apis/build/bazel/remote/execution/v2", 14 | "@com_github_google_uuid//:uuid", 15 | "@org_golang_google_genproto_googleapis_bytestream//:bytestream", 16 | "@org_golang_google_grpc//:grpc", 17 | ], 18 | ) 19 | -------------------------------------------------------------------------------- /img_tool/pkg/cas/error.go: -------------------------------------------------------------------------------- 1 | package cas 2 | 3 | import "fmt" 4 | 5 | type CASError struct { 6 | underlying error 7 | } 8 | 9 | func casErr(err error) error { 10 | if err == nil { 11 | return nil 12 | } 13 | return &CASError{underlying: err} 14 | } 15 | 16 | func (e *CASError) Error() string { 17 | return fmt.Sprintf("from Bazel remote cache: %v", e.underlying) 18 | } 19 | 20 | func (e *CASError) Unwrap() error { 21 | return e.underlying 22 | } 23 | -------------------------------------------------------------------------------- /img_tool/pkg/compress/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "compress", 5 | srcs = [ 6 | "compress.go", 7 | "estargz.go", 8 | "factory.go", 9 | "options.go", 10 | ], 11 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/compress", 12 | visibility = ["//visibility:public"], 13 | deps = [ 14 | "//pkg/api", 15 | "@com_github_containerd_stargz_snapshotter_estargz//:estargz", 16 | "@com_github_containerd_stargz_snapshotter_estargz//zstdchunked", 17 | "@com_github_klauspost_compress//zstd", 18 | "@com_github_klauspost_pgzip//:pgzip", 19 | ], 20 | ) 21 | -------------------------------------------------------------------------------- /img_tool/pkg/compress/options.go: -------------------------------------------------------------------------------- 1 | package compress 2 | 3 | type Option interface { 4 | apply(*options) 5 | } 6 | 7 | type ContentType string 8 | 9 | type HashAlgorithm string 10 | 11 | type CompressionAlgorithm string 12 | 13 | type CompressionLevel int 14 | 15 | type options struct { 16 | contentType ContentType 17 | compressionLevel *CompressionLevel 18 | compressorJobs *int 19 | } 20 | 21 | func (c ContentType) apply(opts *options) { opts.contentType = c } 22 | func (l CompressionLevel) apply(opts *options) { opts.compressionLevel = &l } 23 | type CompressorJobs int 24 | func (j CompressorJobs) apply(opts *options) { v := int(j); opts.compressorJobs = &v } 25 | -------------------------------------------------------------------------------- /img_tool/pkg/compress/util/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 2 | 3 | go_library( 4 | name = "util_lib", 5 | srcs = ["util.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/compress/util", 7 | visibility = ["//visibility:private"], 8 | deps = [ 9 | "//pkg/api", 10 | "//pkg/compress", 11 | ], 12 | ) 13 | 14 | go_binary( 15 | name = "util", 16 | embed = [":util_lib"], 17 | visibility = ["//visibility:public"], 18 | ) 19 | -------------------------------------------------------------------------------- /img_tool/pkg/containerd/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "containerd", 5 | srcs = [ 6 | "client.go", 7 | "content.go", 8 | "images.go", 9 | "lease.go", 10 | "namespace.go", 11 | "support.go", 12 | ], 13 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/containerd", 14 | visibility = ["//visibility:public"], 15 | deps = [ 16 | "@com_github_containerd_containerd_api//services/content/v1:content", 17 | "@com_github_containerd_containerd_api//services/images/v1:images", 18 | "@com_github_containerd_containerd_api//services/leases/v1:leases", 19 | "@com_github_containerd_containerd_api//types", 20 | "@com_github_opencontainers_go_digest//:go-digest", 21 | "@com_github_opencontainers_image_spec//specs-go/v1:specs-go", 22 | "@org_golang_google_grpc//:grpc", 23 | "@org_golang_google_grpc//codes", 24 | "@org_golang_google_grpc//credentials/insecure", 25 | "@org_golang_google_grpc//metadata", 26 | "@org_golang_google_grpc//status", 27 | "@org_golang_google_protobuf//types/known/fieldmaskpb", 28 | ], 29 | ) 30 | -------------------------------------------------------------------------------- /img_tool/pkg/containerd/lease.go: -------------------------------------------------------------------------------- 1 | package containerd 2 | 3 | import ( 4 | "context" 5 | "crypto/rand" 6 | "encoding/hex" 7 | 8 | api "github.com/containerd/containerd/api/services/leases/v1" 9 | ) 10 | 11 | // ImageService is the image service interface 12 | type LeaseService interface { 13 | Create(ctx context.Context, labels map[string]string) (string, error) 14 | Delete(ctx context.Context, id string) error 15 | } 16 | 17 | type leaseService struct { 18 | client api.LeasesClient 19 | } 20 | 21 | func generateLeaseID() string { 22 | b := make([]byte, 16) 23 | rand.Read(b) 24 | return "lease-" + hex.EncodeToString(b) 25 | } 26 | 27 | // Create creates a new image 28 | func (s *leaseService) Create(ctx context.Context, labels map[string]string) (string, error) { 29 | req := &api.CreateRequest{ 30 | ID: generateLeaseID(), 31 | Labels: labels, 32 | } 33 | 34 | resp, err := s.client.Create(ctx, req) 35 | if err != nil { 36 | return "", err 37 | } 38 | 39 | return resp.Lease.ID, nil 40 | } 41 | 42 | // Update updates an existing image 43 | func (s *leaseService) Delete(ctx context.Context, lease string) error { 44 | req := &api.DeleteRequest{ 45 | ID: lease, 46 | } 47 | 48 | _, err := s.client.Delete(ctx, req) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | return nil 54 | } 55 | -------------------------------------------------------------------------------- /img_tool/pkg/contentmanifest/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "contentmanifest", 5 | srcs = [ 6 | "contentmanifest.go", 7 | "multiimporter.go", 8 | "nopexporter.go", 9 | ], 10 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/contentmanifest", 11 | visibility = ["//visibility:public"], 12 | deps = ["//pkg/api"], 13 | ) 14 | -------------------------------------------------------------------------------- /img_tool/pkg/contentmanifest/nopexporter.go: -------------------------------------------------------------------------------- 1 | package contentmanifest 2 | 3 | import "github.com/bazel-contrib/rules_img/img_tool/pkg/api" 4 | 5 | type nopexporter struct{} 6 | 7 | func NopExporter() api.CASStateExporter { 8 | return nopexporter{} 9 | } 10 | 11 | func (nopexporter) Export(api.CASStateSupplier) error { 12 | return nil 13 | } 14 | -------------------------------------------------------------------------------- /img_tool/pkg/deployvfs/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "deployvfs", 5 | srcs = [ 6 | "deployvfs.go", 7 | "image.go", 8 | "index.go", 9 | ], 10 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/deployvfs", 11 | visibility = ["//visibility:public"], 12 | deps = [ 13 | "//pkg/api", 14 | "//pkg/cas", 15 | "@com_github_malt3_go_containerregistry//pkg/name", 16 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 17 | "@com_github_malt3_go_containerregistry//pkg/v1/remote", 18 | "@com_github_malt3_go_containerregistry//pkg/v1/types", 19 | "@rules_go//go/runfiles", 20 | ], 21 | ) 22 | -------------------------------------------------------------------------------- /img_tool/pkg/digestfs/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "digestfs", 5 | srcs = [ 6 | "digestfs.go", 7 | "precacher.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/digestfs", 10 | visibility = ["//visibility:public"], 11 | ) 12 | -------------------------------------------------------------------------------- /img_tool/pkg/docker/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "docker", 5 | srcs = [ 6 | "load.go", 7 | "stream.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/docker", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 13 | "@com_github_opencontainers_go_digest//:go-digest", 14 | "@com_github_opencontainers_image_spec//specs-go/v1:specs-go", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /img_tool/pkg/docker/load.go: -------------------------------------------------------------------------------- 1 | package docker 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "os/exec" 8 | ) 9 | 10 | // Load pipes the tar stream to docker load 11 | func Load(tarReader io.Reader) error { 12 | loaderBinary, ok := os.LookupEnv("LOADER_BINARY") 13 | if !ok { 14 | loaderBinary = "docker" 15 | } 16 | 17 | if _, err := exec.LookPath(loaderBinary); err != nil { 18 | return fmt.Errorf("%s not found in PATH: %w", loaderBinary, err) 19 | } 20 | 21 | fmt.Fprintf(os.Stderr, "Using %s as loader binary\n", loaderBinary) 22 | 23 | cmd := exec.Command(loaderBinary, "load") 24 | cmd.Stdin = tarReader 25 | cmd.Stdout = os.Stdout 26 | cmd.Stderr = os.Stderr 27 | 28 | if err := cmd.Run(); err != nil { 29 | return fmt.Errorf("%s load failed: %w", loaderBinary, err) 30 | } 31 | 32 | return nil 33 | } 34 | 35 | // NormalizeTag normalizes a tag for Docker 36 | func NormalizeTag(tag string) string { 37 | if tag == "" { 38 | return "" 39 | } 40 | 41 | // Docker load expects the full image reference 42 | // The normalization happens in the Load function in pkg/load 43 | return tag 44 | } 45 | -------------------------------------------------------------------------------- /img_tool/pkg/fileopener/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "fileopener", 5 | srcs = ["fileopener.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/fileopener", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/api", 10 | "@com_github_klauspost_compress//zstd", 11 | ], 12 | ) 13 | -------------------------------------------------------------------------------- /img_tool/pkg/load/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "load", 5 | srcs = [ 6 | "load.go", 7 | "loader.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/load", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "//pkg/api", 13 | "//pkg/containerd", 14 | "//pkg/docker", 15 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 16 | "@com_github_opencontainers_go_digest//:go-digest", 17 | "@com_github_opencontainers_image_spec//specs-go/v1:specs-go", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/bazel/src/main/java/com/google/devtools/build/lib/buildeventstream/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("//:go_proto_library.bzl", "go_proto_library") 3 | 4 | # gazelle:exclude build_event_stream.pb.go 5 | 6 | proto_library( 7 | name = "build_event_stream_proto", 8 | srcs = ["build_event_stream.proto"], 9 | strip_import_prefix = "/pkg/proto/bazel", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "//pkg/proto/bazel/src/main/java/com/google/devtools/build/lib/packages/metrics:devtools_build_lib_packages_metrics_proto", 13 | "//pkg/proto/bazel/src/main/protobuf:proto", 14 | "@protobuf//:any_proto", 15 | "@protobuf//:duration_proto", 16 | "@protobuf//:timestamp_proto", 17 | ], 18 | ) 19 | 20 | go_proto_library( 21 | name = "buildeventstream", 22 | compilers = [ 23 | "@rules_go//proto:go_proto", 24 | ], 25 | filenames = ["build_event_stream.pb.go"], 26 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/proto/bazel/src/main/java/com/google/devtools/build/lib/buildeventstream", 27 | proto = ":build_event_stream_proto", 28 | visibility = ["//visibility:public"], 29 | deps = [ 30 | "//pkg/proto/bazel/src/main/java/com/google/devtools/build/lib/packages/metrics", 31 | "//pkg/proto/bazel/src/main/protobuf", 32 | ], 33 | ) 34 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/bazel/src/main/java/com/google/devtools/build/lib/packages/metrics/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("//:go_proto_library.bzl", "go_proto_library") 3 | 4 | # gazelle:exclude package_load_metrics.pb.go 5 | 6 | proto_library( 7 | name = "devtools_build_lib_packages_metrics_proto", 8 | srcs = ["package_load_metrics.proto"], 9 | strip_import_prefix = "/pkg/proto/bazel", 10 | visibility = ["//visibility:public"], 11 | deps = ["@protobuf//:duration_proto"], 12 | ) 13 | 14 | go_proto_library( 15 | name = "metrics", 16 | compilers = ["@rules_go//proto:go_proto"], 17 | filenames = ["package_load_metrics.pb.go"], 18 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/proto/bazel/src/main/java/com/google/devtools/build/lib/packages/metrics", 19 | proto = ":devtools_build_lib_packages_metrics_proto", 20 | visibility = ["//visibility:public"], 21 | ) 22 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/bazel/src/main/protobuf/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("//:go_proto_library.bzl", "go_proto_library") 3 | 4 | # gazelle:exclude *.pb.go 5 | 6 | proto_library( 7 | name = "proto", 8 | srcs = [ 9 | "action_cache.proto", 10 | "command_line.proto", 11 | "failure_details.proto", 12 | "invocation_policy.proto", 13 | "option_filters.proto", 14 | "strategy_policy.proto", 15 | ], 16 | strip_import_prefix = "/pkg/proto/bazel", 17 | visibility = ["//visibility:public"], 18 | deps = ["@protobuf//:descriptor_proto"], 19 | ) 20 | 21 | go_proto_library( 22 | name = "protobuf", 23 | compilers = [ 24 | "@rules_go//proto:go_proto", 25 | ], 26 | filenames = [ 27 | "action_cache.pb.go", 28 | "command_line.pb.go", 29 | "failure_details.pb.go", 30 | "invocation_policy.pb.go", 31 | "option_filters.pb.go", 32 | "strategy_policy.pb.go", 33 | ], 34 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/proto/bazel/src/main/protobuf", 35 | proto = ":proto", 36 | visibility = ["//visibility:public"], 37 | ) 38 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/blobcache/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("//:go_proto_library.bzl", "go_proto_library") 3 | 4 | # gazelle:exclude blobcache.pb.go 5 | # gazelle:exclude blobcache_grpc.pb.go 6 | 7 | proto_library( 8 | name = "blobcache_proto", 9 | srcs = ["blobcache.proto"], 10 | visibility = ["//visibility:public"], 11 | # keep 12 | deps = ["//pkg/proto/remote-apis/build/bazel/remote/execution/v2:remote_execution_proto"], 13 | ) 14 | 15 | go_proto_library( 16 | name = "blobcache", 17 | compilers = [ 18 | "@rules_go//proto:go_proto", 19 | "@rules_go//proto:go_grpc_v2", 20 | ], 21 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/proto/blobcache", 22 | proto = ":blobcache_proto", 23 | visibility = ["//visibility:public"], 24 | deps = [ 25 | "//pkg/proto/remote-apis/build/bazel/remote/execution/v2", 26 | ], 27 | ) 28 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/blobcache/blobcache.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package pkg.proto.blobcache; 4 | 5 | option go_package = "github.com/bazel-contrib/rules_img/pkg/proto/blobcache;blobcache"; 6 | 7 | import "build/bazel/remote/execution/v2/remote_execution.proto"; 8 | 9 | // Service definition for blob management 10 | service Blobs { 11 | // Commits a list of blobs to the cache. 12 | // This RPC: 13 | // - Ensures FindMissingBlobs is called on the backing CAS 14 | // - Prefills the cache with blob existence and size information 15 | // - Returns the list of successfully committed digests 16 | rpc Commit(CommitRequest) returns (CommitResponse) {} 17 | } 18 | 19 | message CommitRequest { 20 | // List of digests to commit to the cache 21 | repeated build.bazel.remote.execution.v2.Digest blob_digests = 1; 22 | // The digest function used for the digests. 23 | // This is typically SHA256, but can be different if the server supports it. 24 | build.bazel.remote.execution.v2.DigestFunction.Value digest_function = 2; 25 | } 26 | 27 | // Response message for the Commit RPC 28 | message CommitResponse { 29 | // List of digests that are missing in the cache 30 | // everything else is considered committed. 31 | repeated build.bazel.remote.execution.v2.Digest missing_blob_digests = 1; 32 | } 33 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/build_event_service/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("//:go_proto_library.bzl", "go_proto_library") 2 | 3 | # gazelle:exclude build_event_service.go 4 | 5 | go_proto_library( 6 | name = "build_event_service", 7 | compilers = [ 8 | "@rules_go//proto:go_grpc", 9 | ], 10 | filenames = [ 11 | "build_events.pb.go", 12 | "build_status.pb.go", 13 | "publish_build_event.pb.go", 14 | ], 15 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/proto/build_event_service", 16 | proto = "@googleapis//google/devtools/build/v1:build_proto", 17 | visibility = ["//visibility:public"], 18 | deps = [ 19 | "@org_golang_google_genproto_googleapis_api//annotations", 20 | ], 21 | ) 22 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/remote-apis/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # gazelle:proto_strip_import_prefix /pkg/proto/remote-apis 2 | # gazelle:resolve proto go build/bazel/remote/execution/v2/remote_execution.proto //pkg/proto/remote-apis/build/bazel/remote/execution/v2 3 | # gazelle:resolve proto go build/bazel/semver/semver.proto //pkg/proto/remote-apis/build/bazel/semver 4 | # gazelle:resolve proto go google/api/annotations.proto @org_golang_google_genproto_googleapis_api//annotations 5 | # gazelle:resolve proto go google/longrunning/operations.proto @com_google_cloud_go_longrunning//autogen/longrunningpb 6 | # gazelle:resolve proto go google/rpc/status.proto @org_golang_google_genproto_googleapis_rpc//status 7 | # gazelle:resolve proto proto build/bazel/remote/execution/v2/remote_execution.proto //pkg/proto/remote-apis/build/bazel/remote/execution/v2:remoteexecution_proto 8 | # gazelle:resolve proto proto build/bazel/semver/semver.proto //pkg/proto/remote-apis/build/bazel/semver:semver_proto 9 | # gazelle:resolve proto proto google/api/annotations.proto @googleapis//google/api:annotations_proto 10 | # gazelle:resolve proto proto google/longrunning/operations.proto @googleapis//google/longrunning:operations_proto 11 | # gazelle:resolve proto proto google/protobuf/any.proto @protobuf//:any_proto 12 | # gazelle:resolve proto proto google/protobuf/duration.proto @protobuf//:duration_proto 13 | # gazelle:resolve proto proto google/protobuf/timestamp.proto @protobuf//:timestamp_proto 14 | # gazelle:resolve proto proto google/protobuf/wrappers.proto @protobuf//:wrappers_proto 15 | # gazelle:resolve proto proto google/rpc/status.proto @googleapis//google/rpc:status_proto 16 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/remote-apis/build/bazel/remote/execution/v2/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("//:go_proto_library.bzl", "go_proto_library") 3 | 4 | # gazelle:exclude remote_execution.pb.go 5 | # gazelle:exclude remote_execution_grpc.pb.go 6 | 7 | proto_library( 8 | name = "remote_execution_proto", 9 | srcs = ["remote_execution.proto"], 10 | strip_import_prefix = "/pkg/proto/remote-apis", 11 | visibility = ["//visibility:public"], 12 | deps = [ 13 | "//pkg/proto/remote-apis/build/bazel/semver:semver_proto", 14 | "@googleapis//google/api:annotations_proto", 15 | "@googleapis//google/longrunning:operations_proto", 16 | "@googleapis//google/rpc:status_proto", 17 | "@protobuf//:any_proto", 18 | "@protobuf//:duration_proto", 19 | "@protobuf//:timestamp_proto", 20 | "@protobuf//:wrappers_proto", 21 | ], 22 | ) 23 | 24 | go_proto_library( 25 | name = "v2", 26 | compilers = [ 27 | "@rules_go//proto:go_proto", 28 | "@rules_go//proto:go_grpc_v2", 29 | ], 30 | filenames = [ 31 | "remote_execution.pb.go", 32 | "remote_execution_grpc.pb.go", 33 | ], 34 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/proto/remote-apis/build/bazel/remote/execution/v2", 35 | proto = ":remote_execution_proto", 36 | visibility = ["//visibility:public"], 37 | deps = [ 38 | "//pkg/proto/remote-apis/build/bazel/semver", 39 | "@com_google_cloud_go_longrunning//autogen/longrunningpb", 40 | "@org_golang_google_genproto_googleapis_api//annotations", 41 | "@org_golang_google_genproto_googleapis_rpc//status", 42 | ], 43 | ) 44 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/remote-apis/build/bazel/semver/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("//:go_proto_library.bzl", "go_proto_library") 3 | 4 | proto_library( 5 | name = "semver_proto", 6 | srcs = ["semver.proto"], 7 | strip_import_prefix = "/pkg/proto/remote-apis", 8 | visibility = ["//visibility:public"], 9 | ) 10 | 11 | go_proto_library( 12 | name = "semver", 13 | compilers = ["@rules_go//proto:go_proto"], 14 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/proto/remote-apis/build/bazel/semver", 15 | proto = ":semver_proto", 16 | visibility = ["//visibility:public"], 17 | ) 18 | -------------------------------------------------------------------------------- /img_tool/pkg/proto/remote-apis/build/bazel/semver/semver.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Bazel Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package build.bazel.semver; 18 | 19 | option csharp_namespace = "Build.Bazel.Semver"; 20 | option go_package = "github.com/bazelbuild/remote-apis/build/bazel/semver"; 21 | option java_multiple_files = true; 22 | option java_outer_classname = "SemverProto"; 23 | option java_package = "build.bazel.semver"; 24 | option objc_class_prefix = "SMV"; 25 | 26 | // The full version of a given tool. 27 | message SemVer { 28 | // The major version, e.g 10 for 10.2.3. 29 | int32 major = 1; 30 | 31 | // The minor version, e.g. 2 for 10.2.3. 32 | int32 minor = 2; 33 | 34 | // The patch version, e.g 3 for 10.2.3. 35 | int32 patch = 3; 36 | 37 | // The pre-release version. Either this field or major/minor/patch fields 38 | // must be filled. They are mutually exclusive. Pre-release versions are 39 | // assumed to be earlier than any released versions. 40 | string prerelease = 4; 41 | } 42 | -------------------------------------------------------------------------------- /img_tool/pkg/push/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "push", 5 | srcs = ["push.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/push", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/api", 10 | "//pkg/proto/blobcache", 11 | "//pkg/proto/remote-apis/build/bazel/remote/execution/v2", 12 | "@com_github_malt3_go_containerregistry//pkg/name", 13 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 14 | "@com_github_malt3_go_containerregistry//pkg/v1/remote", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /img_tool/pkg/serve/bes/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "bes", 5 | srcs = ["bes.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/serve/bes", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/proto/bazel/src/main/java/com/google/devtools/build/lib/buildeventstream", 10 | "//pkg/proto/build_event_service", 11 | "//pkg/serve/bes/syncer", 12 | "@org_golang_google_protobuf//proto", 13 | "@org_golang_google_protobuf//types/known/emptypb", 14 | "@org_golang_x_sync//errgroup", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /img_tool/pkg/serve/bes/syncer/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "syncer", 5 | srcs = ["syncer.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/serve/bes/syncer", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/api", 10 | "//pkg/auth/registry", 11 | "//pkg/cas", 12 | "@com_github_malt3_go_containerregistry//pkg/name", 13 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 14 | "@com_github_malt3_go_containerregistry//pkg/v1/remote", 15 | "@com_github_malt3_go_containerregistry//pkg/v1/types", 16 | "@org_golang_x_sync//errgroup", 17 | ], 18 | ) 19 | -------------------------------------------------------------------------------- /img_tool/pkg/serve/blobcache/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "blobcache", 5 | srcs = ["blobcache.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/serve/blobcache", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/proto/blobcache", 10 | "//pkg/proto/remote-apis/build/bazel/remote/execution/v2", 11 | "//pkg/serve/registry", 12 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 13 | "@org_golang_google_grpc//:grpc", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /img_tool/pkg/serve/registry/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "registry", 5 | srcs = [ 6 | "blobsizecache.go", 7 | "combined.go", 8 | ], 9 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/serve/registry", 10 | visibility = ["//visibility:public"], 11 | deps = [ 12 | "@com_github_malt3_go_containerregistry//pkg/registry", 13 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 14 | "@com_github_malt3_go_containerregistry//pkg/v1/types", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /img_tool/pkg/serve/registry/reapi/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "reapi", 5 | srcs = ["reapi.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/serve/registry/reapi", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/cas", 10 | "//pkg/serve/registry", 11 | "@com_github_malt3_go_containerregistry//pkg/registry", 12 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 13 | "@org_golang_google_grpc//:grpc", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /img_tool/pkg/serve/registry/s3/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "s3", 5 | srcs = ["s3.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/serve/registry/s3", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "@com_github_aws_aws_sdk_go_v2//aws/transport/http", 10 | "@com_github_aws_aws_sdk_go_v2_config//:config", 11 | "@com_github_aws_aws_sdk_go_v2_service_s3//:s3", 12 | "@com_github_malt3_go_containerregistry//pkg/registry", 13 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /img_tool/pkg/serve/registry/upstream/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "upstream", 5 | srcs = ["upstream.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/serve/registry/upstream", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/auth/registry", 10 | "@com_github_malt3_go_containerregistry//pkg/name", 11 | "@com_github_malt3_go_containerregistry//pkg/registry", 12 | "@com_github_malt3_go_containerregistry//pkg/v1:pkg", 13 | "@com_github_malt3_go_containerregistry//pkg/v1/remote", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /img_tool/pkg/tarcas/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "tarcas", 5 | srcs = [ 6 | "factory.go", 7 | "options.go", 8 | "tarcas.go", 9 | "tarmetadata.go", 10 | ], 11 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/tarcas", 12 | visibility = ["//visibility:public"], 13 | deps = [ 14 | "//pkg/api", 15 | "//pkg/digestfs", 16 | "//pkg/tree/merkle", 17 | ], 18 | ) 19 | -------------------------------------------------------------------------------- /img_tool/pkg/tarcas/factory.go: -------------------------------------------------------------------------------- 1 | package tarcas 2 | 3 | import ( 4 | "crypto/sha256" 5 | "errors" 6 | "hash" 7 | 8 | "github.com/bazel-contrib/rules_img/img_tool/pkg/api" 9 | "github.com/bazel-contrib/rules_img/img_tool/pkg/digestfs" 10 | ) 11 | 12 | type SHA256Helper struct{} 13 | 14 | func (SHA256Helper) New() hash.Hash { 15 | return sha256.New() 16 | } 17 | 18 | func NewSHA256CAS(appender api.TarAppender, options ...Option) *CAS[SHA256Helper] { 19 | return New[SHA256Helper](appender, options...) 20 | } 21 | 22 | func NewSHA256CASWithDigestFS(appender api.TarAppender, digestFS *digestfs.FileSystem, options ...Option) *CAS[SHA256Helper] { 23 | return NewWithDigestFS[SHA256Helper](appender, digestFS, options...) 24 | } 25 | 26 | func CASFactory(hashAlgorithm string, appender api.TarAppender, options ...Option) (api.TarCAS, error) { 27 | switch { 28 | case hashAlgorithm == "sha256": 29 | return NewSHA256CAS(appender, options...), nil 30 | } 31 | return nil, errors.New("unsupported hash algorithm") 32 | } 33 | 34 | func CASFactoryWithDigestFS(hashAlgorithm string, appender api.TarAppender, digestFS *digestfs.FileSystem, options ...Option) (api.TarCAS, error) { 35 | switch { 36 | case hashAlgorithm == "sha256": 37 | return NewSHA256CASWithDigestFS(appender, digestFS, options...), nil 38 | } 39 | return nil, errors.New("unsupported hash algorithm") 40 | } 41 | -------------------------------------------------------------------------------- /img_tool/pkg/tarcas/options.go: -------------------------------------------------------------------------------- 1 | package tarcas 2 | 3 | import "archive/tar" 4 | 5 | type Option interface { 6 | apply(*options) 7 | } 8 | 9 | type FileStructure struct{ inner int } 10 | 11 | var ( 12 | CASFirst = FileStructure{inner: 0} 13 | CASOnly = FileStructure{inner: 1} 14 | Intertwined = FileStructure{inner: 2} 15 | ) 16 | 17 | type WriteHeaderCallback (func(hdr *tar.Header) error) 18 | 19 | type WriteHeaderCallbackFilter uint64 20 | 21 | const ( 22 | WriteHeaderCallbackNone WriteHeaderCallbackFilter = (1 << iota) >> 1 23 | WriteHeaderCallbackRegular 24 | WriteHeaderCallbackDir 25 | WriteHeaderCallbackLink 26 | WriteHeaderCallbackSymlink 27 | 28 | WriteHeaderCallbackFilterDefault = WriteHeaderCallbackDir | WriteHeaderCallbackLink | WriteHeaderCallbackSymlink 29 | WriteHeaderCallbackFilterAll = WriteHeaderCallbackRegular | WriteHeaderCallbackDir | WriteHeaderCallbackLink | WriteHeaderCallbackSymlink 30 | ) 31 | 32 | type options struct { 33 | structure FileStructure 34 | writeHeaderCallback WriteHeaderCallback 35 | writeHeaderCallbackFilter WriteHeaderCallbackFilter 36 | } 37 | 38 | func (s FileStructure) apply(opts *options) { opts.structure = s } 39 | 40 | func (f WriteHeaderCallback) apply(opts *options) { opts.writeHeaderCallback = f } 41 | 42 | func (f WriteHeaderCallbackFilter) apply(opts *options) { opts.writeHeaderCallbackFilter = f } 43 | -------------------------------------------------------------------------------- /img_tool/pkg/tree/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "tree", 5 | srcs = ["recorder.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/tree", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "//pkg/api", 10 | "//pkg/fileopener", 11 | "//pkg/tree/runfiles", 12 | "//pkg/tree/treeartifact", 13 | ], 14 | ) 15 | -------------------------------------------------------------------------------- /img_tool/pkg/tree/merkle/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "merkle", 5 | srcs = [ 6 | "merkle.go", 7 | "treehasher.go", 8 | "types.go", 9 | ], 10 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/tree/merkle", 11 | visibility = ["//visibility:public"], 12 | ) 13 | -------------------------------------------------------------------------------- /img_tool/pkg/tree/merkle/merkle.go: -------------------------------------------------------------------------------- 1 | package merkle 2 | -------------------------------------------------------------------------------- /img_tool/pkg/tree/runfiles/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "runfiles", 5 | srcs = ["runfiles.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/tree/runfiles", 7 | visibility = ["//visibility:public"], 8 | deps = ["//pkg/api"], 9 | ) 10 | -------------------------------------------------------------------------------- /img_tool/pkg/tree/runfiles/runfiles.go: -------------------------------------------------------------------------------- 1 | package runfiles 2 | 3 | import ( 4 | "io/fs" 5 | "iter" 6 | 7 | "github.com/bazel-contrib/rules_img/img_tool/pkg/api" 8 | ) 9 | 10 | type Node interface { 11 | Type() api.FileType 12 | Open() (fs.File, error) 13 | Tree() (fs.FS, error) 14 | } 15 | 16 | // PathNode extends Node with path information for optimization 17 | type PathNode interface { 18 | Node 19 | Path() string 20 | } 21 | 22 | type runfilesFS struct { 23 | entries map[string]Node 24 | sortedEntries []string 25 | } 26 | 27 | func NewRunfilesFS() *runfilesFS { 28 | return &runfilesFS{ 29 | entries: make(map[string]Node), 30 | } 31 | } 32 | 33 | func (r *runfilesFS) Add(name string, entry Node) { 34 | r.sortedEntries = append(r.sortedEntries, name) 35 | r.entries[name] = entry 36 | } 37 | 38 | func (r *runfilesFS) Open(name string) (fs.File, error) { 39 | if entry, ok := r.entries[name]; ok { 40 | return entry.Open() 41 | } 42 | return nil, fs.ErrNotExist 43 | } 44 | 45 | func (r *runfilesFS) Items() iter.Seq2[string, Node] { 46 | return func(yield func(string, Node) bool) { 47 | for _, name := range r.sortedEntries { 48 | if entry, ok := r.entries[name]; ok { 49 | if !yield(name, entry) { 50 | break 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /img_tool/pkg/tree/treeartifact/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "treeartifact", 5 | srcs = ["treeartifact.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/img_tool/pkg/tree/treeartifact", 7 | visibility = ["//visibility:public"], 8 | ) 9 | -------------------------------------------------------------------------------- /img_tool/toolchain/BUILD.bazel: -------------------------------------------------------------------------------- 1 | """Defines toolchains that are built from source (instead of prebuilt downloads). 2 | 3 | These toolchains are not registered by default. 4 | You need to register them explicitly if you want to build from source. 5 | """ 6 | 7 | load("@rules_img//img:image_toolchain.bzl", "TOOLCHAIN_TYPE", "image_toolchain") 8 | 9 | package( 10 | default_visibility = ["//visibility:public"], 11 | ) 12 | 13 | image_toolchain( 14 | name = "image_toolchain", 15 | tool_exe = "//cmd/img", 16 | ) 17 | 18 | toolchain( 19 | name = "toolchain", 20 | toolchain = ":image_toolchain", 21 | toolchain_type = TOOLCHAIN_TYPE, 22 | ) 23 | -------------------------------------------------------------------------------- /img_tool/tools/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # gazelle:exclude_from_release 2 | -------------------------------------------------------------------------------- /img_tool/tools/gopackagesdriver-nix.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | exec nix run .#bazel-fhs -- run -- @rules_go//go/tools/gopackagesdriver "${@}" 3 | -------------------------------------------------------------------------------- /img_tool/tools/gopackagesdriver.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | exec bazel run -- @rules_go//go/tools/gopackagesdriver "${@}" 3 | -------------------------------------------------------------------------------- /prebuilt_lockfile.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /pull_tool/.bazelrc: -------------------------------------------------------------------------------- 1 | common --override_module=rules_img=%workspace%/.. 2 | 3 | import %workspace%/.bazelrc.common 4 | 5 | try-import %workspace%/.bazelrc.user 6 | -------------------------------------------------------------------------------- /pull_tool/.bazelrc.common: -------------------------------------------------------------------------------- 1 | ../.bazelrc.common -------------------------------------------------------------------------------- /pull_tool/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # gazelle:resolve_regexp go github.com/bazel-contrib/rules_img/pull_tool/(.*) //$1 2 | 3 | filegroup( 4 | name = "pull_tool_srcs", 5 | srcs = [ 6 | "go.mod", 7 | "go.sum", 8 | "//cmd/downloadblob:go_srcs", 9 | "//cmd/internal/pull:go_srcs", 10 | "//cmd/pull_tool:go_srcs", 11 | "//pkg/auth/registry:go_srcs", 12 | ], 13 | visibility = ["//visibility:public"], 14 | ) 15 | 16 | alias( 17 | name = "source_bootstrapped_pull_tool", 18 | actual = "@pull_bootstrap//:pull_tool.exe", 19 | ) 20 | -------------------------------------------------------------------------------- /pull_tool/MODULE.bazel: -------------------------------------------------------------------------------- 1 | module( 2 | name = "rules_img_pull_tool", 3 | version = "0.2.6", 4 | compatibility_level = 1, 5 | ) 6 | 7 | bazel_dep(name = "rules_img", version = "0.2.6") 8 | bazel_dep(name = "bazel_skylib", version = "1.7.1") 9 | bazel_dep(name = "gazelle", version = "0.45.0") 10 | bazel_dep(name = "rules_go", version = "0.57.0") 11 | 12 | go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") 13 | 14 | # Known to exist since it is instantiated by rules_go itself. 15 | use_repo( 16 | go_sdk, 17 | "go_host_compatible_sdk_label", 18 | ) 19 | 20 | go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") 21 | go_deps.from_file(go_mod = "//:go.mod") 22 | use_repo(go_deps, "com_github_google_go_containerregistry") 23 | 24 | pull_bootstrap = use_repo_rule("//pull/private:pull_bootstrap.bzl", "pull_bootstrap") 25 | 26 | pull_bootstrap( 27 | name = "pull_bootstrap", 28 | go_mod = "//:go.mod", 29 | go_sum = "//:go.sum", 30 | pull_tool_srcs = ["//:pull_tool_srcs"], 31 | ) 32 | 33 | # register the source bootstrapped pull_tool 34 | pull_tool = use_extension("@rules_img//img/private/prebuilt:prebuilt.bzl", "pull_tool") 35 | pull_tool.host_tool(binary = "@pull_bootstrap//:pull_tool.exe") 36 | -------------------------------------------------------------------------------- /pull_tool/cmd/downloadblob/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "downloadblob", 5 | srcs = ["downloadblob.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/pull_tool/cmd/downloadblob", 7 | visibility = ["//cmd/pull_tool:__pkg__"], 8 | deps = [ 9 | "//pkg/auth/registry", 10 | "@com_github_google_go_containerregistry//pkg/name", 11 | "@com_github_google_go_containerregistry//pkg/v1/remote", 12 | ], 13 | ) 14 | 15 | filegroup( 16 | name = "go_srcs", 17 | srcs = glob(["*.go"]), 18 | visibility = ["//visibility:public"], 19 | ) 20 | -------------------------------------------------------------------------------- /pull_tool/cmd/internal/pull/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "pull", 5 | srcs = ["pull.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/pull_tool/cmd/internal/pull", 7 | # keep 8 | visibility = ["//cmd:__subpackages__"], 9 | deps = [ 10 | "//pkg/auth/registry", 11 | "@com_github_google_go_containerregistry//pkg/name:go_default_library", 12 | "@com_github_google_go_containerregistry//pkg/v1:go_default_library", 13 | "@com_github_google_go_containerregistry//pkg/v1/remote:go_default_library", 14 | ], 15 | ) 16 | 17 | filegroup( 18 | name = "go_srcs", 19 | srcs = glob(["*.go"]), 20 | visibility = ["//visibility:public"], 21 | ) 22 | -------------------------------------------------------------------------------- /pull_tool/cmd/pull_tool/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//rules:build_test.bzl", "build_test") 2 | load("@rules_go//go:def.bzl", "go_binary", "go_library") 3 | 4 | go_library( 5 | name = "pull_tool_lib", 6 | srcs = ["pull_tool.go"], 7 | importpath = "github.com/bazel-contrib/rules_img/pull_tool/cmd/pull_tool", 8 | visibility = ["//visibility:private"], 9 | deps = [ 10 | "//cmd/downloadblob", 11 | "//cmd/internal/pull", 12 | ], 13 | ) 14 | 15 | go_binary( 16 | name = "pull_tool", 17 | embed = [":pull_tool_lib"], 18 | visibility = ["//visibility:public"], 19 | ) 20 | 21 | filegroup( 22 | name = "go_srcs", 23 | srcs = glob(["*.go"]), 24 | visibility = ["//visibility:public"], 25 | ) 26 | 27 | build_test( 28 | name = "test", 29 | targets = [":pull_tool"], 30 | ) 31 | -------------------------------------------------------------------------------- /pull_tool/cmd/pull_tool/pull_tool.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/bazel-contrib/rules_img/pull_tool/cmd/downloadblob" 9 | "github.com/bazel-contrib/rules_img/pull_tool/cmd/internal/pull" 10 | ) 11 | 12 | const usage = `Usage: pull_tool [COMMAND] [ARGS...] 13 | 14 | Commands: 15 | pull pulls an image from a registry 16 | download-blob downloads a single blob from a registry` 17 | 18 | func Run(ctx context.Context, args []string) { 19 | if len(args) < 2 { 20 | fmt.Fprintln(os.Stderr, usage) 21 | os.Exit(1) 22 | } 23 | 24 | command := args[1] 25 | switch command { 26 | case "pull": 27 | pull.PullProcess(ctx, args[2:]) 28 | case "download-blob": 29 | downloadblob.DownloadBlobProcess(ctx, args[2:]) 30 | default: 31 | fmt.Fprintln(os.Stderr, usage) 32 | os.Exit(1) 33 | } 34 | } 35 | 36 | func main() { 37 | ctx := context.Background() 38 | Run(ctx, os.Args) 39 | } 40 | -------------------------------------------------------------------------------- /pull_tool/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bazel-contrib/rules_img/pull_tool 2 | 3 | go 1.24.2 4 | 5 | require github.com/google/go-containerregistry v0.20.6 6 | 7 | require ( 8 | cloud.google.com/go/compute/metadata v0.7.0 // indirect 9 | github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect 10 | github.com/docker/cli v28.2.2+incompatible // indirect 11 | github.com/docker/distribution v2.8.3+incompatible // indirect 12 | github.com/docker/docker-credential-helpers v0.9.3 // indirect 13 | github.com/klauspost/compress v1.18.0 // indirect 14 | github.com/mitchellh/go-homedir v1.1.0 // indirect 15 | github.com/opencontainers/go-digest v1.0.0 // indirect 16 | github.com/opencontainers/image-spec v1.1.1 // indirect 17 | github.com/pkg/errors v0.9.1 // indirect 18 | github.com/sirupsen/logrus v1.9.3 // indirect 19 | github.com/vbatts/tar-split v0.12.1 // indirect 20 | golang.org/x/oauth2 v0.30.0 // indirect 21 | golang.org/x/sync v0.15.0 // indirect 22 | golang.org/x/sys v0.33.0 // indirect 23 | ) 24 | -------------------------------------------------------------------------------- /pull_tool/pkg/auth/registry/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library") 2 | 3 | go_library( 4 | name = "registry", 5 | srcs = ["registry.go"], 6 | importpath = "github.com/bazel-contrib/rules_img/pull_tool/pkg/auth/registry", 7 | visibility = ["//visibility:public"], 8 | deps = [ 9 | "@com_github_google_go_containerregistry//pkg/authn:go_default_library", 10 | "@com_github_google_go_containerregistry//pkg/v1/google:go_default_library", 11 | "@com_github_google_go_containerregistry//pkg/v1/remote:go_default_library", 12 | ], 13 | ) 14 | 15 | filegroup( 16 | name = "go_srcs", 17 | srcs = glob(["*.go"]), 18 | visibility = ["//visibility:public"], 19 | ) 20 | -------------------------------------------------------------------------------- /pull_tool/pkg/auth/registry/registry.go: -------------------------------------------------------------------------------- 1 | package registry 2 | 3 | import ( 4 | "github.com/google/go-containerregistry/pkg/authn" 5 | "github.com/google/go-containerregistry/pkg/v1/google" 6 | "github.com/google/go-containerregistry/pkg/v1/remote" 7 | ) 8 | 9 | // WithAuthFromMultiKeychain returns a remote.Option that uses a MultiKeychain 10 | // combining the default keychain and the Google keychain for authentication. 11 | // WARNING: keep in sync with the same function in img_tool/pkg/auth/registry/registry.go. 12 | func WithAuthFromMultiKeychain() remote.Option { 13 | kc := authn.NewMultiKeychain( 14 | authn.DefaultKeychain, 15 | google.Keychain, 16 | ) 17 | 18 | return remote.WithAuthFromKeychain(kc) 19 | } 20 | -------------------------------------------------------------------------------- /pull_tool/pull/private/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | 3 | bzl_library( 4 | name = "pull_bootstrap", 5 | srcs = ["pull_bootstrap.bzl"], 6 | visibility = ["//pull_tool/pull:__subpackages__"], 7 | ) 8 | -------------------------------------------------------------------------------- /pull_tool_lockfile.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /testdata/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # gazelle:exclude_from_release 2 | 3 | filegroup( 4 | name = "ubuntu_testdata", 5 | srcs = glob(["ubuntu/**"]), 6 | visibility = ["//visibility:public"], 7 | ) 8 | -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/007954392b50fbb4d9669775b8a5da9815347b7a44e1f6fee3d79eb9b5e889c4: -------------------------------------------------------------------------------- 1 | {"schemaVersion": 2, "mediaType": "application/vnd.oci.image.manifest.v1+json", "config": {"mediaType": "application/vnd.oci.image.config.v1+json", "size": 2299, "digest": "sha256:66f54a86848b28b65d2e043af21bede6e0b731fda40bd7e401f5fd06113db84e"}, "layers": [{"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "size": 34340867, "digest": "sha256:7be894b3e11d60e6c310a10016f7c569f1a313b370ab3964114b1c135b1ce53c"}]} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/1dca63d9115cd113e9ec3bbf54d1df6e6a30b45c0c3e31f0f259167cd9b8a074: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 4 | "config": { 5 | "mediaType": "application/vnd.oci.image.config.v1+json", 6 | "digest": "sha256:d25a22bccb9b10015295a27960b618910e90c41a843db543fdc192e74fded660", 7 | "size": 167 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.in-toto+json", 12 | "digest": "sha256:bca5f5a3489e3bb901dc5ab400995bc591f8d30a44a663772f1d587ffb0a11bd", 13 | "size": 1828438, 14 | "annotations": { 15 | "in-toto.io/predicate-type": "https://spdx.dev/Document" 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/21818a28a0ba9b93003d382b6165aa8e222e80e0c514df32b8cc8849c5d5b0bf: -------------------------------------------------------------------------------- 1 | {"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:66ab6ea5ab7e06af33d8e6ea4bea35c17a5e9846592442cab9ec29430e3a788a"]}} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/2abc3421f7c2f72a04e5c749eb23d6d834470cc8e7e2a8b4f4ffb2460a1c92e9: -------------------------------------------------------------------------------- 1 | {"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:9a1f5b0a6ed977ec8cf9d970c2f12337c7e9bad189a16402ab0fab1fd9d47543"]}} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/48d9fe745f1a71878d49aab1623a62782bd5d200d259b1502f4ed1591e8d6004: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 4 | "config": { 5 | "mediaType": "application/vnd.oci.image.config.v1+json", 6 | "digest": "sha256:b416553149aff82057bd12e41752a0a9040f1271f20886c698f7dcc9b3bad3c4", 7 | "size": 167 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.in-toto+json", 12 | "digest": "sha256:c859674e2bdeaf6f5ff56265defaac783d6b8c45c93f9da21a830bb2ff25c1a2", 13 | "size": 1837298, 14 | "annotations": { 15 | "in-toto.io/predicate-type": "https://spdx.dev/Document" 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/5a71a5244bb433561f8bc908e1ed5c0ab81d28a63d1f50a489a619cd60d89733: -------------------------------------------------------------------------------- 1 | {"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a3db90536985f42cb33a0667b800236fe8165a7f8b169654896e1f5ca0bb78de"]}} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/8fe30db6f4cded743d10faed55c5b7d1c49b3a56b55967923fd738e66153e5a0: -------------------------------------------------------------------------------- 1 | {"schemaVersion": 2, "mediaType": "application/vnd.oci.image.manifest.v1+json", "config": {"mediaType": "application/vnd.oci.image.config.v1+json", "size": 2308, "digest": "sha256:6ef9ec95193a604ccbbdbcbd67c61add101017bb776387c667dfbb87ff5319f5"}, "layers": [{"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "size": 26837532, "digest": "sha256:34560582cc6246fb88c88648a1db5ef09d8b65d143991211ba2abe7378aee811"}]} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/92c447e8272fc77dae7baa83d526200d696d536bb6efab11056e2c07c7041032: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 4 | "config": { 5 | "mediaType": "application/vnd.oci.image.config.v1+json", 6 | "digest": "sha256:21818a28a0ba9b93003d382b6165aa8e222e80e0c514df32b8cc8849c5d5b0bf", 7 | "size": 167 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.in-toto+json", 12 | "digest": "sha256:66ab6ea5ab7e06af33d8e6ea4bea35c17a5e9846592442cab9ec29430e3a788a", 13 | "size": 1835456, 14 | "annotations": { 15 | "in-toto.io/predicate-type": "https://spdx.dev/Document" 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/97b5e4984a1c353da6a9406c84554aab0422735a1335427a9e883ac477bd71df: -------------------------------------------------------------------------------- 1 | {"schemaVersion": 2, "mediaType": "application/vnd.oci.image.manifest.v1+json", "config": {"mediaType": "application/vnd.oci.image.config.v1+json", "size": 2314, "digest": "sha256:7fc8925289a890695754108847a52df143c50fb950d185b28ec19be502d09071"}, "layers": [{"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "size": 28846958, "digest": "sha256:49b96e96358d7aed127d4f4cd2294d77d497c683123bbad89fa80a83d8ef64aa"}]} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/b416553149aff82057bd12e41752a0a9040f1271f20886c698f7dcc9b3bad3c4: -------------------------------------------------------------------------------- 1 | {"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:c859674e2bdeaf6f5ff56265defaac783d6b8c45c93f9da21a830bb2ff25c1a2"]}} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/b78100d465e7747e775812b96e0fd23d8aa655ec884b0de56038f4584e1f0571: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 4 | "config": { 5 | "mediaType": "application/vnd.oci.image.config.v1+json", 6 | "digest": "sha256:5a71a5244bb433561f8bc908e1ed5c0ab81d28a63d1f50a489a619cd60d89733", 7 | "size": 167 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.in-toto+json", 12 | "digest": "sha256:a3db90536985f42cb33a0667b800236fe8165a7f8b169654896e1f5ca0bb78de", 13 | "size": 1834451, 14 | "annotations": { 15 | "in-toto.io/predicate-type": "https://spdx.dev/Document" 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/b8e917dce6fe31d9f6804908aa9cf2c5366aa5286e6a71e9ce75f58497f546fa: -------------------------------------------------------------------------------- 1 | {"schemaVersion": 2, "mediaType": "application/vnd.oci.image.manifest.v1+json", "config": {"mediaType": "application/vnd.oci.image.config.v1+json", "size": 2298, "digest": "sha256:d776fa41f2cdbe0504029636136c7756e3a743f8de66cef72e9d7aa5d220061a"}, "layers": [{"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "size": 30943202, "digest": "sha256:ba2f284f7444fb0b78fa804d74c44dee4b397610267539e4a6e9c41ae41e06a1"}]} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/d10afaaf8670c9229d902bab8f43945d9a22b14f3c98c7b5d39d6530066027c2: -------------------------------------------------------------------------------- 1 | {"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:91a29c6784d6a93b8808e70b0057be02f37dcb04a3df90a374cdb6636286cd07"]}} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/d25a22bccb9b10015295a27960b618910e90c41a843db543fdc192e74fded660: -------------------------------------------------------------------------------- 1 | {"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:bca5f5a3489e3bb901dc5ab400995bc591f8d30a44a663772f1d587ffb0a11bd"]}} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/e0e13023bde260c25f24c8efabd322adc745a16c0d6fb2a2714393071b4e5946: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 4 | "config": { 5 | "mediaType": "application/vnd.oci.image.config.v1+json", 6 | "digest": "sha256:2abc3421f7c2f72a04e5c749eb23d6d834470cc8e7e2a8b4f4ffb2460a1c92e9", 7 | "size": 167 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.in-toto+json", 12 | "digest": "sha256:9a1f5b0a6ed977ec8cf9d970c2f12337c7e9bad189a16402ab0fab1fd9d47543", 13 | "size": 1836668, 14 | "annotations": { 15 | "in-toto.io/predicate-type": "https://spdx.dev/Document" 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/e5719e2a817892a6751f019335bbbdf9e52bfa1019645da48495d05952f86195: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 4 | "config": { 5 | "mediaType": "application/vnd.oci.image.config.v1+json", 6 | "digest": "sha256:d10afaaf8670c9229d902bab8f43945d9a22b14f3c98c7b5d39d6530066027c2", 7 | "size": 167 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.in-toto+json", 12 | "digest": "sha256:91a29c6784d6a93b8808e70b0057be02f37dcb04a3df90a374cdb6636286cd07", 13 | "size": 1838778, 14 | "annotations": { 15 | "in-toto.io/predicate-type": "https://spdx.dev/Document" 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/f8b860e4f9036f2694571770da292642eebcc4c2ea0c70a1a9244c2a1d436cd9: -------------------------------------------------------------------------------- 1 | {"schemaVersion": 2, "mediaType": "application/vnd.oci.image.manifest.v1+json", "config": {"mediaType": "application/vnd.oci.image.config.v1+json", "size": 2297, "digest": "sha256:602eb6fb314b5fafad376a32ab55194e535e533dec6552f82b70d7ac0e554b1c"}, "layers": [{"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "size": 29717652, "digest": "sha256:2726e237d1a374379e783053d93d0345c8a3bf3c57b5d35b099de1ad777486ee"}]} -------------------------------------------------------------------------------- /testdata/ubuntu/blobs/sha256/faeeccc166857094a7089a1b67813f4b0fe18a3195c3a47da6f1e8d0ca4b26ef: -------------------------------------------------------------------------------- 1 | {"schemaVersion": 2, "mediaType": "application/vnd.oci.image.manifest.v1+json", "config": {"mediaType": "application/vnd.oci.image.config.v1+json", "size": 2295, "digest": "sha256:74f38fa7c32fd13263ce430206bc5d046dce1543e5263d47919b85a64ccd128b"}, "layers": [{"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", "size": 29956206, "digest": "sha256:e5722f32c6281fa87f1e5f7ebe307864b50aa95a116496a205ce47478bc9b52c"}]} -------------------------------------------------------------------------------- /testdata/ubuntu/config: -------------------------------------------------------------------------------- 1 | blobs/sha256/602eb6fb314b5fafad376a32ab55194e535e533dec6552f82b70d7ac0e554b1c -------------------------------------------------------------------------------- /testdata/ubuntu/manifest: -------------------------------------------------------------------------------- 1 | blobs/sha256/f8b860e4f9036f2694571770da292642eebcc4c2ea0c70a1a9244c2a1d436cd9 -------------------------------------------------------------------------------- /testdata/ubuntu/root: -------------------------------------------------------------------------------- 1 | blobs/sha256/1e622c5f073b4f6bfad6632f2616c7f59ef256e96fe78bf6a595d1dc4376ac02 -------------------------------------------------------------------------------- /tests/compression/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@bazel_skylib//:bzl_library.bzl", "bzl_library") 2 | load("@rules_img//img:layer.bzl", "image_layer") 3 | load(":defs.bzl", "layer_combinations") 4 | 5 | # gazelle:exclude_from_release 6 | 7 | image_layer( 8 | name = "large_1GB", 9 | srcs = { 10 | "/1GB.bin": "@large_file_1GB//file", 11 | }, 12 | tags = [ 13 | "exclusive", 14 | "manual", 15 | "no-cache", 16 | ], 17 | ) 18 | 19 | image_layer( 20 | name = "large_10GB", 21 | srcs = { 22 | "/10GB.bin": "@large_file_10GB//file", 23 | }, 24 | tags = [ 25 | "exclusive", 26 | "manual", 27 | "no-cache", 28 | ], 29 | ) 30 | 31 | layer_combinations() 32 | 33 | bzl_library( 34 | name = "defs", 35 | srcs = ["defs.bzl"], 36 | visibility = ["//visibility:public"], 37 | deps = [ 38 | "@bazel_skylib//rules:build_test", 39 | "@rules_img//img:providers", 40 | ], 41 | ) 42 | 43 | filegroup( 44 | name = "all_files", 45 | srcs = glob(["**"]), 46 | visibility = ["//img/private/release:__subpackages__"], 47 | ) 48 | -------------------------------------------------------------------------------- /tests/img_toolchain/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_go//go:def.bzl", "go_library", "go_test") 2 | 3 | # gazelle:exclude_from_release 4 | 5 | go_library( 6 | name = "img_toolchain", 7 | srcs = ["framework.go"], 8 | importpath = "github.com/bazel-contrib/rules_img/tests/img_toolchain", 9 | visibility = ["//visibility:public"], 10 | deps = [ 11 | "@rules_go//go/runfiles", 12 | ], 13 | ) 14 | 15 | go_test( 16 | name = "img_toolchain_test", 17 | size = "medium", 18 | srcs = ["img_toolchain_test.go"], 19 | data = [ 20 | ":testcases", 21 | "//testdata:ubuntu_testdata", 22 | "@rules_img_tool//cmd/img", 23 | ], 24 | embed = [":img_toolchain"], 25 | ) 26 | 27 | filegroup( 28 | name = "testcases", 29 | srcs = glob(["testcases/*.ini"]), 30 | visibility = ["//visibility:public"], 31 | ) 32 | 33 | filegroup( 34 | name = "all_files", 35 | srcs = glob(["**"]), 36 | visibility = ["//img/private/release:__subpackages__"], 37 | ) 38 | 39 | go_test( 40 | name = "lib_test", 41 | srcs = ["img_toolchain_test.go"], 42 | embed = [":img_toolchain"], 43 | ) 44 | -------------------------------------------------------------------------------- /tests/img_toolchain/img_toolchain_test.go: -------------------------------------------------------------------------------- 1 | package img_toolchain 2 | 3 | import ( 4 | "context" 5 | "path/filepath" 6 | "testing" 7 | ) 8 | 9 | func TestImgToolchain(t *testing.T) { 10 | ctx := context.Background() 11 | 12 | tf, err := NewTestFramework(t) 13 | if err != nil { 14 | t.Fatalf("Failed to create test framework: %v", err) 15 | } 16 | defer tf.Cleanup() 17 | 18 | testFiles, err := filepath.Glob("testcases/*.ini") 19 | if err != nil { 20 | t.Fatalf("Failed to find test files: %v", err) 21 | } 22 | 23 | if len(testFiles) == 0 { 24 | t.Skip("No test files found in testcases/") 25 | } 26 | 27 | for _, testFile := range testFiles { 28 | testCase, err := tf.LoadTestCase(testFile) 29 | if err != nil { 30 | t.Fatalf("Failed to load test case %s: %v", testFile, err) 31 | } 32 | 33 | if err := tf.RunTestCase(ctx, testCase); err != nil { 34 | t.Errorf("Test case %s failed: %v", testFile, err) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/compress_ubuntu_blob.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = compress_ubuntu_blob 3 | description = Test compression functionality with real Ubuntu blob data 4 | 5 | [testdata] 6 | copy = input_blob=ubuntu/blobs/sha256/74f38fa7c32fd13263ce430206bc5d046dce1543e5263d47919b85a64ccd128b 7 | 8 | [command] 9 | subcommand = compress 10 | args = --format gzip input_blob compressed_blob.gz 11 | expect_exit = 0 12 | 13 | [assert] 14 | file_exists = compressed_blob.gz 15 | file_valid_gzip = compressed_blob.gz 16 | file_size_gt = compressed_blob.gz, 10 17 | file_size_lt = compressed_blob.gz, 10000000 18 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/compress_with_annotations.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = compress_with_annotations 3 | description = Compress command with multiple annotations to test determinism - regression test for map iteration order 4 | 5 | [testdata] 6 | copy = input_blob=ubuntu/blobs/sha256/74f38fa7c32fd13263ce430206bc5d046dce1543e5263d47919b85a64ccd128b 7 | 8 | [command] 9 | subcommand = compress 10 | args = --annotation foo=bar --annotation version=1.0 --annotation maintainer=test --annotation environment=production --annotation build_date=2024-01-01 --annotation team=platform --annotation project=rules_img --format=gzip --metadata=compress-meta.json input_blob compressed.tar.gz 11 | expect_exit = 0 12 | 13 | [assert] 14 | file_exists = compressed.tar.gz 15 | file_exists = compress-meta.json 16 | file_valid_json = compress-meta.json 17 | file_contains = compress-meta.json, "foo" 18 | file_contains = compress-meta.json, "bar" 19 | file_contains = compress-meta.json, "version" 20 | file_contains = compress-meta.json, "1.0" 21 | file_contains = compress-meta.json, "maintainer" 22 | file_contains = compress-meta.json, "test" 23 | file_contains = compress-meta.json, "environment" 24 | file_contains = compress-meta.json, "production" 25 | file_contains = compress-meta.json, "build_date" 26 | file_contains = compress-meta.json, "2024-01-01" 27 | file_contains = compress-meta.json, "team" 28 | file_contains = compress-meta.json, "platform" 29 | file_contains = compress-meta.json, "project" 30 | file_contains = compress-meta.json, "rules_img" 31 | file_sha256 = compress-meta.json, "7b492556ebc6c8791f42b36d67adc861fd3751a18ddde88cf150538435aab80c" 32 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/dockersave_format_validation.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = dockersave_format_validation 3 | description = Docker save format validation - should fail with invalid format 4 | 5 | [file] 6 | name = manifest.json 7 | { 8 | "schemaVersion": 2, 9 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 10 | "config": { 11 | "mediaType": "application/vnd.oci.image.config.v1+json", 12 | "size": 1469, 13 | "digest": "sha256:b5b2b2c5072406148de34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9b2c5" 14 | }, 15 | "layers": [] 16 | } 17 | 18 | [file] 19 | name = config.json 20 | { 21 | "architecture": "amd64", 22 | "os": "linux" 23 | } 24 | 25 | [command] 26 | subcommand = docker-save 27 | args = --manifest manifest.json --config config.json --format invalid --output docker-output 28 | expect_exit = 1 29 | 30 | [assert] 31 | stderr_contains = --format must be 'directory' or 'tar', got 'invalid' 32 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/dockersave_tar.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = dockersave_tar 3 | description = Docker save format assembly with tar format 4 | 5 | [file] 6 | name = manifest.json 7 | { 8 | "schemaVersion": 2, 9 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 10 | "config": { 11 | "mediaType": "application/vnd.oci.image.config.v1+json", 12 | "size": 1469, 13 | "digest": "sha256:b5b2b2c5072406148de34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9b2c5" 14 | }, 15 | "layers": [ 16 | { 17 | "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", 18 | "size": 1024, 19 | "digest": "sha256:a1a1a1c507240614ade34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9a1a1" 20 | } 21 | ] 22 | } 23 | 24 | [file] 25 | name = config.json 26 | { 27 | "architecture": "amd64", 28 | "os": "linux", 29 | "config": { 30 | "Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], 31 | "Cmd": ["/bin/sh"] 32 | }, 33 | "rootfs": { 34 | "type": "layers", 35 | "diff_ids": [ 36 | "sha256:a1a1a1c507240614ade34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9a1a1" 37 | ] 38 | } 39 | } 40 | 41 | [file] 42 | name = layer1_metadata.json 43 | { 44 | "name": "layer1", 45 | "digest": "sha256:a1a1a1c507240614ade34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9a1a1", 46 | "size": 1024, 47 | "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip" 48 | } 49 | 50 | [file] 51 | name = layer1.tar.gz 52 | fake layer1 content 53 | 54 | [command] 55 | subcommand = docker-save 56 | args = --manifest manifest.json --config config.json --layer layer1_metadata.json=layer1.tar.gz --repo-tag my/image:latest --repo-tag my/image:v1.0 --format tar --output docker-save.tar 57 | expect_exit = 0 58 | 59 | [assert] 60 | file_exists = docker-save.tar 61 | file_not_exists = docker-save.tar/manifest.json 62 | file_not_exists = docker-save.tar/blobs 63 | # The tar file should have reasonable size (>100 bytes) 64 | file_size_gt = docker-save.tar, 100 65 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/expandtemplate_with_stamps.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = expandtemplate_with_stamps 3 | description = Expand template command with multiple stamp files to test determinism - regression test for map iteration order 4 | 5 | [file] 6 | name = input.json 7 | { 8 | "templates": { 9 | "registry": "{{.REGISTRY}}", 10 | "repository": "{{.REPOSITORY}}/{{.PROJECT}}", 11 | "tags": ["{{.VERSION}}", "{{.BUILD_TAG}}"] 12 | }, 13 | "build_settings": { 14 | "BASE_IMAGE": "ubuntu", 15 | "GO_VERSION": "{{.GO_VERSION}}", 16 | "PLATFORM": "{{.PLATFORM}}", 17 | "BUILD_USER": "{{.BUILD_USER}}", 18 | "EXTRA_VAR": "test" 19 | } 20 | } 21 | 22 | [file] 23 | name = stamp1.txt 24 | REGISTRY gcr.io 25 | REPOSITORY my-org 26 | PROJECT my-app 27 | 28 | [file] 29 | name = stamp2.txt 30 | VERSION v1.2.3 31 | BUILD_TAG latest 32 | GO_VERSION 1.21 33 | 34 | [file] 35 | name = stamp3.txt 36 | PLATFORM linux/amd64 37 | BUILD_USER ci-system 38 | 39 | [command] 40 | subcommand = expand-template 41 | args = --stamp stamp1.txt --stamp stamp2.txt --stamp stamp3.txt input.json output.json 42 | expect_exit = 0 43 | 44 | [assert] 45 | file_exists = output.json 46 | file_valid_json = output.json 47 | file_contains = output.json, "gcr.io" 48 | file_contains = output.json, "my-org/my-app" 49 | file_contains = output.json, "v1.2.3" 50 | file_contains = output.json, "latest" 51 | file_not_contains = output.json, "build_settings" 52 | file_not_contains = output.json, "{{." 53 | file_sha256 = output.json, "3802a113b8db83c22ee40cfcceb3021fa688f6a5696bc0d69d3be2a7f6e8571e" 54 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_gzip_level1_singlethread.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_gzip_level1_singlethread 3 | description = Create a gzip layer using single-threaded stdlib gzip with low compression level 4 | 5 | [file] 6 | name = small.txt 7 | Small content for gzip level test 8 | 9 | [command] 10 | subcommand = layer 11 | args = --add /small.txt=small.txt --format gzip --compressor-jobs 1 --compression-level 1 --metadata layer_meta.json layer.tgz 12 | expect_exit = 0 13 | 14 | [assert] 15 | file_exists = layer.tgz 16 | file_valid_gzip = layer.tgz 17 | file_exists = layer_meta.json 18 | file_valid_json = layer_meta.json 19 | file_contains = layer_meta.json, "tar+gzip" 20 | tar_entry_exists = layer.tgz, small.txt 21 | tar_entry_type = layer.tgz, small.txt, link 22 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_gzip_level9_singlethread.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_gzip_level9_singlethread 3 | description = Create a gzip layer using single-threaded stdlib gzip with high compression level 4 | 5 | [file] 6 | name = big.txt 7 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam. 8 | 9 | [command] 10 | subcommand = layer 11 | args = --add /big.txt=big.txt --format gzip --compressor-jobs 1 --compression-level 9 --metadata layer_meta.json layer.tgz 12 | expect_exit = 0 13 | 14 | [assert] 15 | file_exists = layer.tgz 16 | file_valid_gzip = layer.tgz 17 | file_exists = layer_meta.json 18 | file_valid_json = layer_meta.json 19 | file_contains = layer_meta.json, "tar+gzip" 20 | tar_entry_exists = layer.tgz, big.txt 21 | tar_entry_type = layer.tgz, big.txt, link 22 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_help.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_help 3 | description = Test layer help command 4 | 5 | [command] 6 | subcommand = layer 7 | args = --help 8 | expect_exit = 1 9 | 10 | [assert] 11 | stderr_contains = "Creates a compressed tar file" 12 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_pgzip_auto.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_pgzip_nproc 3 | description = Create a gzip layer using pgzip with nproc jobs 4 | 5 | [file] 6 | name = data.txt 7 | This is some test data to compress with pgzip auto jobs. 8 | 9 | [command] 10 | subcommand = layer 11 | args = --add /data.txt=data.txt --format gzip --compressor-jobs nproc --compression-level 1 --metadata layer_meta.json layer.tgz 12 | expect_exit = 0 13 | 14 | [assert] 15 | file_exists = layer.tgz 16 | file_valid_gzip = layer.tgz 17 | file_exists = layer_meta.json 18 | file_valid_json = layer_meta.json 19 | file_contains = layer_meta.json, "tar+gzip" 20 | tar_entry_exists = layer.tgz, data.txt 21 | tar_entry_type = layer.tgz, data.txt, link 22 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_pgzip_jobs2.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_pgzip_jobs2 3 | description = Create a gzip layer using pgzip with 2 jobs and low compression level 4 | 5 | [file] 6 | name = hello.txt 7 | Hello parallel gzip 8 | 9 | [command] 10 | subcommand = layer 11 | args = --add /hello.txt=hello.txt --format gzip --compressor-jobs 2 --compression-level 1 --metadata layer_meta.json layer.tgz 12 | expect_exit = 0 13 | 14 | [assert] 15 | file_exists = layer.tgz 16 | file_valid_gzip = layer.tgz 17 | file_exists = layer_meta.json 18 | file_valid_json = layer_meta.json 19 | file_contains = layer_meta.json, "tar+gzip" 20 | tar_entry_exists = layer.tgz, hello.txt 21 | tar_entry_type = layer.tgz, hello.txt, link 22 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_real_ubuntu_config.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_real_ubuntu_config 3 | description = Test layer creation using real Ubuntu config from testdata 4 | 5 | [file] 6 | name = ubuntu_config.json 7 | {"architecture": "amd64", "config": {"Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], "Cmd": ["/bin/bash"], "Image": "sha256:9e8e73ef7ecf9677998352379644674e54a6b3104ae7da6d1204d83a4118826f", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": {"org.opencontainers.image.ref.name": "ubuntu", "org.opencontainers.image.version": "24.04"}}, "container": "00abb0934f25966f0f238fb3d52ad7e9f927a59b01c43ec79aabf2594fece2f5", "os": "linux"} 8 | 9 | [file] 10 | name = hello_app.go 11 | package main 12 | 13 | import ( 14 | "fmt" 15 | "runtime" 16 | ) 17 | 18 | func main() { 19 | fmt.Printf("Hello, world from %s %s!\n", runtime.GOOS, runtime.GOARCH) 20 | } 21 | 22 | [command] 23 | subcommand = layer 24 | args = --add /app/hello_app.go=hello_app.go --add /config/ubuntu_config.json=ubuntu_config.json --metadata layer_metadata.json output_layer.tar.gz 25 | expect_exit = 0 26 | 27 | [assert] 28 | file_exists = output_layer.tar.gz 29 | file_exists = layer_metadata.json 30 | file_valid_gzip = output_layer.tar.gz 31 | file_valid_json = layer_metadata.json 32 | json_field_exists = layer_metadata.json, digest 33 | json_field_exists = layer_metadata.json, size 34 | json_field_exists = layer_metadata.json, mediaType 35 | file_size_gt = output_layer.tar.gz, 500 36 | file_contains = layer_metadata.json, "application/vnd.oci.image.layer.v1.tar+gzip" 37 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_simple.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_simple 3 | description = Test layer creation with a simple file 4 | 5 | [file] 6 | name = hello.txt 7 | Hello World 8 | 9 | [command] 10 | subcommand = layer 11 | args = --add /hello.txt=hello.txt layer.tar.gz 12 | expect_exit = 0 13 | 14 | [assert] 15 | file_exists = layer.tar.gz 16 | file_size_gt = layer.tar.gz, 0 17 | file_sha256 = layer.tar.gz, "932b23fe84711678bbcff304577af05652b96f9fc9401a6c1cfba55ffec5f816" 18 | tar_entry_exists = layer.tar.gz, hello.txt 19 | tar_entry_type = layer.tar.gz, hello.txt, link 20 | tar_entry_exists = layer.tar.gz, .cas/blob/a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e 21 | tar_entry_type = layer.tar.gz, .cas/blob/a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e, regular 22 | tar_entry_size = layer.tar.gz, .cas/blob/a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e, 11 23 | tar_entry_sha256 = layer.tar.gz, .cas/blob/a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e, "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e" 24 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_unused_metadata_error.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_unused_metadata_error 3 | description = Test that layer command errors when file metadata is unused 4 | 5 | [file] 6 | name = test.txt 7 | Hello World 8 | 9 | [command] 10 | subcommand = layer 11 | args = --file-metadata nonexistent/file.txt={"mode":"0644"} --file-metadata another/missing.txt={"mode":"0755"} --add test.txt=test.txt layer.tgz 12 | expect_exit = 1 13 | expect_stderr_contains = unused file metadata for paths: another/missing.txt, nonexistent/file.txt 14 | 15 | [assert] 16 | file_exists = layer.tgz 17 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_unused_metadata_single_error.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_unused_metadata_single_error 3 | description = Test that layer command errors with correct message for single unused file metadata 4 | 5 | [file] 6 | name = test.txt 7 | Hello World 8 | 9 | [command] 10 | subcommand = layer 11 | args = --file-metadata nonexistent/file.txt={"mode":"0644"} --add test.txt=test.txt layer.tgz 12 | expect_exit = 1 13 | expect_stderr_contains = unused file metadata for path: nonexistent/file.txt 14 | 15 | [assert] 16 | file_exists = layer.tgz 17 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_with_file_metadata.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_with_file_metadata 3 | description = Test image_layer with custom file metadata - test JSON-encoded file attributes 4 | 5 | [file] 6 | name = app.sh 7 | #!/bin/bash 8 | echo "Hello World" 9 | 10 | [file] 11 | name = config.txt 12 | server_port=8080 13 | debug=true 14 | 15 | [command] 16 | subcommand = layer 17 | args = --default-metadata {"mode":"0644","uid":1000,"gid":1000,"uname":"appuser","gname":"appgroup"} --file-metadata bin/app.sh={"mode":"0755","uid":0,"gid":0} --file-metadata etc/config.txt={"mode":"0600","uid":0,"gid":0,"uname":"root","gname":"root"} --add bin/app.sh=app.sh --add etc/config.txt=config.txt --metadata layer-meta.json layer.tgz 18 | expect_exit = 0 19 | 20 | [assert] 21 | file_exists = layer.tgz 22 | file_exists = layer-meta.json 23 | file_valid_json = layer-meta.json 24 | file_valid_gzip = layer.tgz 25 | file_size_gt = layer.tgz, 10 26 | file_contains = layer-meta.json, "mediaType" 27 | file_contains = layer-meta.json, "sha256:" 28 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/layer_with_ubuntu_blobs.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = layer_with_ubuntu_blobs 3 | description = Test layer operations using Ubuntu blob data from testdata 4 | 5 | [testdata] 6 | copy = test_blob=ubuntu/blobs/sha256/602eb6fb314b5fafad376a32ab55194e535e533dec6552f82b70d7ac0e554b1c 7 | 8 | [command] 9 | subcommand = layer 10 | args = --add /test_blob=test_blob --metadata layer_metadata.json test_layer.tar.gz 11 | expect_exit = 0 12 | 13 | [assert] 14 | file_exists = test_layer.tar.gz 15 | file_exists = layer_metadata.json 16 | file_valid_gzip = test_layer.tar.gz 17 | file_valid_json = layer_metadata.json 18 | file_size_gt = test_layer.tar.gz, 500 19 | json_field_exists = layer_metadata.json, digest 20 | json_field_exists = layer_metadata.json, size 21 | json_field_exists = layer_metadata.json, mediaType 22 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/manifest_basic.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = manifest_basic 3 | description = Test basic manifest and config creation 4 | 5 | [command] 6 | subcommand = manifest 7 | args = --manifest manifest.json --config config.json 8 | expect_exit = 0 9 | 10 | [assert] 11 | file_exists = manifest.json 12 | file_exists = config.json 13 | file_valid_json = manifest.json 14 | file_valid_json = config.json 15 | file_sha256 = config.json, "dc570f145a7f2862c9ef3c30b8d6ae2feaceb0d364e4b2e08e67ae18815427d9" 16 | file_sha256 = manifest.json, "c5c3090c78a69c23565353b874b43eda3ad7c4cfcb855e839f3908ac5a11a9e6" 17 | json_field_exists = manifest.json, schemaVersion 18 | json_field_exists = manifest.json, mediaType 19 | json_field_exists = manifest.json, config 20 | json_field_exists = config.json, architecture 21 | json_field_exists = config.json, os 22 | file_contains = manifest.json, "sha256:dc570f145a7f2862c9ef3c30b8d6ae2feaceb0d364e4b2e08e67ae18815427d9" 23 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/manifest_comprehensive.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = manifest_comprehensive 3 | description = Comprehensive manifest test with environment and labels 4 | 5 | [command] 6 | subcommand = manifest 7 | args = --env HOME=/root --env PATH=/usr/local/bin:/usr/bin --label version=1.0 --label maintainer=test --entrypoint /app/server --manifest manifest.json --config config.json 8 | expect_exit = 0 9 | 10 | [assert] 11 | file_exists = manifest.json 12 | file_exists = config.json 13 | file_valid_json = manifest.json 14 | file_valid_json = config.json 15 | file_sha256 = config.json, "3fb31b605e4f79b48cdcdcf474f06633d11dba0b6ce631eee73dd6f7523b0b63" 16 | file_sha256 = manifest.json, "62f9a4fbc61c8c7c0aefcdd6c2cce5dfe37fbd4d3f3d544c6c2c984915f038b0" 17 | json_field_exists = manifest.json, schemaVersion 18 | json_field_exists = manifest.json, mediaType 19 | json_field_exists = config.json, architecture 20 | json_field_exists = config.json, os 21 | file_contains = config.json, "HOME=/root" 22 | file_contains = config.json, "PATH=/usr/local/bin:/usr/bin" 23 | file_contains = config.json, "version" 24 | file_contains = config.json, "1.0" 25 | file_contains = config.json, "/app/server" 26 | file_contains = manifest.json, "sha256:3fb31b605e4f79b48cdcdcf474f06633d11dba0b6ce631eee73dd6f7523b0b63" 27 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/manifest_layer_integration.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = manifest_layer_integration 3 | description = Test creating layers and manifests using Ubuntu testdata for realistic integration test 4 | 5 | [testdata] 6 | copy = base_config.json=ubuntu/config 7 | copy = base_manifest.json=ubuntu/manifest 8 | copy = sample_blob=ubuntu/blobs/sha256/2abc3421f7c2f72a04e5c749eb23d6d834470cc8e7e2a8b4f4ffb2460a1c92e9 9 | 10 | [file] 11 | name = app_layer.txt 12 | Application layer content for testing 13 | Multi-line content to create a realistic layer 14 | 15 | [command] 16 | subcommand = layer 17 | args = --add /app/app_layer.txt=app_layer.txt --add /blobs/sample_blob=sample_blob --metadata new_layer.json new_layer.tar.gz 18 | expect_exit = 0 19 | 20 | [assert] 21 | file_exists = new_layer.tar.gz 22 | file_exists = new_layer.json 23 | file_valid_gzip = new_layer.tar.gz 24 | file_valid_json = new_layer.json 25 | file_valid_json = base_config.json 26 | file_valid_json = base_manifest.json 27 | file_size_gt = new_layer.tar.gz, 100 28 | json_field_exists = new_layer.json, digest 29 | json_field_exists = new_layer.json, size 30 | json_field_exists = base_config.json, architecture 31 | json_field_exists = base_manifest.json, schemaVersion 32 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/manifest_with_testdata.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = manifest_with_ubuntu_testdata 3 | description = Test manifest creation using real Ubuntu config and manifest from testdata 4 | 5 | [testdata] 6 | copy = ubuntu_config.json=ubuntu/config 7 | copy = ubuntu_manifest.json=ubuntu/manifest 8 | 9 | [command] 10 | subcommand = manifest 11 | args = --base-config ubuntu_config.json --base-manifest ubuntu_manifest.json --manifest processed_manifest.json --config processed_config.json 12 | expect_exit = 0 13 | 14 | [assert] 15 | file_exists = processed_manifest.json 16 | file_exists = processed_config.json 17 | file_valid_json = processed_manifest.json 18 | file_valid_json = processed_config.json 19 | json_field_exists = processed_manifest.json, schemaVersion 20 | json_field_exists = processed_manifest.json, mediaType 21 | json_field_exists = processed_config.json, architecture 22 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/ocilayout_format_validation.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = ocilayout_format_validation 3 | description = OCI layout format validation - should fail with invalid format 4 | 5 | [file] 6 | name = manifest.json 7 | { 8 | "schemaVersion": 2, 9 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 10 | "config": { 11 | "mediaType": "application/vnd.oci.image.config.v1+json", 12 | "size": 1469, 13 | "digest": "sha256:b5b2b2c5072406148de34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9b2c5" 14 | }, 15 | "layers": [] 16 | } 17 | 18 | [file] 19 | name = config.json 20 | { 21 | "architecture": "amd64", 22 | "os": "linux" 23 | } 24 | 25 | [command] 26 | subcommand = oci-layout 27 | args = --manifest manifest.json --config config.json --format invalid --output oci-output 28 | expect_exit = 1 29 | 30 | [assert] 31 | stderr_contains = --format must be 'directory' or 'tar', got 'invalid' 32 | -------------------------------------------------------------------------------- /tests/img_toolchain/testcases/ocilayout_tar.ini: -------------------------------------------------------------------------------- 1 | [test] 2 | name = ocilayout_tar 3 | description = OCI layout assembly with tar format to create OCI tarball 4 | 5 | [file] 6 | name = manifest.json 7 | { 8 | "schemaVersion": 2, 9 | "mediaType": "application/vnd.oci.image.manifest.v1+json", 10 | "config": { 11 | "mediaType": "application/vnd.oci.image.config.v1+json", 12 | "size": 1469, 13 | "digest": "sha256:b5b2b2c5072406148de34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9b2c5" 14 | }, 15 | "layers": [ 16 | { 17 | "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", 18 | "size": 1024, 19 | "digest": "sha256:a1a1a1c507240614ade34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9a1a1" 20 | } 21 | ] 22 | } 23 | 24 | [file] 25 | name = config.json 26 | { 27 | "architecture": "amd64", 28 | "os": "linux", 29 | "config": { 30 | "Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], 31 | "Cmd": ["/bin/sh"] 32 | }, 33 | "rootfs": { 34 | "type": "layers", 35 | "diff_ids": [ 36 | "sha256:a1a1a1c507240614ade34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9a1a1" 37 | ] 38 | } 39 | } 40 | 41 | [file] 42 | name = layer1_metadata.json 43 | { 44 | "name": "layer1", 45 | "digest": "sha256:a1a1a1c507240614ade34c2e87b1b0d4e98a8e99e4b1a4d8b48adf2e07f9a1a1", 46 | "size": 1024, 47 | "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip" 48 | } 49 | 50 | [file] 51 | name = layer1.tar.gz 52 | fake layer1 content 53 | 54 | [command] 55 | subcommand = oci-layout 56 | args = --manifest manifest.json --config config.json --layer layer1_metadata.json=layer1.tar.gz --format tar --output oci-layout.tar 57 | expect_exit = 0 58 | 59 | [assert] 60 | file_exists = oci-layout.tar 61 | file_not_exists = oci-layout.tar/oci-layout 62 | file_not_exists = oci-layout.tar/index.json 63 | # The tar file should have reasonable size (>100 bytes) 64 | file_size_gt = oci-layout.tar, 100 65 | -------------------------------------------------------------------------------- /util/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@buildifier_prebuilt//:rules.bzl", "buildifier", "buildifier_test") 2 | load("@gazelle//:def.bzl", "gazelle", "gazelle_binary") 3 | 4 | # gazelle:exclude_from_release 5 | 6 | buildifier( 7 | name = "buildifier.fix", 8 | diff_command = "diff", 9 | lint_mode = "fix", 10 | mode = "fix", 11 | ) 12 | 13 | buildifier_test( 14 | name = "buildifier.check", 15 | size = "small", 16 | diff_command = "diff", 17 | lint_mode = "warn", 18 | mode = "diff", 19 | no_sandbox = True, 20 | tags = ["no-remote-exec"], 21 | workspace = "//:MODULE.bazel", 22 | ) 23 | 24 | gazelle_binary( 25 | name = "gazelle_bin", 26 | languages = [ 27 | "@gazelle//language/go", 28 | "@gazelle//language/proto", 29 | "@bazel_skylib_gazelle_plugin//bzl", 30 | "//img/private/release/gazelle_plugin:gazelle_plugin", 31 | ], 32 | ) 33 | 34 | gazelle( 35 | name = "gazelle", 36 | gazelle = "gazelle_bin", 37 | ) 38 | --------------------------------------------------------------------------------