|
| 1 | +# This Source Code Form is subject to the terms of the Mozilla Public |
| 2 | +# License, v. 2.0. If a copy of the MPL was not distributed with this |
| 3 | +# file, You can obtain one at https://mozilla.org/MPL/2.0/. |
| 4 | +# SPDX-License-Identifier: MPL-2.0 |
| 5 | +# Copyright (c) 2026 Den Rozhnovskiy |
| 6 | + |
| 7 | +from __future__ import annotations |
| 8 | + |
| 9 | +import re |
| 10 | +from typing import Final |
| 11 | + |
| 12 | +_SAFE_GIT_DIFF_REF_RE: Final[re.Pattern[str]] = re.compile( |
| 13 | + r"^(?![-./])[A-Za-z0-9._/@{}^~+-]+$" |
| 14 | +) |
| 15 | + |
| 16 | + |
| 17 | +def validate_git_diff_ref(git_diff_ref: str) -> str: |
| 18 | + """Validate a safe, single git revision expression for `git diff`. |
| 19 | +
|
| 20 | + CodeClone intentionally accepts a conservative subset of git revision |
| 21 | + syntax here: common branch names, tags, revision operators (`~`, `^`), |
| 22 | + reflog selectors (`@{...}`), and dotted range expressions. Whitespace, |
| 23 | + control characters, option-like prefixes, and unsupported punctuation are |
| 24 | + rejected before any subprocess call. |
| 25 | + """ |
| 26 | + |
| 27 | + if git_diff_ref != git_diff_ref.strip(): |
| 28 | + raise ValueError( |
| 29 | + "Invalid git diff ref " |
| 30 | + f"{git_diff_ref!r}: surrounding whitespace is not allowed." |
| 31 | + ) |
| 32 | + if not git_diff_ref: |
| 33 | + raise ValueError("Invalid git diff ref '': value must not be empty.") |
| 34 | + if any(ch.isspace() or ord(ch) < 32 or ord(ch) == 127 for ch in git_diff_ref): |
| 35 | + raise ValueError( |
| 36 | + "Invalid git diff ref " |
| 37 | + f"{git_diff_ref!r}: whitespace and control characters are not allowed." |
| 38 | + ) |
| 39 | + if not _SAFE_GIT_DIFF_REF_RE.fullmatch(git_diff_ref): |
| 40 | + raise ValueError( |
| 41 | + "Invalid git diff ref " |
| 42 | + f"{git_diff_ref!r}: expected a safe revision expression." |
| 43 | + ) |
| 44 | + return git_diff_ref |
0 commit comments