splunkctl 0.11.2__tar.gz → 0.12.0__tar.gz

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 (142) hide show
  1. {splunkctl-0.11.2 → splunkctl-0.12.0}/MANIFEST.in +1 -0
  2. {splunkctl-0.11.2/splunkctl.egg-info → splunkctl-0.12.0}/PKG-INFO +2 -2
  3. splunkctl-0.12.0/docs/guides/alerts.md +79 -0
  4. splunkctl-0.12.0/docs/guides/apps.md +65 -0
  5. splunkctl-0.12.0/docs/guides/audit.md +125 -0
  6. splunkctl-0.12.0/docs/guides/conf.md +84 -0
  7. splunkctl-0.12.0/docs/guides/configure.md +120 -0
  8. splunkctl-0.12.0/docs/guides/dashboards.md +17 -0
  9. splunkctl-0.12.0/docs/guides/datamodels.md +164 -0
  10. splunkctl-0.12.0/docs/guides/doctor.md +70 -0
  11. splunkctl-0.12.0/docs/guides/es.md +236 -0
  12. splunkctl-0.12.0/docs/guides/exit-codes.md +44 -0
  13. splunkctl-0.12.0/docs/guides/hec.md +59 -0
  14. splunkctl-0.12.0/docs/guides/indexes.md +76 -0
  15. splunkctl-0.12.0/docs/guides/inputs.md +80 -0
  16. splunkctl-0.12.0/docs/guides/install.md +55 -0
  17. splunkctl-0.12.0/docs/guides/knowledge.md +113 -0
  18. splunkctl-0.12.0/docs/guides/kvstore.md +125 -0
  19. splunkctl-0.12.0/docs/guides/lookups.md +127 -0
  20. splunkctl-0.12.0/docs/guides/mcp.md +173 -0
  21. splunkctl-0.12.0/docs/guides/parsers.md +67 -0
  22. splunkctl-0.12.0/docs/guides/rules.md +183 -0
  23. splunkctl-0.12.0/docs/guides/search.md +144 -0
  24. splunkctl-0.12.0/docs/guides/server.md +257 -0
  25. splunkctl-0.12.0/docs/guides/soar-actions.md +130 -0
  26. splunkctl-0.12.0/docs/guides/soar-admin.md +120 -0
  27. splunkctl-0.12.0/docs/guides/soar-approvals.md +99 -0
  28. splunkctl-0.12.0/docs/guides/soar-apps.md +56 -0
  29. splunkctl-0.12.0/docs/guides/soar-automation.md +132 -0
  30. splunkctl-0.12.0/docs/guides/soar-cases.md +178 -0
  31. splunkctl-0.12.0/docs/guides/soar-functions.md +94 -0
  32. splunkctl-0.12.0/docs/guides/soar-indicators.md +123 -0
  33. splunkctl-0.12.0/docs/guides/soar-ingest.md +161 -0
  34. splunkctl-0.12.0/docs/guides/soar-lists.md +110 -0
  35. splunkctl-0.12.0/docs/guides/soar-playbooks.md +267 -0
  36. splunkctl-0.12.0/docs/guides/soar.md +440 -0
  37. splunkctl-0.12.0/docs/guides/state.md +270 -0
  38. splunkctl-0.12.0/docs/guides/users.md +86 -0
  39. {splunkctl-0.11.2 → splunkctl-0.12.0}/pyproject.toml +4 -1
  40. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/__init__.py +1 -1
  41. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/mcp_cmd.py +8 -5
  42. splunkctl-0.12.0/splunkctl/mcp/dynamic_server.py +132 -0
  43. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/prompts.py +8 -4
  44. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/resources.py +20 -3
  45. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/runner.py +0 -64
  46. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/server.py +38 -59
  47. splunkctl-0.12.0/splunkctl/mcp/transport.py +18 -0
  48. {splunkctl-0.11.2 → splunkctl-0.12.0/splunkctl.egg-info}/PKG-INFO +2 -2
  49. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/SOURCES.txt +38 -0
  50. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/requires.txt +1 -1
  51. {splunkctl-0.11.2 → splunkctl-0.12.0}/LICENSE +0 -0
  52. {splunkctl-0.11.2 → splunkctl-0.12.0}/README.md +0 -0
  53. {splunkctl-0.11.2 → splunkctl-0.12.0}/setup.cfg +0 -0
  54. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/__main__.py +0 -0
  55. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/client.py +0 -0
  56. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/__init__.py +0 -0
  57. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/alerts.py +0 -0
  58. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/apps.py +0 -0
  59. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/audit.py +0 -0
  60. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/audit_parse.py +0 -0
  61. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/commands_meta.py +0 -0
  62. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/common.py +0 -0
  63. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/conf.py +0 -0
  64. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/conf_ops.py +0 -0
  65. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/config_cmd.py +0 -0
  66. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/dashboards.py +0 -0
  67. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/datamodels.py +0 -0
  68. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/docs_cmd.py +0 -0
  69. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/doctor.py +0 -0
  70. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/es.py +0 -0
  71. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/es_threat_intel.py +0 -0
  72. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/hec.py +0 -0
  73. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/indexes.py +0 -0
  74. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/info.py +0 -0
  75. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/inputs.py +0 -0
  76. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/knowledge.py +0 -0
  77. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/kvstore.py +0 -0
  78. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/lookups.py +0 -0
  79. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/lookups_wiring.py +0 -0
  80. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/parsers.py +0 -0
  81. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/parsers_io.py +0 -0
  82. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/rules.py +0 -0
  83. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/rules_io.py +0 -0
  84. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/rules_schedule.py +0 -0
  85. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/search.py +0 -0
  86. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server.py +0 -0
  87. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_auth.py +0 -0
  88. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_deployment.py +0 -0
  89. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_tokens.py +0 -0
  90. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_topology.py +0 -0
  91. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_workloads.py +0 -0
  92. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/__init__.py +0 -0
  93. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/_client.py +0 -0
  94. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/_ingest_helpers.py +0 -0
  95. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/actions.py +0 -0
  96. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/admin.py +0 -0
  97. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/admin_roles_audit.py +0 -0
  98. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/admin_views.py +0 -0
  99. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/approvals.py +0 -0
  100. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/apps.py +0 -0
  101. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/artifacts.py +0 -0
  102. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/assets.py +0 -0
  103. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/cases.py +0 -0
  104. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/containers.py +0 -0
  105. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/containers_assign.py +0 -0
  106. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/containers_write.py +0 -0
  107. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/functions.py +0 -0
  108. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/indicators.py +0 -0
  109. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/ingest.py +0 -0
  110. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/lists.py +0 -0
  111. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/notes.py +0 -0
  112. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/playbook_runs.py +0 -0
  113. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/playbooks.py +0 -0
  114. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/playbooks_delete.py +0 -0
  115. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/search.py +0 -0
  116. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/system.py +0 -0
  117. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/vault.py +0 -0
  118. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/workbook_templates.py +0 -0
  119. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state.py +0 -0
  120. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io.py +0 -0
  121. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io_blobs.py +0 -0
  122. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io_confs.py +0 -0
  123. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io_soar.py +0 -0
  124. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io_soar_assets.py +0 -0
  125. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_types.py +0 -0
  126. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/users.py +0 -0
  127. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/config.py +0 -0
  128. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/errors.py +0 -0
  129. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/guard.py +0 -0
  130. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/main.py +0 -0
  131. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/__init__.py +0 -0
  132. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/output_cap.py +0 -0
  133. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/tools.py +0 -0
  134. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/output.py +0 -0
  135. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/py.typed +0 -0
  136. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/soar/__init__.py +0 -0
  137. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/soar/cimcef.py +0 -0
  138. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/soar/client.py +0 -0
  139. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/soar/web.py +0 -0
  140. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/dependency_links.txt +0 -0
  141. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/entry_points.txt +0 -0
  142. {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/top_level.txt +0 -0
@@ -3,3 +3,4 @@ prune docs
3
3
  prune samples
4
4
  prune scripts
5
5
  prune installers
6
+ graft docs/guides
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: splunkctl
3
- Version: 0.11.2
3
+ Version: 0.12.0
4
4
  Summary: Open-source MCP server and CLI for Splunk Enterprise SIEM and Splunk SOAR.
5
5
  Author: dannyota
6
6
  License-Expression: Apache-2.0
@@ -27,7 +27,7 @@ Requires-Dist: pyyaml>=6.0
27
27
  Requires-Dist: tabulate>=0.9
28
28
  Requires-Dist: requests>=2.32
29
29
  Requires-Dist: defusedxml>=0.7
30
- Requires-Dist: mcp<2,>=1.28.1
30
+ Requires-Dist: mcp<3,>=2
31
31
  Provides-Extra: dev
32
32
  Requires-Dist: pytest>=8.0; extra == "dev"
33
33
  Requires-Dist: ruff>=0.6; extra == "dev"
@@ -0,0 +1,79 @@
1
+ # Alerts
2
+
3
+ Fired alerts are the SOC's incoming work queue. During an incident, you
4
+ need to see what triggered, when, and at what severity. During planned
5
+ maintenance, you need to suppress noisy rules before they flood the
6
+ on-call channel. After the fact, auditors ask which alerts fired and
7
+ which were suppressed. These commands cover all three workflows.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ splunkctl alerts list # list fired alerts
13
+ splunkctl alerts get 'Alert Name' # details for one alert group
14
+ splunkctl alerts actions # list alert action types
15
+ splunkctl alerts suppress 'Alert Name' \
16
+ --duration 7200 --yes # suppress for 2 hours
17
+ ```
18
+
19
+ ## Triage during an incident
20
+
21
+ List all currently fired alerts to see what the environment is telling you.
22
+ Output includes name, trigger count, triggered time, and severity.
23
+
24
+ ```bash
25
+ splunkctl alerts list
26
+ splunkctl alerts get 'Brute Force Login Attempts'
27
+ ```
28
+
29
+ ## Check alert action types
30
+
31
+ See which action types (email, webhook, script, etc.) are configured on
32
+ the instance. Useful before creating or modifying saved searches that
33
+ fire alerts.
34
+
35
+ ```bash
36
+ splunkctl alerts actions
37
+ ```
38
+
39
+ ## Suppress during a maintenance window
40
+
41
+ Suppression is guarded -- dry-run by default. The first command below
42
+ previews the change; the second applies it. Duration is in seconds.
43
+
44
+ ```bash
45
+ splunkctl alerts suppress 'Brute Force Login Attempts' --duration 7200
46
+ splunkctl alerts suppress 'Brute Force Login Attempts' --duration 7200 --yes
47
+ ```
48
+
49
+ Suppress multiple alerts in a loop during a planned outage:
50
+
51
+ ```bash
52
+ for rule in 'Brute Force Login Attempts' 'Failed VPN Auth' 'DNS Exfil'; do
53
+ splunkctl alerts suppress "$rule" --duration 14400 --yes
54
+ done
55
+ ```
56
+
57
+ ## JSON output for scripts and agents
58
+
59
+ Pass `--json` to get structured output suitable for piping into `jq`,
60
+ feeding into an LLM agent, or storing as audit evidence.
61
+
62
+ ```bash
63
+ splunkctl alerts list --json # all fired alerts
64
+ splunkctl alerts list --json | jq '.[] | select(.severity >= 6)'
65
+ splunkctl alerts get 'Brute Force Login Attempts' --json > alert_detail.json
66
+ ```
67
+
68
+ An LLM agent can consume the JSON directly to decide next steps --
69
+ for example, correlating fired alerts with a change window calendar
70
+ or auto-filing tickets for high-severity triggers.
71
+
72
+ ## Options
73
+
74
+ | Flag | Applies to | Description |
75
+ |------|-----------|-------------|
76
+ | `--duration` | `suppress` | Suppression length in seconds (default 3600) |
77
+ | `--json` | all | Force JSON output regardless of TTY |
78
+ | `--format` | all | Output format: `table`, `json`, `csv`, `jsonl` |
79
+ | `--yes` | `suppress` | Apply the mutation (skip dry-run preview) |
@@ -0,0 +1,65 @@
1
+ # Apps
2
+
3
+ Splunk's detection and enrichment capabilities live in apps --
4
+ Technology Add-ons (TAs) for data normalization, security content packs
5
+ like Splunk Enterprise Security, and custom apps with org-specific
6
+ detections. Managing these remotely lets you deploy, update, and audit
7
+ apps across instances without SSH or manual Web UI clicks.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ splunkctl apps list # list installed apps
13
+ splunkctl apps get SplunkForwarder # get app details
14
+ splunkctl apps install --path ./app.spl --yes # install from local file
15
+ splunkctl apps install --path ./app.tar.gz \
16
+ --force --yes # force overwrite
17
+ splunkctl apps uninstall my_app --yes # uninstall
18
+ splunkctl apps update my_app --enabled \
19
+ --visible --yes # enable + show
20
+ splunkctl apps update my_app --disabled \
21
+ --hidden --yes # disable + hide
22
+ splunkctl apps reload --yes # reload all apps
23
+ ```
24
+
25
+ ## Remote install
26
+
27
+ `apps install --path` uploads a local `.spl` or `.tar.gz` package to
28
+ the remote Splunk instance via the Web UI handler. No SSH, no SCP, no
29
+ server filesystem access needed -- push from your laptop to any
30
+ reachable instance.
31
+
32
+ Use `--force` to overwrite an existing app of the same name.
33
+
34
+ ## Practical examples
35
+
36
+ ```bash
37
+ # Deploy a TA for Windows event log normalization
38
+ splunkctl apps install \
39
+ --path ./Splunk_TA_windows-8.9.0.spl --yes
40
+
41
+ # Upgrade a security content pack (force overwrite)
42
+ splunkctl apps install \
43
+ --path ./DA-ESS-ContentUpdate-4.29.0.spl --force --yes
44
+
45
+ # Disable an app during an incident (stop its scheduled searches)
46
+ splunkctl apps update SplunkEnterpriseSecuritySuite \
47
+ --disabled --yes
48
+
49
+ # Re-enable after the incident
50
+ splunkctl apps update SplunkEnterpriseSecuritySuite \
51
+ --enabled --yes
52
+
53
+ # Audit installed apps -- pipe JSON to jq for scripting
54
+ splunkctl apps list --json | jq '.[] | {name, version, disabled}'
55
+
56
+ # Reload all app configs after a bulk change
57
+ splunkctl apps reload --yes
58
+ ```
59
+
60
+ ## Notes
61
+
62
+ - App install may require a Splunk restart to activate new modular
63
+ inputs or scripted lookups. The CLI does not restart automatically.
64
+ - `--force` is required when reinstalling or upgrading an app that
65
+ already exists on the instance.
@@ -0,0 +1,125 @@
1
+ # Change audit & RBAC attestation
2
+
3
+ Regulator-facing evidence for bank SOC operations: who changed what
4
+ (`audit changes`) and who can do what (`audit rbac`). Both commands are
5
+ **read-only** — no `guard`, no `--yes` needed.
6
+
7
+ ## Why this matters
8
+
9
+ Banks carry regulator obligations for change-management evidence ("who
10
+ changed this saved search / role / index, and when") and periodic access
11
+ recertification ("who has which capabilities, and why"). Today an agent
12
+ would have to hand-write `index=_audit` SPL and know that Splunk mixes
13
+ **two incompatible event shapes** in that one index — this group
14
+ normalizes both into one schema and joins the RBAC graph so neither
15
+ requires bespoke SPL per engagement.
16
+
17
+ ## Commands
18
+
19
+ ```bash
20
+ splunkctl audit changes # last 24h, up to 500
21
+ splunkctl audit changes --since -7d --until -1d # explicit window
22
+ splunkctl audit changes --user jdoe # exact-match user
23
+ splunkctl audit changes --action edit # substring-match action
24
+ splunkctl audit changes --object-type saved_search # exact-match object type
25
+ splunkctl audit changes --limit 2000 --json # raise the display cap
26
+
27
+ splunkctl audit rbac # one row per user
28
+ splunkctl audit rbac --format csv --out recert-2026-07.csv # recertification export
29
+ splunkctl audit rbac --roles-only # one row per role
30
+ ```
31
+
32
+ ## `audit changes`: normalized schema
33
+
34
+ Every row has exactly six keys, in this order: `time`, `user`, `action`,
35
+ `object`, `object_type`, `app`. Splunk's `_audit` index mixes two
36
+ sourcetypes and this command normalizes both:
37
+
38
+ | Sourcetype | Shape | Mapping |
39
+ |---|---|---|
40
+ | `audittrail` (legacy) | `Audit:[timestamp=..., user=..., action=..., <tail>]` plain text | `user`/`action` parsed directly; `object` only when the line carries a literal `object="..."` marker (common on capability checks like `edit_user`/`edit_roles`); `object_type` is always empty — the legacy format has no per-action type field; `app` from `app="..."` or unquoted `app=...`, when present |
41
+ | `audittrailv2` (structured) | one JSON object per line | `user` = `actor.name`; `action` = top-level `action`; `object` = `data.name`; `object_type` = `data.type`; `app` = `data.ownership.app` or `data.attributes.app` |
42
+
43
+ `time` always comes from Splunk's own indexed `_time` (not a re-parse of
44
+ either embedded timestamp format) — it's present on every event
45
+ regardless of shape and gives one consistent, sortable value.
46
+
47
+ There is no literal `data.object`/`data.object_type` key on real
48
+ `audittrailv2` events; `data.name`/`data.type` are the nearest
49
+ equivalents and confirmed present for object/system-category events
50
+ (config changes). Action/authn/check-category events (ad-hoc searches,
51
+ logins, capability grants) carry `data.type` sometimes but rarely
52
+ `data.name` — `object` stays empty for those, which is correct: they
53
+ aren't changes to a named object.
54
+
55
+ An event matching neither shape is **never dropped** — it comes back as
56
+ `action: "unparsed"` with the full raw line in `object`, so evidence
57
+ stays complete even for audit-log formats this parser doesn't yet know.
58
+
59
+ ## `audit changes`: SPL safety
60
+
61
+ The dispatched search is always the constant `search index=_audit` —
62
+ nothing else, ever. `--since`/`--until` go through the oneshot job's
63
+ `earliest_time`/`latest_time` kwargs (not string-composed), and
64
+ `--user`/`--action`/`--object-type` filter the already-normalized rows
65
+ **client-side**, after the fetch. No flag value — however adversarial —
66
+ reaches the SPL string. Verified live with `--debug`:
67
+
68
+ ```bash
69
+ $ splunkctl --debug audit changes --user 'x" | delete' --action 'y | outputlookup evil.csv'
70
+ ...
71
+ POST .../search/v2/jobs/ (body: {'search': 'search index=_audit', ...})
72
+ ```
73
+
74
+ `--limit` (default 500) applies **after** filtering, not to the raw
75
+ fetch — the raw fetch itself is unbounded (`count=0`) within the
76
+ `--since`/`--until` window, so a `--user`/`--action` filter never misses
77
+ a match just because it fell outside an arbitrary raw-fetch cutoff.
78
+ A very wide `--since` over a large `_audit` index may fetch all events in that range before limiting, which can be slow; narrow `--since` when possible.
79
+ `--user`/`--object-type` are case-insensitive exact match; `--action` is case-insensitive substring match.
80
+
81
+ ## `audit rbac`: aggregation
82
+
83
+ One row per user by default: `user`, `email`, `roles` (direct roles,
84
+ semicolon-joined), `capabilities`, `srch_indexes_allowed`. The last two
85
+ are aggregated across the user's direct roles **and the full transitive
86
+ closure of their imported roles** — deduplicated, sorted, and
87
+ semicolon-joined. `--roles-only` flips to one row per role instead:
88
+ `role`, `imported_roles` (direct only), `capabilities`,
89
+ `srch_indexes_allowed` (both aggregated the same transitive way, rooted
90
+ at that role).
91
+
92
+ Example: role `soc_analyst` imports `power`, which imports `user`. A
93
+ `soc_analyst` user's effective `capabilities` is the union of all three
94
+ roles' own capabilities — this is what a role with zero capabilities of
95
+ its own (e.g. Splunk's built-in `splunk-system-role`, which only imports
96
+ `admin`) needs to show its real effective grant, not an empty cell.
97
+
98
+ ## CSV round-trip safety
99
+
100
+ Multi-value fields (`roles`, `capabilities`, `srch_indexes_allowed`,
101
+ `imported_roles`) join with `;`, never `\n` — Splunk role/capability/index
102
+ names can't contain a semicolon, so this is a safe, lossless join that
103
+ never produces an embedded newline inside a CSV cell. `--format csv`
104
+ output round-trips cleanly through Python's `csv` module.
105
+
106
+ ## Options
107
+
108
+ | Flag | Applies to | Description |
109
+ |------|-----------|--------------|
110
+ | `--since` | `changes` | Earliest time (default `-24h`) |
111
+ | `--until` | `changes` | Latest time (default `now`) |
112
+ | `--user` | `changes` | Filter by user, case-insensitive exact match |
113
+ | `--action` | `changes` | Filter by action, case-insensitive substring match |
114
+ | `--object-type` | `changes` | Filter by object type, case-insensitive exact match |
115
+ | `--limit` | `changes` | Max results after client-side filtering (default 500) |
116
+ | `--roles-only` | `rbac` | One row per role instead of per user |
117
+
118
+ ## Implementation notes
119
+
120
+ `changes` runs over the existing oneshot-search infrastructure
121
+ (`svc.jobs.oneshot`); the event-shape parsers live in a sibling module,
122
+ `splunkctl/commands/audit_parse.py`, kept separate from the click
123
+ commands since they're pure functions with their own fixture-driven test
124
+ suite. `rbac` is SDK reads only (`svc.roles`, `svc.users`) — no oneshot
125
+ search involved.
@@ -0,0 +1,84 @@
1
+ # Conf
2
+
3
+ Generic conf file/stanza editor over the REST `confs` API — the escape
4
+ hatch for any Splunk conf file that doesn't have a dedicated command
5
+ group yet: `macros`, `eventtypes`, `tags`, `limits`, `authorize`,
6
+ `server`, `web`, and everything else under `$SPLUNK_HOME/etc/*/local`.
7
+
8
+ ## Why this matters
9
+
10
+ Detections depend on more than saved searches: macros expand reusable
11
+ SPL fragments, eventtypes classify events, tags drive CIM compliance,
12
+ and calculated fields live in `props.conf` alongside sourcetypes.
13
+ `parsers` only reaches `props.conf`/`transforms.conf`; `conf` reaches
14
+ every other conf file the same way, so nothing detection-relevant is
15
+ locked out of code review or CI.
16
+
17
+ There is **no blocklist** — `conf` can edit `authorize.conf`,
18
+ `server.conf`, and `web.conf` just as readily as `macros.conf`. The
19
+ dry-run guard and `--yes` are the only safety net: every `set`/`unset`/
20
+ `reload` preview names the exact file and stanza before it touches
21
+ anything, so review the preview before applying to a sensitive file.
22
+
23
+ ## Commands
24
+
25
+ ```bash
26
+ splunkctl conf files # list conf files
27
+ splunkctl conf list macros # list stanzas in macros.conf
28
+ splunkctl conf list macros --app my_app # scope to one app's stanzas
29
+ splunkctl conf get macros my_macro # full stanza config
30
+ splunkctl conf get macros my_macro --key definition # one key
31
+ splunkctl conf set macros my_macro \
32
+ definition='index=main' --yes # create/update keys
33
+ splunkctl conf unset macros my_macro definition --yes # clear a key
34
+ splunkctl conf reload macros --yes # reload the conf file
35
+ ```
36
+
37
+ ## Recipes
38
+
39
+ ### Add a macro
40
+
41
+ Create a macro and verify it before rollout:
42
+
43
+ ```bash
44
+ splunkctl conf set macros my_macro \
45
+ definition='index=main sourcetype=syslog' --yes
46
+ splunkctl conf get macros my_macro
47
+ ```
48
+
49
+ ### Audit an eventtype
50
+
51
+ ```bash
52
+ splunkctl conf get eventtypes authentication --json | jq .
53
+ ```
54
+
55
+ ### Review a stanza change before applying
56
+
57
+ `conf set` always previews a field-level diff — old value on the left,
58
+ new value on the right, `add` for a brand-new key:
59
+
60
+ ```bash
61
+ splunkctl conf set macros my_macro definition='index=main'
62
+ # [DRY RUN] ...
63
+ # definition: index=old -> index=main
64
+ ```
65
+
66
+ ### List conf files to find the right one
67
+
68
+ ```bash
69
+ splunkctl conf files --filter tag
70
+ ```
71
+
72
+ ## Tips
73
+
74
+ - `conf set` creates the stanza if it doesn't exist yet — there's no
75
+ separate create step.
76
+ - The REST API has no true per-key delete; `conf unset` sets keys to
77
+ the empty string (same mechanism `parsers unset` uses). To fully
78
+ remove a stanza, use the dedicated command group for that conf file
79
+ when one exists (e.g. `parsers delete` for `props.conf`).
80
+ - `--app` on `conf list`/`conf files` matters: the unscoped default
81
+ view can miss app-private stanzas, same as `rules list`/`dashboards
82
+ list`.
83
+ - Reload the conf file after a `set`/`unset` if the change needs to
84
+ take effect immediately (`conf reload <file> --yes`).
@@ -0,0 +1,120 @@
1
+ # Configure
2
+
3
+ ## Interactive setup
4
+
5
+ ```bash
6
+ splunkctl config init
7
+ ```
8
+
9
+ Prompts for host, port, auth method (token or username/password), tests the
10
+ connection, and writes `~/.splunkctl/config.yaml` with `0600` permissions.
11
+
12
+ ## Config file
13
+
14
+ Location: `~/.splunkctl/config.yaml`
15
+
16
+ ```yaml
17
+ host: "localhost"
18
+ port: 8089
19
+ scheme: "https"
20
+ username: "admin"
21
+ password: "" # optional, can use token instead
22
+ token: "" # bearer token (preferred)
23
+ verify: true # TLS cert verification (default: on)
24
+ app: "search" # default app context
25
+ owner: "nobody" # default owner context
26
+ ```
27
+
28
+ **TLS verification is on by default.** Production instances with valid
29
+ certificates work out of the box. For lab/dev instances with self-signed
30
+ certs, set `verify: false` explicitly in the profile — `config init` asks
31
+ during setup (default: yes).
32
+
33
+ ## Profiles (dev/UAT/prod)
34
+
35
+ For more than one Splunk instance, add a `profiles:` map and a `current:`
36
+ pointer instead of the flat keys above:
37
+
38
+ ```yaml
39
+ profiles:
40
+ dev:
41
+ host: "dev.splunk.internal"
42
+ username: "admin"
43
+ password: "devpass"
44
+ uat:
45
+ host: "uat.splunk.internal"
46
+ token: "..."
47
+ prod:
48
+ host: "prod.splunk.internal"
49
+ token: "..."
50
+ current: "uat" # active profile when nothing else selects one
51
+ ```
52
+
53
+ ```bash
54
+ splunkctl config init --profile uat ... # create/update one named profile
55
+ splunkctl config use uat # point 'current' at it (no connectivity test)
56
+ splunkctl config show # active profile (redacted) + other names
57
+ splunkctl config show --profile prod # show a specific profile without switching
58
+ splunkctl --profile prod rules list # override for a single invocation
59
+ ```
60
+
61
+ **Selection precedence**: `--profile <name>` global flag > `current:`
62
+ pointer > `default`.
63
+
64
+ **Legacy files keep working.** A plain flat file (no `profiles:` key) is
65
+ treated as an implicit profile named `default` — nothing to migrate. Bare
66
+ `config init` writes that flat shape — unless the destination file already
67
+ has a `profiles:` key, in which case it folds the new values into
68
+ `profiles.default` instead, leaving sibling profiles and `current`
69
+ untouched (bare `config init` never clobbers an existing multi-profile
70
+ file). The first time you run `config init --profile <name>` against a
71
+ legacy file, it's upgraded to the `profiles:` schema in place: the old flat
72
+ keys move under `profiles.default`, the new named profile is added
73
+ alongside it, and file permissions stay `0600`.
74
+
75
+ **Guard banner.** Every dry-run preview and `--yes` confirmation prints
76
+ which instance is about to be mutated —
77
+ `[DRY RUN] ... (profile: uat @ uat.splunk.internal:8089)` — so switching
78
+ between dev/UAT/prod never happens silently. The banner is built from local
79
+ config only; it never opens a connection.
80
+
81
+ ## Environment variables
82
+
83
+ | Variable | Maps to |
84
+ |---|---|
85
+ | `SPLUNK_HOST` | `host` |
86
+ | `SPLUNK_PORT` | `port` |
87
+ | `SPLUNK_TOKEN` | `token` |
88
+ | `SPLUNK_USER` | `username` |
89
+ | `SPLUNK_PASS` | `password` |
90
+
91
+ Env vars override fields of whichever profile is selected — same as they
92
+ override the flat config today.
93
+
94
+ ## Resolution priority
95
+
96
+ 1. CLI flags (`--host`, `--port`, `--token`)
97
+ 2. Environment variables
98
+ 3. Profile (config file)
99
+
100
+ ## Watch mode
101
+
102
+ Re-run any read-only command at a fixed interval, clearing the screen
103
+ between runs (like `watch(1)` on Linux). Errors are printed in place and
104
+ the loop continues. Press Ctrl-C to stop.
105
+
106
+ ```bash
107
+ splunkctl --watch 5 indexes list # refresh every 5 seconds
108
+ splunkctl --watch 10 server health # poll server health
109
+ splunkctl --watch 3 rules list --filter brute # filtered view
110
+ ```
111
+
112
+ Requires an interactive terminal (TTY). Mutation commands (those guarded
113
+ by `--yes`) are rejected.
114
+
115
+ ## Verify
116
+
117
+ ```bash
118
+ splunkctl config show # display config (secrets redacted)
119
+ splunkctl config test # test connectivity + auth
120
+ ```
@@ -0,0 +1,17 @@
1
+ # Dashboards
2
+
3
+ ## Commands
4
+
5
+ ```bash
6
+ splunkctl dashboards list # list dashboards
7
+ splunkctl dashboards list --app search # filter by app
8
+ splunkctl dashboards get <name> # get definition (XML)
9
+ splunkctl dashboards create --name new_dash --file dash.xml \
10
+ --app search --yes
11
+ splunkctl dashboards update <name> --file updated.xml \
12
+ --app search --yes
13
+ splunkctl dashboards delete <name> --app search --yes
14
+ splunkctl dashboards export <name> --out dash.xml
15
+ ```
16
+
17
+ Uses the `Dashboard`/`Dashboards` entity classes from the SDK fork.
@@ -0,0 +1,164 @@
1
+ # Data models (CIM/tstats acceleration)
2
+
3
+ Mature SOC detections run on accelerated CIM data models via `| tstats`
4
+ — this group answers "which models exist," "is acceleration healthy,"
5
+ and "trigger a rebuild when stale." No SDK entity for data models
6
+ (unlike dashboards/lookups/HEC tokens) — every command is a thin, typed
7
+ wrapper around the raw `datamodel/model` and `admin/summarization` REST
8
+ collections, same pattern as `kvstore`/`server`.
9
+
10
+ ## Why two REST resources
11
+
12
+ `datamodel/model`'s `content["acceleration"]` field is only the
13
+ **configuration** — `enabled`, `earliest_time` (the summarization
14
+ window), `cron_schedule`. It does **not** carry build progress. Percent
15
+ complete, the actual summarized earliest/latest range, size, and the
16
+ last build error live on a separate `admin/summarization` entity, one
17
+ per accelerated model, named `tstats:DM_<app>_<model>`.
18
+
19
+ This shape was confirmed against this project's own Splunk 10.4 install,
20
+ not guessed from REST trial and error alone: the installed
21
+ `splunk.models.summarization.Summarization` REST model class
22
+ (`$SPLUNK_HOME/lib/python3.13/site-packages/splunk/models/summarization.py`)
23
+ declares every `summary.*` field this group reads, and the bundled Data
24
+ Model Manager JS (`data_model_manager.js`) builds the exact
25
+ `tstats:DM_<app>_<model>` id when it fetches a model's acceleration
26
+ info in the Splunk Web UI. Both ship with splunkd itself, so they
27
+ describe exactly what this REST API version does — the same UI page an
28
+ admin would open to check acceleration health.
29
+
30
+ ## Commands
31
+
32
+ ```bash
33
+ splunkctl datamodels list # name, app, accelerated, disabled
34
+ splunkctl datamodels list --app Splunk_SA_CIM
35
+ splunkctl datamodels list --filter auth
36
+
37
+ splunkctl datamodels get Authentication # detection-engineering summary
38
+ splunkctl datamodels get Authentication --definition # raw objects/fields/calculations JSON
39
+ splunkctl datamodels get Authentication --app Splunk_SA_CIM
40
+
41
+ splunkctl datamodels acceleration # every accelerated model's build status
42
+ splunkctl datamodels acceleration Authentication # one model (accelerated or not)
43
+
44
+ splunkctl datamodels rebuild Authentication --yes # re-summarize from scratch (guarded)
45
+ ```
46
+
47
+ ## `list`: cheap collection fields only
48
+
49
+ Columns: `name`, `app`, `accelerated` (bool), `disabled` (bool) — all
50
+ read straight off the collection listing, no per-model follow-up call.
51
+ `--app` (default: all apps), plus the uniform `--limit`/`--offset`/
52
+ `--filter` paging (F2): `--filter` forces a full fetch with client-side
53
+ case-insensitive name matching; without it, `--limit`/`--offset` pass
54
+ straight through to the REST call as `count`/`offset`.
55
+
56
+ ## `get`: detection-engineering summary, not the full blob
57
+
58
+ A data model's raw definition (`content["description"]`) is a
59
+ JSON-encoded string that can run past 250KB for a CIM model with dozens
60
+ of objects — `get` parses it once and surfaces only what a detection
61
+ engineer actually needs:
62
+
63
+ - `name`, `app`, `displayName`, `disabled`
64
+ - `acceleration_enabled`, `acceleration_earliest_time`,
65
+ `acceleration_cron_schedule` — the acceleration *config* (not status;
66
+ use `acceleration` for that)
67
+ - `object_count`, `objects` (comma-joined object names)
68
+ - `root_search` — the base object's first constraint search, i.e. what
69
+ raw index/sourcetype/tag the whole model actually covers
70
+
71
+ Pass `--definition` to get the raw, pretty-printed objects/fields/
72
+ calculations JSON instead — same shape as `dashboards get --definition`,
73
+ just for a data model's object hierarchy instead of a Studio dashboard's
74
+ visualization JSON.
75
+
76
+ ## `acceleration`: the money command
77
+
78
+ `datamodels acceleration` (no argument) lists every model whose
79
+ acceleration config is enabled, with its build status:
80
+
81
+ - `enabled` — acceleration config state (should always be `true` here)
82
+ - `has_summary` — whether `admin/summarization` has an entity yet (a
83
+ freshly-enabled model with a cron that hasn't fired yet is
84
+ `enabled: true, has_summary: false` — accelerated, but nothing built)
85
+ - `is_complete` / `percent_complete` — from `summary.complete` (a 0–1
86
+ fraction server-side; rendered here as a 0–100 percentage, rounded to
87
+ 1 decimal place: `round(float(complete) * 100, 1)`)
88
+ - `size`, `earliest_summarized`, `latest_summarized` — raw
89
+ `summary.size`/`summary.earliest_time`/`summary.latest_time`,
90
+ unmodified (epoch seconds, not reformatted)
91
+ - `last_error` — `summary.last_error` (a list server-side, one entry
92
+ per distributed peer) joined with `; `; empty string when clean
93
+
94
+ If nothing is accelerated, this cleanly renders an empty result — never
95
+ an error — and skips the `admin/summarization` fetch entirely (no
96
+ accelerated models means nothing to look up).
97
+
98
+ `datamodels acceleration <name>` shows one model regardless of whether
99
+ it's accelerated: `enabled: false` (with every other field blank/`null`)
100
+ is a valid, non-error answer to "is this model accelerated at all" — an
101
+ agent auditing acceleration coverage across many models shouldn't have
102
+ to special-case the read path for the ones that aren't accelerated yet.
103
+ Only a model that doesn't exist at all is an error (`kind: "not_found"`).
104
+
105
+ ## `rebuild`: guarded, disable-then-re-enable
106
+
107
+ There is no dedicated "rebuild" REST verb for data model acceleration.
108
+ Splunk Web's own "Rebuild" button (confirmed from the installed Data
109
+ Model Manager JS) works by POSTing `datamodel/model/<name>` twice:
110
+ first `acceleration=0` (disable), then `acceleration=1` with the same
111
+ `acceleration.earliest_time` re-sent explicitly (re-enable) — this drops
112
+ the existing tsidx summary and re-summarizes historical data for the
113
+ same window from scratch. `datamodels rebuild <name>` does exactly this,
114
+ behind the standard dry-run guard:
115
+
116
+ ```bash
117
+ splunkctl datamodels rebuild Authentication # [DRY RUN] preview, no changes
118
+ splunkctl datamodels rebuild Authentication --yes # applies: disable, then re-enable
119
+ ```
120
+
121
+ The dry-run preview names the model, its app, the preserved
122
+ `earliest_time` window, and states plainly that this re-summarizes
123
+ historical data from scratch — there is no partial/incremental rebuild.
124
+
125
+ **Only meaningful for an already-accelerated model.** If the named
126
+ model's acceleration config is disabled, `rebuild` exits 1 with a clear
127
+ message *before* the dry-run/`--yes` guard even runs — passing `--yes`
128
+ against a non-accelerated model does not print a preview and does not
129
+ touch anything, it just fails the same way the bare dry-run would.
130
+
131
+ **Known caveat (inherent to the underlying REST API, not this CLI):**
132
+ because a rebuild is two separate POSTs, a failure between them (e.g. a
133
+ permission or connectivity error on the second call) can leave the
134
+ model disabled without the summary having restarted. This is exactly
135
+ the same risk Splunk Web's own Rebuild button carries — there is no
136
+ atomic rebuild operation to fall back to. A rebuild failure surfaces
137
+ through the normal F1 classified envelope; re-running `datamodels get
138
+ <name>` afterward shows whether acceleration ended up enabled again.
139
+
140
+ ## Errors
141
+
142
+ REST failures are never caught locally — they flow straight through the
143
+ CLI's F1 error-envelope classification (`splunkctl.errors.classify`), so
144
+ a down or misconfigured instance always surfaces a clean `kind`/
145
+ `http_status`/`message`, never blank output or a raw traceback:
146
+
147
+ ```bash
148
+ $ splunkctl --json datamodels list
149
+ {"error": {"kind": "http", "http_status": 503, "message": "..."}}
150
+ ```
151
+
152
+ ## Live-verified status
153
+
154
+ `list`/`get`/`acceleration` (read paths) and `rebuild`'s dry-run preview
155
+ and not-accelerated rejection are live-verified against the local dev
156
+ instance. The instance ships Splunk Security Essentials (sample content
157
+ and CIM-aware detections) but not the `Splunk_SA_CIM` add-on itself, so
158
+ no data model on it is actually accelerated — `acceleration`'s populated
159
+ build-status row (non-zero percent complete, a real summarized range)
160
+ and `rebuild --yes`'s two-POST apply path are unit-tested against the
161
+ REST shape above (verified via the installed Splunk source, not
162
+ guessed) rather than live-verified end-to-end; live verification of a
163
+ populated, real acceleration build is pending an instance with an
164
+ actually-accelerated CIM model.