chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Download the pinned gitleaks binary into .task/bin, verifying its checksum.
|
||||
|
||||
gitleaks is a Go binary with no PyPI package, so it can't be locked like the
|
||||
other tools (ruff/codespell/toml-sort live in scripts/pre-commit/pyproject.toml).
|
||||
This script is the single source of truth for the gitleaks version and the
|
||||
SHA-256 of each release asset. It is cross-platform (stdlib only) and idempotent:
|
||||
if the cached binary already reports the pinned version it does nothing, so
|
||||
`task pre-commit` can call it every run.
|
||||
|
||||
Bump the version by editing VERSION and the SHA256 map (values come from the
|
||||
release's gitleaks_<version>_checksums.txt).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import urllib.request
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
VERSION = "8.30.0"
|
||||
|
||||
# SHA-256 of each release asset, keyed by "<os>_<arch>" (gitleaks' own naming).
|
||||
SHA256 = {
|
||||
"linux_x64": "79a3ab579b53f71efd634f3aaf7e04a0fa0cf206b7ed434638d1547a2470a66e",
|
||||
"linux_arm64": "b4cbbb6ddf7d1b2a603088cd03a4e3f7ce48ee7fd449b51f7de6ee2906f5fa2f",
|
||||
"darwin_x64": "ca221d012d247080c2f6f61f4b7a83bffa2453806b0c195c795bbe9a8c775ed5",
|
||||
"darwin_arm64": "b251ab2bcd4cd8ba9e56ff37698c033ebf38582b477d21ebd86586d927cf87e7",
|
||||
"windows_x64": "54fe94f644b832dd08e8c3a5915efb3bfa862386d59fb27ca0792cb687a83573",
|
||||
}
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
IS_WINDOWS = platform.system() == "Windows"
|
||||
BIN = REPO_ROOT / ".task" / "bin" / ("gitleaks.exe" if IS_WINDOWS else "gitleaks")
|
||||
|
||||
|
||||
def platform_key() -> str:
|
||||
os_name = {"Linux": "linux", "Darwin": "darwin", "Windows": "windows"}.get(
|
||||
platform.system()
|
||||
)
|
||||
arch = {
|
||||
"x86_64": "x64",
|
||||
"amd64": "x64",
|
||||
"arm64": "arm64",
|
||||
"aarch64": "arm64",
|
||||
"i386": "x32",
|
||||
"i686": "x32",
|
||||
"x86": "x32",
|
||||
"armv7l": "armv7",
|
||||
"armv6l": "armv6",
|
||||
}.get(platform.machine().lower())
|
||||
if not os_name or not arch:
|
||||
raise SystemExit(
|
||||
f"Unsupported platform for gitleaks: {platform.system()}/{platform.machine()}"
|
||||
)
|
||||
return f"{os_name}_{arch}"
|
||||
|
||||
|
||||
def cached_version() -> str | None:
|
||||
if not BIN.exists():
|
||||
return None
|
||||
try:
|
||||
return subprocess.run(
|
||||
[str(BIN), "version"], capture_output=True, text=True
|
||||
).stdout.strip()
|
||||
except OSError:
|
||||
return None
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if cached_version() == VERSION:
|
||||
return 0
|
||||
|
||||
key = platform_key()
|
||||
expected = SHA256.get(key)
|
||||
if expected is None:
|
||||
raise SystemExit(f"No pinned gitleaks checksum for {key}")
|
||||
|
||||
suffix = "zip" if key.startswith("windows") else "tar.gz"
|
||||
asset = f"gitleaks_{VERSION}_{key}.{suffix}"
|
||||
url = f"https://github.com/gitleaks/gitleaks/releases/download/v{VERSION}/{asset}"
|
||||
print(f"Downloading gitleaks {VERSION} ({asset})", flush=True)
|
||||
|
||||
BIN.parent.mkdir(parents=True, exist_ok=True)
|
||||
archive, _ = urllib.request.urlretrieve(url)
|
||||
digest = hashlib.sha256(Path(archive).read_bytes()).hexdigest()
|
||||
if digest != expected:
|
||||
raise SystemExit(
|
||||
f"gitleaks checksum mismatch: expected {expected}, got {digest}"
|
||||
)
|
||||
|
||||
member = "gitleaks.exe" if IS_WINDOWS else "gitleaks"
|
||||
if suffix == "zip":
|
||||
with zipfile.ZipFile(archive) as zf:
|
||||
data = zf.read(member)
|
||||
else:
|
||||
with tarfile.open(archive) as tf:
|
||||
extracted = tf.extractfile(member)
|
||||
if extracted is None:
|
||||
raise SystemExit(f"{member} not found in {asset}")
|
||||
data = extracted.read()
|
||||
BIN.write_bytes(data)
|
||||
BIN.chmod(0o755)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,16 @@
|
||||
# Pinned Python lint/format tools for `task pre-commit`. uv.lock locks these
|
||||
# plus their transitive dependencies by hash, so `uv run --project
|
||||
# scripts/pre-commit --locked <tool>` is reproducible and integrity-checked.
|
||||
# This is not a packaged project - it only exists to lock the tooling.
|
||||
[project]
|
||||
name = "stirling-precommit-tools"
|
||||
version = "0"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"ruff==0.15.14",
|
||||
"codespell==2.4.2",
|
||||
"toml-sort==0.24.4",
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
package = false
|
||||
Generated
+75
@@ -0,0 +1,75 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.11"
|
||||
|
||||
[[package]]
|
||||
name = "codespell"
|
||||
version = "2.4.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2d/9d/1d0903dff693160f893ca6abcabad545088e7a2ee0a6deae7c24e958be69/codespell-2.4.2.tar.gz", hash = "sha256:3c33be9ae34543807f088aeb4832dfad8cb2dae38da61cac0a7045dd376cfdf3", size = 352058, upload-time = "2026-03-05T18:10:42.936Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/42/a1/52fa05533e95fe45bcc09bcf8a503874b1c08f221a4e35608017e0938f55/codespell-2.4.2-py3-none-any.whl", hash = "sha256:97e0c1060cf46bd1d5db89a936c98db8c2b804e1fdd4b5c645e82a1ec6b1f886", size = 353715, upload-time = "2026-03-05T18:10:41.398Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.15.14"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/dc/8a/8bce2894573e9dae6ff4d77fe34ad727d79b9e6238ad288c5638990d90f6/ruff-0.15.14.tar.gz", hash = "sha256:48e866b165be4a9bdbf310f7d3c9a07edef2fe8cd63ffeb4e00bb590506ebf9f", size = 4700910, upload-time = "2026-05-21T14:34:55.177Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/c8/74a92c6ff9fcfb4f1f947126d3ebee8389276e161ecc85de5bda7cda51bd/ruff-0.15.14-py3-none-linux_armv6l.whl", hash = "sha256:8dd2db9416e487c8d4b01fa7056bb02c4d05969d4f8d17a08c229c2f4ff3c108", size = 10739177, upload-time = "2026-05-21T14:34:37.332Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/91/254a35c20acc38a7223c9d2d594af12e794432464f2cdeb52af1dc4a892d/ruff-0.15.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:be4ff55af755bd71a00ab3dc6bd7ffc467bd76e0df6881e286c2e3d23e8fb43b", size = 11144969, upload-time = "2026-05-21T14:34:43.978Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/9e/d13e40f83b8d0a94430e6778ce1d94a43b38cf2efe63278bdd2b4c65abbf/ruff-0.15.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:48d5909d7d06276ce7dde6d32bfa4b0d4cb2651145cd8ee4b440722cbc77832f", size = 10478207, upload-time = "2026-05-21T14:34:48.378Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/f1/b15a7839fa4f332f8acec78e20564f26bb2d866e3d21710b877fd0263000/ruff-0.15.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca8cbfa94c4f90984a67561978602746d4cd27103568f745fa90eee3f0d4107d", size = 10818459, upload-time = "2026-05-21T14:34:22.318Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/33/53d651177f84f94b400a0e27f8824eeada3dddc9d5ee8aeb048f4352a520/ruff-0.15.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a6bbc0333f1ab053423bcbf6226477d266ca7cec7738c4c8e3f55647803f3c4", size = 10541800, upload-time = "2026-05-21T14:34:20.209Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/a6/868f87e0bf9786ed24b5d0d0ad8676b8a94fd1912f42cddf9cfc7857818a/ruff-0.15.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a24a4f7605d7003a6674d4387651effd939dead3fddd0f36561eb77a9a2e542", size = 11342149, upload-time = "2026-05-21T14:34:46.365Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/8b/38cd5c19faffdcc05a408d2b78edccc69492ab9720eadb49ea15ef80d768/ruff-0.15.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:049b5326e53ed80978f2fc041a280603f69dd6b0c95464342a2bb4572d9d9e2f", size = 12212563, upload-time = "2026-05-21T14:34:28.579Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/4d/a3c5b874a556d5731e3e657aaf04311bb76f0a5c3ec220ed43051be6b64b/ruff-0.15.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4ed42e6696c8dfa5f06728e6441993901f548eb92d73bc472cb5a38d1395fbf", size = 11493299, upload-time = "2026-05-21T14:34:41.836Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/c0/56472c251d09858a53e51efbd485b09e1995d8731668b76d52e5dd6ee0f1/ruff-0.15.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715c543cf450c4888251f91c52f1942a800541d9bddd7ac060aa4e6b77ae7cba", size = 11455931, upload-time = "2026-05-21T14:34:57.276Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/4a/e2e7b4d8dbf233d4eace59c75bc3435fa6d8bd3bae82d351d4e4300c0fd1/ruff-0.15.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ebab6013ec887d439d8b7593737a0a4ffb06d45d209d4e4bf2e92813082d3f", size = 11400794, upload-time = "2026-05-21T14:34:39.773Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/97/c7/83c0539fe34c3e09136204d1e75d6052492364e0b3cb05e9465423f567d7/ruff-0.15.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:49072d36abdbe97a8dd7f480afe9c675699c0c495d4c84076e2c1203c4550581", size = 10804759, upload-time = "2026-05-21T14:34:31.045Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/a6/18f2bfc095a2ab4a78745644e428205532ce6653a5d0fa8501572891534d/ruff-0.15.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:958522aee105068640c2c2ceae08f413ae44d922f52a1374ac13d6a96032fc93", size = 10539517, upload-time = "2026-05-21T14:34:53.064Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/3a/5a8b3b69c654d4e4bf1d246ac5b49cbcdac6eaab6905925f8915f31e3b80/ruff-0.15.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f3707da619a143a2e8830e2abab8224478d69ace2d28cb6c20543ae97c36bf61", size = 11065169, upload-time = "2026-05-21T14:34:24.484Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/c5/8864e4e7925b836ea354b31d57641ec03830564e281a8b6f061f8c3e0ec1/ruff-0.15.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bb01d645694e3ec0102105d07ef2d53703970407d59c04e59d3ba0b7a1d53553", size = 11560214, upload-time = "2026-05-21T14:34:50.975Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/38/012bf76752e1f89ed50b77b99532d90f3a3e287bc7918e1fc0948ac866ac/ruff-0.15.14-py3-none-win32.whl", hash = "sha256:6d0c1ad2a0ab718d39b6d8fd2217981ce4d625cd96a720095f798fb47d8b13e6", size = 10805548, upload-time = "2026-05-21T14:34:33.453Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/b7/4ea2c170f10ad760fff2a5250beb18897719dc8b52b53a24cddbb9dd3f19/ruff-0.15.14-py3-none-win_amd64.whl", hash = "sha256:802342981e056db3851a7836e5b070f8f15f67d4a685ae2a6160939d364b2902", size = 11939523, upload-time = "2026-05-21T14:34:18.077Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/62/d5/bc97ff895ec35cf3925d4bd60f3b39d822f377a446906ec9bcc87405e59b/ruff-0.15.14-py3-none-win_arm64.whl", hash = "sha256:ff47b90a9ef6a40c9e2f3b479c1fb78531adf055b94c1eba0a7ba04b31951826", size = 11208607, upload-time = "2026-05-21T14:34:26.525Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stirling-precommit-tools"
|
||||
version = "0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "codespell" },
|
||||
{ name = "ruff" },
|
||||
{ name = "toml-sort" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "codespell", specifier = "==2.4.2" },
|
||||
{ name = "ruff", specifier = "==0.15.14" },
|
||||
{ name = "toml-sort", specifier = "==0.24.4" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml-sort"
|
||||
version = "0.24.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "tomlkit" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/47/c5/d6f650fdcf8e1f83096815fa67fb13a9a345b99da6015c60c4b7e4a8ea2b/toml_sort-0.24.4.tar.gz", hash = "sha256:429b69f5b98b7047a11380c80ecf0838556bdea1a8902d0be564961c48841423", size = 17793, upload-time = "2026-03-24T14:05:53.637Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/5a/1f0e54df4eacf0f4d8f94ba50cf72be33d2a3f04babdfb1931bead48a0ab/toml_sort-0.24.4-py3-none-any.whl", hash = "sha256:125aa5fb94f33c542c6901040456145dd38f79bbb310b56b436a93057d30a739", size = 16577, upload-time = "2026-03-24T14:05:54.757Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomlkit"
|
||||
version = "0.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/51/db/03eaf4331631ef6b27d6e3c9b68c54dc6f0d63d87201fed600cc409307fd/tomlkit-0.15.0.tar.gz", hash = "sha256:7d1a9ecba3086638211b13814ea79c90dd54dd11993564376f3aa92271f5c7a3", size = 161875, upload-time = "2026-05-10T07:38:22.245Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/43/8bd850ee71a191bf072e31302c73a66be413fecdd98fdcd111ecbcce13ca/tomlkit-0.15.0-py3-none-any.whl", hash = "sha256:4dbc8f0fc024412b57ced8757ac7461305126a648ff8c2c807fcb8e133a78738", size = 41328, upload-time = "2026-05-10T07:38:23.517Z" },
|
||||
]
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Trailing-whitespace and end-of-file normalisation, driven by Task.
|
||||
|
||||
Replaces the end-of-file-fixer / trailing-whitespace pre-commit hooks, which
|
||||
have no read-only mode. Run via `task pre-commit` (check) and `task
|
||||
pre-commit:fix`.
|
||||
|
||||
Takes git pathspecs (not a file list) and runs `git ls-files` itself, so the
|
||||
matched files never hit the command line - on Windows that list can be ~66KB
|
||||
and exceed the ~32KB CreateProcess argv limit.
|
||||
|
||||
python whitespace.py <pathspec>... # check: report, exit 1 if any need fixing
|
||||
python whitespace.py --fix <pathspec>... # fix: rewrite in place
|
||||
|
||||
Operates on bytes and only ever touches trailing spaces/tabs and the final
|
||||
newline, so it never mangles content or line endings. Binary files (those with
|
||||
a NUL byte) are skipped.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def tracked_files(pathspecs: list[str]) -> list[str]:
|
||||
result = subprocess.run(
|
||||
["git", "ls-files", "-z", *pathspecs],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
return [path for path in result.stdout.split("\0") if path]
|
||||
|
||||
|
||||
def normalise(data: bytes) -> bytes:
|
||||
# Strip trailing spaces/tabs from each line (leave \r so CRLF survives).
|
||||
lines = [line.rstrip(b" \t") for line in data.split(b"\n")]
|
||||
body = b"\n".join(lines)
|
||||
# Ensure a non-empty file ends with exactly one newline.
|
||||
stripped = body.rstrip(b"\r\n")
|
||||
return stripped + b"\n" if stripped else body
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = sys.argv[1:]
|
||||
fix = "--fix" in args
|
||||
pathspecs = [a for a in args if a != "--fix"]
|
||||
|
||||
offenders: list[str] = []
|
||||
for path in tracked_files(pathspecs):
|
||||
data = Path(path).read_bytes()
|
||||
if b"\0" in data:
|
||||
continue
|
||||
fixed = normalise(data)
|
||||
if fixed == data:
|
||||
continue
|
||||
offenders.append(path)
|
||||
if fix:
|
||||
Path(path).write_bytes(fixed)
|
||||
|
||||
if offenders and not fix:
|
||||
print(f"{len(offenders)} file(s) need whitespace fixing:")
|
||||
for path in offenders:
|
||||
print(f" {path}")
|
||||
return 1
|
||||
if offenders and fix:
|
||||
print(f"Fixed whitespace in {len(offenders)} file(s).")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user