Module: Alap::LinkProvenance

Defined in:
lib/alap/link_provenance.rb

Overview

Provenance tier stamping — Ruby port of src/core/linkProvenance.ts.

Links carry a provenance tier (where they came from) so downstream sanitizers can apply strictness matched to the source’s trustworthiness.

Tiers, loosest to strictest:

- "author"          — link came from the developer's hand-written config
- "storage:local"   — loaded from a local storage adapter
- "storage:remote"  — loaded from a remote config server
- "protocol:<name>" — returned by a protocol handler

TypeScript stores the stamp in a WeakMap keyed on runtime object identity so an attacker-writable “.provenance” field on an incoming link cannot pre-stamp itself for free. Ruby Hashes are hashable but use structural equality, making identity-based WeakMaps awkward; this port instead stamps a reserved “_provenance” key on the link Hash directly. The safety property is preserved through the whitelist in ValidateConfig: each link is built from a fixed set of known field names, and “_provenance” is stamped after the whitelist step. An incoming config carrying its own “_provenance” field is filtered out by the whitelist before stamping.

Constant Summary collapse

PROVENANCE_KEY =

Reserved key. The ValidateConfig whitelist intentionally excludes this key so it cannot be pre-stamped from untrusted input.

"_provenance"
VALID_SINGLETONS =
Set.new(%w[author storage:local storage:remote]).freeze

Class Method Summary collapse

Class Method Details

.author_tier?(link) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/alap/link_provenance.rb', line 55

def self.author_tier?(link)
  link[PROVENANCE_KEY] == "author"
end

.clone_to(src, dest) ⇒ Object

Copy the provenance stamp from src to dest. No-op if src is unstamped.



71
72
73
74
# File 'lib/alap/link_provenance.rb', line 71

def self.clone_to(src, dest)
  prov = src[PROVENANCE_KEY]
  dest[PROVENANCE_KEY] = prov if prov.is_a?(String)
end

.get(link) ⇒ Object

Read a link’s provenance tier, or nil if unstamped.



50
51
52
53
# File 'lib/alap/link_provenance.rb', line 50

def self.get(link)
  value = link[PROVENANCE_KEY]
  value.is_a?(String) ? value : nil
end

.protocol_tier?(link) ⇒ Boolean

Returns:

  • (Boolean)


64
65
66
67
# File 'lib/alap/link_provenance.rb', line 64

def self.protocol_tier?(link)
  prov = link[PROVENANCE_KEY]
  prov.is_a?(String) && prov.start_with?("protocol:")
end

.stamp(link, tier) ⇒ Object

Stamp link with its provenance tier. Overwrites any existing stamp.



39
40
41
42
43
44
45
46
47
# File 'lib/alap/link_provenance.rb', line 39

def self.stamp(link, tier)
  unless tier.is_a?(String) &&
         (VALID_SINGLETONS.include?(tier) || tier.start_with?("protocol:"))
    raise ArgumentError,
          "Invalid provenance tier: #{tier.inspect}. Must be one of " \
          "\"author\", \"storage:local\", \"storage:remote\", or \"protocol:<name>\"."
  end
  link[PROVENANCE_KEY] = tier
end

.storage_tier?(link) ⇒ Boolean

Returns:

  • (Boolean)


59
60
61
62
# File 'lib/alap/link_provenance.rb', line 59

def self.storage_tier?(link)
  prov = link[PROVENANCE_KEY]
  prov == "storage:local" || prov == "storage:remote"
end