clickwrap 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +90 -0
  3. data/CHANGELOG.md +612 -0
  4. data/README.md +830 -1204
  5. data/SECURITY.md +33 -0
  6. data/app/assets/stylesheets/clickwrap.css +241 -0
  7. data/app/controllers/clickwrap/application_controller.rb +79 -0
  8. data/app/controllers/clickwrap/captures_controller.rb +145 -0
  9. data/app/controllers/clickwrap/document_versions_controller.rb +71 -0
  10. data/app/controllers/clickwrap/receipts_controller.rb +115 -0
  11. data/app/controllers/clickwrap/withdrawals_controller.rb +60 -0
  12. data/app/helpers/clickwrap/engine_helper.rb +97 -0
  13. data/app/views/clickwrap/captures/show.html.erb +34 -0
  14. data/app/views/clickwrap/receipts/index.html.erb +38 -0
  15. data/app/views/clickwrap/receipts/show.html.erb +91 -0
  16. data/app/views/clickwrap/shared/_error_summary.html.erb +39 -0
  17. data/app/views/clickwrap/shared/_fields.html.erb +100 -0
  18. data/app/views/clickwrap/shared/_statement.html.erb +105 -0
  19. data/app/views/clickwrap/withdrawals/new.html.erb +30 -0
  20. data/config/locales/en.yml +160 -0
  21. data/config/locales/es.yml +138 -0
  22. data/config/routes.rb +41 -0
  23. data/exe/clickwrap +374 -0
  24. data/guides/README.md +30 -0
  25. data/guides/accessibility.md +249 -0
  26. data/guides/consent-and-lifecycle.md +299 -0
  27. data/guides/integrating.md +610 -0
  28. data/guides/integrity.md +212 -0
  29. data/guides/migrating.md +335 -0
  30. data/guides/naming.md +320 -0
  31. data/guides/organizations.md +320 -0
  32. data/guides/receipts-and-verification.md +415 -0
  33. data/guides/request-evidence.md +512 -0
  34. data/guides/retention-and-legal-holds.md +438 -0
  35. data/lib/clickwrap/actor_proxy.rb +147 -0
  36. data/lib/clickwrap/anonymous_actor.rb +47 -0
  37. data/lib/clickwrap/authority.rb +174 -0
  38. data/lib/clickwrap/canonical_json.rb +216 -0
  39. data/lib/clickwrap/capture/event_builder.rb +220 -0
  40. data/lib/clickwrap/capture/presentation_verifier.rb +521 -0
  41. data/lib/clickwrap/capture.rb +650 -0
  42. data/lib/clickwrap/configuration.rb +1129 -0
  43. data/lib/clickwrap/controller_helpers.rb +758 -0
  44. data/lib/clickwrap/current_state.rb +282 -0
  45. data/lib/clickwrap/digest.rb +125 -0
  46. data/lib/clickwrap/doctor.rb +418 -0
  47. data/lib/clickwrap/document_definition.rb +255 -0
  48. data/lib/clickwrap/document_renderer.rb +83 -0
  49. data/lib/clickwrap/document_renderers/markdown.rb +175 -0
  50. data/lib/clickwrap/document_renderers/markdown_rails.rb +126 -0
  51. data/lib/clickwrap/dsl/policy_builder.rb +462 -0
  52. data/lib/clickwrap/dsl/retention_builder.rb +89 -0
  53. data/lib/clickwrap/durable_commit_callback.rb +37 -0
  54. data/lib/clickwrap/engine.rb +184 -0
  55. data/lib/clickwrap/errors.rb +181 -0
  56. data/lib/clickwrap/form_builder_extensions.rb +341 -0
  57. data/lib/clickwrap/front_matter.rb +67 -0
  58. data/lib/clickwrap/identifier.rb +112 -0
  59. data/lib/clickwrap/import/external_receipt.rb +241 -0
  60. data/lib/clickwrap/import/fine_print.rb +290 -0
  61. data/lib/clickwrap/import/legacy.rb +450 -0
  62. data/lib/clickwrap/integrations/organizations_authority.rb +81 -0
  63. data/lib/clickwrap/integrity/anchor.rb +130 -0
  64. data/lib/clickwrap/integrity/attestation_reconciler.rb +114 -0
  65. data/lib/clickwrap/integrity/attestor.rb +221 -0
  66. data/lib/clickwrap/integrity/chain.rb +313 -0
  67. data/lib/clickwrap/integrity/timestamp.rb +143 -0
  68. data/lib/clickwrap/ip_geolocation/location.rb +112 -0
  69. data/lib/clickwrap/ip_geolocation/null_resolver.rb +35 -0
  70. data/lib/clickwrap/ip_geolocation/resolver.rb +97 -0
  71. data/lib/clickwrap/ip_geolocation/static_resolver.rb +107 -0
  72. data/lib/clickwrap/ip_geolocation/trackdown_resolver.rb +330 -0
  73. data/lib/clickwrap/ip_geolocation.rb +16 -0
  74. data/lib/clickwrap/lifecycle.rb +534 -0
  75. data/lib/clickwrap/linter.rb +382 -0
  76. data/lib/clickwrap/localized_text.rb +101 -0
  77. data/lib/clickwrap/macros.rb +203 -0
  78. data/lib/clickwrap/models/application_record.rb +20 -0
  79. data/lib/clickwrap/models/chain_head.rb +79 -0
  80. data/lib/clickwrap/models/concerns/has_clickwraps.rb +55 -0
  81. data/lib/clickwrap/models/disposition_plan.rb +208 -0
  82. data/lib/clickwrap/models/document.rb +46 -0
  83. data/lib/clickwrap/models/document_version.rb +163 -0
  84. data/lib/clickwrap/models/event.rb +743 -0
  85. data/lib/clickwrap/models/event_document.rb +79 -0
  86. data/lib/clickwrap/models/event_statement.rb +92 -0
  87. data/lib/clickwrap/models/external_action.rb +150 -0
  88. data/lib/clickwrap/models/integrity_attestation.rb +90 -0
  89. data/lib/clickwrap/models/legal_hold.rb +81 -0
  90. data/lib/clickwrap/models/policy_revision.rb +115 -0
  91. data/lib/clickwrap/models/presentation.rb +59 -0
  92. data/lib/clickwrap/models/receipt_access.rb +53 -0
  93. data/lib/clickwrap/models/recording_sequence.rb +21 -0
  94. data/lib/clickwrap/models/request_evidence.rb +378 -0
  95. data/lib/clickwrap/models/statement_identity_lock.rb +38 -0
  96. data/lib/clickwrap/models/statement_state.rb +130 -0
  97. data/lib/clickwrap/pending_receipt.rb +177 -0
  98. data/lib/clickwrap/policy.rb +283 -0
  99. data/lib/clickwrap/presentation_manifest.rb +210 -0
  100. data/lib/clickwrap/presenter.rb +716 -0
  101. data/lib/clickwrap/privacy.rb +419 -0
  102. data/lib/clickwrap/protected_outcome.rb +120 -0
  103. data/lib/clickwrap/receipt.rb +606 -0
  104. data/lib/clickwrap/receipt_html.rb +235 -0
  105. data/lib/clickwrap/receipt_verifier.rb +978 -0
  106. data/lib/clickwrap/reference.rb +44 -0
  107. data/lib/clickwrap/registration.rb +236 -0
  108. data/lib/clickwrap/registry.rb +54 -0
  109. data/lib/clickwrap/remediation_token.rb +155 -0
  110. data/lib/clickwrap/request_evidence_extractor.rb +590 -0
  111. data/lib/clickwrap/request_evidence_policy.rb +261 -0
  112. data/lib/clickwrap/retention/applier.rb +231 -0
  113. data/lib/clickwrap/retention/disposition.rb +221 -0
  114. data/lib/clickwrap/retention/planner.rb +502 -0
  115. data/lib/clickwrap/retention_class.rb +97 -0
  116. data/lib/clickwrap/reviewed_text.rb +28 -0
  117. data/lib/clickwrap/schema_requirements.rb +196 -0
  118. data/lib/clickwrap/services/authorize_external_action.rb +149 -0
  119. data/lib/clickwrap/services/load_policies.rb +69 -0
  120. data/lib/clickwrap/services/publish_documents.rb +251 -0
  121. data/lib/clickwrap/services/validate_policy_references.rb +166 -0
  122. data/lib/clickwrap/statement.rb +248 -0
  123. data/lib/clickwrap/subject_fingerprint.rb +28 -0
  124. data/lib/clickwrap/submission.rb +169 -0
  125. data/lib/clickwrap/system_actor.rb +31 -0
  126. data/lib/clickwrap/test_helpers.rb +676 -0
  127. data/lib/clickwrap/testing.rb +211 -0
  128. data/lib/clickwrap/trusted_proxy_configuration.rb +92 -0
  129. data/lib/clickwrap/verification.rb +504 -0
  130. data/lib/clickwrap/version.rb +12 -1
  131. data/lib/clickwrap/view_helpers.rb +190 -0
  132. data/lib/clickwrap/vocabulary.rb +294 -0
  133. data/lib/clickwrap.rb +497 -7
  134. data/lib/generators/clickwrap/document_generator.rb +164 -0
  135. data/lib/generators/clickwrap/hardening_generator.rb +177 -0
  136. data/lib/generators/clickwrap/install_generator.rb +1287 -0
  137. data/lib/generators/clickwrap/link_generator.rb +56 -0
  138. data/lib/generators/clickwrap/policy_generator.rb +118 -0
  139. data/lib/generators/clickwrap/templates/clickwrap_hardening.rb.erb +256 -0
  140. data/lib/generators/clickwrap/templates/clickwrap_policies.rb.erb +192 -0
  141. data/lib/generators/clickwrap/templates/create_clickwrap_external_action_tables.rb.erb +128 -0
  142. data/lib/generators/clickwrap/templates/create_clickwrap_integrity_tables.rb.erb +157 -0
  143. data/lib/generators/clickwrap/templates/create_clickwrap_presentation_tables.rb.erb +160 -0
  144. data/lib/generators/clickwrap/templates/create_clickwrap_request_evidence_tables.rb.erb +180 -0
  145. data/lib/generators/clickwrap/templates/create_clickwrap_retention_tables.rb.erb +174 -0
  146. data/lib/generators/clickwrap/templates/create_clickwrap_tables.rb.erb +568 -0
  147. data/lib/generators/clickwrap/templates/initializer.rb.erb +439 -0
  148. data/lib/generators/clickwrap/templates/link_clickwrap_event_migration.rb.erb +12 -0
  149. data/lib/generators/clickwrap/templates/policy.rb.erb +31 -0
  150. data/lib/generators/clickwrap/templates/policy_test.rb.erb +56 -0
  151. data/lib/generators/clickwrap/templates/privacy.md.erb +58 -0
  152. data/lib/generators/clickwrap/templates/terms.md.erb +49 -0
  153. data/lib/generators/clickwrap/upgrade_generator.rb +50 -0
  154. data/lib/generators/clickwrap/views_generator.rb +101 -0
  155. data/lib/tasks/clickwrap.rake +569 -0
  156. metadata +311 -16
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Retention operations — `rails generate clickwrap:install
4
+ # --with-retention-ops`, or added later with the same command.
5
+ #
6
+ # Legal holds and reviewed disposition plans are the operator tooling for
7
+ # deleting evidence on schedule and pausing that schedule. Retention
8
+ # PERIODS are core and live on the event itself; these two tables are the
9
+ # workflow around them, and neither receives a row until an operator runs
10
+ # the disposition or legal-hold tasks.
11
+ class CreateClickwrapRetentionTables < ActiveRecord::Migration<%= migration_version %>
12
+ def change
13
+ primary_key_type, = primary_and_foreign_key_types
14
+
15
+ # ---------------------------------------------------------------------------
16
+ # clickwrap_legal_holds
17
+ #
18
+ # A hold pauses scheduled disposition. It requires a reason, an owner, and a
19
+ # review date, because an indefinite hold with no owner is how "we'll delete
20
+ # it later" becomes "we kept everything forever". Placement and release
21
+ # append linked events; this row changes only through the named release path.
22
+ # ---------------------------------------------------------------------------
23
+ create_table :clickwrap_legal_holds, id: primary_key_type do |t|
24
+ t.string :hold_scope, null: false, default: "event"
25
+ t.string :event_id, limit: 26
26
+ t.string :actor_reference
27
+ t.string :policy_key
28
+
29
+ t.text :reason, null: false
30
+ t.string :placed_by_reference, null: false
31
+ t.datetime :placed_at, precision: 6, null: false
32
+ t.datetime :review_at, precision: 6, null: false
33
+
34
+ t.datetime :released_at, precision: 6
35
+ t.string :released_by_reference
36
+ t.text :release_reason
37
+
38
+ t.datetime :created_at, precision: 6, null: false
39
+ end
40
+
41
+ add_index :clickwrap_legal_holds, [ :event_id, :released_at ],
42
+ name: "index_clickwrap_legal_holds_on_event"
43
+ add_index :clickwrap_legal_holds, [ :actor_reference, :released_at ],
44
+ name: "index_clickwrap_legal_holds_on_actor"
45
+ add_index :clickwrap_legal_holds, :review_at, name: "index_clickwrap_legal_holds_on_review_at"
46
+ add_index :clickwrap_legal_holds, [ :policy_key, :released_at ],
47
+ name: "index_clickwrap_legal_holds_on_policy"
48
+ add_clickwrap_check_constraint :clickwrap_legal_holds,
49
+ "hold_scope IN (#{quoted_values(%w[event actor policy])})",
50
+ name: "chk_clickwrap_holds_scope"
51
+
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # clickwrap_disposition_plans
55
+ #
56
+ # Deletion is a two-step operation: plan, review, then apply. The plan is
57
+ # immutable, scoped, and expiring, and it is rechecked at apply time — a new
58
+ # hold, a changed policy, or a stale plan stops the run rather than deleting
59
+ # a broader set than the person reviewing it agreed to.
60
+ # ---------------------------------------------------------------------------
61
+ create_table :clickwrap_disposition_plans, id: :string, limit: 26 do |t|
62
+ t.string :kind, null: false
63
+ t.send(json_column_type, :disposition_scope, null: false)
64
+ t.send(json_column_type, :summary, null: false)
65
+ t.integer :item_count, null: false, default: 0
66
+
67
+ t.string :created_by_reference
68
+ t.text :reason
69
+
70
+ t.datetime :expires_at, precision: 6, null: false
71
+ t.datetime :applied_at, precision: 6
72
+ t.string :applied_by_reference
73
+ t.string :state, null: false, default: "open"
74
+ t.string :plan_digest, null: false
75
+ t.datetime :application_started_at, precision: 6
76
+ t.integer :application_attempt_count, null: false, default: 0
77
+ t.send(json_column_type, :application_recoveries, default: json_array_default)
78
+ t.send(json_column_type, :application_outcome, default: json_column_default)
79
+ t.datetime :superseded_at, precision: 6
80
+ t.string :superseded_by_reference
81
+ t.text :superseded_reason
82
+
83
+ t.timestamps precision: 6
84
+ end
85
+
86
+ add_index :clickwrap_disposition_plans, [ :state, :expires_at ],
87
+ name: "index_clickwrap_disposition_plans_on_state"
88
+ add_clickwrap_check_constraint :clickwrap_disposition_plans,
89
+ "kind IN (#{quoted_values(%w[retention actor_privacy])})",
90
+ name: "chk_clickwrap_disposition_plans_kind"
91
+ add_clickwrap_check_constraint :clickwrap_disposition_plans,
92
+ "state IN (#{quoted_values(%w[open applying applied applied_with_errors superseded])})",
93
+ name: "chk_clickwrap_disposition_plans_state"
94
+
95
+
96
+ add_clickwrap_foreign_key :clickwrap_legal_holds, :clickwrap_events,
97
+ column: :event_id, name: "fk_clickwrap_legal_holds_event"
98
+ end
99
+
100
+ private
101
+
102
+ # Honor the host's configured primary key type (uuid vs bigint). Reads the
103
+ # same setting `rails g model` uses, so an app generated with
104
+ # `config.generators { |g| g.orm :active_record, primary_key_type: :uuid }`
105
+ # gets uuid clickwrap tables and uuid foreign keys, automatically.
106
+ #
107
+ # Note that clickwrap_events keeps a ULID string key regardless: its id is
108
+ # quoted verbatim in receipts and exports, so it has to be stable, sortable,
109
+ # and identical in every host.
110
+ def primary_and_foreign_key_types
111
+ config = Rails.configuration.generators
112
+ setting = config.options[config.orm][:primary_key_type]
113
+ primary_key_type = setting || :primary_key
114
+ foreign_key_type = setting || :bigint
115
+ [ primary_key_type, foreign_key_type ]
116
+ end
117
+
118
+ def json_column_type
119
+ return :jsonb if connection.adapter_name.downcase.match?(/postg/) # postgresql, postgis
120
+
121
+ :json
122
+ end
123
+
124
+ # MySQL 8+ doesn't allow default values on JSON columns. Returns an empty-hash
125
+ # default for SQLite/PostgreSQL, nil for MySQL. The models handle nil
126
+ # gracefully by defaulting to {} in their accessors.
127
+ def json_column_default
128
+ return nil if connection.adapter_name.downcase.match?(/mysql|trilogy/)
129
+
130
+ {}
131
+ end
132
+
133
+ # Same MySQL caveat as `json_column_default`, but for list-shaped columns.
134
+ def json_array_default
135
+ return nil if connection.adapter_name.downcase.match?(/mysql|trilogy/)
136
+
137
+ []
138
+ end
139
+
140
+ # Legal documents are routinely longer than MySQL's 64 KB TEXT limit, and a
141
+ # silently truncated agreement is the worst possible failure for this gem.
142
+ # `:mediumtext` maps to MEDIUMTEXT on MySQL (16 MB) and to ordinary TEXT
143
+ # everywhere else.
144
+ def text_column_type
145
+ return :mediumtext if connection.adapter_name.downcase.match?(/mysql|trilogy/)
146
+
147
+ :text
148
+ end
149
+
150
+ def quoted_values(values)
151
+ values.map { |value| connection.quote(value) }.join(", ")
152
+ end
153
+
154
+ # SQLite implements both foreign keys and check constraints by rebuilding a
155
+ # table. During a long install migration, Active Record can otherwise rebuild
156
+ # from a schema-cache entry captured before the indexes/columns immediately
157
+ # above were added. Refreshing around every rebuild keeps the SQLite result
158
+ # identical to PostgreSQL/MySQL instead of quietly resurrecting stale shape.
159
+ def add_clickwrap_check_constraint(table, expression, **options)
160
+ refresh_clickwrap_table_schema!(table)
161
+ add_check_constraint(table, expression, **options)
162
+ refresh_clickwrap_table_schema!(table)
163
+ end
164
+
165
+ def add_clickwrap_foreign_key(from_table, to_table, **options)
166
+ refresh_clickwrap_table_schema!(from_table)
167
+ add_foreign_key(from_table, to_table, **options)
168
+ refresh_clickwrap_table_schema!(from_table)
169
+ end
170
+
171
+ def refresh_clickwrap_table_schema!(table)
172
+ connection.schema_cache.clear_data_source_cache!(table.to_s)
173
+ end
174
+ end