************************ 为 Suricata 贡献代码 ********************

本指南描述了如果您想为 Suricata 提交补丁或补丁集时需要采取的步骤。

主要包括以下几点:

  1. 同意并签署我们的 贡献协议

  2. 尽早沟通,并使用 首选渠道

  3. 认领工单

  4. 从 master 分支 fork

  5. 遵循我们的 编码规范

  6. 使用我们的 文档风格

  7. 遵守我们的 提交指南

  8. 为您的 Pull Requests 添加版本号

  9. 反馈意见 整合到新的 PR 中

  10. [工作合并后] 收尾工作!

本文档其余部分将详细说明这些内容。

Note

重要提示!

在贡献之前,请查看并签署我们的 贡献协议

沟通是关键!

为了澄清问题、讨论或建议新功能、讨论错误和优化、和/或寻求帮助,沟通非常重要。

我们的主要渠道有:

认领(或创建)工单

对于功能和错误修复,我们需要 工单。工单帮助我们跟踪已完成的工作,标明哪些更改需要回移植等。

如果您希望看到您的新功能被正式添加到我们的工具中,工单也非常重要:工单记录了您的想法,以便我们分析它们如何符合我们对 Suricata 的计划,如果功能被接受,我们可以正确跟踪进度等。

工单应清楚反映跟踪器中的意图。例如,如果工单是一个 "Bug",标题应仅说明错误是什么。

好的工单标题示例

1. 工单: [Bug #00000] stream: 在出现递增间隙时发生段错误

为什么好? 它显示了受影响的子系统和错误的具体内容。

2. 工单: [Bug #19999] dcerpc: 在无效数据情况下出现内存泄漏

为什么好? 它按照跟踪器的要求讨论了错误本身。

3. 工单: [Bug #44444] stream: TcpTracking 中内存使用过多

为什么好? 标题直击要点,传达了问题的本质。

Note

工单标题用于自动生成每个版本的变更日志。如果工单标题不清楚,变更日志无法正确传达版本中修复的问题。

Note

如果您想添加新功能(例如一个新的应用层协议),请先询问我们是否认为该功能会被合并到 Suricata 中。这有助于双方理解新功能如何适应我们的路线图,并避免浪费时间和动力在可能不被接受的贡献上。因此,`在`开始任何与新功能相关的代码之前,请向团队征求意见。

对于非常简单的修复或清理,我们不需要这样做。

一旦就问题的处理达成一致:

将工单分配给自己。为此,您需要拥有 "developer" 角色。您可以直接在您想认领的工单上申请,或在我们的 Discord 开发者频道 上表明您有兴趣处理 工单编号

如果工单已经分配给某人,请在工单上联系或先询问该人。

您可以通过 Suricata 的 Discord 服务器 联系其他社区成员。

期望

如果您提交的新功能不属于 Suricata 的核心功能,它将具有 `社区支持`_ 状态。这意味着在我们能够批准新功能之前,我们希望您或赞助您工作的组织做出一些承诺,因为 Suricata 开发团队相当精简(而且很多时候工作过度)。

这意味着我们希望:

  • 新贡献附带一组 Suricata-verify 测试(可能还有单元测试,如果适用),然后我们才能批准;

  • 在贡献用于替换现有功能时,提供与现有关键字/功能兼容的证明;

  • 您将在功能获得批准后维护它 - 或者如果您无法做到,其他社区成员会这样做。

Note

无论贡献的大小或复杂性如何,我们都希望您尊重我们的指南和流程。我们感谢社区贡献者: Suricata 不会是他们现在的样子;我们工具和社区的价值也来自于我们对此的重视程度,因此我们要求我们的贡献者也这样做!

"社区支持" 和 "支持一个功能" 是什么意思?

如果一个功能是 社区支持 的,Suricata 团队将尽量花费最少的时间在上面 - 以便专注于核心功能。如果出于任何原因您不愿意或无法承诺支持一个功能,请表明这一点。

团队和/或社区成员可以考虑提供帮助。最好在实际工作之前表明这一点,因为如果没有人站出来,我们将拒绝功能。

同样重要的是要注意,社区支持 的功能将默认禁用,如果它引入了新的依赖项(库或 Rust crate),这些也将是可选的并默认禁用。

支持一个功能 意味着实际 维护 它:

  • 修复错误

  • 编写文档

  • 保持更新

  • 通过论坛和/或 Discord 聊天提供最终用户支持

工单过期政策

我们理解人们的可用性和志愿为我们的项目贡献时间的兴趣可能会改变。因此,为了防止工单过期(无人处理),以及问题长时间未解决,我们有一项政策,如果6个月内没有贡献更新,我们将取消认领工单。

如果您认领了一个工单,后来发现您无法处理它,也欢迎您在工单中告知我们并取消认领,这样每个人都知道工作仍然开放并等待完成。

在哪个分支上工作

通常有2或3个活跃的分支:

  • master-x.x.x (例如 master-6.0.x)

  • main-x.x.x (例如 main-7.0.x)

  • master

带有版本号的是稳定分支。master 是开发分支。

稳定分支应仅用于重要的错误修复或其他需要的 回移植。这些主要来自更有经验的贡献者。

新功能或大规模重新设计的开发在开发分支中进行。新开发和新贡献者应使用 master 分支,除非在非常特殊的情况下 - 这些情况应首先与我们讨论。

如果有疑问,请通过 Redmine、Discord 或论坛 联系我们。

创建自己的分支

创建描述性分支名称很有用。您正在处理工单123以改进 GeoIP?将您的分支命名为 "geoip-feature-123-v1"。 "-v1" 的添加是为了反馈。当整合反馈时,您需要为每个拉取请求创建一个新分支。因此,当您处理第一个反馈时,您将在 "geoip-feature-123-v2" 中工作,依此类推。

更多详情请查看:创建分支进行更改

编码规范

我们有一个必须遵循的 编码规范

文档风格

对于 代码 文档,请根据您的贡献使用的语言(Rust 或 C)遵循 Rust 文档和/或 Doxygen 指南。本节的其余部分涉及用户和开发者文档。

用户和开发者指南文档(您现在正在阅读的内容)是用 reStructuredText 编写的,并使用 Sphinx 渲染。关于 reStucturedText 的入门,请参阅 reStructuredText 入门

在编写或更新 文档页面 时,请:

  • 将行限制在79(最多80)个字符;

  • 在添加图表或图像时,如果可能,我们更喜欢可以自动生成的替代方案;

  • 记住我们的文档发布在 Read the Docs 上,也可以构建为 pdf,因此重要的是它在这些格式中看起来不错。

标题

reStructuredText 允许灵活的标题顺序,为了一致性,请使用以下顺序:

  • #: 用于 h1

  • *: 用于 h2

  • =: 用于 h3

  • -: 用于 h4

  • ~: 用于 h5

  • ^: 用于 h6

例如,在一个新的文档页面中:

页面标题
##########

部分
*******

子部分
===========

规则示例

对于规则文档,我们有一个特殊的容器:

example-rule

这将在一个更容易阅读的字体大小的框中呈现规则,并且还允许突出显示签名中的特定元素,如名称所示 - action、header、options 或强调自定义部分:

  • example-rule-action

  • example-rule-header

  • example-rule-options

  • example-rule-emphasis

使用这些时,通过用 ` 包围要突出显示的部分来指示。在使用它们之前,必须调用特定的角色,如下:

.. role:: example-rule-role

每个文档只需调用一次角色。可以在我们的规则语言介绍中看到这些被调用(参见 规则介绍)。

一个规则示例如下:

.. container:: example-rule

:example-rule-action:`alert` :example-rule-header:`http $HOME_NET any ->
$EXTERNAL_NET any` :example-rule-options:`(msg:"HTTP GET Request Containing
Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri;
content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; rev:1;)`

结果如下:

alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"HTTP GET Request Containing Rule in URI"; flow:established,to_server; http.method; content:"GET"; http.uri; content:"rule"; fast_pattern; classtype:bad-unknown; sid:123; rev:1;)

示例 - 强调:

.. container:: example-rule

alert ssh any any -> any any (msg:"match SSH protocol version";
:example-rule-emphasis:`ssh.proto;` content:"2.0"; sid:1000010;)

渲染为:

alert ssh any any -> any any (msg:"match SSH protocol version"; ssh.proto; content:"2.0"; sid:1000010;)

提交历史很重要

在提交您的 PR 之前,请考虑我们的 提交指南

发送 Pull Request

Pull request 用于请求将您的补丁包含到主仓库中。在合并之前,它将经过审查并通过 QA 流程。

在提交时,请考虑我们的 Pull Requests 标准

我们启用了 'GitHub-CI' 集成。这意味着在 pull request 上执行一些自动构建检查、suricata-verity 和单元测试。通常,这在几分钟后就会准备好。如果测试失败,pull request 将不会被考虑。因此,当您提交某些内容时,请密切关注检查,并解决任何失败 - 如果您不理解它们是什么,可以在失败的 PR 上询问。

在合并之前,我们还在我们的私有 QA 实验室中执行其他集成测试。如果这些测试失败,我们可能会要求进一步更改,即使 GitHub-CI 已通过。

反馈

您可能会得到一些反馈。即使我们最有经验的开发人员也会得到反馈,所以不要为此感到难过。

在讨论了需要更改的内容(通常在 PR 本身上)之后,是时候回到 "创建自己的分支" 并重新开始。随着贡献的完善,这个过程可能会迭代多次。

收尾工作

合并!清理

恭喜!您的更改已合并到主仓库中。非常感谢!

我们强烈建议清理:删除您的相关分支,包括本地和 GitHub 上的 - 这有助于您在想要进行新贡献时保持组织有序。

更新工单

您现在可以将 合并的 pull request 的 URL 放入 Redmine 工单中。接下来,将工单标记为 "Closed" 或 "Resolved"。

干得好!您现在一切都完成了。