博客

Sensei Feature Highlight: Library Scope

June 9, 2021
Nick Van Haver

Manage dependencies flexibly

The Scope functionality of Sensei has always been a favorite of developers. With the ability to expand or limit the scope of a recipe’s application, development teams have been able to customize its usage to individual projects and verticals within their organizations - empowering developers to personalize their experience.

And understandably, it is at the center of Sensei’s continuous innovation processes. During an innovation brainstorming session on expanding the scope of “scope” (yes, pun intended), a question came up: 

"I was trying to create a recipe for ... but since version x, the framework has deprecated the feature. I am not sure whether it will be useful to create a recipe anymore. What do you think?"

Of course, this is not the first time we have hesitated to create a recipe. While the recipe might be seen as providing redundant information, we believe it is valuable to create something that is applicable to a limited number of versions of the involved dependency. And therefore, we created the Library scope.

Library scope enables us to check whether a dependency is present in the project and conditionally apply Sensei recipes. This gives great flexibility as teams navigate through legacy code and dependencies.

Many of you might know of the Library scope that is already available under General Settings. So what is this you ask? We have enabled Library Scope to be present in YAML, just like the search. This creates a better user experience and does not break your flow as you create the recipe, which otherwise would have you navigate to General Settings and back to update metadata. More of these scopes will come into YAML but we have started with the Library Scope.

So let us dive a little further into how it works with an example.

Library scope applied to hibernate-jpamodelgen

Imagine the following case: 

We want to create a Spring Web REST API that allows us to query some data. According to the best practices, we create a model for the entity we want to query. Next, we add a dependency to Hibernate ORM, so that we do not need to fiddle with the database structure. The ORM takes care of that for us. We also need to create a service that provides the data from the data access layer (CRUD repositories and so on) to the controller. Finally, we create the controller class for our API, where we will expose the allowed queries as endpoints.

To prevent having to expose different endpoints for each field that can be queried, we instead opt to use JPA 2 Specifications. To do so, we create a specification in the controller from the request URL. This specification describes what the entities we are looking for should look like. In the `Specification` class itself, we implement the `toPredicate` method to indicate how the specification can be validated.

But we are faced with an issue in the `toPredicate` method. To construct the predicate, we need to know the names of the columns in the database to compare. But because we are using an ORM, we do not have these columns present in a separate model. So, Hibernate's JPA 2 Metamodel Generator() comes to the rescue! This will help generate a metamodel for the entities we requested it to handle. These metamodels allow us to reference the column names as properties instead of hardcoding them.

Creating the Sensei recipe

Now that we have the metamodels generated, we want to put them to good use. Sensei can help anyone who works on the project by reminding them to use the metamodel, making sure that column names are not hardcoded anywhere. So let’s put that into practice.

To start, we take a look at the `toPredicate` method:‍

To Predicate method

This basic predicate will only compare the name of our entity. We can expand on it using `and` clauses, but for the purpose of this recipe, this 'simple' check will do.

For the search component of the recipe, we want to call the method `get()` of the root parameter, so we select the `methodcall` option from the dropdown. Next, we want to limit the search to a methodcall with the name `get` whose signature is declared in the `Path` interface of the `javax.persistence.criteria` package. As the method has been overloaded, we also need to tell the search that our recipe only applies to the variant that takes a single string as an argument. To fix the issue of having the column names in the code we would want to use an argument of type `SingularAttribute` instead, the same type provided by the metamodel generator.

Setting up the search criteria for the recipe

The recipe that we have created so far will trigger on any codebase that uses the JPA 2 `Path` interface, regardless of whether the codebase is set up to use the Hibernate Model Generator. If this library is present in the project, we want to indicate to the user that it should be used, so we add a library scope to the recipe.

Limiting the scope of search for this recipe

And finally, our recipe is now ready.

Test Recipe Methodcall

With this recipe, any occurrence of `Path#get` that uses a string value as an argument will be flagged. As you can tell from the highlighted example code in the above screenshot, this recipe still works when the literal name of the column name is stored in an intermediate variable.

Note - We can also invert the library scope to handle the case where the library is not available, by prepending a `not` clause to the scope.

Conclusion

As we have seen in the example above, this new feature enables us to create more useful recipes by applying them based on the presence of dependencies in the project. To enhance its power even further, we included more options than were shown in the example, such as not only checking whether the dependency is present, but also applying conditions to the specific version of the dependency. 

The main use cases we see for this feature are preventing recipes from providing duplicate information, detecting issues related to specific versions of dependencies, but also performing migrations from one dependency version to the next. We're looking forward to hearing from you about what uses you see for this feature.

As for all Sensei features, more information on the library scope is available in the reference documentation.

标语

在 AI 驱动的开发成果发布前实现有效治理

评估 AI 辅助风险,在提交代码时强制执行安全编码策略,并加速整个软件开发生命周期的安全交付。

预约演示
资源库

探索更多博客

获取有关安全编码、人工智能治理和软件风险管理的专家内容。

浏览全部
案例研究
筛选标签
这是 div 块中的一段文本。

Supercharged Security Awareness: How Tournaments are Inspiring Developers at Erste Group

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

了解更多
案例研究
筛选标签
这是 div 块中的一段文本。

Security as culture: How Blue Prism cultivates world-class secure developers

Learn how Blue Prism, the global leader in intelligent automation for the enterprise, used Secure Code Warrior's agile learning platform to create a security-first culture with their developers, achieve their business goals, and ship secure code at speed

了解更多
案例研究
筛选标签
这是 div 块中的一段文本。

统一的安全文化:Sage 如何打造其安全倡导者项目

了解 Sage 如何通过灵活且以关系为导向的方法提升安全性,成功培养了 200 多名安全倡导者,并实现了显著的风险降低。

了解更多
博客
筛选标签
这是 div 块中的一段文本。

2026年网络安全意识月:理解人工智能安全对企业防御至关重要

目前,大多数顶级人工智能公司已公开呼吁全球放缓人工智能的发展速度,以便安全防护措施能够跟上步伐。然而事实是,严重的安全问题已经显现。随着人工智能实施带来的经济成本和风险不断累积,无数安全领导者和高管团队正处于紧迫的境地。

了解更多
博客
筛选标签
这是 div 块中的一段文本。

赋能要素 8:打造项目品牌

成功的安全编码项目不仅需要优质的内容。赋能要素 8 展示了如何通过品牌化将参与过程转变为一种令人向往、以地位为驱动的体验。

了解更多
博客
筛选标签
这是 div 块中的一段文本。

每一位员工现在都处于 AI 网络安全的最前线

企业技术格局正以一种鲜有人预料到的速度发生剧变,直到为时已晚。我们已正式跨越了从人工编写代码和基础辅助编程,进入“智能体开发生命周期”(ADLC)的时代。虽然自主 AI 智能体有望在多个职能领域实现前所未有的效率,但它们也带来了全新的安全和监管风险。

了解更多

在产品发布前确保 AI 驱动的开发安全

洞察开发风险,执行安全策略,并在整个软件开发生命周期中预防漏洞。

预约演示
未找到相关项目。