@testzugang/pi-plugin-dependency-audit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+
6
+ echo "== Current global versions =="
7
+ bash "$SCRIPT_DIR/pi-check-current-global-versions.sh" "$@"
8
+
9
+ echo
10
+ echo "== Latest npm versions =="
11
+ bash "$SCRIPT_DIR/pi-check-latest-npm-versions.sh" "$@"
12
+
13
+ echo
14
+ echo "== Git source update status =="
15
+ bash "$SCRIPT_DIR/pi-check-git-source-updates.sh"
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ DEFAULT_PACKAGES_FILE="$SCRIPT_DIR/pi-default-packages.txt"
6
+ GLOBAL_ROOT="${NPM_GLOBAL_ROOT:-$(npm root -g 2>/dev/null || true)}"
7
+
8
+ if [[ -z "$GLOBAL_ROOT" ]]; then
9
+ echo "Could not determine npm global root. Set NPM_GLOBAL_ROOT or ensure npm is available." >&2
10
+ exit 2
11
+ fi
12
+
13
+ read_packages() {
14
+ if (( $# > 0 )); then
15
+ printf '%s\n' "$@"
16
+ return
17
+ fi
18
+
19
+ if [[ ! -f "$DEFAULT_PACKAGES_FILE" ]]; then
20
+ echo "Missing package list: $DEFAULT_PACKAGES_FILE" >&2
21
+ exit 2
22
+ fi
23
+
24
+ grep -vE '^\s*(#|$)' "$DEFAULT_PACKAGES_FILE"
25
+ }
26
+
27
+ while IFS= read -r pkg; do
28
+ [[ -z "$pkg" ]] && continue
29
+ pkg_json="$GLOBAL_ROOT/$pkg/package.json"
30
+
31
+ if [[ -f "$pkg_json" ]]; then
32
+ version="$(node -p "require('$pkg_json').version" 2>/dev/null || echo UNKNOWN)"
33
+ echo "$pkg: current=$version"
34
+ else
35
+ echo "$pkg: NOT FOUND at $pkg_json"
36
+ fi
37
+ done < <(read_packages "$@")
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ DEFAULT_REPOS_FILE="$SCRIPT_DIR/pi-default-git-repos.txt"
6
+
7
+ read_repos() {
8
+ if (( $# > 0 )); then
9
+ printf '%s\n' "$@"
10
+ return
11
+ fi
12
+
13
+ if [[ ! -f "$DEFAULT_REPOS_FILE" ]]; then
14
+ echo "Missing repo list: $DEFAULT_REPOS_FILE" >&2
15
+ exit 2
16
+ fi
17
+
18
+ grep -vE '^\s*(#|$)' "$DEFAULT_REPOS_FILE"
19
+ }
20
+
21
+ while IFS= read -r repo; do
22
+ [[ -z "$repo" ]] && continue
23
+
24
+ if [[ ! -d "$repo" ]]; then
25
+ echo "Directory $repo NOT FOUND"
26
+ continue
27
+ fi
28
+
29
+ if ! git -C "$repo" rev-parse --git-dir >/dev/null 2>&1; then
30
+ echo "Directory $repo is not a git repository"
31
+ continue
32
+ fi
33
+
34
+ echo "--- $repo ---"
35
+
36
+ branch="$(git -C "$repo" rev-parse --abbrev-ref HEAD 2>/dev/null || echo DETACHED)"
37
+ current_commit="$(git -C "$repo" rev-parse HEAD 2>/dev/null || echo UNKNOWN)"
38
+
39
+ git -C "$repo" fetch --quiet origin 2>/dev/null || true
40
+
41
+ remote_commit="NO_REMOTE_BRANCH"
42
+ if [[ "$branch" != "HEAD" && "$branch" != "DETACHED" ]]; then
43
+ remote_commit="$(git -C "$repo" rev-parse "origin/$branch" 2>/dev/null || echo NO_REMOTE_BRANCH)"
44
+ fi
45
+
46
+ echo "Branch: $branch"
47
+ echo "Current Commit: $current_commit"
48
+ echo "Remote Commit: $remote_commit"
49
+
50
+ if [[ "$remote_commit" == "NO_REMOTE_BRANCH" ]]; then
51
+ echo "Status: UNKNOWN"
52
+ elif [[ "$current_commit" != "$remote_commit" ]]; then
53
+ echo "Status: UPDATE_AVAILABLE"
54
+ else
55
+ echo "Status: UP_TO_DATE"
56
+ fi
57
+ done < <(read_repos "$@")
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ DEFAULT_PACKAGES_FILE="$SCRIPT_DIR/pi-default-packages.txt"
6
+
7
+ read_packages() {
8
+ if (( $# > 0 )); then
9
+ printf '%s\n' "$@"
10
+ return
11
+ fi
12
+
13
+ if [[ ! -f "$DEFAULT_PACKAGES_FILE" ]]; then
14
+ echo "Missing package list: $DEFAULT_PACKAGES_FILE" >&2
15
+ exit 2
16
+ fi
17
+
18
+ grep -vE '^\s*(#|$)' "$DEFAULT_PACKAGES_FILE"
19
+ }
20
+
21
+ while IFS= read -r pkg; do
22
+ [[ -z "$pkg" ]] && continue
23
+ latest="$(npm view "$pkg" version 2>/dev/null || echo NOT_IN_REGISTRY)"
24
+ echo "$pkg: latest=$latest"
25
+ done < <(read_packages "$@")
@@ -0,0 +1,4 @@
1
+ # Default local git-based pi package checkouts.
2
+ ~/.pi/agent/git/github.com/testzugang/pi-plugins
3
+ ~/.pi/agent/git/github.com/fgladisch/pi-skills
4
+ ~/.pi/agent/git/github.com/hasit/pi-community-themes
@@ -0,0 +1,16 @@
1
+ # Default global pi-related npm packages to audit.
2
+ pi-mcp-adapter
3
+ pi-subagents
4
+ pi-web-access
5
+ pi-claude-bridge
6
+ pi-mermaid
7
+ pi-tool-display
8
+ pi-total-recall
9
+ pi-terminal-signals
10
+ @aliou/pi-guardrails
11
+ @fgladisch/pi-bash-approval
12
+ @fgladisch/pi-persistent-history
13
+ @fgladisch/pi-user-select
14
+ @fgladisch/pi-welcome-message
15
+ pi-powerline
16
+ pi-suggest
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import os
4
+ import subprocess
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ SCRIPT_DIR = Path(__file__).resolve().parent
9
+ RUN_AUDIT_SCRIPT = SCRIPT_DIR / "run_pi_dependency_audit.py"
10
+ AGGREGATED_JSON = Path("/tmp/pi_audit_aggregated.json")
11
+
12
+ def main():
13
+ print("\n🛡️ Starte Sicherheits-Audit der Pi-Abhängigkeiten...")
14
+
15
+ # 1. Run the audit script
16
+ audit_res = subprocess.run(["python3", str(RUN_AUDIT_SCRIPT)], text=True)
17
+ if audit_res.returncode != 0:
18
+ print("❌ Audit fehlgeschlagen oder abgebrochen.")
19
+ return 1
20
+
21
+ if not AGGREGATED_JSON.exists():
22
+ print("❌ Audit-Ergebnisdatei nicht gefunden.")
23
+ return 1
24
+
25
+ try:
26
+ results = json.loads(AGGREGATED_JSON.read_text(encoding="utf-8"))
27
+ except Exception as e:
28
+ print(f"❌ Fehler beim Lesen der Audit-Ergebnisse: {e}")
29
+ return 1
30
+
31
+ # 2. Filter updates
32
+ updates = [i for i in results if i.get("status") in {"update_available", "too_fresh"}]
33
+ if not updates:
34
+ print("\n✅ Alle Pi-Erweiterungen sind auf dem neuesten Stand!")
35
+ return 0
36
+
37
+ print("\n🔄 Ausstehende Updates und Audit-Ergebnisse:")
38
+ print("=" * 80)
39
+
40
+ # Helper to get source name
41
+ def get_pi_source(item):
42
+ if item.get("type") == "npm":
43
+ return f"npm:{item['name']}"
44
+ source = item.get("source")
45
+ if source:
46
+ return str(source)
47
+ name = item.get("name", "")
48
+ if name == "pi-skills":
49
+ return "git:github.com/fgladisch/pi-skills"
50
+ if name == "pi-plugins":
51
+ return "git:github.com/testzugang/pi-plugins"
52
+ if name == "pi-community-themes":
53
+ return "git:https://github.com/hasit/pi-community-themes"
54
+ return f"git:github.com/testzugang/{name}"
55
+
56
+ # Print menu
57
+ for idx, item in enumerate(updates, start=1):
58
+ name = item.get("name")
59
+ current = item.get("current")[:8] if item.get("type") == "git" and item.get("current") else item.get("current")
60
+ latest = item.get("latest")[:8] if item.get("type") == "git" and item.get("latest") else item.get("latest")
61
+ decision = item.get("decision", "UNKNOWN")
62
+ status = item.get("status")
63
+
64
+ # Format decision string
65
+ if decision in {"QUARANTINE", "BLOCK_UNTIL_REVIEW"}:
66
+ dec_str = f"❌ {decision}"
67
+ elif decision == "REVIEW_BEFORE_USE":
68
+ dec_str = f"🟡 {decision}"
69
+ elif status == "too_fresh":
70
+ dec_str = f"⏱️ TOO FRESH (Alterssperre)"
71
+ else:
72
+ dec_str = f"✅ SAFE"
73
+
74
+ print(f"[{idx}] {name} ({current} -> {latest})")
75
+ print(f" Urteil: {dec_str} | Quelle: {get_pi_source(item)}")
76
+ print("-" * 80)
77
+
78
+ print("\nOptionen:")
79
+ print(" - Gib die Nummern ein, die du aktualisieren willst (z.B. 1, 3, 5)")
80
+ print(" - 'safe' für alle als sicher eingestuften Updates")
81
+ print(" - 'all' für alle Updates (inkl. Warnungen/Quarantäne, auf eigene Gefahr!)")
82
+ print(" - 'q' zum Abbrechen")
83
+
84
+ try:
85
+ user_input = input("\nDeine Auswahl: ").strip().lower()
86
+ except KeyboardInterrupt:
87
+ print("\nAbgebrochen.")
88
+ return 0
89
+
90
+ if user_input in {"q", "quit", "exit", ""}:
91
+ print("Abgebrochen.")
92
+ return 0
93
+
94
+ selected_items = []
95
+
96
+ if user_input == "safe":
97
+ selected_items = [i for i in updates if i.get("decision") not in {"BLOCK_UNTIL_REVIEW", "QUARANTINE"} and i.get("status") != "too_fresh"]
98
+ if not selected_items:
99
+ print("Keine sicheren Updates vorhanden.")
100
+ return 0
101
+ elif user_input == "all":
102
+ selected_items = updates
103
+ else:
104
+ # Parse numbers
105
+ parts = [p.strip() for p in user_input.split(",")]
106
+ for p in parts:
107
+ try:
108
+ idx = int(p)
109
+ if 1 <= idx <= len(updates):
110
+ selected_items.append(updates[idx - 1])
111
+ else:
112
+ print(f"⚠️ Ungültige Nummer: {idx}")
113
+ except ValueError:
114
+ if p:
115
+ print(f"⚠️ Ungültige Eingabe übersprungen: '{p}'")
116
+
117
+ if not selected_items:
118
+ print("Keine Updates ausgewählt.")
119
+ return 0
120
+
121
+ print(f"\n🚀 Folgende {len(selected_items)} Updates werden installiert:")
122
+ for item in selected_items:
123
+ print(f" - {item.get('name')} ({get_pi_source(item)})")
124
+
125
+ try:
126
+ confirm = input("\nFortfahren? [J/n]: ").strip().lower()
127
+ except KeyboardInterrupt:
128
+ print("\nAbgebrochen.")
129
+ return 0
130
+
131
+ if confirm not in {"", "j", "ja", "yes", "y"}:
132
+ print("Abgebrochen.")
133
+ return 0
134
+
135
+ # Execute actual pi update commands
136
+ for item in selected_items:
137
+ source = get_pi_source(item)
138
+ print(f"\n========================================================")
139
+ print(f"📦 Führe aus: pi update {source}")
140
+ print(f"========================================================")
141
+ subprocess.run(["pi", "update", source])
142
+
143
+ print("\n✅ Update-Prozess beendet!")
144
+ return 0
145
+
146
+ if __name__ == "__main__":
147
+ try:
148
+ sys.exit(main())
149
+ except KeyboardInterrupt:
150
+ print("\nAbgebrochen.")
151
+ sys.exit(0)