lex-service_now 0.1.0 → 0.3.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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +45 -0
  4. data/CLAUDE.md +160 -0
  5. data/README.md +199 -0
  6. data/lex-service_now.gemspec +1 -0
  7. data/lib/legion/extensions/service_now/access_control/runners/access_control.rb +54 -0
  8. data/lib/legion/extensions/service_now/aggregate/runners/aggregate.rb +35 -0
  9. data/lib/legion/extensions/service_now/approval/runners/approval.rb +50 -0
  10. data/lib/legion/extensions/service_now/asset/runners/asset.rb +65 -0
  11. data/lib/legion/extensions/service_now/attachment/runners/attachment.rb +74 -0
  12. data/lib/legion/extensions/service_now/audit/runners/audit.rb +45 -0
  13. data/lib/legion/extensions/service_now/business_rule/runners/business_rule.rb +63 -0
  14. data/lib/legion/extensions/service_now/calendar/runners/calendar.rb +60 -0
  15. data/lib/legion/extensions/service_now/catalog_task/runners/catalog_task.rb +51 -0
  16. data/lib/legion/extensions/service_now/catalog_variable/runners/catalog_variable.rb +60 -0
  17. data/lib/legion/extensions/service_now/change/runners/change.rb +4 -4
  18. data/lib/legion/extensions/service_now/ci_relationship/runners/ci_relationship.rb +52 -0
  19. data/lib/legion/extensions/service_now/client.rb +58 -0
  20. data/lib/legion/extensions/service_now/cmdb_health/runners/cmdb_health.rb +48 -0
  21. data/lib/legion/extensions/service_now/company/runners/company.rb +55 -0
  22. data/lib/legion/extensions/service_now/contract/runners/contract.rb +55 -0
  23. data/lib/legion/extensions/service_now/cost_center/runners/cost_center.rb +52 -0
  24. data/lib/legion/extensions/service_now/currency/runners/currency.rb +40 -0
  25. data/lib/legion/extensions/service_now/department/runners/department.rb +56 -0
  26. data/lib/legion/extensions/service_now/deprecation_log/runners/deprecation_log.rb +43 -0
  27. data/lib/legion/extensions/service_now/discovery/runners/discovery.rb +53 -0
  28. data/lib/legion/extensions/service_now/email_log/runners/email_log.rb +38 -0
  29. data/lib/legion/extensions/service_now/errors.rb +26 -0
  30. data/lib/legion/extensions/service_now/event/runners/event.rb +40 -0
  31. data/lib/legion/extensions/service_now/flow/runners/flow.rb +52 -0
  32. data/lib/legion/extensions/service_now/helpers/client.rb +32 -0
  33. data/lib/legion/extensions/service_now/helpers/pagination.rb +31 -0
  34. data/lib/legion/extensions/service_now/helpers/retry.rb +32 -0
  35. data/lib/legion/extensions/service_now/hr_case/runners/hr_case.rb +55 -0
  36. data/lib/legion/extensions/service_now/import_set/runners/import_set.rb +31 -0
  37. data/lib/legion/extensions/service_now/incident/runners/incident.rb +77 -0
  38. data/lib/legion/extensions/service_now/knowledge_base/runners/knowledge_base.rb +64 -0
  39. data/lib/legion/extensions/service_now/knowledge_feedback/runners/knowledge_feedback.rb +45 -0
  40. data/lib/legion/extensions/service_now/license/runners/license.rb +44 -0
  41. data/lib/legion/extensions/service_now/location/runners/location.rb +59 -0
  42. data/lib/legion/extensions/service_now/metric/runners/metric.rb +47 -0
  43. data/lib/legion/extensions/service_now/mid_server/runners/mid_server.rb +54 -0
  44. data/lib/legion/extensions/service_now/notification/runners/notification.rb +56 -0
  45. data/lib/legion/extensions/service_now/on_call/runners/on_call.rb +52 -0
  46. data/lib/legion/extensions/service_now/performance_analytics/runners/performance_analytics.rb +51 -0
  47. data/lib/legion/extensions/service_now/problem/runners/problem.rb +73 -0
  48. data/lib/legion/extensions/service_now/project/runners/project.rb +67 -0
  49. data/lib/legion/extensions/service_now/release/runners/release.rb +54 -0
  50. data/lib/legion/extensions/service_now/request/runners/request.rb +62 -0
  51. data/lib/legion/extensions/service_now/scheduled_job/runners/scheduled_job.rb +54 -0
  52. data/lib/legion/extensions/service_now/script_action/runners/script_action.rb +50 -0
  53. data/lib/legion/extensions/service_now/script_include/runners/script_include.rb +55 -0
  54. data/lib/legion/extensions/service_now/security_incident/runners/security_incident.rb +58 -0
  55. data/lib/legion/extensions/service_now/skills/approval_workflow.rb +51 -0
  56. data/lib/legion/extensions/service_now/skills/asset_management.rb +52 -0
  57. data/lib/legion/extensions/service_now/skills/problem_management.rb +60 -0
  58. data/lib/legion/extensions/service_now/skills/request_fulfillment.rb +60 -0
  59. data/lib/legion/extensions/service_now/skills/security_incident_response.rb +60 -0
  60. data/lib/legion/extensions/service_now/sla/runners/sla.rb +49 -0
  61. data/lib/legion/extensions/service_now/survey/runners/survey.rb +52 -0
  62. data/lib/legion/extensions/service_now/system_property/runners/system_property.rb +54 -0
  63. data/lib/legion/extensions/service_now/table/runners/table.rb +56 -0
  64. data/lib/legion/extensions/service_now/tag/runners/tag.rb +61 -0
  65. data/lib/legion/extensions/service_now/task/runners/task.rb +56 -0
  66. data/lib/legion/extensions/service_now/ui_action/runners/ui_action.rb +53 -0
  67. data/lib/legion/extensions/service_now/ui_policy/runners/ui_policy.rb +51 -0
  68. data/lib/legion/extensions/service_now/update_set/runners/update_set.rb +61 -0
  69. data/lib/legion/extensions/service_now/user/runners/user.rb +74 -0
  70. data/lib/legion/extensions/service_now/user_group/runners/user_group.rb +79 -0
  71. data/lib/legion/extensions/service_now/vendor/runners/vendor.rb +61 -0
  72. data/lib/legion/extensions/service_now/version.rb +1 -1
  73. data/lib/legion/extensions/service_now/work_order/runners/work_order.rb +66 -0
  74. data/lib/legion/extensions/service_now/workflow/runners/workflow.rb +59 -0
  75. data/lib/legion/extensions/service_now.rb +64 -0
  76. metadata +81 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9850b5ae25b0769c3e26b07fac9cbfe6fb6913e718e0eaba29c2a62e42bdc155
4
- data.tar.gz: 72b828b004be9fe534c51a677c011a6cbe8d6470f91e7b25912d42b1ee1eb956
3
+ metadata.gz: 7299f2cb64f753600e58b75350804a51164e4ed0b246a0124e9dd691ae813860
4
+ data.tar.gz: 4cdb63326d0a106814c0f6abb67bf819198e0114d299dbf971a3185ed3b75f8c
5
5
  SHA512:
6
- metadata.gz: 6d728a8a52d1178d62eaa70b3d1c90b41a22fff61e9a8dc6916369eeb508e523f16b09c7e12262c8d6dec3c13ad62892ccfbffe6a8dc33ceca56379b26cff5fd
7
- data.tar.gz: ae69b9ad088f9f5ed8fb5420cb6dea76eb6c083152af6800af83d74a34c8f32f1d093da9a3ede7b8b6f95ece399f65f8a3c32d3c0e2e380afbf12c59acc37f1b
6
+ metadata.gz: 619c90c1289c5b046076a55290a5969d51605b5491ad3163a4038de98d99e06294b62774d5a3d24592ec27f0705ab759df3aafca91778be7c6af10f8d0e0d3ea
7
+ data.tar.gz: 3ee2c4fb6921cf67f71139d9a288d6d056302a0b403f63dcb6b809dfb3667ca00b7689255e5ade8bb188d618a97169338b71673b7c8febb99401ca7e2e493374
data/.rubocop.yml CHANGED
@@ -28,7 +28,7 @@ Metrics/BlockLength:
28
28
  - 'spec/**/*'
29
29
 
30
30
  Metrics/ParameterLists:
31
- Max: 8
31
+ Max: 12
32
32
 
33
33
  Naming/MethodParameterName:
34
34
  MinNameLength: 2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0] - 2026-04-22
4
+
5
+ ### Added
6
+ - Incident runner (6 methods)
7
+ - Problem runner (6 methods)
8
+ - Attachment runner (5 methods) with multipart upload support
9
+ - Table runner (5 methods) — generic CRUD escape hatch for any table
10
+ - Aggregate runner (1 method) — stats/count/sum/avg queries
11
+ - User runner (7 methods) including lookup by username and email
12
+ - UserGroup runner (9 methods) including member management
13
+ - Request/RITM runner (6 methods)
14
+ - Approval runner (5 methods) — approve, reject, list_for_record
15
+ - Task runner (5 methods) including add_work_note
16
+ - SLA runner (5 methods) — definitions and task SLA tracking
17
+ - ImportSet runner (2 methods)
18
+ - Event runner (3 methods)
19
+ - PerformanceAnalytics runner (5 methods) — widgets, scorecards, indicators
20
+ - Flow/Subflow runner (6 methods)
21
+ - Notification runner (5 methods)
22
+ - EmailLog runner (3 methods)
23
+ - Audit runner (3 methods) — field change history
24
+ - SystemProperty runner (6 methods)
25
+ - Asset runner (6 methods) including hardware
26
+ - Location runner (5 methods)
27
+ - Department runner (5 methods)
28
+ - Company runner (5 methods)
29
+ - Project runner (6 methods) including project tasks
30
+ - Release runner (5 methods)
31
+ - HrCase runner (5 methods)
32
+ - SecurityIncident runner (5 methods)
33
+ - UpdateSet runner (6 methods) including change listing
34
+ - ScriptInclude runner (5 methods)
35
+ - BusinessRule runner (5 methods)
36
+ - ScheduledJob runner (5 methods)
37
+ - OnCall runner (5 methods) — schedules, members, who_is_on_call
38
+ - Survey runner (5 methods) — instances and responses
39
+ - Contract runner (5 methods)
40
+ - CostCenter runner (5 methods)
41
+ - WorkOrder runner (6 methods) including tasks
42
+ - Discovery runner (5 methods)
43
+ - MidServer runner (5 methods)
44
+ - CatalogVariable runner (5 methods)
45
+ - Workflow runner (6 methods) — contexts and cancellation
46
+ - 10 LLM skills: Incident, ChangeRequest, CmdbQuery, Knowledge, ServiceCatalog, ProblemManagement, RequestFulfillment, ApprovalWorkflow, AssetManagement, SecurityIncidentResponse
47
+
3
48
  ## [0.1.0] - 2026-04-22
4
49
 
5
50
  ### Added
data/CLAUDE.md ADDED
@@ -0,0 +1,160 @@
1
+ # lex-service_now: ServiceNow Integration for LegionIO
2
+
3
+ **Repository Level 3 Documentation**
4
+ - **Parent**: `/Users/miverso2/rubymine/legion/extensions-other/CLAUDE.md`
5
+ - **Grandparent**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
6
+
7
+ ## Purpose
8
+
9
+ Comprehensive Legion Extension connecting LegionIO to ServiceNow via REST APIs. Covers 46 domains spanning ITSM, ITOM, ITAM, HR, Security, DevOps, and platform administration.
10
+
11
+ **Version**: 0.2.0
12
+ **GitHub**: https://github.com/LegionIO/lex-service_now
13
+ **License**: MIT
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ Legion::Extensions::ServiceNow
19
+ +-- Helpers/
20
+ | +-- Client # connection() with OAuth2→Bearer→Basic auth priority fallback
21
+ +-- ITSM/
22
+ | +-- Change::Runners::Change (14 methods) — normal/emergency/standard + tasks/conflicts/approvals
23
+ | +-- Incident::Runners::Incident (6 methods) — CRUD + resolve
24
+ | +-- Problem::Runners::Problem (6 methods) — CRUD + close
25
+ | +-- Request::Runners::Request (6 methods) — sc_request + sc_req_item
26
+ | +-- Approval::Runners::Approval (5 methods) — approve/reject + list_for_record
27
+ | +-- Task::Runners::Task (5 methods) — CRUD + add_work_note
28
+ | +-- Sla::Runners::Sla (5 methods) — definitions + task SLAs
29
+ +-- CMDB/
30
+ | +-- Cmdb::Instance::Runners::Instance (7 methods) — CI CRUD + relationships
31
+ | +-- Cmdb::Meta::Runners::Meta (2 methods) — hierarchy + class metadata
32
+ +-- Knowledge/
33
+ | +-- Knowledge::Runners::Knowledge (5 methods) — article CRUD
34
+ +-- ServiceCatalog/
35
+ | +-- ServiceCatalog::Runners::ServiceCatalog (11 methods) — catalogs/items/cart/order
36
+ | +-- CatalogVariable::Runners::CatalogVariable (5 methods) — item variables CRUD
37
+ +-- User Management/
38
+ | +-- User::Runners::User (7 methods) — CRUD + lookup_by_username/email
39
+ | +-- UserGroup::Runners::UserGroup (9 methods) — CRUD + member management
40
+ | +-- Account::Runners::Account (4 methods) — core account CRUD
41
+ +-- Assets/
42
+ | +-- Asset::Runners::Asset (6 methods) — alm_asset CRUD + hardware
43
+ | +-- Contract::Runners::Contract (5 methods) — ast_contract CRUD
44
+ +-- Organization/
45
+ | +-- Location::Runners::Location (5 methods) — cmn_location CRUD
46
+ | +-- Department::Runners::Department (5 methods) — cmn_department CRUD
47
+ | +-- Company::Runners::Company (5 methods) — core_company CRUD
48
+ | +-- CostCenter::Runners::CostCenter (5 methods) — cmn_cost_center CRUD
49
+ +-- Project & Release/
50
+ | +-- Project::Runners::Project (6 methods) — pm_project CRUD + tasks
51
+ | +-- Release::Runners::Release (5 methods) — rm_release CRUD
52
+ +-- Security/
53
+ | +-- SecurityIncident::Runners::SecurityIncident (5 methods) — sn_si_incident CRUD
54
+ +-- HR/
55
+ | +-- HrCase::Runners::HrCase (5 methods) — sn_hr_core_case CRUD
56
+ +-- Platform Admin/
57
+ | +-- SystemProperty::Runners::SystemProperty (6 methods) — sys_properties CRUD
58
+ | +-- UpdateSet::Runners::UpdateSet (6 methods) — CRUD + list changes
59
+ | +-- ScriptInclude::Runners::ScriptInclude (5 methods) — sys_script_include CRUD
60
+ | +-- BusinessRule::Runners::BusinessRule (5 methods) — sys_script CRUD
61
+ | +-- ScheduledJob::Runners::ScheduledJob (5 methods) — sysauto_script CRUD
62
+ | +-- Workflow::Runners::Workflow (6 methods) — wf_workflow + contexts
63
+ | +-- Flow::Runners::Flow (6 methods) — sn_fd flow execute + subflows
64
+ | +-- Audit::Runners::Audit (3 methods) — sys_audit + field changes
65
+ +-- ITOM/
66
+ | +-- Discovery::Runners::Discovery (5 methods) — schedules/logs/devices
67
+ | +-- MidServer::Runners::MidServer (5 methods) — ecc_agent CRUD + capabilities
68
+ | +-- Event::Runners::Event (3 methods) — sysevent CRUD
69
+ +-- Analytics/
70
+ | +-- PerformanceAnalytics::Runners::PerformanceAnalytics (5 methods) — widgets/scorecards/indicators
71
+ | +-- Aggregate::Runners::Aggregate (1 method) — stats queries on any table
72
+ +-- Comms/
73
+ | +-- Notification::Runners::Notification (5 methods) — sysevent_email_action CRUD
74
+ | +-- EmailLog::Runners::EmailLog (3 methods) — sys_email list/get/list_for_record
75
+ +-- Field Service/
76
+ | +-- WorkOrder::Runners::WorkOrder (6 methods) — wm_order CRUD + tasks + close
77
+ | +-- OnCall::Runners::OnCall (5 methods) — cmn_rota + members + who_is_on_call
78
+ +-- Utilities/
79
+ | +-- Table::Runners::Table (5 methods) — generic CRUD on any table
80
+ | +-- ImportSet::Runners::ImportSet (2 methods) — /api/now/import
81
+ | +-- Survey::Runners::Survey (5 methods) — assessments + instances + responses
82
+ +-- Skills/ (loaded only if legion-llm available)
83
+ | +-- Incident, ChangeRequest, CmdbQuery, Knowledge, ServiceCatalog
84
+ | +-- ProblemManagement, RequestFulfillment, ApprovalWorkflow
85
+ | +-- AssetManagement, SecurityIncidentResponse
86
+ +-- Client # Standalone client class including all 46 runners
87
+ ```
88
+
89
+ ## Authentication
90
+
91
+ `Helpers::Client#connection` selects auth priority order (most secure first):
92
+ 1. **OAuth2** — `client_id` + `client_secret` → client credentials grant → `/oauth_token.do`, token memoized in `@fetch_oauth2_token`
93
+ 2. **Bearer** — `token` → `Authorization: Bearer <token>`
94
+ 3. **Basic Auth** — `username` + `password` → HTTP Basic
95
+
96
+ Instance URL defaults to `Legion::Settings[:service_now][:url]`, overridable per `Client.new` or per call.
97
+
98
+ ## Standalone Client
99
+
100
+ ```ruby
101
+ client = Legion::Extensions::ServiceNow::Client.new(
102
+ url: 'https://your-instance.service-now.com',
103
+ username: 'svc_account',
104
+ password: 'secret'
105
+ )
106
+
107
+ # Or with OAuth2
108
+ client = Legion::Extensions::ServiceNow::Client.new(
109
+ url: 'https://your-instance.service-now.com',
110
+ client_id: 'abc',
111
+ client_secret: 'xyz'
112
+ )
113
+
114
+ client.list_incidents(sysparm_query: 'state=1', sysparm_limit: 50)
115
+ client.create_change(short_description: 'Deploy v2.0')
116
+ client.get_ci(class_name: 'cmdb_ci_server', sys_id: 'abc123')
117
+ ```
118
+
119
+ ## Settings
120
+
121
+ ```json
122
+ {
123
+ "service_now": {
124
+ "url": "https://your-instance.service-now.com",
125
+ "username": null,
126
+ "password": null,
127
+ "token": null,
128
+ "client_id": null,
129
+ "client_secret": null
130
+ }
131
+ }
132
+ ```
133
+
134
+ ## Dependencies
135
+
136
+ | Gem | Purpose |
137
+ |-----|---------|
138
+ | `faraday >= 2.0` | HTTP client |
139
+ | `faraday-multipart >= 1.0` | Multipart upload for attachments |
140
+ | `legion-settings >= 1.3.14` | Settings/config |
141
+ | `legion-logging >= 1.3.2` | Structured logging |
142
+ | `legion-cache >= 1.3.11` | Caching |
143
+ | `legion-crypt >= 1.4.9` | Credential encryption |
144
+ | `legion-data >= 1.4.17` | ORM |
145
+ | `legion-json >= 1.2.1` | JSON helpers |
146
+ | `legion-transport >= 1.3.9` | AMQP transport |
147
+
148
+ `legion-llm` is an optional soft dependency — skills load only if defined.
149
+
150
+ ## Development
151
+
152
+ ```bash
153
+ bundle install
154
+ bundle exec rspec # 217+ examples, 0 failures
155
+ bundle exec rubocop # 0 offenses
156
+ ```
157
+
158
+ ---
159
+
160
+ **Maintained By**: Matthew Iverson (@Esity)
data/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # lex-service_now
2
+
3
+ A LegionIO extension connecting Legion to ServiceNow via REST APIs. Covers 46 domains spanning ITSM, ITOM, ITAM, HR, Security, DevOps, and platform administration.
4
+
5
+ ## Installation
6
+
7
+ Add to your Gemfile:
8
+
9
+ ```ruby
10
+ gem 'lex-service_now'
11
+ ```
12
+
13
+ ## Configuration
14
+
15
+ Set credentials via Legion settings (`~/.legionio/settings/service_now.json`):
16
+
17
+ ```json
18
+ {
19
+ "service_now": {
20
+ "url": "https://your-instance.service-now.com",
21
+ "username": "svc_account",
22
+ "password": "secret"
23
+ }
24
+ }
25
+ ```
26
+
27
+ OAuth2 and Bearer token auth are also supported — the most secure credentials provided are used automatically (OAuth2 > Bearer > Basic Auth).
28
+
29
+ ## Usage
30
+
31
+ ### Standalone Client
32
+
33
+ ```ruby
34
+ require 'legion/extensions/service_now'
35
+
36
+ client = Legion::Extensions::ServiceNow::Client.new(
37
+ url: 'https://your-instance.service-now.com',
38
+ username: 'admin',
39
+ password: 'secret'
40
+ )
41
+
42
+ # Incidents
43
+ client.list_incidents(sysparm_query: 'state=1^priority=1', sysparm_limit: 10)
44
+ client.create_incident(short_description: 'Production server down', urgency: '1', impact: '1')
45
+ client.resolve_incident(sys_id: 'abc123', close_code: 'Solved (Permanently)', close_notes: 'Fixed')
46
+
47
+ # Change Management
48
+ client.create_normal(short_description: 'Deploy app v2.0', assignment_group: 'CAB Approval')
49
+ client.get_change(id: 'CHG0012345')
50
+ client.get_approvals(id: 'CHG0012345')
51
+
52
+ # CMDB
53
+ client.list_cis(class_name: 'cmdb_ci_server', sysparm_query: 'operational_status=1')
54
+ client.get_relationships(class_name: 'cmdb_ci_server', sys_id: 'srv001')
55
+
56
+ # Service Catalog
57
+ client.list_items(catalog_id: 'cat1')
58
+ client.order_now(sys_id: 'item_id', quantity: 1, variables: { justification: 'Project work' })
59
+
60
+ # Users & Groups
61
+ client.get_user_by_email(email: 'jdoe@company.com')
62
+ client.list_group_members(group_sys_id: 'network_team_id')
63
+
64
+ # Generic Table API (escape hatch for any table)
65
+ client.table_list(table_name: 'u_custom_table', sysparm_query: 'active=true')
66
+ ```
67
+
68
+ ## Supported Domains
69
+
70
+ ### ITSM
71
+ | Domain | Methods | Table |
72
+ |--------|---------|-------|
73
+ | Change | 14 | `sn_chg_rest` API |
74
+ | Incident | 6 | `incident` |
75
+ | Problem | 6 | `problem` |
76
+ | Request/RITM | 6 | `sc_request`, `sc_req_item` |
77
+ | Approval | 5 | `sysapproval_approver` |
78
+ | Task | 5 | `task` |
79
+ | SLA | 5 | `contract_sla`, `task_sla` |
80
+
81
+ ### CMDB & Discovery
82
+ | Domain | Methods | Table |
83
+ |--------|---------|-------|
84
+ | CMDB Instance | 7 | `/api/now/cmdb/instance` |
85
+ | CMDB Meta | 2 | `/api/now/doc/meta` |
86
+ | Discovery | 5 | `discovery_schedule`, `discovery_log` |
87
+ | MID Server | 5 | `ecc_agent` |
88
+
89
+ ### Service Catalog
90
+ | Domain | Methods | Table |
91
+ |--------|---------|-------|
92
+ | Service Catalog | 11 | `/api/sn_sc/servicecatalog` |
93
+ | Catalog Variable | 5 | `item_option_new` |
94
+
95
+ ### Knowledge & Content
96
+ | Domain | Methods | Table |
97
+ |--------|---------|-------|
98
+ | Knowledge | 5 | `/api/sn_km_api/knowledge` |
99
+ | Survey | 5 | `survey`, `asmt_assessment_instance` |
100
+
101
+ ### User & Organization
102
+ | Domain | Methods | Table |
103
+ |--------|---------|-------|
104
+ | User | 7 | `sys_user` |
105
+ | UserGroup | 9 | `sys_user_group`, `sys_user_grmember` |
106
+ | Account | 4 | `account` |
107
+ | Location | 5 | `cmn_location` |
108
+ | Department | 5 | `cmn_department` |
109
+ | Company | 5 | `core_company` |
110
+ | Cost Center | 5 | `cmn_cost_center` |
111
+
112
+ ### Asset & Contract Management
113
+ | Domain | Methods | Table |
114
+ |--------|---------|-------|
115
+ | Asset | 6 | `alm_asset`, `alm_hardware` |
116
+ | Contract | 5 | `ast_contract` |
117
+
118
+ ### Security
119
+ | Domain | Methods | Table |
120
+ |--------|---------|-------|
121
+ | Security Incident | 5 | `sn_si_incident` |
122
+
123
+ ### HR
124
+ | Domain | Methods | Table |
125
+ |--------|---------|-------|
126
+ | HR Case | 5 | `sn_hr_core_case` |
127
+
128
+ ### Project & Release
129
+ | Domain | Methods | Table |
130
+ |--------|---------|-------|
131
+ | Project | 6 | `pm_project`, `pm_project_task` |
132
+ | Release | 5 | `rm_release` |
133
+
134
+ ### Platform Administration
135
+ | Domain | Methods | Table |
136
+ |--------|---------|-------|
137
+ | System Property | 6 | `sys_properties` |
138
+ | Update Set | 6 | `sys_update_set`, `sys_update_xml` |
139
+ | Script Include | 5 | `sys_script_include` |
140
+ | Business Rule | 5 | `sys_script` |
141
+ | Scheduled Job | 5 | `sysauto_script` |
142
+ | Workflow | 6 | `wf_workflow`, `wf_context` |
143
+ | Flow/Subflow | 6 | `/api/sn_fd` |
144
+ | Audit | 3 | `sys_audit` |
145
+
146
+ ### ITOM & Monitoring
147
+ | Domain | Methods | Table |
148
+ |--------|---------|-------|
149
+ | Event | 3 | `sysevent` |
150
+ | Performance Analytics | 5 | `/api/now/pa` |
151
+
152
+ ### Communications
153
+ | Domain | Methods | Table |
154
+ |--------|---------|-------|
155
+ | Notification | 5 | `sysevent_email_action` |
156
+ | Email Log | 3 | `sys_email` |
157
+
158
+ ### Field Service
159
+ | Domain | Methods | Table |
160
+ |--------|---------|-------|
161
+ | Work Order | 6 | `wm_order`, `wm_task` |
162
+ | On-Call | 5 | `cmn_rota`, `cmn_rota_member` |
163
+
164
+ ### Utilities
165
+ | Domain | Methods | Table |
166
+ |--------|---------|-------|
167
+ | Table (generic) | 5 | Any table via `/api/now/table/{table}` |
168
+ | Import Set | 2 | `/api/now/import` |
169
+ | Aggregate | 1 | `/api/now/stats/{table}` |
170
+ | Attachment | 5 | `/api/now/attachment` |
171
+
172
+ ## LLM Skills
173
+
174
+ When `legion-llm` is available, 10 workflow skills are registered automatically:
175
+
176
+ | Skill | Trigger Words |
177
+ |-------|--------------|
178
+ | `servicenow:incident` | incident, INC, outage, p1, sev1 |
179
+ | `servicenow:change_request` | CHG, RFC, change request, CAB |
180
+ | `servicenow:cmdb_query` | CMDB, CI, configuration item |
181
+ | `servicenow:knowledge` | KB, knowledge base, article |
182
+ | `servicenow:service_catalog` | catalog, service request, order |
183
+ | `servicenow:problem_management` | PRB, problem, root cause, RCA |
184
+ | `servicenow:request_fulfillment` | RITM, request item, fulfillment |
185
+ | `servicenow:approval_workflow` | approval, approve, reject |
186
+ | `servicenow:asset_management` | asset, hardware, inventory, ALM |
187
+ | `servicenow:security_incident_response` | SIR, security incident, breach |
188
+
189
+ ## Development
190
+
191
+ ```bash
192
+ bundle install
193
+ bundle exec rspec # 217 examples, 0 failures
194
+ bundle exec rubocop # 0 offenses
195
+ ```
196
+
197
+ ## License
198
+
199
+ MIT — see [LICENSE](LICENSE).
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.require_paths = ['lib']
26
26
 
27
27
  spec.add_dependency 'faraday', '>= 2.0'
28
+ spec.add_dependency 'faraday-multipart', '>= 1.0'
28
29
  spec.add_dependency 'legion-cache', '>= 1.3.11'
29
30
  spec.add_dependency 'legion-crypt', '>= 1.4.9'
30
31
  spec.add_dependency 'legion-data', '>= 1.4.17'
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module ServiceNow
6
+ module AccessControl
7
+ module Runners
8
+ module AccessControl
9
+ include Legion::Extensions::ServiceNow::Helpers::Client
10
+
11
+ def list_acls(sysparm_limit: 100, sysparm_offset: 0,
12
+ sysparm_query: nil, **)
13
+ params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
14
+ params[:sysparm_query] = sysparm_query if sysparm_query
15
+ resp = connection(**).get('/api/now/table/sys_security_acl', params)
16
+ { acls: resp.body['result'] }
17
+ end
18
+
19
+ def get_acl(sys_id:, **)
20
+ resp = connection(**).get("/api/now/table/sys_security_acl/#{sys_id}")
21
+ { acl: resp.body['result'] }
22
+ end
23
+
24
+ def create_acl(name:, type:, operation:, active: true,
25
+ script: nil, condition: nil, **)
26
+ body = { name: name, type: type, operation: operation, active: active }
27
+ body[:script] = script if script
28
+ body[:condition] = condition if condition
29
+ resp = connection(**).post('/api/now/table/sys_security_acl', body)
30
+ { acl: resp.body['result'] }
31
+ end
32
+
33
+ def update_acl(sys_id:, active: nil, script: nil, condition: nil, **)
34
+ body = {}
35
+ body[:active] = active unless active.nil?
36
+ body[:script] = script if script
37
+ body[:condition] = condition if condition
38
+ resp = connection(**).patch("/api/now/table/sys_security_acl/#{sys_id}", body)
39
+ { acl: resp.body['result'] }
40
+ end
41
+
42
+ def delete_acl(sys_id:, **)
43
+ resp = connection(**).delete("/api/now/table/sys_security_acl/#{sys_id}")
44
+ { deleted: resp.status == 204, sys_id: sys_id }
45
+ end
46
+
47
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
48
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module ServiceNow
6
+ module Aggregate
7
+ module Runners
8
+ module Aggregate
9
+ include Legion::Extensions::ServiceNow::Helpers::Client
10
+
11
+ def aggregate(table_name:, sysparm_count: nil, sysparm_sum_fields: nil,
12
+ sysparm_avg_fields: nil, sysparm_min_fields: nil,
13
+ sysparm_max_fields: nil, sysparm_query: nil,
14
+ sysparm_group_by: nil, sysparm_having: nil, **)
15
+ params = {}
16
+ params[:sysparm_count] = sysparm_count unless sysparm_count.nil?
17
+ params[:sysparm_sum_fields] = sysparm_sum_fields if sysparm_sum_fields
18
+ params[:sysparm_avg_fields] = sysparm_avg_fields if sysparm_avg_fields
19
+ params[:sysparm_min_fields] = sysparm_min_fields if sysparm_min_fields
20
+ params[:sysparm_max_fields] = sysparm_max_fields if sysparm_max_fields
21
+ params[:sysparm_query] = sysparm_query if sysparm_query
22
+ params[:sysparm_group_by] = sysparm_group_by if sysparm_group_by
23
+ params[:sysparm_having] = sysparm_having if sysparm_having
24
+ resp = connection(**).get("/api/now/stats/#{table_name}", params)
25
+ { stats: resp.body['result'] }
26
+ end
27
+
28
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
29
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module ServiceNow
6
+ module Approval
7
+ module Runners
8
+ module Approval
9
+ include Legion::Extensions::ServiceNow::Helpers::Client
10
+
11
+ def list_approvals(sysparm_limit: 100, sysparm_offset: 0, sysparm_query: nil, **)
12
+ params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
13
+ params[:sysparm_query] = sysparm_query if sysparm_query
14
+ resp = connection(**).get('/api/now/table/sysapproval_approver', params)
15
+ { approvals: resp.body['result'] }
16
+ end
17
+
18
+ def get_approval(sys_id:, **)
19
+ resp = connection(**).get("/api/now/table/sysapproval_approver/#{sys_id}")
20
+ { approval: resp.body['result'] }
21
+ end
22
+
23
+ def approve(sys_id:, comments: nil, **)
24
+ body = { state: 'approved' }
25
+ body[:comments] = comments if comments
26
+ resp = connection(**).patch("/api/now/table/sysapproval_approver/#{sys_id}", body)
27
+ { approval: resp.body['result'] }
28
+ end
29
+
30
+ def reject(sys_id:, comments: nil, **)
31
+ body = { state: 'rejected' }
32
+ body[:comments] = comments if comments
33
+ resp = connection(**).patch("/api/now/table/sysapproval_approver/#{sys_id}", body)
34
+ { approval: resp.body['result'] }
35
+ end
36
+
37
+ def list_approvals_for_record(document_id:, **)
38
+ params = { sysparm_query: "document_id=#{document_id}", sysparm_limit: 100 }
39
+ resp = connection(**).get('/api/now/table/sysapproval_approver', params)
40
+ { approvals: resp.body['result'] }
41
+ end
42
+
43
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
44
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module ServiceNow
6
+ module Asset
7
+ module Runners
8
+ module Asset
9
+ include Legion::Extensions::ServiceNow::Helpers::Client
10
+
11
+ def list_assets(sysparm_limit: 100, sysparm_offset: 0, sysparm_query: nil,
12
+ sysparm_fields: nil, **)
13
+ params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
14
+ params[:sysparm_query] = sysparm_query if sysparm_query
15
+ params[:sysparm_fields] = sysparm_fields if sysparm_fields
16
+ resp = connection(**).get('/api/now/table/alm_asset', params)
17
+ { assets: resp.body['result'] }
18
+ end
19
+
20
+ def get_asset(sys_id:, **)
21
+ resp = connection(**).get("/api/now/table/alm_asset/#{sys_id}")
22
+ { asset: resp.body['result'] }
23
+ end
24
+
25
+ def create_asset(model:, model_category:, serial_number: nil,
26
+ assigned_to: nil, state: nil, **)
27
+ body = { model: model, model_category: model_category }
28
+ body[:serial_number] = serial_number if serial_number
29
+ body[:assigned_to] = assigned_to if assigned_to
30
+ body[:state] = state if state
31
+ resp = connection(**).post('/api/now/table/alm_asset', body)
32
+ { asset: resp.body['result'] }
33
+ end
34
+
35
+ def update_asset(sys_id:, state: nil, assigned_to: nil,
36
+ location: nil, serial_number: nil, **)
37
+ body = {}
38
+ body[:state] = state if state
39
+ body[:assigned_to] = assigned_to if assigned_to
40
+ body[:location] = location if location
41
+ body[:serial_number] = serial_number if serial_number
42
+ resp = connection(**).patch("/api/now/table/alm_asset/#{sys_id}", body)
43
+ { asset: resp.body['result'] }
44
+ end
45
+
46
+ def delete_asset(sys_id:, **)
47
+ resp = connection(**).delete("/api/now/table/alm_asset/#{sys_id}")
48
+ { deleted: resp.status == 204, sys_id: sys_id }
49
+ end
50
+
51
+ def list_hardware(sysparm_limit: 100, sysparm_offset: 0, sysparm_query: nil, **)
52
+ params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
53
+ params[:sysparm_query] = sysparm_query if sysparm_query
54
+ resp = connection(**).get('/api/now/table/alm_hardware', params)
55
+ { hardware: resp.body['result'] }
56
+ end
57
+
58
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
59
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end