Class: Legion::Extensions::Llm::Inventory::PublisherToken

Inherits:
Object
  • Object
show all
Defined in:
lib/legion/extensions/llm/inventory/probe_token.rb

Overview

An opaque fenced publisher claim token. The raw secret is never serialized, logged, included in a record/snapshot/exception, returned separately, or compared for order. publisher_id and publisher_token_id are safe correlation/fencing values derived from the secret. See phase-1-lex-llm-additive.md section 11.1.

Constant Summary collapse

TOKEN_ID_DOMAIN =
"publisher-token-id-v1\x00"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(instance_key:, secret:, publisher_id:, publisher_token_id:) ⇒ PublisherToken

Returns a new instance of PublisherToken.



36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/legion/extensions/llm/inventory/probe_token.rb', line 36

def initialize(instance_key:, secret:, publisher_id:, publisher_token_id:)
  raise Errors::ValidationError, 'instance_key must be an InstanceKey' unless instance_key.is_a?(Identity::InstanceKey)
  raise Errors::ValidationError, 'secret must be a nonempty String' unless nonempty_string?(secret)
  raise Errors::ValidationError, 'publisher_id must be a pub:v1: String' unless publisher_id.to_s.start_with?('pub:v1:')
  raise Errors::ValidationError, 'publisher_token_id must be a ptok:v1: String' unless publisher_token_id.to_s.start_with?('ptok:v1:')

  @instance_key = instance_key
  @secret = secret.b.dup.freeze
  @publisher_id = publisher_id.dup.freeze
  @publisher_token_id = publisher_token_id.dup.freeze
  freeze
end

Instance Attribute Details

#instance_keyObject (readonly)

Returns the value of attribute instance_key.



20
21
22
# File 'lib/legion/extensions/llm/inventory/probe_token.rb', line 20

def instance_key
  @instance_key
end

#publisher_idObject (readonly)

Returns the value of attribute publisher_id.



20
21
22
# File 'lib/legion/extensions/llm/inventory/probe_token.rb', line 20

def publisher_id
  @publisher_id
end

#publisher_token_idObject (readonly)

Returns the value of attribute publisher_token_id.



20
21
22
# File 'lib/legion/extensions/llm/inventory/probe_token.rb', line 20

def publisher_token_id
  @publisher_token_id
end

Class Method Details

.derive_token_id(secret) ⇒ Object



22
23
24
# File 'lib/legion/extensions/llm/inventory/probe_token.rb', line 22

def self.derive_token_id(secret)
  "ptok:v1:#{::Digest::SHA256.hexdigest(TOKEN_ID_DOMAIN.b + secret.b)}"
end

.issue(instance_key:) ⇒ Object

Factory used by the registry: builds a fresh secret and derives the public correlation IDs from it.



28
29
30
31
32
33
34
# File 'lib/legion/extensions/llm/inventory/probe_token.rb', line 28

def self.issue(instance_key:)
  secret = ::SecureRandom.hex(32)
  new(
    instance_key: instance_key, secret: secret,
    publisher_id: "pub:v1:#{::SecureRandom.uuid}", publisher_token_id: derive_token_id(secret)
  )
end

Instance Method Details

#authenticates?(other) ⇒ Boolean

Fenced validation: same InstanceKey, same public token ID, and a constant-time equal-length secret comparison using a local XOR accumulator (no ActiveSupport).

Returns:

  • (Boolean)


52
53
54
55
56
57
# File 'lib/legion/extensions/llm/inventory/probe_token.rb', line 52

def authenticates?(other)
  other.is_a?(PublisherToken) &&
    instance_key == other.instance_key &&
    publisher_token_id == other.publisher_token_id &&
    secrets_match?(other)
end

#inspectObject Also known as: to_s



59
60
61
62
# File 'lib/legion/extensions/llm/inventory/probe_token.rb', line 59

def inspect
  "#<#{self.class.name} instance_key=#{@instance_key.inspect} " \
    "publisher_id=#{@publisher_id} publisher_token_id=#{@publisher_token_id} secret=[REDACTED]>"
end