Ask Me Anything sessions: A unique opportunity to learn more about Sigrid. Sign up now!

Changing the analysis scope configuration

You can change Sigrid’s configuration for your project, to make Sigrid’s feedback as useful and actionable as possible. We call this configuration “the scope”.

How can you customize your Sigrid configuration?

By default, Sigrid will try to automatically detect the technologies you use, the component structure, and files/directories that should be excluded from the analysis. However, you can override this standard configuration with your project-specific configuration. To do this, create a file called sigrid.yaml and add it to the root of your repository. When you merge changes to sigrid.yaml, Sigrid will pick up the new configuration and apply it to subsequent scans.

The following example shows a typical example of the sigrid.yaml configuration file:

component_depth: 1
exclude:
  - ".*/simulator/.*"
languages:
  - name: java
  - name: python
  - name: typescript

The various options and sections are explained in more detail in the remainder of this page.

When should you customize the configuration?

Whenever you need behavior that is custom for your project. Common examples are to exclude code, to include/exclude specific parts of the code or programming languages, or to resolve ambiguities.

Editing scope files

Since scope files are part of your repository, you can edit them using your preferred text editor. Sigrid scope configuration files are registered with SchemaStore.org, which means you get IDE features like content assist and error detection while you’re editing the file.

Excluding files and directories

Sigrid will exclude common patterns by default. For example, directories like build, dist, and target typically contain build output and are not part of the source code. Directories like node_modules contain open source libraries and are not part of the application’s own source code. Those directories are therefore ignored during the analysis.

It is possible to extend this list with project-specific files and directories that should also be excluded. The exclude section in the YAML file contains a list of regular expressions for paths to ignore. For example, .*[.]out[.]js will exclude all files with a name ending in .out.js from the analysis. Adding .*/simulator/.* will exclude everything in a path that contains the directory /simulator/.

Note that it is not necessary to exclude files and directories that would not be analyzed anyway.

Patterns are defined using regular expressions, as explained in the next section.

Defining include and exclude patterns

Various options across the scope configuration file allow you to define include and exclude patterns. At first glance, many people expect these patterns to behave like Glob patterns (for example *.py), but Sigrid actually uses regular expressions instead. The reason for this is fairly straightforward: regular expressions are more flexible, which is relevant considering the large number of technologies and conventions that Sigrid needs to support.

The following example specifies a component that includes all .js and .jsx files with a path that includes the frontend directory, except files ending with .spec.jsx:

components:
- name: "Our new React website"
  include:
  - ".*/frontend/.*[.]jsx?"
  exclude:
  - ".*[.]spec[.]jsx?" #excluding all `spec.js` files from this component, wherever they are; alternatively, limiting to files within a `/frontend/` directory tree, `.*/frontend/.*[.]spec[.]js`

When you specify both include and exclude patterns, the exclude patterns take precedence. In this example, the file frontend/home.jsx would be included, but the file frontend/example.spec.jsx would be excluded. This is much easier and maintainable than trying .*(?<![.]spec)[.]jsx? under include, even though that would work.

Since we know that spec.js files are meant to be test files, what you probably want in this case is to make this distinction according to its context:

components:
- name: "Our new React website"
  include:
    - ".*/frontend/.*[.]jsx?"
  exclude:
    - ".*[.]spec[.]jsx?"

As a convention, all include and exclude patterns always start with .*/. It is tempting to always define patterns relative to the root of the codebase, but it is important to realize that what is considered the “root” is flexible in Sigrid. Depending on how you map your repositories to systems, the root of your repository might not match the root of the Sigrid system that contains your repository. Starting all patterns .*/ will avoid confusion in such situations.

Other common tips and caveats when using regular expressions to define patterns

Scoping YAML indentation rules

The configuration is sensitive to indentation.

Technology support

The languages section lists all languages that you want Sigrid to analyze:

languages:
  - name: Csharp
  - name: Java
  - name: Python
  - name: Typescript

Refer to the list of supported technologies for an overview of all supported technologies and the names that can be used.

Overriding automatic technology and test code detection

When you add a technology to your scope file, Sigrid will try to locate the corresponding files based on file and directory name conventions. This includes automatic detection of test code. For example, Java-based projects typically use src/main/java for production code and src/test/java for test code.

This automatic detection is usually sufficient for the majority of projects. However, if you are using less common frameworks or a custom naming convention, you will need to tell Sigrid where it can find the test code. Like other parts of the scope file, this is done using regular expressions:

languages:
  - name: Java
    production:
    test:
      include:
        - ".*/our-smoke-tests/.*[.]java"

This example will classify all Java code in the our-smoke-tests directory as test code.

Defining components

Component detection is based on the project’s directory structure. What “components” mean depends on the technology. In Java, components are usually based on Maven modules. In C, components are often simply the project’s top-level directories.

Components can be defined in several ways, which are explained below.

Option 1: Defining components based on directory depth

The simple option is to simply base the components on directory depth. The following example will use the project’s top-level directories as components.

component_depth: 1

Option 2: Defining components based on base directories

In some projects, using directory depth will not accurately reflect the actual component structure. The more advanced options allows you to define components explicitly:

component_base_dirs:
  - "modules"
  - "modules/specific"
  - "" # This "empty string" includes the `root` directory, as it appears in the upload folder structure, as a separate component. While this is like setting `"component_depth: 1"`, in this way you are able to split only some folders into separate components (in this case, `"modules"` and `"modules/specific"`) 

Option 3: Defining components manually

In some cases the components really do not match the directory structure, and the only way to define components is by manually listing what should go where. In the example below, regular expressions are used to define what files and directories belong to each component. The syntax is identical to the patterns used in the exclude section. These include and exclude patterns work as explained in the patterns section.

components:
  - name: "Back-end"
    include:
      - ".*[.]java"
  - name: "Log"
    include:
      - ".*/cs/findbugs/log/.*"

In general you should try to avoid defining components in this way: not because it is not possible, but because it is hard to maintain. This might work perfectly well for your system’s current codebase, but what is going to happen when someone moves a file or adds a directory? This type of component configuration will require constant maintenance.

Note regarding test code mapping per component: In case that test code resides in the same directory tree as the base directories (i.e. deeper in the tree than production code) and they are correctly identified as test code (either by default detection or manually under languages:), test code will be mapped correctly to its corresponding component. Either way this implies a test code naming convention that is applied consistently. Which you would expect anyway. Note that on a higher level, the production: and test: filtering will split any code that ends up in scope between production and test. For this reason, you do not need to, and cannot, define production and test code within a component.

For example, imagine that you have defined components manually and test code follows a pattern where the component name is suffixed with -Test or -Tests as the last word in the folder name, a pattern could be configured like so:

components:
  - name: "Back-end"
    include:
      # Instead of defining production code with a cut-off directory of .*/backend/specific-component/.*[.]java,
      # you could include test code in this way, if the naming convention is indeed followed consistently and
      # an example directory would be /backend/specific-component-integration-tests/. 
      - ".*/backend/specific-component[^/]*-[Tt]ests?/.*[.]java" 

Resolving pattern match ambiguities that may stall analysis

An analysis may fail if pattern matches are ambiguous. Examples:

Configuring the SIG Maintainability Model version

By default, your configuration will use the latest version of the SIG Maintainability Model, which is based on the ISO 25010 standard for software product quality.

You can customize this by adding a model entry to your configuration. For example, adding model: "2020" will analyze your system using the 2020 of the SIG Maintainability Model. You can use this option to ensure your system is analyzed using a specific version of the model. However, in most cases you’ll want to use the latest version, as the SIG Maintainability Model is recalibrated on a yearly basis to reflect industry best practices.

Open Source Health

Note: This requires a Sigrid license for Open Source Health. Without this license, you will not be able to see security results in Sigrid.

Open Source Health allows you to scan all open sources libraries used by your system, and identify risks such as security vulnerabilities or heavily outdated libraries.

dependencychecker:
  blocklist:
  - ".*companyname.*"
  transitive: false
  exclude:
    - ".*/scripts/.*"

The dependencychecker section supports the following options:

Option name Required? Description
blocklist Yes List of library names that should not be scanned. Typically used to ignore internal libraries.
transitive No When true, also scans the dependencies of your dependencies. Defaults to false.
exclude No List of file/directory patterns that should be excluded from the Open Source Health analysis.
model No SIG Open Source Health model version that should be used for the analysis, defaults to latest.

Please Note: dependency exclusions may be necessary in case your system resolves internal dependencies that could expose organization- or system name based on their internal URI. Therefore, as part of the onboarding process, please inform SIG of any such naming conventions that should be filtered. See also this question in the FAQ on dependency filtering.

Security

Note: This requires a Sigrid license for Software Security. Without this license, you will not be able to see security results in Sigrid.

Third Party Findings

Sigrid uses a combination of its own security checks and security checks performed by third party tools. It then combines the results, benchmarks them, and reports on the overall results. As an example, the following configuration options are available to include or exclude certain code and/or security analyzers:

thirdpartyfindings:
  enabled: true
  exclude:
    - ".*/scripts/.*[.]sh"
  disabled_analyzers:
    - "Google ErrorProne"
    - "SemGrep"
  enabled_analyzers:
    - "VMWare CSA"

This thirdpartyfindings section in the scope file supports the following options:

Option name Required? Description
enabled Yes Set to true to enable security analysis.
exclude No List of file/directory patterns that should be excluded from the security analysis.
disabled_analyzers [1] No Defining a list of disabled specific scanning tools.
enabled_analyzers [1] No Defining a list of specific scanning tools to enable (if not enabled by default).
  1. You can see the list of enabled analyzers in your Sigrid security overview, if you group by finding and then by origin. For the list of all supported analyzers, see the technology support section.

Architecture Quality

Architecture Quality is available by default. However, you can still use the various scope file options to customize your analysis. The options related to architecture live in the architecture section in the scope file.

architecture:
  # options go here

The architecture section of the scope file supports the following options:

Option Required Description
model No SIG Architecture Quality Model that should be used for the analysis, defaults to latest.
exclude No See Excluding files and directories for Architecture Quality.
custom_components No See Components in Maintainability versus components in Architecture Quality.
add_dependencies No See Manually specifying architecture dependencies.
remove_dependencies No See Manually specifying architecture dependencies.
undesirable_dependencies No See Highlighting undesirable dependencies.
add_system_elements No See Manually specifying architecture elements.
grouping No See Grouping and annotating components in Architecture Quality.
history_period_months No See Analyzing your repository history.
history_start No See Analyzing your repository history.
history_end No See Analyzing your repository history.

Components in Maintainability versus components in Architecture Quality

Sigrid combines different capabilities, and those different capabilities might necessitate their own view on your system. In Sigrid’s Maintainability pages, you get a simple breakdown into one level of components. Because you only get a single level, you need to define these components manually as explained in the defining components section.

Out of the box, Sigrid’s Architecture Quality provides a different componentization, which allows for more detail: components can have sub-components, those can also have sub-components, and so on. Having multiple levels of sub-components is necessary to make Architecture Quality useful. In many cases, there is general consensus on the top-level architecture. It’s the internal architecture within sub-components where things get interesting. Generally, those internal architectures are the responsibility of a team, and therefore less known to people outside of the team (and in many cases it’s even not fully transparent to the team itself). Moreover, incrementally improving the top-level architecture is very hard. Focusing on architecture improvement/modernization is easier when starting with a component’s internal architecture, as there are less people involved and it’s therefore more realistic to realize improvements within a sprint.

The fact that Architecture Quality relies on these sub-components also explains the second difference with the components you see in the maintainability page: For Architecture Quality, components and sub-components are detected automatically. This is required to make them useful and practical: defining components manually just isn’t practical if your system has 50 microservices, each with their own internal architecture. Configuring such a system manually would be a huge amount of work. And you would need to update the configuration every time you add a microservice or change its internal architecture!

The obvious downside of this approach is that it leads to different views in Sigrid’s Maintainability and Architecture Quality pages. However, having multiple architecture views is fairly mainstream, hence we adopted this approach by Sigrid.

However, if it is essential for you to have the same componentization for both Maintainability and Architecture Quality, or if you really want to define your Architecture Quality view manually, it is possible to override the standard behavior in the configuration:

architecture:
  custom_components: true

This will disable the automatic component detection for Architecture Quality, and will instead use the components you defined manually.

Analyzing your repository history

Architecture Quality analyzes both your source code and the repository history. See the frequently asked questions for architecture quality for more information on how the repository history is analyzed.

When you publish your repository history to Sigrid, it is automatically picked up by the Architecture Quality analysis without needing further configuration. By default, Sigrid will analyze the repository history for the last year. If you want to change this to a different period, you can manually specify the time period that should be analyzed:

architecture:
  history_period_months: 6

This example will change the default period of 12 months, and instead analyze only analyze the last 6 months of history. If you want to go even further, it is also possible to define an exact start date:

architecture:
  history_start: "2023-01-01"

Manually specifying architecture dependencies

Although Sigrid supports hundreds of technologies, there is always the possibility that Sigrid doesn’t automatically detect the dependencies for your particular framework. It is therefore possible to manually define additional dependencies, which will be added on top of the automatic dependency detection:

architecture:
  add_dependencies:
    - source: backend
      target: frontend
      type: code_call

The names for the source and target fields are the same you see in Sigrid’s user interface. The type field indicates the type of dependency that should be added, for example a code call versus an interface call. The list of supported dependency types can be found in the Architecture Quality documentation.

You can use the same mechanism to remove false positives from the automatic dependency detection:

architecture:
  remove_dependencies:
    - source: frontend
      target: backend

Excluding files and directories for Architecture Quality

The architecture section in the configuration has its own exclude option, which can be used to exclude certain files and directories from the Architecture Quality analysis.

architecture:
  exclude:
    - ".*/index[.]ts"

The list of exclude patterns works in the same way as the global, top-level exclude option. The difference is the global option excludes files and directories from all Sigrid capabilities, and the architecture exclude option excludes them from Architecture Quality but not from other Sigrid capabilities. See the pattern section for more information on writing these patterns.

Highlighting undesirable dependencies

Architecture Quality allows you to mark certain dependencies as undesirable. You can configure which dependencies should be considered undesirable:

architecture:
  undesirable_dependencies:
    - source: "backend"
      target: "legacy"

This example will mark all dependencies from the “backend” component to the “legacy” component as “undesirable”. You can also use additional options to be more specific about which type of dependencies are undesirable:

architecture:
  undesirable_dependencies:
    - source: "backend"
      target: "legacy"
      bidirectional: true
      type: code_call

Adding bidirectional: true means the dependencies are undesirable in both directions. This is basically a shorthand notation so that you do not have to configure both A -> B and B -> A separately. The type option can be used to only consider certain types of dependencies. In the example, since one type has been defined, code dependencies are undesirable but other types (such as interface dependencies) are still allowed. The list of supported dependency types can be found in the Architecture Quality documentation.

Manually specifying architecture elements

The term “system element” is used for all information that is depicted as “blocks” in the Architecture Quality view. Common examples are components, files, or databases. Normally, this detection of system elements is based on Sigrid’s code analysis. However, it is possible to extend the list of system elements in the configuration. This is intended for situations where the architecture view would become considerably more clear by adding some context, but this context cannot be detected automatically.

add_system_elements:
  - name: accounts
    type: code_components

The following example adds a component called “accounts” to the architecture view. Refer to the Architecture Quality documentation for an overview of all supported sytem element types.

Grouping and annotating components in Architecture Quality

You can define architecture groups and annotations, and these annotations are then displayed on top of the architecture visualization. As with the other customization options, this is done in the configuration:

architecture:
  grouping:
    - name: "Title of my architecture group"
      include:
        - some_component
        - other_component
      annotation: "Slightly longer text that adds more context beyond just the name."

The contents of the include option refer to the component names you see in Architecture Quality. You can either use the exact component names, or you can use regular expressions. For example, using target: backend.* will match all components that have a name starting with “backend”. Note you are matching the component name, not the files within the component.

Configuring multi-repo systems

Sigrid allows you to create “multi-repo systems” that are the combination of multiple repositories in your development environment. In this situation, each individual repository within the system is referred to as a “subsystem”. Such a view is more high-level than looking at individual repositories, and is sometimes a better fit if you want to align on Sigrid findings with stakeholders from outside the development organization.

Since multi-repo systems are used to create a shared view, they also require shared objectives and a shared configuration. The latter creates an obvious problem: if the configuration file is normally located in the root of the repository, how does that work when there are multiple repositories?

In such a situation, you can use Sigrid CI to manage the shared configuration:

Sigrid metadata

sigrid.yaml is used for analysis configuration. It is also possible to configure Sigrid metadata. See the Sigrid metadata section for the various ways you can update this metadata.

Contact and support

Feel free to contact SIG’s support department for any questions or issues you may have after reading this document, or when using Sigrid or Sigrid CI. Users in Europe can also contact us by phone at +31 20 314 0953.