pwn 0.5.783 → 0.5.785
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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/Gemfile +8 -8
- data/README.md +37 -0
- data/Rakefile +19 -1
- data/bin/pwn +2 -1
- data/bin/pwn_setup +1 -1
- data/bin/pwn_web_cache_deception +35 -7
- data/build_gem.sh +1 -1
- data/documentation/AI-Integration.md +7 -5
- data/documentation/Agent-Tool-Registry.md +2 -2
- data/documentation/Backup-Retention.md +82 -0
- data/documentation/Configuration.md +10 -6
- data/documentation/Contributing.md +1 -1
- data/documentation/Cron.md +64 -35
- data/documentation/Diagrams.md +2 -2
- data/documentation/General-PWN-Usage.md +4 -3
- data/documentation/Home.md +6 -5
- data/documentation/How-PWN-Works.md +7 -6
- data/documentation/Installation.md +254 -10
- data/documentation/Mission-Cancellation.md +134 -0
- data/documentation/Operability.md +17 -0
- data/documentation/Persistence.md +8 -6
- data/documentation/Plugin-Degradation.md +12 -0
- data/documentation/Plugins.md +3 -2
- data/documentation/Reinforcement-Learning.md +5 -6
- data/documentation/Runtime-Source-Protection.md +162 -0
- data/documentation/Transparent-Browser.md +11 -0
- data/documentation/Troubleshooting.md +3 -2
- data/documentation/What-is-PWN.md +2 -2
- data/documentation/YubiKey-Vaults.md +183 -0
- data/documentation/YubiKey.md +339 -0
- data/documentation/diagrams/cron-scheduling.svg +130 -128
- data/documentation/diagrams/dot/cron-scheduling.dot +5 -5
- data/documentation/diagrams/dot/persistence-filesystem.dot +5 -3
- data/documentation/diagrams/dot/plugin-ecosystem.dot +2 -2
- data/documentation/diagrams/persistence-filesystem.svg +172 -142
- data/documentation/diagrams/plugin-ecosystem.svg +64 -64
- data/documentation/pwn-ai-Agent.md +10 -4
- data/etc/default_cron/session_cleanup.rb +1245 -22
- data/etc/default_skills/pwn/ai/agent/mission_namespace/SKILL.md +21 -0
- data/etc/default_skills/pwn/ai/agent/tools/browser_act/SKILL.md +45 -0
- data/etc/default_skills/pwn/ai/agent/tools/loot_query/SKILL.md +27 -26
- data/etc/default_skills/pwn/ai/agent/tools/recon_run/SKILL.md +25 -15
- data/etc/default_skills/pwn/ai/agent/tools/workspace_tool/SKILL.md +24 -0
- data/etc/default_skills/pwn/ai/server_tools/SKILL.md +25 -0
- data/etc/default_skills/pwn/backups/SKILL.md +54 -0
- data/etc/default_skills/pwn/plugins/recon/SKILL.md +12 -1
- data/etc/default_skills/pwn/plugins/yubikey/SKILL.md +157 -0
- data/etc/default_skills/pwn/plugins/yubikey/fido/SKILL.md +189 -0
- data/etc/default_skills/pwn/plugins/yubikey/hsmauth/SKILL.md +83 -0
- data/etc/default_skills/pwn/plugins/yubikey/management/SKILL.md +80 -0
- data/etc/default_skills/pwn/plugins/yubikey/oath/SKILL.md +115 -0
- data/etc/default_skills/pwn/plugins/yubikey/openpgp/SKILL.md +144 -0
- data/etc/default_skills/pwn/plugins/yubikey/otp/SKILL.md +97 -0
- data/etc/default_skills/pwn/plugins/yubikey/piv/SKILL.md +110 -0
- data/etc/default_skills/pwn/plugins/yubikey/protocol/SKILL.md +21 -0
- data/etc/default_skills/pwn/plugins/yubikey/security_domain/SKILL.md +75 -0
- data/etc/default_skills/pwn/plugins/yubikey/security_domain/scp/SKILL.md +46 -0
- data/etc/default_skills/pwn/plugins/yubikey/transport/SKILL.md +98 -0
- data/etc/default_skills/pwn/redaction/SKILL.md +13 -1
- data/lib/pwn/ai/agent/dispatch.rb +26 -15
- data/lib/pwn/ai/agent/extrospection.rb +6 -7
- data/lib/pwn/ai/agent/learning.rb +62 -25
- data/lib/pwn/ai/agent/loop.rb +17 -1
- data/lib/pwn/ai/agent/mission_namespace.rb +331 -0
- data/lib/pwn/ai/agent/policy.rb +5 -0
- data/lib/pwn/ai/agent/policy_evaluation.rb +8 -8
- data/lib/pwn/ai/agent/prompt_builder.rb +13 -2
- data/lib/pwn/ai/agent/request_runtime.rb +122 -18
- data/lib/pwn/ai/agent/reward.rb +5 -3
- data/lib/pwn/ai/agent/skill_consolidation.rb +3 -2
- data/lib/pwn/ai/agent/skill_review.rb +9 -5
- data/lib/pwn/ai/agent/swarm.rb +35 -16
- data/lib/pwn/ai/agent/tools/browser_act.rb +32 -0
- data/lib/pwn/ai/agent/tools/loot_query.rb +11 -1
- data/lib/pwn/ai/agent/tools/recon_run.rb +11 -1
- data/lib/pwn/ai/agent/tools/workspace_tool.rb +29 -0
- data/lib/pwn/ai/agent/turn_finalizer.rb +6 -2
- data/lib/pwn/ai/agent.rb +1 -0
- data/lib/pwn/ai/anthropic.rb +8 -33
- data/lib/pwn/ai/cli.rb +34 -5
- data/lib/pwn/ai/gemini.rb +1 -0
- data/lib/pwn/ai/grok.rb +39 -28
- data/lib/pwn/ai/ollama.rb +4 -2
- data/lib/pwn/ai/open_ai.rb +11 -32
- data/lib/pwn/ai/open_web_ui.rb +62 -4
- data/lib/pwn/ai/router.rb +53 -3
- data/lib/pwn/ai/server_tools.rb +231 -0
- data/lib/pwn/ai.rb +1 -0
- data/lib/pwn/backups.rb +347 -0
- data/lib/pwn/config.rb +70 -39
- data/lib/pwn/cron.rb +120 -49
- data/lib/pwn/migrate.rb +150 -68
- data/lib/pwn/module_skills.rb +7 -0
- data/lib/pwn/plugins/ai_sandbox.rb +538 -1
- data/lib/pwn/plugins/authentication_helper.rb +74 -4
- data/lib/pwn/plugins/basic_auth.rb +2 -1
- data/lib/pwn/plugins/binary_parser.rb +5 -4
- data/lib/pwn/plugins/ghidra.rb +4 -3
- data/lib/pwn/plugins/google_workspace.rb +4 -21
- data/lib/pwn/plugins/jobs.rb +1 -1
- data/lib/pwn/plugins/log.rb +21 -3
- data/lib/pwn/plugins/preflight_checker.rb +34 -9
- data/lib/pwn/plugins/recon.rb +4 -1
- data/lib/pwn/plugins/repl/ai.rb +305 -27
- data/lib/pwn/plugins/repl/ai_console.rb +273 -89
- data/lib/pwn/plugins/repl/ai_swarm.rb +181 -62
- data/lib/pwn/plugins/repl/mesh.rb +3 -16
- data/lib/pwn/plugins/repl/vault.rb +4 -15
- data/lib/pwn/plugins/repl.rb +1 -216
- data/lib/pwn/plugins/sandbox/driver.rb +4 -0
- data/lib/pwn/plugins/transparent_browser.rb +215 -0
- data/lib/pwn/plugins/vault.rb +412 -135
- data/lib/pwn/plugins/yubikey/fido.rb +1288 -0
- data/lib/pwn/plugins/yubikey/hsmauth.rb +439 -0
- data/lib/pwn/plugins/yubikey/management.rb +686 -0
- data/lib/pwn/plugins/yubikey/oath.rb +766 -0
- data/lib/pwn/plugins/yubikey/openpgp.rb +1063 -0
- data/lib/pwn/plugins/yubikey/otp.rb +897 -0
- data/lib/pwn/plugins/yubikey/piv.rb +1315 -0
- data/lib/pwn/plugins/yubikey/protocol.rb +341 -0
- data/lib/pwn/plugins/yubikey/security_domain/scp.rb +482 -0
- data/lib/pwn/plugins/yubikey/security_domain.rb +464 -0
- data/lib/pwn/plugins/yubikey/transport.rb +1017 -0
- data/lib/pwn/plugins/yubikey.rb +844 -0
- data/lib/pwn/plugins.rb +1 -0
- data/lib/pwn/redaction.rb +69 -12
- data/lib/pwn/session_trace.rb +4 -0
- data/lib/pwn/sessions.rb +58 -16
- data/lib/pwn/setup.rb +123 -41
- data/lib/pwn/version.rb +1 -1
- data/lib/pwn/www/app_cobalt_io.rb +16 -5
- data/lib/pwn/www/bug_crowd.rb +16 -5
- data/lib/pwn/www/coinbase_pro.rb +16 -5
- data/lib/pwn/www/github.rb +30 -14
- data/lib/pwn/www/paypal.rb +15 -4
- data/lib/pwn/www/synack.rb +16 -5
- data/lib/pwn/www/twitter.rb +17 -6
- data/lib/pwn.rb +1 -0
- data/scripts/build_gate.rb +58 -0
- data/spec/documentation/installation_md_spec.rb +1 -1
- data/spec/fixtures/yubikey/apdu_frames.json +162 -0
- data/spec/integration/authentication_helper_oath_spec.rb +117 -0
- data/spec/integration/build_gate_spec.rb +73 -0
- data/spec/integration/controller_spill_spec.rb +48 -0
- data/spec/integration/harness_process_spec.rb +97 -0
- data/spec/integration/mission_cancel_spec.rb +79 -0
- data/spec/integration/mission_curses_pty_spec.rb +44 -0
- data/spec/integration/persistence_roundtrip_spec.rb +1 -7
- data/spec/integration/readme_security_spec.rb +47 -0
- data/spec/integration/web_cache_deception_yubikey_spec.rb +159 -0
- data/spec/lib/pwn/ai/agent/dispatch_spec.rb +6 -3
- data/spec/lib/pwn/ai/agent/dispatch_vault_safety_spec.rb +86 -0
- data/spec/lib/pwn/ai/agent/injection_guard_spec.rb +2 -0
- data/spec/lib/pwn/ai/agent/learning_spec.rb +4 -4
- data/spec/lib/pwn/ai/agent/loop_artifacts_spec.rb +5 -0
- data/spec/lib/pwn/ai/agent/loop_spec.rb +104 -29
- data/spec/lib/pwn/ai/agent/mission_namespace_spec.rb +138 -0
- data/spec/lib/pwn/ai/agent/policy_spec.rb +27 -0
- data/spec/lib/pwn/ai/agent/request_runtime_spec.rb +48 -0
- data/spec/lib/pwn/ai/agent/shell_search_effect_spec.rb +44 -0
- data/spec/lib/pwn/ai/agent/solve_spec.rb +6 -4
- data/spec/lib/pwn/ai/agent/tools/browser_act_spec.rb +44 -0
- data/spec/lib/pwn/ai/agent/tools/loot_query_yubikey_spec.rb +55 -0
- data/spec/lib/pwn/ai/agent/tools/recon_run_yubikey_spec.rb +43 -0
- data/spec/lib/pwn/ai/agent/tools/workspace_tool_spec.rb +20 -0
- data/spec/lib/pwn/ai/agent/turn_finalizer_spec.rb +7 -0
- data/spec/lib/pwn/ai/anthropic_vault_enrollment_spec.rb +37 -0
- data/spec/lib/pwn/ai/cli_spec.rb +6 -9
- data/spec/lib/pwn/ai/oauth_vault_persistence_spec.rb +195 -0
- data/spec/lib/pwn/ai/open_ai_spec.rb +2 -2
- data/spec/lib/pwn/ai/open_web_ui_workspace_spec.rb +36 -0
- data/spec/lib/pwn/ai/router_spec.rb +31 -3
- data/spec/lib/pwn/ai/server_tools_spec.rb +39 -0
- data/spec/lib/pwn/backups_spec.rb +114 -0
- data/spec/lib/pwn/config_redaction_yubikey_spec.rb +28 -0
- data/spec/lib/pwn/config_yubikey_spec.rb +92 -0
- data/spec/lib/pwn/cron_spec.rb +113 -6
- data/spec/lib/pwn/migrate_spec.rb +108 -5
- data/spec/lib/pwn/migrate_yubikey_spec.rb +128 -0
- data/spec/lib/pwn/module_skills_spec.rb +8 -0
- data/spec/lib/pwn/plugins/ai_sandbox_spec.rb +230 -0
- data/spec/lib/pwn/plugins/authentication_helper_native_yubikey_spec.rb +40 -0
- data/spec/lib/pwn/plugins/authentication_helper_yubikey_spec.rb +90 -0
- data/spec/lib/pwn/plugins/capability_broker/daemon_spec.rb +1 -1
- data/spec/lib/pwn/plugins/google_workspace_spec.rb +17 -35
- data/spec/lib/pwn/plugins/log_spec.rb +7 -0
- data/spec/lib/pwn/plugins/log_yubikey_spec.rb +47 -0
- data/spec/lib/pwn/plugins/preflight_checker_native_yubikey_spec.rb +19 -0
- data/spec/lib/pwn/plugins/preflight_checker_yubikey_spec.rb +55 -0
- data/spec/lib/pwn/plugins/recon_yubikey_spec.rb +43 -0
- data/spec/lib/pwn/plugins/repl/ai_console_spec.rb +125 -78
- data/spec/lib/pwn/plugins/repl/ai_legacy_containment_spec.rb +200 -0
- data/spec/lib/pwn/plugins/repl/ai_swarm_spec.rb +30 -16
- data/spec/lib/pwn/plugins/repl/ai_vault_edit_yubikey_spec.rb +103 -0
- data/spec/lib/pwn/plugins/repl/ai_yubikey_spec.rb +48 -0
- data/spec/lib/pwn/plugins/repl/mesh_vault_persistence_spec.rb +149 -0
- data/spec/lib/pwn/plugins/repl/vault_yaml_serialization_spec.rb +11 -0
- data/spec/lib/pwn/plugins/repl/vault_yubikey_spec.rb +39 -0
- data/spec/lib/pwn/plugins/repl_spec.rb +56 -5
- data/spec/lib/pwn/plugins/transparent_browser_jev_spec.rb +46 -0
- data/spec/lib/pwn/plugins/vault_native_yubikey_spec.rb +29 -0
- data/spec/lib/pwn/plugins/vault_publication_safety_spec.rb +258 -0
- data/spec/lib/pwn/plugins/vault_store_safety_spec.rb +241 -0
- data/spec/lib/pwn/plugins/vault_yubikey_safety_spec.rb +168 -0
- data/spec/lib/pwn/plugins/vault_yubikey_spec.rb +128 -0
- data/spec/lib/pwn/plugins/vault_yubikey_vector_spec.rb +45 -0
- data/spec/lib/pwn/plugins/yubikey/fido_spec.rb +854 -0
- data/spec/lib/pwn/plugins/yubikey/hsmauth_spec.rb +235 -0
- data/spec/lib/pwn/plugins/yubikey/management_spec.rb +277 -0
- data/spec/lib/pwn/plugins/yubikey/oath_spec.rb +349 -0
- data/spec/lib/pwn/plugins/yubikey/openpgp_spec.rb +810 -0
- data/spec/lib/pwn/plugins/yubikey/otp_spec.rb +337 -0
- data/spec/lib/pwn/plugins/yubikey/piv_spec.rb +646 -0
- data/spec/lib/pwn/plugins/yubikey/protocol_secure_spec.rb +28 -0
- data/spec/lib/pwn/plugins/yubikey/protocol_spec.rb +149 -0
- data/spec/lib/pwn/plugins/yubikey/protocol_vectors_spec.rb +18 -0
- data/spec/lib/pwn/plugins/yubikey/security_domain/scp_spec.rb +256 -0
- data/spec/lib/pwn/plugins/yubikey/security_domain/support.rb +153 -0
- data/spec/lib/pwn/plugins/yubikey/security_domain_spec.rb +296 -0
- data/spec/lib/pwn/plugins/yubikey/transport_spec.rb +760 -0
- data/spec/lib/pwn/plugins/yubikey_security_spec.rb +260 -0
- data/spec/lib/pwn/plugins/yubikey_spec.rb +209 -0
- data/spec/lib/pwn/plugins/yubikey_terminal_spec.rb +147 -0
- data/spec/lib/pwn/redaction_spec.rb +13 -10
- data/spec/lib/pwn/redaction_yubikey_spec.rb +61 -0
- data/spec/lib/pwn/session_cleanup_concurrency_spec.rb +201 -0
- data/spec/lib/pwn/session_cleanup_default_spec.rb +167 -2
- data/spec/lib/pwn/session_cleanup_legacy_spec.rb +101 -0
- data/spec/lib/pwn/session_cleanup_payload_spec.rb +335 -2
- data/spec/lib/pwn/session_cleanup_recovery_spec.rb +403 -0
- data/spec/lib/pwn/sessions_spec.rb +112 -0
- data/spec/lib/pwn/setup_native_yubikey_spec.rb +66 -0
- data/spec/lib/pwn/setup_spec.rb +3 -1
- data/spec/lib/pwn/setup_vault_yubikey_spec.rb +61 -0
- data/spec/lib/pwn/setup_yubikey_spec.rb +40 -0
- data/spec/lib/pwn/www/login_yubikey_spec.rb +273 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/gate_failure_formatter.rb +14 -0
- data/spec/support/harness/cli_faults.rb +13 -9
- data/spec/support/harness/controller_spill.rb +26 -0
- data/spec/support/harness/controller_state.rb +54 -0
- data/spec/support/harness/evaluate.rb +12 -1
- data/spec/support/harness/experiments.rb +1 -1
- data/spec/support/harness/fake_provider.rb +22 -6
- data/spec/support/harness/fault_preload.rb +3 -1
- data/spec/support/harness/mission_console.rb +54 -0
- data/spec/support/harness/mission_curses_pty.rb +41 -0
- data/spec/support/harness/mission_dispatch.rb +30 -0
- data/spec/support/harness/mission_fixture_preload.rb +24 -0
- data/spec/support/harness/mission_job_lifetime.rb +25 -0
- data/spec/support/harness/mission_legacy.rb +25 -0
- data/spec/support/harness/mission_normal_exit.rb +34 -0
- data/spec/support/harness/mission_swarm.rb +23 -0
- data/spec/support/harness/mission_unsupported.rb +29 -0
- data/spec/support/harness/package_acceptance.rb +33 -5
- data/spec/support/harness/session_acceptance.rb +4 -4
- data/spec/support/harness/swarm_acceptance.rb +1 -1
- data/spec/support/harness/swarm_control.rb +44 -0
- data/spec/support/mission_namespace.rb +14 -0
- data/spec/support/mission_pipe_queue.rb +33 -0
- data/third_party/pwn_rdoc.jsonl +599 -15
- metadata +140 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fef74967cd315acf1e070378d8e12000d552604b8d0f273d42638014d0a13a8c
|
|
4
|
+
data.tar.gz: 3d68aa5c28678b95a4b20acbe878a36c6d0cd8c04357ee3d18c768a7e0435c75
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0871b196e754cfe2134ba0372f4108b24113d9a1f7b0355257b31a032833c4b91bd1e52f53ff467a4e9e817375b9138b5691c15ef621c6026a34d32672f77d2b'
|
|
7
|
+
data.tar.gz: 2fef6064addee1ba16706d641f19af7a8bbf99432dfb1a13426fbd1d534d01b89d4a7f4dced9db9ad934d30db94dfcf908e88c993cb779424b706a0296db1cd2
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.0.
|
|
1
|
+
4.0.9
|
data/Gemfile
CHANGED
|
@@ -22,7 +22,7 @@ gem 'brakeman', '8.1.0'
|
|
|
22
22
|
gem 'bson', '5.2.0'
|
|
23
23
|
gem 'bundler', '>=4.0.23'
|
|
24
24
|
gem 'bundler-audit', '>=0.9.3'
|
|
25
|
-
gem 'bunny', '3.
|
|
25
|
+
gem 'bunny', '3.5.0'
|
|
26
26
|
gem 'colorize', '1.1.0'
|
|
27
27
|
gem 'credit_card_validations', '10.0.0'
|
|
28
28
|
gem 'curses', '1.7.0'
|
|
@@ -49,8 +49,8 @@ gem 'jwt', '3.3.0'
|
|
|
49
49
|
gem 'libusb', '0.8.0'
|
|
50
50
|
gem 'luhn', '3.0.0'
|
|
51
51
|
gem 'mail', '2.9.1'
|
|
52
|
-
gem 'mcp', '1.
|
|
53
|
-
gem 'meshtastic', '0.0.
|
|
52
|
+
gem 'mcp', '1.9.0'
|
|
53
|
+
gem 'meshtastic', '0.0.192'
|
|
54
54
|
gem 'metasm', '1.0.6'
|
|
55
55
|
gem 'mongo', '2.26.0'
|
|
56
56
|
gem 'msfrpc-client', '1.1.2'
|
|
@@ -59,7 +59,7 @@ gem 'net-ldap', '0.21.0'
|
|
|
59
59
|
gem 'net-openvpn', '0.8.7'
|
|
60
60
|
gem 'net-smtp', '0.5.2'
|
|
61
61
|
gem 'nexpose', '7.3.0'
|
|
62
|
-
gem 'nokogiri', '1.19.
|
|
62
|
+
gem 'nokogiri', '1.19.7'
|
|
63
63
|
gem 'nokogiri-diff', '0.3.0'
|
|
64
64
|
gem 'oily_png', '1.2.1'
|
|
65
65
|
gem 'open3', '0.3.0'
|
|
@@ -81,7 +81,7 @@ gem 'rmagick', '7.2.0'
|
|
|
81
81
|
gem 'rqrcode', '3.2.0'
|
|
82
82
|
gem 'rspec', '3.13.2'
|
|
83
83
|
gem 'rtesseract', '3.1.4'
|
|
84
|
-
gem 'rubocop', '1.92.
|
|
84
|
+
gem 'rubocop', '1.92.2'
|
|
85
85
|
gem 'rubocop-rake', '0.7.1'
|
|
86
86
|
gem 'rubocop-rspec', '3.10.2'
|
|
87
87
|
gem 'ruby-audio', '1.6.1'
|
|
@@ -89,12 +89,12 @@ gem 'ruby-nmap', '1.0.3'
|
|
|
89
89
|
gem 'ruby-saml', '1.18.1'
|
|
90
90
|
gem 'rvm', '1.11.3.9'
|
|
91
91
|
gem 'savon', '2.17.5'
|
|
92
|
-
gem 'selenium-devtools', '0.
|
|
93
|
-
gem 'selenium-webdriver', '4.
|
|
92
|
+
gem 'selenium-devtools', '0.156.0'
|
|
93
|
+
gem 'selenium-webdriver', '4.52.0'
|
|
94
94
|
gem 'slack-ruby-client', '3.3.0'
|
|
95
95
|
gem 'socksify', '1.8.1'
|
|
96
96
|
gem 'spreadsheet', '1.3.5'
|
|
97
|
-
gem 'sqlite3', '2.10.
|
|
97
|
+
gem 'sqlite3', '2.10.2'
|
|
98
98
|
gem 'thin', '2.0.1'
|
|
99
99
|
gem 'tty-prompt', '0.23.1'
|
|
100
100
|
gem 'tty-spinner', '0.9.3'
|
data/README.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
- [Intro](#intro)
|
|
10
10
|
* [What is PWN](#what-is-pwn)
|
|
11
11
|
* [Why PWN](#why-pwn)
|
|
12
|
+
* [Vault and Sandboxing](#vault-and-sandboxing)
|
|
12
13
|
* [How PWN Works](#how-pwn-works)
|
|
13
14
|
- [Documentation](#documentation)
|
|
14
15
|
- [Installation](#installation)
|
|
@@ -88,6 +89,42 @@ is driving security decisions without you watching every click.
|
|
|
88
89
|
|
|
89
90
|
Full page: [Why PWN](documentation/Why-PWN.md)
|
|
90
91
|
|
|
92
|
+
##### **Vault and Sandboxing** #####
|
|
93
|
+
|
|
94
|
+
Agentic security research, bug bounty hunting and penetration testing put
|
|
95
|
+
credentials, client evidence and untrusted target content in the same tool loop.
|
|
96
|
+
Vault and sandboxing reduce accidental secret persistence and limit local damage
|
|
97
|
+
from untrusted PoCs or target-supplied prompt injection:
|
|
98
|
+
|
|
99
|
+
- **Keep secrets separate from the conversation.** [Vault](lib/pwn/plugins/vault.rb)
|
|
100
|
+
encrypts configuration and captured credential values at rest. Use
|
|
101
|
+
`{{vault:label}}` references: [Dispatch](lib/pwn/ai/agent/dispatch.rb) resolves
|
|
102
|
+
them at the tool boundary and redacts known stored secrets from returned results.
|
|
103
|
+
Together with transcript/log redaction, this reduces copying raw secrets into
|
|
104
|
+
prompts, logs and reusable context. Store/query loot under explicit engagement
|
|
105
|
+
IDs with host/service/finding provenance. Use unique labels: reference expansion
|
|
106
|
+
can search across engagements, so these IDs are not credential access controls.
|
|
107
|
+
- **Contain tool effects, not just model instructions.** The
|
|
108
|
+
[mandatory runtime boundary](documentation/Runtime-Source-Protection.md) uses
|
|
109
|
+
Linux workers to separate tool writes from protected source and controller state;
|
|
110
|
+
[mission containment](documentation/Mission-Cancellation.md) owns their descendants.
|
|
111
|
+
Unnamed writes default to `~/.pwn/workspaces/runtime`. Other destinations must
|
|
112
|
+
come from the original operator request, not tool output; naming a file can
|
|
113
|
+
grant its parent directory. Protected source stays read-only even if named.
|
|
114
|
+
Missing required Landlock/seccomp or namespace support makes execution fail closed.
|
|
115
|
+
Optional `strict`/`permissive`/`off` profiles do not disable that mandatory boundary.
|
|
116
|
+
|
|
117
|
+
**Know the limits.** Encryption at rest does not protect secrets from an active
|
|
118
|
+
process that has unlocked them or promise LLM-provider privacy. Vault is not
|
|
119
|
+
whole-filesystem or evidence/artifact encryption, and redaction can miss secrets.
|
|
120
|
+
Sandboxing is not authorization, complete network isolation, a perfect container,
|
|
121
|
+
or a guarantee against bugs or prompt injection. Operators still need target
|
|
122
|
+
authorization and scope, least-privilege credentials, and separate evidence access,
|
|
123
|
+
retention and encryption controls.
|
|
124
|
+
|
|
125
|
+
Details: [Configuration](documentation/Configuration.md) ·
|
|
126
|
+
[Optional hardware-backed vaults and recovery](documentation/YubiKey-Vaults.md)
|
|
127
|
+
|
|
91
128
|
#### **How PWN Works** ####
|
|
92
129
|
|
|
93
130
|
PWN is five layers. Dependencies only point downward, so each level stays
|
data/Rakefile
CHANGED
|
@@ -5,12 +5,30 @@
|
|
|
5
5
|
exec('bundle', 'exec', 'rake', *ARGV) unless ENV['BUNDLE_BIN_PATH'] || ENV['RUBYOPT'].to_s.include?('bundler/setup')
|
|
6
6
|
|
|
7
7
|
require 'bundler/setup'
|
|
8
|
+
require 'English'
|
|
8
9
|
require 'bundler/gem_tasks'
|
|
9
10
|
require 'rspec/core/rake_task'
|
|
10
11
|
require 'rdoc/task'
|
|
11
12
|
require 'rubocop/rake_task'
|
|
12
13
|
|
|
13
|
-
RSpec
|
|
14
|
+
# RSpec's stock task maps a signalled child to exit 1 without naming the
|
|
15
|
+
# signal. Preserve that evidence when an interrupted run has no summary.
|
|
16
|
+
class DiagnosticSpecTask < RSpec::Core::RakeTask
|
|
17
|
+
def run_task(verbose)
|
|
18
|
+
super
|
|
19
|
+
rescue SystemExit
|
|
20
|
+
status = $CHILD_STATUS
|
|
21
|
+
if status
|
|
22
|
+
result = status.signaled? ? "signal=#{Signal.signame(status.termsig)}" : "exit=#{status.exitstatus}"
|
|
23
|
+
warn "RSpec child failed: #{result}"
|
|
24
|
+
end
|
|
25
|
+
raise
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
DiagnosticSpecTask.new(:spec) do |task|
|
|
30
|
+
task.rspec_opts = "#{task.rspec_opts} --require ./spec/support/gate_failure_formatter.rb --format progress --format GateFailureFormatter"
|
|
31
|
+
end
|
|
14
32
|
task :silence_rspec_filter_banner do
|
|
15
33
|
ENV['PWN_RAKE_SPEC'] = '1'
|
|
16
34
|
end
|
data/bin/pwn
CHANGED
|
@@ -81,7 +81,8 @@ begin
|
|
|
81
81
|
warn result.to_s[0, 700]
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
require 'pwn/plugins/repl/ai'
|
|
85
|
+
final = PWN::Plugins::REPL.pwn_ai_run_steerable(
|
|
85
86
|
request: prompt,
|
|
86
87
|
session_id: sess[:id],
|
|
87
88
|
enabled_toolsets: PWN::Env.dig(:ai, :agent, :toolsets),
|
data/bin/pwn_setup
CHANGED
|
@@ -58,7 +58,7 @@ pwn_driver = PWN::Driver::Parser.new do |options|
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
options.on('--[no-]cron',
|
|
61
|
-
'<Optional - Enable (default) or disable
|
|
61
|
+
'<Optional - Enable (default) or disable the built-in pwn-ai cron worker; no OS scheduler changes>') do |o|
|
|
62
62
|
opts[:cron] = o
|
|
63
63
|
end
|
|
64
64
|
end
|
data/bin/pwn_web_cache_deception
CHANGED
|
@@ -33,6 +33,18 @@ PWN::Driver::Parser.new do |options|
|
|
|
33
33
|
opts[:mfa] = f
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
options.on('--yubikey-account=NAME', '<Optional - Exact OATH account; supports GitHub, Synack, Twitter, BugCrowd, CoinbasePro, AppCobaltIO; Paypal SMS adapter unsupported; requires --yubikey-confirm; enables MFA even with --no-mfa; never an OTP slot>') do |name|
|
|
37
|
+
opts[:yubikey_account] = name
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
options.on('--yubikey-confirm', '<Required with --yubikey-account - Explicit OATH consent: HOTP advances counters; ykman may authenticate/delete remembered keys and delete corrupted OATH credentials>') do |confirm|
|
|
41
|
+
opts[:yubikey_confirm] = confirm
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
options.on('--yubikey-serial=SERIAL', '<Optional - Decimal YubiKey serial; requires --yubikey-account>') do |serial|
|
|
45
|
+
opts[:yubikey_serial] = serial
|
|
46
|
+
end
|
|
47
|
+
|
|
36
48
|
options.on('-pPROXY', '--proxy=PROXY', '<Optional - HTTP or Socks Proxy || tor>') do |p|
|
|
37
49
|
opts[:proxy] = p
|
|
38
50
|
end
|
|
@@ -60,6 +72,24 @@ pwn_www_mod_str = opts[:pwn_www_mod_str].to_s.scrub.strip.chomp
|
|
|
60
72
|
|
|
61
73
|
username = opts[:username].to_s.scrub.strip.chomp
|
|
62
74
|
|
|
75
|
+
yubikey = nil
|
|
76
|
+
raise ArgumentError, 'YubiKey serial requires --yubikey-account with an exact OATH account name' if opts[:yubikey_account].nil? && !opts[:yubikey_serial].nil?
|
|
77
|
+
raise ArgumentError, '--yubikey-confirm requires --yubikey-account with an exact OATH account name' if opts[:yubikey_account].nil? && !opts[:yubikey_confirm].nil?
|
|
78
|
+
|
|
79
|
+
unless opts[:yubikey_account].nil?
|
|
80
|
+
supported_oath_modules = %w[GitHub Synack Twitter BugCrowd CoinbasePro AppCobaltIO]
|
|
81
|
+
raise ArgumentError, "YubiKey OATH is supported only with --pwn-www-mod=#{supported_oath_modules.join('|')}; the Paypal adapter is SMS-only" unless supported_oath_modules.include?(pwn_www_mod_str)
|
|
82
|
+
|
|
83
|
+
yubikey = { account: opts[:yubikey_account], confirm: opts[:yubikey_confirm] }
|
|
84
|
+
unless opts[:yubikey_serial].nil?
|
|
85
|
+
serial = opts[:yubikey_serial]
|
|
86
|
+
raise ArgumentError, 'YubiKey serial must be a decimal string without whitespace' unless serial.is_a?(String) && serial.match?(/\A[0-9]+\z/)
|
|
87
|
+
|
|
88
|
+
yubikey[:serial] = serial
|
|
89
|
+
end
|
|
90
|
+
PWN::Plugins::AuthenticationHelper.validate_mfa_options(yubikey: yubikey, mfa: opts[:mfa], mfa_token: opts[:mfa_token])
|
|
91
|
+
end
|
|
92
|
+
|
|
63
93
|
password = opts[:password] # Don't cast to string to detect if PWN::Plugins::AuthenticationHelper is necessary
|
|
64
94
|
if password.nil?
|
|
65
95
|
password = PWN::Plugins::AuthenticationHelper.mask_password
|
|
@@ -67,11 +97,7 @@ else
|
|
|
67
97
|
password = opts[:password].to_s.scrub.strip.chomp
|
|
68
98
|
end
|
|
69
99
|
|
|
70
|
-
|
|
71
|
-
mfa = true
|
|
72
|
-
else
|
|
73
|
-
mfa = false
|
|
74
|
-
end
|
|
100
|
+
mfa = opts[:mfa] || false
|
|
75
101
|
|
|
76
102
|
proxy = opts[:proxy].to_s.scrub.strip.chomp unless opts[:proxy].nil?
|
|
77
103
|
|
|
@@ -151,12 +177,14 @@ begin
|
|
|
151
177
|
browser_obj = pwn_www_mod.open(browser_type: :chrome)
|
|
152
178
|
end
|
|
153
179
|
# Now AuthN via PWN::WWW::<MODULE>
|
|
154
|
-
|
|
180
|
+
login_opts = {
|
|
155
181
|
browser_obj: browser_obj,
|
|
156
182
|
username: username,
|
|
157
183
|
password: password,
|
|
158
184
|
mfa: mfa
|
|
159
|
-
|
|
185
|
+
}
|
|
186
|
+
login_opts[:yubikey] = yubikey unless yubikey.nil?
|
|
187
|
+
browser_obj = pwn_www_mod.login(login_opts)
|
|
160
188
|
puts "#{@green}complete.#{@end_of_color}\n\n\n"
|
|
161
189
|
elsif pwn_www_mod_str == '' && proxy
|
|
162
190
|
browser_obj = PWN::Plugins::TransparentBrowser.open(
|
data/build_gem.sh
CHANGED
|
@@ -44,7 +44,7 @@ if [[ $old_ruby_version == $new_ruby_version ]]; then
|
|
|
44
44
|
export rvmsudo_secure_path=1
|
|
45
45
|
rvmsudo /bin/bash --login -c "cd ${pwn_root} && ./reinstall_gemset.sh"
|
|
46
46
|
cd /tmp && cd "$pwn_root"
|
|
47
|
-
rvmsudo /bin/bash --login -c "cd ${pwn_root} && bundle exec rake"
|
|
47
|
+
ruby "${pwn_root}/scripts/build_gate.rb" rvmsudo /bin/bash --login -c "cd ${pwn_root} && bundle exec rake"
|
|
48
48
|
rvmsudo /bin/bash --login -c "cd ${pwn_root} && bundle exec rake install"
|
|
49
49
|
rvmsudo /bin/bash --login -c "cd ${pwn_root} && bundle exec rake rerdoc"
|
|
50
50
|
echo "Invoking bundle-audit Gemfile Scanner..."
|
|
@@ -15,7 +15,7 @@ agent code never cares which model is behind it.
|
|
|
15
15
|
| `grok` | `PWN::AI::Grok` | `key:` **or** `oauth: true` | OAuth = RFC-8628 device-code flow using xAI's public Grok-CLI client id (no secret) - see skill `xai_grok_oauth_device_flow` |
|
|
16
16
|
| `gemini` | `PWN::AI::Gemini` | `key:` | function-calling native |
|
|
17
17
|
| `ollama` | `PWN::AI::Ollama` | none (stock) | Direct Ollama server (default `http://127.0.0.1:11434`). Native `/api/chat` (`num_ctx`, `num_predict`, `keep_alive`, low `tool_temp`) and `/api/embed` for `PWN::MemoryIndex`. No prefix-cache field. |
|
|
18
|
-
| `openwebui` | `PWN::AI::OpenWebUI` | `key:` (JWT / API token) + `base_uri:` | Open WebUI gateway - OpenAI-compatible `/api/v1/chat/completions` plus proxied Ollama `/ollama/api
|
|
18
|
+
| `openwebui` | `PWN::AI::OpenWebUI` | `key:` (JWT / API token) + `base_uri:` | Open WebUI gateway - OpenAI-compatible `/api/v1/chat/completions` plus proxied Ollama `/ollama/api/*`. Workspace tools such as Ask Jev run server-side through `tool_ids` on `chat` / `workspace_tool`. A client `tools` array on that same request disables them. |
|
|
19
19
|
|
|
20
20
|
> PWN is **model-agnostic**. `ai.<engine>.model` is passed straight through to
|
|
21
21
|
choose a provider-supported model ID (or a tag from `ollama list`).
|
|
@@ -56,12 +56,14 @@ The trailing `nil` prevents the console from echoing the returned bearer.
|
|
|
56
56
|
Successful enrollment updates the live environment and calls the private
|
|
57
57
|
`persist_oauth_to_vault` helper, as token refresh does. It uses the configured
|
|
58
58
|
`driver_opts.pwn_env_path` and `pwn_dec_path`, defaulting to
|
|
59
|
-
`~/.pwn/pwn.yaml` and its `.decryptor` file.
|
|
60
|
-
|
|
59
|
+
`~/.pwn/pwn.yaml` and its legacy `.decryptor` file. A [YubiKey vault](YubiKey-Vaults.md)
|
|
60
|
+
uses its hardware selector instead and does not need a software sidecar.
|
|
61
|
+
Unavailable credentials or hardware leave tokens in the session only and produce a
|
|
61
62
|
notice. Tokens are not printed by the enrollment success message.
|
|
62
63
|
|
|
63
|
-
Persistence retains unrelated settings and the
|
|
64
|
-
|
|
64
|
+
Persistence retains unrelated settings and the encryption backend, decrypts and
|
|
65
|
+
merges in memory, writes only ciphertext to a private temporary file, and
|
|
66
|
+
replaces the vault only after encryption succeeds.
|
|
65
67
|
The resulting vault has mode `0600`. The original vault remains unchanged on
|
|
66
68
|
a persistence failure; the helper does not create or rotate decryptor secrets.
|
|
67
69
|
|
|
@@ -6,13 +6,13 @@ toolsets; the JSON-Schema for each tool is what the model actually sees.
|
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
9
|
-
## Toolsets to tools (16 toolsets ·
|
|
9
|
+
## Toolsets to tools (16 toolsets · 152 tools)
|
|
10
10
|
|
|
11
11
|
| Toolset | Tools | Backed by |
|
|
12
12
|
|---|---|---|
|
|
13
13
|
| `http` | `http_proxy_start` · `http_proxy_stop` · `http_proxy_entries` · `http_proxy_rules` · `http_replay` | `PWN::Plugins::MitmProxy`: native HTTP HAR capture/replay; opaque CONNECT tunnels |
|
|
14
14
|
| `terminal` | `pty_expect` · `job_run` · `job_status` · `job_result` · `job_tail` · `job_kill` · `pty_open` · `pty_send` · `pty_read` · `pty_close` · `pty_session` · `shell` | Foreground host commands plus `PWN::Plugins::Jobs` durable supervisors |
|
|
15
|
-
| `pwn` | `binary_triage` · `browser_goto` · `capabilities` · `debug_session` · `gdb_run_to_crash` · `binary_diff` · `crash_triage` · `emulate` · `detonate` · `decompile` · `exploitdev` · `finding_record` · `finding_report` · `chain_score` · `fuzz_campaign` · `intel_lookup` · `loot_query` · `nmap_scan` · `nuclei_scan` · `r2_functions` · `r2_disasm` · `recon_run` · `pwn_eval` · `sandbox_run` · `sandbox_fuzz` · `sbom_scan` · `swarm_map` | `TOPLEVEL_BINDING.eval` in the live REPL process, after `ToolGuard`; SBOM engines via `PWN::Plugins::SBOM` store CVE leads as recon observations, not findings; r2pipe JSON via `PWN::Plugins::Radare2`; gdb MI3 crash reports via `PWN::Plugins::GDBMI`; nmap XML ingest/diff via `PWN::Plugins::NmapIt`, which skips a known port unless `refresh: true`; nuclei/httpx JSONL via `PWN::Plugins::Nuclei` writes a recon observation (a template match is not a finding) and accepts a `Recon.handoff` record; TransparentBrowser navigation captures screenshot/DOM/HAR via `browser_goto`; engagement loot via `PWN::Plugins::Vault` |
|
|
15
|
+
| `pwn` | `binary_triage` · `browser_goto` · `browser_act` · `workspace_tool` · `capabilities` · `debug_session` · `gdb_run_to_crash` · `binary_diff` · `crash_triage` · `emulate` · `detonate` · `decompile` · `exploitdev` · `finding_record` · `finding_report` · `chain_score` · `fuzz_campaign` · `intel_lookup` · `loot_query` · `nmap_scan` · `nuclei_scan` · `r2_functions` · `r2_disasm` · `recon_run` · `pwn_eval` · `sandbox_run` · `sandbox_fuzz` · `sbom_scan` · `swarm_map` | `TOPLEVEL_BINDING.eval` in the live REPL process, after `ToolGuard`; SBOM engines via `PWN::Plugins::SBOM` store CVE leads as recon observations, not findings; r2pipe JSON via `PWN::Plugins::Radare2`; gdb MI3 crash reports via `PWN::Plugins::GDBMI`; nmap XML ingest/diff via `PWN::Plugins::NmapIt`, which skips a known port unless `refresh: true`; nuclei/httpx JSONL via `PWN::Plugins::Nuclei` writes a recon observation (a template match is not a finding) and accepts a `Recon.handoff` record; TransparentBrowser navigation captures screenshot/DOM/HAR via `browser_goto`; engagement loot via `PWN::Plugins::Vault` |
|
|
16
16
|
| `mcp` | `mcp` | `PWN::AI::MCP` session broker → any `PWN::AI::MCP::*` stdio client |
|
|
17
17
|
| `memory` | `memory_remember` · `memory_recall` · `memory_forget` · `memory_clear` · `memory_lean` | `PWN::Memory` → `~/.pwn/memory.json` |
|
|
18
18
|
| `skills` | `skills_recall` · `skills_update` · `skill_list` · `skill_view` · `skill_create` · `skills_create` · `skill_add_reference` · `skill_delete` · `skill_migrate_legacy` · `skills_consolidate` | `~/.pwn/skills/<name>/SKILL.md` (**[agentskills.io](https://agentskills.io) spec**; legacy flat `*.md` auto-migrated) |
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Shared recovery backup retention
|
|
2
|
+
|
|
3
|
+
All PWN-owned recovery producers use `PWN::Backups` and the single
|
|
4
|
+
`~/.pwn/backup` store. The limit is **seven total generation folders**, not seven
|
|
5
|
+
per producer. Producer payloads and recovery receipts are grouped inside their
|
|
6
|
+
transaction's generation. No new adjacent learning, preference, skill or
|
|
7
|
+
Terminator `.bak` / `.pwnbak` files are produced.
|
|
8
|
+
|
|
9
|
+
## Producers
|
|
10
|
+
|
|
11
|
+
| Producer | Contents |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| Migrate | Exact registry-owned state paths, encrypted configuration and decryptor; verified snapshot manifest; no recursive logs/cache/backup copies |
|
|
14
|
+
| Learning | Learning rewrites and original evidence-migration index |
|
|
15
|
+
| Reward | Preference rewrite recovery |
|
|
16
|
+
| SkillReview / SkillConsolidation | Original skill bytes |
|
|
17
|
+
| PolicyEvaluation | Pinned routing-policy rollback snapshot |
|
|
18
|
+
| Setup | Original Terminator configuration |
|
|
19
|
+
| SessionCleanup | Session/layout recovery, dependency removal, continuation retirement and disposable quarantine payloads with their recovery receipts |
|
|
20
|
+
|
|
21
|
+
Immutable learning evidence, artifacts, evaluation inputs and user-requested
|
|
22
|
+
exports are not disposable backup generations. Device read/write backup commands,
|
|
23
|
+
GitHub gist exports and Jenkins-to-S3 transfer operate on operator-selected data,
|
|
24
|
+
not PWN's internal recovery state.
|
|
25
|
+
|
|
26
|
+
## Admission, locking and failures
|
|
27
|
+
|
|
28
|
+
The permanent `.retention.lock` serializes cooperating producers. Maintenance
|
|
29
|
+
acquires its maintenance lock, then the Learning writer lock, then the backup
|
|
30
|
+
lock. Ordinary backup producers acquire Learning before backups and never acquire
|
|
31
|
+
maintenance. Learning reentrancy is bound to the owning PID and thread; an
|
|
32
|
+
attempt to acquire Learning underneath an unowned backup transaction is rejected.
|
|
33
|
+
Maintenance still defers when the Learning writer is busy.
|
|
34
|
+
|
|
35
|
+
Before a new folder is admitted, oldest completed, unpinned generations may be
|
|
36
|
+
expired to make room. Prepared/interrupted generations, explicit pins and current
|
|
37
|
+
literal evidence references remain protected. Malformed reference data fails
|
|
38
|
+
closed when expiry would be needed. Pins count **inside** the seven-folder limit:
|
|
39
|
+
if they occupy capacity, the next producer fails before modifying its source.
|
|
40
|
+
Unknown legacy folders count toward capacity but are not silently certified or
|
|
41
|
+
expired. A pre-existing over-limit store can therefore block admission until an
|
|
42
|
+
explicit offline remediation is performed; importing this source does not fix a
|
|
43
|
+
live store or grant permission to prune it.
|
|
44
|
+
|
|
45
|
+
Transactions publish `prepared` before payload/source changes and `complete`
|
|
46
|
+
only after successful return. Exceptions, interrupted/blocked results and failed
|
|
47
|
+
receipts leave prepared recovery. Copies are hash-verified and fsynced. Keep the
|
|
48
|
+
transaction open through source mutation and receipt publication. Restoring one
|
|
49
|
+
store does not undo all children of a maintenance operation.
|
|
50
|
+
|
|
51
|
+
Use the owning store's recovery API (`SessionCleanup.recover`,
|
|
52
|
+
`Learning.rollback_evidence`, skill review rollback or policy rollback) first.
|
|
53
|
+
`Backups.reconcile` only acknowledges recovery: it requires the exact generation,
|
|
54
|
+
its inspected manifest SHA-256 and explicit confirmation. It retains a pin by
|
|
55
|
+
default; `pinned: false` permits normal retention but does not override live
|
|
56
|
+
references. It does not restore payloads or declare a failed operation successful.
|
|
57
|
+
Never edit shared/hardlinked historical payloads in place; restore by copying.
|
|
58
|
+
|
|
59
|
+
## Upgrade and legacy relocation
|
|
60
|
+
|
|
61
|
+
Schema 12 changes the existing retention policy from three to seven, preserving
|
|
62
|
+
pins and other policy fields. A second migration is byte-stable. The old
|
|
63
|
+
`Migrate.prune_backups` entry point is a compatibility report only; it cannot run
|
|
64
|
+
an independent three-generation pruning policy. Retention happens at producer
|
|
65
|
+
admission, not via another scheduler.
|
|
66
|
+
|
|
67
|
+
`Backups.relocate_legacy(paths: ..., dry_run: true)` previews exact recognized
|
|
68
|
+
legacy paths. Applying requires `dry_run: false, writers_stopped: true`, owned
|
|
69
|
+
non-symlink sources, unchanged verified copies and no references to their old
|
|
70
|
+
paths. The shared generation contains an origin mapping before originals are
|
|
71
|
+
removed. Unknown, referenced or over-capacity inputs must be resolved explicitly,
|
|
72
|
+
not bypassed. Existing cleanup recovery readers remain available for legacy
|
|
73
|
+
ledgers. Legacy diagnostic/cache expiry is a separate explicit operation and is
|
|
74
|
+
not a new backup producer.
|
|
75
|
+
|
|
76
|
+
## Deployment boundary
|
|
77
|
+
|
|
78
|
+
Source changes do not upgrade installed gems, existing clients or immutable cron
|
|
79
|
+
releases. Deploy a matched release and restart only explicitly authorized
|
|
80
|
+
processes separately. Use only PWN's existing internal cron worker; no systemd,
|
|
81
|
+
native scheduler, live provider calls or live backup pruning is required for
|
|
82
|
+
fixture verification. Tests must use an isolated HOME and scratch storage.
|
|
@@ -5,18 +5,22 @@ Provider and plugin configuration lives in **one encrypted YAML file**, loaded b
|
|
|
5
5
|
constant **`PWN::Env`** (whose nested settings are mutable) (a redacted copy is available as
|
|
6
6
|
`PWN::EnvRedacted`).
|
|
7
7
|
|
|
8
|
-
The file is **AES-encrypted at rest** by `PWN::Plugins::Vault`.
|
|
9
|
-
live in a sibling **`~/.pwn/pwn.yaml.decryptor`** file (or in
|
|
10
|
-
`PWN_DECRYPTOR_KEY` / `PWN_DECRYPTOR_IV` env vars).
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
The file is **AES-encrypted at rest** by `PWN::Plugins::Vault`. Legacy CBC key/IV
|
|
9
|
+
values live in a sibling **`~/.pwn/pwn.yaml.decryptor`** file (or in
|
|
10
|
+
`PWN_DECRYPTOR_KEY` / `PWN_DECRYPTOR_IV` env vars). Explicitly selected
|
|
11
|
+
[YubiKey vaults](YubiKey-Vaults.md) instead use an authenticated hardware-derived
|
|
12
|
+
AES-GCM envelope and need no software decryptor. Never edit ciphertext by hand;
|
|
13
|
+
use the **`pwn-vault`** REPL command, which edits a private temporary copy,
|
|
14
|
+
re-encrypts before replacing the original, and reloads `PWN::Env`. If `PWN::Config` rejects the
|
|
13
15
|
edited file, the editor reopens until the vault loads cleanly, so you do not
|
|
14
16
|
leave the REPL stuck on a decrypt / re-edit / encrypt loop.
|
|
15
17
|
|
|
16
18
|
If `~/.pwn/pwn.yaml` does not exist on first run, `PWN::Config.default_env`
|
|
17
19
|
writes a fully-commented template with every key below (values set to
|
|
18
20
|
`'optional - ...'` / `'required - ...'` placeholder strings), encrypts it, and
|
|
19
|
-
generates the decryptor.
|
|
21
|
+
generates the legacy decryptor. `default_env(yubikey: { slot: 2 })` explicitly
|
|
22
|
+
selects hardware protection for a new vault and omits that sidecar; it does not
|
|
23
|
+
provision the device slot or silently convert an existing file.
|
|
20
24
|
|
|
21
25
|
> **Before configuring**, run `pwn setup` - the
|
|
22
26
|
> [doctor](Installation.md#pwn-setup--the-post-install-doctor--provisioner)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
lib/pwn/ # all namespaces
|
|
7
7
|
lib/pwn/setup.rb # PWN::Setup - doctor/provisioner data tables
|
|
8
8
|
lib/pwn/migrate.rb # PWN::Migrate - ~/.pwn state doctor / auto-migrator
|
|
9
|
-
lib/pwn/plugins/ #
|
|
9
|
+
lib/pwn/plugins/ # 108 top-level plugin autoloads
|
|
10
10
|
lib/pwn/ai/agent/ # agent core
|
|
11
11
|
lib/pwn/ai/agent/tools/ # LLM tool registrations
|
|
12
12
|
bin/ # 56 executables: 53 pwn_* drivers + pwn / pwn-ai / pwn-capd (incl. pwn_setup)
|
data/documentation/Cron.md
CHANGED
|
@@ -2,17 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
`PWN::Cron` (`lib/pwn/cron.rb`) stores job definitions in
|
|
4
4
|
`~/.pwn/cron/jobs.yml`. `pwn setup` starts (or reuses) a background cron
|
|
5
|
-
worker
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
worker. Setup, migration and startup only seed internal job definitions;
|
|
6
|
+
they never install, start, repair or remove native scheduler units. After a
|
|
7
|
+
reboot, start/reuse the portable worker with `pwn setup --cron`; automatic
|
|
8
|
+
jobs require that worker, while manual commands do not. `--no-cron` disables
|
|
9
|
+
the internal worker without changing host services.
|
|
10
|
+
|
|
11
|
+
**Housekeeping must never use systemd or another native scheduler.**
|
|
12
|
+
The one enabled housekeeping default, `session_cleanup`, uses only this existing
|
|
13
|
+
worker or a manual command. `install_native_job` and each platform-specific job
|
|
14
|
+
installer explicitly skip housekeeping (`housekeeping_internal_only`),
|
|
15
|
+
including recognizable cleanup payloads under another name. Native worker
|
|
16
|
+
contexts exclude housekeeping from ticks and direct job execution.
|
|
17
|
+
|
|
18
|
+
Generic scheduler APIs remain for unrelated custom jobs: `install_crontab:
|
|
19
|
+
true` can still add their per-job system lines. They are not called by setup,
|
|
20
|
+
migration or default seeding. Existing housekeeping units/drop-ins are left
|
|
21
|
+
untouched and require explicit operator approval for removal; they are never
|
|
22
|
+
re-enabled automatically. See [Installation](Installation.md) for the legacy
|
|
23
|
+
service migration boundary. Do not create another worker or run cleanup just
|
|
24
|
+
to validate scheduling.
|
|
16
25
|
|
|
17
26
|

|
|
18
27
|
|
|
@@ -34,33 +43,53 @@ does not remove existing per-job lines.
|
|
|
34
43
|
| `cron_enable` / `cron_disable` | Toggle without deleting |
|
|
35
44
|
| `cron_remove` | Delete from `jobs.yml` (does **not** scrub crontab - `crontab -e` yourself) |
|
|
36
45
|
|
|
37
|
-
##
|
|
38
|
-
|
|
39
|
-
`
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
## Default housekeeping and explicit curriculum opt-in
|
|
47
|
+
|
|
48
|
+
`PWN::Cron.install_defaults` seeds **one** enabled job on a fresh install:
|
|
49
|
+
`session_cleanup`, daily at `45 3 * * *`, guarded until its first scheduled slot.
|
|
50
|
+
It calls `SessionCleanup.coordinate` through the existing internal worker:
|
|
51
|
+
|
|
52
|
+
1. Shared maintenance: preflight, evidence migration, protected-session cleanup,
|
|
53
|
+
and disposable storage maintenance.
|
|
54
|
+
2. Memory consolidation (`Learning.consolidate`, including Memory lean).
|
|
55
|
+
3. Learning outcome retention (`Learning.prune_outcomes!`).
|
|
56
|
+
4. Mistakes retention (`Mistakes.lean!`).
|
|
57
|
+
5. Policy trajectory retention (`Policy.lean!`).
|
|
58
|
+
|
|
59
|
+
The coordinator holds the permanent maintenance lock across these phases and
|
|
60
|
+
records their separate results. Blocked/incomplete maintenance skips retention;
|
|
61
|
+
dry-run does not consolidate memory or mutate stores. Store writer locks and
|
|
62
|
+
existing gold/recent/protected-entry policies remain in force. It does not call
|
|
63
|
+
`gc_stores!`, which would repeat memory consolidation and session cleanup.
|
|
64
|
+
|
|
65
|
+
Existing jobs are preserved verbatim, including disabled/custom schedules and
|
|
66
|
+
legacy curriculum aliases. Existing `learning_consolidate_nightly` and
|
|
67
|
+
`pwn_stores_lean_nightly` are **not** removed automatically. If either exists
|
|
68
|
+
when a missing session job is seeded, that job uses maintenance-only payloads
|
|
69
|
+
rather than duplicate retention. Consolidate those live schedules only after
|
|
70
|
+
all writers and the matched helper have been safely upgraded and tested.
|
|
71
|
+
|
|
72
|
+
Curriculum schedules are **not seeded at all**, including after deletion,
|
|
73
|
+
startup, or repeat migration. `CURRICULUM_JOBS` contains optional templates for
|
|
74
|
+
`curriculum_practice_nightly`, `curriculum_train_weekly`, and
|
|
75
|
+
`curriculum_offline_judge`. Explicitly create a selected template only when
|
|
76
|
+
wanted; templates default disabled:
|
|
50
77
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- **offline_judge** - backfill outcome/process labels + plan calibration from PLAN `p(success)=` so `:failure_only` local introspect does not starve the corpus; also runs `Reward.warm_sentinel` so the reward-sentinel window can fill on local hosts
|
|
56
|
-
- **dedupe** - legacy alias `offline_judge_nightly` counts as the same job; `install_defaults` will not double-seed `30 3 * * *` and disables the alias when both exist
|
|
57
|
-
- **train** - export SFT + balanced DPO, LoRA-train `pwn-vN+1`, replay Mistakes.top, promote only on win. `dry_run: false` only with a trainer+GPU
|
|
58
|
-
- **consolidate** - memory GC (semantic merge + importance eviction) so the injected MEMORY block stays high-signal
|
|
78
|
+
```ruby
|
|
79
|
+
spec = PWN::Cron::CURRICULUM_JOBS.find { |job| job[:name] == 'curriculum_practice_nightly' }
|
|
80
|
+
PWN::Cron.create(spec.merge(enabled: false, sync_native: false))
|
|
81
|
+
```
|
|
59
82
|
|
|
60
|
-
|
|
83
|
+
Practice runs real tools, judge can spend provider tokens, and training needs
|
|
84
|
+
its own explicit configuration/approval. See [Reinforcement Learning](Reinforcement-Learning.md).
|
|
61
85
|
|
|
62
|
-
|
|
63
|
-
|
|
86
|
+
For schedule-only deletion without touching native schedulers, use
|
|
87
|
+
`PWN::Cron.remove(id: exact_id, sync_native: false)`. It preserves job logs and
|
|
88
|
+
other evidence. Registry writes use a permanent lock and atomic replacement;
|
|
89
|
+
completion updates merge into the current registry and never resurrect a deleted
|
|
90
|
+
job. Old workers without this protocol must drain safely before a registry edit;
|
|
91
|
+
never use a forced stop while a job is writing. A current worker reloads the
|
|
92
|
+
registry each tick; ordinary schedule changes need no restart.
|
|
64
93
|
|
|
65
94
|
## Example
|
|
66
95
|
|
data/documentation/Diagrams.md
CHANGED
|
@@ -24,7 +24,7 @@ a dependency guarantee. External services/radios require separate live verificat
|
|
|
24
24
|
[source](diagrams/dot/persistence-filesystem.dot) · doc: [Persistence](Persistence.md)
|
|
25
25
|

|
|
26
26
|
|
|
27
|
-
### Plugin Ecosystem (
|
|
27
|
+
### Plugin Ecosystem (108 modules)
|
|
28
28
|
[source](diagrams/dot/plugin-ecosystem.dot) · doc: [Plugins](Plugins.md)
|
|
29
29
|

|
|
30
30
|
|
|
@@ -69,7 +69,7 @@ a dependency guarantee. External services/radios require separate live verificat
|
|
|
69
69
|
[source](diagrams/dot/ai-integration-tool-calling.dot) · doc: [AI Integration](AI-Integration.md)
|
|
70
70
|

|
|
71
71
|
|
|
72
|
-
### Agent Tool Registry (16 toolsets ·
|
|
72
|
+
### Agent Tool Registry (16 toolsets · 152 tools)
|
|
73
73
|
[source](diagrams/dot/agent-tool-registry.dot) · doc: [Agent Tool Registry](Agent-Tool-Registry.md)
|
|
74
74
|

|
|
75
75
|
|
|
@@ -18,13 +18,14 @@ $ pwn setup --migrate --fix # after `gem update pwn`: verify + autofix ~/.pwn
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
See [Installation](Installation.md) for every flag and the
|
|
21
|
-
`PWN::Setup` / `PWN::Migrate` API.
|
|
21
|
+
`PWN::Setup` / `PWN::Migrate` API. Unspecified `pwn-ai` writes use
|
|
22
|
+
`~/.pwn/workspaces/runtime`; see [Operability](Operability.md).
|
|
22
23
|
|
|
23
24
|
## Inside the REPL
|
|
24
25
|
|
|
25
26
|
```ruby
|
|
26
27
|
PWN.help # top-level help
|
|
27
|
-
PWN::Plugins.constants.sort # list all
|
|
28
|
+
PWN::Plugins.constants.sort # list all 108 plugins
|
|
28
29
|
PWN::Plugins::NmapIt.help # per-plugin usage
|
|
29
30
|
PWN::Setup.check # capability doctor from inside the REPL
|
|
30
31
|
PWN::Migrate.status # ~/.pwn state-file compatibility rows
|
|
@@ -40,7 +41,7 @@ history # what you've typed → copy into a driver
|
|
|
40
41
|
| `pwn-ai` | Enter the agent TUI (SHIFT+ENTER = newline, ENTER = submit) |
|
|
41
42
|
| `pwn-asm` | Multi-line assembly ↔ opcode workbench |
|
|
42
43
|
| `pwn-mesh` | Meshtastic serial / bluetooth / TCP / MQTT client (Ruby ≥ 4.0) |
|
|
43
|
-
| `pwn-vault` |
|
|
44
|
+
| `pwn-vault` | Edit a private temporary copy, then replace `~/.pwn/pwn.yaml` only after encryption succeeds (legacy or YubiKey) |
|
|
44
45
|
| `pwn-ai-memory` | Inspect / edit `~/.pwn/memory.json` |
|
|
45
46
|
| `pwn-ai-sessions` | List / view / delete transcripts |
|
|
46
47
|
| `pwn-ai-cron` | List / run scheduled jobs |
|