From aca42caf0a2b8076bfbc36b6830bfb49b83f1fd0 Mon Sep 17 00:00:00 2001 From: IgorRachkov <89467086+igor04091968@users.noreply.github.com> Date: Thu, 30 Apr 2026 20:59:40 +0300 Subject: [PATCH] Add install-kit to repo drift checker --- scripts/check_install_kit_vs_repo.sh | 53 +++++++++++++++++++ scripts/quality-gate.sh | 17 ++++-- scripts/validate_install_kit.sh | 79 ++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 3 deletions(-) create mode 100755 scripts/check_install_kit_vs_repo.sh create mode 100755 scripts/validate_install_kit.sh diff --git a/scripts/check_install_kit_vs_repo.sh b/scripts/check_install_kit_vs_repo.sh new file mode 100755 index 0000000..97d165d --- /dev/null +++ b/scripts/check_install_kit_vs_repo.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT_DIR" + +KIT_DIR="install-kit-awindows-20260427-211240" + +python - <<'PY' +from pathlib import Path +import hashlib + +root=Path('.') +kit=Path('install-kit-awindows-20260427-211240') +if not kit.exists(): + raise SystemExit('Install kit directory not found') + +def sha(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + +all_compared=[] +mismatches=[] +missing_in_repo=[] + +for kp in sorted(p for p in kit.rglob('*') if p.is_file() and p.name!='MANIFEST.txt'): + rel=kp.relative_to(kit) + rp=root/rel + if not rp.exists(): + missing_in_repo.append(str(rel)) + continue + all_compared.append(str(rel)) + if sha(kp)!=sha(rp): + mismatches.append(str(rel)) + +ps_mismatches=[p for p in mismatches if p.startswith('windows/') and p.endswith('.ps1') or p.endswith('.psm1') or p.endswith('.psd1')] + +print(f'Compared files: {len(all_compared)}') +print(f'Missing in repo: {len(missing_in_repo)}') +print(f'Mismatched content: {len(mismatches)}') +if missing_in_repo: + print('--- Missing in repo ---') + for p in missing_in_repo: + print(p) +if mismatches: + print('--- Mismatches ---') + for p in mismatches: + print(p) +print(f'PowerShell mismatches: {len(ps_mismatches)}') +if ps_mismatches: + print('--- PowerShell mismatches ---') + for p in ps_mismatches: + print(p) +PY diff --git a/scripts/quality-gate.sh b/scripts/quality-gate.sh index 84b68eb..9182bfa 100755 --- a/scripts/quality-gate.sh +++ b/scripts/quality-gate.sh @@ -4,17 +4,17 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$ROOT_DIR" -echo "[1/3] Bash syntax check" +echo "[1/4] Bash syntax check" find aw-server proxmox -type f -name "*.sh" -print0 | xargs -0 -r -n1 bash -n -echo "[2/3] Shellcheck (if available)" +echo "[2/4] Shellcheck (if available)" if command -v shellcheck >/dev/null 2>&1; then find aw-server proxmox -type f -name "*.sh" -print0 | xargs -0 -r shellcheck else echo "shellcheck not found, skipping." fi -echo "[3/3] PowerShell parse check (if pwsh available)" +echo "[3/4] PowerShell parse check (if pwsh available)" if command -v pwsh >/dev/null 2>&1; then pwsh -NoLogo -NoProfile -Command ' $ErrorActionPreference = "Stop" @@ -28,4 +28,15 @@ else echo "pwsh not found, skipping." fi + + +echo "[4/4] Ansible syntax check (if ansible-playbook available)" +if command -v ansible-playbook >/dev/null 2>&1; then + for playbook in ansible/*.yml; do + ansible-playbook --syntax-check "$playbook" -i ansible/inventory.example.ini >/dev/null + done +else + echo "ansible-playbook not found, skipping." +fi + echo "quality-gate: OK" diff --git a/scripts/validate_install_kit.sh b/scripts/validate_install_kit.sh new file mode 100755 index 0000000..f0ddc43 --- /dev/null +++ b/scripts/validate_install_kit.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT_DIR" + +KIT_DIR="install-kit-awindows-20260427-211240" +MANIFEST="$KIT_DIR/MANIFEST.txt" +ZIP_ARCHIVE="install-kit-awindows-20260427-211240.zip" +TAR_ARCHIVE="install-kit-awindows-20260427-211240.tar.gz" + +required_files=( + "$MANIFEST" + "$KIT_DIR/README-INSTALL-KIT.txt" + "$KIT_DIR/windows/deploy-ensemble.ps1" + "$KIT_DIR/windows/validate-deployment.ps1" + "$KIT_DIR/ansible/deploy_aw_windows_phase2.yml" + "$KIT_DIR/aw-server/install_aw_server.sh" +) + +echo "[1/4] Required files presence" +for file in "${required_files[@]}"; do + [[ -f "$file" ]] || { echo "Missing required file: $file"; exit 1; } +done + +echo "[2/4] Manifest checksum verification" +sha256sum -c "$MANIFEST" >/dev/null + +echo "[3/4] Manifest completeness" +python - <<'PY' +from pathlib import Path +import sys +kit=Path('install-kit-awindows-20260427-211240') +manifest=kit/'MANIFEST.txt' +listed=[] +for line in manifest.read_text().splitlines(): + line=line.strip() + if not line: + continue + parts=line.split(' ',1) + if len(parts)!=2: + print(f'Invalid MANIFEST line: {line}') + sys.exit(1) + listed.append(parts[1]) +listed_set=set(listed) +actual_set={str(p) for p in kit.rglob('*') if p.is_file() and p.name!='MANIFEST.txt'} +missing=sorted(listed_set-actual_set) +extra=sorted(actual_set-listed_set) +if missing or extra: + print('Missing files listed in MANIFEST:', missing) + print('Files not listed in MANIFEST:', extra) + sys.exit(1) +print(f'MANIFEST complete: {len(actual_set)} files tracked') +PY + +echo "[4/4] Archive composition check" +python - <<'PY' +from pathlib import Path +import tarfile, zipfile, sys +kit_prefix='install-kit-awindows-20260427-211240/' +zip_path=Path('install-kit-awindows-20260427-211240.zip') +tar_path=Path('install-kit-awindows-20260427-211240.tar.gz') +if not zip_path.exists() or not tar_path.exists(): + print('Archives not found') + sys.exit(1) +with zipfile.ZipFile(zip_path) as z: + zip_files=sorted(i for i in z.namelist() if not i.endswith('/')) +with tarfile.open(tar_path, 'r:gz') as t: + tar_files=sorted(m.name for m in t.getmembers() if m.isfile()) +if zip_files != tar_files: + print('ZIP and TAR contents differ') + sys.exit(1) +if not all(f.startswith(kit_prefix) for f in zip_files): + print('Unexpected archive prefix layout') + sys.exit(1) +print(f'Archives match: {len(zip_files)} files') +PY + +echo "validate_install_kit: OK"