)]}'
{
  "commit": "3598c2f92baa66fcd3ad686df216027b42c14d91",
  "tree": "a689a68ba69a8128f992d9f99bf5df823f5fb3e8",
  "parents": [
    "87cc1cd21a0c69dd64d46a0cdd1dc00f27468120"
  ],
  "author": {
    "name": "herdiyanitdev",
    "email": "82978131+herdiyana256@users.noreply.github.com",
    "time": "Wed Aug 26 16:41:57 2026 +0700"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Wed Aug 26 09:41:57 2026 +0000"
  },
  "message": "Validate module name and version derived from PR paths in bcr_presubmit.py (#2759)\n\n`module_name` and `module_version` in `bcr_presubmit.py` are derived\nfrom a pull request\u0027s changed file paths (`modules/\u003cname\u003e/\u003cversion\u003e/`)\nvia `get_target_modules()`, using a regex whose only constraint is \"no\nslash\" (`modules\\/([^\\/]+)\\/([^\\/]+)\\/`). Both values can therefore\ncontain arbitrary shell and Starlark metacharacters.\n\nTwo sinks interpolate these values unescaped:\n- The shell command string built in `add_presubmit_jobs()` (partially\naddressed by #2739\u0027s `shlex.quote` fix at that one call site).\n- The generated `MODULE.bazel` content in `create_anonymous_repo()`:\n  ```python\nscratch_file(root, \"MODULE.bazel\", [\"bazel_dep(name \u003d \u0027%s\u0027, version \u003d\n\u0027%s\u0027)\" % (module_name, module_version)])\n  ```\nA `module_name`/`module_version` containing a single quote closes the\nStarlark string literal early, letting the rest of the payload be parsed\nas new top-level `MODULE.bazel` statements (e.g. `load(...)` + a\nrepository rule invocation), evaluated when `bazel vendor` runs during\n`anonymous_module_runner`/`test_module_runner`. This sink is unaffected\nby #2739, since `shlex.quote` only protects shell-argument parsing, not\nthe raw string value that later reaches this `%`-format call.\n\nThis patch rejects any `module_name`/`module_version` that doesn\u0027t match\nthe character set Bzlmod itself accepts\n(https://bazel.build/external/module#module_name, `#version`) at the\npoint they\u0027re derived from the PR path in\n`get_target_modules()`/`get_modules_with_metadata_change()`. Validating\nat the source closes both the already-partially-fixed shell sink and the\nstill-open `MODULE.bazel` sink (and any future sink in this file) at a\nsingle choke point, rather than escaping per call site.\n\nNormal module names/versions (e.g. `rules_foo` / `1.2.3`, `protobuf` /\n`27.0-rc1`) are unaffected. Anything containing quotes, backticks,\nsemicolons, dollar signs, spaces, or uppercase letters in the name is\nnow rejected before it reaches any downstream sink.",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "be7ff6234327570d41dd206d751b6ccdca85d3b8",
      "old_mode": 33261,
      "old_path": "buildkite/bazel-central-registry/bcr_presubmit.py",
      "new_id": "cc097839b46590930ebcfa88cadef61c421a52c4",
      "new_mode": 33261,
      "new_path": "buildkite/bazel-central-registry/bcr_presubmit.py"
    }
  ]
}
