From a3c5f371c584ddb6977a2f5c512889e41b56fdfe Mon Sep 17 00:00:00 2001 From: okxlin <61420215+okxlin@users.noreply.github.com> Date: Sun, 12 Jul 2026 02:16:01 +0800 Subject: [PATCH] Require Docker Hub auth for Renovate (#4729) --- .github/renovate-global.js | 19 +++++++++++ .github/scripts/test_renovate_app_version.py | 34 ++++++++++++++++++++ .github/workflows/renovate.yml | 3 ++ 3 files changed, 56 insertions(+) create mode 100644 .github/renovate-global.js diff --git a/.github/renovate-global.js b/.github/renovate-global.js new file mode 100644 index 000000000..8fd4db8ca --- /dev/null +++ b/.github/renovate-global.js @@ -0,0 +1,19 @@ +const username = process.env.RENOVATE_DOCKERHUB_USERNAME; +const password = process.env.RENOVATE_DOCKERHUB_TOKEN; + +if (!username || !password) { + throw new Error( + "Docker Hub credentials are required: configure DOCKERHUB_USERNAME and DOCKERHUB_TOKEN repository secrets.", + ); +} + +module.exports = { + hostRules: [ + { + hostType: "docker", + matchHost: "docker.io", + username, + password, + }, + ], +}; diff --git a/.github/scripts/test_renovate_app_version.py b/.github/scripts/test_renovate_app_version.py index eab3867c1..bccbd5a39 100644 --- a/.github/scripts/test_renovate_app_version.py +++ b/.github/scripts/test_renovate_app_version.py @@ -121,6 +121,40 @@ class RenovateAppVersionTests(unittest.TestCase): self.assertIn("docker-cmd-file: .github/scripts/renovate-entrypoint.sh", workflow) + def test_self_hosted_renovate_requires_docker_hub_credentials(self): + workflow = (REPO_ROOT / ".github" / "workflows" / "renovate.yml").read_text(encoding="utf-8") + + self.assertIn("configurationFile: .github/renovate-global.js", workflow) + self.assertIn("RENOVATE_DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}", workflow) + self.assertIn("RENOVATE_DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}", workflow) + + def test_global_config_fails_fast_without_docker_hub_credentials(self): + config = REPO_ROOT / ".github" / "renovate-global.js" + env = os.environ.copy() + env.pop("RENOVATE_DOCKERHUB_USERNAME", None) + env.pop("RENOVATE_DOCKERHUB_TOKEN", None) + + result = subprocess.run(["node", "-e", f"require({json.dumps(str(config))})"], text=True, capture_output=True, env=env, check=False) + + self.assertNotEqual(0, result.returncode) + self.assertIn("DOCKERHUB_USERNAME and DOCKERHUB_TOKEN", result.stderr) + + def test_global_config_authenticates_docker_hub(self): + config = REPO_ROOT / ".github" / "renovate-global.js" + env = os.environ.copy() + env["RENOVATE_DOCKERHUB_USERNAME"] = "renovate-user" + env["RENOVATE_DOCKERHUB_TOKEN"] = "test-token" + expression = f"const c=require({json.dumps(str(config))}); console.log(JSON.stringify(c.hostRules[0]))" + + result = subprocess.run(["node", "-e", expression], text=True, capture_output=True, env=env, check=False) + host_rule = json.loads(result.stdout) + + self.assertEqual(0, result.returncode) + self.assertEqual("docker", host_rule["hostType"]) + self.assertEqual("docker.io", host_rule["matchHost"]) + self.assertEqual("renovate-user", host_rule["username"]) + self.assertEqual("test-token", host_rule["password"]) + def test_semantic_entrypoint_blocks_external_host_abort(self): entrypoint = REPO_ROOT / ".github" / "scripts" / "renovate-entrypoint.sh" with tempfile.TemporaryDirectory(prefix="renovate-entrypoint-test-") as tmp: diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index 790c21d80..ceec008f1 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -21,7 +21,10 @@ jobs: - name: Run Renovate uses: renovatebot/github-action@b50d2ba2bd928235abdcc14d06dfafc217f1c565 # v46.1.18 with: + configurationFile: .github/renovate-global.js docker-cmd-file: .github/scripts/renovate-entrypoint.sh token: ${{ secrets.GITHUBTOKEN }} env: + RENOVATE_DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + RENOVATE_DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} RENOVATE_REPOSITORIES: ${{ github.repository }}