pwn 0.5.766 → 0.5.772
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/Gemfile +3 -3
- data/documentation/Configuration.md +2 -0
- data/documentation/General-PWN-Usage.md +68 -0
- data/documentation/Harness-Evaluation.md +312 -0
- data/documentation/pwn-ai-Agent.md +135 -6
- data/etc/default_cron/session_cleanup.rb +6 -1
- data/etc/default_skills/pwn/ai/agent/dispatch/SKILL.md +1 -0
- data/etc/default_skills/pwn/ai/agent/open_goal/SKILL.md +1 -0
- data/etc/default_skills/pwn/ai/agent/skill_review/SKILL.md +2 -0
- data/etc/default_skills/pwn/ai/agent/solve/SKILL.md +4 -2
- data/etc/default_skills/pwn/ai/context_ingestion/SKILL.md +1 -1
- data/etc/default_skills/pwn/ai/http_retry/SKILL.md +1 -0
- data/etc/default_skills/pwn/plugins/repl/ai_console/SKILL.md +1 -1
- data/etc/default_skills/pwn/plugins/repl/mesh/SKILL.md +4 -0
- data/etc/default_skills/pwn/plugins/repl/mesh/references/urls.md +3 -0
- data/etc/default_skills/pwn/redaction/SKILL.md +1 -1
- data/etc/default_skills/pwn/runtime_fingerprint/SKILL.md +47 -0
- data/lib/pwn/ai/agent/dispatch.rb +50 -6
- data/lib/pwn/ai/agent/loop.rb +192 -115
- data/lib/pwn/ai/agent/open_goal.rb +43 -1
- data/lib/pwn/ai/agent/registry.rb +6 -1
- data/lib/pwn/ai/agent/request_runtime.rb +508 -17
- data/lib/pwn/ai/agent/result.rb +23 -6
- data/lib/pwn/ai/agent/reward.rb +4 -1
- data/lib/pwn/ai/agent/skill_review.rb +148 -1
- data/lib/pwn/ai/agent/solve.rb +420 -39
- data/lib/pwn/ai/agent/swarm.rb +11 -2
- data/lib/pwn/ai/agent/tools/shell.rb +23 -0
- data/lib/pwn/ai/agent/turn_finalizer.rb +37 -6
- data/lib/pwn/ai/agent/verification.rb +42 -5
- data/lib/pwn/ai/anthropic.rb +59 -5
- data/lib/pwn/ai/cli.rb +48 -4
- data/lib/pwn/ai/context.rb +1 -1
- data/lib/pwn/ai/context_ingestion.rb +16 -1
- data/lib/pwn/ai/gemini.rb +36 -5
- data/lib/pwn/ai/grok.rb +19 -15
- data/lib/pwn/ai/http_retry.rb +14 -0
- data/lib/pwn/ai/mcp/combo_nation.rb +5 -2
- data/lib/pwn/ai/mcp.rb +5 -2
- data/lib/pwn/ai/ollama.rb +46 -5
- data/lib/pwn/ai/open_ai.rb +11 -11
- data/lib/pwn/ai/open_web_ui.rb +46 -5
- data/lib/pwn/config.rb +10 -2
- data/lib/pwn/migrate.rb +9 -1
- data/lib/pwn/plugins/repl/ai.rb +31 -1
- data/lib/pwn/plugins/repl/ai_console.rb +843 -19
- data/lib/pwn/plugins/repl/ai_console_commands.rb +23 -5
- data/lib/pwn/plugins/repl/ai_swarm.rb +65 -5
- data/lib/pwn/plugins/repl/mesh.rb +894 -83
- data/lib/pwn/plugins/repl.rb +2 -0
- data/lib/pwn/redaction.rb +29 -5
- data/lib/pwn/runtime_fingerprint.rb +84 -0
- data/lib/pwn/version.rb +1 -1
- data/lib/pwn.rb +1 -0
- data/spec/fixtures/harness/adapters.json +62 -0
- data/spec/fixtures/harness/adapters.json.sha256 +1 -0
- data/spec/fixtures/harness/experiment_gold.json +9 -0
- data/spec/fixtures/harness/experiment_gold.json.sha256 +1 -0
- data/spec/fixtures/harness/experiment_tasks.json +12 -0
- data/spec/fixtures/harness/experiment_tasks.json.sha256 +1 -0
- data/spec/fixtures/harness/live_comparison.json +21 -0
- data/spec/fixtures/harness/live_comparison.json.sha256 +1 -0
- data/spec/fixtures/harness/manifest.json +290 -0
- data/spec/fixtures/harness/manifest.json.sha256 +1 -0
- data/spec/integration/harness_evaluation_spec.rb +171 -0
- data/spec/integration/harness_layout_spec.rb +15 -0
- data/spec/integration/harness_live_spec.rb +26 -0
- data/spec/integration/harness_package_spec.rb +38 -0
- data/spec/integration/native_ruby_helpers_spec.rb +4 -2
- data/spec/integration/reinforced_feedback_loop_spec.rb +2 -2
- data/spec/lib/pwn/ai/agent/dispatch_spec.rb +47 -3
- data/spec/lib/pwn/ai/agent/loop_spec.rb +479 -17
- data/spec/lib/pwn/ai/agent/open_goal_spec.rb +17 -0
- data/spec/lib/pwn/ai/agent/registry_spec.rb +10 -0
- data/spec/lib/pwn/ai/agent/request_runtime_spec.rb +232 -0
- data/spec/lib/pwn/ai/agent/result_spec.rb +33 -0
- data/spec/lib/pwn/ai/agent/signal_hygiene_spec.rb +1 -1
- data/spec/lib/pwn/ai/agent/skill_review_spec.rb +17 -5
- data/spec/lib/pwn/ai/agent/solve_spec.rb +392 -7
- data/spec/lib/pwn/ai/agent/swarm_spec.rb +19 -0
- data/spec/lib/pwn/ai/agent/tools/ruby_eval_spec.rb +2 -2
- data/spec/lib/pwn/ai/agent/turn_finalizer_spec.rb +20 -0
- data/spec/lib/pwn/ai/agent/verification_spec.rb +12 -0
- data/spec/lib/pwn/ai/anthropic_spec.rb +10 -0
- data/spec/lib/pwn/ai/cli_spec.rb +40 -0
- data/spec/lib/pwn/ai/context_ingestion_spec.rb +12 -0
- data/spec/lib/pwn/ai/grok_spec.rb +35 -0
- data/spec/lib/pwn/ai/mcp/combo_nation_spec.rb +10 -0
- data/spec/lib/pwn/ai/mcp_spec.rb +10 -0
- data/spec/lib/pwn/ai/open_ai_spec.rb +13 -0
- data/spec/lib/pwn/migrate_spec.rb +37 -4
- data/spec/lib/pwn/plugins/repl/ai_console_completion_wrap_spec.rb +110 -0
- data/spec/lib/pwn/plugins/repl/ai_console_spec.rb +307 -3
- data/spec/lib/pwn/plugins/repl/ai_swarm_spec.rb +29 -0
- data/spec/lib/pwn/plugins/repl/ai_vault_edit_spec.rb +221 -0
- data/spec/lib/pwn/plugins/repl_mesh_channel_identity_spec.rb +134 -0
- data/spec/lib/pwn/plugins/repl_mesh_dispatch_spec.rb +2 -0
- data/spec/lib/pwn/plugins/repl_mesh_dm_transport_spec.rb +2 -1
- data/spec/lib/pwn/plugins/repl_mesh_multi_rx_spec.rb +315 -0
- data/spec/lib/pwn/plugins/repl_mesh_origin_gps_spec.rb +120 -0
- data/spec/lib/pwn/plugins/repl_mesh_rx_errors_spec.rb +325 -0
- data/spec/lib/pwn/plugins/repl_mesh_scroll_spec.rb +49 -0
- data/spec/lib/pwn/plugins/repl_mesh_transport_label_spec.rb +43 -15
- data/spec/lib/pwn/plugins/repl_spec.rb +31 -7
- data/spec/lib/pwn/redaction_spec.rb +17 -0
- data/spec/lib/pwn/runtime_fingerprint_spec.rb +53 -0
- data/spec/lib/pwn/session_cleanup_default_spec.rb +1 -1
- data/spec/spec_helper.rb +3 -1
- data/spec/support/harness/cli_faults.rb +112 -0
- data/spec/support/harness/evaluate.rb +191 -0
- data/spec/support/harness/experiment_preload.rb +20 -0
- data/spec/support/harness/experiments.rb +137 -0
- data/spec/support/harness/fake_provider.rb +82 -0
- data/spec/support/harness/fault_preload.rb +44 -0
- data/spec/support/harness/package_acceptance.rb +77 -0
- data/spec/support/harness/record_training.rb +18 -0
- data/spec/support/harness/reference_adapter.py +128 -0
- data/spec/support/harness/runtime_faults.rb +97 -0
- data/spec/support/harness/session_acceptance.rb +70 -0
- data/spec/support/harness/swarm_acceptance.rb +61 -0
- data/third_party/pwn_rdoc.jsonl +129 -3
- metadata +46 -8
|
@@ -28,11 +28,13 @@ Class methods take `(opts = {})` and read `opts`.
|
|
|
28
28
|
|
|
29
29
|
```ruby
|
|
30
30
|
PWN::AI::Agent::Solve.help
|
|
31
|
-
PWN::AI::Agent::Solve.
|
|
31
|
+
PWN::AI::Agent::Solve.apply_patch(opts)
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## Public methods
|
|
35
35
|
|
|
36
|
+
- `apply_patch`
|
|
37
|
+
- `cleanup_worktree`
|
|
36
38
|
- `authors`
|
|
37
39
|
- `help`
|
|
38
40
|
|
|
@@ -42,5 +44,5 @@ PWN::AI::Agent::Solve.help(opts)
|
|
|
42
44
|
|
|
43
45
|
## Verification
|
|
44
46
|
|
|
45
|
-
`PWN::AI::Agent::Solve.respond_to?(:
|
|
47
|
+
`PWN::AI::Agent::Solve.respond_to?(:apply_patch)` after the
|
|
46
48
|
module is loaded. Read the source for parameter names.
|
|
@@ -12,7 +12,7 @@ metadata:
|
|
|
12
12
|
|
|
13
13
|
# PWN::AI::Context
|
|
14
14
|
|
|
15
|
-
Local evidence ingestion;
|
|
15
|
+
Local evidence ingestion; XML is bounded to 100 element levels before XPath. Unavailable embeddings never become synthetic vectors.
|
|
16
16
|
|
|
17
17
|
## When to use
|
|
18
18
|
|
|
@@ -12,7 +12,7 @@ metadata:
|
|
|
12
12
|
|
|
13
13
|
# PWN::Plugins::REPL::AIConsole
|
|
14
14
|
|
|
15
|
-
Single-owner fullscreen
|
|
15
|
+
Single-owner fullscreen console: wrapped completion and private /vault edit; Ctrl+S saves encrypted, Esc cancels.
|
|
16
16
|
|
|
17
17
|
## When to use
|
|
18
18
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pwn-runtimefingerprint
|
|
3
|
+
description: Drive PWN::RuntimeFingerprint from pwn_eval.
|
|
4
|
+
license: MIT
|
|
5
|
+
allowed-tools: [pwn, pwn_eval]
|
|
6
|
+
metadata:
|
|
7
|
+
bundled: true
|
|
8
|
+
generated: true
|
|
9
|
+
module: PWN::RuntimeFingerprint
|
|
10
|
+
source: pwn/runtime_fingerprint.rb
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# PWN::RuntimeFingerprint
|
|
14
|
+
|
|
15
|
+
Read-only deployment diagnostics. A disk observation at compilation is not an attestation of VM bytecode, native extensions, or later monkey patches.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
Call `PWN::RuntimeFingerprint` from `pwn_eval` when the task needs this module.
|
|
20
|
+
Do not reimplement it in shell.
|
|
21
|
+
|
|
22
|
+
## Methodologies
|
|
23
|
+
|
|
24
|
+
Generated from `pwn/runtime_fingerprint.rb`. Prefer the public class methods below.
|
|
25
|
+
Class methods take `(opts = {})` and read `opts`.
|
|
26
|
+
|
|
27
|
+
## How to call
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
PWN::RuntimeFingerprint.help
|
|
31
|
+
PWN::RuntimeFingerprint.report(opts)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Public methods
|
|
35
|
+
|
|
36
|
+
- `report`
|
|
37
|
+
- `authors`
|
|
38
|
+
- `help`
|
|
39
|
+
|
|
40
|
+
## Source
|
|
41
|
+
|
|
42
|
+
`pwn/runtime_fingerprint.rb`
|
|
43
|
+
|
|
44
|
+
## Verification
|
|
45
|
+
|
|
46
|
+
`PWN::RuntimeFingerprint.respond_to?(:report)` after the
|
|
47
|
+
module is loaded. Read the source for parameter names.
|
|
@@ -51,6 +51,9 @@ module PWN
|
|
|
51
51
|
entry = Registry.lookup(name: name) || Registry.lookup(name: repair_name(name: name))
|
|
52
52
|
return JSON.generate(error: "unknown tool: #{name}") unless entry
|
|
53
53
|
|
|
54
|
+
owner = Thread.current[:pwn_request_runtime]
|
|
55
|
+
return JSON.generate(success: false, error: 'request_tool_permission_denied') if owner && !owner.tool_allowed?(name: entry.name, toolset: entry.toolset)
|
|
56
|
+
|
|
54
57
|
solve_tools = Thread.current[:pwn_solve_tools]
|
|
55
58
|
return JSON.generate(success: false, error: 'Tool denied by solve role capability boundary') if solve_tools && !solve_tools.include?(entry.name.to_s)
|
|
56
59
|
|
|
@@ -123,7 +126,12 @@ module PWN
|
|
|
123
126
|
|
|
124
127
|
started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
125
128
|
begin
|
|
126
|
-
|
|
129
|
+
runtime = Thread.current[:pwn_request_runtime]
|
|
130
|
+
result = if runtime
|
|
131
|
+
runtime.execute_tool(name: entry.name, args: args, effect: effect(name: entry.name, args: args), action_id: tool_call[:id] || tool_call['id']) { entry.handler.call(args) }
|
|
132
|
+
else
|
|
133
|
+
entry.handler.call(args)
|
|
134
|
+
end
|
|
127
135
|
rescue StandardError => e
|
|
128
136
|
finish_budget(budget: budget, result: { error: e.is_a?(Timeout::Error) ? 'timeout' : e.class.name }, elapsed: Process.clock_gettime(Process::CLOCK_MONOTONIC) - started)
|
|
129
137
|
raise
|
|
@@ -138,6 +146,7 @@ module PWN
|
|
|
138
146
|
result = JSON.parse(PWN::Plugins::Vault.redact(text: JSON.generate(result)))
|
|
139
147
|
end
|
|
140
148
|
response = { success: true, result: result, effect: effect(name: entry.name, args: args) }
|
|
149
|
+
response[:success] = false if result.is_a?(Hash) && (result[:error] || result['error'] || result[:success] == false || result['success'] == false)
|
|
141
150
|
response[:budget] = telemetry if telemetry
|
|
142
151
|
if telemetry && telemetry[:remaining_s].zero?
|
|
143
152
|
response[:success] = false
|
|
@@ -207,6 +216,8 @@ module PWN
|
|
|
207
216
|
private_class_method def self.prepare_budget(opts = {})
|
|
208
217
|
entry = opts[:entry]
|
|
209
218
|
args = opts[:args]
|
|
219
|
+
return nil if Thread.current[:pwn_request_runtime] && args.key?(:timeout)
|
|
220
|
+
|
|
210
221
|
if entry.name == 'shell' && (args[:background] == true || (!args.key?(:timeout) && ToolGuard.auto_job?(payload: args[:command].to_s)))
|
|
211
222
|
args[:background] = true
|
|
212
223
|
return nil
|
|
@@ -299,15 +310,18 @@ module PWN
|
|
|
299
310
|
|
|
300
311
|
private_class_method def self.drop_required(opts = {})
|
|
301
312
|
node = opts[:node]
|
|
313
|
+
depth = opts.fetch(:depth, 0)
|
|
314
|
+
raise JSON::NestingError, 'tool schema exceeds JSON nesting limit (100)' if depth >= 100 && (node.is_a?(Hash) || node.is_a?(Array))
|
|
315
|
+
|
|
302
316
|
case node
|
|
303
317
|
when Hash
|
|
304
318
|
node.each_with_object({}) do |(key, value), acc|
|
|
305
319
|
next if key.to_s == 'required'
|
|
306
320
|
|
|
307
|
-
acc[key] = drop_required(node: value)
|
|
321
|
+
acc[key] = drop_required(node: value, depth: depth + 1)
|
|
308
322
|
end
|
|
309
323
|
when Array
|
|
310
|
-
node.map { |value| drop_required(node: value) }
|
|
324
|
+
node.map { |value| drop_required(node: value, depth: depth + 1) }
|
|
311
325
|
else
|
|
312
326
|
node
|
|
313
327
|
end
|
|
@@ -514,9 +528,34 @@ module PWN
|
|
|
514
528
|
learning_note_outcome skill_create skill_add_reference skills_update
|
|
515
529
|
].freeze
|
|
516
530
|
|
|
531
|
+
# Audited local reads only. Resource conflicts deliberately serialize
|
|
532
|
+
# even two reads of one handle, and every other tool is a barrier.
|
|
533
|
+
PARALLEL_READS = %w[artifact_read artifact_grep artifacts_get artifact_get job_tail].freeze
|
|
534
|
+
|
|
535
|
+
# Supported Method Parameters::
|
|
536
|
+
# metadata = PWN::AI::Agent::Dispatch.scheduling(
|
|
537
|
+
# tool_call: 'required - tool call whose audited read resources are resolved'
|
|
538
|
+
# )
|
|
539
|
+
public_class_method def self.scheduling(opts = {})
|
|
540
|
+
call = opts[:tool_call]
|
|
541
|
+
name = call.dig(:function, :name).to_s
|
|
542
|
+
args = call.dig(:function, :arguments)
|
|
543
|
+
args = JSON.parse(args) if args.is_a?(String)
|
|
544
|
+
args = args.transform_keys(&:to_s)
|
|
545
|
+
resource = args['id'] if name == 'job_tail'
|
|
546
|
+
if PARALLEL_READS.include?(name) && name != 'job_tail'
|
|
547
|
+
handle = args['handle'] || args['sha256']
|
|
548
|
+
path = handle ? PWN::Plugins::ArtifactRegistry.resolve(handle: handle)[:path] : args['path'] || args['ref']
|
|
549
|
+
resource = File.realpath(path) if path
|
|
550
|
+
end
|
|
551
|
+
{ exclusive: !PARALLEL_READS.include?(name) || resource.to_s.empty?, resources: ["handle:#{resource}"] }
|
|
552
|
+
rescue JSON::ParserError, NoMethodError, ArgumentError, SystemCallError
|
|
553
|
+
{ exclusive: true, resources: ['*'] }
|
|
554
|
+
end
|
|
555
|
+
|
|
517
556
|
public_class_method def self.effect(opts = {})
|
|
518
557
|
name = opts[:name].to_s
|
|
519
|
-
return :read if
|
|
558
|
+
return :read if PARALLEL_READS.include?(name)
|
|
520
559
|
return :recall if RECALL_TOOLS.include?(name)
|
|
521
560
|
return :store if STORE_TOOLS.include?(name)
|
|
522
561
|
|
|
@@ -525,9 +564,9 @@ module PWN
|
|
|
525
564
|
return :browse if blob.match?(BROWSE_ARGV_RX)
|
|
526
565
|
return :eval if name == 'pwn_eval'
|
|
527
566
|
|
|
528
|
-
:
|
|
567
|
+
:exclusive
|
|
529
568
|
rescue StandardError
|
|
530
|
-
:
|
|
569
|
+
:exclusive
|
|
531
570
|
end
|
|
532
571
|
|
|
533
572
|
private_class_method def self.argv_blob(opts = {})
|
|
@@ -632,6 +671,11 @@ module PWN
|
|
|
632
671
|
call: 'optional - shell{command: uname -s} / tool:shell{command:id}'
|
|
633
672
|
)
|
|
634
673
|
|
|
674
|
+
# Resolve audited read resources; unknown tools are exclusive barriers.
|
|
675
|
+
#{self}.scheduling(
|
|
676
|
+
tool_call: 'required - tool call with function name and arguments'
|
|
677
|
+
)
|
|
678
|
+
|
|
635
679
|
# Run effect and return its result
|
|
636
680
|
#{self}.effect(
|
|
637
681
|
name: 'required - binary or identifier name',
|