ctf-agent 1.2.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.
Files changed (152) hide show
  1. package/AGENTS.md +131 -0
  2. package/Dockerfile +192 -0
  3. package/README.md +522 -0
  4. package/agents/ctf-analyzer.md +58 -0
  5. package/agents/ctf-controller.md +151 -0
  6. package/agents/ctf-speedrun.md +74 -0
  7. package/bin/ctf-agent.js +119 -0
  8. package/docker-compose.yml +13 -0
  9. package/mcp_config.json +19 -0
  10. package/package.json +44 -0
  11. package/references/ctf-triage-ladder.md +68 -0
  12. package/references/exploit-databases.md +575 -0
  13. package/references/llm-safety-and-policy-compliance.md +173 -0
  14. package/references/multi-agent-orchestration-and-policy-routing.md +278 -0
  15. package/references/security-events-and-intelligence.md +566 -0
  16. package/references/version-matrix.md +59 -0
  17. package/rules/ctf-execution-rules.md +44 -0
  18. package/rules/ctf-safety-framing-rules.md +140 -0
  19. package/rules/flag-validation-rules.md +25 -0
  20. package/scripts/__init__.py +1 -0
  21. package/scripts/ctf-tools.lock +205 -0
  22. package/scripts/ctf_init.py +1026 -0
  23. package/scripts/ctf_update.py +583 -0
  24. package/scripts/ctfd_client.py +81 -0
  25. package/scripts/cve_lookup.py +453 -0
  26. package/scripts/extract_flags.py +155 -0
  27. package/scripts/install_as_agent.py +278 -0
  28. package/scripts/install_ctf_tools.sh +603 -0
  29. package/scripts/parallel_triage.py +395 -0
  30. package/scripts/prompt_policy_sanitizer.py +283 -0
  31. package/scripts/scope_guard.py +444 -0
  32. package/scripts/skill_validator.py +504 -0
  33. package/scripts/workspace_cleaner.py +141 -0
  34. package/skills/ctf-ai-ml/SKILL.md +120 -0
  35. package/skills/ctf-ai-ml/adversarial-ml.md +623 -0
  36. package/skills/ctf-ai-ml/llm-attacks.md +487 -0
  37. package/skills/ctf-ai-ml/model-attacks.md +422 -0
  38. package/skills/ctf-crypto/SKILL.md +320 -0
  39. package/skills/ctf-crypto/advanced-math.md +798 -0
  40. package/skills/ctf-crypto/classic-ciphers.md +651 -0
  41. package/skills/ctf-crypto/ecc-attacks.md +347 -0
  42. package/skills/ctf-crypto/exotic-crypto-2.md +380 -0
  43. package/skills/ctf-crypto/exotic-crypto.md +528 -0
  44. package/skills/ctf-crypto/historical.md +113 -0
  45. package/skills/ctf-crypto/lattice-and-lwe.md +524 -0
  46. package/skills/ctf-crypto/modern-ciphers-2.md +563 -0
  47. package/skills/ctf-crypto/modern-ciphers-3.md +453 -0
  48. package/skills/ctf-crypto/modern-ciphers.md +649 -0
  49. package/skills/ctf-crypto/prng-attacks.md +257 -0
  50. package/skills/ctf-crypto/prng.md +664 -0
  51. package/skills/ctf-crypto/rsa-attacks-2.md +792 -0
  52. package/skills/ctf-crypto/rsa-attacks.md +487 -0
  53. package/skills/ctf-crypto/stream-ciphers.md +390 -0
  54. package/skills/ctf-crypto/zkp-and-advanced.md +456 -0
  55. package/skills/ctf-forensics/3d-printing.md +121 -0
  56. package/skills/ctf-forensics/SKILL.md +379 -0
  57. package/skills/ctf-forensics/disk-advanced.md +497 -0
  58. package/skills/ctf-forensics/disk-and-memory.md +491 -0
  59. package/skills/ctf-forensics/disk-recovery.md +699 -0
  60. package/skills/ctf-forensics/linux-forensics.md +511 -0
  61. package/skills/ctf-forensics/network-advanced.md +583 -0
  62. package/skills/ctf-forensics/network.md +645 -0
  63. package/skills/ctf-forensics/peripheral-capture.md +287 -0
  64. package/skills/ctf-forensics/signals-and-hardware.md +713 -0
  65. package/skills/ctf-forensics/steganography.md +694 -0
  66. package/skills/ctf-forensics/stego-advanced-2.md +475 -0
  67. package/skills/ctf-forensics/stego-advanced.md +481 -0
  68. package/skills/ctf-forensics/stego-image.md +691 -0
  69. package/skills/ctf-forensics/windows.md +625 -0
  70. package/skills/ctf-malware/SKILL.md +181 -0
  71. package/skills/ctf-malware/c2-and-protocols.md +274 -0
  72. package/skills/ctf-malware/pe-and-dotnet.md +108 -0
  73. package/skills/ctf-malware/scripts-and-obfuscation.md +449 -0
  74. package/skills/ctf-misc/SKILL.md +498 -0
  75. package/skills/ctf-misc/bashjails.md +323 -0
  76. package/skills/ctf-misc/ctfd-navigation.md +465 -0
  77. package/skills/ctf-misc/dns.md +255 -0
  78. package/skills/ctf-misc/encodings-advanced.md +504 -0
  79. package/skills/ctf-misc/encodings.md +431 -0
  80. package/skills/ctf-misc/games-and-vms-2.md +254 -0
  81. package/skills/ctf-misc/games-and-vms-3.md +690 -0
  82. package/skills/ctf-misc/games-and-vms-4.md +229 -0
  83. package/skills/ctf-misc/games-and-vms.md +529 -0
  84. package/skills/ctf-misc/linux-privesc.md +333 -0
  85. package/skills/ctf-misc/pyjails.md +671 -0
  86. package/skills/ctf-misc/rf-sdr.md +91 -0
  87. package/skills/ctf-osint/SKILL.md +198 -0
  88. package/skills/ctf-osint/geolocation-and-media.md +464 -0
  89. package/skills/ctf-osint/social-media.md +312 -0
  90. package/skills/ctf-osint/web-and-dns.md +341 -0
  91. package/skills/ctf-pwn/SKILL.md +214 -0
  92. package/skills/ctf-pwn/advanced-exploits-2.md +579 -0
  93. package/skills/ctf-pwn/advanced-exploits-3.md +598 -0
  94. package/skills/ctf-pwn/advanced-exploits-4.md +590 -0
  95. package/skills/ctf-pwn/advanced-exploits-5.md +119 -0
  96. package/skills/ctf-pwn/advanced-exploits.md +773 -0
  97. package/skills/ctf-pwn/advanced.md +326 -0
  98. package/skills/ctf-pwn/field-notes.md +245 -0
  99. package/skills/ctf-pwn/format-string.md +694 -0
  100. package/skills/ctf-pwn/heap-fsop.md +285 -0
  101. package/skills/ctf-pwn/heap-techniques-2.md +333 -0
  102. package/skills/ctf-pwn/heap-techniques.md +513 -0
  103. package/skills/ctf-pwn/kernel-bypass.md +421 -0
  104. package/skills/ctf-pwn/kernel-techniques.md +366 -0
  105. package/skills/ctf-pwn/kernel.md +636 -0
  106. package/skills/ctf-pwn/overflow-basics.md +611 -0
  107. package/skills/ctf-pwn/rop-advanced.md +725 -0
  108. package/skills/ctf-pwn/rop-and-shellcode.md +659 -0
  109. package/skills/ctf-pwn/sandbox-escape.md +313 -0
  110. package/skills/ctf-reverse/SKILL.md +163 -0
  111. package/skills/ctf-reverse/anti-analysis-ctf.md +204 -0
  112. package/skills/ctf-reverse/anti-analysis.md +693 -0
  113. package/skills/ctf-reverse/field-notes.md +376 -0
  114. package/skills/ctf-reverse/languages-compiled.md +666 -0
  115. package/skills/ctf-reverse/languages-platforms.md +592 -0
  116. package/skills/ctf-reverse/languages.md +553 -0
  117. package/skills/ctf-reverse/patterns-ctf-2.md +397 -0
  118. package/skills/ctf-reverse/patterns-ctf-3.md +797 -0
  119. package/skills/ctf-reverse/patterns-ctf.md +670 -0
  120. package/skills/ctf-reverse/patterns-runtime.md +274 -0
  121. package/skills/ctf-reverse/patterns.md +572 -0
  122. package/skills/ctf-reverse/platforms-hardware.md +387 -0
  123. package/skills/ctf-reverse/platforms.md +664 -0
  124. package/skills/ctf-reverse/tools-advanced-2.md +421 -0
  125. package/skills/ctf-reverse/tools-advanced.md +407 -0
  126. package/skills/ctf-reverse/tools-dynamic.md +679 -0
  127. package/skills/ctf-reverse/tools-emulation.md +319 -0
  128. package/skills/ctf-reverse/tools.md +573 -0
  129. package/skills/ctf-web/SKILL.md +153 -0
  130. package/skills/ctf-web/auth-and-access-2.md +82 -0
  131. package/skills/ctf-web/auth-and-access.md +783 -0
  132. package/skills/ctf-web/auth-infra.md +321 -0
  133. package/skills/ctf-web/auth-jwt.md +186 -0
  134. package/skills/ctf-web/client-side-advanced.md +739 -0
  135. package/skills/ctf-web/client-side.md +529 -0
  136. package/skills/ctf-web/cves.md +373 -0
  137. package/skills/ctf-web/field-notes.md +482 -0
  138. package/skills/ctf-web/node-and-prototype.md +200 -0
  139. package/skills/ctf-web/server-side-2.md +337 -0
  140. package/skills/ctf-web/server-side-advanced-2.md +559 -0
  141. package/skills/ctf-web/server-side-advanced-3.md +125 -0
  142. package/skills/ctf-web/server-side-advanced-4.md +480 -0
  143. package/skills/ctf-web/server-side-advanced.md +378 -0
  144. package/skills/ctf-web/server-side-deser.md +443 -0
  145. package/skills/ctf-web/server-side-exec-2.md +799 -0
  146. package/skills/ctf-web/server-side-exec.md +457 -0
  147. package/skills/ctf-web/server-side.md +629 -0
  148. package/skills/ctf-web/sql-injection.md +790 -0
  149. package/skills/ctf-web/web3.md +374 -0
  150. package/skills/ctf-writeup/SKILL.md +90 -0
  151. package/skills/solve-challenge/SKILL.md +269 -0
  152. package/skills.json +16 -0
@@ -0,0 +1,603 @@
1
+ #!/usr/bin/env bash
2
+ # shellcheck disable=SC2024 # redirects target user-owned log file, not sudo
3
+ # ===========================================================================
4
+ # CTF Security Workstation Installer & Profile Manager (v2.0)
5
+ # Modular 3-Tier Architecture: Core, Category Profiles & Heavy Research
6
+ # ===========================================================================
7
+ #
8
+ # Usage:
9
+ # bash scripts/install_ctf_tools.sh [OPTIONS] [PROFILE]
10
+ #
11
+ # Available Profiles:
12
+ # core - Tier 1: Essential system utilities, compilers, network tools, and base libraries
13
+ # pwn - Tier 2: Binary exploitation, ROP generation, seccomp bypass, and heap tooling
14
+ # rev - Tier 2: Reverse engineering, disassemblers, decompilers, and symbolics
15
+ # crypto - Tier 2: Cryptanalysis, lattice reduction, number theory, and solvers
16
+ # forensics - Tier 2: Digital forensics, memory analysis, PCAP carvers, and file parsing
17
+ # stego - Tier 2: Steganography, bit-plane inspection, and audio/image recovery
18
+ # web - Tier 2: Modern web exploitation, fuzzers, JWT, HTTP/2/3, and crawler pipelines
19
+ # mobile - Tier 2: Android & iOS reverse engineering, APK patching, and dynamic instrumentation
20
+ # cloud - Tier 2: Container security, Kubernetes inspection, and cloud metadata testing
21
+ # ad - Tier 2: Active Directory, Kerberos, SMB, and Windows penetration testing
22
+ # kernel - Tier 2: Linux kernel exploitation, eBPF inspection, debugging, and tracing
23
+ # hardware - Tier 2: IoT firmware, serial debugging, JTAG, and multi-architecture cross tools
24
+ # web3 - Tier 2: Smart contract auditing, EVM interaction, and bytecode analysis
25
+ # wasm - Tier 2: WebAssembly binary analysis, disassembling, and execution
26
+ # ai - Tier 2: Machine learning security, adversarial models, and safetensors analysis
27
+ # all - Install all category profiles sequentially
28
+ #
29
+ # Legacy Modes (Backwards Compatibility):
30
+ # python, apt, brew, gems, go, manual
31
+ #
32
+ # Options:
33
+ # --list-profiles Show available profiles, descriptions, and package breakdowns
34
+ # --verify [PROF] Verify tool availability and exact Python package versions
35
+ # --dry-run Preview packages and commands without executing installations
36
+ # --force Reinstall packages even if already present
37
+ # --update Upgrade packages to match locked definitions
38
+ #
39
+ # Examples:
40
+ # bash scripts/install_ctf_tools.sh core
41
+ # bash scripts/install_ctf_tools.sh web
42
+ # bash scripts/install_ctf_tools.sh --verify pwn
43
+ # bash scripts/install_ctf_tools.sh --list-profiles
44
+ # bash scripts/install_ctf_tools.sh all
45
+
46
+ set -euo pipefail
47
+
48
+ # ---------------------------------------------------------------------------
49
+ # Globals & Configuration
50
+ # ---------------------------------------------------------------------------
51
+
52
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
53
+ LOCKFILE="${SCRIPT_DIR}/ctf-tools.lock"
54
+ LOG_DIR="${HOME}/.ctf-tools"
55
+ CTF_VENV="${HOME}/.ctf-tools/venv"
56
+
57
+ DRY_RUN=false
58
+ FORCE=false
59
+ UPDATE=false
60
+ MODE=""
61
+ TARGET_PROFILE=""
62
+ LOG_FILE=""
63
+
64
+ FAILED=()
65
+ SUCCEEDED=()
66
+ SKIPPED=()
67
+
68
+ ALL_PROFILES=(
69
+ "core" "pwn" "rev" "crypto" "forensics" "stego"
70
+ "web" "mobile" "cloud" "ad" "kernel" "hardware"
71
+ "web3" "wasm" "ai"
72
+ )
73
+
74
+ # ---------------------------------------------------------------------------
75
+ # Logging & Output Helpers
76
+ # ---------------------------------------------------------------------------
77
+
78
+ setup_logging() {
79
+ mkdir -p "$LOG_DIR"
80
+ LOG_FILE="${LOG_DIR}/install-$(date +%Y-%m-%d_%H%M%S).log"
81
+ log_info "Session log: $LOG_FILE"
82
+ }
83
+
84
+ log_info() { echo "==> $*" | tee -a "${LOG_FILE:-/dev/null}"; }
85
+ log_warn() { echo "WARNING: $*" | tee -a "${LOG_FILE:-/dev/null}" >&2; }
86
+ log_error() { echo "ERROR: $*" | tee -a "${LOG_FILE:-/dev/null}" >&2; }
87
+ log_detail() { echo " $*" >> "${LOG_FILE:-/dev/null}"; }
88
+
89
+ require_cmd() {
90
+ local cmd="$1"
91
+ if ! command -v "$cmd" >/dev/null 2>&1; then
92
+ log_error "'$cmd' is required but not found in PATH"
93
+ return 1
94
+ fi
95
+ }
96
+
97
+ # ---------------------------------------------------------------------------
98
+ # Version & Installation Verification Checks
99
+ # ---------------------------------------------------------------------------
100
+
101
+ # Check if exact Python package version matches requested version via importlib.metadata
102
+ py_pkg_version_matches() {
103
+ local pkg_name="$1"
104
+ local req_ver="$2"
105
+
106
+ python3 -c "
107
+ import sys
108
+ try:
109
+ import importlib.metadata as m
110
+ v = m.version('$pkg_name')
111
+ req = '$req_ver'.strip()
112
+ if not req or v == req:
113
+ sys.exit(0)
114
+ sys.exit(1)
115
+ except Exception:
116
+ sys.exit(1)
117
+ " 2>/dev/null
118
+ }
119
+
120
+ # Check if an apt package is installed
121
+ apt_pkg_installed() {
122
+ dpkg -s "$1" >/dev/null 2>&1
123
+ }
124
+
125
+ # Check if a Homebrew formula is installed
126
+ brew_pkg_installed() {
127
+ brew list --formula "$1" >/dev/null 2>&1
128
+ }
129
+
130
+ # Check if a Ruby gem is installed
131
+ gem_installed() {
132
+ local gem_name="$1"
133
+ local gem_ver="${2:-}"
134
+ if [ -n "$gem_ver" ]; then
135
+ gem list -i "^${gem_name}$" -v "$gem_ver" >/dev/null 2>&1
136
+ else
137
+ gem list -i "^${gem_name}$" >/dev/null 2>&1
138
+ fi
139
+ }
140
+
141
+ # ---------------------------------------------------------------------------
142
+ # Lockfile Query Engine
143
+ # ---------------------------------------------------------------------------
144
+
145
+ query_lockfile() {
146
+ local profile="$1"
147
+ local query_type="$2" # apt, pip, gem, go, verify_bins, manual, description
148
+
149
+ if [ ! -f "$LOCKFILE" ]; then
150
+ log_warn "Lockfile not found at $LOCKFILE, operating with internal fallbacks."
151
+ return 1
152
+ fi
153
+
154
+ python3 -c "
155
+ import json, sys
156
+ try:
157
+ with open('$LOCKFILE', 'r') as f:
158
+ data = json.load(f)
159
+ prof = data.get('profiles', {}).get('$profile', {})
160
+ qtype = '$query_type'
161
+
162
+ if qtype == 'description':
163
+ print(prof.get('description', 'No description available.'))
164
+ elif qtype == 'apt':
165
+ for pkg in prof.get('apt', []):
166
+ print(pkg)
167
+ elif qtype == 'pip':
168
+ pips = prof.get('pip', {})
169
+ for name, meta in pips.items():
170
+ ver = meta.get('version', '')
171
+ imp = meta.get('import', name)
172
+ if ver:
173
+ print(f'{name}=={ver}:{imp}')
174
+ else:
175
+ print(f'{name}:{imp}')
176
+ elif qtype == 'gem':
177
+ for g in prof.get('gem', []):
178
+ print(f\"{g.get('name')}:{g.get('version', '')}\")
179
+ elif qtype == 'go':
180
+ for g in prof.get('go', []):
181
+ print(f\"{g.get('package')}@{g.get('version')}:{g.get('bin')}\")
182
+ elif qtype == 'verify_bins':
183
+ for b in prof.get('verify_bins', []):
184
+ print(b)
185
+ elif qtype == 'manual':
186
+ for m in prof.get('manual', []):
187
+ print(m)
188
+ except Exception as e:
189
+ sys.exit(1)
190
+ " 2>/dev/null
191
+ }
192
+
193
+ # ---------------------------------------------------------------------------
194
+ # Dedicated Virtualenv Setup (PEP 668 Compliant)
195
+ # ---------------------------------------------------------------------------
196
+
197
+ ensure_virtualenv() {
198
+ require_cmd python3 || return 1
199
+
200
+ if [ -n "${VIRTUAL_ENV:-}" ]; then
201
+ return 0
202
+ fi
203
+
204
+ if [ ! -d "$CTF_VENV" ]; then
205
+ if [ "$DRY_RUN" = true ]; then
206
+ log_info "Would create dedicated virtualenv at $CTF_VENV"
207
+ return 0
208
+ fi
209
+ log_info "Creating dedicated CTF virtualenv at $CTF_VENV"
210
+ python3 -m venv "$CTF_VENV" >>"${LOG_FILE:-/dev/null}" 2>&1 || {
211
+ log_warn "venv creation failed, defaulting to active Python runtime"
212
+ return 0
213
+ }
214
+ fi
215
+
216
+ if [ -f "$CTF_VENV/bin/activate" ]; then
217
+ # shellcheck disable=SC1091
218
+ source "$CTF_VENV/bin/activate"
219
+ log_info "Active virtualenv: $CTF_VENV"
220
+ fi
221
+ }
222
+
223
+ # ---------------------------------------------------------------------------
224
+ # Installation Primitives
225
+ # ---------------------------------------------------------------------------
226
+
227
+ install_apt_packages() {
228
+ local packages=("$@")
229
+ if [ ${#packages[@]} -eq 0 ]; then return 0; fi
230
+ if ! command -v apt-get >/dev/null 2>&1; then
231
+ log_warn "apt-get not available; skipping APT packages"
232
+ return 0
233
+ fi
234
+
235
+ local to_install=()
236
+ for pkg in "${packages[@]}"; do
237
+ if [ "$FORCE" = false ] && apt_pkg_installed "$pkg"; then
238
+ SKIPPED+=("apt:$pkg")
239
+ continue
240
+ fi
241
+ to_install+=("$pkg")
242
+ done
243
+
244
+ if [ ${#to_install[@]} -eq 0 ]; then
245
+ log_info "APT: All ${#packages[@]} packages already installed"
246
+ return 0
247
+ fi
248
+
249
+ log_info "APT: Installing ${#to_install[@]} package(s): ${to_install[*]}"
250
+ if [ "$DRY_RUN" = true ]; then return 0; fi
251
+
252
+ sudo DEBIAN_FRONTEND=noninteractive apt-get update -q >>"${LOG_FILE:-/dev/null}" 2>&1 || true
253
+ for pkg in "${to_install[@]}"; do
254
+ if sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -q "$pkg" >>"${LOG_FILE:-/dev/null}" 2>&1; then
255
+ SUCCEEDED+=("apt:$pkg")
256
+ else
257
+ log_warn "APT installation failed: $pkg"
258
+ FAILED+=("apt:$pkg")
259
+ fi
260
+ done
261
+ }
262
+
263
+ install_pip_packages() {
264
+ local entries=("$@")
265
+ if [ ${#entries[@]} -eq 0 ]; then return 0; fi
266
+ ensure_virtualenv
267
+
268
+ local to_install=()
269
+ local to_install_names=()
270
+
271
+ for entry in "${entries[@]}"; do
272
+ local spec="${entry%%:*}"
273
+ local name="${spec%%==*}"
274
+ local ver="${spec#*==}"
275
+ if [ "$ver" = "$spec" ]; then ver=""; fi
276
+
277
+ if [ "$FORCE" = false ] && [ "$UPDATE" = false ] && py_pkg_version_matches "$name" "$ver"; then
278
+ SKIPPED+=("pip:$name")
279
+ continue
280
+ fi
281
+
282
+ to_install+=("$spec")
283
+ to_install_names+=("$name")
284
+ done
285
+
286
+ if [ ${#to_install[@]} -eq 0 ]; then
287
+ log_info "Pip: All ${#entries[@]} package(s) up-to-date and matching locked versions"
288
+ return 0
289
+ fi
290
+
291
+ log_info "Pip: Installing/Updating ${#to_install[@]} package(s): ${to_install_names[*]}"
292
+ if [ "$DRY_RUN" = true ]; then return 0; fi
293
+
294
+ python3 -m pip install --upgrade pip setuptools wheel >>"${LOG_FILE:-/dev/null}" 2>&1 || true
295
+
296
+ for spec in "${to_install[@]}"; do
297
+ local name="${spec%%==*}"
298
+ if python3 -m pip install "$spec" >>"${LOG_FILE:-/dev/null}" 2>&1; then
299
+ SUCCEEDED+=("pip:$name")
300
+ else
301
+ log_warn "Pip installation failed: $spec"
302
+ FAILED+=("pip:$name")
303
+ fi
304
+ done
305
+ }
306
+
307
+ install_gem_packages() {
308
+ local entries=("$@")
309
+ if [ ${#entries[@]} -eq 0 ]; then return 0; fi
310
+ if ! command -v gem >/dev/null 2>&1; then
311
+ log_warn "gem command not found; skipping Ruby gems"
312
+ for e in "${entries[@]}"; do SKIPPED+=("gem:${e%%:*}"); done
313
+ return 0
314
+ fi
315
+
316
+ for entry in "${entries[@]}"; do
317
+ local name="${entry%%:*}"
318
+ local ver="${entry##*:}"
319
+
320
+ if [ "$FORCE" = false ] && gem_installed "$name" "$ver"; then
321
+ SKIPPED+=("gem:$name")
322
+ continue
323
+ fi
324
+
325
+ log_info "Gem: Installing $name ($ver)"
326
+ if [ "$DRY_RUN" = true ]; then continue; fi
327
+
328
+ local cmd=()
329
+ if [ "$(id -u)" -ne 0 ] && command -v sudo >/dev/null 2>&1; then
330
+ cmd+=(sudo)
331
+ fi
332
+ cmd+=(gem install "$name" --no-document)
333
+ if [ -n "$ver" ]; then cmd+=(-v "$ver"); fi
334
+
335
+ if "${cmd[@]}" >>"${LOG_FILE:-/dev/null}" 2>&1; then
336
+ SUCCEEDED+=("gem:$name")
337
+ else
338
+ log_warn "Gem installation failed: $name"
339
+ FAILED+=("gem:$name")
340
+ fi
341
+ done
342
+ }
343
+
344
+ install_go_packages() {
345
+ local entries=("$@")
346
+ if [ ${#entries[@]} -eq 0 ]; then return 0; fi
347
+ if ! command -v go >/dev/null 2>&1; then
348
+ log_warn "go command not found; skipping Go binaries"
349
+ for e in "${entries[@]}"; do SKIPPED+=("go:${e##*:}"); done
350
+ return 0
351
+ fi
352
+
353
+ for entry in "${entries[@]}"; do
354
+ local spec="${entry%%:*}"
355
+ local bin="${entry##*:}"
356
+
357
+ if [ "$FORCE" = false ] && command -v "$bin" >/dev/null 2>&1; then
358
+ SKIPPED+=("go:$bin")
359
+ continue
360
+ fi
361
+
362
+ log_info "Go: Installing $bin from $spec"
363
+ if [ "$DRY_RUN" = true ]; then continue; fi
364
+
365
+ if go install "$spec" >>"${LOG_FILE:-/dev/null}" 2>&1; then
366
+ local gopath_bin
367
+ gopath_bin="$(go env GOPATH 2>/dev/null || echo "$HOME/go")/bin"
368
+ if [ -f "$gopath_bin/$bin" ]; then
369
+ if [ "$(id -u)" -eq 0 ]; then
370
+ cp -f "$gopath_bin/$bin" /usr/local/bin/ 2>/dev/null || true
371
+ elif command -v sudo >/dev/null 2>&1; then
372
+ sudo cp -f "$gopath_bin/$bin" /usr/local/bin/ 2>/dev/null || true
373
+ fi
374
+ fi
375
+ SUCCEEDED+=("go:$bin")
376
+ else
377
+ log_warn "Go installation failed: $bin"
378
+ FAILED+=("go:$bin")
379
+ fi
380
+ done
381
+ }
382
+
383
+ # ---------------------------------------------------------------------------
384
+ # Profile Dispatcher
385
+ # ---------------------------------------------------------------------------
386
+
387
+ install_profile() {
388
+ local profile="$1"
389
+ log_info "Processing Profile: [$profile]"
390
+
391
+ local desc
392
+ desc="$(query_lockfile "$profile" "description" || echo "")"
393
+ if [ -n "$desc" ]; then
394
+ log_info "Description: $desc"
395
+ fi
396
+
397
+ # 1. APT packages
398
+ mapfile -t apt_pkgs < <(query_lockfile "$profile" "apt" || true)
399
+ if [ ${#apt_pkgs[@]} -gt 0 ]; then
400
+ install_apt_packages "${apt_pkgs[@]}"
401
+ fi
402
+
403
+ # 2. Pip packages
404
+ mapfile -t pip_pkgs < <(query_lockfile "$profile" "pip" || true)
405
+ if [ ${#pip_pkgs[@]} -gt 0 ]; then
406
+ install_pip_packages "${pip_pkgs[@]}"
407
+ fi
408
+
409
+ # 3. Ruby Gems
410
+ mapfile -t gem_pkgs < <(query_lockfile "$profile" "gem" || true)
411
+ if [ ${#gem_pkgs[@]} -gt 0 ]; then
412
+ install_gem_packages "${gem_pkgs[@]}"
413
+ fi
414
+
415
+ # 4. Go binaries
416
+ mapfile -t go_pkgs < <(query_lockfile "$profile" "go" || true)
417
+ if [ ${#go_pkgs[@]} -gt 0 ]; then
418
+ install_go_packages "${go_pkgs[@]}"
419
+ fi
420
+
421
+ # 5. Manual Tools Advisories
422
+ mapfile -t manual_notes < <(query_lockfile "$profile" "manual" || true)
423
+ if [ ${#manual_notes[@]} -gt 0 ]; then
424
+ echo ""
425
+ echo " [i] Note for profile [$profile] - Additional tools available:"
426
+ for m in "${manual_notes[@]}"; do
427
+ echo " * $m"
428
+ done
429
+ echo ""
430
+ fi
431
+ }
432
+
433
+ # ---------------------------------------------------------------------------
434
+ # Verification Engine
435
+ # ---------------------------------------------------------------------------
436
+
437
+ verify_profile() {
438
+ local profile="$1"
439
+ echo "======================================================================"
440
+ echo "[*] VERIFYING PROFILE: [$profile]"
441
+ echo "======================================================================"
442
+
443
+ ensure_virtualenv 2>/dev/null || true
444
+
445
+ local found_bins=()
446
+ local missing_bins=()
447
+ local found_py=()
448
+ local missing_py=()
449
+
450
+ # 1. Check binaries
451
+ mapfile -t bins < <(query_lockfile "$profile" "verify_bins" || true)
452
+ for b in "${bins[@]}"; do
453
+ [ -z "$b" ] && continue
454
+ if command -v "$b" >/dev/null 2>&1; then
455
+ found_bins+=("$b")
456
+ else
457
+ missing_bins+=("$b")
458
+ fi
459
+ done
460
+
461
+ # 2. Check Pip Packages with exact version validation
462
+ mapfile -t pips < <(query_lockfile "$profile" "pip" || true)
463
+ for p in "${pips[@]}"; do
464
+ [ -z "$p" ] && continue
465
+ local spec="${p%%:*}"
466
+ local name="${spec%%==*}"
467
+ local ver="${spec#*==}"
468
+ if [ "$ver" = "$spec" ]; then ver=""; fi
469
+
470
+ if py_pkg_version_matches "$name" "$ver"; then
471
+ found_py+=("$name ($ver)")
472
+ else
473
+ missing_py+=("$name ($ver)")
474
+ fi
475
+ done
476
+
477
+ echo " - CLI Binaries Verified: ${#found_bins[@]}/${#bins[@]}"
478
+ if [ ${#missing_bins[@]} -gt 0 ]; then
479
+ echo " Missing Binaries: ${missing_bins[*]}"
480
+ fi
481
+
482
+ echo " - Python Packages Verified: ${#found_py[@]}/${#pips[@]}"
483
+ if [ ${#missing_py[@]} -gt 0 ]; then
484
+ echo " Missing/Version Mismatch: ${missing_py[*]}"
485
+ fi
486
+ echo ""
487
+ }
488
+
489
+ verify_all() {
490
+ local target="${1:-all}"
491
+ if [ "$target" = "all" ]; then
492
+ for p in "${ALL_PROFILES[@]}"; do
493
+ verify_profile "$p"
494
+ done
495
+ else
496
+ verify_profile "$target"
497
+ fi
498
+ }
499
+
500
+ # ---------------------------------------------------------------------------
501
+ # List Profiles
502
+ # ---------------------------------------------------------------------------
503
+
504
+ list_profiles() {
505
+ echo "======================================================================"
506
+ echo " CTF Security Workstation - Available Profiles (v2.0)"
507
+ echo "======================================================================"
508
+ for p in "${ALL_PROFILES[@]}"; do
509
+ local desc
510
+ desc="$(query_lockfile "$p" "description" || echo "")"
511
+ printf " %-12s : %s\n" "$p" "$desc"
512
+ done
513
+ printf " %-12s : %s\n" "all" "Install all 15 category profiles sequentially"
514
+ echo "======================================================================"
515
+ }
516
+
517
+ # ---------------------------------------------------------------------------
518
+ # Execution Summary
519
+ # ---------------------------------------------------------------------------
520
+
521
+ print_summary() {
522
+ echo ""
523
+ echo "========================================"
524
+ echo " Installation Summary"
525
+ echo "========================================"
526
+ echo " Installed: ${#SUCCEEDED[@]}"
527
+ echo " Skipped: ${#SKIPPED[@]} (already up to date)"
528
+ echo " Failed: ${#FAILED[@]}"
529
+ if [ ${#FAILED[@]} -gt 0 ]; then
530
+ echo ""
531
+ echo " Failed Packages:"
532
+ for f in "${FAILED[@]}"; do
533
+ echo " - $f"
534
+ done
535
+ fi
536
+ echo "========================================"
537
+ if [ -n "${LOG_FILE:-}" ]; then
538
+ echo " Session Log: $LOG_FILE"
539
+ echo "========================================"
540
+ fi
541
+ }
542
+
543
+ # ---------------------------------------------------------------------------
544
+ # CLI Argument Parser & Entry Point
545
+ # ---------------------------------------------------------------------------
546
+
547
+ main() {
548
+ local positional=()
549
+
550
+ while [ $# -gt 0 ]; do
551
+ case "$1" in
552
+ --dry-run) DRY_RUN=true; shift ;;
553
+ --force) FORCE=true; shift ;;
554
+ --update) UPDATE=true; shift ;;
555
+ --list-profiles) list_profiles; exit 0 ;;
556
+ --verify) MODE="verify"; shift ;;
557
+ -*) echo "Unknown option: $1" >&2; exit 2 ;;
558
+ *) positional+=("$1"); shift ;;
559
+ esac
560
+ done
561
+
562
+ TARGET_PROFILE="${positional[0]:-}"
563
+
564
+ # Verification Mode
565
+ if [ "$MODE" = "verify" ]; then
566
+ verify_all "${TARGET_PROFILE:-all}"
567
+ exit 0
568
+ fi
569
+
570
+ # Default to 'all' if no positional profile was supplied
571
+ TARGET_PROFILE="${TARGET_PROFILE:-all}"
572
+
573
+ # Backwards compatibility with legacy mode strings
574
+ case "$TARGET_PROFILE" in
575
+ python) TARGET_PROFILE="core" ;;
576
+ apt) TARGET_PROFILE="core" ;;
577
+ brew) TARGET_PROFILE="core" ;;
578
+ gems) TARGET_PROFILE="pwn" ;;
579
+ go) TARGET_PROFILE="web" ;;
580
+ manual) TARGET_PROFILE="rev" ;;
581
+ esac
582
+
583
+ if [ "$DRY_RUN" = false ]; then
584
+ setup_logging
585
+ fi
586
+
587
+ if [ "$TARGET_PROFILE" = "all" ]; then
588
+ log_info "Initiating Full Workstation Installation Across All Profiles"
589
+ for p in "${ALL_PROFILES[@]}"; do
590
+ install_profile "$p"
591
+ done
592
+ else
593
+ install_profile "$TARGET_PROFILE"
594
+ fi
595
+
596
+ print_summary
597
+
598
+ if [ ${#FAILED[@]} -gt 0 ]; then
599
+ exit 1
600
+ fi
601
+ }
602
+
603
+ main "$@"