From 51747a265e29658976b9742f6f334394c67067e5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 3 Nov 2026 18:08:36 +0000 Subject: [PATCH 1/2] chore(template-sync): sync to v1.15.1 --- .github/scripts/README.md | 6 +++++ .github/scripts/ruff.toml | 6 +++-- .github/scripts/test_moderate_apply_result.py | 12 ++++++++-- .github/scripts/test_moderate_tools.py | 12 +++++++--- .github/template-sync-state.json | 2 +- .pre-commit-config.yaml | 23 +++++++++++++++++++ docs/TEMPLATE.md | 11 +++++++-- 7 files changed, 62 insertions(+), 10 deletions(-) diff --git a/.github/scripts/README.md b/.github/scripts/README.md index 6d2d1fa..d4905d6 100644 --- a/.github/scripts/README.md +++ b/.github/scripts/README.md @@ -89,6 +89,12 @@ that label the test fails until you look up the new image's `python3` (actions/runner-images) and update `RUNNER_IMAGE_PYTHON`, `RUNNER_PYTHON` and `ruff.toml` together. +- Formatting: base has no ruff dependency of its own, so `ruff-check`/`ruff-format` + from `astral-sh/ruff-pre-commit` in `../../.pre-commit-config.yaml`, scoped + to `^\.github/scripts/.*\.py$`, keep these scripts formatted to `ruff.toml`. + Unformatted scripts would otherwise fail every Python instance's own + `ruff format` hook after a sync. Keep that hook's `rev` equal to the ruff + the Python templates pin. - `test_moderate_labels.py` — checks that every `create "" "" ""` line in `../workflows/moderate-setup.yml` has a description of at most 100 characters (GitHub answers HTTP 422 to a longer one, and only diff --git a/.github/scripts/ruff.toml b/.github/scripts/ruff.toml index dc0a302..dfa88ee 100644 --- a/.github/scripts/ruff.toml +++ b/.github/scripts/ruff.toml @@ -23,6 +23,8 @@ line-length = 100 [lint] # Ruff's long-standing defaults, spelled out so a newer ruff that widens -# its default rule set does not start flagging these scripts. Base itself -# does not run ruff; this keeps `ruff check` quiet in every checkout. +# its default rule set does not start flagging these scripts. Base runs +# ruff on this directory only through the ruff-pre-commit hook in +# ../../.pre-commit-config.yaml; this keeps `ruff check` quiet in every +# checkout. select = ["E4", "E7", "E9", "F"] diff --git a/.github/scripts/test_moderate_apply_result.py b/.github/scripts/test_moderate_apply_result.py index 4e8b025..5b34b86 100644 --- a/.github/scripts/test_moderate_apply_result.py +++ b/.github/scripts/test_moderate_apply_result.py @@ -280,7 +280,9 @@ def test_base_sha_must_be_a_full_hex_sha(self) -> None: (self.tmp / "log.txt").unlink(missing_ok=True) proc = self.run_script(meta_extra={"base_sha": bad}) log = self.log() - self.assertFalse([c for c in log if c.startswith(("git fetch", "git am", "gh api"))]) + self.assertFalse( + [c for c in log if c.startswith(("git fetch", "git am", "gh api"))] + ) self.assert_failed_cleanly(proc, log) def test_denied_path_in_the_patch_is_never_pushed(self) -> None: @@ -317,7 +319,13 @@ def test_ordinary_paths_pass(self) -> None: """Source, tests and docs (also next to look-alike names) are accepted.""" diff = "".join( f":100644 100644 a b M\\0{p}\\0" - for p in ("src/a.py", "tests/test_a.py", "docs/Makefile.md", "scripts/other.sh", ".githubx/y") + for p in ( + "src/a.py", + "tests/test_a.py", + "docs/Makefile.md", + "scripts/other.sh", + ".githubx/y", + ) ) proc = self.run_script(run_env={"FAKE_DIFF": diff}) self.assertEqual(proc.returncode, 0, proc.stderr) diff --git a/.github/scripts/test_moderate_tools.py b/.github/scripts/test_moderate_tools.py index 6ed9244..c695e8d 100644 --- a/.github/scripts/test_moderate_tools.py +++ b/.github/scripts/test_moderate_tools.py @@ -270,7 +270,9 @@ def test_key_only_from_the_environment(self) -> None: self.assertIn("KEY:sk-test", lines) self.assertIn("SCRUB:1", lines) self.assertIn("AUTHOR:claude-moderator[bot]", lines) - self.assertEqual(lines[lines.index("ARG:--allowedTools") + 1], "ARG:Read,Grep,Bash(uv run pytest *)") + self.assertEqual( + lines[lines.index("ARG:--allowedTools") + 1], "ARG:Read,Grep,Bash(uv run pytest *)" + ) settings = json.loads(lines[lines.index("ARG:--settings") + 1].removeprefix("ARG:")) self.assertIn("Read(//proc/**)", settings["permissions"]["deny"]) sandbox = settings["sandbox"] @@ -281,14 +283,18 @@ def test_key_only_from_the_environment(self) -> None: self.assertNotIn("enableWeakerNestedSandbox", sandbox) self.assertEqual(sandbox["network"]["allowedDomains"], ["github.com", "api.github.com"]) self.assertIs(sandbox["network"]["strictAllowlist"], True) - self.assertIn({"name": "ANTHROPIC_API_KEY", "mode": "deny"}, sandbox["credentials"]["envVars"]) + self.assertIn( + {"name": "ANTHROPIC_API_KEY", "mode": "deny"}, sandbox["credentials"]["envVars"] + ) self.assertEqual(lines[lines.index("ARG:-p") + 1], "ARG:do the thing") def test_missing_or_bad_domains_fail_before_claude_runs(self) -> None: """No network allow-list, or a malformed host, means claude never starts.""" for domains in ("", ",", 'x.com","evil', "a b"): with self.subTest(domains=domains): - proc = self.launch({"ANTHROPIC_API_KEY": "k", "MODERATION_ALLOWED_DOMAINS": domains}) + proc = self.launch( + {"ANTHROPIC_API_KEY": "k", "MODERATION_ALLOWED_DOMAINS": domains} + ) self.assertEqual(proc.returncode, 1) self.assertFalse(self.out.exists()) diff --git a/.github/template-sync-state.json b/.github/template-sync-state.json index 51bc1b0..02ff3c6 100644 --- a/.github/template-sync-state.json +++ b/.github/template-sync-state.json @@ -1,4 +1,4 @@ { "template_repo": "craftainer/template-base", - "synced_tag": "v1.15.0" + "synced_tag": "v1.15.1" } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 70cb725..66c62d3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,6 +30,9 @@ repos: - id: check-added-large-files stages: [pre-commit, manual] - id: check-merge-conflict + # Without this the hook only runs during an in-progress git merge, so + # conflict markers committed by a template-sync PR were never caught. + args: [--assume-in-merge] stages: [pre-commit, manual] - id: mixed-line-ending stages: [pre-commit, manual] @@ -48,6 +51,7 @@ repos: - id: conventional-pre-commit stages: [commit-msg] +<<<<<<< /home/runner/work/devcontainer-features/devcontainer-features/.pre-commit-config.yaml # This instance's own hooks: the features' shell code. - repo: https://github.com/shellcheck-py/shellcheck-py rev: v0.11.0.1 @@ -58,6 +62,25 @@ repos: # --external-sources lets install.sh follow its sourced copy. args: [--external-sources, --source-path=SCRIPTDIR] files: ^(src/.*|common/[^/]*|scripts/(check-[^/]*|release-features))\.sh$ +======= + # Guard for the upstream-owned scripts in .github/scripts/: base ships + # them to every instance, whose own ruff-format hook then checks them + # against .github/scripts/ruff.toml (the closest config wins), so an + # unformatted script here fails every Python instance after a sync. Base + # has no ruff dependency of its own, hence this pinned hook, scoped to + # that directory only. Keep the rev equal to the ruff the Python + # templates pin in pyproject.toml. + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.16.8 + hooks: + - id: ruff-check + name: ruff check (.github/scripts) + files: ^\.github/scripts/.*\.py$ + stages: [pre-commit, manual] + - id: ruff-format + name: ruff format (.github/scripts) + files: ^\.github/scripts/.*\.py$ +>>>>>>> /tmp/template-new/.pre-commit-config.yaml stages: [pre-commit, manual] - repo: local diff --git a/docs/TEMPLATE.md b/docs/TEMPLATE.md index 542ca5e..a8b4620 100644 --- a/docs/TEMPLATE.md +++ b/docs/TEMPLATE.md @@ -103,13 +103,20 @@ instance's own toolchain needs. `.pre-commit-config.yaml` defines whitespace/EOF fixers, YAML/TOML/JSON checks, `conventional-pre-commit` (Conventional Commits, enforced at the `commit-msg` stage), the `template-sync-manifest` completeness check, and -the `devcontainer-lock` lockfile-consistency check, and three security -scanners (below). An instance layers +the `devcontainer-lock` lockfile-consistency check, `ruff-check`/`ruff-format` +(`astral-sh/ruff-pre-commit`, scoped to `.github/scripts/*.py` so base can't +ship scripts that fail a Python instance's own ruff hook; keep its `rev` equal +to the ruff the Python templates pin), and three security scanners (below). An instance layers its own language-specific hooks on top (lint, format, type check, test suite, dependency-vulnerability scan, ...), matching the shape `template-fastapi`'s own `.pre-commit-config.yaml` already establishes for `ruff`/`mypy`/`pytest`/`pip-audit`. +`check-merge-conflict` runs with `--assume-in-merge`, so it flags committed +conflict markers (a line starting `<<<<<<< `, `=======` or `>>>>>>> `) in any +file, not just during an in-progress git merge; a template sync PR that +commits a merge-tier conflict is then caught in CI. + ### Security scanners | Hook | Scans | Stage | Network | OWASP (2025) | From 0a03b1f7001d37d4666dfed7d5514852ec03e472 Mon Sep 17 00:00:00 2001 From: crazyracer98 <8631139+crazyracer98@users.noreply.github.com> Date: Wed, 4 Nov 2026 00:25:05 +0000 Subject: [PATCH 2/2] fix(sync): resolve committed conflict markers in .pre-commit-config.yaml (keep ruff guard and shellcheck hook) --- .pre-commit-config.yaml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 66c62d3..13d2e6d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -51,18 +51,6 @@ repos: - id: conventional-pre-commit stages: [commit-msg] -<<<<<<< /home/runner/work/devcontainer-features/devcontainer-features/.pre-commit-config.yaml - # This instance's own hooks: the features' shell code. - - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.11.0.1 - hooks: - - id: shellcheck - name: shellcheck (features, install-lib, check and release scripts) - # install-lib.sh declares its shell (bash) with a directive; - # --external-sources lets install.sh follow its sourced copy. - args: [--external-sources, --source-path=SCRIPTDIR] - files: ^(src/.*|common/[^/]*|scripts/(check-[^/]*|release-features))\.sh$ -======= # Guard for the upstream-owned scripts in .github/scripts/: base ships # them to every instance, whose own ruff-format hook then checks them # against .github/scripts/ruff.toml (the closest config wins), so an @@ -80,7 +68,18 @@ repos: - id: ruff-format name: ruff format (.github/scripts) files: ^\.github/scripts/.*\.py$ ->>>>>>> /tmp/template-new/.pre-commit-config.yaml + stages: [pre-commit, manual] + + # This instance's own hooks: the features' shell code. + - repo: https://github.com/shellcheck-py/shellcheck-py + rev: v0.11.0.1 + hooks: + - id: shellcheck + name: shellcheck (features, install-lib, check and release scripts) + # install-lib.sh declares its shell (bash) with a directive; + # --external-sources lets install.sh follow its sourced copy. + args: [--external-sources, --source-path=SCRIPTDIR] + files: ^(src/.*|common/[^/]*|scripts/(check-[^/]*|release-features))\.sh$ stages: [pre-commit, manual] - repo: local