pwn 0.5.642 → 0.5.647

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.
data/lib/pwn/config.rb CHANGED
@@ -49,7 +49,22 @@ module PWN
49
49
  system_role_content: 'You are an ethically hacking OpenAI agent.',
50
50
  temp: 'optional - OpenAI temperature',
51
51
  max_tokens: 'optional - Max output tokens per response (default 16384). Mapped to OpenAI wire param max_completion_tokens.',
52
- max_prompt_length: 128_000
52
+ max_prompt_length: 128_000,
53
+ # OAuth support for ChatGPT / Codex subscriptions (in addition to API key)
54
+ # Populate via pwn-vault (values stored encrypted in ~/.pwn/pwn.yaml)
55
+ oauth: {
56
+ # OpenAI OAuth uses the PUBLIC Codex client (app_EMoamEEZ73f0CkXaXp7hrann) --
57
+ # NO client_secret. Run PWN::AI::OpenAI.obtain_oauth_bearer_token once
58
+ # (Codex device-code flow) then store refresh_token here; PWN refreshes
59
+ # the short-lived access_token automatically on every run.
60
+ refresh_token: 'optional - ChatGPT/Codex OAuth Refresh Token (durable; enables silent re-auth)',
61
+ bearer_token: 'optional - ChatGPT/Codex OAuth Access Token (short-lived JWT; auto-refreshed if refresh_token set)',
62
+ client_id: 'optional - override public Codex client_id (default: app_EMoamEEZ73f0CkXaXp7hrann)',
63
+ account_id: 'optional - ChatGPT account/workspace id (sent as ChatGPT-Account-Id when set)',
64
+ issuer: 'optional - override OAuth issuer (default: https://auth.openai.com)',
65
+ token_uri: 'optional - override OAuth token endpoint (default: https://auth.openai.com/oauth/token)',
66
+ enroll: 'optional - set true to force device-flow enrollment even when an API key is present'
67
+ }
53
68
  },
54
69
  ollama: {
55
70
  base_uri: 'required - Base URI for Open WebUI - e.g. https://ollama.local',
@@ -77,7 +92,25 @@ module PWN
77
92
  system_role_content: 'You are an ethically hacking Anthropic agent.',
78
93
  temp: 'optional - Anthropic temperature',
79
94
  max_tokens: 'optional - Max output tokens per response (default 8192). Raise if tool calls truncate.',
80
- max_prompt_length: 200_000
95
+ max_prompt_length: 200_000,
96
+ # OAuth support for Claude Pro/Max subscriptions (in addition to API key)
97
+ # Populate via pwn-vault (values stored encrypted in ~/.pwn/pwn.yaml)
98
+ oauth: {
99
+ # Anthropic OAuth uses the PUBLIC Claude Code client
100
+ # (9d1c250a-e61b-44d9-88ed-5944d1962f5e) -- NO client_secret.
101
+ # Run PWN::AI::Anthropic.obtain_oauth_bearer_token once (PKCE paste
102
+ # flow) then store refresh_token here; PWN refreshes the short-lived
103
+ # access_token automatically on every run.
104
+ refresh_token: 'optional - Claude Pro/Max OAuth Refresh Token (durable; enables silent re-auth)',
105
+ bearer_token: 'optional - Claude Pro/Max OAuth Access Token (short-lived; auto-refreshed if refresh_token set)',
106
+ client_id: 'optional - override public Claude Code client_id (default: 9d1c250a-e61b-44d9-88ed-5944d1962f5e)',
107
+ scope: 'optional - override OAuth scope (default: user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload)',
108
+ authorize_uri: 'optional - override authorize endpoint (default: https://claude.ai/oauth/authorize)',
109
+ token_uri: 'optional - override token endpoint (default: https://platform.claude.com/v1/oauth/token)',
110
+ redirect_uri: 'optional - override redirect_uri (default: https://platform.claude.com/oauth/code/callback)',
111
+ beta_flags: 'optional - anthropic-beta header value for OAuth requests',
112
+ enroll: 'optional - set true to force PKCE enrollment even when an API key is present'
113
+ }
81
114
  },
82
115
  gemini: {
83
116
  base_uri: 'optional - Base URI for Gemini - Use private base OR defaults to https://generativelanguage.googleapis.com/v1beta',
@@ -416,13 +449,16 @@ module PWN
416
449
  key = nil unless real_cfg.call(key)
417
450
 
418
451
  oauth_configured = false
419
- if engine == :grok
452
+ if %i[grok openai anthropic].include?(engine)
420
453
  oauth = env[:ai][engine][:oauth]
421
454
  oauth = env[:ai][engine][:oauth] = {} unless oauth.is_a?(Hash)
422
- # OAuth is considered configured when either a bearer_token is
423
- # stored (preferred, long-lived) OR client_id + client_secret are
424
- # present (PWN::AI::Grok will run the singular enrollment flow).
455
+ # OAuth is considered configured when a bearer_token / refresh_token
456
+ # is stored, enroll is truthy, or a non-placeholder client_id is set
457
+ # (module will run the singular enrollment flow).
425
458
  oauth_configured = real_cfg.call(oauth[:bearer_token]) ||
459
+ real_cfg.call(oauth[:refresh_token]) ||
460
+ oauth[:enroll] == true ||
461
+ real_cfg.call(oauth[:client_id]) ||
426
462
  (real_cfg.call(oauth[:client_id]) && real_cfg.call(oauth[:client_secret]))
427
463
  end
428
464
 
@@ -433,9 +469,14 @@ module PWN
433
469
  interactive = $stdin.tty? && $stdout.tty? && ENV['PWN_NONINTERACTIVE'].to_s.empty?
434
470
 
435
471
  if key.nil? && !oauth_configured && interactive
436
- key = PWN::Plugins::AuthenticationHelper.mask_password(
437
- prompt: "#{engine} API Key (or store ai.grok.oauth.refresh_token via pwn-vault -- run PWN::AI::Grok.obtain_oauth_bearer_token to enroll)"
438
- )
472
+ enroll_hints = {
473
+ grok: 'or store ai.grok.oauth.refresh_token via pwn-vault -- run PWN::AI::Grok.obtain_oauth_bearer_token to enroll',
474
+ openai: 'or store ai.openai.oauth.refresh_token via pwn-vault -- run PWN::AI::OpenAI.obtain_oauth_bearer_token to enroll',
475
+ anthropic: 'or store ai.anthropic.oauth.refresh_token via pwn-vault -- run PWN::AI::Anthropic.obtain_oauth_bearer_token to enroll'
476
+ }
477
+ enroll_hint = enroll_hints[engine]
478
+ prompt = enroll_hint ? "#{engine} API Key (#{enroll_hint})" : "#{engine} API Key"
479
+ key = PWN::Plugins::AuthenticationHelper.mask_password(prompt: prompt)
439
480
  env[:ai][engine][:key] = key
440
481
  end
441
482
 
data/lib/pwn/cron.rb CHANGED
@@ -231,8 +231,11 @@ module PWN
231
231
  )
232
232
  end
233
233
 
234
- # P3 — backfill ORM/PRM labels when local :failure_only introspect is on
235
- unless names.include?('curriculum_offline_judge')
234
+ # P3 — backfill ORM/PRM labels when local :failure_only introspect is on.
235
+ # P13 — treat legacy alias offline_judge_nightly as the same job so
236
+ # install_defaults never double-seeds the 30 3 * * * slot.
237
+ offline_names = %w[curriculum_offline_judge offline_judge_nightly]
238
+ unless names.intersect?(offline_names)
236
239
  seeded << create(
237
240
  name: 'curriculum_offline_judge',
238
241
  schedule: '30 3 * * *',
@@ -241,6 +244,15 @@ module PWN
241
244
  enabled: true
242
245
  )
243
246
  end
247
+ # Disable duplicate alias if both exist (idempotent cleanup).
248
+ if names.include?('curriculum_offline_judge') && names.include?('offline_judge_nightly')
249
+ begin
250
+ dup = jobs.values.find { |j| j[:name].to_s == 'offline_judge_nightly' }
251
+ disable(id: dup[:id]) if dup && dup[:enabled]
252
+ rescue StandardError
253
+ nil
254
+ end
255
+ end
244
256
 
245
257
  # M1/M3 — nightly memory GC so the injected MEMORY block stays high-signal
246
258
  unless names.include?('learning_consolidate_nightly')
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.5.642'
4
+ VERSION = '0.5.647'
5
5
  end