mcpField
S
splunk-setup-page-builder

splunk-setup-page-builder

github.com/splunk开发6393 次安装7 周前更新
代码仓库

关于 splunk-setup-page-builder

这项技能用于为 Splunk 应用和附加组件构建首次启动配置页面,避免使用已弃用的 setup.xml。它指导页面实现和验证,并区分普通设置与机密信息的存储方式。

主要功能

  1. 01创建首次启动配置页面
  2. 02通过 configurations REST 集合保存设置
  3. 03使用 storage/passwords 保存机密
  4. 04验证字段并完成配置
  5. 05使用 splunk-appinspect 验证包

适用场景

  1. 01为应用添加 API 端点和令牌配置
  2. 02替换已弃用的 setup.xml 页面
  3. 03发布前验证应用包

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/splunk/splunk-agent-skills --skill splunk-setup-page-builder

安装后在 Claude Code 中输入/splunk-setup-page-builder确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
references/
appinspect-checklist.md
setup-page.js

详细介绍

Splunk 设置页面构建器

为 Splunk 应用或附加组件构建首次运行设置页面:用户首次启动应用时显示的页面,用于收集所需配置(端点 URL、API 令牌、功能开关等),并在不使用已弃用的 setup.xml 机制的情况下完成设置。

这套流程经过实际验证,并非纸上谈兵:下方的工作流已在真实的 Splunk Enterprise 10.4 实例上端到端构建,通过了 splunk-appinspect 的 test 和 precert 模式验证,并在手动测试发现两个实际问题后进行了修订(参见已知陷阱——请勿再次引入这两个问题)。之后又由全新 Agent 会话独立重新验证了两次;这些会话没有任何先前上下文,并且各自仅根据说明构建了不同的玩具应用。

前提条件

  • 一个要添加设置页面的 Splunk 应用目录(现有应用,或使用 default/app.conf、default/data/ui/ 和 metadata/default.meta 搭建的新应用)。
  • 目标平台:Splunk Enterprise 9.x+ 或 Splunk Cloud Platform(同等版本)。编写文件不需要本地 Splunk 实例,但必须安装到真实实例中才能验证文件——参见验证。
  • 本地已安装 splunk-appinspect,用于静态验证(pip install splunk-appinspect;在 macOS 上,你可能还需要运行 brew install libmagic,以便顺利导入)。

使用场景

当用户正在为 Splunkbase(或内部 TA)构建 Splunk 应用/附加组件,并且需要用户在应用运行前提供配置——最常见的是 API 端点、凭据/令牌或少量功能设置——且希望提供规范的“设置应用”体验,而不是在安装后手动编辑 .conf 文件时,使用此技能。

不要为此使用 default/setup.xml。该机制已弃用,在 Splunk Cloud Platform 和搜索头集群中不受支持,并且会直接导致 Splunk AppInspect 的云检查失败(check_setup_xml_in_default)。所有需要首次运行配置且希望兼容云环境的应用都必须改用设置视图(Simple XML 或 React),并通过 app.conf 的 [install] is_configured / [ui] setup_view 进行配置。

除非用户明确确认目标,否则不要安装或重新配置生产环境或共享 Splunk 实例。绝不要向用户索要原始 Splunk 管理员凭据——使用 Splunk Web 已提供的会话/身份验证方式,通过 JS SDK 访问即可。

工作范围仅限构建设置页面本身。将相关请求转交至:

  • 有关通用应用/附加组件打包、兼容性、升级、弃用或移除的建议(与设置页面无关)→ app-and-add-on-lifecycle-advisor(仅提供建议;不会编写或安装任何内容——实际构建设置页面仍由此技能负责)。
  • 超出此应用自身 default.meta 范围的现有共享知识对象治理(所有权、孤立对象、ACL 审查、命名冲突)→ knowledge-object-governance。
  • HEC 或其他数据摄取的设置/故障排除 → hec-setup-and-troubleshooting。
  • 与设置页面无关的字段提取、CIM 映射或临时 SPL 编写 → field-extraction-and-cim-mapping 或 splunk-search。
  • 与设置页面无关的通用 Splunk 产品问题 → splunk-product-question-navigator。

架构

<app>/
├── app.manifest                              # required metadata for packaging/AppInspect
├── default/
│   ├── app.conf                               # [install] is_configured, [ui] setup_view, [triggers]
│   └── data/ui/
│       ├── views/
│       │   ├── setup_page_dashboard.xml       # the setup view (Simple XML)
│       │   └── home.xml                       # minimal landing view (see below)
│       └── nav/
│           └── default.xml                    # declares home.xml as the default view
├── metadata/
│   └── default.meta                           # permissions for the app + any custom conf file
├── appserver/static/
│   ├── javascript/setup_page.js               # setup logic, uses the Splunk JS SDK
│   └── styles/setup_page.css
└── README/
    └── <settings_conf_file>.conf.spec         # spec for any custom conf file you introduce

两种存储后端,按字段选择:

字段类型存储原因
非机密设置(URL、开关、间隔等)内置的 configurations REST 集合,指向你定义的自定义 <name>.conf 文件无需自定义 Python REST 处理程序。开箱即用,兼容云环境。
机密信息(令牌、密码、API 密钥)storage/passwordsSplunk 会将其加密并存储在 passwords.conf 中;绝不要将机密信息写入纯文本 conf 文件——这会导致 AppInspect 检查失败,也会造成实际安全风险。

工作流概览

1. 收集需求

询问用户(或根据上下文推断):

  • 应用 ID/目录(必须与 app.conf [package] id 一致——只能包含字母、数字、点和下划线)。
  • 哪些字段是非机密设置,哪些是机密信息。每项都要确认:名称、类型、必填/可选、验证规则。
  • 应用是否已有其他视图。如果没有,则添加一个最简主页视图(第 6 步),以免设置完成后用户进入无关的共享内容。
  • 此应用是否已有可扩展的设置页面,还是需要从头创建。
2. 配置 app.conf
[install]
is_configured = 0

[package]
id = <app_id>
check_for_updates = false

[id]
name = <app_id>
version = 1.0.0

[ui]
is_visible = 1
label = <Human Readable Label>
# No file extension; resolves to default/data/ui/views/setup_page_dashboard.xml
setup_view = setup_page_dashboard

[launcher]
author = <author>
description = <description>
version = 1.0.0

[triggers]
# One reload.<conf_file> line per custom conf file the setup page writes.
reload.<settings_conf_file> = simple

如果漏掉 check_for_updates = false 和 [triggers] 中的 reload 行,AppInspect 都会将其标记出来——请参阅你应预期并修复的 AppInspect 检查结果。

[id] version 和 [launcher] version 是两个彼此独立的字段,必须保持相同。系统不会自动强制执行;每次发布时都要同时更新这两个字段,否则 AppInspect/Splunkbase 可能会根据某项检查读取的字段,将版本判定为不匹配。

3. 构建设置视图(Simple XML + JS)

default/data/ui/views/setup_page_dashboard.xml:

<dashboard isDashboard="false"
           script="javascript/setup_page.js"
           stylesheet="styles/setup_page.css"
           hideTitle="true"
           version="1.1">
    <row>
        <panel>
            <html>
                <div id="main_container">
                    <h3>&lt;Human Readable Label&gt;</h3>
                    
                </div>
            </html>
        </panel>
    </row>
</dashboard>

appserver/static/javascript/setup_page.js 使用 Splunk JS SDK (通过 require 加载的 splunkjs/splunk)。完整且经过验证的实现 ——包括验证、保存非机密设置、保存机密信息、完成设置、重新加载并重定向、 错误呈现——位于 references/setup-page.js。请复制它并 调整字段名称和验证逻辑;不要从头重写 SDK 的连接代码——它已经发现并修复了 两个实际 bug(参见已知陷阱)。 以下约定在该文件中隐含体现;此处再次说明,免得你需要从代码中反向推断:

  • 设置配置文件本身的命名:使用 <app_id>_settings (例如 my_app_settings),除非应用已有更具体的名称。此名称对应 configurations 集合所创建的 <name>.conf 文件——Splunk 并未固定此名称, 只需选定一个,并在所有地方保持一致(JS、.conf.spec、[triggers] 重载 行)。
  • 段落命名:该配置文件中的段落名称同样不由 Splunk 固定——选择一个与设置组 相关且有描述性的名称(例如,region 字段对应 region_settings, 轮询间隔字段对应 polling_settings)。请在 JS 和第 7 步编写的 .conf.spec 中保持一致。
  • 命名 storage/passwords realm 和 name:realm 与应用关联 (<app_id>_realm),name 与具体的机密字段关联(使用字段本身的名称,例如 api_token、webhook_signing_secret)。这样可以区分同一应用中的多个机密, 并与下方的键格式一致。
  • 不要随应用分发 default/<settings_conf_file>.conf。 configurations REST 集合会在设置页面首次保存时于磁盘上的 local/ 中创建该文件和段落—— 这正是使用它而非自定义 REST 处理程序的目的。你只需编写 default/app.conf、default/data/ui/*、metadata/default.meta 和 app.manifest;设置配置文件是运行时创建的输出文件,不是源文件。
  • storage/passwords 的查找键格式为 <realm>:<name>:——realm、 name 和一个字面上的结尾冒号,以冒号连接。检查凭据是否已存在时 (passwords.item(key)),必须严格按此格式构建字符串,再决定使用 create 还是 update。格式错误会导致每次“更新”都悄无声息地变成空操作后不匹配,或创建重复项。
  • 应根据每个字段的实际格式进行验证,而不仅仅检查是否存在或是否有某个前缀。 已知陷阱 #1 中的 URL 示例 就是一个常见问题:仅检查是否存在或是否有前缀会放过无效数据。应针对字段的实际 格式编写真正的模式或范围检查(例如区域代码、端口号、电子邮件地址等),而不只是 检查“是否非空”。
4. 添加最简主页视图和导航

如果应用没有其他视图,请添加:

default/data/ui/views/home.xml——一个单面板仪表板,说明应用的用途以及稍后前往何处重新配置。

default/data/ui/nav/default.xml:

<nav search_view="search" color="#5C6773">
    <view name="home" default="true" />
</nav>

否则,点击 Splunk Web 侧边栏中的应用时,会跳转到此实例上存在的某个共享/全局仪表板 (例如,另一款已安装且全局导出的应用的仪表板),这会让人困惑,看起来像是应用出错, 尽管设置页面本身运行正常。

5. 在 metadata/default.meta 中设置权限
[]
access = read : [ * ], write : [ admin, power, sc_admin ]
export = none

[<settings_conf_file>]
access = read : [ admin, power, sc_admin ], write : [ admin, power, sc_admin ]
export = none

请包含 sc_admin,而不仅仅是 admin——Splunk Cloud 客户无法使用单独的 admin,且 AppInspect 会对此发出警告 (check_kos_are_accessible)。

6. 添加 app.manifest

打包/AppInspect 必需(check_for_valid_package_id)。最简格式:

{
  "schemaVersion": "2.0.0",
  "info": {
    "title": "<Human Readable Label>",
    "id": { "group": null, "name": "<app_id>", "version": "1.0.0" },
    "author": [{ "name": "<author>", "email": null, "company": null }],
    "releaseDate": null,
    "description": "<description>",
    "classification": { "intendedAudience": null, "categories": [], "developmentStatus": null },
    "commonInformationModels": null,
    "license": { "name": null, "text": null, "uri": null },
    "privacyPolicy": { "name": null, "text": null, "uri": null },
    "releaseNotes": { "name": null, "text": null, "uri": null }
  },
  "dependencies": {},
  "tasks": [],
  "inputGroups": {},
  "incompatibleApps": {},
  "platformRequirements": { "splunk": { "Enterprise": "*" } }
}
7. 为任何自定义设置文件编写 conf 规范

使用标准 Splunk .conf.spec 语法,在 README/<settings_conf_file>.conf.spec 中记录你引入的每个段和键——包含 [stanza] 标头、每项设置对应的 key = <type>,以及紧跟其后的 * 项描述行:

[<settings_stanza>]
<field_name> = <string>
* <what this field is and any format constraint, e.g. "Must look like a
  region code, e.g. us-east-1.">
* No default.

使用与字段实际匹配的值类型标记,不要总是用 <string>——常见类型包括 <string>、<integer>、<bool>、<seconds>。例如,限制取值范围的整数型字段:

[<settings_stanza>]
poll_interval_seconds = <integer>
* How often, in seconds, the app polls its data source.
* Must be an integer between 30 and 3600 inclusive.
* No default.

此文件供管理员参考,configurations REST 端点本身不会强制执行这些类型或约束。客户端 JavaScript 验证只能改善设置页面的体验;之后使用这些值的任何后端代码或模块化输入,都必须在使用前重新验证。值可能通过完全绕过 JavaScript 的途径进入底层 conf 文件——例如直接编辑 local/<file>.conf,或向同一端点发送原始 REST 调用——因此下游任何环节都不能假定设置页面的验证已经运行。

切勿在此记录机密字段——机密信息根本不应放在此文件中,因为它们本来就不会存储在纯文本 conf 文件中。

已知问题(再次遇到时请修复)

这些问题是通过实际端到端测试发现的,并非仅靠检查代码得出。如果不注意,照搬较早的参考示例时很容易再次引入这两个问题。

  1. 仅检查是否存在,或仅检查前缀。 这是一条通用规则,不只适用于 URL:任何只检查“是否非空”或“是否以正确前缀开头”的验证,都会放过无效内容。实际发现的具体情况是:像 /^https?:\/\// 这样的正则表达式会把后面什么都没有的字面字符串 http:// 接受为“有效” URL。修复方法是要求包含主机名: /^https?:\/\/[^\s]+\..+/i。对每个字段都应采用同样的标准——针对字段的实际内容编写真正的模式/范围/格式检查(例如区域代码、端口号、非空且格式正确的机密信息等),而不只是检查是否存在。

  2. 不要使用 is_configured 作为保存条件。 Splunk 官方设置页面示例会在提交处理程序开头检查 is_configured,如果其值已为 1,便直接跳过保存,执行重新加载并重定向。这会悄无声息地丢弃用户之后重新打开设置页面(例如通过 Manage Apps > Set up)输入的新值,比如轮换令牌或更改设置。已通过复现验证这一点:尝试“更新”后,passwords.conf 中的加密密码逐字节保持不变,因为根本没有执行保存。提交时始终执行工作流的第 2 至第 5 步,不论当前 is_configured 的值如何。Splunk 平台层面的重定向行为(由 is_configured 控制)已经可以避免强制要求已完成配置的用户访问此页面;提交处理程序无需再次强制执行这一逻辑。

    此规则针对的是行为,而非某个特定变量名。 提交处理程序(completeSetup / onSubmit / 或你使用的其他名称)必须在每次用户点击提交时,无条件调用保存逻辑——写入设置、写入机密信息、设置 is_configured、重新加载、重定向。保存之前不得添加任何检查 is_configured 的提前退出保护,无论其名称是 isAlreadyConfigured、isConfigured、alreadyConfigured、configuredAlready、skipIfConfigured、skipSave,还是任何等效名称。如果你发现自己编写了一个读取 is_configured、并可能在执行保存调用前就 return 的 if 语句,请将其删除——无论你给变量起什么名字,这都是同一个确切的错误。

验证

仅靠静态分析不足以证明一切正常——请同时验证以下两项:

  1. AppInspect(可发现结构和认证问题):

    splunk-appinspect inspect <app_dir_or_package> --mode test
    splunk-appinspect inspect <app_dir_or_package> --mode precert
    

    预期 error/failure 均为 0。全新应用中常见的问题及其修复方法,请参阅 references/appinspect-checklist.md。

  2. 真实的 Splunk 实例(可发现 AppInspect 无法发现的行为问题,例如上述两个陷阱)。未经明确确认,请勿安装到生产实例或共享实例中。最低限度的手动检查:

    • 全新安装并设置 is_configured=0 → 确认会重定向到设置页面。
    • 必填字段留空后提交 → 确认验证会阻止提交,且不会发出 REST 调用。
    • 提交满足“非空”条件但格式不符合实际要求的字段(例如 URL 字段仅填写 http://)→ 确认仍会被拒绝。
    • 提交有效值 → 确认出现成功消息、发生重定向,并且非机密设置写入自定义 conf 文件,机密写入 passwords.conf 时为加密状态(绝不能是明文)。
    • 重启 Splunk → 确认 is_configured=1 已持久保存,应用不会再次重定向到设置页面。
    • 重新打开设置并提交新的机密值 → 确认现有密码条目会原位更新(不会产生重复的 stanza),如上述陷阱 #2 所述。
    • 点击侧边栏中的应用 → 确认会进入该应用自己的主页视图,而不是无关的共享内容。

示例

  • “为此插件添加一个设置页面,用于收集基础 API URL 和 API 令牌,然后才能运行应用。”→ 收集这两个字段,配置 app.conf,根据 references/setup-page.js 构建设置视图和 JS,添加主页视图和导航,设置 default.meta,添加 app.manifest,然后使用 AppInspect 和真实实例进行验证。
  • “此应用已有 app.conf 和导航;请添加首次运行设置,用于保存 webhook 签名密钥和介于 30 到 3600 秒之间的轮询间隔。”→ 工作流相同,但跳过步骤 4(主页视图和导航已存在),并按“根据每个字段的实际格式进行验证”规则,使用范围/长度验证,而不是 URL 模式。
  • “我们的设置界面使用 default/setup.xml,未能通过 Splunk Cloud AppInspect 审查。”→ 完全删除 default/setup.xml,并按照此技能的工作流,将相同字段重建为 setup_view;不要尝试修补或移动现有的 setup.xml。

故障排除

  • AppInspect 报告“Do not use default/setup.xml in the Cloud environment.” 删除该文件;没有受支持的方法可以保留它以兼容 Cloud。请按相同配置重建为 setup_view(本技能的完整做法)。
  • AppInspect 报告“Invalid XML File”或未定义实体错误(例如 mdash)。 XML 只定义了五种内置实体(&amp; &lt; &gt; &apos; &quot;)。将任何命名 HTML 实体(如 &mdash;、&nbsp; 等)替换为数字形式(&#8212;、&#160;)。
  • 重新安装或重启后,对 setup_page.js 的更改似乎没有生效。 Splunk Web(以及浏览器)会积极缓存静态 JS。仅执行 splunk restart 并不能保证重新获取文件。在认定修复无效之前,请强制刷新(Cmd/Ctrl+Shift+R),或在隐私/无痕窗口中打开页面。
  • 之后重新打开设置页面(从 Manage Apps 中选择“Set up”)更改某个值时没有效果——提交后值看起来没有变化。这是常见问题 #2:is_configured 门控会在不提示的情况下跳过保存。请移除该门控。
  • 在 Splunk Web 侧边栏中点击应用后,却跳转到其他应用中无关的仪表板。 该应用没有自己的主页视图/导航,因此 Splunk 会转而显示其他应用共享/全局导出的内容。请添加 default/data/ui/views/home.xml 和 default/data/ui/nav/default.xml(步骤 4)。
  • 无法访问“Manage Apps”或“Set up”,或 Splunk 报告许可证功能错误(例如 Requires license feature='Auth')。 目标实例使用 Free 许可证运行,该许可证会完全禁用身份验证/RBAC。本技能的设置页面依赖角色/功能以及 storage/passwords,这些都属于 Auth 系统——验证需要使用 Trial 或 Enterprise 许可证实例,而不能使用 Free 许可证实例。

安全

  • 除 storage/passwords 外,绝不要在其他任何位置存储机密。绝不要记录机密值(包括在向用户显示的错误消息中)。
  • 绝不要要求用户在你编写的任何内容中输入原始 Splunk 管理员凭据;请依赖 JS SDK 已通过 Splunk Web 获得的会话。
  • 未经用户明确确认目标实例,绝不要安装、重启或重新配置共享/生产 Splunk 实例。
  • 不要修改属于其他应用的知识对象。

评论

支持 Markdown