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.
- checksums.yaml +4 -4
- data/.rubocop.yml +90 -0
- data/CHANGELOG.md +612 -0
- data/README.md +830 -1204
- data/SECURITY.md +33 -0
- data/app/assets/stylesheets/clickwrap.css +241 -0
- data/app/controllers/clickwrap/application_controller.rb +79 -0
- data/app/controllers/clickwrap/captures_controller.rb +145 -0
- data/app/controllers/clickwrap/document_versions_controller.rb +71 -0
- data/app/controllers/clickwrap/receipts_controller.rb +115 -0
- data/app/controllers/clickwrap/withdrawals_controller.rb +60 -0
- data/app/helpers/clickwrap/engine_helper.rb +97 -0
- data/app/views/clickwrap/captures/show.html.erb +34 -0
- data/app/views/clickwrap/receipts/index.html.erb +38 -0
- data/app/views/clickwrap/receipts/show.html.erb +91 -0
- data/app/views/clickwrap/shared/_error_summary.html.erb +39 -0
- data/app/views/clickwrap/shared/_fields.html.erb +100 -0
- data/app/views/clickwrap/shared/_statement.html.erb +105 -0
- data/app/views/clickwrap/withdrawals/new.html.erb +30 -0
- data/config/locales/en.yml +160 -0
- data/config/locales/es.yml +138 -0
- data/config/routes.rb +41 -0
- data/exe/clickwrap +374 -0
- data/guides/README.md +30 -0
- data/guides/accessibility.md +249 -0
- data/guides/consent-and-lifecycle.md +299 -0
- data/guides/integrating.md +610 -0
- data/guides/integrity.md +212 -0
- data/guides/migrating.md +335 -0
- data/guides/naming.md +320 -0
- data/guides/organizations.md +320 -0
- data/guides/receipts-and-verification.md +415 -0
- data/guides/request-evidence.md +512 -0
- data/guides/retention-and-legal-holds.md +438 -0
- data/lib/clickwrap/actor_proxy.rb +147 -0
- data/lib/clickwrap/anonymous_actor.rb +47 -0
- data/lib/clickwrap/authority.rb +174 -0
- data/lib/clickwrap/canonical_json.rb +216 -0
- data/lib/clickwrap/capture/event_builder.rb +220 -0
- data/lib/clickwrap/capture/presentation_verifier.rb +521 -0
- data/lib/clickwrap/capture.rb +650 -0
- data/lib/clickwrap/configuration.rb +1129 -0
- data/lib/clickwrap/controller_helpers.rb +758 -0
- data/lib/clickwrap/current_state.rb +282 -0
- data/lib/clickwrap/digest.rb +125 -0
- data/lib/clickwrap/doctor.rb +418 -0
- data/lib/clickwrap/document_definition.rb +255 -0
- data/lib/clickwrap/document_renderer.rb +83 -0
- data/lib/clickwrap/document_renderers/markdown.rb +175 -0
- data/lib/clickwrap/document_renderers/markdown_rails.rb +126 -0
- data/lib/clickwrap/dsl/policy_builder.rb +462 -0
- data/lib/clickwrap/dsl/retention_builder.rb +89 -0
- data/lib/clickwrap/durable_commit_callback.rb +37 -0
- data/lib/clickwrap/engine.rb +184 -0
- data/lib/clickwrap/errors.rb +181 -0
- data/lib/clickwrap/form_builder_extensions.rb +341 -0
- data/lib/clickwrap/front_matter.rb +67 -0
- data/lib/clickwrap/identifier.rb +112 -0
- data/lib/clickwrap/import/external_receipt.rb +241 -0
- data/lib/clickwrap/import/fine_print.rb +290 -0
- data/lib/clickwrap/import/legacy.rb +450 -0
- data/lib/clickwrap/integrations/organizations_authority.rb +81 -0
- data/lib/clickwrap/integrity/anchor.rb +130 -0
- data/lib/clickwrap/integrity/attestation_reconciler.rb +114 -0
- data/lib/clickwrap/integrity/attestor.rb +221 -0
- data/lib/clickwrap/integrity/chain.rb +313 -0
- data/lib/clickwrap/integrity/timestamp.rb +143 -0
- data/lib/clickwrap/ip_geolocation/location.rb +112 -0
- data/lib/clickwrap/ip_geolocation/null_resolver.rb +35 -0
- data/lib/clickwrap/ip_geolocation/resolver.rb +97 -0
- data/lib/clickwrap/ip_geolocation/static_resolver.rb +107 -0
- data/lib/clickwrap/ip_geolocation/trackdown_resolver.rb +330 -0
- data/lib/clickwrap/ip_geolocation.rb +16 -0
- data/lib/clickwrap/lifecycle.rb +534 -0
- data/lib/clickwrap/linter.rb +382 -0
- data/lib/clickwrap/localized_text.rb +101 -0
- data/lib/clickwrap/macros.rb +203 -0
- data/lib/clickwrap/models/application_record.rb +20 -0
- data/lib/clickwrap/models/chain_head.rb +79 -0
- data/lib/clickwrap/models/concerns/has_clickwraps.rb +55 -0
- data/lib/clickwrap/models/disposition_plan.rb +208 -0
- data/lib/clickwrap/models/document.rb +46 -0
- data/lib/clickwrap/models/document_version.rb +163 -0
- data/lib/clickwrap/models/event.rb +743 -0
- data/lib/clickwrap/models/event_document.rb +79 -0
- data/lib/clickwrap/models/event_statement.rb +92 -0
- data/lib/clickwrap/models/external_action.rb +150 -0
- data/lib/clickwrap/models/integrity_attestation.rb +90 -0
- data/lib/clickwrap/models/legal_hold.rb +81 -0
- data/lib/clickwrap/models/policy_revision.rb +115 -0
- data/lib/clickwrap/models/presentation.rb +59 -0
- data/lib/clickwrap/models/receipt_access.rb +53 -0
- data/lib/clickwrap/models/recording_sequence.rb +21 -0
- data/lib/clickwrap/models/request_evidence.rb +378 -0
- data/lib/clickwrap/models/statement_identity_lock.rb +38 -0
- data/lib/clickwrap/models/statement_state.rb +130 -0
- data/lib/clickwrap/pending_receipt.rb +177 -0
- data/lib/clickwrap/policy.rb +283 -0
- data/lib/clickwrap/presentation_manifest.rb +210 -0
- data/lib/clickwrap/presenter.rb +716 -0
- data/lib/clickwrap/privacy.rb +419 -0
- data/lib/clickwrap/protected_outcome.rb +120 -0
- data/lib/clickwrap/receipt.rb +606 -0
- data/lib/clickwrap/receipt_html.rb +235 -0
- data/lib/clickwrap/receipt_verifier.rb +978 -0
- data/lib/clickwrap/reference.rb +44 -0
- data/lib/clickwrap/registration.rb +236 -0
- data/lib/clickwrap/registry.rb +54 -0
- data/lib/clickwrap/remediation_token.rb +155 -0
- data/lib/clickwrap/request_evidence_extractor.rb +590 -0
- data/lib/clickwrap/request_evidence_policy.rb +261 -0
- data/lib/clickwrap/retention/applier.rb +231 -0
- data/lib/clickwrap/retention/disposition.rb +221 -0
- data/lib/clickwrap/retention/planner.rb +502 -0
- data/lib/clickwrap/retention_class.rb +97 -0
- data/lib/clickwrap/reviewed_text.rb +28 -0
- data/lib/clickwrap/schema_requirements.rb +196 -0
- data/lib/clickwrap/services/authorize_external_action.rb +149 -0
- data/lib/clickwrap/services/load_policies.rb +69 -0
- data/lib/clickwrap/services/publish_documents.rb +251 -0
- data/lib/clickwrap/services/validate_policy_references.rb +166 -0
- data/lib/clickwrap/statement.rb +248 -0
- data/lib/clickwrap/subject_fingerprint.rb +28 -0
- data/lib/clickwrap/submission.rb +169 -0
- data/lib/clickwrap/system_actor.rb +31 -0
- data/lib/clickwrap/test_helpers.rb +676 -0
- data/lib/clickwrap/testing.rb +211 -0
- data/lib/clickwrap/trusted_proxy_configuration.rb +92 -0
- data/lib/clickwrap/verification.rb +504 -0
- data/lib/clickwrap/version.rb +12 -1
- data/lib/clickwrap/view_helpers.rb +190 -0
- data/lib/clickwrap/vocabulary.rb +294 -0
- data/lib/clickwrap.rb +497 -7
- data/lib/generators/clickwrap/document_generator.rb +164 -0
- data/lib/generators/clickwrap/hardening_generator.rb +177 -0
- data/lib/generators/clickwrap/install_generator.rb +1287 -0
- data/lib/generators/clickwrap/link_generator.rb +56 -0
- data/lib/generators/clickwrap/policy_generator.rb +118 -0
- data/lib/generators/clickwrap/templates/clickwrap_hardening.rb.erb +256 -0
- data/lib/generators/clickwrap/templates/clickwrap_policies.rb.erb +192 -0
- data/lib/generators/clickwrap/templates/create_clickwrap_external_action_tables.rb.erb +128 -0
- data/lib/generators/clickwrap/templates/create_clickwrap_integrity_tables.rb.erb +157 -0
- data/lib/generators/clickwrap/templates/create_clickwrap_presentation_tables.rb.erb +160 -0
- data/lib/generators/clickwrap/templates/create_clickwrap_request_evidence_tables.rb.erb +180 -0
- data/lib/generators/clickwrap/templates/create_clickwrap_retention_tables.rb.erb +174 -0
- data/lib/generators/clickwrap/templates/create_clickwrap_tables.rb.erb +568 -0
- data/lib/generators/clickwrap/templates/initializer.rb.erb +439 -0
- data/lib/generators/clickwrap/templates/link_clickwrap_event_migration.rb.erb +12 -0
- data/lib/generators/clickwrap/templates/policy.rb.erb +31 -0
- data/lib/generators/clickwrap/templates/policy_test.rb.erb +56 -0
- data/lib/generators/clickwrap/templates/privacy.md.erb +58 -0
- data/lib/generators/clickwrap/templates/terms.md.erb +49 -0
- data/lib/generators/clickwrap/upgrade_generator.rb +50 -0
- data/lib/generators/clickwrap/views_generator.rb +101 -0
- data/lib/tasks/clickwrap.rake +569 -0
- 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
|