Class: Clickwrap::Policy
- Inherits:
-
Object
- Object
- Clickwrap::Policy
- Defined in:
- lib/clickwrap/policy.rb
Overview
A compiled, frozen policy: what the server will present and what it will accept back.
The browser may answer a policy. It may never choose one. Policy key, revision, document versions, validity, subject binding, retention, and request-evidence fields are all resolved server-side and rechecked at submit, because every one of them is a security decision and a form field is not a safe place to keep one.
A policy's revision is the digest of its compiled snapshot. Publishing
freezes that snapshot in the database the first time the policy is
presented or captured, so a receipt written today still explains itself
after the Ruby source has moved on. The digest covers declared structure and
copy; host lambdas (subject fingerprints, protected-outcome recorders) are
recorded as present rather than serialized, since their bodies cannot be
canonicalized. That boundary is stated in the receipt rather than papered
over.
Instance Attribute Summary collapse
-
#authority_rule ⇒ Object
readonly
Returns the value of attribute authority_rule.
-
#capture_channels ⇒ Object
readonly
Returns the value of attribute capture_channels.
-
#key ⇒ Object
readonly
Returns the value of attribute key.
-
#locales ⇒ Object
readonly
Returns the value of attribute locales.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#persist_presentations_because ⇒ Object
readonly
Returns the value of attribute persist_presentations_because.
-
#persist_presentations_for ⇒ Object
readonly
Returns the value of attribute persist_presentations_for.
-
#request_evidence ⇒ Object
readonly
Returns the value of attribute request_evidence.
-
#retention_class_key ⇒ Object
readonly
Returns the value of attribute retention_class_key.
-
#revision ⇒ Object
readonly
Returns the value of attribute revision.
-
#snapshot ⇒ Object
readonly
Returns the value of attribute snapshot.
-
#statements ⇒ Object
readonly
Returns the value of attribute statements.
-
#tenant_scope ⇒ Object
readonly
Returns the value of attribute tenant_scope.
Instance Method Summary collapse
- #authorization_statements ⇒ Object
- #consent_statements ⇒ Object
- #document_keys ⇒ Object
-
#initialize(key:, statements:, retention_class_key: nil, request_evidence: nil, persist_presentations_for: nil, persist_presentations_because: nil, capture_channels: nil, locales: nil, tenant_scope: "optional", authority_rule: nil, options: {}) ⇒ Policy
constructor
A new instance of Policy.
- #kinds ⇒ Object
- #one_time_statements ⇒ Object
- #optional_statements ⇒ Object
-
#permits_acting_for? ⇒ Boolean
Delegation, guardianship, service-account action, and impersonation are rejected unless the policy opts in and the host authority adapter agrees.
- #permits_acting_for_party?(represented_party) ⇒ Boolean
- #permits_capture_channel?(channel) ⇒ Boolean
-
#permits_exemptions? ⇒ Boolean
Whether a system exemption may stand in for a human action under this policy.
- #permits_locale?(locale) ⇒ Boolean
- #persist_presentations? ⇒ Boolean
- #protected_outcome_statement ⇒ Object
- #protected_outcome_statements ⇒ Object
- #records_protected_outcome? ⇒ Boolean
- #required_statements ⇒ Object
- #statement(statement_key) ⇒ Object
- #statement!(statement_key) ⇒ Object
- #subject_bound? ⇒ Boolean
-
#tenant_from_controller(candidate) ⇒ Object
Resolves ambient controller context according to this policy.
- #tenant_not_applicable? ⇒ Boolean
- #tenant_optional? ⇒ Boolean
- #tenant_required? ⇒ Boolean
- #to_s ⇒ Object
-
#validate_tenant!(tenant) ⇒ Object
Direct service callers own their arguments, so an incompatible explicit value is rejected instead of silently rewritten.
Constructor Details
#initialize(key:, statements:, retention_class_key: nil, request_evidence: nil, persist_presentations_for: nil, persist_presentations_because: nil, capture_channels: nil, locales: nil, tenant_scope: "optional", authority_rule: nil, options: {}) ⇒ Policy
Returns a new instance of Policy.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/clickwrap/policy.rb', line 26 def initialize(key:, statements:, retention_class_key: nil, request_evidence: nil, persist_presentations_for: nil, persist_presentations_because: nil, capture_channels: nil, locales: nil, tenant_scope: "optional", authority_rule: nil, options: {}) @key = key.to_s @statements = statements.freeze # A policy that never says `retain_with` keeps its evidence indefinitely # under the built-in class — the reversible default. Deletion clocks are # the reviewed opt-in, declared with `Clickwrap.retention` and named here. @retention_class_key = (retention_class_key || DEFAULT_RETENTION_CLASS_KEY).to_s @request_evidence = request_evidence || RequestEvidencePolicy.new(policy_key: @key) @persist_presentations_for = persist_presentations_for @persist_presentations_because = persist_presentations_because @capture_channels = (capture_channels || Vocabulary::CAPTURE_CHANNELS).map(&:to_s).freeze @locales = locales&.map(&:to_s)&.freeze @tenant_scope = tenant_scope.to_s @authority_rule = @options = .freeze validate! @snapshot = build_snapshot.freeze @revision = Digest.digest_canonical(@snapshot).freeze freeze end |
Instance Attribute Details
#authority_rule ⇒ Object (readonly)
Returns the value of attribute authority_rule.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def @authority_rule end |
#capture_channels ⇒ Object (readonly)
Returns the value of attribute capture_channels.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def capture_channels @capture_channels end |
#key ⇒ Object (readonly)
Returns the value of attribute key.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def key @key end |
#locales ⇒ Object (readonly)
Returns the value of attribute locales.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def locales @locales end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def @options end |
#persist_presentations_because ⇒ Object (readonly)
Returns the value of attribute persist_presentations_because.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def persist_presentations_because @persist_presentations_because end |
#persist_presentations_for ⇒ Object (readonly)
Returns the value of attribute persist_presentations_for.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def persist_presentations_for @persist_presentations_for end |
#request_evidence ⇒ Object (readonly)
Returns the value of attribute request_evidence.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def request_evidence @request_evidence end |
#retention_class_key ⇒ Object (readonly)
Returns the value of attribute retention_class_key.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def retention_class_key @retention_class_key end |
#revision ⇒ Object (readonly)
Returns the value of attribute revision.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def revision @revision end |
#snapshot ⇒ Object (readonly)
Returns the value of attribute snapshot.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def snapshot @snapshot end |
#statements ⇒ Object (readonly)
Returns the value of attribute statements.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def statements @statements end |
#tenant_scope ⇒ Object (readonly)
Returns the value of attribute tenant_scope.
22 23 24 |
# File 'lib/clickwrap/policy.rb', line 22 def tenant_scope @tenant_scope end |
Instance Method Details
#authorization_statements ⇒ Object
71 |
# File 'lib/clickwrap/policy.rb', line 71 def = statements.select { |statement| statement.kind == "authorization" } |
#consent_statements ⇒ Object
70 |
# File 'lib/clickwrap/policy.rb', line 70 def = statements.select { |statement| statement.kind == "consent" } |
#document_keys ⇒ Object
65 |
# File 'lib/clickwrap/policy.rb', line 65 def document_keys = statements.flat_map(&:document_keys).uniq |
#kinds ⇒ Object
66 |
# File 'lib/clickwrap/policy.rb', line 66 def kinds = statements.map(&:kind).uniq |
#one_time_statements ⇒ Object
68 |
# File 'lib/clickwrap/policy.rb', line 68 def one_time_statements = statements.select(&:one_time?) |
#optional_statements ⇒ Object
64 |
# File 'lib/clickwrap/policy.rb', line 64 def optional_statements = statements.select(&:optional?) |
#permits_acting_for? ⇒ Boolean
Delegation, guardianship, service-account action, and impersonation are rejected unless the policy opts in and the host authority adapter agrees. When permitted, the receipt keeps the authenticated principal, asserted actor, and represented party as separate facts; Clickwrap does not decide whether that authority is sufficient.
128 |
# File 'lib/clickwrap/policy.rb', line 128 def permits_acting_for? = .fetch(:permit_acting_for, false) == true |
#permits_acting_for_party?(represented_party) ⇒ Boolean
130 131 132 |
# File 'lib/clickwrap/policy.rb', line 130 def permits_acting_for_party?(represented_party) permits_acting_for? && &.permits?(represented_party) end |
#permits_capture_channel?(channel) ⇒ Boolean
84 |
# File 'lib/clickwrap/policy.rb', line 84 def permits_capture_channel?(channel) = capture_channels.include?(channel.to_s) |
#permits_exemptions? ⇒ Boolean
Whether a system exemption may stand in for a human action under this
policy. It is off unless the policy says otherwise, and an exemption never
satisfies agreed_to? or any other human-action predicate even when it
is permitted — it answers exempted_from? instead.
82 |
# File 'lib/clickwrap/policy.rb', line 82 def permits_exemptions? = .fetch(:permit_exemptions, false) == true |
#permits_locale?(locale) ⇒ Boolean
86 87 88 |
# File 'lib/clickwrap/policy.rb', line 86 def permits_locale?(locale) locales.nil? || locales.include?(locale.to_s) end |
#persist_presentations? ⇒ Boolean
76 |
# File 'lib/clickwrap/policy.rb', line 76 def persist_presentations? = !persist_presentations_for.nil? |
#protected_outcome_statement ⇒ Object
73 |
# File 'lib/clickwrap/policy.rb', line 73 def protected_outcome_statement = protected_outcome_statements.first |
#protected_outcome_statements ⇒ Object
72 |
# File 'lib/clickwrap/policy.rb', line 72 def protected_outcome_statements = statements.select(&:record_protected_outcome_with) |
#records_protected_outcome? ⇒ Boolean
74 |
# File 'lib/clickwrap/policy.rb', line 74 def records_protected_outcome? = protected_outcome_statement.present? |
#required_statements ⇒ Object
63 |
# File 'lib/clickwrap/policy.rb', line 63 def required_statements = statements.select(&:required?) |
#statement(statement_key) ⇒ Object
51 52 53 |
# File 'lib/clickwrap/policy.rb', line 51 def statement(statement_key) statements.find { |statement| statement.key == statement_key.to_s } end |
#statement!(statement_key) ⇒ Object
55 56 57 58 59 60 61 |
# File 'lib/clickwrap/policy.rb', line 55 def statement!(statement_key) statement(statement_key) || raise( UnknownStatementError, "Policy #{key} has no statement #{statement_key.inspect}. It declares: " \ "#{statements.map(&:key).join(", ")}." ) end |
#subject_bound? ⇒ Boolean
69 |
# File 'lib/clickwrap/policy.rb', line 69 def subject_bound? = statements.any?(&:subject_bound?) |
#tenant_from_controller(candidate) ⇒ Object
Resolves ambient controller context according to this policy. Personal evidence deliberately discards a current organization; tenant-required evidence fails before rendering if the host cannot supply one.
97 98 99 100 101 102 |
# File 'lib/clickwrap/policy.rb', line 97 def tenant_from_controller(candidate) return nil if tenant_not_applicable? validate_tenant!(candidate) candidate end |
#tenant_not_applicable? ⇒ Boolean
90 |
# File 'lib/clickwrap/policy.rb', line 90 def tenant_not_applicable? = tenant_scope == "not_applicable" |
#tenant_optional? ⇒ Boolean
92 |
# File 'lib/clickwrap/policy.rb', line 92 def tenant_optional? = tenant_scope == "optional" |
#tenant_required? ⇒ Boolean
91 |
# File 'lib/clickwrap/policy.rb', line 91 def tenant_required? = tenant_scope == "required" |
#to_s ⇒ Object
134 |
# File 'lib/clickwrap/policy.rb', line 134 def to_s = "Clickwrap policy #{key} (#{revision})" |
#validate_tenant!(tenant) ⇒ Object
Direct service callers own their arguments, so an incompatible explicit value is rejected instead of silently rewritten.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/clickwrap/policy.rb', line 106 def validate_tenant!(tenant) if tenant_not_applicable? && tenant.present? raise DefinitionError, "Policy #{key} says `tenant_is :not_applicable`, but this call supplied a tenant. " \ "Remove `tenant:`; personal evidence must not change identity when the actor joins " \ "or switches organizations." end if tenant_required? && tenant.nil? raise DefinitionError, "Policy #{key} says `tenant_is :required`, but this call supplied no tenant. Pass " \ "the server-resolved tenant to presentation, capture, and verification." end true end |