Compare commits
2 Commits
main
...
claude-check
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b5af60157 | |||
| acaefd404c |
Executable
+148
@@ -0,0 +1,148 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import urllib.request
|
||||||
|
import urllib.parse
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import tempfile
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
def run_cmd(cmd, cwd=None):
|
||||||
|
return subprocess.run(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||||
|
|
||||||
|
def get_local_foreign_packages():
|
||||||
|
res = run_cmd(['pacman', '-Qm'])
|
||||||
|
if res.returncode != 0:
|
||||||
|
return {}
|
||||||
|
pkgs = {}
|
||||||
|
for line in res.stdout.strip().split('\n'):
|
||||||
|
if line:
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) == 2:
|
||||||
|
pkgs[parts[0]] = parts[1]
|
||||||
|
return pkgs
|
||||||
|
|
||||||
|
def get_aur_info(pkgnames):
|
||||||
|
if not pkgnames:
|
||||||
|
return {}
|
||||||
|
results = {}
|
||||||
|
chunk_size = 100
|
||||||
|
pkgs = list(pkgnames)
|
||||||
|
for i in range(0, len(pkgs), chunk_size):
|
||||||
|
chunk = pkgs[i:i+chunk_size]
|
||||||
|
url = "https://aur.archlinux.org/rpc/v5/info?" + "&".join([f"arg[]={urllib.parse.quote(p)}" for p in chunk])
|
||||||
|
try:
|
||||||
|
req = urllib.request.urlopen(url, timeout=10)
|
||||||
|
data = json.loads(req.read().decode('utf-8'))
|
||||||
|
if data.get('type') == 'multiinfo':
|
||||||
|
for item in data.get('results', []):
|
||||||
|
results[item['Name']] = item
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return results
|
||||||
|
|
||||||
|
def needs_upgrade(local_ver, aur_ver):
|
||||||
|
res = run_cmd(['vercmp', local_ver, aur_ver])
|
||||||
|
try:
|
||||||
|
return int(res.stdout.strip()) < 0
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def extract_ver(content):
|
||||||
|
pkgver, pkgrel = None, None
|
||||||
|
for line in content.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith('pkgver='):
|
||||||
|
pkgver = line.split('=', 1)[1].strip('"\'')
|
||||||
|
elif line.startswith('pkgrel='):
|
||||||
|
pkgrel = line.split('=', 1)[1].strip('"\'')
|
||||||
|
return pkgver, pkgrel
|
||||||
|
|
||||||
|
def strip_volatile_fields(content):
|
||||||
|
content = re.sub(r'^pkgver=.*$', '', content, flags=re.MULTILINE)
|
||||||
|
content = re.sub(r'^pkgrel=.*$', '', content, flags=re.MULTILINE)
|
||||||
|
sum_patterns = [
|
||||||
|
r'md5sums', r'sha1sums', r'sha224sums', r'sha256sums',
|
||||||
|
r'sha384sums', r'sha512sums', r'b2sums', r'cksums'
|
||||||
|
]
|
||||||
|
for sp in sum_patterns:
|
||||||
|
pattern = r'^' + sp + r'(?:_[a-zA-Z0-9_]+)?=\(.*?\)'
|
||||||
|
content = re.sub(pattern, '', content, flags=re.MULTILINE | re.DOTALL)
|
||||||
|
|
||||||
|
lines = [line.rstrip() for line in content.split('\n') if line.strip()]
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
local_pkgs = get_local_foreign_packages()
|
||||||
|
if not local_pkgs:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
aur_info = get_aur_info(list(local_pkgs.keys()))
|
||||||
|
|
||||||
|
upgrades = []
|
||||||
|
for pkg, local_ver in local_pkgs.items():
|
||||||
|
if pkg in aur_info:
|
||||||
|
aur_ver = aur_info[pkg]['Version']
|
||||||
|
if needs_upgrade(local_ver, aur_ver):
|
||||||
|
upgrades.append((pkg, local_ver, aur_ver))
|
||||||
|
|
||||||
|
if not upgrades:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
print(f"Checking PKGBUILD diffs for {len(upgrades)} upgrades...")
|
||||||
|
|
||||||
|
temp_dir = tempfile.mkdtemp()
|
||||||
|
try:
|
||||||
|
for pkg, local_ver, aur_ver in upgrades:
|
||||||
|
print(f"Checking {pkg} ({local_ver} -> {aur_ver})")
|
||||||
|
repo_dir = os.path.join(temp_dir, pkg)
|
||||||
|
res = run_cmd(['git', 'clone', '--quiet', f'https://aur.archlinux.org/{pkg}.git', repo_dir])
|
||||||
|
if res.returncode != 0:
|
||||||
|
print(f"Failed to clone {pkg}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
res = run_cmd(['git', 'log', '--pretty=format:%H'], cwd=repo_dir)
|
||||||
|
commits = res.stdout.strip().split('\n')
|
||||||
|
|
||||||
|
old_pkgbuild_content = None
|
||||||
|
new_pkgbuild_content = None
|
||||||
|
|
||||||
|
with open(os.path.join(repo_dir, 'PKGBUILD'), 'r', encoding='utf-8', errors='ignore') as f:
|
||||||
|
new_pkgbuild_content = f.read()
|
||||||
|
|
||||||
|
local_ver_no_epoch = local_ver.split(':', 1)[-1]
|
||||||
|
parts = local_ver_no_epoch.rsplit('-', 1)
|
||||||
|
expected_ver, expected_rel = parts if len(parts) == 2 else (parts[0], "")
|
||||||
|
|
||||||
|
for commit in commits:
|
||||||
|
res = run_cmd(['git', 'show', f"{commit}:PKGBUILD"], cwd=repo_dir)
|
||||||
|
if res.returncode == 0:
|
||||||
|
content = res.stdout
|
||||||
|
p_ver, p_rel = extract_ver(content)
|
||||||
|
if p_ver == expected_ver and p_rel == expected_rel:
|
||||||
|
old_pkgbuild_content = content
|
||||||
|
break
|
||||||
|
|
||||||
|
if old_pkgbuild_content is None:
|
||||||
|
print(f"ERROR: Could not find old PKGBUILD for {pkg} version {local_ver}. Cannot safely verify diff.", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
old_stripped = strip_volatile_fields(old_pkgbuild_content)
|
||||||
|
new_stripped = strip_volatile_fields(new_pkgbuild_content)
|
||||||
|
|
||||||
|
if old_stripped != new_stripped:
|
||||||
|
print(f"ERROR: Unsafe changes detected in PKGBUILD for {pkg}!", file=sys.stderr)
|
||||||
|
with open(os.path.join(temp_dir, 'old'), 'w') as f:
|
||||||
|
f.write(old_stripped)
|
||||||
|
with open(os.path.join(temp_dir, 'new'), 'w') as f:
|
||||||
|
f.write(new_stripped)
|
||||||
|
subprocess.run(['diff', '-u', os.path.join(temp_dir, 'old'), os.path.join(temp_dir, 'new')])
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
shutil.rmtree(temp_dir)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
- name: Get list of AUR Python packages that need to be rebuilt
|
- name: Get list of AUR Python packages that need to be rebuilt
|
||||||
ansible.builtin.shell:
|
ansible.builtin.shell:
|
||||||
cmd:
|
cmd:
|
||||||
comm -12 <(pactree -lrud1 {{ package_pattern }} | sort -u) <(pacman -Qqm | sort -u)
|
comm -12 <(pactree -lrud1 {{ package_pattern }} | sort -u) <(pacman -Qqm | sort -u)
|
||||||
|
executable: /bin/bash
|
||||||
register: aur_packages
|
register: aur_packages
|
||||||
- name: Rebuild AUR Python packages
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Rebuild AUR Python packages
|
||||||
aur:
|
aur:
|
||||||
use: "{{ aur_helper }}"
|
use: "{{ aur_helper }}"
|
||||||
name: '{{ item }}'
|
name: '{{ item }}'
|
||||||
aur_only: true
|
aur_only: true
|
||||||
extra_args: --rebuild
|
extra_args: --rebuild
|
||||||
loop: '{{ aur_packages.stdout.split() }}'
|
loop: '{{ aur_packages.stdout_lines | default([]) }}'
|
||||||
|
when: aur_packages.stdout_lines | default([]) | length > 0
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
---
|
---
|
||||||
|
- name: Check AUR package diffs for poisoning
|
||||||
|
ansible.builtin.script: aur_diff_check.py
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
- name: AUR upgrade
|
- name: AUR upgrade
|
||||||
aur:
|
aur:
|
||||||
use: "{{ aur_helper }}"
|
use: "{{ aur_helper }}"
|
||||||
|
|||||||
@@ -6,12 +6,10 @@
|
|||||||
upgrade: true
|
upgrade: true
|
||||||
extra_args: "--noconfirm"
|
extra_args: "--noconfirm"
|
||||||
register: arch_upgrade_result
|
register: arch_upgrade_result
|
||||||
#- name: Debug full Arch upgrade output
|
|
||||||
# ansible.builtin.debug:
|
|
||||||
# var: arch_upgrade_result
|
|
||||||
failed_when:
|
failed_when:
|
||||||
- arch_upgrade_result.failed == true
|
- arch_upgrade_result.failed == true
|
||||||
# We ignore the failure if it's just 'nothing to do',
|
- "'there is nothing to do' not in (arch_upgrade_result.stdout | default('') | lower)"
|
||||||
# # but otherwise, we let it fail so you can step in.
|
- name: Debug full Arch upgrade output
|
||||||
- "'Nothing to upgrade' not in arch_upgrade_result.msg"
|
ansible.builtin.debug:
|
||||||
|
var: arch_upgrade_result
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
- name: Full system upgrade
|
|
||||||
become: true
|
|
||||||
ansible.builtin.apt:
|
|
||||||
update_cache: true
|
|
||||||
upgrade: full
|
|
||||||
@@ -1,2 +1,6 @@
|
|||||||
- name: Perform official repository updates
|
---
|
||||||
ansible.builtin.import_tasks: apt_upgrade.yaml
|
- name: Full system upgrade
|
||||||
|
become: true
|
||||||
|
ansible.builtin.apt:
|
||||||
|
update_cache: true
|
||||||
|
upgrade: full
|
||||||
|
|||||||
Regular → Executable
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env zsh
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Exit code 0 = Reboot required
|
# Exit code 0 = Reboot required
|
||||||
# Exit code 1 = System is up to date / No reboot needed
|
# Exit code 1 = System is up to date / No reboot needed
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
name: mollyguard.service
|
name: mollyguard.service
|
||||||
state: stopped
|
state: stopped
|
||||||
listen: Reboot system
|
listen: Reboot system
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
- name: Execute System Reboot
|
- name: Execute System Reboot
|
||||||
become: true
|
become: true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Check if kernel or microcode update requires reboot
|
- name: Check if kernel or microcode update requires reboot
|
||||||
ansible.builtin.script: check_reboot.zsh # Your script placed in files/
|
ansible.builtin.script: check_reboot.sh # Your script placed in files/
|
||||||
register: reboot_check
|
register: reboot_check
|
||||||
# Prevent Ansible from failing if the script returns false (exit code 1)
|
# Prevent Ansible from failing if the script returns false (exit code 1)
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|||||||
+1
-1
@@ -22,6 +22,6 @@
|
|||||||
- name: Create override
|
- name: Create override
|
||||||
ansible.builtin.shell:
|
ansible.builtin.shell:
|
||||||
cmd: |
|
cmd: |
|
||||||
printf {{ passphrase }} | (echo "[Service]"; systemd-creds encrypt --name={{ creds_name }} --pretty - -) >> /etc/systemd/system/shared.d/00-systemd-creds.conf
|
printf '%s' {{ passphrase | quote }} | (echo "[Service]"; systemd-creds encrypt --name={{ creds_name }} --pretty - -) >> /etc/systemd/system/shared.d/00-systemd-creds.conf
|
||||||
printf "Environment=%s=%%d/%s\n" {{ creds_var }} {{ creds_name }} >> /etc/systemd/system/shared.d/00-systemd-creds.conf
|
printf "Environment=%s=%%d/%s\n" {{ creds_var }} {{ creds_name }} >> /etc/systemd/system/shared.d/00-systemd-creds.conf
|
||||||
#creates: /etc/systemd/system/shared.d/00-systemd-creds.conf
|
#creates: /etc/systemd/system/shared.d/00-systemd-creds.conf
|
||||||
|
|||||||
Reference in New Issue
Block a user