Class: Clickwrap::Import::Legacy
- Inherits:
-
Object
- Object
- Clickwrap::Import::Legacy
- Defined in:
- lib/clickwrap/import/legacy.rb
Overview
Clickwrap.import_legacy! — bring an accepted_terms_at column, a
bespoke audit table, or any other pre-Clickwrap record into the event log
without inventing anything that was never recorded.
=========================================================================== The governing rule: HISTORICAL WEAKNESS STAYS VISIBLE RATHER THAN BEING LAUNDERED INTO MODERN CERTAINTY.
An import is the single easiest place in this gem to manufacture evidence by accident. Every field a modern capture fills in is sitting right there with an obvious plausible value: the current Terms text, today's document digest, the submit-button label from the current view, the assertion sentence from the current policy, an IP address from the user's last session. Writing any of them here would produce a row that is indistinguishable from a real capture and is, in the parts that matter, a fabrication.
So this importer NEVER synthesizes:
* a presentation manifest — nobody signed one, and there is no offer to
reproduce;
* an assertion — we do not know the sentence the old system offered;
* submit-button text — we do not know what the control said;
* an IP address or browser user-agent — these were not observed by us,
and a later session's address is a different fact about a different
request;
* document bytes or a digest — unless the caller can point at a version
that is actually published here.
Every key the caller lists in unknown: is recorded explicitly as unknown
in a structured field on the event, AND said in plain words in the
assertion text of each statement — which is inside the digested canonical
body, so the admission travels with the evidence rather than beside it.
The event also keeps occurred_at (when it happened, according to the old
record) strictly separate from recorded_at_by_server (when we wrote it
down). That gap is a fact about the evidence and it stays visible.
Defined Under Namespace
Classes: Result
Constant Summary collapse
- PERMITTED_CHANNELS =
The capture channels an import may claim.
imported_providermeans the record came from another system;systemmeans this application wrote it without a human at a keyboard. Neither isweb_browser, because no browser was involved and a receipt that said otherwise would be wrong. %w[imported_provider system].freeze
- CONVENTIONAL_UNKNOWN_KEYS =
Naming an unknown as unknown is the whole point, so the vocabulary is open: a host may list any key it wants. These are the ones the README and the FinePrint importer use, kept here so a typo in a migration script is at least visibly a typo next to its neighbours.
%w[ exact_document_bytes document_version presentation presentation_manifest assertion submit_button_text protected_action request_evidence ip_address browser_user_agent capture_channel authentication_context ].freeze
Instance Attribute Summary collapse
-
#actor ⇒ Object
readonly
Returns the value of attribute actor.
-
#because ⇒ Object
readonly
Returns the value of attribute because.
-
#capture_channel ⇒ Object
readonly
Returns the value of attribute capture_channel.
-
#counts_as_current ⇒ Object
readonly
Returns the value of attribute counts_as_current.
-
#dry_run ⇒ Object
readonly
Returns the value of attribute dry_run.
-
#known ⇒ Object
readonly
Returns the value of attribute known.
-
#occurred_at ⇒ Object
readonly
Returns the value of attribute occurred_at.
-
#policy ⇒ Object
readonly
Returns the value of attribute policy.
-
#source ⇒ Object
readonly
Returns the value of attribute source.
-
#subject ⇒ Object
readonly
Returns the value of attribute subject.
-
#tenant ⇒ Object
readonly
Returns the value of attribute tenant.
-
#unknown ⇒ Object
readonly
Returns the value of attribute unknown.
Instance Method Summary collapse
-
#idempotency_key ⇒ Object
The derived key.
- #import! ⇒ Object (also: #call)
-
#initialize(policy:, actor:, occurred_at:, because:, known: {}, unknown: [], dry_run: false, subject: nil, tenant: nil, statements: nil, capture_channel: "imported_provider", source: nil, counts_as_current: true) ⇒ Legacy
constructor
A new instance of Legacy.
Constructor Details
#initialize(policy:, actor:, occurred_at:, because:, known: {}, unknown: [], dry_run: false, subject: nil, tenant: nil, statements: nil, capture_channel: "imported_provider", source: nil, counts_as_current: true) ⇒ Legacy
Returns a new instance of Legacy.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/clickwrap/import/legacy.rb', line 83 def initialize(policy:, actor:, occurred_at:, because:, known: {}, unknown: [], dry_run: false, subject: nil, tenant: nil, statements: nil, capture_channel: "imported_provider", source: nil, counts_as_current: true) @policy = policy @actor = actor @occurred_at = coerce_time(occurred_at) @because = because.to_s @known = normalize_known(known) @unknown = normalize_unknown(unknown) @dry_run = dry_run @subject = subject @tenant = tenant @statement_keys = statements&.map(&:to_s) @capture_channel = capture_channel.to_s @source = source&.to_s @counts_as_current = counts_as_current == true end |
Instance Attribute Details
#actor ⇒ Object (readonly)
Returns the value of attribute actor.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def actor @actor end |
#because ⇒ Object (readonly)
Returns the value of attribute because.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def because @because end |
#capture_channel ⇒ Object (readonly)
Returns the value of attribute capture_channel.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def capture_channel @capture_channel end |
#counts_as_current ⇒ Object (readonly)
Returns the value of attribute counts_as_current.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def counts_as_current @counts_as_current end |
#dry_run ⇒ Object (readonly)
Returns the value of attribute dry_run.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def dry_run @dry_run end |
#known ⇒ Object (readonly)
Returns the value of attribute known.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def known @known end |
#occurred_at ⇒ Object (readonly)
Returns the value of attribute occurred_at.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def occurred_at @occurred_at end |
#policy ⇒ Object (readonly)
Returns the value of attribute policy.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def policy @policy end |
#source ⇒ Object (readonly)
Returns the value of attribute source.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def source @source end |
#subject ⇒ Object (readonly)
Returns the value of attribute subject.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def subject @subject end |
#tenant ⇒ Object (readonly)
Returns the value of attribute tenant.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def tenant @tenant end |
#unknown ⇒ Object (readonly)
Returns the value of attribute unknown.
102 103 104 |
# File 'lib/clickwrap/import/legacy.rb', line 102 def unknown @unknown end |
Instance Method Details
#idempotency_key ⇒ Object
The derived key. Two runs of the same migration script over the same legacy row produce the same key, so re-running an import is a no-op rather than a second history for the same person.
It covers what the legacy record actually said: who, which policy, which
subject and tenant, when it happened, and every known: value. Change
any of those and it is a different import, which is correct — a
different claim deserves a different event rather than silently
colliding with the first one.
127 128 129 |
# File 'lib/clickwrap/import/legacy.rb', line 127 def idempotency_key @idempotency_key ||= "imported_legacy:#{Digest.hex(CanonicalJson.generate(identity_body))}" end |
#import! ⇒ Object Also known as: call
105 106 107 108 109 110 111 112 113 114 |
# File 'lib/clickwrap/import/legacy.rb', line 105 def import! validate! existing = Event.find_by(policy_key: policy.key, idempotency_key: idempotency_key) return already_imported(existing) if existing return planned if dry_run write! end |