{"owner":"github","repo":"codeql","hasSkills":true,"totalSkillsCount":3,"totalTokensCount":2784,"categories":["anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["javascript/resources/tools/baseline-config.json","actions/extractor/tools/baseline-config.json",".github/skills/bazel/SKILL.md"],"skills":{"javascript/resources/tools/baseline-config.json":"{\n    \"paths-ignore\": [\n        \"**/node_modules/**\",\n        \"**/bower_components/**\",\n        \"**/*.min.js\",\n        \"**/*-min.js\"\n    ]\n}\n","actions/extractor/tools/baseline-config.json":"{\n    \"paths\": [\n        \".github/workflows/*.yml\",\n        \".github/workflows/*.yaml\",\n        \".github/reusable_workflows/**/*.yml\",\n        \".github/reusable_workflows/**/*.yaml\",\n        \"**/action.yml\",\n        \"**/action.yaml\",\n        \"**/actions.lock\"\n    ]\n}\n",".github/skills/bazel/SKILL.md":"---\nname: bazel\ndescription: Conventions for editing Bazel files in the github/codeql repository: the shared `misc/bazel` helpers, `codeql_platform_select` and the `{CODEQL_PLATFORM}` packaging placeholder, adding `MODULE.bazel` dependencies, and the `semmle_code` stub that keeps the standalone build working. Use when editing any `BUILD.bazel`, `*.bzl`, `MODULE.bazel` or `.bazelrc` here, and before validating such an edit.\n---\n\n# Bazel in the codeql repository\n\nA bzlmod module named `ql`, repo name `@codeql` ([`MODULE.bazel`](../../../MODULE.bazel)). It builds standalone, and is\nalso consumed by an internal module; standalone builds replace that module with a stub.\n\n## Traps\n\nThings that will waste your time or produce a wrong edit here. Read this section even if you skip the rest.\n\n* **`//...` does not work.** `bazel build //...`, and even `bazel query //...`, fail at the repo root: the patched\n  modules under [`misc/bazel/registry`](../../../misc/bazel/registry) are real packages referencing repos that are not\n  visible from the main repo, and [`.bazelrc`](../../../.bazelrc) notes separately that transitions break `...` builds.\n  The error names a registry directory unrelated to your edit, so it is easy to misdiagnose. **Validate the specific\n  target or package you changed**, not a recursive pattern.\n* **There is no `MODULE.bazel.lock`, deliberately.** [`.bazelrc`](../../../.bazelrc) sets `--lockfile_mode=off` because\n  the workspace-relative module override makes a lockfile unstable. Do not add one, and do not \"fix\" its absence.\n* **`linux_arm64` vs `linux-arm64`.** The keyword argument and config setting use an underscore; the platform *string*\n  substituted into paths and zip names uses a hyphen. They are not interchangeable.\n* **Do not stub your way out of a missing internal dependency.** See [Building standalone](#building-standalone) for the\n  one narrow case where extending the stub is correct.\n\n## Conventions\n\n* **Copy a neighboring target rather than inventing a shape.** Packaging is not uniform: some packages use the\n  `codeql_*` wrappers, others still use `pkg_files` directly. Copy the closest *working* neighbor, and prefer the\n  wrapper for new code.\n* **Pin anything fetched over the network** with `sha256` or `integrity`. Bazel only *warns* on an unpinned download, so\n  nothing fails loudly, but the build stops being reproducible and a retagged upstream release silently changes what you\n  build. `lfs_archive` is the exception: content is pinned by git object.\n* **Format with `bazel run //misc/bazel/buildifier`.** It rewrites in place, so do not hand-tune formatting. Also wired\n  as a `pre-commit` hook ([`.pre-commit-config.yaml`](../../../.pre-commit-config.yaml)).\n\n## Where new code goes\n\nBazel's own macro / rule / repository-rule distinction applies as usual. What is repo-specific:\n\n| Adding | Goes in |\n| --- | --- |\n| a new packaging shape | extend [`misc/bazel/pkg.bzl`](../../../misc/bazel/pkg.bzl), do not fork `pkg_files` |\n| a new OS or arch split | [`misc/bazel/os.bzl`](../../../misc/bazel/os.bzl), do not hand-roll a `select()` over `@platforms//` |\n| a fetch of something external | a repository rule ([`lfs.bzl`](../../../misc/bazel/lfs.bzl), [`ripunzip.bzl`](../../../misc/ripunzip/ripunzip.bzl)), not a `genrule` |\n| a wrapper used by one language | next to that language ([`swift/rules.bzl`](../../../swift/rules.bzl)) |\n| a wrapper used across languages | `misc/bazel/` |\n\nPrefer inline rules in `BUILD.bazel`. A `.bzl` file earns its `load()` only when the shape repeats across packages or a\nvalue must be computed: [`rust.bzl`](../../../misc/bazel/rust.bzl) is worth it because every Rust binary that ships in a\npack must get the same universal-binary wrapper and symbols test, and forgetting either is a release bug. A local\ndebugging aid opts out and declares a plain `rust_binary`; see `swift-syntax-parse` in\n[`unified/swift-syntax-rs/BUILD.bazel`](../../../unified/swift-syntax-rs/BUILD.bazel). The `_gen_binaries` list in\n[`go/BUILD.bazel`](../../../go/BUILD.bazel) does not earn a `.bzl`, because it is shared within a single file, where a\nlocal variable does the job.\n\nMacros here are typically a thin public wrapper around a private rule (`codeql_csharp_binary`, `swift_cc_binary`). Keep\nthe rule narrow and the ergonomics in the macro. Each macro decorates the caller's `name` to mint its helper targets,\nfor example `internal/<name>` or `single_arch/<name>`. Their visibility is that macro's choice (private, package\ndefault, or the caller's own), so read the macro instead of assuming. When an error names a target you cannot find in\nany source file, a macro minted it: grep the suffix under `misc/bazel/`.\n\n## Shared helpers\n\nFrequently-used pieces, so you load the existing one instead of rewriting it. Read the file for its actual exports.\n\n| `load()` path | Covers |\n| --- | --- |\n| `//misc/bazel:pkg.bzl` | CodeQL packs and packaging |\n| `//misc/bazel:os.bzl` | platform and architecture selection |\n| `//misc/bazel:lfs.bzl` | on-demand git-LFS repositories |\n| `//misc/bazel:rust.bzl` | Rust binary wrapper |\n| `//misc/bazel:csharp.bzl` | C# binary/library/test wrappers |\n| `//misc/bazel:utils.bzl` | `select_os`; prefer `os.bzl`'s `os_select` in new code |\n\n[`defs.bzl`](../../../defs.bzl) at the root exports `codeql_platform` for *dependent* modules. It is not the way to get\nthe platform string here; use `os.bzl`.\n\n## Platform selection\n\n[`codeql_platform_select`](../../../misc/bazel/os.bzl) takes one keyword argument per CodeQL platform: `linux64`,\n`linux_arm64`, `osx64` and `win64`. `otherwise` supplies the value for whichever of those you leave unset; it is **not**\na `//conditions:default`. **There is deliberately no fallback from `linux_arm64` to `linux64`.** If you only care about\nthe OS, use `os_select`, which gives Linux the same value on both architectures and has a `posix` shorthand for the\nshared Linux/macOS value.\n\nIn a macro (no `ctx`) it returns a `select()`:\n\n```python\nload(\"//misc/bazel:os.bzl\", \"codeql_platform_select\")\nload(\"//misc/bazel:pkg.bzl\", \"codeql_pkg_files\")\n\ncodeql_pkg_files(\n    name = \"extractor-arch\",\n    exes = codeql_platform_select(\n        otherwise = [\"//unified/extractor\"],\n        win64 = [\"//unified/extractor-unsupported-os:extractor\"],\n    ),\n    prefix = \"tools/{CODEQL_PLATFORM}\",\n)\n```\n\nIf implementation code needs to *branch* on the value rather than pass it through, pass `ctx` and add\n`OS_DETECTION_ATTRS` to the rule's attributes. The value is then resolved eagerly instead of being an opaque `select()`:\n\n```python\nload(\"//misc/bazel:os.bzl\", \"OS_DETECTION_ATTRS\", \"os_select\")\n\ndef _impl(ctx):\n    ext = os_select(ctx, windows = \".exe\", posix = \"\")\n    ...\n\nmy_rule = rule(\n    implementation = _impl,\n    attrs = {\"src\": attr.label()} | OS_DETECTION_ATTRS,\n)\n```\n\n## Packs\n\n`codeql_pack` assembles the files that become an extractor pack. See [`unified/BUILD.bazel`](../../../unified/BUILD.bazel)\nfor a minimal complete example and [`pkg.bzl`](../../../misc/bazel/pkg.bzl) for the arguments. The non-obvious parts:\n\n* **`{CODEQL_PLATFORM}` in a destination path is the routing mechanism**, not just a substitution. A path containing it\n  is *arch-specific* and lands in the per-architecture zip; every other path is *common*. So `prefix =\n  \"tools/{CODEQL_PLATFORM}\"` both places the file and marks it arch-specific. `arch_overrides` forces named\n  destinations into the arch-specific part without a placeholder.\n* **`codeql_pkg_files` splits `srcs` (plain) from `exes` (mode 755)** and **rejects `attributes =`** with an explicit\n  error. Use `exes` rather than hand-rolling `pkg_attributes(mode = \"755\")`.\n* **`pkg_dirs` and `pkg_symlinks` are unsupported** and fail at analysis time.\n* `codeql_pack` also generates an installer and an `install` alias, hence `bazel run //unified:install`. Pass\n  `installer_alias = None` if one package defines several packs.\n* `codeql_pack_group` exists for bundling packs into distribution zips, but nothing in this repo instantiates it.\n\n## Adding a dependency\n\nIn order of preference:\n\n1. **A [Bazel Central Registry](https://registry.bazel.build/) module.** Add a `bazel_dep` in\n   [`MODULE.bazel`](../../../MODULE.bazel).\n2. **A patched upstream module.** Add it under [`misc/bazel/registry`](../../../misc/bazel/registry), which `.bazelrc`\n   puts ahead of the BCR. Put patches in `modules/<repo>/<version>/patches`, rename the version with a `-codeql.N`\n   suffix, and run [`fix.py`](../../../misc/bazel/registry/fix.py) to realign the metadata.\n3. **A raw archive.** Use `http_archive` via `use_repo_rule`, or a repository rule. Copy an adjacent declaration and\n   keep its checksum field populated.\n\nVendored Rust crates under [`misc/bazel/3rdparty`](../../../misc/bazel/3rdparty) are generated. Regenerate with\n[`update_cargo_deps.sh`](../../../misc/bazel/3rdparty/update_cargo_deps.sh) rather than editing, and keep the\n`use_repo` lists in sync, which `bazel mod tidy` does for module extensions.\n\n## Building standalone\n\n[`MODULE.bazel`](../../../MODULE.bazel) declares `semmle_code` with a `local_path_override` pointing at `..`, which\nresolves when this repo is checked out inside the internal module. [`.bazelrc`](../../../.bazelrc), which Bazel reads\nwhen invoked in *this* workspace, overrides that with a stub. This line is the whole reason a standalone build resolves:\n\n```\ncommon --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub\n```\n\nDo not change either the override path or the `local_path_override`; they work as a pair.\n\n[`misc/bazel/semmle_code_stub`](../../../misc/bazel/semmle_code_stub) is an otherwise empty module supplying no-op\nversions of the internal helpers that shared `.bzl` files load *unconditionally*. That is its only job, and it is small\nenough to read.\n\n**Extend the stub only when a `.bzl` file every standalone target loads gains a new internal `load()`**, which breaks\npackage loading outright, for everyone. Prefer not needing one. **Never add a stub so that an internal-only target\nappears to build**: some targets depend on internal libraries (`grep -rl @semmle_code --include=*.bazel` finds them) and\nare correctly unbuildable here. Unlike a `load()`, such a dependency only fails when that target is actually requested.\n\n[`.bazelrc.internal`](../../../.bazelrc.internal) is **not** read here; it carries settings for the internal build. A\nsetting needed by both has to be written in both files, with paths differing because this repo sits at a different depth\nthere.\n"},"files":{"javascript/resources/tools/baseline-config.json":"{\n    \"paths-ignore\": [\n        \"**/node_modules/**\",\n        \"**/bower_components/**\",\n        \"**/*.min.js\",\n        \"**/*-min.js\"\n    ]\n}\n","actions/extractor/tools/baseline-config.json":"{\n    \"paths\": [\n        \".github/workflows/*.yml\",\n        \".github/workflows/*.yaml\",\n        \".github/reusable_workflows/**/*.yml\",\n        \".github/reusable_workflows/**/*.yaml\",\n        \"**/action.yml\",\n        \"**/action.yaml\",\n        \"**/actions.lock\"\n    ]\n}\n",".github/skills/bazel/SKILL.md":"---\nname: bazel\ndescription: Conventions for editing Bazel files in the github/codeql repository: the shared `misc/bazel` helpers, `codeql_platform_select` and the `{CODEQL_PLATFORM}` packaging placeholder, adding `MODULE.bazel` dependencies, and the `semmle_code` stub that keeps the standalone build working. Use when editing any `BUILD.bazel`, `*.bzl`, `MODULE.bazel` or `.bazelrc` here, and before validating such an edit.\n---\n\n# Bazel in the codeql repository\n\nA bzlmod module named `ql`, repo name `@codeql` ([`MODULE.bazel`](../../../MODULE.bazel)). It builds standalone, and is\nalso consumed by an internal module; standalone builds replace that module with a stub.\n\n## Traps\n\nThings that will waste your time or produce a wrong edit here. Read this section even if you skip the rest.\n\n* **`//...` does not work.** `bazel build //...`, and even `bazel query //...`, fail at the repo root: the patched\n  modules under [`misc/bazel/registry`](../../../misc/bazel/registry) are real packages referencing repos that are not\n  visible from the main repo, and [`.bazelrc`](../../../.bazelrc) notes separately that transitions break `...` builds.\n  The error names a registry directory unrelated to your edit, so it is easy to misdiagnose. **Validate the specific\n  target or package you changed**, not a recursive pattern.\n* **There is no `MODULE.bazel.lock`, deliberately.** [`.bazelrc`](../../../.bazelrc) sets `--lockfile_mode=off` because\n  the workspace-relative module override makes a lockfile unstable. Do not add one, and do not \"fix\" its absence.\n* **`linux_arm64` vs `linux-arm64`.** The keyword argument and config setting use an underscore; the platform *string*\n  substituted into paths and zip names uses a hyphen. They are not interchangeable.\n* **Do not stub your way out of a missing internal dependency.** See [Building standalone](#building-standalone) for the\n  one narrow case where extending the stub is correct.\n\n## Conventions\n\n* **Copy a neighboring target rather than inventing a shape.** Packaging is not uniform: some packages use the\n  `codeql_*` wrappers, others still use `pkg_files` directly. Copy the closest *working* neighbor, and prefer the\n  wrapper for new code.\n* **Pin anything fetched over the network** with `sha256` or `integrity`. Bazel only *warns* on an unpinned download, so\n  nothing fails loudly, but the build stops being reproducible and a retagged upstream release silently changes what you\n  build. `lfs_archive` is the exception: content is pinned by git object.\n* **Format with `bazel run //misc/bazel/buildifier`.** It rewrites in place, so do not hand-tune formatting. Also wired\n  as a `pre-commit` hook ([`.pre-commit-config.yaml`](../../../.pre-commit-config.yaml)).\n\n## Where new code goes\n\nBazel's own macro / rule / repository-rule distinction applies as usual. What is repo-specific:\n\n| Adding | Goes in |\n| --- | --- |\n| a new packaging shape | extend [`misc/bazel/pkg.bzl`](../../../misc/bazel/pkg.bzl), do not fork `pkg_files` |\n| a new OS or arch split | [`misc/bazel/os.bzl`](../../../misc/bazel/os.bzl), do not hand-roll a `select()` over `@platforms//` |\n| a fetch of something external | a repository rule ([`lfs.bzl`](../../../misc/bazel/lfs.bzl), [`ripunzip.bzl`](../../../misc/ripunzip/ripunzip.bzl)), not a `genrule` |\n| a wrapper used by one language | next to that language ([`swift/rules.bzl`](../../../swift/rules.bzl)) |\n| a wrapper used across languages | `misc/bazel/` |\n\nPrefer inline rules in `BUILD.bazel`. A `.bzl` file earns its `load()` only when the shape repeats across packages or a\nvalue must be computed: [`rust.bzl`](../../../misc/bazel/rust.bzl) is worth it because every Rust binary that ships in a\npack must get the same universal-binary wrapper and symbols test, and forgetting either is a release bug. A local\ndebugging aid opts out and declares a plain `rust_binary`; see `swift-syntax-parse` in\n[`unified/swift-syntax-rs/BUILD.bazel`](../../../unified/swift-syntax-rs/BUILD.bazel). The `_gen_binaries` list in\n[`go/BUILD.bazel`](../../../go/BUILD.bazel) does not earn a `.bzl`, because it is shared within a single file, where a\nlocal variable does the job.\n\nMacros here are typically a thin public wrapper around a private rule (`codeql_csharp_binary`, `swift_cc_binary`). Keep\nthe rule narrow and the ergonomics in the macro. Each macro decorates the caller's `name` to mint its helper targets,\nfor example `internal/<name>` or `single_arch/<name>`. Their visibility is that macro's choice (private, package\ndefault, or the caller's own), so read the macro instead of assuming. When an error names a target you cannot find in\nany source file, a macro minted it: grep the suffix under `misc/bazel/`.\n\n## Shared helpers\n\nFrequently-used pieces, so you load the existing one instead of rewriting it. Read the file for its actual exports.\n\n| `load()` path | Covers |\n| --- | --- |\n| `//misc/bazel:pkg.bzl` | CodeQL packs and packaging |\n| `//misc/bazel:os.bzl` | platform and architecture selection |\n| `//misc/bazel:lfs.bzl` | on-demand git-LFS repositories |\n| `//misc/bazel:rust.bzl` | Rust binary wrapper |\n| `//misc/bazel:csharp.bzl` | C# binary/library/test wrappers |\n| `//misc/bazel:utils.bzl` | `select_os`; prefer `os.bzl`'s `os_select` in new code |\n\n[`defs.bzl`](../../../defs.bzl) at the root exports `codeql_platform` for *dependent* modules. It is not the way to get\nthe platform string here; use `os.bzl`.\n\n## Platform selection\n\n[`codeql_platform_select`](../../../misc/bazel/os.bzl) takes one keyword argument per CodeQL platform: `linux64`,\n`linux_arm64`, `osx64` and `win64`. `otherwise` supplies the value for whichever of those you leave unset; it is **not**\na `//conditions:default`. **There is deliberately no fallback from `linux_arm64` to `linux64`.** If you only care about\nthe OS, use `os_select`, which gives Linux the same value on both architectures and has a `posix` shorthand for the\nshared Linux/macOS value.\n\nIn a macro (no `ctx`) it returns a `select()`:\n\n```python\nload(\"//misc/bazel:os.bzl\", \"codeql_platform_select\")\nload(\"//misc/bazel:pkg.bzl\", \"codeql_pkg_files\")\n\ncodeql_pkg_files(\n    name = \"extractor-arch\",\n    exes = codeql_platform_select(\n        otherwise = [\"//unified/extractor\"],\n        win64 = [\"//unified/extractor-unsupported-os:extractor\"],\n    ),\n    prefix = \"tools/{CODEQL_PLATFORM}\",\n)\n```\n\nIf implementation code needs to *branch* on the value rather than pass it through, pass `ctx` and add\n`OS_DETECTION_ATTRS` to the rule's attributes. The value is then resolved eagerly instead of being an opaque `select()`:\n\n```python\nload(\"//misc/bazel:os.bzl\", \"OS_DETECTION_ATTRS\", \"os_select\")\n\ndef _impl(ctx):\n    ext = os_select(ctx, windows = \".exe\", posix = \"\")\n    ...\n\nmy_rule = rule(\n    implementation = _impl,\n    attrs = {\"src\": attr.label()} | OS_DETECTION_ATTRS,\n)\n```\n\n## Packs\n\n`codeql_pack` assembles the files that become an extractor pack. See [`unified/BUILD.bazel`](../../../unified/BUILD.bazel)\nfor a minimal complete example and [`pkg.bzl`](../../../misc/bazel/pkg.bzl) for the arguments. The non-obvious parts:\n\n* **`{CODEQL_PLATFORM}` in a destination path is the routing mechanism**, not just a substitution. A path containing it\n  is *arch-specific* and lands in the per-architecture zip; every other path is *common*. So `prefix =\n  \"tools/{CODEQL_PLATFORM}\"` both places the file and marks it arch-specific. `arch_overrides` forces named\n  destinations into the arch-specific part without a placeholder.\n* **`codeql_pkg_files` splits `srcs` (plain) from `exes` (mode 755)** and **rejects `attributes =`** with an explicit\n  error. Use `exes` rather than hand-rolling `pkg_attributes(mode = \"755\")`.\n* **`pkg_dirs` and `pkg_symlinks` are unsupported** and fail at analysis time.\n* `codeql_pack` also generates an installer and an `install` alias, hence `bazel run //unified:install`. Pass\n  `installer_alias = None` if one package defines several packs.\n* `codeql_pack_group` exists for bundling packs into distribution zips, but nothing in this repo instantiates it.\n\n## Adding a dependency\n\nIn order of preference:\n\n1. **A [Bazel Central Registry](https://registry.bazel.build/) module.** Add a `bazel_dep` in\n   [`MODULE.bazel`](../../../MODULE.bazel).\n2. **A patched upstream module.** Add it under [`misc/bazel/registry`](../../../misc/bazel/registry), which `.bazelrc`\n   puts ahead of the BCR. Put patches in `modules/<repo>/<version>/patches`, rename the version with a `-codeql.N`\n   suffix, and run [`fix.py`](../../../misc/bazel/registry/fix.py) to realign the metadata.\n3. **A raw archive.** Use `http_archive` via `use_repo_rule`, or a repository rule. Copy an adjacent declaration and\n   keep its checksum field populated.\n\nVendored Rust crates under [`misc/bazel/3rdparty`](../../../misc/bazel/3rdparty) are generated. Regenerate with\n[`update_cargo_deps.sh`](../../../misc/bazel/3rdparty/update_cargo_deps.sh) rather than editing, and keep the\n`use_repo` lists in sync, which `bazel mod tidy` does for module extensions.\n\n## Building standalone\n\n[`MODULE.bazel`](../../../MODULE.bazel) declares `semmle_code` with a `local_path_override` pointing at `..`, which\nresolves when this repo is checked out inside the internal module. [`.bazelrc`](../../../.bazelrc), which Bazel reads\nwhen invoked in *this* workspace, overrides that with a stub. This line is the whole reason a standalone build resolves:\n\n```\ncommon --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub\n```\n\nDo not change either the override path or the `local_path_override`; they work as a pair.\n\n[`misc/bazel/semmle_code_stub`](../../../misc/bazel/semmle_code_stub) is an otherwise empty module supplying no-op\nversions of the internal helpers that shared `.bzl` files load *unconditionally*. That is its only job, and it is small\nenough to read.\n\n**Extend the stub only when a `.bzl` file every standalone target loads gains a new internal `load()`**, which breaks\npackage loading outright, for everyone. Prefer not needing one. **Never add a stub so that an internal-only target\nappears to build**: some targets depend on internal libraries (`grep -rl @semmle_code --include=*.bazel` finds them) and\nare correctly unbuildable here. Unlike a `load()`, such a dependency only fails when that target is actually requested.\n\n[`.bazelrc.internal`](../../../.bazelrc.internal) is **not** read here; it carries settings for the internal build. A\nsetting needed by both has to be written in both files, with paths differing because this repo sits at a different depth\nthere.\n"},"items":[{"name":"SKILL.md","path":".github/skills/bazel/SKILL.md","rawUrl":"https://raw.githubusercontent.com/github/codeql/HEAD/.github/skills/bazel/SKILL.md","title":"bazel","category":"anthropic-skill","format":"markdown","content":"---\nname: bazel\ndescription: Conventions for editing Bazel files in the github/codeql repository: the shared `misc/bazel` helpers, `codeql_platform_select` and the `{CODEQL_PLATFORM}` packaging placeholder, adding `MODULE.bazel` dependencies, and the `semmle_code` stub that keeps the standalone build working. Use when editing any `BUILD.bazel`, `*.bzl`, `MODULE.bazel` or `.bazelrc` here, and before validating such an edit.\n---\n\n# Bazel in the codeql repository\n\nA bzlmod module named `ql`, repo name `@codeql` ([`MODULE.bazel`](../../../MODULE.bazel)). It builds standalone, and is\nalso consumed by an internal module; standalone builds replace that module with a stub.\n\n## Traps\n\nThings that will waste your time or produce a wrong edit here. Read this section even if you skip the rest.\n\n* **`//...` does not work.** `bazel build //...`, and even `bazel query //...`, fail at the repo root: the patched\n  modules under [`misc/bazel/registry`](../../../misc/bazel/registry) are real packages referencing repos that are not\n  visible from the main repo, and [`.bazelrc`](../../../.bazelrc) notes separately that transitions break `...` builds.\n  The error names a registry directory unrelated to your edit, so it is easy to misdiagnose. **Validate the specific\n  target or package you changed**, not a recursive pattern.\n* **There is no `MODULE.bazel.lock`, deliberately.** [`.bazelrc`](../../../.bazelrc) sets `--lockfile_mode=off` because\n  the workspace-relative module override makes a lockfile unstable. Do not add one, and do not \"fix\" its absence.\n* **`linux_arm64` vs `linux-arm64`.** The keyword argument and config setting use an underscore; the platform *string*\n  substituted into paths and zip names uses a hyphen. They are not interchangeable.\n* **Do not stub your way out of a missing internal dependency.** See [Building standalone](#building-standalone) for the\n  one narrow case where extending the stub is correct.\n\n## Conventions\n\n* **Copy a neighboring target rather than inventing a shape.** Packaging is not uniform: some packages use the\n  `codeql_*` wrappers, others still use `pkg_files` directly. Copy the closest *working* neighbor, and prefer the\n  wrapper for new code.\n* **Pin anything fetched over the network** with `sha256` or `integrity`. Bazel only *warns* on an unpinned download, so\n  nothing fails loudly, but the build stops being reproducible and a retagged upstream release silently changes what you\n  build. `lfs_archive` is the exception: content is pinned by git object.\n* **Format with `bazel run //misc/bazel/buildifier`.** It rewrites in place, so do not hand-tune formatting. Also wired\n  as a `pre-commit` hook ([`.pre-commit-config.yaml`](../../../.pre-commit-config.yaml)).\n\n## Where new code goes\n\nBazel's own macro / rule / repository-rule distinction applies as usual. What is repo-specific:\n\n| Adding | Goes in |\n| --- | --- |\n| a new packaging shape | extend [`misc/bazel/pkg.bzl`](../../../misc/bazel/pkg.bzl), do not fork `pkg_files` |\n| a new OS or arch split | [`misc/bazel/os.bzl`](../../../misc/bazel/os.bzl), do not hand-roll a `select()` over `@platforms//` |\n| a fetch of something external | a repository rule ([`lfs.bzl`](../../../misc/bazel/lfs.bzl), [`ripunzip.bzl`](../../../misc/ripunzip/ripunzip.bzl)), not a `genrule` |\n| a wrapper used by one language | next to that language ([`swift/rules.bzl`](../../../swift/rules.bzl)) |\n| a wrapper used across languages | `misc/bazel/` |\n\nPrefer inline rules in `BUILD.bazel`. A `.bzl` file earns its `load()` only when the shape repeats across packages or a\nvalue must be computed: [`rust.bzl`](../../../misc/bazel/rust.bzl) is worth it because every Rust binary that ships in a\npack must get the same universal-binary wrapper and symbols test, and forgetting either is a release bug. A local\ndebugging aid opts out and declares a plain `rust_binary`; see `swift-syntax-parse` in\n[`unified/swift-syntax-rs/BUILD.bazel`](../../../unified/swift-syntax-rs/BUILD.bazel). The `_gen_binaries` list in\n[`go/BUILD.bazel`](../../../go/BUILD.bazel) does not earn a `.bzl`, because it is shared within a single file, where a\nlocal variable does the job.\n\nMacros here are typically a thin public wrapper around a private rule (`codeql_csharp_binary`, `swift_cc_binary`). Keep\nthe rule narrow and the ergonomics in the macro. Each macro decorates the caller's `name` to mint its helper targets,\nfor example `internal/<name>` or `single_arch/<name>`. Their visibility is that macro's choice (private, package\ndefault, or the caller's own), so read the macro instead of assuming. When an error names a target you cannot find in\nany source file, a macro minted it: grep the suffix under `misc/bazel/`.\n\n## Shared helpers\n\nFrequently-used pieces, so you load the existing one instead of rewriting it. Read the file for its actual exports.\n\n| `load()` path | Covers |\n| --- | --- |\n| `//misc/bazel:pkg.bzl` | CodeQL packs and packaging |\n| `//misc/bazel:os.bzl` | platform and architecture selection |\n| `//misc/bazel:lfs.bzl` | on-demand git-LFS repositories |\n| `//misc/bazel:rust.bzl` | Rust binary wrapper |\n| `//misc/bazel:csharp.bzl` | C# binary/library/test wrappers |\n| `//misc/bazel:utils.bzl` | `select_os`; prefer `os.bzl`'s `os_select` in new code |\n\n[`defs.bzl`](../../../defs.bzl) at the root exports `codeql_platform` for *dependent* modules. It is not the way to get\nthe platform string here; use `os.bzl`.\n\n## Platform selection\n\n[`codeql_platform_select`](../../../misc/bazel/os.bzl) takes one keyword argument per CodeQL platform: `linux64`,\n`linux_arm64`, `osx64` and `win64`. `otherwise` supplies the value for whichever of those you leave unset; it is **not**\na `//conditions:default`. **There is deliberately no fallback from `linux_arm64` to `linux64`.** If you only care about\nthe OS, use `os_select`, which gives Linux the same value on both architectures and has a `posix` shorthand for the\nshared Linux/macOS value.\n\nIn a macro (no `ctx`) it returns a `select()`:\n\n```python\nload(\"//misc/bazel:os.bzl\", \"codeql_platform_select\")\nload(\"//misc/bazel:pkg.bzl\", \"codeql_pkg_files\")\n\ncodeql_pkg_files(\n    name = \"extractor-arch\",\n    exes = codeql_platform_select(\n        otherwise = [\"//unified/extractor\"],\n        win64 = [\"//unified/extractor-unsupported-os:extractor\"],\n    ),\n    prefix = \"tools/{CODEQL_PLATFORM}\",\n)\n```\n\nIf implementation code needs to *branch* on the value rather than pass it through, pass `ctx` and add\n`OS_DETECTION_ATTRS` to the rule's attributes. The value is then resolved eagerly instead of being an opaque `select()`:\n\n```python\nload(\"//misc/bazel:os.bzl\", \"OS_DETECTION_ATTRS\", \"os_select\")\n\ndef _impl(ctx):\n    ext = os_select(ctx, windows = \".exe\", posix = \"\")\n    ...\n\nmy_rule = rule(\n    implementation = _impl,\n    attrs = {\"src\": attr.label()} | OS_DETECTION_ATTRS,\n)\n```\n\n## Packs\n\n`codeql_pack` assembles the files that become an extractor pack. See [`unified/BUILD.bazel`](../../../unified/BUILD.bazel)\nfor a minimal complete example and [`pkg.bzl`](../../../misc/bazel/pkg.bzl) for the arguments. The non-obvious parts:\n\n* **`{CODEQL_PLATFORM}` in a destination path is the routing mechanism**, not just a substitution. A path containing it\n  is *arch-specific* and lands in the per-architecture zip; every other path is *common*. So `prefix =\n  \"tools/{CODEQL_PLATFORM}\"` both places the file and marks it arch-specific. `arch_overrides` forces named\n  destinations into the arch-specific part without a placeholder.\n* **`codeql_pkg_files` splits `srcs` (plain) from `exes` (mode 755)** and **rejects `attributes =`** with an explicit\n  error. Use `exes` rather than hand-rolling `pkg_attributes(mode = \"755\")`.\n* **`pkg_dirs` and `pkg_symlinks` are unsupported** and fail at analysis time.\n* `codeql_pack` also generates an installer and an `install` alias, hence `bazel run //unified:install`. Pass\n  `installer_alias = None` if one package defines several packs.\n* `codeql_pack_group` exists for bundling packs into distribution zips, but nothing in this repo instantiates it.\n\n## Adding a dependency\n\nIn order of preference:\n\n1. **A [Bazel Central Registry](https://registry.bazel.build/) module.** Add a `bazel_dep` in\n   [`MODULE.bazel`](../../../MODULE.bazel).\n2. **A patched upstream module.** Add it under [`misc/bazel/registry`](../../../misc/bazel/registry), which `.bazelrc`\n   puts ahead of the BCR. Put patches in `modules/<repo>/<version>/patches`, rename the version with a `-codeql.N`\n   suffix, and run [`fix.py`](../../../misc/bazel/registry/fix.py) to realign the metadata.\n3. **A raw archive.** Use `http_archive` via `use_repo_rule`, or a repository rule. Copy an adjacent declaration and\n   keep its checksum field populated.\n\nVendored Rust crates under [`misc/bazel/3rdparty`](../../../misc/bazel/3rdparty) are generated. Regenerate with\n[`update_cargo_deps.sh`](../../../misc/bazel/3rdparty/update_cargo_deps.sh) rather than editing, and keep the\n`use_repo` lists in sync, which `bazel mod tidy` does for module extensions.\n\n## Building standalone\n\n[`MODULE.bazel`](../../../MODULE.bazel) declares `semmle_code` with a `local_path_override` pointing at `..`, which\nresolves when this repo is checked out inside the internal module. [`.bazelrc`](../../../.bazelrc), which Bazel reads\nwhen invoked in *this* workspace, overrides that with a stub. This line is the whole reason a standalone build resolves:\n\n```\ncommon --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub\n```\n\nDo not change either the override path or the `local_path_override`; they work as a pair.\n\n[`misc/bazel/semmle_code_stub`](../../../misc/bazel/semmle_code_stub) is an otherwise empty module supplying no-op\nversions of the internal helpers that shared `.bzl` files load *unconditionally*. That is its only job, and it is small\nenough to read.\n\n**Extend the stub only when a `.bzl` file every standalone target loads gains a new internal `load()`**, which breaks\npackage loading outright, for everyone. Prefer not needing one. **Never add a stub so that an internal-only target\nappears to build**: some targets depend on internal libraries (`grep -rl @semmle_code --include=*.bazel` finds them) and\nare correctly unbuildable here. Unlike a `load()`, such a dependency only fails when that target is actually requested.\n\n[`.bazelrc.internal`](../../../.bazelrc.internal) is **not** read here; it carries settings for the internal build. A\nsetting needed by both has to be written in both files, with paths differing because this repo sits at a different depth\nthere.\n","isInternal":false,"tokens":2682,"sizeBytes":10553},{"name":"baseline-config.json","path":"actions/extractor/tools/baseline-config.json","rawUrl":"https://raw.githubusercontent.com/github/codeql/HEAD/actions/extractor/tools/baseline-config.json","title":"Tools Skill","category":"anthropic-skill","format":"json","content":"{\n    \"paths\": [\n        \".github/workflows/*.yml\",\n        \".github/workflows/*.yaml\",\n        \".github/reusable_workflows/**/*.yml\",\n        \".github/reusable_workflows/**/*.yaml\",\n        \"**/action.yml\",\n        \"**/action.yaml\",\n        \"**/actions.lock\"\n    ]\n}\n","frontmatter":{"paths":[".github/workflows/*.yml",".github/workflows/*.yaml",".github/reusable_workflows/**/*.yml",".github/reusable_workflows/**/*.yaml","**/action.yml","**/action.yaml","**/actions.lock"]},"isInternal":false,"tokens":65,"sizeBytes":268},{"name":"baseline-config.json","path":"javascript/resources/tools/baseline-config.json","rawUrl":"https://raw.githubusercontent.com/github/codeql/HEAD/javascript/resources/tools/baseline-config.json","title":"Tools Skill","category":"anthropic-skill","format":"json","content":"{\n    \"paths-ignore\": [\n        \"**/node_modules/**\",\n        \"**/bower_components/**\",\n        \"**/*.min.js\",\n        \"**/*-min.js\"\n    ]\n}\n","frontmatter":{"paths-ignore":["**/node_modules/**","**/bower_components/**","**/*.min.js","**/*-min.js"]},"isInternal":false,"tokens":37,"sizeBytes":141}],"systemPromptSnippet":"<yakaai_skills repo=\"github/codeql\">\n<!-- File: .github/skills/bazel/SKILL.md (Tokens: ~2682 | Category: anthropic-skill) -->\n---\nname: bazel\ndescription: Conventions for editing Bazel files in the github/codeql repository: the shared `misc/bazel` helpers, `codeql_platform_select` and the `{CODEQL_PLATFORM}` packaging placeholder, adding `MODULE.bazel` dependencies, and the `semmle_code` stub that keeps the standalone build working. Use when editing any `BUILD.bazel`, `*.bzl`, `MODULE.bazel` or `.bazelrc` here, and before validating such an edit.\n---\n\n# Bazel in the codeql repository\n\nA bzlmod module named `ql`, repo name `@codeql` ([`MODULE.bazel`](../../../MODULE.bazel)). It builds standalone, and is\nalso consumed by an internal module; standalone builds replace that module with a stub.\n\n## Traps\n\nThings that will waste your time or produce a wrong edit here. Read this section even if you skip the rest.\n\n* **`//...` does not work.** `bazel build //...`, and even `bazel query //...`, fail at the repo root: the patched\n  modules under [`misc/bazel/registry`](../../../misc/bazel/registry) are real packages referencing repos that are not\n  visible from the main repo, and [`.bazelrc`](../../../.bazelrc) notes separately that transitions break `...` builds.\n  The error names a registry directory unrelated to your edit, so it is easy to misdiagnose. **Validate the specific\n  target or package you changed**, not a recursive pattern.\n* **There is no `MODULE.bazel.lock`, deliberately.** [`.bazelrc`](../../../.bazelrc) sets `--lockfile_mode=off` because\n  the workspace-relative module override makes a lockfile unstable. Do not add one, and do not \"fix\" its absence.\n* **`linux_arm64` vs `linux-arm64`.** The keyword argument and config setting use an underscore; the platform *string*\n  substituted into paths and zip names uses a hyphen. They are not interchangeable.\n* **Do not stub your way out of a missing internal dependency.** See [Building standalone](#building-standalone) for the\n  one narrow case where extending the stub is correct.\n\n## Conventions\n\n* **Copy a neighboring target rather than inventing a shape.** Packaging is not uniform: some packages use the\n  `codeql_*` wrappers, others still use `pkg_files` directly. Copy the closest *working* neighbor, and prefer the\n  wrapper for new code.\n* **Pin anything fetched over the network** with `sha256` or `integrity`. Bazel only *warns* on an unpinned download, so\n  nothing fails loudly, but the build stops being reproducible and a retagged upstream release silently changes what you\n  build. `lfs_archive` is the exception: content is pinned by git object.\n* **Format with `bazel run //misc/bazel/buildifier`.** It rewrites in place, so do not hand-tune formatting. Also wired\n  as a `pre-commit` hook ([`.pre-commit-config.yaml`](../../../.pre-commit-config.yaml)).\n\n## Where new code goes\n\nBazel's own macro / rule / repository-rule distinction applies as usual. What is repo-specific:\n\n| Adding | Goes in |\n| --- | --- |\n| a new packaging shape | extend [`misc/bazel/pkg.bzl`](../../../misc/bazel/pkg.bzl), do not fork `pkg_files` |\n| a new OS or arch split | [`misc/bazel/os.bzl`](../../../misc/bazel/os.bzl), do not hand-roll a `select()` over `@platforms//` |\n| a fetch of something external | a repository rule ([`lfs.bzl`](../../../misc/bazel/lfs.bzl), [`ripunzip.bzl`](../../../misc/ripunzip/ripunzip.bzl)), not a `genrule` |\n| a wrapper used by one language | next to that language ([`swift/rules.bzl`](../../../swift/rules.bzl)) |\n| a wrapper used across languages | `misc/bazel/` |\n\nPrefer inline rules in `BUILD.bazel`. A `.bzl` file earns its `load()` only when the shape repeats across packages or a\nvalue must be computed: [`rust.bzl`](../../../misc/bazel/rust.bzl) is worth it because every Rust binary that ships in a\npack must get the same universal-binary wrapper and symbols test, and forgetting either is a release bug. A local\ndebugging aid opts out and declares a plain `rust_binary`; see `swift-syntax-parse` in\n[`unified/swift-syntax-rs/BUILD.bazel`](../../../unified/swift-syntax-rs/BUILD.bazel). The `_gen_binaries` list in\n[`go/BUILD.bazel`](../../../go/BUILD.bazel) does not earn a `.bzl`, because it is shared within a single file, where a\nlocal variable does the job.\n\nMacros here are typically a thin public wrapper around a private rule (`codeql_csharp_binary`, `swift_cc_binary`). Keep\nthe rule narrow and the ergonomics in the macro. Each macro decorates the caller's `name` to mint its helper targets,\nfor example `internal/<name>` or `single_arch/<name>`. Their visibility is that macro's choice (private, package\ndefault, or the caller's own), so read the macro instead of assuming. When an error names a target you cannot find in\nany source file, a macro minted it: grep the suffix under `misc/bazel/`.\n\n## Shared helpers\n\nFrequently-used pieces, so you load the existing one instead of rewriting it. Read the file for its actual exports.\n\n| `load()` path | Covers |\n| --- | --- |\n| `//misc/bazel:pkg.bzl` | CodeQL packs and packaging |\n| `//misc/bazel:os.bzl` | platform and architecture selection |\n| `//misc/bazel:lfs.bzl` | on-demand git-LFS repositories |\n| `//misc/bazel:rust.bzl` | Rust binary wrapper |\n| `//misc/bazel:csharp.bzl` | C# binary/library/test wrappers |\n| `//misc/bazel:utils.bzl` | `select_os`; prefer `os.bzl`'s `os_select` in new code |\n\n[`defs.bzl`](../../../defs.bzl) at the root exports `codeql_platform` for *dependent* modules. It is not the way to get\nthe platform string here; use `os.bzl`.\n\n## Platform selection\n\n[`codeql_platform_select`](../../../misc/bazel/os.bzl) takes one keyword argument per CodeQL platform: `linux64`,\n`linux_arm64`, `osx64` and `win64`. `otherwise` supplies the value for whichever of those you leave unset; it is **not**\na `//conditions:default`. **There is deliberately no fallback from `linux_arm64` to `linux64`.** If you only care about\nthe OS, use `os_select`, which gives Linux the same value on both architectures and has a `posix` shorthand for the\nshared Linux/macOS value.\n\nIn a macro (no `ctx`) it returns a `select()`:\n\n```python\nload(\"//misc/bazel:os.bzl\", \"codeql_platform_select\")\nload(\"//misc/bazel:pkg.bzl\", \"codeql_pkg_files\")\n\ncodeql_pkg_files(\n    name = \"extractor-arch\",\n    exes = codeql_platform_select(\n        otherwise = [\"//unified/extractor\"],\n        win64 = [\"//unified/extractor-unsupported-os:extractor\"],\n    ),\n    prefix = \"tools/{CODEQL_PLATFORM}\",\n)\n```\n\nIf implementation code needs to *branch* on the value rather than pass it through, pass `ctx` and add\n`OS_DETECTION_ATTRS` to the rule's attributes. The value is then resolved eagerly instead of being an opaque `select()`:\n\n```python\nload(\"//misc/bazel:os.bzl\", \"OS_DETECTION_ATTRS\", \"os_select\")\n\ndef _impl(ctx):\n    ext = os_select(ctx, windows = \".exe\", posix = \"\")\n    ...\n\nmy_rule = rule(\n    implementation = _impl,\n    attrs = {\"src\": attr.label()} | OS_DETECTION_ATTRS,\n)\n```\n\n## Packs\n\n`codeql_pack` assembles the files that become an extractor pack. See [`unified/BUILD.bazel`](../../../unified/BUILD.bazel)\nfor a minimal complete example and [`pkg.bzl`](../../../misc/bazel/pkg.bzl) for the arguments. The non-obvious parts:\n\n* **`{CODEQL_PLATFORM}` in a destination path is the routing mechanism**, not just a substitution. A path containing it\n  is *arch-specific* and lands in the per-architecture zip; every other path is *common*. So `prefix =\n  \"tools/{CODEQL_PLATFORM}\"` both places the file and marks it arch-specific. `arch_overrides` forces named\n  destinations into the arch-specific part without a placeholder.\n* **`codeql_pkg_files` splits `srcs` (plain) from `exes` (mode 755)** and **rejects `attributes =`** with an explicit\n  error. Use `exes` rather than hand-rolling `pkg_attributes(mode = \"755\")`.\n* **`pkg_dirs` and `pkg_symlinks` are unsupported** and fail at analysis time.\n* `codeql_pack` also generates an installer and an `install` alias, hence `bazel run //unified:install`. Pass\n  `installer_alias = None` if one package defines several packs.\n* `codeql_pack_group` exists for bundling packs into distribution zips, but nothing in this repo instantiates it.\n\n## Adding a dependency\n\nIn order of preference:\n\n1. **A [Bazel Central Registry](https://registry.bazel.build/) module.** Add a `bazel_dep` in\n   [`MODULE.bazel`](../../../MODULE.bazel).\n2. **A patched upstream module.** Add it under [`misc/bazel/registry`](../../../misc/bazel/registry), which `.bazelrc`\n   puts ahead of the BCR. Put patches in `modules/<repo>/<version>/patches`, rename the version with a `-codeql.N`\n   suffix, and run [`fix.py`](../../../misc/bazel/registry/fix.py) to realign the metadata.\n3. **A raw archive.** Use `http_archive` via `use_repo_rule`, or a repository rule. Copy an adjacent declaration and\n   keep its checksum field populated.\n\nVendored Rust crates under [`misc/bazel/3rdparty`](../../../misc/bazel/3rdparty) are generated. Regenerate with\n[`update_cargo_deps.sh`](../../../misc/bazel/3rdparty/update_cargo_deps.sh) rather than editing, and keep the\n`use_repo` lists in sync, which `bazel mod tidy` does for module extensions.\n\n## Building standalone\n\n[`MODULE.bazel`](../../../MODULE.bazel) declares `semmle_code` with a `local_path_override` pointing at `..`, which\nresolves when this repo is checked out inside the internal module. [`.bazelrc`](../../../.bazelrc), which Bazel reads\nwhen invoked in *this* workspace, overrides that with a stub. This line is the whole reason a standalone build resolves:\n\n```\ncommon --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub\n```\n\nDo not change either the override path or the `local_path_override`; they work as a pair.\n\n[`misc/bazel/semmle_code_stub`](../../../misc/bazel/semmle_code_stub) is an otherwise empty module supplying no-op\nversions of the internal helpers that shared `.bzl` files load *unconditionally*. That is its only job, and it is small\nenough to read.\n\n**Extend the stub only when a `.bzl` file every standalone target loads gains a new internal `load()`**, which breaks\npackage loading outright, for everyone. Prefer not needing one. **Never add a stub so that an internal-only target\nappears to build**: some targets depend on internal libraries (`grep -rl @semmle_code --include=*.bazel` finds them) and\nare correctly unbuildable here. Unlike a `load()`, such a dependency only fails when that target is actually requested.\n\n[`.bazelrc.internal`](../../../.bazelrc.internal) is **not** read here; it carries settings for the internal build. A\nsetting needed by both has to be written in both files, with paths differing because this repo sits at a different depth\nthere.\n\n<!-- File: actions/extractor/tools/baseline-config.json (Tokens: ~65 | Category: anthropic-skill) -->\n{\n    \"paths\": [\n        \".github/workflows/*.yml\",\n        \".github/workflows/*.yaml\",\n        \".github/reusable_workflows/**/*.yml\",\n        \".github/reusable_workflows/**/*.yaml\",\n        \"**/action.yml\",\n        \"**/action.yaml\",\n        \"**/actions.lock\"\n    ]\n}\n\n<!-- File: javascript/resources/tools/baseline-config.json (Tokens: ~37 | Category: anthropic-skill) -->\n{\n    \"paths-ignore\": [\n        \"**/node_modules/**\",\n        \"**/bower_components/**\",\n        \"**/*.min.js\",\n        \"**/*-min.js\"\n    ]\n}\n</yakaai_skills>"}