legion-data 1.7.3 → 1.8.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/.pre-commit-config.yaml +29 -0
- data/AGENTS.md +66 -13
- data/CHANGELOG.md +29 -0
- data/CLAUDE.md +44 -307
- data/README.md +119 -7
- data/lib/legion/data/connection.rb +3 -1
- data/lib/legion/data/migrations/077_create_llm_conversations.rb +32 -0
- data/lib/legion/data/migrations/078_create_llm_messages.rb +33 -0
- data/lib/legion/data/migrations/079_create_llm_message_inference_requests.rb +47 -0
- data/lib/legion/data/migrations/080_create_llm_message_inference_responses.rb +39 -0
- data/lib/legion/data/migrations/081_add_llm_message_inference_foreign_keys.rb +17 -0
- data/lib/legion/data/migrations/082_create_llm_route_attempts.rb +31 -0
- data/lib/legion/data/migrations/083_create_llm_message_inference_metrics.rb +36 -0
- data/lib/legion/data/migrations/084_create_llm_tool_calls.rb +32 -0
- data/lib/legion/data/migrations/085_add_llm_message_tool_call_foreign_key.rb +15 -0
- data/lib/legion/data/migrations/086_create_llm_tool_call_attempts.rb +30 -0
- data/lib/legion/data/migrations/087_create_llm_conversation_compactions.rb +31 -0
- data/lib/legion/data/migrations/088_create_llm_policy_evaluations.rb +33 -0
- data/lib/legion/data/migrations/089_create_llm_security_events.rb +33 -0
- data/lib/legion/data/migrations/090_create_llm_registry_events.rb +23 -0
- data/lib/legion/data/migrations/091_create_portable_identity_providers.rb +35 -0
- data/lib/legion/data/migrations/092_create_portable_identity_principals.rb +25 -0
- data/lib/legion/data/migrations/093_create_portable_identities.rb +31 -0
- data/lib/legion/data/migrations/094_create_portable_identity_groups.rb +21 -0
- data/lib/legion/data/migrations/095_create_portable_identity_group_memberships.rb +25 -0
- data/lib/legion/data/migrations/096_create_portable_identity_audit_log.rb +26 -0
- data/lib/legion/data/migrations/097_add_llm_dispatch_fields.rb +16 -0
- data/lib/legion/data/model.rb +11 -1
- data/lib/legion/data/models/apollo/access_log.rb +17 -0
- data/lib/legion/data/models/apollo/entries.rb +22 -0
- data/lib/legion/data/models/apollo/expertise.rb +16 -0
- data/lib/legion/data/models/apollo/model_helpers.rb +17 -0
- data/lib/legion/data/models/apollo/operation.rb +16 -0
- data/lib/legion/data/models/apollo/relation.rb +18 -0
- data/lib/legion/data/models/function.rb +1 -0
- data/lib/legion/data/models/identity/audit_log.rb +20 -0
- data/lib/legion/data/models/identity/group.rb +28 -0
- data/lib/legion/data/models/identity/group_memberships.rb +28 -0
- data/lib/legion/data/models/identity/identity.rb +24 -0
- data/lib/legion/data/models/identity/model_helpers.rb +86 -0
- data/lib/legion/data/models/identity/principal.rb +37 -0
- data/lib/legion/data/models/identity/providers.rb +34 -0
- data/lib/legion/data/models/identity.rb +8 -0
- data/lib/legion/data/models/identity_group.rb +13 -0
- data/lib/legion/data/models/identity_provider.rb +8 -0
- data/lib/legion/data/models/llm/conversation.rb +25 -0
- data/lib/legion/data/models/llm/conversation_compaction.rb +22 -0
- data/lib/legion/data/models/llm/message.rb +105 -0
- data/lib/legion/data/models/llm/message_inference_metric.rb +46 -0
- data/lib/legion/data/models/llm/message_inference_request.rb +80 -0
- data/lib/legion/data/models/llm/message_inference_response.rb +23 -0
- data/lib/legion/data/models/llm/model_helpers.rb +18 -0
- data/lib/legion/data/models/llm/policy_evaluation.rb +20 -0
- data/lib/legion/data/models/llm/registry_event.rb +15 -0
- data/lib/legion/data/models/llm/route_attempt.rb +18 -0
- data/lib/legion/data/models/llm/security_event.rb +66 -0
- data/lib/legion/data/models/llm/tool_call.rb +21 -0
- data/lib/legion/data/models/llm/tool_call_attempt.rb +18 -0
- data/lib/legion/data/models/node.rb +2 -1
- data/lib/legion/data/models/principal.rb +13 -0
- data/lib/legion/data/models/rbac/cross_team_grants.rb +25 -0
- data/lib/legion/data/models/rbac/model_helpers.rb +25 -0
- data/lib/legion/data/models/rbac/role_assignments.rb +25 -0
- data/lib/legion/data/models/rbac/runner_grants.rb +23 -0
- data/lib/legion/data/models/relationship.rb +1 -0
- data/lib/legion/data/models/runner.rb +24 -2
- data/lib/legion/data/models/task.rb +4 -0
- data/lib/legion/data/version.rb +1 -1
- data/scripts/pre-commit-rubocop.sh +16 -0
- metadata +54 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Sequel.migration do
|
|
4
|
+
change do
|
|
5
|
+
create_table(:llm_registry_events) do
|
|
6
|
+
primary_key :id
|
|
7
|
+
String :uuid, size: 36, null: false, unique: true
|
|
8
|
+
String :provider, size: 128
|
|
9
|
+
String :model_key, size: 255
|
|
10
|
+
String :event_type, size: 128, null: false
|
|
11
|
+
String :status, size: 64, null: false
|
|
12
|
+
String :reason, text: true
|
|
13
|
+
DateTime :recorded_at
|
|
14
|
+
DateTime :inserted_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
15
|
+
|
|
16
|
+
index :uuid
|
|
17
|
+
index %i[provider model_key]
|
|
18
|
+
index :event_type
|
|
19
|
+
index :status
|
|
20
|
+
index :recorded_at
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Sequel.migration do
|
|
4
|
+
change do
|
|
5
|
+
create_table(:portable_identity_providers) do
|
|
6
|
+
primary_key :id
|
|
7
|
+
String :uuid, size: 36, null: false, unique: true
|
|
8
|
+
String :name, size: 255, null: false, unique: true
|
|
9
|
+
String :provider_type, size: 64, null: false
|
|
10
|
+
String :facing, size: 32, null: false
|
|
11
|
+
Integer :priority, null: false, default: 100
|
|
12
|
+
Integer :trust_weight, null: false, default: 50
|
|
13
|
+
String :source, size: 64, null: false, default: 'gem'
|
|
14
|
+
TrueClass :enabled, null: false, default: true
|
|
15
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
16
|
+
DateTime :updated_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
17
|
+
|
|
18
|
+
index :uuid
|
|
19
|
+
index :name
|
|
20
|
+
index :provider_type
|
|
21
|
+
index :enabled
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
create_table(:portable_identity_provider_capabilities) do
|
|
25
|
+
primary_key :id
|
|
26
|
+
foreign_key :provider_id, :portable_identity_providers, null: false, on_delete: :cascade
|
|
27
|
+
String :capability_key, size: 128, null: false
|
|
28
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
29
|
+
|
|
30
|
+
unique %i[provider_id capability_key]
|
|
31
|
+
index :provider_id
|
|
32
|
+
index :capability_key
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Sequel.migration do
|
|
4
|
+
change do
|
|
5
|
+
create_table(:portable_identity_principals) do
|
|
6
|
+
primary_key :id
|
|
7
|
+
String :uuid, size: 36, null: false, unique: true
|
|
8
|
+
String :canonical_name, size: 255, null: false
|
|
9
|
+
String :kind, size: 64, null: false
|
|
10
|
+
String :employee_key, size: 255
|
|
11
|
+
String :display_name, size: 255
|
|
12
|
+
TrueClass :active, null: false, default: true
|
|
13
|
+
DateTime :last_seen_at
|
|
14
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
15
|
+
DateTime :updated_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
16
|
+
|
|
17
|
+
unique %i[canonical_name kind]
|
|
18
|
+
index :uuid
|
|
19
|
+
index :canonical_name
|
|
20
|
+
index :kind
|
|
21
|
+
index :employee_key
|
|
22
|
+
index :active
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Sequel.migration do
|
|
4
|
+
change do
|
|
5
|
+
create_table(:portable_identities) do
|
|
6
|
+
primary_key :id
|
|
7
|
+
String :uuid, size: 36, null: false, unique: true
|
|
8
|
+
foreign_key :principal_id, :portable_identity_principals, null: false, on_delete: :cascade
|
|
9
|
+
foreign_key :provider_id, :portable_identity_providers, null: false, on_delete: :cascade
|
|
10
|
+
String :provider_identity_key, size: 255, null: false
|
|
11
|
+
String :profile_ciphertext, text: true
|
|
12
|
+
TrueClass :active, null: false, default: true
|
|
13
|
+
DateTime :last_authenticated_at
|
|
14
|
+
String :account_type, size: 64, null: false, default: 'primary'
|
|
15
|
+
String :qualifier, size: 255
|
|
16
|
+
TrueClass :is_default, null: false, default: false
|
|
17
|
+
String :link_evidence, text: true
|
|
18
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
19
|
+
DateTime :updated_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
20
|
+
|
|
21
|
+
unique %i[principal_id provider_id provider_identity_key]
|
|
22
|
+
index :uuid
|
|
23
|
+
index :principal_id
|
|
24
|
+
index :provider_id
|
|
25
|
+
index :provider_identity_key
|
|
26
|
+
index %i[provider_id provider_identity_key]
|
|
27
|
+
index :active
|
|
28
|
+
index :is_default
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Sequel.migration do
|
|
4
|
+
change do
|
|
5
|
+
create_table(:portable_identity_groups) do
|
|
6
|
+
primary_key :id
|
|
7
|
+
String :uuid, size: 36, null: false, unique: true
|
|
8
|
+
String :name, size: 255, null: false, unique: true
|
|
9
|
+
String :source, size: 64, null: false, default: 'ldap'
|
|
10
|
+
String :description, text: true
|
|
11
|
+
TrueClass :active, null: false, default: true
|
|
12
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
13
|
+
DateTime :updated_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
14
|
+
|
|
15
|
+
index :uuid
|
|
16
|
+
index :name
|
|
17
|
+
index :source
|
|
18
|
+
index :active
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Sequel.migration do
|
|
4
|
+
change do
|
|
5
|
+
create_table(:portable_identity_group_memberships) do
|
|
6
|
+
primary_key :id
|
|
7
|
+
String :uuid, size: 36, null: false, unique: true
|
|
8
|
+
foreign_key :principal_id, :portable_identity_principals, null: false, on_delete: :cascade
|
|
9
|
+
foreign_key :group_id, :portable_identity_groups, null: false, on_delete: :cascade
|
|
10
|
+
String :status, size: 32, null: false, default: 'active'
|
|
11
|
+
String :discovered_by, size: 255, null: false
|
|
12
|
+
Integer :trust_weight, null: false, default: 50
|
|
13
|
+
DateTime :expires_at
|
|
14
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
15
|
+
DateTime :updated_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
16
|
+
|
|
17
|
+
unique %i[principal_id group_id discovered_by]
|
|
18
|
+
index :uuid
|
|
19
|
+
index :principal_id
|
|
20
|
+
index :group_id
|
|
21
|
+
index :status
|
|
22
|
+
index %i[principal_id status]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Sequel.migration do
|
|
4
|
+
change do
|
|
5
|
+
create_table(:portable_identity_audit_log) do
|
|
6
|
+
primary_key :id
|
|
7
|
+
String :uuid, size: 36, null: false, unique: true
|
|
8
|
+
foreign_key :principal_id, :portable_identity_principals, on_delete: :set_null
|
|
9
|
+
foreign_key :identity_id, :portable_identities, on_delete: :set_null
|
|
10
|
+
String :provider_name, size: 255, null: false
|
|
11
|
+
String :event_type, size: 128, null: false
|
|
12
|
+
String :trust_level, size: 64
|
|
13
|
+
String :detail_payload, text: true
|
|
14
|
+
String :node_ref, size: 255
|
|
15
|
+
String :session_ref, size: 255
|
|
16
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
17
|
+
|
|
18
|
+
index :uuid
|
|
19
|
+
index :principal_id
|
|
20
|
+
index :identity_id
|
|
21
|
+
index :event_type
|
|
22
|
+
index :created_at
|
|
23
|
+
index %i[principal_id event_type created_at]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Sequel.migration do
|
|
4
|
+
change do
|
|
5
|
+
alter_table(:llm_message_inference_requests) do
|
|
6
|
+
add_column :operation, String, size: 64, null: false, default: 'chat'
|
|
7
|
+
add_column :correlation_id, String, size: 64
|
|
8
|
+
add_column :idempotency_key, String, size: 128
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
alter_table(:llm_message_inference_responses) do
|
|
12
|
+
add_column :provider_instance, String, size: 128
|
|
13
|
+
add_column :dispatch_path, String, size: 32
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/legion/data/model.rb
CHANGED
|
@@ -14,7 +14,17 @@ module Legion
|
|
|
14
14
|
%w[extension function relationship chain task runner node setting digital_worker
|
|
15
15
|
apollo_entry apollo_relation apollo_expertise apollo_access_log audit_log
|
|
16
16
|
audit_record identity_provider principal identity identity_group
|
|
17
|
-
identity_group_membership identity_audit_log extract_step_timing
|
|
17
|
+
identity_group_membership identity_audit_log extract_step_timing
|
|
18
|
+
identity/identity identity/principal identity/providers identity/group
|
|
19
|
+
identity/group_memberships identity/audit_log
|
|
20
|
+
apollo/entries apollo/relation apollo/access_log apollo/expertise
|
|
21
|
+
apollo/operation
|
|
22
|
+
rbac/role_assignments rbac/runner_grants rbac/cross_team_grants
|
|
23
|
+
llm/conversation llm/message llm/message_inference_request
|
|
24
|
+
llm/message_inference_response llm/route_attempt
|
|
25
|
+
llm/message_inference_metric llm/tool_call llm/tool_call_attempt
|
|
26
|
+
llm/conversation_compaction llm/policy_evaluation
|
|
27
|
+
llm/security_event llm/registry_event]
|
|
18
28
|
end
|
|
19
29
|
|
|
20
30
|
def load
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Apollo::ModelHelpers.table_available?(:apollo_access_log)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
module Apollo
|
|
11
|
+
class AccessLog < Sequel::Model(:apollo_access_log)
|
|
12
|
+
many_to_one :entry, class: 'Legion::Data::Model::Apollo::Entry', key: :entry_id
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Apollo::ModelHelpers.table_available?(:apollo_entries)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
module Apollo
|
|
11
|
+
class Entry < Sequel::Model(:apollo_entries)
|
|
12
|
+
one_to_many :outgoing_relations, class: 'Legion::Data::Model::Apollo::Relation',
|
|
13
|
+
key: :from_entry_id
|
|
14
|
+
one_to_many :incoming_relations, class: 'Legion::Data::Model::Apollo::Relation',
|
|
15
|
+
key: :to_entry_id
|
|
16
|
+
one_to_many :access_logs, class: 'Legion::Data::Model::Apollo::AccessLog',
|
|
17
|
+
key: :entry_id
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Apollo::ModelHelpers.table_available?(:apollo_expertise)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
module Apollo
|
|
11
|
+
class Expertise < Sequel::Model(:apollo_expertise)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Data
|
|
5
|
+
module Model
|
|
6
|
+
module Apollo
|
|
7
|
+
module ModelHelpers
|
|
8
|
+
def self.table_available?(table_name)
|
|
9
|
+
Legion::Data::Connection.sequel&.table_exists?(table_name)
|
|
10
|
+
rescue StandardError
|
|
11
|
+
false
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Apollo::ModelHelpers.table_available?(:apollo_operations)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
module Apollo
|
|
11
|
+
class Operation < Sequel::Model(:apollo_operations)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Apollo::ModelHelpers.table_available?(:apollo_relations)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
module Apollo
|
|
11
|
+
class Relation < Sequel::Model(:apollo_relations)
|
|
12
|
+
many_to_one :from_entry, class: 'Legion::Data::Model::Apollo::Entry', key: :from_entry_id
|
|
13
|
+
many_to_one :to_entry, class: 'Legion::Data::Model::Apollo::Entry', key: :to_entry_id
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -11,6 +11,7 @@ module Legion
|
|
|
11
11
|
many_to_one :runner
|
|
12
12
|
one_to_many :trigger_relationships, class: 'Legion::Data::Model::Relationship', key: :trigger_id
|
|
13
13
|
one_to_many :action_relationships, class: 'Legion::Data::Model::Relationship', key: :action_id
|
|
14
|
+
one_to_many :tasks
|
|
14
15
|
|
|
15
16
|
def embedding_vector
|
|
16
17
|
return nil unless embedding
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Identity::ModelHelpers.table_available?(:portable_identity_audit_log)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
class Identity
|
|
11
|
+
class AuditLog < Sequel::Model(:portable_identity_audit_log)
|
|
12
|
+
include ModelHelpers
|
|
13
|
+
|
|
14
|
+
many_to_one :principal, class: 'Legion::Data::Model::Identity::Principal'
|
|
15
|
+
many_to_one :identity, class: 'Legion::Data::Model::Identity::Identity'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Identity::ModelHelpers.table_available?(:portable_identity_groups)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
class Identity
|
|
11
|
+
class Group < Sequel::Model(:portable_identity_groups)
|
|
12
|
+
include ModelHelpers
|
|
13
|
+
|
|
14
|
+
one_to_many :memberships, class: 'Legion::Data::Model::Identity::GroupMembership', key: :group_id
|
|
15
|
+
many_to_many :principals,
|
|
16
|
+
class: 'Legion::Data::Model::Identity::Principal',
|
|
17
|
+
join_table: :portable_identity_group_memberships,
|
|
18
|
+
left_key: :group_id,
|
|
19
|
+
right_key: :principal_id
|
|
20
|
+
|
|
21
|
+
def self.lookup_columns
|
|
22
|
+
%i[id uuid name]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Identity::ModelHelpers.table_available?(:portable_identity_group_memberships)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
class Identity
|
|
11
|
+
class GroupMembership < Sequel::Model(:portable_identity_group_memberships)
|
|
12
|
+
include ModelHelpers
|
|
13
|
+
|
|
14
|
+
many_to_one :principal, class: 'Legion::Data::Model::Identity::Principal'
|
|
15
|
+
many_to_one :group, class: 'Legion::Data::Model::Identity::Group'
|
|
16
|
+
|
|
17
|
+
def expired?
|
|
18
|
+
status == 'expired' || (expires_at && Time.now >= expires_at)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def stale?
|
|
22
|
+
status == 'stale'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Identity::ModelHelpers.table_available?(:portable_identities)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
class Identity
|
|
11
|
+
class Identity < Sequel::Model(:portable_identities)
|
|
12
|
+
include ModelHelpers
|
|
13
|
+
|
|
14
|
+
many_to_one :principal, class: 'Legion::Data::Model::Identity::Principal'
|
|
15
|
+
many_to_one :provider, class: 'Legion::Data::Model::Identity::Provider', key: :provider_id
|
|
16
|
+
|
|
17
|
+
def self.lookup_columns
|
|
18
|
+
%i[id uuid provider_identity_key]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Data
|
|
7
|
+
module Model
|
|
8
|
+
class Identity
|
|
9
|
+
module ModelHelpers
|
|
10
|
+
def self.included(model)
|
|
11
|
+
model.extend(ClassMethods)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.table_available?(table_name)
|
|
15
|
+
Legion::Data::Connection.sequel&.table_exists?(table_name)
|
|
16
|
+
rescue StandardError
|
|
17
|
+
false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module ClassMethods
|
|
21
|
+
def lookup(value)
|
|
22
|
+
lookup_by_columns(value, lookup_columns)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def lookup_by_columns(value, lookup_columns)
|
|
26
|
+
normalized = normalize_lookup_value(value)
|
|
27
|
+
return if normalized.nil?
|
|
28
|
+
|
|
29
|
+
lookup_columns.each do |column|
|
|
30
|
+
next unless columns.include?(column)
|
|
31
|
+
|
|
32
|
+
query_value = lookup_query_value(column, normalized)
|
|
33
|
+
next if query_value == :skip
|
|
34
|
+
|
|
35
|
+
record = where(column => query_value).first
|
|
36
|
+
return record if record
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def lookup_columns
|
|
45
|
+
%i[id uuid name]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def normalize_lookup_value(value)
|
|
49
|
+
normalized = value.is_a?(String) ? value.strip : value
|
|
50
|
+
return if normalized.respond_to?(:empty?) && normalized.empty?
|
|
51
|
+
|
|
52
|
+
normalized
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def lookup_query_value(column, value)
|
|
56
|
+
case column
|
|
57
|
+
when :id
|
|
58
|
+
return value.to_i if integer_lookup_value?(value)
|
|
59
|
+
return value.to_s if uuid_lookup_value?(value) && !columns.include?(:uuid)
|
|
60
|
+
|
|
61
|
+
:skip
|
|
62
|
+
when :uuid
|
|
63
|
+
uuid_lookup_value?(value) ? value.to_s : :skip
|
|
64
|
+
else
|
|
65
|
+
value.to_s
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def integer_lookup_value?(value)
|
|
70
|
+
value.is_a?(Integer) || value.to_s.match?(/\A\d+\z/)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def uuid_lookup_value?(value)
|
|
74
|
+
value.to_s.match?(/\A[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/i)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def before_create
|
|
79
|
+
self[:uuid] ||= SecureRandom.uuid if self.class.columns.include?(:uuid)
|
|
80
|
+
super
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Identity::ModelHelpers.table_available?(:portable_identity_principals)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
class Identity
|
|
11
|
+
class Principal < Sequel::Model(:portable_identity_principals)
|
|
12
|
+
include ModelHelpers
|
|
13
|
+
|
|
14
|
+
one_to_many :identities, class: 'Legion::Data::Model::Identity::Identity'
|
|
15
|
+
one_to_many :group_memberships, class: 'Legion::Data::Model::Identity::GroupMembership'
|
|
16
|
+
many_to_many :groups,
|
|
17
|
+
class: 'Legion::Data::Model::Identity::Group',
|
|
18
|
+
join_table: :portable_identity_group_memberships,
|
|
19
|
+
left_key: :principal_id,
|
|
20
|
+
right_key: :group_id
|
|
21
|
+
|
|
22
|
+
def self.lookup_columns
|
|
23
|
+
%i[id uuid canonical_name employee_key]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def active_groups
|
|
27
|
+
group_memberships_dataset
|
|
28
|
+
.where(status: 'active')
|
|
29
|
+
.eager(:group)
|
|
30
|
+
.all
|
|
31
|
+
.map(&:group)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'model_helpers'
|
|
4
|
+
|
|
5
|
+
return unless Legion::Data::Model::Identity::ModelHelpers.table_available?(:portable_identity_providers)
|
|
6
|
+
|
|
7
|
+
module Legion
|
|
8
|
+
module Data
|
|
9
|
+
module Model
|
|
10
|
+
class Identity
|
|
11
|
+
class Provider < Sequel::Model(:portable_identity_providers)
|
|
12
|
+
include ModelHelpers
|
|
13
|
+
|
|
14
|
+
one_to_many :identities, class: 'Legion::Data::Model::Identity::Identity', key: :provider_id
|
|
15
|
+
one_to_many :capabilities,
|
|
16
|
+
class: 'Legion::Data::Model::Identity::ProviderCapability',
|
|
17
|
+
key: :provider_id
|
|
18
|
+
|
|
19
|
+
def self.lookup_columns
|
|
20
|
+
%i[id uuid name]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def parsed_capabilities
|
|
24
|
+
capabilities_dataset.select_map(:capability_key)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class ProviderCapability < Sequel::Model(:portable_identity_provider_capabilities)
|
|
29
|
+
many_to_one :provider, class: 'Legion::Data::Model::Identity::Provider'
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'identity/model_helpers'
|
|
4
|
+
|
|
3
5
|
return unless Legion::Data::Connection.adapter == :postgres
|
|
4
6
|
|
|
5
7
|
module Legion
|
|
6
8
|
module Data
|
|
7
9
|
module Model
|
|
8
10
|
class Identity < Sequel::Model(:identities)
|
|
11
|
+
include ModelHelpers
|
|
12
|
+
|
|
9
13
|
many_to_one :principal, class: 'Legion::Data::Model::Principal'
|
|
10
14
|
many_to_one :provider, class: 'Legion::Data::Model::IdentityProvider', key: :provider_id
|
|
11
15
|
|
|
16
|
+
def self.lookup_columns
|
|
17
|
+
%i[id uuid provider_identity_key provider_identity]
|
|
18
|
+
end
|
|
19
|
+
|
|
12
20
|
if defined?(Legion::Data::Encryption::SequelPlugin)
|
|
13
21
|
plugin Legion::Data::Encryption::SequelPlugin
|
|
14
22
|
encrypted_column :profile
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'identity/model_helpers'
|
|
4
|
+
|
|
3
5
|
return unless Legion::Data::Connection.adapter == :postgres
|
|
4
6
|
|
|
5
7
|
module Legion
|
|
6
8
|
module Data
|
|
7
9
|
module Model
|
|
8
10
|
class IdentityGroup < Sequel::Model(:identity_groups)
|
|
11
|
+
include Identity::ModelHelpers
|
|
12
|
+
|
|
9
13
|
one_to_many :memberships, class: 'Legion::Data::Model::IdentityGroupMembership', key: :group_id
|
|
14
|
+
many_to_many :principals,
|
|
15
|
+
class: 'Legion::Data::Model::Principal',
|
|
16
|
+
join_table: :identity_group_memberships,
|
|
17
|
+
left_key: :group_id,
|
|
18
|
+
right_key: :principal_id
|
|
19
|
+
|
|
20
|
+
def self.lookup_columns
|
|
21
|
+
%i[id uuid name]
|
|
22
|
+
end
|
|
10
23
|
end
|
|
11
24
|
end
|
|
12
25
|
end
|