fix: manifest SHA256 from git blobs (CRLF/LF) — release 2.2.2-SAC
Manifest was hashed from Windows working tree while Linux checkout uses git blobs; verify failed with sha256 mismatch. build-release-manifest.sh now hashes :index/HEAD; .gitattributes enforces LF for agent scripts.
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
# Агентские скрипты — LF в git и на Linux (manifest SHA256 = git blob).
|
||||||
|
ssh-monitor text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
version.txt text eol=lf
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# ssh-monitor
|
# ssh-monitor
|
||||||
|
|
||||||
**Версия:** `2.2.1-SAC`
|
**Версия:** `2.2.2-SAC`
|
||||||
|
|
||||||
Bash-мониторинг **SSH**, **sudo**, **systemd-logind**: Telegram/email, бан IP (ipset), ежедневный отчёт, heartbeat.
|
Bash-мониторинг **SSH**, **sudo**, **systemd-logind**: Telegram/email, бан IP (ipset), ежедневный отчёт, heartbeat.
|
||||||
|
|
||||||
|
|||||||
@@ -91,13 +91,13 @@ Updater читает **`GIT_REF`**, **`GIT_VERIFY_MODE`**, **`GIT_ALLOW_RESET`**
|
|||||||
- Файл не найден → WARN, update продолжается (или exit 1 при **`RELEASE_MANIFEST_STRICT=1`**).
|
- Файл не найден → WARN, update продолжается (или exit 1 при **`RELEASE_MANIFEST_STRICT=1`**).
|
||||||
- Копирование **`update_ssh_monitor.sh`** в `/opt/scripts/` и re-exec — только если manifest для версии был и прошёл verify.
|
- Копирование **`update_ssh_monitor.sh`** в `/opt/scripts/` и re-exec — только если manifest для версии был и прошёл verify.
|
||||||
|
|
||||||
Генерация при релизе (после **финального** коммита кода, чтобы `git_commit` в manifest совпал с HEAD):
|
Генерация при релизе (хеши **из git**, как на Linux после `checkout` — не с диска Windows):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git commit -m "release: 2.2.0-SAC"
|
git add --renormalize ssh-monitor *.sh # при смене .gitattributes
|
||||||
./scripts/build-release-manifest.sh 2.2.0-SAC
|
./scripts/build-release-manifest.sh 2.2.2-SAC
|
||||||
git add release/manifest-2.2.0-SAC.json && git commit -m "release: manifest 2.2.0-SAC"
|
git add release/manifest-2.2.2-SAC.json && git commit -m "release: manifest 2.2.2-SAC"
|
||||||
git tag 2.2.0-SAC
|
git tag 2.2.2-SAC
|
||||||
```
|
```
|
||||||
|
|
||||||
### Примеры для прода
|
### Примеры для прода
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": "2.2.2-SAC",
|
||||||
|
"git_commit": "",
|
||||||
|
"files": {
|
||||||
|
"ssh-monitor": "sha256:be35da47fb1cf370628795bfdfe34195a7ba098c666bd8aa092929a168a10ef6",
|
||||||
|
"sac-client.sh": "sha256:4c481effd0e50b3db8cfa3baf3c5f228892530939df6f534a5d3d3d8a79db048",
|
||||||
|
"update_ssh_monitor.sh": "sha256:510d63b43ea02e5aaa4385bcc6c9396ad99637c377c9880125cb2168e9d422cd",
|
||||||
|
"ssh-monitor-watchdog": "sha256:41aa139cab0fb275249780953fceb3f8ebe01c49bf96f901dd3cf4d2fb3a9274",
|
||||||
|
"ssh-monitor-perms.sh": "sha256:53ebf15138d59be1610e5bc14a107b942d9a7fd039683abfd2fdd0aa0b54b933"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Генерация release/manifest-VERSION.json (SHA256 файлов + git commit HEAD).
|
# Генерация release/manifest-VERSION.json (SHA256 файлов + git commit HEAD).
|
||||||
|
# Хеши считаются по содержимому git (HEAD), как после checkout на Linux-хосте.
|
||||||
# Запуск из корня репозитория: ./scripts/build-release-manifest.sh [VERSION]
|
# Запуск из корня репозитория: ./scripts/build-release-manifest.sh [VERSION]
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -27,8 +28,8 @@ FILES=(
|
|||||||
)
|
)
|
||||||
|
|
||||||
for f in "${FILES[@]}"; do
|
for f in "${FILES[@]}"; do
|
||||||
[ -f "$f" ] || {
|
git rev-parse "HEAD:$f" >/dev/null 2>&1 || [ -f "$f" ] || {
|
||||||
echo "ERROR: нет файла $f" >&2
|
echo "ERROR: нет файла $f (ни в git HEAD, ни на диске)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
done
|
done
|
||||||
@@ -51,6 +52,7 @@ python3 <<'PY'
|
|||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
root = os.environ["MANIFEST_ROOT"]
|
root = os.environ["MANIFEST_ROOT"]
|
||||||
version = os.environ["MANIFEST_VERSION"]
|
version = os.environ["MANIFEST_VERSION"]
|
||||||
@@ -58,21 +60,41 @@ git_commit = os.environ.get("MANIFEST_GIT_COMMIT", "")
|
|||||||
files = os.environ["MANIFEST_FILES"].split()
|
files = os.environ["MANIFEST_FILES"].split()
|
||||||
out = os.environ["MANIFEST_OUT"]
|
out = os.environ["MANIFEST_OUT"]
|
||||||
|
|
||||||
def sha256_file(path: str) -> str:
|
|
||||||
|
def sha256_bytes(data: bytes) -> str:
|
||||||
|
h = hashlib.sha256()
|
||||||
|
h.update(data)
|
||||||
|
return h.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def file_bytes_from_git(name: str) -> bytes | None:
|
||||||
|
for ref in (f":{name}", f"HEAD:{name}"):
|
||||||
|
try:
|
||||||
|
return subprocess.check_output(["git", "-C", root, "show", ref])
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
continue
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def sha256_release_file(name: str) -> str:
|
||||||
|
blob = file_bytes_from_git(name)
|
||||||
|
if blob is not None:
|
||||||
|
return sha256_bytes(blob)
|
||||||
|
path = os.path.join(root, name)
|
||||||
h = hashlib.sha256()
|
h = hashlib.sha256()
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
for chunk in iter(lambda: f.read(1024 * 1024), b""):
|
for chunk in iter(lambda: f.read(1024 * 1024), b""):
|
||||||
h.update(chunk)
|
h.update(chunk)
|
||||||
return h.hexdigest()
|
return h.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
manifest = {
|
manifest = {
|
||||||
"version": version,
|
"version": version,
|
||||||
"git_commit": git_commit,
|
"git_commit": git_commit,
|
||||||
"files": {},
|
"files": {},
|
||||||
}
|
}
|
||||||
for name in files:
|
for name in files:
|
||||||
path = os.path.join(root, name)
|
manifest["files"][name] = f"sha256:{sha256_release_file(name)}"
|
||||||
manifest["files"][name] = f"sha256:{sha256_file(path)}"
|
|
||||||
|
|
||||||
with open(out, "w", encoding="utf-8") as f:
|
with open(out, "w", encoding="utf-8") as f:
|
||||||
json.dump(manifest, f, indent=2, ensure_ascii=False)
|
json.dump(manifest, f, indent=2, ensure_ascii=False)
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ IFS=$'\n\t'
|
|||||||
# ============================================
|
# ============================================
|
||||||
|
|
||||||
CONFIG_FILE="/etc/ssh-monitor.conf"
|
CONFIG_FILE="/etc/ssh-monitor.conf"
|
||||||
SSH_MONITOR_VERSION="2.2.1-SAC"
|
SSH_MONITOR_VERSION="2.2.2-SAC"
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
if [ -f "$SCRIPT_DIR/ssh-monitor-perms.sh" ]; then
|
if [ -f "$SCRIPT_DIR/ssh-monitor-perms.sh" ]; then
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
2.2.1-SAC
|
2.2.2-SAC
|
||||||
|
|||||||
Reference in New Issue
Block a user