lex-service_now 0.2.0 → 0.3.1

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -49
  3. data/CLAUDE.md +107 -79
  4. data/README.md +140 -94
  5. data/lex-service_now.gemspec +1 -1
  6. data/lib/legion/extensions/service_now/access_control/runners/access_control.rb +54 -0
  7. data/lib/legion/extensions/service_now/account/runners/account.rb +4 -4
  8. data/lib/legion/extensions/service_now/aggregate/runners/aggregate.rb +1 -1
  9. data/lib/legion/extensions/service_now/approval/runners/approval.rb +5 -5
  10. data/lib/legion/extensions/service_now/asset/runners/asset.rb +6 -6
  11. data/lib/legion/extensions/service_now/attachment/runners/attachment.rb +4 -4
  12. data/lib/legion/extensions/service_now/audit/runners/audit.rb +3 -3
  13. data/lib/legion/extensions/service_now/business_rule/runners/business_rule.rb +5 -5
  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 +5 -5
  17. data/lib/legion/extensions/service_now/change/runners/change.rb +18 -18
  18. data/lib/legion/extensions/service_now/ci_relationship/runners/ci_relationship.rb +52 -0
  19. data/lib/legion/extensions/service_now/client.rb +22 -0
  20. data/lib/legion/extensions/service_now/cmdb/instance/runners/instance.rb +7 -7
  21. data/lib/legion/extensions/service_now/cmdb/meta/runners/meta.rb +2 -2
  22. data/lib/legion/extensions/service_now/cmdb_health/runners/cmdb_health.rb +48 -0
  23. data/lib/legion/extensions/service_now/company/runners/company.rb +5 -5
  24. data/lib/legion/extensions/service_now/contract/runners/contract.rb +5 -5
  25. data/lib/legion/extensions/service_now/cost_center/runners/cost_center.rb +5 -5
  26. data/lib/legion/extensions/service_now/csm/runners/csm.rb +64 -0
  27. data/lib/legion/extensions/service_now/currency/runners/currency.rb +40 -0
  28. data/lib/legion/extensions/service_now/department/runners/department.rb +5 -5
  29. data/lib/legion/extensions/service_now/deprecation_log/runners/deprecation_log.rb +43 -0
  30. data/lib/legion/extensions/service_now/discovery/runners/discovery.rb +5 -5
  31. data/lib/legion/extensions/service_now/email_log/runners/email_log.rb +3 -3
  32. data/lib/legion/extensions/service_now/errors.rb +26 -0
  33. data/lib/legion/extensions/service_now/event/runners/event.rb +3 -3
  34. data/lib/legion/extensions/service_now/flow/runners/flow.rb +6 -6
  35. data/lib/legion/extensions/service_now/grc/runners/grc.rb +61 -0
  36. data/lib/legion/extensions/service_now/helpers/client.rb +55 -0
  37. data/lib/legion/extensions/service_now/helpers/pagination.rb +31 -0
  38. data/lib/legion/extensions/service_now/helpers/retry.rb +32 -0
  39. data/lib/legion/extensions/service_now/hr_case/runners/hr_case.rb +5 -5
  40. data/lib/legion/extensions/service_now/import_set/runners/import_set.rb +2 -2
  41. data/lib/legion/extensions/service_now/incident/runners/incident.rb +6 -6
  42. data/lib/legion/extensions/service_now/integration_hub/runners/integration_hub.rb +49 -0
  43. data/lib/legion/extensions/service_now/knowledge/runners/knowledge.rb +5 -5
  44. data/lib/legion/extensions/service_now/knowledge_base/runners/knowledge_base.rb +64 -0
  45. data/lib/legion/extensions/service_now/knowledge_feedback/runners/knowledge_feedback.rb +45 -0
  46. data/lib/legion/extensions/service_now/license/runners/license.rb +44 -0
  47. data/lib/legion/extensions/service_now/location/runners/location.rb +5 -5
  48. data/lib/legion/extensions/service_now/metric/runners/metric.rb +47 -0
  49. data/lib/legion/extensions/service_now/mid_server/runners/mid_server.rb +5 -5
  50. data/lib/legion/extensions/service_now/notification/runners/notification.rb +5 -5
  51. data/lib/legion/extensions/service_now/on_call/runners/on_call.rb +5 -5
  52. data/lib/legion/extensions/service_now/performance_analytics/runners/performance_analytics.rb +5 -5
  53. data/lib/legion/extensions/service_now/problem/runners/problem.rb +6 -6
  54. data/lib/legion/extensions/service_now/project/runners/project.rb +6 -6
  55. data/lib/legion/extensions/service_now/release/runners/release.rb +5 -5
  56. data/lib/legion/extensions/service_now/request/runners/request.rb +6 -6
  57. data/lib/legion/extensions/service_now/scheduled_job/runners/scheduled_job.rb +5 -5
  58. data/lib/legion/extensions/service_now/script_action/runners/script_action.rb +50 -0
  59. data/lib/legion/extensions/service_now/script_include/runners/script_include.rb +5 -5
  60. data/lib/legion/extensions/service_now/security_incident/runners/security_incident.rb +5 -5
  61. data/lib/legion/extensions/service_now/service_catalog/runners/service_catalog.rb +11 -11
  62. data/lib/legion/extensions/service_now/service_portal/runners/service_portal.rb +55 -0
  63. data/lib/legion/extensions/service_now/skills/approval_workflow.rb +5 -5
  64. data/lib/legion/extensions/service_now/skills/asset_management.rb +5 -5
  65. data/lib/legion/extensions/service_now/skills/change_request.rb +6 -6
  66. data/lib/legion/extensions/service_now/skills/cmdb_query.rb +5 -5
  67. data/lib/legion/extensions/service_now/skills/incident.rb +6 -6
  68. data/lib/legion/extensions/service_now/skills/knowledge.rb +5 -5
  69. data/lib/legion/extensions/service_now/skills/problem_management.rb +6 -6
  70. data/lib/legion/extensions/service_now/skills/request_fulfillment.rb +6 -6
  71. data/lib/legion/extensions/service_now/skills/security_incident_response.rb +6 -6
  72. data/lib/legion/extensions/service_now/skills/service_catalog.rb +6 -6
  73. data/lib/legion/extensions/service_now/sla/runners/sla.rb +5 -5
  74. data/lib/legion/extensions/service_now/survey/runners/survey.rb +5 -5
  75. data/lib/legion/extensions/service_now/system_property/runners/system_property.rb +6 -6
  76. data/lib/legion/extensions/service_now/table/runners/table.rb +7 -5
  77. data/lib/legion/extensions/service_now/tag/runners/tag.rb +61 -0
  78. data/lib/legion/extensions/service_now/task/runners/task.rb +5 -5
  79. data/lib/legion/extensions/service_now/ui_action/runners/ui_action.rb +53 -0
  80. data/lib/legion/extensions/service_now/ui_policy/runners/ui_policy.rb +51 -0
  81. data/lib/legion/extensions/service_now/update_set/runners/update_set.rb +6 -6
  82. data/lib/legion/extensions/service_now/user/runners/user.rb +7 -7
  83. data/lib/legion/extensions/service_now/user_group/runners/user_group.rb +9 -9
  84. data/lib/legion/extensions/service_now/vendor/runners/vendor.rb +60 -0
  85. data/lib/legion/extensions/service_now/version.rb +1 -1
  86. data/lib/legion/extensions/service_now/work_order/runners/work_order.rb +6 -6
  87. data/lib/legion/extensions/service_now/workflow/runners/workflow.rb +6 -6
  88. data/lib/legion/extensions/service_now.rb +23 -0
  89. metadata +26 -3
data/README.md CHANGED
@@ -1,19 +1,15 @@
1
1
  # lex-service_now
2
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.
3
+ A LegionIO extension connecting Legion to ServiceNow via REST APIs. Covers **66 domains** and **345 methods** spanning ITSM, ITOM, ITAM, HR, Security, GRC, CSM, DevOps, and platform administration.
4
4
 
5
5
  ## Installation
6
6
 
7
- Add to your Gemfile:
8
-
9
7
  ```ruby
10
8
  gem 'lex-service_now'
11
9
  ```
12
10
 
13
11
  ## Configuration
14
12
 
15
- Set credentials via Legion settings (`~/.legionio/settings/service_now.json`):
16
-
17
13
  ```json
18
14
  {
19
15
  "service_now": {
@@ -24,154 +20,204 @@ Set credentials via Legion settings (`~/.legionio/settings/service_now.json`):
24
20
  }
25
21
  ```
26
22
 
27
- OAuth2 and Bearer token auth are also supported — the most secure credentials provided are used automatically (OAuth2 > Bearer > Basic Auth).
23
+ OAuth2 and Bearer token are also supported — the most secure credentials provided win (OAuth2 > Bearer > Basic Auth).
28
24
 
29
25
  ## Usage
30
26
 
31
- ### Standalone Client
32
-
33
27
  ```ruby
34
- require 'legion/extensions/service_now'
35
-
36
28
  client = Legion::Extensions::ServiceNow::Client.new(
37
29
  url: 'https://your-instance.service-now.com',
38
30
  username: 'admin',
39
31
  password: 'secret'
40
32
  )
41
33
 
42
- # Incidents
34
+ # ITSM
43
35
  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')
36
+ client.create_incident(short_description: 'Production down', urgency: '1', impact: '1')
37
+ client.resolve_incident(sys_id: 'abc', close_code: 'Solved (Permanently)', close_notes: 'Fixed')
46
38
 
47
- # Change Management
48
- client.create_normal(short_description: 'Deploy app v2.0', assignment_group: 'CAB Approval')
49
- client.get_change(id: 'CHG0012345')
39
+ # Change
40
+ client.create_normal(short_description: 'Deploy v2.0')
50
41
  client.get_approvals(id: 'CHG0012345')
51
42
 
52
43
  # CMDB
53
44
  client.list_cis(class_name: 'cmdb_ci_server', sysparm_query: 'operational_status=1')
54
45
  client.get_relationships(class_name: 'cmdb_ci_server', sys_id: 'srv001')
55
46
 
56
- # Service Catalog
57
- client.list_items(catalog_id: 'cat1')
58
- client.order_now(sys_id: 'item_id', quantity: 1, variables: { justification: 'Project work' })
47
+ # Generic table escape hatch
48
+ client.table_list(table_name: 'u_custom_table', sysparm_query: 'active=true')
49
+ client.table_create(table_name: 'u_custom_table', name: 'New Record', u_field: 'value')
59
50
 
60
- # Users & Groups
61
- client.get_user_by_email(email: 'jdoe@company.com')
62
- client.list_group_members(group_sys_id: 'network_team_id')
51
+ # Pagination helper — automatically fetches all pages
52
+ all_incidents = client.paginate(:list_incidents, sysparm_query: 'state=1')
63
53
 
64
- # Generic Table API (escape hatch for any table)
65
- client.table_list(table_name: 'u_custom_table', sysparm_query: 'active=true')
54
+ # Retry helper retries on rate limits and server errors
55
+ client.with_retry(max_retries: 3) { client.create_incident(short_description: 'Issue') }
56
+
57
+ # Error handling
58
+ begin
59
+ client.get_incident(sys_id: 'nonexistent')
60
+ rescue Legion::Extensions::ServiceNow::Errors::NotFoundError => e
61
+ puts "Not found: #{e.message} (status: #{e.status})"
62
+ end
66
63
  ```
67
64
 
68
- ## Supported Domains
65
+ ## Supported Domains (66 total)
69
66
 
70
67
  ### ITSM
71
- | Domain | Methods | Table |
68
+ | Domain | Methods | Notes |
72
69
  |--------|---------|-------|
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` |
70
+ | Change | 14 | normal/emergency/standard + change_tasks/conflicts/approvals |
71
+ | Incident | 6 | CRUD + resolve |
72
+ | Problem | 6 | CRUD + close |
73
+ | Request/RITM | 6 | sc_request + sc_req_item |
74
+ | Approval | 5 | approve/reject + list_for_record |
75
+ | Task | 5 | CRUD + add_work_note |
76
+ | SLA | 5 | definitions + task SLAs |
77
+ | CatalogTask | 4 | sc_task list/get/update/close |
80
78
 
81
79
  ### CMDB & Discovery
82
- | Domain | Methods | Table |
80
+ | Domain | Methods | Notes |
83
81
  |--------|---------|-------|
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` |
82
+ | CMDB Instance | 7 | CI CRUD + relationships |
83
+ | CMDB Meta | 2 | hierarchy + class metadata |
84
+ | CiRelationship | 5 | cmdb_rel_type + cmdb_rel_ci |
85
+ | CmdbHealth | 4 | duplicates, stale CIs, health dashboard |
86
+ | Discovery | 5 | schedules/logs/devices |
87
+ | MID Server | 5 | ecc_agent CRUD + capabilities |
88
88
 
89
89
  ### Service Catalog
90
- | Domain | Methods | Table |
90
+ | Domain | Methods | Notes |
91
91
  |--------|---------|-------|
92
- | Service Catalog | 11 | `/api/sn_sc/servicecatalog` |
93
- | Catalog Variable | 5 | `item_option_new` |
92
+ | Service Catalog | 11 | catalogs/items/cart/order |
93
+ | Catalog Variable | 5 | item_option_new CRUD |
94
94
 
95
- ### Knowledge & Content
96
- | Domain | Methods | Table |
95
+ ### Knowledge
96
+ | Domain | Methods | Notes |
97
97
  |--------|---------|-------|
98
- | Knowledge | 5 | `/api/sn_km_api/knowledge` |
99
- | Survey | 5 | `survey`, `asmt_assessment_instance` |
98
+ | Knowledge | 5 | article CRUD |
99
+ | Knowledge Base | 6 | kb_knowledge_base CRUD + categories |
100
+ | Knowledge Feedback | 4 | feedback + views |
100
101
 
101
102
  ### User & Organization
102
- | Domain | Methods | Table |
103
+ | Domain | Methods | Notes |
103
104
  |--------|---------|-------|
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` |
105
+ | User | 7 | CRUD + lookup_by_username/email |
106
+ | UserGroup | 9 | CRUD + member management |
107
+ | Account | 4 | account CRUD |
108
+ | Location | 5 | cmn_location CRUD |
109
+ | Department | 5 | cmn_department CRUD |
110
+ | Company | 5 | core_company CRUD |
111
+ | Cost Center | 5 | cmn_cost_center CRUD |
112
+ | Vendor | 5 | vendor-filtered company records |
111
113
 
112
114
  ### Asset & Contract Management
113
- | Domain | Methods | Table |
115
+ | Domain | Methods | Notes |
114
116
  |--------|---------|-------|
115
- | Asset | 6 | `alm_asset`, `alm_hardware` |
116
- | Contract | 5 | `ast_contract` |
117
+ | Asset | 6 | alm_asset CRUD + hardware |
118
+ | Contract | 5 | ast_contract CRUD |
119
+ | License | 4 | agreements + allocations + installed software |
117
120
 
118
- ### Security
119
- | Domain | Methods | Table |
121
+ ### Security & Compliance
122
+ | Domain | Methods | Notes |
120
123
  |--------|---------|-------|
121
- | Security Incident | 5 | `sn_si_incident` |
124
+ | Security Incident | 5 | sn_si_incident CRUD |
125
+ | Access Control | 5 | sys_security_acl CRUD |
126
+ | GRC | 7 | risks + controls + audits + policies |
122
127
 
123
- ### HR
124
- | Domain | Methods | Table |
128
+ ### HR & Customer Service
129
+ | Domain | Methods | Notes |
125
130
  |--------|---------|-------|
126
- | HR Case | 5 | `sn_hr_core_case` |
131
+ | HR Case | 5 | sn_hr_core_case CRUD |
132
+ | CSM | 6 | customer cases + contacts |
127
133
 
128
134
  ### Project & Release
129
- | Domain | Methods | Table |
135
+ | Domain | Methods | Notes |
130
136
  |--------|---------|-------|
131
- | Project | 6 | `pm_project`, `pm_project_task` |
132
- | Release | 5 | `rm_release` |
137
+ | Project | 6 | pm_project CRUD + tasks |
138
+ | Release | 5 | rm_release CRUD |
133
139
 
134
140
  ### Platform Administration
135
- | Domain | Methods | Table |
141
+ | Domain | Methods | Notes |
136
142
  |--------|---------|-------|
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` |
143
+ | System Property | 6 | sys_properties CRUD |
144
+ | Update Set | 6 | CRUD + list changes |
145
+ | Script Include | 5 | sys_script_include CRUD |
146
+ | Business Rule | 5 | sys_script CRUD |
147
+ | Script Action | 5 | sysevent_script_action CRUD |
148
+ | Scheduled Job | 5 | sysauto_script CRUD |
149
+ | UI Policy | 5 | sys_ui_policy CRUD |
150
+ | UI Action | 5 | sys_ui_action CRUD |
151
+ | Workflow | 6 | wf_workflow + contexts |
152
+ | Flow/Subflow | 6 | sn_fd flows + execution |
153
+ | Audit | 3 | sys_audit + field changes |
154
+ | Deprecation Log | 4 | upgrade history + deprecations |
145
155
 
146
156
  ### ITOM & Monitoring
147
- | Domain | Methods | Table |
157
+ | Domain | Methods | Notes |
148
158
  |--------|---------|-------|
149
- | Event | 3 | `sysevent` |
150
- | Performance Analytics | 5 | `/api/now/pa` |
159
+ | Event | 3 | sysevent CRUD |
160
+ | Performance Analytics | 5 | widgets/scorecards/indicators |
161
+ | Metric | 4 | definitions + instances |
151
162
 
152
163
  ### Communications
153
- | Domain | Methods | Table |
164
+ | Domain | Methods | Notes |
154
165
  |--------|---------|-------|
155
- | Notification | 5 | `sysevent_email_action` |
156
- | Email Log | 3 | `sys_email` |
166
+ | Notification | 5 | sysevent_email_action CRUD |
167
+ | Email Log | 3 | sys_email list/get/list_for_record |
157
168
 
158
169
  ### Field Service
159
- | Domain | Methods | Table |
170
+ | Domain | Methods | Notes |
171
+ |--------|---------|-------|
172
+ | Work Order | 6 | wm_order CRUD + tasks + close |
173
+ | On-Call | 5 | schedules + members + who_is_on_call |
174
+
175
+ ### Platform Modules
176
+ | Domain | Methods | Notes |
160
177
  |--------|---------|-------|
161
- | Work Order | 6 | `wm_order`, `wm_task` |
162
- | On-Call | 5 | `cmn_rota`, `cmn_rota_member` |
178
+ | Service Portal | 6 | portals/pages/widgets |
179
+ | Integration Hub | 5 | spokes/connections/credentials |
163
180
 
164
- ### Utilities
165
- | Domain | Methods | Table |
181
+ ### Utilities & Reference
182
+ | Domain | Methods | Notes |
166
183
  |--------|---------|-------|
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` |
184
+ | Table (generic) | 5 | Any table via /api/now/table/{table} |
185
+ | Import Set | 2 | /api/now/import |
186
+ | Aggregate | 1 | count/sum/avg/min/max on any table |
187
+ | Attachment | 5 | upload/download files |
188
+ | Survey | 5 | assessments + instances + responses |
189
+ | Tag | 7 | label + label_entry CRUD |
190
+ | Currency | 3 | fx_currency + fx_rate |
191
+ | Calendar | 6 | cmn_schedule CRUD + entries |
192
+
193
+ ## Helpers
194
+
195
+ ### Pagination
196
+ ```ruby
197
+ all_results = client.paginate(:list_incidents, sysparm_query: 'state=1')
198
+ ```
199
+ Automatically iterates through all pages.
200
+
201
+ ### Retry
202
+ ```ruby
203
+ client.with_retry(max_retries: 3) { client.create_incident(...) }
204
+ ```
205
+ Retries on `RateLimitError` (exponential backoff) and `ServerError`. Raises immediately on auth errors.
206
+
207
+ ### Error Handling
208
+ ```ruby
209
+ rescue Legion::Extensions::ServiceNow::Errors::AuthenticationError => e # 401
210
+ rescue Legion::Extensions::ServiceNow::Errors::AuthorizationError => e # 403
211
+ rescue Legion::Extensions::ServiceNow::Errors::NotFoundError => e # 404
212
+ rescue Legion::Extensions::ServiceNow::Errors::UnprocessableError => e # 422
213
+ rescue Legion::Extensions::ServiceNow::Errors::RateLimitError => e # 429
214
+ rescue Legion::Extensions::ServiceNow::Errors::ServerError => e # 5xx
215
+ rescue Legion::Extensions::ServiceNow::Errors::ServiceNowError => e # all others
216
+ ```
171
217
 
172
- ## LLM Skills
218
+ ## LLM Skills (10 total)
173
219
 
174
- When `legion-llm` is available, 10 workflow skills are registered automatically:
220
+ Registered automatically when `legion-llm` is available:
175
221
 
176
222
  | Skill | Trigger Words |
177
223
  |-------|--------------|
@@ -183,17 +229,17 @@ When `legion-llm` is available, 10 workflow skills are registered automatically:
183
229
  | `servicenow:problem_management` | PRB, problem, root cause, RCA |
184
230
  | `servicenow:request_fulfillment` | RITM, request item, fulfillment |
185
231
  | `servicenow:approval_workflow` | approval, approve, reject |
186
- | `servicenow:asset_management` | asset, hardware, inventory, ALM |
232
+ | `servicenow:asset_management` | asset, hardware, inventory |
187
233
  | `servicenow:security_incident_response` | SIR, security incident, breach |
188
234
 
189
235
  ## Development
190
236
 
191
237
  ```bash
192
238
  bundle install
193
- bundle exec rspec # 217 examples, 0 failures
239
+ bundle exec rspec # 372 examples, 0 failures
194
240
  bundle exec rubocop # 0 offenses
195
241
  ```
196
242
 
197
243
  ## License
198
244
 
199
- MIT — see [LICENSE](LICENSE).
245
+ MIT
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ['matthewdiverson@gmail.com']
10
10
 
11
11
  spec.summary = 'LEX::ServiceNow'
12
- spec.description = 'Connects Legion to ServiceNow via Change Management, CMDB, Knowledge, Service Catalog, and Account REST APIs'
12
+ spec.description = 'Connects Legion to ServiceNow via 60+ REST API domains spanning ITSM, ITOM, ITAM, HR, Security, DevOps, and platform administration'
13
13
  spec.homepage = 'https://github.com/LegionIO/lex-service_now'
14
14
  spec.license = 'MIT'
15
15
  spec.required_ruby_version = '>= 3.4'
@@ -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 = get('/api/now/table/sys_security_acl', params, **)
16
+ { acls: resp.body['result'] }
17
+ end
18
+
19
+ def get_acl(sys_id:, **)
20
+ resp = 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 = 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 = 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 = 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
@@ -11,12 +11,12 @@ module Legion
11
11
  def list_accounts(sysparm_limit: 100, sysparm_offset: 0, sysparm_query: nil, **)
12
12
  params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
13
13
  params[:sysparm_query] = sysparm_query if sysparm_query
14
- resp = connection(**).get('/api/now/account', params)
14
+ resp = get('/api/now/account', params, **)
15
15
  { accounts: resp.body['result'] }
16
16
  end
17
17
 
18
18
  def get_account(sys_id:, **)
19
- resp = connection(**).get("/api/now/account/#{sys_id}")
19
+ resp = get("/api/now/account/#{sys_id}", {}, **)
20
20
  { account: resp.body['result'] }
21
21
  end
22
22
 
@@ -24,7 +24,7 @@ module Legion
24
24
  body = { name: name }
25
25
  body[:phone] = phone if phone
26
26
  body[:email] = email if email
27
- resp = connection(**).post('/api/now/account', body)
27
+ resp = post('/api/now/account', body, **)
28
28
  { account: resp.body['result'] }
29
29
  end
30
30
 
@@ -33,7 +33,7 @@ module Legion
33
33
  body[:name] = name if name
34
34
  body[:phone] = phone if phone
35
35
  body[:email] = email if email
36
- resp = connection(**).patch("/api/now/account/#{sys_id}", body)
36
+ resp = patch("/api/now/account/#{sys_id}", body, **)
37
37
  { account: resp.body['result'] }
38
38
  end
39
39
 
@@ -21,7 +21,7 @@ module Legion
21
21
  params[:sysparm_query] = sysparm_query if sysparm_query
22
22
  params[:sysparm_group_by] = sysparm_group_by if sysparm_group_by
23
23
  params[:sysparm_having] = sysparm_having if sysparm_having
24
- resp = connection(**).get("/api/now/stats/#{table_name}", params)
24
+ resp = get("/api/now/stats/#{table_name}", params, **)
25
25
  { stats: resp.body['result'] }
26
26
  end
27
27
 
@@ -11,32 +11,32 @@ module Legion
11
11
  def list_approvals(sysparm_limit: 100, sysparm_offset: 0, sysparm_query: nil, **)
12
12
  params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
13
13
  params[:sysparm_query] = sysparm_query if sysparm_query
14
- resp = connection(**).get('/api/now/table/sysapproval_approver', params)
14
+ resp = get('/api/now/table/sysapproval_approver', params, **)
15
15
  { approvals: resp.body['result'] }
16
16
  end
17
17
 
18
18
  def get_approval(sys_id:, **)
19
- resp = connection(**).get("/api/now/table/sysapproval_approver/#{sys_id}")
19
+ resp = get("/api/now/table/sysapproval_approver/#{sys_id}", {}, **)
20
20
  { approval: resp.body['result'] }
21
21
  end
22
22
 
23
23
  def approve(sys_id:, comments: nil, **)
24
24
  body = { state: 'approved' }
25
25
  body[:comments] = comments if comments
26
- resp = connection(**).patch("/api/now/table/sysapproval_approver/#{sys_id}", body)
26
+ resp = patch("/api/now/table/sysapproval_approver/#{sys_id}", body, **)
27
27
  { approval: resp.body['result'] }
28
28
  end
29
29
 
30
30
  def reject(sys_id:, comments: nil, **)
31
31
  body = { state: 'rejected' }
32
32
  body[:comments] = comments if comments
33
- resp = connection(**).patch("/api/now/table/sysapproval_approver/#{sys_id}", body)
33
+ resp = patch("/api/now/table/sysapproval_approver/#{sys_id}", body, **)
34
34
  { approval: resp.body['result'] }
35
35
  end
36
36
 
37
37
  def list_approvals_for_record(document_id:, **)
38
38
  params = { sysparm_query: "document_id=#{document_id}", sysparm_limit: 100 }
39
- resp = connection(**).get('/api/now/table/sysapproval_approver', params)
39
+ resp = get('/api/now/table/sysapproval_approver', params, **)
40
40
  { approvals: resp.body['result'] }
41
41
  end
42
42
 
@@ -13,12 +13,12 @@ module Legion
13
13
  params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
14
14
  params[:sysparm_query] = sysparm_query if sysparm_query
15
15
  params[:sysparm_fields] = sysparm_fields if sysparm_fields
16
- resp = connection(**).get('/api/now/table/alm_asset', params)
16
+ resp = get('/api/now/table/alm_asset', params, **)
17
17
  { assets: resp.body['result'] }
18
18
  end
19
19
 
20
20
  def get_asset(sys_id:, **)
21
- resp = connection(**).get("/api/now/table/alm_asset/#{sys_id}")
21
+ resp = get("/api/now/table/alm_asset/#{sys_id}", {}, **)
22
22
  { asset: resp.body['result'] }
23
23
  end
24
24
 
@@ -28,7 +28,7 @@ module Legion
28
28
  body[:serial_number] = serial_number if serial_number
29
29
  body[:assigned_to] = assigned_to if assigned_to
30
30
  body[:state] = state if state
31
- resp = connection(**).post('/api/now/table/alm_asset', body)
31
+ resp = post('/api/now/table/alm_asset', body, **)
32
32
  { asset: resp.body['result'] }
33
33
  end
34
34
 
@@ -39,19 +39,19 @@ module Legion
39
39
  body[:assigned_to] = assigned_to if assigned_to
40
40
  body[:location] = location if location
41
41
  body[:serial_number] = serial_number if serial_number
42
- resp = connection(**).patch("/api/now/table/alm_asset/#{sys_id}", body)
42
+ resp = patch("/api/now/table/alm_asset/#{sys_id}", body, **)
43
43
  { asset: resp.body['result'] }
44
44
  end
45
45
 
46
46
  def delete_asset(sys_id:, **)
47
- resp = connection(**).delete("/api/now/table/alm_asset/#{sys_id}")
47
+ resp = delete("/api/now/table/alm_asset/#{sys_id}", **)
48
48
  { deleted: resp.status == 204, sys_id: sys_id }
49
49
  end
50
50
 
51
51
  def list_hardware(sysparm_limit: 100, sysparm_offset: 0, sysparm_query: nil, **)
52
52
  params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
53
53
  params[:sysparm_query] = sysparm_query if sysparm_query
54
- resp = connection(**).get('/api/now/table/alm_hardware', params)
54
+ resp = get('/api/now/table/alm_hardware', params, **)
55
55
  { hardware: resp.body['result'] }
56
56
  end
57
57
 
@@ -14,17 +14,17 @@ module Legion
14
14
  sysparm_offset: 0, **)
15
15
  params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
16
16
  params[:sysparm_query] = "table_name=#{table_name}^table_sys_id=#{table_sys_id}" if table_name && table_sys_id
17
- resp = connection(**).get('/api/now/attachment', params)
17
+ resp = get('/api/now/attachment', params, **)
18
18
  { attachments: resp.body['result'] }
19
19
  end
20
20
 
21
21
  def get_attachment(sys_id:, **)
22
- resp = connection(**).get("/api/now/attachment/#{sys_id}")
22
+ resp = get("/api/now/attachment/#{sys_id}", {}, **)
23
23
  { attachment: resp.body['result'] }
24
24
  end
25
25
 
26
26
  def get_attachment_file(sys_id:, **)
27
- resp = connection(**).get("/api/now/attachment/#{sys_id}/file")
27
+ resp = get("/api/now/attachment/#{sys_id}/file", {}, **)
28
28
  { content: resp.body, status: resp.status }
29
29
  end
30
30
 
@@ -41,7 +41,7 @@ module Legion
41
41
  end
42
42
 
43
43
  def delete_attachment(sys_id:, **)
44
- resp = connection(**).delete("/api/now/attachment/#{sys_id}")
44
+ resp = delete("/api/now/attachment/#{sys_id}", **)
45
45
  { deleted: resp.status == 204, sys_id: sys_id }
46
46
  end
47
47
 
@@ -17,12 +17,12 @@ module Legion
17
17
  elsif sysparm_query
18
18
  params[:sysparm_query] = sysparm_query
19
19
  end
20
- resp = connection(**).get('/api/now/table/sys_audit', params)
20
+ resp = get('/api/now/table/sys_audit', params, **)
21
21
  { audit_records: resp.body['result'] }
22
22
  end
23
23
 
24
24
  def get_audit_record(sys_id:, **)
25
- resp = connection(**).get("/api/now/table/sys_audit/#{sys_id}")
25
+ resp = get("/api/now/table/sys_audit/#{sys_id}", {}, **)
26
26
  { audit_record: resp.body['result'] }
27
27
  end
28
28
 
@@ -31,7 +31,7 @@ module Legion
31
31
  query = "tablename=#{tablename}^documentkey=#{documentkey}"
32
32
  query += "^fieldname=#{fieldname}" if fieldname
33
33
  params = { sysparm_query: query, sysparm_limit: sysparm_limit }
34
- resp = connection(**).get('/api/now/table/sys_audit', params)
34
+ resp = get('/api/now/table/sys_audit', params, **)
35
35
  { field_changes: resp.body['result'] }
36
36
  end
37
37
 
@@ -12,12 +12,12 @@ module Legion
12
12
  sysparm_query: nil, **)
13
13
  params = { sysparm_limit: sysparm_limit, sysparm_offset: sysparm_offset }
14
14
  params[:sysparm_query] = sysparm_query if sysparm_query
15
- resp = connection(**).get('/api/now/table/sys_script', params)
15
+ resp = get('/api/now/table/sys_script', params, **)
16
16
  { business_rules: resp.body['result'] }
17
17
  end
18
18
 
19
19
  def get_business_rule(sys_id:, **)
20
- resp = connection(**).get("/api/now/table/sys_script/#{sys_id}")
20
+ resp = get("/api/now/table/sys_script/#{sys_id}", {}, **)
21
21
  { business_rule: resp.body['result'] }
22
22
  end
23
23
 
@@ -34,7 +34,7 @@ module Legion
34
34
  action_delete: action_delete,
35
35
  active: active
36
36
  }
37
- resp = connection(**).post('/api/now/table/sys_script', body)
37
+ resp = post('/api/now/table/sys_script', body, **)
38
38
  { business_rule: resp.body['result'] }
39
39
  end
40
40
 
@@ -44,12 +44,12 @@ module Legion
44
44
  body[:script] = script if script
45
45
  body[:active] = active unless active.nil?
46
46
  body[:name] = name if name
47
- resp = connection(**).patch("/api/now/table/sys_script/#{sys_id}", body)
47
+ resp = patch("/api/now/table/sys_script/#{sys_id}", body, **)
48
48
  { business_rule: resp.body['result'] }
49
49
  end
50
50
 
51
51
  def delete_business_rule(sys_id:, **)
52
- resp = connection(**).delete("/api/now/table/sys_script/#{sys_id}")
52
+ resp = delete("/api/now/table/sys_script/#{sys_id}", **)
53
53
  { deleted: resp.status == 204, sys_id: sys_id }
54
54
  end
55
55