pwn 0.5.631 → 0.5.632
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/.github/workflows/install-matrix.yml +177 -0
- data/.rubocop.yml +1 -1
- data/Gemfile +3 -3
- data/README.md +2 -2
- data/bin/pwn_autoinc_version +0 -20
- data/documentation/Configuration.md +39 -4
- data/documentation/Extrospection.md +61 -10
- data/documentation/Installation.md +5 -5
- data/documentation/Reinforcement-Learning.md +123 -0
- data/documentation/pwn-ai-Agent.md +1 -1
- data/etc/osint/social_sites.json +116 -0
- data/install.sh +27 -18
- data/lib/pwn/ai/agent/curriculum.rb +561 -0
- data/lib/pwn/ai/agent/extrospection/osint/bridges.rb +240 -0
- data/lib/pwn/ai/agent/extrospection/osint/social.rb +405 -0
- data/lib/pwn/ai/agent/extrospection.rb +81 -11
- data/lib/pwn/ai/agent/learning.rb +187 -39
- data/lib/pwn/ai/agent/loop.rb +62 -19
- data/lib/pwn/ai/agent/metrics.rb +172 -2
- data/lib/pwn/ai/agent/mistakes.rb +54 -5
- data/lib/pwn/ai/agent/registry.rb +19 -9
- data/lib/pwn/ai/agent/reward.rb +523 -0
- data/lib/pwn/ai/agent/tools/curriculum.rb +95 -0
- data/lib/pwn/ai/agent/tools/extrospection.rb +9 -4
- data/lib/pwn/ai/agent/tools/reward.rb +117 -0
- data/lib/pwn/ai/agent.rb +2 -0
- data/lib/pwn/config.rb +11 -2
- data/lib/pwn/cron.rb +39 -0
- data/lib/pwn/memory.rb +15 -4
- data/lib/pwn/memory_index.rb +12 -1
- data/lib/pwn/version.rb +1 -1
- data/packer/provisioners/pwn.sh +57 -93
- data/spec/documentation/installation_md_spec.rb +173 -0
- data/spec/documentation/prompt_version_placeholder_spec.rb +37 -0
- data/spec/integration/fresh_install_spec.rb +73 -0
- data/spec/integration/install_doc.sh +79 -0
- data/spec/integration/reinforced_feedback_loop_spec.rb +453 -0
- data/spec/lib/pwn/ai/agent/curriculum_spec.rb +56 -0
- data/spec/lib/pwn/ai/agent/extrospection/osint/bridges_spec.rb +24 -0
- data/spec/lib/pwn/ai/agent/extrospection/osint/social_spec.rb +36 -0
- data/spec/lib/pwn/ai/agent/extrospection_spec.rb +68 -0
- data/spec/lib/pwn/ai/agent/learning_spec.rb +1 -1
- data/spec/lib/pwn/ai/agent/reward_spec.rb +58 -0
- data/spec/lib/pwn/ai/agent/tools/curriculum_spec.rb +18 -0
- data/spec/lib/pwn/ai/agent/tools/reward_spec.rb +14 -0
- data/third_party/pwn_rdoc.jsonl +107 -2
- metadata +27 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5bea724f1a504fa45e1f4eaa786761599a75e08a07b5848327b1dafd61dbe6f2
|
|
4
|
+
data.tar.gz: 9a4e693fe7b54d7477896d78272fb5c87a42deb5719730489a0a623eb39230dd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3998a8a58340cdf1c8b4a9ba9a57a8fe9fb7a749117a606f65b643996ec343606692d5382f71ccd6e119ceac6f995047092bdd87f2e14e8e575b1a306ee29b1f
|
|
7
|
+
data.tar.gz: c10128b60319de27d0404c18289b91dd40ca78ca18df522e788c6b2a968e85c8b71c49c2447ef6eee268538787c1b09ba786a303a9fe8eb5198912eb4834ab90
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# .github/workflows/install-matrix.yml
|
|
2
|
+
#
|
|
3
|
+
# Layer 3 of the Installation.md verification strategy: prove the
|
|
4
|
+
# fresh-host install path ("gem install pwn && pwn setup") on clean
|
|
5
|
+
# images for every distro / package manager the doc claims to support,
|
|
6
|
+
# then assert the result *via rspec* so failures read like the rest of
|
|
7
|
+
# the test suite.
|
|
8
|
+
#
|
|
9
|
+
# Layers 1 & 2 (doc↔code parity, behavioural contracts) live in
|
|
10
|
+
# spec/documentation/installation_md_spec.rb.
|
|
11
|
+
# Layer 3's functional assertions live in
|
|
12
|
+
# spec/integration/fresh_install_spec.rb and only activate when
|
|
13
|
+
# PWN_FRESH_INSTALL is set — this workflow sets it, `rake` on a
|
|
14
|
+
# developer box does not.
|
|
15
|
+
#
|
|
16
|
+
# This is world-drift, not repo-drift — distro package names change
|
|
17
|
+
# upstream — so it also runs nightly.
|
|
18
|
+
name: install-matrix
|
|
19
|
+
|
|
20
|
+
on:
|
|
21
|
+
push:
|
|
22
|
+
paths:
|
|
23
|
+
- 'lib/pwn/setup.rb'
|
|
24
|
+
- 'bin/pwn_setup'
|
|
25
|
+
- 'bin/pwn'
|
|
26
|
+
- 'documentation/Installation.md'
|
|
27
|
+
- 'install.sh'
|
|
28
|
+
- 'packer/provisioners/pwn.sh'
|
|
29
|
+
- 'pwn.gemspec'
|
|
30
|
+
- '.github/workflows/install-matrix.yml'
|
|
31
|
+
- 'spec/documentation/installation_md_spec.rb'
|
|
32
|
+
- 'spec/integration/**'
|
|
33
|
+
pull_request:
|
|
34
|
+
paths:
|
|
35
|
+
- 'lib/pwn/setup.rb'
|
|
36
|
+
- 'bin/pwn_setup'
|
|
37
|
+
- 'bin/pwn'
|
|
38
|
+
- 'documentation/Installation.md'
|
|
39
|
+
- 'install.sh'
|
|
40
|
+
- 'packer/provisioners/pwn.sh'
|
|
41
|
+
- 'pwn.gemspec'
|
|
42
|
+
- 'spec/documentation/installation_md_spec.rb'
|
|
43
|
+
- 'spec/integration/**'
|
|
44
|
+
schedule:
|
|
45
|
+
- cron: '17 4 * * *' # nightly — catch upstream distro package-name drift
|
|
46
|
+
workflow_dispatch:
|
|
47
|
+
|
|
48
|
+
jobs:
|
|
49
|
+
linux:
|
|
50
|
+
name: ${{ matrix.image }} / ${{ matrix.pm }} / ${{ matrix.profile }}
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
container:
|
|
53
|
+
image: ${{ matrix.image }}
|
|
54
|
+
strategy:
|
|
55
|
+
fail-fast: false
|
|
56
|
+
matrix:
|
|
57
|
+
# Base axes → 5 images × 2 profiles = 10 legs.
|
|
58
|
+
image:
|
|
59
|
+
- kalilinux/kali-rolling
|
|
60
|
+
- debian:bookworm
|
|
61
|
+
- ubuntu:24.04
|
|
62
|
+
- fedora:latest
|
|
63
|
+
- archlinux:latest
|
|
64
|
+
profile:
|
|
65
|
+
- core
|
|
66
|
+
- net
|
|
67
|
+
# `include` here EXTENDS each base combo whose `image` matches
|
|
68
|
+
# with the per-distro pm + ruby-bootstrap command; it does NOT
|
|
69
|
+
# add new combos. (Putting these under `include` alone with a
|
|
70
|
+
# separate top-level `profile:` would collapse to 2 legs — the
|
|
71
|
+
# bug this rewrite fixes.)
|
|
72
|
+
include:
|
|
73
|
+
- image: kalilinux/kali-rolling
|
|
74
|
+
pm: apt
|
|
75
|
+
ruby: apt-get update && apt-get install -y ruby-full ruby-dev build-essential git
|
|
76
|
+
- image: debian:bookworm
|
|
77
|
+
pm: apt
|
|
78
|
+
ruby: apt-get update && apt-get install -y ruby-full ruby-dev build-essential git
|
|
79
|
+
- image: ubuntu:24.04
|
|
80
|
+
pm: apt
|
|
81
|
+
ruby: apt-get update && apt-get install -y ruby-full ruby-dev build-essential git
|
|
82
|
+
- image: fedora:latest
|
|
83
|
+
pm: dnf
|
|
84
|
+
ruby: dnf install -y ruby ruby-devel redhat-rpm-config gcc gcc-c++ make git
|
|
85
|
+
- image: archlinux:latest
|
|
86
|
+
pm: pacman
|
|
87
|
+
ruby: pacman -Sy --noconfirm ruby base-devel git
|
|
88
|
+
env:
|
|
89
|
+
DEBIAN_FRONTEND: noninteractive
|
|
90
|
+
PWN_FRESH_INSTALL: '1'
|
|
91
|
+
PWN_EXPECTED_PM: ${{ matrix.pm }}
|
|
92
|
+
PWN_PROFILE: ${{ matrix.profile }}
|
|
93
|
+
steps:
|
|
94
|
+
- name: bootstrap ruby (${{ matrix.pm }})
|
|
95
|
+
run: ${{ matrix.ruby }}
|
|
96
|
+
|
|
97
|
+
- name: checkout
|
|
98
|
+
uses: actions/checkout@v4
|
|
99
|
+
|
|
100
|
+
- name: build & install gem from checkout (git-checkout path in doc)
|
|
101
|
+
run: |
|
|
102
|
+
gem build pwn.gemspec
|
|
103
|
+
gem install --no-document ./pwn-*.gem
|
|
104
|
+
gem install --no-document rspec
|
|
105
|
+
ruby -r pwn -e 'puts "pwn #{PWN::VERSION} ruby #{RUBY_VERSION} #{RUBY_PLATFORM}"'
|
|
106
|
+
|
|
107
|
+
- name: dry-run — every package name resolves for this distro
|
|
108
|
+
run: pwn setup --profile full --dry-run --yes
|
|
109
|
+
|
|
110
|
+
- name: provision profile (documentation/Installation.md verbatim)
|
|
111
|
+
run: pwn setup --profile ${{ matrix.profile }} --yes
|
|
112
|
+
|
|
113
|
+
- name: rspec — doc↔code parity + behavioural + fresh-install functional
|
|
114
|
+
run: |
|
|
115
|
+
rspec --format documentation \
|
|
116
|
+
spec/documentation/installation_md_spec.rb \
|
|
117
|
+
spec/integration/fresh_install_spec.rb
|
|
118
|
+
|
|
119
|
+
macos:
|
|
120
|
+
name: macos / brew / core
|
|
121
|
+
runs-on: macos-latest
|
|
122
|
+
env:
|
|
123
|
+
PWN_FRESH_INSTALL: '1'
|
|
124
|
+
PWN_EXPECTED_PM: brew
|
|
125
|
+
PWN_PROFILE: core
|
|
126
|
+
steps:
|
|
127
|
+
- uses: actions/checkout@v4
|
|
128
|
+
|
|
129
|
+
- uses: ruby/setup-ruby@v1
|
|
130
|
+
with:
|
|
131
|
+
ruby-version: '3.4'
|
|
132
|
+
|
|
133
|
+
- name: build & install gem from checkout
|
|
134
|
+
run: |
|
|
135
|
+
gem build pwn.gemspec
|
|
136
|
+
gem install --no-document ./pwn-*.gem
|
|
137
|
+
gem install --no-document rspec
|
|
138
|
+
|
|
139
|
+
- name: dry-run full profile
|
|
140
|
+
run: pwn setup --profile full --dry-run --yes
|
|
141
|
+
|
|
142
|
+
- name: provision core
|
|
143
|
+
run: pwn setup --profile core --yes
|
|
144
|
+
|
|
145
|
+
- name: rspec — doc↔code parity + behavioural + fresh-install functional
|
|
146
|
+
run: |
|
|
147
|
+
rspec --format documentation \
|
|
148
|
+
spec/documentation/installation_md_spec.rb \
|
|
149
|
+
spec/integration/fresh_install_spec.rb
|
|
150
|
+
|
|
151
|
+
git-checkout:
|
|
152
|
+
# "From a git checkout (contributors)" section of Installation.md —
|
|
153
|
+
# exercises packer/provisioners/pwn.sh end-to-end.
|
|
154
|
+
name: kali / git-checkout / packer-provisioner
|
|
155
|
+
runs-on: ubuntu-latest
|
|
156
|
+
container:
|
|
157
|
+
image: kalilinux/kali-rolling
|
|
158
|
+
env:
|
|
159
|
+
DEBIAN_FRONTEND: noninteractive
|
|
160
|
+
PWN_FRESH_INSTALL: '1'
|
|
161
|
+
PWN_EXPECTED_PM: apt
|
|
162
|
+
PWN_PROFILE: core
|
|
163
|
+
PWN_ROOT: ${{ github.workspace }}
|
|
164
|
+
steps:
|
|
165
|
+
- run: apt-get update && apt-get install -y ruby-full ruby-dev build-essential git
|
|
166
|
+
|
|
167
|
+
- uses: actions/checkout@v4
|
|
168
|
+
|
|
169
|
+
- name: run legacy provisioner (must delegate to `pwn setup`)
|
|
170
|
+
run: bash packer/provisioners/pwn.sh
|
|
171
|
+
|
|
172
|
+
- name: rspec — fresh-install functional
|
|
173
|
+
run: |
|
|
174
|
+
gem install --no-document rspec
|
|
175
|
+
rspec --format documentation \
|
|
176
|
+
spec/documentation/installation_md_spec.rb \
|
|
177
|
+
spec/integration/fresh_install_spec.rb
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
|
@@ -49,7 +49,7 @@ gem 'jwt', '3.2.0'
|
|
|
49
49
|
gem 'libusb', '0.7.2'
|
|
50
50
|
gem 'luhn', '3.0.0'
|
|
51
51
|
gem 'mail', '2.9.1'
|
|
52
|
-
gem 'mcp', '0.
|
|
52
|
+
gem 'mcp', '0.24.0'
|
|
53
53
|
gem 'meshtastic', '0.0.171'
|
|
54
54
|
gem 'metasm', '1.0.6'
|
|
55
55
|
gem 'mongo', '2.24.1'
|
|
@@ -89,8 +89,8 @@ 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.4'
|
|
92
|
-
gem 'selenium-devtools', '0.
|
|
93
|
-
gem 'selenium-webdriver', '4.
|
|
92
|
+
gem 'selenium-devtools', '0.150.0'
|
|
93
|
+
gem 'selenium-webdriver', '4.46.0'
|
|
94
94
|
gem 'slack-ruby-client', '3.2.0'
|
|
95
95
|
gem 'socksify', '1.8.1'
|
|
96
96
|
gem 'spreadsheet', '1.3.5'
|
data/README.md
CHANGED
|
@@ -113,7 +113,7 @@ $ gem install pwn
|
|
|
113
113
|
$ pwn setup # read-only doctor: which capabilities are usable?
|
|
114
114
|
$ pwn setup --profile full --yes # provision everything (or: web | net | sdr | vision | ...)
|
|
115
115
|
$ pwn
|
|
116
|
-
pwn[
|
|
116
|
+
pwn[CURRENT_VERSION]:001 >>> PWN.help
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
Only need a subset?
|
|
@@ -147,7 +147,7 @@ land regularly:
|
|
|
147
147
|
$ gem update pwn
|
|
148
148
|
$ pwn setup # re-doctor - new versions may add capabilities
|
|
149
149
|
$ pwn
|
|
150
|
-
pwn[
|
|
150
|
+
pwn[CURRENT_VERSION]:001 >>> PWN.help
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
From a git checkout:
|
data/bin/pwn_autoinc_version
CHANGED
|
@@ -36,23 +36,3 @@ File.open('./lib/pwn/version.rb', 'w') do |f|
|
|
|
36
36
|
f.puts " VERSION = '#{new_rev}'"
|
|
37
37
|
f.puts 'end'
|
|
38
38
|
end
|
|
39
|
-
|
|
40
|
-
# Update README.md
|
|
41
|
-
current_ruby_version = "ruby-#{File.read(current_ruby).chomp}"
|
|
42
|
-
old_readme_md = File.read(readme_md_path, encoding: 'utf-8')
|
|
43
|
-
pwn_regex = 'pwn\[v.+\..+\..+\]'
|
|
44
|
-
rb_regex = 'ruby-.+'
|
|
45
|
-
File.open(readme_md_path, 'w') do |file|
|
|
46
|
-
old_readme_md.each_line do |line|
|
|
47
|
-
if line.to_s.scrub.match?(/#{pwn_regex}/) ||
|
|
48
|
-
line.to_s.scrub.match?(/#{rb_regex}/)
|
|
49
|
-
|
|
50
|
-
new_line = line.to_s.gsub(/pwn\[v#{old_rev}\]/, "pwn\[v#{new_rev}\]") if line.to_s.scrub.match?(/#{pwn_regex}/)
|
|
51
|
-
new_line = line.to_s.gsub(/ruby-.+(?=(@))/, current_ruby_version) if line.to_s.scrub.match?(/#{rb_regex}/)
|
|
52
|
-
|
|
53
|
-
file.puts new_line
|
|
54
|
-
else
|
|
55
|
-
file.puts line
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -118,6 +118,29 @@ ai:
|
|
|
118
118
|
port: 7356 # GQRX remote-control port.
|
|
119
119
|
settle_secs: 8 # Seconds to sample RDS after tuning (max 30).
|
|
120
120
|
ttl: 300 # Observation TTL for :rf (songs change - keep short).
|
|
121
|
+
osint:
|
|
122
|
+
ttl: 86400 # Observation TTL for :osint (default 1 day).
|
|
123
|
+
proxy: ~ # Optional upstream proxy for OSINT HTTP feeds.
|
|
124
|
+
api_keys: # Per-feed API keys (all optional; keyed feeds return {skipped:} when absent). ENV fallbacks also honoured.
|
|
125
|
+
shodan: ... # ← SHODAN_API_KEY
|
|
126
|
+
hunter: ... # ← HUNTER_API_KEY
|
|
127
|
+
abuseipdb: ... # ← ABUSEIPDB_API_KEY
|
|
128
|
+
virustotal: ... # ← VIRUSTOTAL_API_KEY / VT_API_KEY
|
|
129
|
+
greynoise: ... # ← GREYNOISE_API_KEY
|
|
130
|
+
haveibeenpwned: ... # ← HIBP_API_KEY
|
|
131
|
+
securitytrails: ... # ← SECURITYTRAILS_API_KEY
|
|
132
|
+
steam: ... # ← STEAM_API_KEY
|
|
133
|
+
social:
|
|
134
|
+
sites_file: etc/osint/social_sites.json # Vendored sherlock-derived presence list used by :social_sweep. Override to extend.
|
|
135
|
+
max_threads: 16 # Concurrent presence checks in :social_sweep.
|
|
136
|
+
max_sites: 120 # Hard cap on sites read from sites_file.
|
|
137
|
+
timeout: 6 # Per-site HTTP timeout (seconds).
|
|
138
|
+
mastodon_instance: mastodon.social # Default Fediverse instance for a bare @handle.
|
|
139
|
+
bridges:
|
|
140
|
+
timeout: 120 # Per local-tool wall clock (seconds) for theHarvester/amass/spiderfoot/recon-ng.
|
|
141
|
+
theharvester_sources: anubis,crtsh,hackertarget,otx,rapiddns,urlscan,certspotter,dnsdumpster,duckduckgo
|
|
142
|
+
spiderfoot_modules: sfp_dnsresolve,sfp_crt,sfp_hackertarget,sfp_dnsdumpster,sfp_wayback,sfp_social
|
|
143
|
+
amass_passive: true # false → active enum (touches target DNS - OPSEC).
|
|
121
144
|
|
|
122
145
|
plugins:
|
|
123
146
|
asm:
|
|
@@ -178,10 +201,6 @@ cron:
|
|
|
178
201
|
|
|
179
202
|
targets: # Optional - engagement-scope URLs/hosts. Merged into :web snapshot anchors
|
|
180
203
|
- https://target.example.com # ONLY when ai.agent.extrospection.web.allow_targets: true.
|
|
181
|
-
| `ai.agent.extrospection.rf.host` | String | `127.0.0.1` | `Extrospection.rf_tune` | GQRX remote-control host for the RF sense organ. |
|
|
182
|
-
| `ai.agent.extrospection.rf.port` | Integer | `7356` | `Extrospection.rf_tune` | GQRX remote-control port. |
|
|
183
|
-
| `ai.agent.extrospection.rf.settle_secs` | Integer | `8` | `Extrospection.rf_tune` | Seconds to sample RDS after tuning (capped at 30). |
|
|
184
|
-
| `ai.agent.extrospection.rf.ttl` | Integer | `300` | `Extrospection.rf_tune` | TTL (seconds) for `:rf` observations written by `extro_rf_tune` (ephemeral radio content). |
|
|
185
204
|
```
|
|
186
205
|
|
|
187
206
|
---
|
|
@@ -250,6 +269,22 @@ PWN::Config.refresh_env
|
|
|
250
269
|
| `ai.agent.extrospection.web.per_page_timeout` | Integer | `15` | `Extrospection` (headless browser) | Seconds before a page render is abandoned. |
|
|
251
270
|
| `ai.agent.extrospection.web.screenshot` | Boolean | `false` | `Extrospection.probe_web` / `.watch` | Persist a PNG per anchor to `~/.pwn/extrospection/web/`. |
|
|
252
271
|
| `ai.agent.extrospection.web.allow_targets` | Boolean | `false` | `Extrospection.web_anchors` | Merge top-level `targets:` into the anchor list (opt-in - off by default to avoid touching in-scope hosts unprompted). |
|
|
272
|
+
| `ai.agent.extrospection.rf.host` | String | `127.0.0.1` | `Extrospection.rf_tune` | GQRX remote-control host for the RF sense organ. |
|
|
273
|
+
| `ai.agent.extrospection.rf.port` | Integer | `7356` | `Extrospection.rf_tune` | GQRX remote-control port. |
|
|
274
|
+
| `ai.agent.extrospection.rf.settle_secs` | Integer | `8` | `Extrospection.rf_tune` | Seconds to sample RDS after tuning (capped at 30). |
|
|
275
|
+
| `ai.agent.extrospection.rf.ttl` | Integer | `300` | `Extrospection.rf_tune` | TTL (seconds) for `:rf` observations written by `extro_rf_tune` (ephemeral radio content). |
|
|
276
|
+
| `ai.agent.extrospection.osint.ttl` | Integer | `86400` | `Extrospection.osint` | TTL (seconds) for `:osint` observations written by `extro_osint`. |
|
|
277
|
+
| `ai.agent.extrospection.osint.proxy` | String | - | `Extrospection.osint` | Optional upstream proxy for OSINT HTTP feeds. |
|
|
278
|
+
| `ai.agent.extrospection.osint.api_keys.<feed>` | String | - | `Extrospection.osint_api_keys` | Per-feed API keys for keyed OSINT sources: `shodan`, `hunter`, `abuseipdb`, `virustotal`, `greynoise`, `haveibeenpwned`, `securitytrails`, `steam`. Keyed feeds return `{skipped:}` when absent. ENV fallbacks (`SHODAN_API_KEY`, `HUNTER_API_KEY`, `ABUSEIPDB_API_KEY`, `VIRUSTOTAL_API_KEY`/`VT_API_KEY`, `GREYNOISE_API_KEY`, `HIBP_API_KEY`, `SECURITYTRAILS_API_KEY`, `STEAM_API_KEY`) also honoured. Redacted. |
|
|
279
|
+
| `ai.agent.extrospection.osint.social.sites_file` | Path | `etc/osint/social_sites.json` | `Extrospection.osint_social_sweep` | JSON of `{sites:{Name:{url:"...{u}...",absent_status:[404],absent_body:[...],head:bool}}}` used by the `:social_sweep` presence check. Vendored subset of sherlock-project (MIT). Override to add/remove platforms. |
|
|
280
|
+
| `ai.agent.extrospection.osint.social.max_threads` | Integer | `16` | `Extrospection.osint_social_sweep` | Concurrency for the presence sweep (`Concurrent::FixedThreadPool`). |
|
|
281
|
+
| `ai.agent.extrospection.osint.social.max_sites` | Integer | `120` | `Extrospection.osint_social_sweep` | Hard cap on sites loaded from `sites_file`. |
|
|
282
|
+
| `ai.agent.extrospection.osint.social.timeout` | Integer | `6` | `Extrospection` social feeds | Per-site / per-profile HTTP timeout (seconds). |
|
|
283
|
+
| `ai.agent.extrospection.osint.social.mastodon_instance` | String | `mastodon.social` | `Extrospection.osint_mastodon` | Default Fediverse instance when a bare `@handle` (no `@instance`) is queried. |
|
|
284
|
+
| `ai.agent.extrospection.osint.bridges.timeout` | Integer | `120` | `Extrospection` bridge feeds | Per local-tool wall clock for `:theharvester` / `:amass` / `:spiderfoot` / `:reconng`. |
|
|
285
|
+
| `ai.agent.extrospection.osint.bridges.theharvester_sources` | String | passive set | `Extrospection.osint_theharvester` | Comma-separated `-b` sources passed to theHarvester. |
|
|
286
|
+
| `ai.agent.extrospection.osint.bridges.spiderfoot_modules` | String | passive set | `Extrospection.osint_spiderfoot` | Comma-separated `-m` modules for the headless SpiderFoot CLI (`-o json -q`; web UI never launched). |
|
|
287
|
+
| `ai.agent.extrospection.osint.bridges.amass_passive` | Boolean | `true` | `Extrospection.osint_amass` | `false` → active enumeration (touches target DNS - OPSEC-sensitive). |
|
|
253
288
|
|
|
254
289
|
### `plugins` - module credentials & wiring
|
|
255
290
|
|
|
@@ -13,7 +13,7 @@ say when I need it for a better answer?"*
|
|
|
13
13
|
| Song on 101.1 FM (RDS) | **`extro_rf_tune(freq: "101.1")`** → RDS `now_playing` / `station` |
|
|
14
14
|
| CVE / Exploit-DB hit | `extro_intel` / `extro_verify(kind: :cve)` |
|
|
15
15
|
| Target DOM / TLS drift | `extro_watch(url:)` / `extro_snapshot(sections: [:web])` |
|
|
16
|
-
| Reverse phone / person / FCC ID / patent / IP pivot | **`extro_osint(query:)`** |
|
|
16
|
+
| Reverse phone / person / @handle sweep / FCC ID / patent / IP pivot | **`extro_osint(query:)`** |
|
|
17
17
|
| Serial / USB-UART / AT-modem banner | **`extro_serial`** |
|
|
18
18
|
| SIP / VoIP / BareSIP status or dial | **`extro_telecomm`** |
|
|
19
19
|
| Live capture / pcap summary | **`extro_packet`** |
|
|
@@ -81,7 +81,7 @@ Override / extend via `PWN::Env[:ai][:agent][:extrospection][:web][:anchors]`; s
|
|
|
81
81
|
| **`extro_watch`** | **Render a URL headless, hash the *rendered* DOM, screenshot, diff vs prior** | `observations[]` (`category: :web`) |
|
|
82
82
|
| **`extro_verify`** | **Browser-backed self fact-check of a claim (`:cve` `:version` `:doc` `:generic`) → `:confirmed`/`:refuted`/`:unknown`** | `Mistakes.record` / `observe(:intel)` / `Learning.note_outcome` |
|
|
83
83
|
| **`extro_rf_tune`** | **Tune running GQRX + demod + strength + RDS sample → `now_playing` / `station`** | `observations[]` (`category: :rf`, ttl 300s) |
|
|
84
|
-
| **`extro_osint`** | **Aggregate public OSINT APIs (phone / IP / domain / FCC ID / patent / VIN / MAC / callsign / person / company / SEC / CourtListener / Federal Register / UK Police / OTX / URLHaus / openFDA / NPPES / Nominatim / EPSS / CISA KEV / Microlink / vital records / Shodan / Hunter / AbuseIPDB / VT / HIBP / Wayback)** | `observations[]` (`category: :osint`) |
|
|
84
|
+
| **`extro_osint`** | **Aggregate public OSINT APIs (phone / IP / domain / FCC ID / patent / VIN / MAC / callsign / person / company / SEC / CourtListener / Federal Register / UK Police / OTX / URLHaus / openFDA / NPPES / Nominatim / EPSS / CISA KEV / Microlink / vital records / Shodan / Hunter / AbuseIPDB / VT / HIBP / Wayback) + social/identity feeds (Keybase / Gravatar / Mastodon / Bluesky / HN / StackExchange / npm / PyPI / RubyGems / crates / DockerHub / Codeberg / Steam / Telegram + ~100-site presence sweep) + local-tool bridges (theHarvester / spiderfoot / amass / recon-ng)** | `observations[]` (`category: :osint`) |
|
|
85
85
|
| **`extro_serial`** | **Open serial device · optional payload · drain response · disconnect** | `observations[]` (`category: :serial`) |
|
|
86
86
|
| **`extro_telecomm`** | **BareSIP inventory / status / dial / hangup (never launches baresip)** | `observations[]` (`category: :telecomm`) |
|
|
87
87
|
| **`extro_packet`** | **Inventory · bounded live capture · pcap summarise (tshark/PacketFu)** | `observations[]` (`category: :packet`) |
|
|
@@ -185,14 +185,15 @@ unreachable endpoints return `{error:...}` instead of raising.
|
|
|
185
185
|
|---|---|---|
|
|
186
186
|
| `:ip` | IPv4 / IPv6 | ip · geo · ipapi_is · iplocate · ipwhois · dns · rdap · bgpview · otx · abuseipdb · greynoise · shodan · hackertarget |
|
|
187
187
|
| `:geo` | street-like address / geo query | geo · nominatim · ip |
|
|
188
|
-
| `:domain` / `:dns` / `:whois` / `:rdap` | FQDN | dns · whois · rdap · crtsh · certspotter · wayback · otx · urlhaus · urlscan · shodan · securitytrails · hackertarget |
|
|
188
|
+
| `:domain` / `:dns` / `:whois` / `:rdap` | FQDN | dns · whois · rdap · crtsh · certspotter · wayback · otx · urlhaus · urlscan · shodan · securitytrails · hackertarget · theharvester · amass |
|
|
189
189
|
| `:url` | `http(s)://...` | urlscan · otx · urlhaus · wayback · microlink · virustotal |
|
|
190
|
-
| `:email` | `a@b.c` | hunter · person · github · haveibeenpwned |
|
|
190
|
+
| `:email` | `a@b.c` | hunter · person · github · haveibeenpwned · gravatar · keybase |
|
|
191
191
|
| `:phone` | E.164 / NANP | phone · person |
|
|
192
192
|
| `:fcc_id` | `2ABIP-ESP32` style | fcc_id |
|
|
193
193
|
| `:patent` | `US10123456` / `patent ...` | patent |
|
|
194
194
|
| `:person` | `Jane Doe` | person · username · github · open_sanctions · agify · genderize · nationalize · vital_records |
|
|
195
|
-
| `:username` / `:github` |
|
|
195
|
+
| `:username` / `:github` | bare `handle` / `gh:` | username · github · keybase · hackernews · social_sweep |
|
|
196
|
+
| `:social` | `@handle` / `@user@instance` (Fediverse) | keybase · gravatar · mastodon · bluesky · hackernews · stackexchange · npm · pypi · rubygems · crates · dockerhub · codeberg · sourcehut · chesscom · lichess · steam · telegram · github · social_sweep |
|
|
196
197
|
| `:company` | `... Inc.` / `LLC` / `Ltd` | opencorporates · sec_edgar · federal_register · person · courtlistener |
|
|
197
198
|
| `:cik` | 10-digit CIK | sec_edgar · opencorporates |
|
|
198
199
|
| `:vital_records` | birth/death/marriage keywords | vital_records · person |
|
|
@@ -220,7 +221,7 @@ unreachable endpoints return `{error:...}` instead of raising.
|
|
|
220
221
|
| `:fcc_id` | fccid.io · device.report · fcc.gov OET | grantee/product, MHz excerpts |
|
|
221
222
|
| `:patent` | Google Patents HTML + PatentsView API | title, number, assignee, date |
|
|
222
223
|
| `:person` | Wikipedia · Wikidata · OpenSanctions + NamUs/FBI/Charley targets | missing-person pivot plan |
|
|
223
|
-
| `:username` / `:github` | GitHub · GitLab · Reddit public APIs | profile pivots |
|
|
224
|
+
| `:username` / `:github` | GitHub · GitLab · Reddit public APIs | legacy 3-platform profile pivots (kept for back-compat) |
|
|
224
225
|
| `:wayback` | archive.org availability + CDX | snapshots |
|
|
225
226
|
| `:otx` | AlienVault OTX indicators + passive DNS | IP/domain/url |
|
|
226
227
|
| `:urlhaus` | abuse.ch URLHaus host/url API | malware distribution URLs |
|
|
@@ -253,7 +254,27 @@ unreachable endpoints return `{error:...}` instead of raising.
|
|
|
253
254
|
| `:agify` / `:genderize` / `:nationalize` | agify.io · genderize.io · nationalize.io | First-name age/gender/nationality estimates |
|
|
254
255
|
| `:haveibeenpwned` | haveibeenpwned.com v3 | Breach membership - **needs** `HIBP_API_KEY` |
|
|
255
256
|
| `:securitytrails` | api.securitytrails.com | Domain DNS history - **needs** `SECURITYTRAILS_API_KEY` |
|
|
256
|
-
|
|
257
|
+
| `:keybase` | keybase.io lookup API | **crypto-proven** cross-links (Twitter/GitHub/DNS/PGP) → highest-confidence pivots |
|
|
258
|
+
| `:gravatar` | gravatar.com profile JSON | email → md5 → username, verified accounts, bio, urls |
|
|
259
|
+
| `:mastodon` | `<instance>/api/v1/accounts/lookup` + WebFinger | Fediverse identity; instance defaults to `mastodon.social` |
|
|
260
|
+
| `:bluesky` | public.api.bsky.app `getProfile` | DID, handle, followers, bio |
|
|
261
|
+
| `:hackernews` | hn.algolia.com users + submissions | karma, about, recent posts |
|
|
262
|
+
| `:stackexchange` | api.stackexchange.com users?inname= | rep, location, website |
|
|
263
|
+
| `:npm` | registry.npmjs.org user + maintainer search | packages, email, GitHub/Twitter |
|
|
264
|
+
| `:pypi` | pypi.org/user/ (HTML) | packages maintained |
|
|
265
|
+
| `:rubygems` | rubygems.org owners/gems API | gems, downloads, homepage |
|
|
266
|
+
| `:crates` | crates.io users API | login, name, url |
|
|
267
|
+
| `:dockerhub` | hub.docker.com v2 users + repos | full_name, company, images |
|
|
268
|
+
| `:codeberg` | codeberg.org Gitea API | login, full_name, website, location |
|
|
269
|
+
| `:sourcehut` | sr.ht/~user (presence) | HTTP presence check |
|
|
270
|
+
| `:chesscom` / `:lichess` | api.chess.com · lichess.org/api | real name, country, timezone leak |
|
|
271
|
+
| `:steam` | steamcommunity.com XML / ISteamUser | vanity → SteamID64, persona; **key upgrades** to ISteamUser |
|
|
272
|
+
| `:telegram` | t.me/<user> og:meta scrape | display name, description (200 always → body-heuristic) |
|
|
273
|
+
| `:social_sweep` | `etc/osint/social_sites.json` (~100 sites, MIT-vendored from sherlock-project) | Concurrent HEAD/GET presence sweep via `Concurrent::FixedThreadPool`; ≤0.5 confidence (soft-404s possible) |
|
|
274
|
+
| `:theharvester` | **local bin** `theHarvester -b <sources> -f json` | domain → hosts, emails, IPs, ASNs (passive sources only) |
|
|
275
|
+
| `:amass` | **local bin** `amass enum -passive -json` | domain → subdomains + resolved addresses |
|
|
276
|
+
| `:spiderfoot` | **local bin** `spiderfoot -s <t> -m <mods> -o json -q` | headless CLI events grouped by type; web UI never launched |
|
|
277
|
+
| `:reconng` | **local bin** `recon-ng -r <resource>` | domain → hosts via hackertarget + CT modules; workspace auto-cleaned |
|
|
257
278
|
> Feed selection inspired by [public-api-lists/public-api-lists](https://github.com/public-api-lists/public-api-lists) (Anti-Malware, Security, Geocoding, Government, Health, Open Data, Vehicle, Development).
|
|
258
279
|
|
|
259
280
|
### Examples
|
|
@@ -294,6 +315,18 @@ extro_osint(query: "CVE-2021-44228")
|
|
|
294
315
|
|
|
295
316
|
extro_osint(query: "8.8.8.8", feeds: ["ipapi_is", "iplocate", "greynoise", "abuseipdb"])
|
|
296
317
|
→ multi-source IP threat/geo (keyed feeds skip cleanly when no key)
|
|
318
|
+
|
|
319
|
+
extro_osint(query: "@defunkt")
|
|
320
|
+
→ kind=:social · Keybase proofs + Bluesky DID + HN karma + npm/RubyGems/DockerHub + ~100-site sweep
|
|
321
|
+
|
|
322
|
+
extro_osint(query: "@gargron@mastodon.social")
|
|
323
|
+
→ kind=:social · Fediverse WebFinger + Mastodon profile
|
|
324
|
+
|
|
325
|
+
extro_osint(query: "defunkt", feeds: ["social_sweep"], limit: 50)
|
|
326
|
+
→ Sherlock-mode presence sweep only (107 sites, ~10-15 s @ 16 threads)
|
|
327
|
+
|
|
328
|
+
extro_osint(query: "target.tld", feeds: ["theharvester", "amass"])
|
|
329
|
+
→ local-tool bridges: passive subdomain + email harvest (skips cleanly if bins absent)
|
|
297
330
|
```
|
|
298
331
|
|
|
299
332
|
Configure:
|
|
@@ -308,12 +341,26 @@ PWN::Env[:ai][:agent][:extrospection][:osint] = {
|
|
|
308
341
|
virustotal: '...',
|
|
309
342
|
greynoise: '...',
|
|
310
343
|
haveibeenpwned: '...',
|
|
311
|
-
securitytrails: '...'
|
|
344
|
+
securitytrails: '...',
|
|
345
|
+
steam: '...'
|
|
346
|
+
},
|
|
347
|
+
social: {
|
|
348
|
+
sites_file: '/opt/pwn/etc/osint/social_sites.json', # override / extend the vendored sherlock-derived list
|
|
349
|
+
max_threads: 16, # concurrent presence checks in :social_sweep
|
|
350
|
+
max_sites: 120, # cap sites read from sites_file
|
|
351
|
+
timeout: 6, # per-site HTTP timeout (seconds)
|
|
352
|
+
mastodon_instance: 'mastodon.social' # default Fediverse instance for bare @handle
|
|
353
|
+
},
|
|
354
|
+
bridges: {
|
|
355
|
+
timeout: 120, # per-tool wall clock (seconds)
|
|
356
|
+
theharvester_sources: 'anubis,crtsh,hackertarget,otx,rapiddns,urlscan,certspotter,dnsdumpster,duckduckgo',
|
|
357
|
+
spiderfoot_modules: 'sfp_dnsresolve,sfp_crt,sfp_hackertarget,sfp_dnsdumpster,sfp_wayback,sfp_social',
|
|
358
|
+
amass_passive: true # false → active enum (touches target DNS)
|
|
312
359
|
}
|
|
313
360
|
}
|
|
314
361
|
# ENV fallbacks also accepted:
|
|
315
362
|
# SHODAN_API_KEY, HUNTER_API_KEY, ABUSEIPDB_API_KEY, VIRUSTOTAL_API_KEY,
|
|
316
|
-
# GREYNOISE_API_KEY, HIBP_API_KEY, SECURITYTRAILS_API_KEY
|
|
363
|
+
# GREYNOISE_API_KEY, HIBP_API_KEY, SECURITYTRAILS_API_KEY, STEAM_API_KEY
|
|
317
364
|
```
|
|
318
365
|
|
|
319
366
|
|
|
@@ -481,6 +528,10 @@ use **Chicago** so the catalog stays portable.
|
|
|
481
528
|
- "Any prior litigation or SEC 8-K breach filings for `Target Corp` before we disclose?"
|
|
482
529
|
- "Wayback the old `/admin` path - did an earlier deploy expose a debug console?"
|
|
483
530
|
- "Pivot `@lead-dev` across GitHub/GitLab - hardcoded secrets in personal repos?"
|
|
531
|
+
- "Sweep `@lead-dev` across ~100 socials - which platforms reuse that handle, and does Keybase crypto-prove any of them?"
|
|
532
|
+
- "Gravatar `alice@target.tld` - what username, avatar and verified accounts leak from that email?"
|
|
533
|
+
- "Which npm / PyPI / RubyGems / DockerHub packages does `@maintainer` own - supply-chain blast radius?"
|
|
534
|
+
- "Run theHarvester + amass (passive) against `target.tld` and merge with our crt.sh subdomains."
|
|
484
535
|
|
|
485
536
|
### Serial / hardware sense organ (`extro_serial`)
|
|
486
537
|
|
|
@@ -571,7 +622,7 @@ use **Chicago** so the catalog stays portable.
|
|
|
571
622
|
| Pattern | Likely tools |
|
|
572
623
|
|---|---|
|
|
573
624
|
| "tune / MHz / FM / RDS / ISM / key-fob / pager / ADS-B" | `extro_rf_tune` |
|
|
574
|
-
| "subdomain / CT log / ASN / whois / FCC ID / VIN / MAC OUI / EPSS / KEV / Wayback / pivot @user" | `extro_osint` |
|
|
625
|
+
| "subdomain / CT log / ASN / whois / FCC ID / VIN / MAC OUI / EPSS / KEV / Wayback / pivot @user / Keybase / Gravatar / social sweep / theHarvester / amass" | `extro_osint` |
|
|
575
626
|
| "UART / ttyUSB / U-Boot / AT command / Flipper / JTAG banner" | `extro_serial` |
|
|
576
627
|
| "SIP / PBX / IVR / BareSIP / dial / hangup" | `extro_telecomm` |
|
|
577
628
|
| "capture on iface / summarise pcap / mDNS / Modbus / RTSP creds" | `extro_packet` |
|
|
@@ -31,7 +31,7 @@ pwn # launch the REPL
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
```text
|
|
34
|
-
pwn[
|
|
34
|
+
pwn[CURRENT_VERSION]:001 >>> PWN.help
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
If you only need a subset (e.g. web testing on a CI runner, SDR on a lab
|
|
@@ -228,10 +228,10 @@ Docker, Packer, Vagrant, CI) picks it up automatically.
|
|
|
228
228
|
## Verify
|
|
229
229
|
|
|
230
230
|
```ruby
|
|
231
|
-
pwn[
|
|
232
|
-
pwn[
|
|
233
|
-
pwn[
|
|
234
|
-
pwn[
|
|
231
|
+
pwn[CURRENT_VERSION]:001 >>> PWN::Setup.check[:ok] # => true
|
|
232
|
+
pwn[CURRENT_VERSION]:002 >>> PWN::Plugins.constants.count # => 66
|
|
233
|
+
pwn[CURRENT_VERSION]:003 >>> PWN::SAST.constants.count # => 48
|
|
234
|
+
pwn[CURRENT_VERSION]:004 >>> pwn-ai # launches agent TUI
|
|
235
235
|
```
|
|
236
236
|
|
|
237
237
|
**Next:** [Configuration](Configuration.md) · [General Usage](General-PWN-Usage.md)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Reinforcement Learning in pwn-ai
|
|
2
|
+
|
|
3
|
+
pwn-ai implements a **six-tier** in-context → weight-level RL loop that
|
|
4
|
+
surpasses every published LLM-agent harness (Reflexion, Voyager, ExpeL,
|
|
5
|
+
LATS, Generative Agents, PRM, RLAIF, DPO, Self-Refine, Toolformer, DSPy)
|
|
6
|
+
on at least one axis, and on **five axes simultaneously** for the full
|
|
7
|
+
`Curriculum.practice → Reward.export_dpo → Curriculum.train_and_gate` path.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌────────────────────────────────────────────────┐
|
|
11
|
+
request ──────►│ Loop.run │
|
|
12
|
+
│ plan_first ─► Curriculum.red_team_plan (S4) │
|
|
13
|
+
│ Dispatch ──► Reward.semantic_ok (R4) │
|
|
14
|
+
│ └► Mistakes.record(cause:) (E1) │
|
|
15
|
+
│ guard ────► Curriculum.counterfactual (S2) │──► Reward.record_preference (W1)
|
|
16
|
+
│ final ────► Curriculum.critic (S3) │
|
|
17
|
+
│ └► Reward.judge (ORM) (R1) │──► Reward.verify_as_reward (E3)
|
|
18
|
+
│ └► Reward.prm (PRM) (R2) │──► Sessions[step_reward] (C4)
|
|
19
|
+
│ └► Curriculum.hindsight (C3) │
|
|
20
|
+
│ └► Curriculum.calibrate (W3) │──► Metrics.calibration
|
|
21
|
+
│ └► Reward.sentinel (R3) │──► Mistakes(reward_signal)
|
|
22
|
+
└────────────────────────────────────────────────┘
|
|
23
|
+
│
|
|
24
|
+
Learning.consolidate (M1 semantic-merge, M3 importance-evict)
|
|
25
|
+
MemoryIndex.recall_semantic (M2 sim × recency × importance)
|
|
26
|
+
Registry.rank (C1 α·sim + β·advantage + γ·UCB)
|
|
27
|
+
Learning.exemplars_for (C2 prioritized replay, C4 minimal trace)
|
|
28
|
+
│
|
|
29
|
+
nightly cron ──► Curriculum.practice (S1) ──► Mistakes.resolve ──► preference (W1)
|
|
30
|
+
weekly cron ──► Curriculum.train_and_gate (W2) ──► LoRA vN+1 ──► A/B gate ──► promote
|
|
31
|
+
│
|
|
32
|
+
Extrospection.correlate rule 9 (E2 causal lead-lag)
|
|
33
|
+
Metrics.changepoints (E1 CUSUM) ──► Mistakes(cause: :env_drift)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Tier 1 — Reward signal (`PWN::AI::Agent::Reward`)
|
|
37
|
+
|
|
38
|
+
| ID | Method | What it does | Beats |
|
|
39
|
+
|----|--------|-------------|-------|
|
|
40
|
+
| **R1** | `.judge` | LLM Outcome Reward Model → `{score:0..1, verdict:, rationale:, key_step:}`. Replaces `infer_success` regex. | Reflexion (binary self-eval) |
|
|
41
|
+
| **R2** | `.prm` | Process Reward Model — per-tool-step `+1/0/−1` written into `Sessions[:step_reward]`. | Lightman '23 (math only) — first PRM on security tooling |
|
|
42
|
+
| **R3** | `.sentinel` | proxy vs judge vs (1 − user_correction_rate); >0.15 gap → `Mistakes.record(tool:'reward_signal')`. | — novel |
|
|
43
|
+
| **R4** | `.semantic_ok` | `grep exit 1` ≠ failure. `Loop.record_metrics` records Metrics on `:ok`, Mistakes on `!semantic_ok`. Kills phantom `31f1871b8a15`. | — bugfix |
|
|
44
|
+
|
|
45
|
+
## Tier 2 — Credit assignment & replay
|
|
46
|
+
|
|
47
|
+
| ID | Where | What |
|
|
48
|
+
|----|-------|------|
|
|
49
|
+
| **C1** | `Registry.rank` + `Metrics.{ucb,thompson,advantage}` | score = α·keyword_sim + β·advantage + γ·UCB1. Untried tools get exploration bonus. |
|
|
50
|
+
| **C2** | `Learning.exemplars_for` | priority = judge_score × e^(−Δt/30d) × keyword_sim. |
|
|
51
|
+
| **C3** | `Curriculum.hindsight` | HER — relabel failed trajectory with achieved-goal as `success:true`. |
|
|
52
|
+
| **C4** | `Learning.{compress_exemplar,build_skill_from_session}` | keep only `step_reward > 0` — minimal sufficient trace. |
|
|
53
|
+
|
|
54
|
+
## Tier 3 — Memory that stays high-signal
|
|
55
|
+
|
|
56
|
+
| ID | Where | What |
|
|
57
|
+
|----|-------|------|
|
|
58
|
+
| **M1** | `Learning.consolidate` → `semantic_merge` | embed `:lesson`, greedy cosine ≥0.92, `Reflect.on("merge → 1 imperative")`. |
|
|
59
|
+
| **M2** | `MemoryIndex.recall_semantic` | score = 0.6·sim + 0.25·recency + 0.15·importance (Park '23). |
|
|
60
|
+
| **M3** | `Memory.remember(source:,confidence:,importance:,ttl:)` | consolidate evicts by `(age/ttl)/(importance×confidence)` — heuristic garbage self-evicts. |
|
|
61
|
+
| **M4** | `Learning.note_outcome` | outcomes → `learning.jsonl` ONLY. Memory `:lesson` reserved for reflect/resolve/human. `purge_noise` GCs pre-R1 garbage. |
|
|
62
|
+
|
|
63
|
+
## Tier 4 — Curriculum & self-play (`PWN::AI::Agent::Curriculum`)
|
|
64
|
+
|
|
65
|
+
| ID | Method | What |
|
|
66
|
+
|----|--------|------|
|
|
67
|
+
| **S1** | `.practice` | mine `Mistakes.top` → generate reproducers → self-play → auto-`resolve` on judge≥0.7. |
|
|
68
|
+
| **S2** | `.counterfactual` | fork alt-persona branch on REPEAT_THRESHOLD, judge both, `(loser,winner)` → DPO pair. |
|
|
69
|
+
| **S3** | `.critic` | tool-armed constitutional critic (can `shell`/`extro_verify` the claim). |
|
|
70
|
+
| **S4** | `.red_team_plan` | adversarial plan review grounded in Metrics/Mistakes/extro_drift telemetry. |
|
|
71
|
+
|
|
72
|
+
## Tier 5 — Close the weight loop
|
|
73
|
+
|
|
74
|
+
| ID | Where | What |
|
|
75
|
+
|----|-------|------|
|
|
76
|
+
| **W1** | `Reward.{record_preference,export_dpo}` | 5 free preference sources: user_correction, mistakes_resolve, counterfactual, curriculum, critic. |
|
|
77
|
+
| **W2** | `Curriculum.train_and_gate` | SFT+DPO → unsloth/axolotl LoRA → `ollama create pwn-vN+1` → replay `Mistakes.top` on vN vs vN+1 → promote iff `resolved(N+1) > resolved(N)`. |
|
|
78
|
+
| **W3** | `Curriculum.calibrate` + `Metrics.{record_calibration,calibration}` | plan_first `p(success)` vs actual → per-engine Brier/overconfidence. |
|
|
79
|
+
|
|
80
|
+
## Tier 6 — Deepen the intro↔extro join
|
|
81
|
+
|
|
82
|
+
| ID | Where | What |
|
|
83
|
+
|----|-------|------|
|
|
84
|
+
| **E1** | `Metrics.changepoints` (CUSUM) + `Loop.attribute_cause` | env-drift-attributed failures tagged `cause: :env_drift`, do NOT count toward `[REPEATING]`. |
|
|
85
|
+
| **E2** | `Extrospection.correlate` rule 9 | lead-lag: "nmap started failing 2.1h AFTER toolchain.nmap changed" with confidence. |
|
|
86
|
+
| **E3** | `Reward.verify_as_reward` | browser-verified verdict caps/floors judge score. Ground-truth reward without a human. |
|
|
87
|
+
|
|
88
|
+
## Config (`PWN::Env[:ai][:agent]`)
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
:ai:
|
|
92
|
+
:agent:
|
|
93
|
+
:critic: true # S3
|
|
94
|
+
:red_team_plan: true # S4
|
|
95
|
+
:counterfactual: true # S2
|
|
96
|
+
:hindsight: true # C3 (default true)
|
|
97
|
+
:verify_as_reward: true # E3
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Cron self-improvement
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
PWN::Cron.create(name: 'self_play', schedule: '0 3 * * *',
|
|
104
|
+
ruby: 'PWN::AI::Agent::Curriculum.practice(limit: 5)')
|
|
105
|
+
PWN::Cron.create(name: 'weight_loop', schedule: '0 4 * * 0',
|
|
106
|
+
ruby: 'PWN::AI::Agent::Curriculum.train_and_gate(dry_run: false)')
|
|
107
|
+
PWN::Cron.create(name: 'mem_gc', schedule: '0 5 * * *',
|
|
108
|
+
ruby: 'PWN::AI::Agent::Learning.consolidate')
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Tools exposed to the model
|
|
112
|
+
|
|
113
|
+
`reward_judge` · `reward_prm` · `reward_sentinel` · `reward_preferences` ·
|
|
114
|
+
`reward_export_dpo` · `curriculum_practice` · `curriculum_train` ·
|
|
115
|
+
`curriculum_hindsight` · `learning_purge_noise`
|
|
116
|
+
|
|
117
|
+
## What no other harness does simultaneously
|
|
118
|
+
|
|
119
|
+
1. **Process reward on real security tool traces** (R2)
|
|
120
|
+
2. **Automatic blame attribution** self vs env-drift via CUSUM×correlate (E1+E2)
|
|
121
|
+
3. **Reward-hacking self-detection** (R3)
|
|
122
|
+
4. **Mistake-driven curriculum with regression-gated LoRA promotion** (S1+W2)
|
|
123
|
+
5. **Five naturally-generated DPO sources** with zero human labelling (W1)
|
|
@@ -10,7 +10,7 @@ a final answer - **learning from every failure so it doesn't repeat it**.
|
|
|
10
10
|
|
|
11
11
|
```text
|
|
12
12
|
# 1. Interactive TUI (inside the pwn REPL)
|
|
13
|
-
pwn[
|
|
13
|
+
pwn[CURRENT_VERSION]:001 >>> pwn-ai
|
|
14
14
|
✨ pwn-ai · anthropic · session 20260707_225041_d7f2f3bb
|
|
15
15
|
> Use NmapIt to sweep 10.0.0.0/24, then TransparentBrowser via Burp on any
|
|
16
16
|
host with 443 open, active-scan, and give me a Reports::SAST summary.
|