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
- .author_tier?(link) ⇒ Boolean
-
.clone_to(src, dest) ⇒ Object
Copy the provenance stamp from
srctodest. -
.get(link) ⇒ Object
Read a link’s provenance tier, or
nilif unstamped. - .protocol_tier?(link) ⇒ Boolean
-
.stamp(link, tier) ⇒ Object
Stamp
linkwith its provenance tier. - .storage_tier?(link) ⇒ Boolean
Class Method Details
.author_tier?(link) ⇒ Boolean
55 56 57 |
# File 'lib/alap/link_provenance.rb', line 55 def self.(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
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
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 |