来自 网络 2022-06-09 04:30 的文章

cc防御_云盾科技_零误杀

cc防御_云盾科技_零误杀

深入测试(另外,请不要使用未声明的依赖项。)Robert FinkFollow 5月27日7分钟阅读

我在今天上午的内部聊天中看到了以下讨论(稍作解释):

Alice:我们在启动日志中看到java.lang.ClassNotFoundException;这是在我们的数据库客户端的依赖项升级之后发生的。鲍勃:数据库人员需要更新他们的RPC库依赖项。数据库客户端使用的是从RPC库传递过来的OkHttp依赖项。RPC库删除了对OkHttp的支持,因此当您升级数据库时,客户端找不到OkHttp类?啊,我想我们使用内存数据库进行集成测试。它们不会到达OkHttp路径.Bob。确切地幸运的是,这对任何人来说都不是一个P0,因为阿波罗已经自动回滚并召回了受影响的版本。但是,还是让我们尽快修复数据库依赖项设置吧?

这个bug是如何逃过测试的?为什么不在半夜把工程师们叫醒?我们的连续发射系统阿波罗到底是如何帮助我们的?这里有很多东西需要解包,下面的博文试图解包。

不要使用未声明的依赖项:AKA,bug。

上面讨论的产品与这里显示的调用大致相同。

该产品使用RPC库(我们使用Concure for RPC)调用多个web服务。它还依赖于具有两种不同实现的数据库客户机:

对于发布前集成测试("体外",蓝色),我们使用内存中的伪实现(下文将对此进行详细介绍)。生产实现("体内",红色)使用RPC库调用远程数据库服务(这是AtlasDb/Cassandra)。

您可能已经闻到钻石依赖问题;好了,它来了。RPC库最初在内部使用OkHttp进行HTTP调用,产生以下依赖项设置:

Product@1.0.0→ RPC@2.0.0→ OkHttp→ 数据库客户端→ RPC@2.0.0→ OkHttp

RPC库后来迁移到Apache HTTP客户端并删除了OkHttp依赖项;当产品升级到版本为2.1的新RPC库时。依赖关系图如下所示:

产品@1.1.0→ RPC@2.1.0→ 数据库客户端→ RPC@2.0.0→ OkHttp

请注意,RPC依赖关系在依赖关系图中出现两次—一次是版本2.1.0(使用Apache HTTP客户端)的直接依赖关系,一次是版本2.0.0(使用OkHttp)的DatabaseClient的可传递依赖关系。我们的构建系统(Gradle)使用锁文件作为依赖项(相关的,请查看我们的Gradle一致版本插件,它非常整洁)。通常,产品开发人员会将RPC依赖项锁定到2.1.0,从而有效地覆盖和升级对的DatabaseClient依赖项RPC@2.0.0.

到目前为止,我们没有做错任何事情:RPC升级了一个内部库,其行为或API没有任何改变(因此是一个小版本bump 2.0.0)→ 2.1.0),并且构建系统拾取新的RPC依赖项并一致地应用它。请注意,什么是高防cdn,OkHttp不再是一个依赖项,但这很好,因为RPC@2.1.0不再使用OkHttp。

那么,如果我们没有做错任何事情,这是怎么发生的?事实证明,DatabaseClient直接使用了OkHttp类(即,在RPC库之外)。但是,DatabaseClient没有声明对OkHttp的依赖关系。换句话说,依靠php防御cc,DatabaseClient使用了一个可传递的依赖项而没有声明它,有效地依赖于RPC库的私有实现细节。这是一个构建系统错误,通过向DatabaseClient库添加明确的OkHttp依赖项可以很容易地修复。

我们可以防止该错误吗?这取决于构建系统工具。在Palantir,我们使用了许多Gradle插件来帮助实现依赖性卫生:

Gradle一致版本允许开发人员为项目声明依赖性版本(它与nebula.dependency-recommender和vanilla Gradle 4.8+锁文件有着细微的区别,更多细节请参见自述文件。)CheckClassUnique可防止类路径上出现重复类。请注意,通过Maven coordinate消除重复数据依赖项是不够的,例如,在重命名内部或开源依赖项时。重复类是微妙错误的一个令人讨厌的来源,因为运行时行为(即使用哪个类)取决于难以观察的属性,如依赖项JAR文件的文件系统顺序。checkImplicitDependencies努力防止导致上述错误的确切原因:已使用但未声明的依赖项。在这一点上,确定一个类何时被使用但未被声明并不是一个完全解决的问题,特别是当库使用反射时。在这种情况下,为什么checkImplicitDependencies没有发现问题?不幸的是,检查在CI时没有强制执行;当然,我们正在通过添加check.checkUnusedDependencies来修复根本原因。当开发人员声明他们不使用的依赖项时,checkUnusedDependencies会提醒他们。虽然这看起来主要是一个卫生问题,最小的依赖性足迹降低了发布漏洞的风险,并有助于保持较小的发布规模。gradle-dependency-control(内部)管理依赖关系的中心AllowList和DenyList

Java Jigsaw项目以及Maven的依赖关系范围(使用gradle的api与实现配置清晰地表示)通过让开发人员明确(并且可以强制执行!)以更有原则的方式解决这些问题在公共和私有API以及依赖项之间拆分。我希望Jigsaw模块的采用将慢慢渗透到开源和Palantir代码库中,便宜ddos防御,帮助提高代码质量和防止依赖性bug。关于该主题的更多阅读,请查看谷歌Bazel构建系统的文档,描述完全相同的问题。

深入测试