Snyk语言服务器(Snyk LS)
  
支持的功能
语言服务器如下 这 语言服务器协议 并与Snyk开源、Snyk基础设施即代码、SnykCode和Snyk Secrets集成。对于开源和IaC,它使用Snyk CLI作为数据提供者;Snyk代码使用Snyk编码API;机密扫描在适用的情况下使用CLI。
目前,语言服务器支持以下操作:
- 如果文档是当前文件夹集的一部分,则在打开文档时向客户端发送诊断。
- 启动时启动文件夹扫描并发送诊断。
- 根据命令启动所有文件夹的工作区扫描。
- 缓存诊断,直到保存或触发新的工作区扫描。
- 保存文档时使缓存无效,并重新检索保存的文档诊断。
- 提供范围计算,以正确突出显示文件中的Snyk开源问题。
- 提供带有诊断详细信息和后续链接的格式化悬停
- 向客户报告后台作业的进度
- 通知和向客户端记录消息
- 需要时进行身份验证,使用OAuth2或令牌身份验证,必要时打开网页
- 如果打开网页时出现问题,请将身份验证URL复制到剪贴板
- 如果未找到Snyk CLI或配置为XDG_DATA_HOME,则自动下载Snyk命令行界面
- 根据传输的设置选择性激活产品
- 扫描错误作为诊断报告给语言服务器客户端
- 代码透镜,用于在编辑器中导航Snyk代码数据流
- 编辑器内命令的代码操作,如打开浏览器、执行快速修复或打开Snyk Learn课程
对于已找到的诊断
已执行的操作
语言服务器协议支持
请求:
- 初始化
- 退出
- text文档/代码操作
- text文档/code镜头
- text文档/did关闭
- text文档/did保存
- text文档/悬停
- text文档/内联值
- 关闭
- workspace/diChangeWorkspaceFolders
- workspace/did更改配置
- 工作区/执行命令
- window/workDonePress/create(从服务器->客户端)
- windows/showMessageRequest
- 窗口/显示文档
通知
- $/进度
- $/取消请求
- text文档/发布诊断
- 参数: types.PublishDiagnosticsParams - 示例:Snyk开源
{
"uri": "file:///path/to/file",
"diagnostics": [
{
"range": {
"start": { "line": 1, "character": 0 },
"end": { "line": 2, "character": 0 },
},
"severity": 1,
"code": "S100",
"source": "Snyk",
"message": "Message",
"tags": ["security"],
"data": {
"id": "123",
"issueType": "vulnerability",
"packageName": "packageName",
"packageVersion": "packageVersion",
"issue": "issue",
"additionalData": {
"ruleId": "ruleId",
"identifiers": {
"cwe": ["cwe"],
"cve": ["cve"]
},
"description": "description",
"language": "language",
"packageManager": "packageManager",
"packageName": "packageName"
}
}
}
]
}- 示例:Snyk代码
{
"uri": "file:///path/to/file",
"diagnostics": [
{
"range": {
"start": { "line": 1, "character": 0 },
"end": { "line": 2, "character": 0 },
},
"severity": 1,
"code": "S100",
"source": "Snyk",
"message": "Message",
"tags": ["security"],
"data": {
"id": "123",
"filePath": "filePath",
"range": {
"start": { "line": 1, "character": 0 },
"end": { "line": 2, "character": 0 },
},
"additionalData": {
"message": "message",
"rule": "rule",
"ruleId": "ruleId",
"dataFlow": [
{
"filePath": "filePath",
"range": {
"start": { "line": 1, "character": 0 },
"end": { "line": 2, "character": 0 },
},
}
],
"cwe": "cwe",
"isSecurityType": true
}
}
}
]
}- 窗口/日志消息
- 窗口/显示消息
语言服务器协议的自定义添加(服务器->客户端)
- SDK回调,用于从客户端检索已配置的SDK
- 方法: workspace/snyk.sdks - 参数: types.WorkspaceFolder - 例子:
[{
"type": "java", // or python or go
"path": "/path/to/sdk" // JAVA_HOME for java, GOROOT for Go, Python executable for Python
}]- 配置通知(协议v25+)
- 方法: $/snyk.configuration - 参数: types.LspConfigurationParam - 注意:统一的基于映射的协议——全局设置+每个文件夹设置,每个文件夹都携带值、源、源和锁状态 - 例子:
{
"settings": {
"api_endpoint": { "value": "https://api.snyk.io", "source": "global" },
"snyk_oss_enabled": { "value": true, "source": "ldx-sync", "originScope": "organization" },
"proxy_http": { "value": "http://proxy:8080", "source": "ldx-sync-locked", "originScope": "tenant", "isLocked": true }
},
"folderConfigs": [
{
"folderPath": "/path/to/project",
"settings": {
"base_branch": { "value": "main", "source": "folder" },
"preferred_org": { "value": "org-id", "source": "folder" },
"snyk_code_enabled": { "value": false, "source": "ldx-sync-locked", "originScope": "group", "isLocked": true },
"severity_filter_critical": { "value": true, "source": "ldx-sync", "originScope": "organization" },
"severity_filter_high": { "value": true, "source": "ldx-sync", "originScope": "organization" },
"severity_filter_medium": { "value": false, "source": "ldx-sync", "originScope": "organization" },
"severity_filter_low": { "value": false, "source": "ldx-sync", "originScope": "organization" }
}
}
]
}- IDE→LS使用 changed: true 对于PATCH语义: {"snyk_oss_enabled": {"value": true, "changed": true}}
- 自定义发布诊断通知
- 方法: $/snyk.publishDiagnostics316 - 参数: types.PublishDiagnosticsParams - 注意:textDocument/publishDiagnostics的别名
- 身份验证通知
- 方法: $/snyk.hasAuthenticated - 参数: types.AuthenticationParams - 例子:
{
"token": "the snyk token", // this can be an oauth2.Token string or a legacy token
"apiUrl": "https://api.snyk.io"
}- 看https://pkg.go.dev/golang.org/x/oauth2@v0.6.0#令牌,了解有关oauth令牌的更多详细信息。
- CLI路径通知
- 方法: $/snyk.isAvailableCli - 参数: types.SnykIsAvailableCli - 例子:
{
"cliPath": "/a/path/to/cli-executable"
}- 受信任文件夹通知
- 方法: $/snyk.addTrustedFolders - 参数: types.SnykTrustedFoldersParams - 例子:
{
"trustedFolders": ["/a/path/to/trust"]
}- 扫描通知
- 方法: $/snyk.scan - 参数: types.ScanParams - 示例:扫描成功
{
"status": "success", // possible values: "error", "inProgress", "success"
"product": "code", // possible values: "code", "oss", "iac", "secrets"
"folderPath": "/a/path/to/folder",
}- 示例:扫描失败,出现错误
{
"status": "error",
"product": "code",
"folderPath": "/a/path/to/folder",
"presentableError": {
"cliError": {
"code": "CLI_ERROR_CODE",
"error": "An error occurred"
},
"showNotification": true,
"treeNodeSuffixError": "(failed)"
}
}- 摘要面板状态通知
- 方法: $/snyk.scanSummary - 参数: types.ScanSummary - 例子:
{
"scanSummary": ""
}- 注册MCP通知
- 方法: $/snyk.registerMcp - 参数: types.SnykRegisterMcpParams - 例子:
{
"command": "/path/to/cli",
"args": [ "mcp", "-t", "stdio" ],
"env": {
"ENV1": "value1",
"ENV2": "value2"
}
}命令
NavigateToRangeCommand将客户端导航到给定范围
- 命令: snyk.navigateToRange - args: path, Range
WorkspaceScanCommand触发对所有工作区文件夹的扫描
- 命令: snyk.workspace.scan - args:空
WorkspaceFolderScanCommand触发对给定工作区文件夹的扫描
- 命令: snyk.workspaceFolder.scan - args: path
OpenBrowserCommand在默认浏览器中打开给定的URL
- 命令: snyk.openBrowser - args: URL
LoginCommand触发登录过程
- 命令: snyk.login - args:可选 [authMethod, endpoint, insecure] --例如。 ["oauth", "https://api.snyk.io", false] (参见配置HTML桥);省略的参数使用当前设置
CopyAuthLinkCommand将身份验证URL复制到剪贴板
- 命令: snyk.copyAuthLink - args:空
LogoutCommand触发注销过程
- 命令: snyk.logout - args:空
TrustWorkspaceFoldersCommand检查受信任的工作区文件夹,必要时请求信任
- 命令: snyk.trustWorkspaceFolders - args:空
OpenLearnLesson在Snyk Learn网站上打开给定的课程
- 命令: snyk.openLearnLesson - args: - rule string - ecosystem string - cwes string (逗号分隔),例如。 CWE-79,CWE-89 - cves string (逗号分隔),例如。 CVE-2018-11776,CVE-2018-11784 - issueType int
PackageHealth Type = 0
CodeSecurityVulnerability = 1
LicenceIssue = 2
DependencyVulnerability = 3
InfrastructureIssue = 4GetLearnSession在Snyk Learn网站上返回给定的课程
- 命令: snyk.getLearnLesson - args: - rule string - ecosystem string - cwes string (逗号分隔),例如。 CWE-79,CWE-89 - cves string (逗号分隔),例如。 CVE-2018-11776,CVE-2018-11784 - issueType int
PackageHealth Type = 0
CodeSecurityVulnerability = 1
LicenceIssue = 2
DependencyVulnerability = 3
InfrastructureIssue = 4- 结果:课程json
{
"lessonId": "123",
"datePublished": "2022-01-01",
"author": "John Doe",
"title": "Introduction to Golang",
"subtitle": "A beginner's guide to Golang",
"seoKeywords": ["Golang", "Programming", "Beginner"],
"seoTitle": "Learn Golang",
"cves": ["CVE-2022-1234", "CVE-2022-5678"],
"cwes": ["CWE-123", "CWE-456"],
"description": "This lesson provides an introduction to Golang for beginners",
"ecosystem": "Programming",
"rules": ["Rule 1", "Rule 2", "Rule 3"],
"slug": "golang-intro",
"published": true,
"url": "https://example.com/golang-intro",
"source": "Example.com",
"img": "https://example.com/images/golang-intro.png"
}SettingsSastEnabled触发api调用以检查是否启用了Snyk代码
- 命令: snyk.getSettingsSastEnabled - args:空 - 返回a *sast_contract.SastResponse 或者,如果发生错误,则为false
GetActiveUser触发api调用以获取活动登录用户,如果未登录,则触发错误
- 命令: snyk.getActiveUser - args:空 - 返回活动用户及其组织和组,如果未登录,则返回错误。
{
"id": "123",
"username": "johndoe",
"orgs": [
{
"name": "org1",
"id": "org1_id",
"group": {
"name": "group1",
"id": "group1_id"
}
}
],
}Code Fix Command触发自动修复并应用第一个建议的更改
- 命令: snyk.code.fix - args: - codeActionId 字符串 - AffectedFilePath 字符串 - range 范围 - 如果不成功,则返回错误
Code Fix Diffs允许检索自动修复建议的差异
- 命令: snyk.code.fixDiffs - args: - issueID字符串(UUID) - 返回一组建议:
[{
"fixId": "123",
"unifiedDiffsPerFile": {
"path/to/file": "diff"
}
}]- 差异示例:
--- /var/folders/vn/77lwfy3974g7vykcm5lr6mkh0000gn/T/Test_SmokeWorkspaceScanOssAndCode952013010/001/1
+++ /var/folders/vn/77lwfy3974g7vykcm5lr6mkh0000gn/T/Test_SmokeWorkspaceScanOssAndCode952013010/001/1-fixed
@@ -32,7 +32,8 @@
test('should set success to OK upon success', function() {
// GIVEN
- comp.password = comp.confirmPassword = 'myPassword';
+ comp.password = process.env.TEST_PASSWORD;
+ comp.confirmPassword = process.env.TEST_PASSWORD;
// WHEN
comp.changePassword();Code Fix Apply Edit Command触发自动修复并应用第一个建议的更改
- 命令: snyk.code.fixApplyEdit - args: - fixId 字符串 - 返回工作区编辑:
Feature Flag Status Command触发api调用以检查是否启用了功能标志
- 命令: snyk.getFeatureFlagStatus - args: - featureFlagType 字符串 - 返回一个具有功能标志状态和可选用户消息的对象
{
"ok": true, // boolean indicating if the feature is enabled (true or false)
"userMessage": "Optional message to the user" // present if 'ok' is false
}Clear Cache清除持久缓存或内存缓存,或两者都清除。
- 命令: snyk.clearCache - args: - folderUri 字符串, - cacheType persisted 或 inMemory
Generate Issue Description以HTML格式生成问题描述。
- 命令: snyk.generateIssueDescription - args: - issueId 字符串
Configuration Dialog打开包含所有Snyk设置的配置对话框。
- 命令: snyk.workspace.configuration - args:空 - return:包含配置对话框的HTML字符串 - 例子:
Snyk Configuration
...
- 看 配置对话框集成指南 有关完整集成的详细信息。
Connectivity Check执行全面的连接诊断,包括网络检查、代理检测、身份验证和组织访问。
- 命令: snyk.diagnostics.checkConnectivity - args:空 - return:字符串(格式化的连接检查结果,没有ANSI颜色) - 已执行的检查: - 与所有Snyk端点的网络连接 - 代理配置检测(包括Kerberos环境变量) - 身份验证状态 - 组织访问权限
Directory Diagnostics对Snyk使用的目录执行目录诊断,检查是否存在、可写性和CLI二进制文件。
- 命令: snyk.diagnostics.checkDirectories - args:要检查的附加目录的可选数组
[
{
"pathWanted": "/path/to/check",
"purpose": "Description of the directory purpose",
"mayContainCLI": true // whether this directory may contain CLI binaries
}
]- return:字符串(格式化的目录诊断结果,没有ANSI颜色) - 已执行的检查: - 当前用户信息 - 默认Snyk目录位置(CLI下载、配置存储、缓存) - LS设置中配置的CLI路径 - 客户端传递的其他目录 - 对于每个目录: - 存在性检查(如果不存在,则查找最近的现有父级) - 写入权限 - 找到Snyk CLI二进制文件(用于可能包含CLI的目录)
安装
下载
发布工作流存储生成的可执行文件,以便它们可以 下载 这里。只需选择您想要构建的版本 从附件中获取工件并下载附件中的zip文件。目前,适用于Windows、macOS和Linux的可执行文件为 生成。
当前发布的二进制文件可以通过以下方式检索 这 bash脚本,请记住 协议版本 是下载链接的一部分,可以更改为强制插件/语言服务器 同步。有关更多信息,请参阅 贡献.md.
来源
- 安装中列出的Go版本 贡献.md (当前Go为1.26.x),设置
GOPATH和GOROOT如有需要 - 输入此存储库的根目录
- 执行
go get ./...下载所有依赖项 - 执行
make build && make install生产asnyk-ls二进制
配置
Snyk LSP命令行标志
-c 允许在所有其他配置文件之前指定要加载的配置文件
-f 允许您指定日志文件,而不是记录到控制台
-l \ 允许指定输出格式(md 或 html`)对于问题
-v 打印语言服务器的版本
配置
LSP初始化选项(协议v25+)
作为 初始化消息, initializationOptions 被拆分为 types.InitializationOptions (internal/types/lsp.go).
机器设置 使用 pflag规范名称 作为映射键,每个值都是 ConfigSetting (value,可选 changed等等)。仅包含以下内容的条目 changed: true 在初始化过程中应用(IDE默认值不得擦除LDX同步或GAF默认值)。
仅初始化元数据 (相同的JSON对象,顶级字段): requiredProtocolVersion, deviceId, integrationName, integrationVersion, osPlatform, osArch, runtimeName, runtimeVersion, hoverVerbosity, outputFormat, path, trustedFolders.
示例形状:
{
"requiredProtocolVersion": "25",
"integrationName": "VISUAL_STUDIO_CODE",
"integrationVersion": "1.0.0",
"deviceId": "00000000-0000-0000-0000-000000000000",
"path": "/usr/local/bin",
"trustedFolders": ["/safe/project"],
"settings": {
"snyk_oss_enabled": { "value": true, "changed": true },
"snyk_code_enabled": { "value": true, "changed": true },
"snyk_iac_enabled": { "value": true, "changed": true },
"api_endpoint": { "value": "https://api.snyk.io", "changed": true },
"organization": { "value": "org-slug-or-uuid", "changed": true },
"token": { "value": "secret-token", "changed": true },
"proxy_insecure": { "value": false, "changed": true },
"authentication_method": { "value": "oauth", "changed": true },
"scan_automatic": { "value": true, "changed": true },
"severity_filter_critical": { "value": true, "changed": true },
"severity_filter_high": { "value": true, "changed": true },
"severity_filter_medium": { "value": true, "changed": true },
"severity_filter_low": { "value": true, "changed": true },
"issue_view_open_issues": { "value": true, "changed": true },
"issue_view_ignored_issues": { "value": false, "changed": true },
"scan_net_new": { "value": false, "changed": true },
"risk_score_threshold": { "value": 400, "changed": true },
"cli_path": { "value": "/path/to/snyk", "changed": true },
"automatic_download": { "value": true, "changed": true },
"binary_base_url": { "value": "https://downloads.snyk.io", "changed": true },
"cli_release_channel": { "value": "stable", "changed": true }
},
"folderConfigs": [
{
"folderPath": "/path/to/workspace",
"settings": {
"base_branch": { "value": "main", "changed": true },
"preferred_org": { "value": "org-id", "changed": true },
"org_set_by_user": { "value": true, "changed": true }
}
}
]
}注册的旗帜名称和优先规则记录在 docs/configuration.md.
运行时更新 使用 workspace/didChangeConfiguration 具有相同的有效载荷包络:LSP settings 是一个 LspConfigurationParam 其字段为 settings (地图), folderConfigs,可选 trustedFolders --看 types.DidChangeConfigurationParams 在 internal/types/lsp.go.
工作区信任
作为检查代码库漏洞的一部分,Snyk可能会自动在您的计算机上执行代码以获取 用于分析的附加数据。例如,这包括调用包管理器(例如pip、gradle、maven、yarn、, npm等) 获取Snyk开源的依赖关系信息。在具有恶意的不受信任的代码上调用这些程序 配置可能会使您的系统暴露于恶意代码执行和漏洞利用中。
为了防止在不受信任的文件夹上使用语言服务器,我们的语言服务器将要求文件夹信任 在对这些文件夹运行扫描之前。有疑问时,不要给予信任。
默认情况下启用信任功能。当一个文件夹受信任时,所有子文件夹也受信任。在文件夹之后 如果受信任,Snyk语言服务器会向语言服务器客户端通知自定义 $/snyk.addTrustedFolders 通知, 其中包含当前受信任文件夹路径的列表。基于此,客户端可以实现拦截逻辑 此通知并将决定和信任持久化在IDE或编辑器存储机制中。
可以通过设置禁用信任对话框 enableTrustedFoldersFeature 到 false 在初始化选项中。这 将禁用所有信任提示和检查。
通过设置,可以提供一组初始的受信任文件夹 trustedFolders 到中的一系列路径 initializationOptions。这些文件夹在启动时将受到信任,不会提示用户信任它们。
环境变量
Snyk LS和Snyk CLI支持并需要某些环境变量才能运行:
HTTP_PROXY,HTTPS_PROXY和NO_PROXY定义要使用的http代理JAVA_HOME通过Snyk CLI分析基于Java JVM的项目PATH在分析maven项目时查找maven,查找python等
自动配置
为了自动将这些变量添加到环境中,Snyk LS按顺序搜索以下文件 确定优先级。如果未从已配置的环境调用可执行文件(例如通过 zsh -i -c 'snyk-ls'),您还可以使用以下命令指定配置文件 -c 用于设置上述内容的命令行标志 变量。Snyk LS按照给定的优先级和顺序读取以下文件,不会覆盖已加载的文件 变量。
given config file via -c flag
/.snyk.env
$HOME/.snyk.env格式中包含环境变量的任何行 VARIABLENAME=VARIABLEVALUE 如果不存在,则自动添加到环境中。这符合 dotenv 格式。万一 .profile, .zshrc等,如果变量直接导出,例如通过 export VARIABLENAME=VARIABLEVALUE,它没有加载。出口需要拆分并保持独立,例如
VARIABLENAME=VARIABLEVALUE
export VARIABLENAMEPATH变量的处理方式与所有其他变量不同,因为它是中所有PATH变量的集合 文件和环境中。此外,当前工作目录 . 会自动添加到路径中,因此 LSP客户端将Snyk CLI下载到当前工作目录中,将为 语言服务器。
除了通过配置文件配置变量外,Snyk LS还将以下目录添加到linux上的路径中 以及macOS:
- /垃圾箱
- $HOME/bin
- /usr/local/bin
- $JAVA_HOME/bin
如果没有设置JAVA_HOME,它会自动先在路径中搜索JAVA可执行文件,然后在以下目录中搜索 并将其父目录添加为JAVA_HOME。递归搜索以下目录:
- /usr/lib
- /usr/java
- /opt
- /图书馆
- $HOME/.sdkman
- C: \\程序文件
- C: \\程序文件(x86)
在相同的目录中搜索maven可执行文件,并将父目录添加到路径中。
Snyk命令行界面
为了找到自动管理的Snyk CLI, 这 XDG数据之家 和 PATH 自动扫描路径以查找依赖于操作系统的文件,例如。 snyk-macos 在macOS上, snyk-linux Linux和 snyk-win.exe 在Windows上,找到它的第一条路径被添加到环境中。 它稍后用于依赖CLI的所有功能。
全局设置环境变量
如果你想让环境变量在系统范围内可用,你需要添加变量 到 /etc/environment 或在macOS上 /etc/launchd.conf 或通过以下方式设置它们 launchctl 在shell脚本中。前两个 snyk-lsp会自动读取位置。在Windows上,用户变量可以通过用户界面定义,或者 全系统。在类似的文件中 ~/.profile 它会这样:
SNYK_TOKEN=
DEEPROXY_API_URL=https://deeproxy.snyk.io/
# export variables, but make sure the export is not on the same line as the variable definition
export SNYK_TOKEN
export DEEPROXY_API_URLSnyk身份验证
Snyk LS身份验证流会自动发生,除非在配置中禁用,如下所示。当Snyk 语言服务器启动,它:
- 如果端点是snykgov.io端点,或者authenticationMethod设置为
oauth,它通过OAuth2进行身份验证。
这将打开一个浏览器窗口。
- 如果身份验证方法不是
oauth,它尝试使用Snyk CLI令牌身份验证来检索令牌。 - 如果CLI也未通过身份验证,它将打开一个浏览器窗口进行身份验证
- 如果打开浏览器窗口时出现问题,可以将身份验证URL复制到剪贴板(通过实现
的 snyk.copyAuthLink). _请注意,有一个要求 xsel 或 xclip 为Linux/Unix用户安装 对于这个功能。_
在web浏览器中成功通过身份验证后,Snyk语言服务器 自动检索Snyk身份验证凭据,并将其用于进一步的请求。
运行测试
go test ./...如果您在运行约定时有任何问题,请扩展您的PATH环境。 例如:
PATH=$PATH:$PWD/.bin/pact/bin make test输出应该是这样的(它是在Snyk Code API上运行的,并使用真正的CLI):
? github.com/snyk/snyk-ls [no test files]
ok github.com/snyk/snyk-ls/code 24.201s
ok github.com/snyk/snyk-ls/diagnostics 26.590s
ok github.com/snyk/snyk-ls/iac 25.780s
? github.com/snyk/snyk-ls/lsp [no test files]
ok github.com/snyk/snyk-ls/oss 22.427s
ok github.com/snyk/snyk-ls/server 48.558s
ok github.com/snyk/snyk-ls/util 9.562s在本地测试Github操作
您可以使用以下命令在本地测试github操作 行动.
安装动作和先决条件
brew install act
# if you don't have docker desktop you can use minikube (a one-node kubernetes distribution)
brew install --cask virtualbox # you need to enable the virtualbox extension in macOS settings
brew install minikube
minikube start
eval $(minikube docker-env) # gives you a fully functional docker environment奔跑表演
act --secret SNYK_TOKEN=$SNYK_TOKEN --secret DEEPROXY_API_URL=$DEEPROXY_API_URL