Class: Clickwrap::PolicyRevision

Inherits:
ApplicationRecord show all
Defined in:
lib/clickwrap/models/policy_revision.rb

Overview

A frozen snapshot of one compiled policy.

Policies are written in Ruby because that is what a reviewer can read in a pull request. But an export has to stay intelligible after the source has moved on, so the first time a revision is offered or captured its compiled form is written here and never changed. An event points at the revision it was captured under, so a receipt explains itself without a checkout of the application at the right commit.

The revision digest covers declared structure and copy. Host callables — subject fingerprints, protected-outcome recorders — are recorded as present rather than serialized, because a lambda's body cannot be canonicalized. That boundary is stated in the receipt rather than papered over.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.freeze_for(policy) ⇒ Object

Finds or freezes the revision for a compiled policy. Called on the first presentation and again at capture; both are races that the unique index settles, so a lost race just reads the row the winner wrote.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/clickwrap/models/policy_revision.rb', line 42

def self.freeze_for(policy)
  existing = find_by(policy_key: policy.key, revision_digest: policy.revision)
  return existing if existing

  create!(
    policy_key: policy.key,
    revision_digest: policy.revision,
    compiled_snapshot: policy.snapshot,
    retention_class_key: policy.retention_class_key,
    canonical_schema_version: Clickwrap::CANONICAL_SCHEMA_VERSION,
    gem_version: Clickwrap::VERSION,
    compiled_at: Clickwrap.now,
    created_at: Clickwrap.now
  )
rescue ActiveRecord::RecordNotUnique
  find_by!(policy_key: policy.key, revision_digest: policy.revision)
end

.freeze_legacy_import_for(policy, source:, statements:, known:, unknown:) ⇒ Object

Freezes the semantics of a legacy mapping without pretending the old act used the policy revision loaded today. The snapshot names only what the importer actually knows: source, mapped statements, known facts, and unknown facts. It intentionally cannot match policy.revision, so require_current_revision: true always asks for a modern presentation.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/clickwrap/models/policy_revision.rb', line 65

def self.freeze_legacy_import_for(policy, source:, statements:, known:, unknown:)
  snapshot = {
    "schema" => Clickwrap::CANONICAL_SCHEMA_VERSION,
    "policy" => policy.key,
    "revision_kind" => "legacy_import_mapping",
    "source" => source.presence,
    "statements" => statements.map { |statement| { "key" => statement.key, "kind" => statement.kind } },
    "known" => known,
    "unknown" => unknown,
    "retention_class" => policy.retention_class_key
  }.compact
  digest = Digest.digest_canonical(snapshot)
  existing = find_by(policy_key: policy.key, revision_digest: digest)
  return existing if existing

  create!(
    policy_key: policy.key,
    revision_digest: digest,
    compiled_snapshot: snapshot,
    retention_class_key: policy.retention_class_key,
    canonical_schema_version: Clickwrap::CANONICAL_SCHEMA_VERSION,
    gem_version: Clickwrap::VERSION,
    compiled_at: Clickwrap.now,
    created_at: Clickwrap.now
  )
rescue ActiveRecord::RecordNotUnique
  find_by!(policy_key: policy.key, revision_digest: digest)
end

Instance Method Details

#matches_loaded_policy?Boolean

True when the currently loaded policy compiles to this same revision. A false is not an error — it means the policy has been edited since, which is exactly why the snapshot is here.

Returns:

  • (Boolean)


97
98
99
# File 'lib/clickwrap/models/policy_revision.rb', line 97

def matches_loaded_policy?
  Clickwrap.policies[policy_key]&.revision == revision_digest
end

#statement_snapshot(statement_key) ⇒ Object



101
102
103
# File 'lib/clickwrap/models/policy_revision.rb', line 101

def statement_snapshot(statement_key)
  Array(compiled_snapshot["statements"]).find { |s| s["key"] == statement_key.to_s }
end

#to_sObject



105
# File 'lib/clickwrap/models/policy_revision.rb', line 105

def to_s = "#{policy_key}@#{revision_digest}"