pwn 0.5.784 → 0.5.787
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 +6 -6
- data/README.md +37 -0
- data/bin/pwn +2 -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 +69 -15
- data/documentation/Configuration.md +10 -6
- data/documentation/Contributing.md +1 -1
- data/documentation/Cron.md +2 -2
- data/documentation/Diagrams.md +2 -2
- data/documentation/General-PWN-Usage.md +4 -3
- data/documentation/Harness-Evaluation.md +1 -1
- data/documentation/Home.md +6 -5
- data/documentation/How-PWN-Works.md +6 -5
- data/documentation/Installation.md +12 -9
- data/documentation/Mission-Cancellation.md +134 -0
- data/documentation/Operability.md +18 -0
- data/documentation/Persistence.md +7 -5
- data/documentation/Plugin-Degradation.md +14 -0
- data/documentation/Plugins.md +3 -2
- data/documentation/Policy-Benchmark.md +32 -33
- 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 +185 -0
- data/documentation/YubiKey.md +218 -0
- data/documentation/diagrams/cron-scheduling.svg +130 -130
- data/documentation/diagrams/dot/cron-scheduling.dot +3 -3
- data/documentation/diagrams/dot/persistence-filesystem.dot +5 -3
- data/documentation/diagrams/dot/plugin-ecosystem.dot +2 -2
- data/documentation/diagrams/dot/pwn-ai-feedback-learning-loop.dot +1 -1
- data/documentation/diagrams/dot/reinforcement-learning.dot +2 -2
- data/documentation/diagrams/persistence-filesystem.svg +172 -142
- data/documentation/diagrams/plugin-ecosystem.svg +64 -64
- data/documentation/diagrams/pwn-ai-feedback-learning-loop.svg +1 -1
- data/documentation/diagrams/reinforcement-learning.svg +89 -89
- data/documentation/pwn-ai-Agent.md +10 -4
- data/etc/default_cron/session_cleanup.rb +43 -27
- 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/learning.rb +14 -18
- 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_evaluation.rb +334 -36
- 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 +4 -0
- 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 +8 -1
- data/lib/pwn/ai/server_tools.rb +231 -0
- data/lib/pwn/ai.rb +1 -0
- data/lib/pwn/backups.rb +349 -0
- data/lib/pwn/config.rb +70 -39
- data/lib/pwn/migrate.rb +85 -280
- 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/google_workspace.rb +4 -21
- data/lib/pwn/plugins/jobs.rb +1 -1
- data/lib/pwn/plugins/log.rb +3 -1
- data/lib/pwn/plugins/preflight_checker.rb +34 -9
- data/lib/pwn/plugins/recon.rb +4 -1
- data/lib/pwn/plugins/repl/ai.rb +293 -26
- data/lib/pwn/plugins/repl/ai_console.rb +268 -88
- data/lib/pwn/plugins/repl/ai_swarm.rb +177 -58
- data/lib/pwn/plugins/repl/mesh.rb +14 -19
- data/lib/pwn/plugins/repl/vault.rb +4 -15
- data/lib/pwn/plugins/repl.rb +9 -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/setup.rb +114 -24
- 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/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/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/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_evaluation_spec.rb +10 -23
- 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 +8 -16
- 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 +1 -1
- data/spec/lib/pwn/ai/server_tools_spec.rb +39 -0
- data/spec/lib/pwn/backups_spec.rb +129 -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/migrate_spec.rb +29 -81
- 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_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 +110 -75
- data/spec/lib/pwn/plugins/repl/ai_legacy_containment_spec.rb +200 -0
- data/spec/lib/pwn/plugins/repl/ai_swarm_spec.rb +19 -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_mesh_layout_spec.rb +2 -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_yubikey_spec.rb +61 -0
- data/spec/lib/pwn/session_cleanup_default_spec.rb +7 -5
- data/spec/lib/pwn/session_cleanup_payload_spec.rb +11 -11
- data/spec/lib/pwn/session_cleanup_recovery_spec.rb +34 -20
- data/spec/lib/pwn/setup_native_yubikey_spec.rb +66 -0
- 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/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 +605 -19
- metadata +129 -16
- data/scripts/benchmark_policy.rb +0 -376
- data/scripts/build_gate.rb +0 -58
- data/spec/integration/build_gate_spec.rb +0 -73
|
@@ -34,7 +34,7 @@ anchors:
|
|
|
34
34
|
| state | `swarm/`, `cron/`, `agents.yml`, `jobs/`, `missions/`, `runs/`, metrics | Preserve continuation associations and active work |
|
|
35
35
|
| logs | `logs/` | Only explicitly registered disposable closed logs are eligible; unknown logs remain |
|
|
36
36
|
| cache | `cache/` | Only producer-registered, checksum-verified, inactive disposable files |
|
|
37
|
-
| tmp | `
|
|
37
|
+
| tmp | `workspaces/runtime/` | Same registration contract; never glob-delete arbitrary temp files |
|
|
38
38
|
| maintenance | `maintenance/`, legacy `session_cleanup_archive/` | Policy, permanent locks, metadata ledgers and recoverable quarantine |
|
|
39
39
|
|
|
40
40
|
`maintenance/policy.json` is non-secret JSON, version 1. `batch_size` defaults to
|
|
@@ -42,7 +42,7 @@ anchors:
|
|
|
42
42
|
`work_seconds: 30` and `work_bytes: 67108864` for dependency and maintenance
|
|
43
43
|
payload reads, plus reserved disposable backup writes. Existing policy
|
|
44
44
|
files acquire these defaults in memory, without rewriting operator values.
|
|
45
|
-
`maintenance/layout.json` upgrades recognized inventory v1
|
|
45
|
+
`maintenance/layout.json` upgrades recognized inventory v1 or v2 to v3 separately from
|
|
46
46
|
policy; unknown inventory versions are refused. `retention_days` defaults to sessions 0, logs 30,
|
|
47
47
|
cache 7, tmp 1, maintenance 90. Null disables that category's expiry. Session
|
|
48
48
|
age is an additional floor, never an override of leases, provenance or evidence.
|
|
@@ -149,7 +149,7 @@ deployment or provider run is implied.
|
|
|
149
149
|
|
|
150
150
|
The audit covers `Dir.tmpdir`, `Tempfile`, `mktmpdir` and atomic replacement
|
|
151
151
|
call sites, not a filesystem filename sweep:
|
|
152
|
-
- Festival speech input now uses `SessionCleanup.temporary` in `~/.pwn/
|
|
152
|
+
- Festival speech input now uses `SessionCleanup.temporary` in `~/.pwn/workspaces/runtime`, with
|
|
153
153
|
a lifetime lease and exact registration. Concurrent calls have unique names;
|
|
154
154
|
normal completion unlinks the input and a crashed consumer leaves registered bytes.
|
|
155
155
|
- Ghidra/BinaryParser canonical cache publication and managed temporary inputs
|
|
@@ -315,7 +315,7 @@ pwn setup --list-profiles
|
|
|
315
315
|
| `vision` | `OCR` · `ScannableCodes` · `Reports` · `extro_vision` · tesseract / zbar / graphviz |
|
|
316
316
|
| `voice` | `PWN::Plugins::Voice` · `extro_voice` · espeak-ng / sox |
|
|
317
317
|
| `exploit` | `Metasploit` · `sqlmap` |
|
|
318
|
-
| `hardware` | `Serial` · `BusPirate` · `Android` · `BareSIP` · `extro_serial` · `extro_telecomm` |
|
|
318
|
+
| `hardware` | `Serial` · `BusPirate` · `Android` · `BareSIP` · `YubiKey` (HIDAPI/PC/SC, no `ykman`) · `extro_serial` · `extro_telecomm` |
|
|
319
319
|
| `re` | `Radare2` · `GDB` · `ExploitDev` · `Frida` · Android RE (`apktool`/`jadx`) · `pwndbg` · `ropper` · `rizin` |
|
|
320
320
|
| `full` | everything above |
|
|
321
321
|
|
|
@@ -365,7 +365,8 @@ What `--migrate` does:
|
|
|
365
365
|
(`PWN::Migrate::STATE_FILES` - no re-implemented parsers). If the raw
|
|
366
366
|
file has bytes but the owner returned its empty-fallback, the file is
|
|
367
367
|
flagged incompatible.
|
|
368
|
-
3. **Autofix** (with `--fix`):
|
|
368
|
+
3. **Autofix** (with `--fix`): one shared recovery generation under
|
|
369
|
+
`~/.pwn/backup/` (seven folders total; see [Backup Retention](Backup-Retention.md))
|
|
369
370
|
→ ordered schema migrations → per-file repair (quarantine corrupt to
|
|
370
371
|
`~/.pwn/quarantine/`, re-seed missing dirs, strip unparsable JSONL lines,
|
|
371
372
|
convert legacy flat skills to the [agentskills.io](https://agentskills.io)
|
|
@@ -410,8 +411,10 @@ and schedule-only deletion. Already-running old binaries must be upgraded before
|
|
|
410
411
|
their startup/config-refresh hooks can be relied on to honor the new defaults.
|
|
411
412
|
|
|
412
413
|
**Housekeeping never uses systemd or any other native scheduler.**
|
|
413
|
-
`session_cleanup
|
|
414
|
-
|
|
414
|
+
`session_cleanup` is the only seeded housekeeping job. It runs only through
|
|
415
|
+
PWN's built-in cron worker or a manual command. Older split names
|
|
416
|
+
(`learning_consolidate_nightly`, `pwn_stores_lean_nightly`) are not seeded and
|
|
417
|
+
are not removed automatically. Native job
|
|
415
418
|
installers explicitly skip them with `housekeeping_internal_only`; this also
|
|
416
419
|
covers renamed payloads that invoke `SessionCleanup` or `session_cleanup.rb`.
|
|
417
420
|
Generic scheduler APIs remain available for unrelated custom jobs. Native
|
|
@@ -680,7 +683,7 @@ row as `MISSING` until a key is set.
|
|
|
680
683
|
Everything above is a thin CLI over two autoloaded modules:
|
|
681
684
|
|
|
682
685
|
```ruby
|
|
683
|
-
PWN::Setup.check # → { ok:, native_gems_missing:, toolchain_missing:, state:, pkg_manager:, os:, arch: }
|
|
686
|
+
PWN::Setup.check # → { ok:, native_gems_missing:, toolchain_missing:, state:, pkg_manager:, os:, arch:, native_libraries_missing: }
|
|
684
687
|
PWN::Setup.deps(profile: :web, yes: true) # install, then re-check
|
|
685
688
|
PWN::Setup.list_profiles
|
|
686
689
|
PWN::Setup.migrate(fix: true) # thin wrapper → PWN::Migrate.run
|
|
@@ -715,7 +718,7 @@ Vagrant, CI) picks it up automatically.
|
|
|
715
718
|
```ruby
|
|
716
719
|
pwn[CURRENT_VERSION]:001 >>> PWN::Setup.check[:ok] # => true
|
|
717
720
|
pwn[CURRENT_VERSION]:002 >>> PWN::Migrate.needed? # => false
|
|
718
|
-
pwn[CURRENT_VERSION]:003 >>> PWN::Plugins.constants.count # =>
|
|
721
|
+
pwn[CURRENT_VERSION]:003 >>> PWN::Plugins.constants.count # => 108
|
|
719
722
|
pwn[CURRENT_VERSION]:004 >>> PWN::SAST.constants.count # => 48
|
|
720
723
|
pwn[CURRENT_VERSION]:005 >>> pwn-ai # launches agent TUI
|
|
721
724
|
```
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Mission process lifetime and cancellation
|
|
2
|
+
|
|
3
|
+
## Implemented boundary
|
|
4
|
+
|
|
5
|
+
The curses ordinary-request path, local slash-command workers, each curses
|
|
6
|
+
swarm job, and the non-curses `pwn_ai_run_steerable` entrypoint execute provider,
|
|
7
|
+
controller, and tool work
|
|
8
|
+
in a mission-owned Linux PID namespace. CTRL+C kills
|
|
9
|
+
namespace PID 1 through a pidfd, waits for its supervisor to reap it, joins the
|
|
10
|
+
IPC reader, and only then releases the UI's running state. A process group is
|
|
11
|
+
not the ownership boundary: setsid, double forks, and nested child namespaces
|
|
12
|
+
remain descendants of the mission namespace. Other sessions and unrelated
|
|
13
|
+
processes are not signalled.
|
|
14
|
+
|
|
15
|
+
There is no systemd, cgroup, application compiler, or PGID fallback.
|
|
16
|
+
`PWN::AI::Agent::MissionNamespace` is Ruby code using stdlib Fiddle for Linux pidfds and
|
|
17
|
+
process-death signals. Its runtime prerequisite is **util-linux `unshare`**
|
|
18
|
+
(`pwn setup --profile ai`). Linux user/PID namespaces and pidfds must be enabled;
|
|
19
|
+
unsupported kernels or local policy fail closed with setup guidance.
|
|
20
|
+
|
|
21
|
+
Ruby recreates its timer thread after fork, so creating a user namespace from a
|
|
22
|
+
Ruby fork is not supported. For ordinary launches the controller **execs** an
|
|
23
|
+
`unshare --user --map-current-user --keep-caps` supervisor. That fresh Ruby
|
|
24
|
+
supervisor creates a PID namespace and forks its init. It passes a pidfd back
|
|
25
|
+
through a private Unix socket; the init waits for acknowledgement before running
|
|
26
|
+
any request. Killing the supervisor also kills its init through PDEATHSIG.
|
|
27
|
+
The controller, its cwd, and unrelated embedded PWN REPL modes are unchanged.
|
|
28
|
+
|
|
29
|
+
Curses/native, legacy, slash, swarm and one-shot CLI requests use named,
|
|
30
|
+
serializable descriptors, not serialized Ruby closures. Configuration, loaded
|
|
31
|
+
skill metadata and routing context travel as typed JSON over inherited private
|
|
32
|
+
sockets, never in argv or plaintext staging files. RequestRuntime's tool-worker
|
|
33
|
+
snapshot excludes locks and caller cancellation callbacks; the enclosing owner
|
|
34
|
+
provides cancellation. Replies and events remain JSON with generation fencing.
|
|
35
|
+
Loaded Ruby skill scripts are required in the worker. Embedders with additional
|
|
36
|
+
trusted plugin initializers can explicitly set
|
|
37
|
+
`PWN::AI::Agent::MissionNamespace.bootstrap_requires = ['/absolute/plugin/bootstrap.rb']`.
|
|
38
|
+
Arbitrary monkey patches, IO objects and Proc values are not serializable.
|
|
39
|
+
|
|
40
|
+
For applications explicitly launched in a single-identity user namespace,
|
|
41
|
+
MissionNamespace can fork its PID supervisor directly. This preserves trusted
|
|
42
|
+
in-memory Ruby closures without calling unshare(NEWUSER) from Ruby. The caller
|
|
43
|
+
must bootstrap explicitly with `unshare --user --map-current-user --keep-caps`;
|
|
44
|
+
there is no automatic re-exec of an embedded application. The unit-test runner
|
|
45
|
+
uses this real-kernel mode for in-memory mocks; exec/PTy fixtures explicitly
|
|
46
|
+
force the ordinary descriptor path. Both paths create a real per-mission PID
|
|
47
|
+
namespace and reject unavailable containment.
|
|
48
|
+
|
|
49
|
+
Ordinary-request events carry a generation; swarm child messages carry job
|
|
50
|
+
IDs, and console swarm callbacks carry an epoch invalidated by CTRL+C.
|
|
51
|
+
Provider calls, including ordinary-request title refresh, remain in the child.
|
|
52
|
+
Steering uses a separate JSON control pipe. The UI never deserializes Ruby
|
|
53
|
+
objects from the child.
|
|
54
|
+
|
|
55
|
+
## Detached jobs
|
|
56
|
+
|
|
57
|
+
Detached jobs started by a tool inside a mission inherit that mission's
|
|
58
|
+
namespace. They can continue after the individual tool returns, but **not**
|
|
59
|
+
after mission completion, cancellation, or namespace-owner death. Normal
|
|
60
|
+
mission completion also tears down remaining detached descendants. This is
|
|
61
|
+
intentionally different from cross-session durable jobs. A standalone
|
|
62
|
+
`AISandbox.protect_call` without an enclosing mission creates its own namespace
|
|
63
|
+
and ends that lifetime when the call ends.
|
|
64
|
+
|
|
65
|
+
Existing files and already-submitted remote operations are not rolled back.
|
|
66
|
+
The local process guarantee does not revoke work accepted by an external
|
|
67
|
+
service or remote host. Kernel-blocked uninterruptible I/O may delay reaping;
|
|
68
|
+
the UI must remain busy rather than claim readiness early.
|
|
69
|
+
|
|
70
|
+
## Controller-state separation
|
|
71
|
+
|
|
72
|
+
Tool workers are denied writes to their RequestRuntime artifact/checkpoint
|
|
73
|
+
root, including its spill directories and inherited descriptors. The actual
|
|
74
|
+
worker-symlink -> parent-spill reproducer now fails at the worker's symlink
|
|
75
|
+
with permission denied, and the synthetic source directory remains unchanged.
|
|
76
|
+
The audited controller stores (sessions/traces, transcript artifacts,
|
|
77
|
+
learning/policy/metrics, skills, logs, vault/configuration and mission state) are
|
|
78
|
+
also excluded from worker grants. See the finite writer checklist in
|
|
79
|
+
[Runtime-Source-Protection](Runtime-Source-Protection.md). Unspecified tool
|
|
80
|
+
writes stay in `~/.pwn/workspaces/runtime`; another path is allowed only when
|
|
81
|
+
the original operator request names it. Naming a missing file grants its parent,
|
|
82
|
+
including when that parent contains unrelated unreadable directories, so the
|
|
83
|
+
named file can be created. Controller state and tool output
|
|
84
|
+
workspaces must be disjoint: a parent directory containing protected state
|
|
85
|
+
cannot safely receive a broad Landlock write grant.
|
|
86
|
+
|
|
87
|
+
## Verification and remaining scope
|
|
88
|
+
|
|
89
|
+
RSpec owns the subprocess fixtures under `spec/support/harness/mission_*.rb`.
|
|
90
|
+
`spec/integration/mission_cancel_spec.rb` exercises ordinary console next-request
|
|
91
|
+
readiness and generation fencing, blocked-provider descendants, setsid escape,
|
|
92
|
+
normal-exit double forks, unrelated-process preservation, mission-lived tool
|
|
93
|
+
jobs, swarm cancellation, and fail-closed bootstrap. The namespace-denial
|
|
94
|
+
fixture injects EPERM; namespace creation/teardown tests use the real kernel.
|
|
95
|
+
`spec/integration/controller_spill_spec.rb` exercises actual RequestRuntime,
|
|
96
|
+
Dispatch, sandbox restriction, and parent spill persistence with synthetic paths.
|
|
97
|
+
|
|
98
|
+
Local slash-command maintenance/model/MCP workers now use the same hard process
|
|
99
|
+
ownership. Their completion and UI-state messages are generation-fenced JSON;
|
|
100
|
+
CTRL+C reaps the owner before returning ready. Maintenance already committed
|
|
101
|
+
before cancellation is not rolled back. Model persistence decrypts and encrypts
|
|
102
|
+
in memory; its staging file contains only ciphertext (or is empty). An offline
|
|
103
|
+
SIGKILL regression interrupts encryption startup and verifies unchanged original
|
|
104
|
+
ciphertext and absence of plaintext in the abandoned stage. Native curses PTY
|
|
105
|
+
coverage includes cancellation during a blocked local command and a successful
|
|
106
|
+
next mission.
|
|
107
|
+
|
|
108
|
+
The legacy regex-ReAct fallback now runs its provider/parser/tool loop in the
|
|
109
|
+
same MissionProcess owner. Completed history is transferred by JSON; native
|
|
110
|
+
containment failures are terminal rather than an excuse to retry uncontained.
|
|
111
|
+
Its actual after_read hook and PTY fixture cover detached Ruby/bash descendants,
|
|
112
|
+
CTRL+C, no late writes and a successful next request. Workspace policy
|
|
113
|
+
clarification does not block these offline gates.
|
|
114
|
+
|
|
115
|
+
Native PTY regressions drive actual terminal CTRL+C through both the curses
|
|
116
|
+
console and `pwn_ai_run_steerable`, assert no late descendant writes, then complete
|
|
117
|
+
a second mission. Compiler-free package acceptance builds and installs into a
|
|
118
|
+
private scratch GEM_HOME with compiler/make commands replaced by failing shims,
|
|
119
|
+
activates that exact specification, checks an empty extensions list and no
|
|
120
|
+
mission shared object, then executes a descriptor. Root and nonroot acceptance
|
|
121
|
+
must be reported separately; these are offline checks, not provider or hardware
|
|
122
|
+
evidence.
|
|
123
|
+
|
|
124
|
+
Root loses host-wide DAC override when it enters a user namespace. A host-root
|
|
125
|
+
mission therefore cannot traverse another user's mode-0700 home merely because
|
|
126
|
+
its parent could. Test roots and deployment workspaces must be traversable by
|
|
127
|
+
the mapped host identity. Do not chmod the operator's home to make a fixture
|
|
128
|
+
pass. Filesystem fixtures beneath a private nonroot HOME must use that identity,
|
|
129
|
+
including when their outer test runner is root. The integrated root fixture uses
|
|
130
|
+
an isolated mount namespace: only its task-owned scratch layout is bound at a
|
|
131
|
+
root-traversable path, with HOME, TMPDIR and inherited stdout/stderr logs opened
|
|
132
|
+
inside that layout. Inherited logs opened below the inaccessible real home would
|
|
133
|
+
correctly fail the protected-descriptor preflight. Neither the host mount table
|
|
134
|
+
nor the operator's directory permissions are changed.
|
|
@@ -57,6 +57,24 @@ PKI DMs remain unsupported. Topic `region` is an opaque prefix, not the radio's
|
|
|
57
57
|
regulatory-band setting; `radio_index` is distinct from legacy `channel_num`.
|
|
58
58
|
See [General Usage](General-PWN-Usage.md) and [REPL](pwn-REPL.md).
|
|
59
59
|
|
|
60
|
+
## Current runtime contract
|
|
61
|
+
|
|
62
|
+
These are source contracts. A checkout edit does not change an installed gem or
|
|
63
|
+
a process that is already running. Restart after installing the matching package.
|
|
64
|
+
|
|
65
|
+
| Contract | Current behavior |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| Tool writes | Unspecified `pwn-ai` writes and `TMPDIR` use `~/.pwn/workspaces/runtime`. Another path is writable only when the original operator request names it, including `mv`/`to`. A missing file grants its parent so the file can be created; that parent is still granted when it contains unrelated unreadable directories. `/opt/pwn` and the loaded package stay read-only. |
|
|
68
|
+
| Mission lifetime | CTRL+C kills the mission through `PWN::AI::Agent::MissionNamespace`. That owner is Ruby plus util-linux `unshare` and Linux pidfds. There is no compiled `pwn_mission` extension and no systemd fallback. |
|
|
69
|
+
| Recovery copies | Every PWN recovery producer uses `PWN::Backups` and `~/.pwn/backup/`, seven generation folders total. Adjacent `.bak` files are not the current producer. |
|
|
70
|
+
| Housekeeping | A fresh install seeds one internal `session_cleanup` coordinator. Curriculum jobs are not seeded. Housekeeping never uses systemd. |
|
|
71
|
+
| YubiKey | `PWN::Plugins::YubiKey` is native Ruby over HIDAPI and PC/SC. `required_bins` is empty and no `ykman` process is started. A library probe is not a connected device. Fixture coverage is not physical interoperability. See [YubiKey](YubiKey.md). |
|
|
72
|
+
|
|
73
|
+
Details: [Runtime Source Protection](Runtime-Source-Protection.md),
|
|
74
|
+
[Mission Cancellation](Mission-Cancellation.md),
|
|
75
|
+
[Backup Retention](Backup-Retention.md), [Cron](Cron.md),
|
|
76
|
+
[Persistence](Persistence.md).
|
|
77
|
+
|
|
60
78
|
## Deployment and safe verification
|
|
61
79
|
|
|
62
80
|
1. Inspect the intended checkout and preserve existing changes before upgrading.
|
|
@@ -7,8 +7,8 @@ external services and environment overrides can place evidence elsewhere.
|
|
|
7
7
|
|
|
8
8
|
| Path | Owner | Format | Reset tool | Purpose |
|
|
9
9
|
|---|---|---|---|---|
|
|
10
|
-
| `pwn.yaml` | `PWN::Config` · `PWN::Plugins::Vault` | AES-
|
|
11
|
-
| `pwn.yaml.decryptor` | `PWN::Plugins::Vault` | key/IV | - | decrypts `pwn.yaml` (or set `PWN_DECRYPTOR_KEY`/`_IV`) |
|
|
10
|
+
| `pwn.yaml` | `PWN::Config` · `PWN::Plugins::Vault` | Legacy AES-CBC or authenticated YubiKey-derived AES-GCM | `pwn-vault` | engines, keys, agent options; see [hardware vaults](YubiKey-Vaults.md) |
|
|
11
|
+
| `pwn.yaml.decryptor` | `PWN::Plugins::Vault` | Legacy key/IV | - | decrypts legacy `pwn.yaml` (or set `PWN_DECRYPTOR_KEY`/`_IV`); absent for hardware-only vaults |
|
|
12
12
|
| **`.schema`** | **`PWN::Migrate`** | JSON `{schema:,pwn_version:,at:}` | `pwn setup --migrate` | **schema stamp - drives the one-line drift warning on launch** |
|
|
13
13
|
| `memory.json` | `PWN::Memory` | JSON array | `memory_clear` | facts · prefs · lessons · env - injected into every prompt |
|
|
14
14
|
| `memory.idx` | `PWN::MemoryIndex` | JSON `{key → {sha,vec}}` | `PWN::MemoryIndex.reset` | local embedding index over `memory.json` - powers **relevance-ranked** MEMORY injection (incremental; only re-embeds changed entries) |
|
|
@@ -34,7 +34,8 @@ external services and environment overrides can place evidence elsewhere.
|
|
|
34
34
|
| `curriculum/` | `PWN::AI::Agent::Curriculum` | JSONL | rm -rf | self-play reproducers · train/gate A/B eval sets |
|
|
35
35
|
| `curriculum_kpi.jsonl` | `PWN::AI::Agent::Curriculum.practice_kpi` | JSONL | rm | outer curriculum KPI snapshots (repeating-mistake trend) |
|
|
36
36
|
| `finetune/*.jsonl` | `Learning.export_finetune` · `Reward.export_dpo` | ShareGPT / OpenAI / DPO JSONL | `rm` | supervised + preference datasets - feed to a LoRA over the local model |
|
|
37
|
-
| `
|
|
37
|
+
| `workspaces/runtime/` | `PWN::Plugins::AISandbox` · `SessionCleanup.temporary` | files | operator-managed | Unspecified `pwn-ai` writes, `TMPDIR`, and registered disposable inputs such as Festival speech. Another path is writable only when the original request names it. `/opt/pwn` stays read-only |
|
|
38
|
+
| `backup/<generation>/` | `PWN::Backups` | shared generations | see [Backup Retention](Backup-Retention.md) | One store, seven generation folders total, for every recovery producer including migrate |
|
|
38
39
|
| `quarantine/` | `PWN::Migrate` | quarantined originals | rm -rf | corrupt/incompatible state files moved aside so the owner re-seeds |
|
|
39
40
|
| `pwn_history` | Pry / pwn-ai | text | operator-managed | Shared durable input history at `~/.pwn/pwn_history` |
|
|
40
41
|
|
|
@@ -69,8 +70,9 @@ for the full `PWN::Migrate` API.
|
|
|
69
70
|
tar czf pwn-state-$(date +%F).tgz -C "$HOME" .pwn
|
|
70
71
|
```
|
|
71
72
|
|
|
72
|
-
`pwn setup --migrate --fix`
|
|
73
|
-
`~/.pwn/backup
|
|
73
|
+
`pwn setup --migrate --fix` admits one generation through `PWN::Backups` under
|
|
74
|
+
`~/.pwn/backup/` before it changes state. That store holds seven generations
|
|
75
|
+
total, not a new unbounded tree per run. See [Backup Retention](Backup-Retention.md).
|
|
74
76
|
|
|
75
77
|
## Start fresh for a new engagement
|
|
76
78
|
|
|
@@ -75,6 +75,20 @@ Required: `searchsploit`. Fallback: `intel_lookup`.
|
|
|
75
75
|
|
|
76
76
|
Required: `subfinder`, `httpx`. Fallback: `NmapIt.scan` + `Corpus.get`.
|
|
77
77
|
|
|
78
|
+
## pwn-plugins-yubikey
|
|
79
|
+
|
|
80
|
+
Required: none. `required_bins` is empty. Preflight probes HIDAPI and PC/SC
|
|
81
|
+
through `available?` and reports `FIDO native transport` or
|
|
82
|
+
`PC/SC native transport` when a library is missing. It never opens a device,
|
|
83
|
+
requests a PIN, or performs a challenge. An `ok` library probe does not
|
|
84
|
+
establish device availability, provisioning, or authorization.
|
|
85
|
+
Hardware-backed vault operations require the selected YubiKey and its existing
|
|
86
|
+
HMAC-SHA1 OTP slot; missing devices, denied touch, or authentication failures
|
|
87
|
+
raise without falling back to a disk master key or software MFA. Restore device
|
|
88
|
+
access before retrying. Dispatch blocks the handler when vault expansion fails;
|
|
89
|
+
if output redaction fails after execution, it withholds the result and reports
|
|
90
|
+
that the handler executed, so verify its effects before retrying.
|
|
91
|
+
|
|
78
92
|
## pwn-plugins-credentialattack
|
|
79
93
|
|
|
80
94
|
Required: `hydra`, `john`, `hashcat`. Fallback: `pwn_eval` + `Corpus`.
|
data/documentation/Plugins.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# `PWN::Plugins` - All
|
|
1
|
+
# `PWN::Plugins` - All 108 Modules
|
|
2
2
|
|
|
3
3
|
Every plugin is a plain Ruby module of `public_class_method def self.x(opts = {})`
|
|
4
4
|
methods with self-documenting `.help`. Source: `lib/pwn/plugins/*.rb`.
|
|
@@ -64,6 +64,7 @@ show-source PWN::Plugins::Fuzz.http
|
|
|
64
64
|
|---|---|
|
|
65
65
|
| `OAuth2` · `BasicAuth` · `AuthenticationHelper` | credential flows |
|
|
66
66
|
| `Vault` | Local encrypted configuration and engagement loot helpers; not a HashiCorp Vault client |
|
|
67
|
+
| [`YubiKey`](YubiKey.md) | Native Ruby HID/PC/SC operations, HMAC-backed vaults and OATH codes |
|
|
67
68
|
|
|
68
69
|
### Hardware / Physical
|
|
69
70
|
| Module | Purpose | Doc |
|
|
@@ -97,6 +98,6 @@ show-source PWN::Plugins::Fuzz.http
|
|
|
97
98
|
|
|
98
99
|
## Full alphabetical list
|
|
99
100
|
|
|
100
|
-
`AFLplusplus AISandbox Android ArtifactRegistry Assembly AuthenticationHelper BareSIP BasicAuth BeEF BinaryAnalysis BinaryParser BinWorkspace BlackDuckBinaryAnalysis BurpSuite BusPirate Capability CapabilityBroker Char CredentialAttack CreditCard DAOLDAP DAOMongo DAOPostgres DAOSQLite3 Debugger DefectDojo DetectOS Detonate EIN Emulator ExploitDB ExploitDev FileFu Findings Frida Fuzz GDB GDBMI GDBMi Ghidra GhidraHeadless Git Github GoogleWorkspace HackerOne Handler Httpx Hunter IPInfo IRC Jenkins JiraDataCenter Jobs JSONPathify K8s Log MailAgent Metasploit MethodCatalog MitmProxy MonkeyPatch MSR206 NessusCloud NexposeVulnScan NmapIt Nuclei OAuth2 OCR OpenAPI OpenVAS Packet PDFParse Pony PreflightChecker ProcessTube PS PWNLogger RabbitMQ Radare2 Recon REDB REPL ROP Sandbox SBOM ScannableCodes Semgrep Serial Shodan SlackClient Sock Spider Sqlmap SSN ThreadPool Tor TransparentBrowser TTYSpinner TwitterAPI URIScheme Vault VIN Voice Volatility Vsphere XXD Zaproxy`
|
|
101
|
+
`AFLplusplus AISandbox Android ArtifactRegistry Assembly AuthenticationHelper BareSIP BasicAuth BeEF BinaryAnalysis BinaryParser BinWorkspace BlackDuckBinaryAnalysis BurpSuite BusPirate Capability CapabilityBroker Char CredentialAttack CreditCard DAOLDAP DAOMongo DAOPostgres DAOSQLite3 Debugger DefectDojo DetectOS Detonate EIN Emulator ExploitDB ExploitDev FileFu Findings Frida Fuzz GDB GDBMI GDBMi Ghidra GhidraHeadless Git Github GoogleWorkspace HackerOne Handler Httpx Hunter IPInfo IRC Jenkins JiraDataCenter Jobs JSONPathify K8s Log MailAgent Metasploit MethodCatalog MitmProxy MonkeyPatch MSR206 NessusCloud NexposeVulnScan NmapIt Nuclei OAuth2 OCR OpenAPI OpenVAS Packet PDFParse Pony PreflightChecker ProcessTube PS PWNLogger RabbitMQ Radare2 Recon REDB REPL ROP Sandbox SBOM ScannableCodes Semgrep Serial Shodan SlackClient Sock Spider Sqlmap SSN ThreadPool Tor TransparentBrowser TTYSpinner TwitterAPI URIScheme Vault VIN Voice Volatility Vsphere XXD YubiKey Zaproxy`
|
|
101
102
|
|
|
102
103
|
[← Home](Home.md) · [Diagrams](Diagrams.md)
|
|
@@ -9,37 +9,37 @@ not a simulated language model.
|
|
|
9
9
|
|
|
10
10
|
## Run from a source checkout
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
There is no standalone `scripts/benchmark_policy.rb`. The worker lives in
|
|
13
|
+
`PWN::AI::Agent::PolicyEvaluation` and runs only in a fresh Ruby process.
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
require './lib/pwn/ai/agent/policy_evaluation'
|
|
17
|
+
PWN::AI::Agent::PolicyEvaluation.export_training(dir: '/tmp/pwn-policy-snapshots')
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
overlap, a negative control succeeds, or a positive control fails. Self-checks
|
|
26
|
-
also require actual training updates in the on arm and none in the off arm.
|
|
27
|
-
They deliberately do **not** require an improvement of a predetermined size.
|
|
20
|
+
`export_training` writes `off.json` and `on.json` under a new directory whose
|
|
21
|
+
parent is a real directory, then returns held-out reports for seeds 0 and 1.
|
|
22
|
+
It does not promote. Frozen snapshots are compared with `evaluate` or
|
|
23
|
+
`pwn-ai --policy evaluate`. Do not load this from the live agent console.
|
|
24
|
+
The worker exits nonzero if persistence changes during evaluation, splits
|
|
25
|
+
overlap, a negative control succeeds, or a positive control fails.
|
|
26
|
+
It does **not** require an improvement of a predetermined size.
|
|
28
27
|
|
|
29
28
|
## Relation to existing evaluation
|
|
30
29
|
|
|
31
30
|
`lib/pwn/ai/agent/curriculum.rb` provides live self-play, judge-based practice,
|
|
32
31
|
mistake-derived evaluation prompts, and adapter training/promotion gates. This
|
|
33
|
-
|
|
32
|
+
module does not invoke those paths. It provides a small, independently
|
|
34
33
|
scored experiment where the training labels come from actual task achievement,
|
|
35
34
|
not `Reward.judge`, model prose, or a previously assigned reward. It calls
|
|
36
35
|
`Policy.begin_episode`, `observe_step`, and `finish` with those labels during
|
|
37
36
|
training. This is not a test of Reward's verification-record binding, the live
|
|
38
37
|
Loop, Metrics learning, memory retrieval, or adapter training.
|
|
39
38
|
|
|
40
|
-
The experimental driver
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
The experimental driver is `PWN::AI::Agent::PolicyEvaluation`. Its public
|
|
40
|
+
methods spawn a fresh Ruby process that loads only Policy and Registry after
|
|
41
|
+
clearing the environment. Loading the module does not enable evaluation or
|
|
42
|
+
promotion.
|
|
43
43
|
|
|
44
44
|
## Protocol
|
|
45
45
|
|
|
@@ -161,21 +161,19 @@ usage records. Do not present this controller experiment as that study.
|
|
|
161
161
|
|
|
162
162
|
## Opt-in independent snapshot evaluation (R5)
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
export snapshots and run repeated evaluations in **fresh subprocesses**, use:
|
|
164
|
+
To export snapshots and run repeated evaluations in **fresh subprocesses**:
|
|
166
165
|
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
--output /tmp/pwn-policy-heldout.json
|
|
166
|
+
```ruby
|
|
167
|
+
require './lib/pwn/ai/agent/policy_evaluation'
|
|
168
|
+
PWN::AI::Agent::PolicyEvaluation.export_training(dir: '/tmp/pwn-policy-snapshots')
|
|
171
169
|
```
|
|
172
170
|
|
|
173
|
-
The snapshot directory must be **new
|
|
174
|
-
`off.json` and `on.json` are genuine Policy JSON tables after
|
|
175
|
-
training schedule. Exported `updated_at` metadata is normalized
|
|
176
|
-
reproducible snapshot digests; no Q entries or rewards are
|
|
177
|
-
happens before that arm's evaluation.
|
|
178
|
-
|
|
171
|
+
The snapshot directory must be **new**. Its parent must be a real directory,
|
|
172
|
+
not a symlink. `off.json` and `on.json` are genuine Policy JSON tables after
|
|
173
|
+
the same real training schedule. Exported `updated_at` metadata is normalized
|
|
174
|
+
to `null` for reproducible snapshot digests; no Q entries or rewards are
|
|
175
|
+
fabricated. Export happens before that arm's evaluation. Export does not
|
|
176
|
+
promote anything or discover/read a real home-directory policy.
|
|
179
177
|
|
|
180
178
|
The added `heldout` array contains protocol `pwn-policy-heldout-v2`, for suite
|
|
181
179
|
indices 0 and 1. Each worker runs three frozen arms: `off` (baseline snapshot,
|
|
@@ -231,13 +229,14 @@ not train or write the live policy. The Ruby API supports other indices 0..7.
|
|
|
231
229
|
|
|
232
230
|
From a source checkout, this disposable demonstration stays entirely under a
|
|
233
231
|
new `/tmp` directory (use `pwn-ai` instead of `ruby -Ilib bin/pwn-ai` for an
|
|
234
|
-
installed executable)
|
|
232
|
+
installed executable). Export writes `off.json` and `on.json`; it does not
|
|
233
|
+
promote:
|
|
235
234
|
|
|
236
235
|
```sh
|
|
237
236
|
umask 077
|
|
238
237
|
work=$(mktemp -d /tmp/pwn-offline-policy.XXXXXX)
|
|
239
|
-
ruby
|
|
240
|
-
|
|
238
|
+
ruby -Ilib -rpwn/ai/agent/policy_evaluation -e \
|
|
239
|
+
"PWN::AI::Agent::PolicyEvaluation.export_training(dir: '$work/snapshots')"
|
|
241
240
|
ruby -Ilib bin/pwn-ai --policy evaluate \
|
|
242
241
|
--baseline "$work/snapshots/off.json" --candidate "$work/snapshots/on.json" \
|
|
243
242
|
> "$work/reports.json"
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Runtime source protection
|
|
2
|
+
|
|
3
|
+
> The mandatory worker boundary protects source and separates the finite
|
|
4
|
+
> controller-state inventory below from tool writes. Checkpoint persistence also
|
|
5
|
+
> uses pinned fd-relative no-follow directory operations. Process containment
|
|
6
|
+
> owns detached tool jobs until mission completion/cancellation; it is not a
|
|
7
|
+
> substitute for filesystem protection. Unspecified tool writes use
|
|
8
|
+
> `~/.pwn/workspaces/runtime`. A path is writable outside that directory only
|
|
9
|
+
> when the original operator request names it. An explicit destination grants
|
|
10
|
+
> its parent even when that parent contains unrelated unreadable directories,
|
|
11
|
+
> so a new file can be created there. Source checkouts stay read-only
|
|
12
|
+
> even if named. See [Mission-Cancellation](Mission-Cancellation.md).
|
|
13
|
+
|
|
14
|
+
A pwn-ai RequestRuntime dispatch executes its registered handler in an AISandbox
|
|
15
|
+
worker. This boundary is mandatory even when the optional `ai_sandbox` profile
|
|
16
|
+
is `off`. It covers shell, Ruby evaluation, other registered handlers, nested
|
|
17
|
+
Dispatch calls, and fork/exec descendants including durable Jobs supervisors.
|
|
18
|
+
Direct library calls made by an operator outside a RequestRuntime are not AI
|
|
19
|
+
runtime tool calls and are unchanged. Legacy regex-ReAct Ruby and shell blocks
|
|
20
|
+
also use the mandatory worker boundary (inside their enclosing mission); they
|
|
21
|
+
no longer evaluate directly in the mission controller. The source-denial
|
|
22
|
+
regression drives both languages through the actual Pry after_read hook.
|
|
23
|
+
|
|
24
|
+
The host protects `/opt/pwn` when present and the real source root containing the
|
|
25
|
+
loaded package. Linux Landlock ABI 3 or newer denies content writes, truncation,
|
|
26
|
+
creation, removal, and linking under those roots. It resolves symlinks and `..`
|
|
27
|
+
in the kernel: scripts are not rewritten. Repo reads remain available. The UI
|
|
28
|
+
process does not change cwd. Relative reads use the task directory when it is
|
|
29
|
+
outside protected source; otherwise they use `~/.pwn/workspaces/runtime`.
|
|
30
|
+
Unnamed new files and temporary files go to that runtime directory. `/tmp`, the
|
|
31
|
+
launch directory, and the rest of `~/.pwn` are not default write grants. A path
|
|
32
|
+
named by the original operator request is created and granted; naming a file
|
|
33
|
+
grants its parent so the file can be created. That parent grant is a directory
|
|
34
|
+
rule, so a new file can still be created when the parent contains unrelated
|
|
35
|
+
unreadable directories. Do not create the missing destination as a directory.
|
|
36
|
+
Protected source is never granted.
|
|
37
|
+
Standard null/zero/random devices are available. Other filesystem writes fail
|
|
38
|
+
closed. This bounded write set permits hardlink-alias exclusion without scanning
|
|
39
|
+
all mounted filesystems or changing checkout permissions.
|
|
40
|
+
|
|
41
|
+
## Fail-closed requirements and restrictions
|
|
42
|
+
|
|
43
|
+
- Supported syscall ABIs are Linux x86_64 and aarch64; libseccomp is required.
|
|
44
|
+
Missing enforcement prevents handler execution, rather than falling back to
|
|
45
|
+
regex checks or unsandboxed execution.
|
|
46
|
+
- Landlock does not mediate file metadata changes. The worker therefore denies
|
|
47
|
+
chmod/chown, timestamp and extended-attribute mutation system-wide, including
|
|
48
|
+
outside source. Ordinary outside content writes and file creation still work.
|
|
49
|
+
Tools that need those metadata operations require a different supported
|
|
50
|
+
execution environment, not an exception to source protection.
|
|
51
|
+
- Mount/namespace manipulation, ptrace/process-memory writes, and io_uring setup
|
|
52
|
+
are denied. Existing descriptors into protected roots are closed in the child.
|
|
53
|
+
- Host preflight inventories multiply linked protected file identities and
|
|
54
|
+
excludes matching aliases in every writable tree. Aliases elsewhere receive
|
|
55
|
+
no write grant. Alias inventories are cached against source inode/link-count/
|
|
56
|
+
ctime fingerprints and writable-root identity; source link changes invalidate
|
|
57
|
+
that cache. Unreadable subtrees encountered during alias scanning are excluded.
|
|
58
|
+
This includes generated rdoc assets linked to installed gem assets; no source
|
|
59
|
+
files are chmodded, deleted, or automatically rewritten.
|
|
60
|
+
- Protected root ancestors cannot grant inherited write permission without also
|
|
61
|
+
granting it to source. Creating a new sibling directly in such an ancestor is
|
|
62
|
+
consequently denied; use an existing writable outside directory.
|
|
63
|
+
- This is a local process/filesystem effect boundary, not isolation of remote
|
|
64
|
+
services or already-running privileged daemons commanded over IPC/network.
|
|
65
|
+
It does not defend against a concurrent external actor replacing policy paths
|
|
66
|
+
or introducing new hardlink aliases after preflight. Do not run untrusted
|
|
67
|
+
external writers against the protected installation.
|
|
68
|
+
- Handler-local Ruby variables and in-memory plugin state do not propagate back
|
|
69
|
+
to the UI. Persistent outputs and durable job state do. A handler that requires
|
|
70
|
+
process-local state across calls must not assume the old in-process evaluator.
|
|
71
|
+
|
|
72
|
+
## Sandboxed swarm control
|
|
73
|
+
|
|
74
|
+
`agent_spawn` and `agent_ask` handlers still run inside the mandatory worker.
|
|
75
|
+
Their Swarm calls use a private socket to request only the controller's typed
|
|
76
|
+
`spawn`/`ask` operations. The controller checks request tool permissions, rejects
|
|
77
|
+
unknown fields/operations and traversal identifiers, and never invokes a
|
|
78
|
+
worker-selected Registry handler, callback, Ruby expression, or filesystem path.
|
|
79
|
+
Nested persona tools pass through Dispatch and get their own mandatory workers.
|
|
80
|
+
|
|
81
|
+
Before launch the controller provisions the fixed swarm directory, persona file,
|
|
82
|
+
and continuation lock with no-follow ancestry and regular-file/single-link
|
|
83
|
+
checks. Workers cannot write the persona file, swarm subtree, or request
|
|
84
|
+
checkpoint tree, nor rename their ancestors. No parent-directory write grant is
|
|
85
|
+
added. Child Loop receipts remain controller-observed and are rechecked when
|
|
86
|
+
merged into the parent. This preserves sandboxed spawn/ask state creation without
|
|
87
|
+
allowing arbitrary controller callbacks.
|
|
88
|
+
|
|
89
|
+
## Finite parent-writer audit
|
|
90
|
+
|
|
91
|
+
The worker deny set now includes these controller-owned stores, even before a
|
|
92
|
+
store exists. Missing paths still split the ancestor's Landlock grant, preventing
|
|
93
|
+
first-write symlink planting. Existing inherited descriptors and hardlink aliases
|
|
94
|
+
are covered by the same preflight as source. Store constants are resolved in the
|
|
95
|
+
controller, not from model/tool output. Both lexical paths and canonical store
|
|
96
|
+
aliases are denied, so a configured symlink cannot expose controller state
|
|
97
|
+
through another otherwise writable directory.
|
|
98
|
+
|
|
99
|
+
| Parent writer | Protected state |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| RequestRuntime checkpoints and EngagementMemory | Request-specific artifact root; checkpoint lock/temp/final persistence is also fd-relative/no-follow |
|
|
102
|
+
| Sessions and SessionTrace | Sessions root, including support, leases, traces and requests |
|
|
103
|
+
| Loop transcript compaction, ArtifactRegistry, swarm bus spills | Default artifacts root and configured ArtifactRegistry root |
|
|
104
|
+
| Learning, Policy, Metrics, Reward, Mistakes, ToolGuard | Declared files/directories, learning and metrics subtrees; absent sibling staging paths cannot be planted |
|
|
105
|
+
| Memory and MemoryIndex | Memory, archive and index files |
|
|
106
|
+
| OpenGoal, Mission and TaskDAG | Goal file, missions and runs roots |
|
|
107
|
+
| SkillReview and Curriculum | Ledger, curriculum/finetune roots, default/configured skill directories and loaded skill parents |
|
|
108
|
+
| Provider credential persistence and local model configuration | Default vault/decryptor and configured driver paths |
|
|
109
|
+
| Session redaction's Vault persistence | Engagements tree, legacy vault file and master-key path |
|
|
110
|
+
| Log and Extrospection | Default logs and declared Extrospection stores |
|
|
111
|
+
| Typed swarm controller | Swarm subtree, personas and continuation lock |
|
|
112
|
+
|
|
113
|
+
The regression first reproduced an actual worker redirect of the transcript
|
|
114
|
+
spill directory: after the worker returned, Loop created a file in synthetic
|
|
115
|
+
protected source. It now receives permission denied, as does the earlier
|
|
116
|
+
RequestRuntime spill reproducer. An independent fixture attempts 29 state
|
|
117
|
+
mutations across existing directories/files and an absent staging path in both
|
|
118
|
+
ordinary and symlinked-store layouts, while also creating a legitimate output in
|
|
119
|
+
a disjoint workspace.
|
|
120
|
+
|
|
121
|
+
Tools that directly mutate these controller stores are deliberately denied;
|
|
122
|
+
only spawn/ask currently have the typed broker exception. This is not a promise
|
|
123
|
+
that arbitrary in-process stateful plugins retain their old behavior. New parent
|
|
124
|
+
writers or custom stores require an inventory update. The guarantee assumes a
|
|
125
|
+
trusted initial controller layout and excludes concurrent external filesystem
|
|
126
|
+
writers as described above; it is not a general host sandbox.
|
|
127
|
+
|
|
128
|
+
## Completion evidence and uncertainty
|
|
129
|
+
|
|
130
|
+
Required artifact names come from the original operator request (including
|
|
131
|
+
explicit amendments), not cached model guesses or tool transcripts. Unquoted
|
|
132
|
+
prose such as `i.e.` does not create a required file named `i.e`; explicitly
|
|
133
|
+
quoted filenames are still honored.
|
|
134
|
+
|
|
135
|
+
RequestRuntime snapshots required artifacts before dispatch and, on success,
|
|
136
|
+
reads their stat, bounded head/tail and SHA-256 from the host. Successful actual
|
|
137
|
+
file deltas count even if payload classification called the tool `eval` rather
|
|
138
|
+
than `write`. Receipts accumulate across separate calls/iterations and survive
|
|
139
|
+
transcript compaction. A failed tool, unchanged stale file, or tool stdout claim
|
|
140
|
+
cannot create a receipt. Current bytes/identity must still match at completion.
|
|
141
|
+
A combined write/read call does not require a ritual second call.
|
|
142
|
+
|
|
143
|
+
Unknown side effects remain replay-fenced. A timeout/interruption or failed
|
|
144
|
+
mutation is not erased by unrelated successful artifacts. On an attempted final
|
|
145
|
+
answer the loop returns a structured `blocked` outcome with action ID and payload
|
|
146
|
+
hash, instead of endlessly asking for rewrites. Exact-target operator-approved
|
|
147
|
+
reconciliation is still required for genuine uncertainty; the existing HTTP
|
|
148
|
+
reconciliation API is unchanged. Kernel/preflight failure before the handler
|
|
149
|
+
starts is recorded as `rejected`, not falsely labeled an uncertain mutation.
|
|
150
|
+
|
|
151
|
+
## Verification and deployment
|
|
152
|
+
|
|
153
|
+
Offline specs exercise actual kernel workers, symlink/parent traversal denial,
|
|
154
|
+
metadata denial, nested Dispatch, a detached Jobs worker, fail-closed unsupported
|
|
155
|
+
protection/hardlinks, and the Loop → Dispatch → cumulative host receipt path with
|
|
156
|
+
an actual generated PDF and separate text output. Provider messages in that
|
|
157
|
+
replay are fixtures, not a live remote-model test.
|
|
158
|
+
|
|
159
|
+
Source changes do not update an installed gem or a running pwn-ai process.
|
|
160
|
+
Deploy the matching source/package files and restart the remote process through
|
|
161
|
+
the operator's normal deployment procedure. Inspect the reported root/hardlink
|
|
162
|
+
and kernel requirements before claiming that host is operational.
|
|
@@ -52,5 +52,16 @@ All four honor `proxy:` (Burp / `tor`) so attribution stays controlled, reuse
|
|
|
52
52
|
**one** browser handle across anchors, and `close` in an `ensure`. See
|
|
53
53
|
[Extrospection](Extrospection.md) for the full loop.
|
|
54
54
|
|
|
55
|
+
## Jev action loop
|
|
56
|
+
|
|
57
|
+
`act` and `browser_act` run only when Open WebUI is configured and its model
|
|
58
|
+
list contains a Jev model. Jev receives the visible control table and returns
|
|
59
|
+
one operation plus one index: `CLICK`, `TYPE_TEXT`, `SELECT`, `SCROLL_UP`,
|
|
60
|
+
`SCROLL_DOWN`, `WAIT`, `DONE`, or `BLOCKED`. It does not receive screenshots
|
|
61
|
+
and it does not emit selectors. If the active pwn-ai model is not Jev, that
|
|
62
|
+
model still writes the field text for `TYPE_TEXT`. Other pwn-ai work stays on
|
|
63
|
+
the active model. This is the indexed-action idea from
|
|
64
|
+
[jev-ultrafast](https://github.com/browser-use/jev-ultrafast), not TypeSafe's
|
|
65
|
+
multi-head API and not a claim of its measured latency.
|
|
55
66
|
|
|
56
67
|
[← Home](Home.md) · [BurpSuite](BurpSuite.md) · [WWW](WWW.md) · [Extrospection](Extrospection.md)
|
|
@@ -32,8 +32,9 @@ $ pwn setup --migrate --dry-run # report only
|
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Corrupt / incompatible files are moved to `~/.pwn/quarantine/` (never
|
|
35
|
-
deleted)
|
|
36
|
-
first
|
|
35
|
+
deleted). Recovery copies go to one shared generation under `~/.pwn/backup/`
|
|
36
|
+
first; the store keeps seven generations total. See
|
|
37
|
+
[Backup Retention](Backup-Retention.md). Missing config keys added by the new release are deep-merged into
|
|
37
38
|
your encrypted `~/.pwn/pwn.yaml` **under** your existing values. See
|
|
38
39
|
[Installation § Upgrading](Installation.md#upgrading--pwn-state-migration-pwnmigrate).
|
|
39
40
|
|