Module: Legion::LLM::Fleet::TokenIssuer

Defined in:
lib/legion/llm/fleet/token_issuer.rb

Constant Summary collapse

ISSUER =
'legion-llm'
AUDIENCE =
'lex-llm-fleet-worker'
ALGORITHM =
'HS256'

Class Method Summary collapse

Class Method Details

.algorithmObject



96
97
98
# File 'lib/legion/llm/fleet/token_issuer.rb', line 96

def algorithm
  auth_setting(:algorithm, default: ALGORITHM)
end

.audienceObject



92
93
94
# File 'lib/legion/llm/fleet/token_issuer.rb', line 92

def audience
  auth_setting(:audience, default: AUDIENCE)
end

.auth_setting(key, default:) ⇒ Object



100
101
102
103
# File 'lib/legion/llm/fleet/token_issuer.rb', line 100

def auth_setting(key, default:)
  val = Legion::Settings[:llm][:fleet][:auth][key]
  val.nil? ? default : val
end

.issue(payload) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/legion/llm/fleet/token_issuer.rb', line 21

def issue(payload)
  ttl = token_ttl_seconds
  now = Time.now.to_i
  claims = required_claims(payload).merge(
    iss: issuer,
    aud: audience,
    iat: now,
    exp: now + ttl,
    nbf: now,
    jti: "fleet-jti-#{SecureRandom.uuid}"
  )

  jwt_module.issue(
    claims,
    signing_key: signing_key,
    ttl:         ttl,
    issuer:      issuer,
    algorithm:   algorithm
  )
rescue TokenError
  raise
rescue StandardError => e
  raise TokenError, "failed to issue fleet token: #{e.message}"
end

.issuerObject



88
89
90
# File 'lib/legion/llm/fleet/token_issuer.rb', line 88

def issuer
  auth_setting(:issuer, default: ISSUER)
end

.jwt_moduleObject

Raises:



116
117
118
119
120
121
# File 'lib/legion/llm/fleet/token_issuer.rb', line 116

def jwt_module
  require_crypt!
  return Legion::Crypt::JWT if defined?(Legion::Crypt::JWT) && Legion::Crypt::JWT.respond_to?(:issue)

  raise TokenError, 'Legion::Crypt::JWT.issue unavailable'
end

.require_crypt!Object

Raises:



123
124
125
126
127
# File 'lib/legion/llm/fleet/token_issuer.rb', line 123

def require_crypt!
  return if defined?(Legion::Crypt)

  raise TokenError, 'Legion::Crypt is required for fleet token issuance'
end

.required_claims(payload) ⇒ Object

Raises:



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/legion/llm/fleet/token_issuer.rb', line 46

def required_claims(payload)
  payload = symbolize_keys(payload || {})
  claims = {}
  %i[
    request_id correlation_id idempotency_key operation provider provider_instance
    model reply_to message_context
  ].each do |key|
    value = payload[key]
    raise TokenError, "missing token claim source: #{key}" if value.nil?

    claims[key] = value
  end
  %i[params caller trace_context timeout_seconds expires_at].each do |key|
    value = payload[key]
    raise TokenError, "missing token claim source: #{key}" if value.nil?

    claims[key] = value
  end
  # S3: every request is exact (06 P2) — the exact signed scalar
  # claims are verified unconditionally on the worker, so they are
  # issued unconditionally. The marker-absence branch is deleted.
  execution_contract = payload[:execution_contract]
  if execution_contract.nil?
    raise TokenError,
          'missing token claim source: execution_contract (fleet protocol v3 is exact-execution only)'
  end
  unless execution_contract == ::Legion::Extensions::Llm::Fleet::Protocol::EXACT_EXECUTION_CONTRACT
    raise TokenError, "unknown fleet execution_contract marker: #{execution_contract.inspect}"
  end

  offering_id = payload[:offering_id]
  raise TokenError, 'missing token claim source: nonempty String offering_id (exact execution)' unless offering_id.is_a?(String) && !offering_id.strip.empty?

  claims[:execution_contract] = execution_contract
  claims[:offering_id] = offering_id
  claims
end

.signing_keyObject



105
106
107
108
109
110
111
112
113
114
# File 'lib/legion/llm/fleet/token_issuer.rb', line 105

def signing_key
  require_crypt!
  return Legion::Crypt.cluster_secret if Legion::Crypt.respond_to?(:cluster_secret)

  raise TokenError, 'no signing key available - Legion::Crypt not initialized'
rescue TokenError
  raise
rescue StandardError => e
  raise TokenError, "no signing key available: #{e.message}"
end

.symbolize_keys(hash) ⇒ Object



129
130
131
132
133
# File 'lib/legion/llm/fleet/token_issuer.rb', line 129

def symbolize_keys(hash)
  hash.each_with_object({}) do |(key, value), result|
    result[key.respond_to?(:to_sym) ? key.to_sym : key] = value
  end
end

.token_ttl_secondsObject



84
85
86
# File 'lib/legion/llm/fleet/token_issuer.rb', line 84

def token_ttl_seconds
  Integer(Legion::Settings[:llm][:fleet][:dispatch][:token_ttl_seconds])
end