Skip to content
4 changes: 4 additions & 0 deletions .asist.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,20 @@ dontforceignore: false
cicdrules:
- "XSSLabel"
- "XSSMergeField"
- "XSSTooltip"

# `ruleoverrides` property is used to override some properties of standard rules. The following are defined below:
# severity: Low|Medium|High|Critical
# includepattern: specify files or folders to be included from scans.
# excludepattern: specify files or folders to be excluded from scans.
# `enabled` property is used to enable/disable a particular rule. It will override `enableAllStandardRules` property.
# `cicdmaxissues` property sets maximum allowed issue count (default is 0 if not specified - no issues allowed).
# This is useful when introducing ASIST to a codebase with existing issues - you can gradually reduce cicdmaxissues.
ruleoverrides:
XSSTooltip: # Rule Id to be overriden
severity: Medium
enabled: true
cicdmaxissues: 50 # Allow up to 50 XSSTooltip issues (grandfathered existing issues)
XSSLabel:
includepattern: "\\.page$|\\.component$"
enabled: true
Expand Down
102 changes: 61 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
</div>

# ASIST (Automated Security Issue Scanning Tool)

[![Go Reference](https://pkg.go.dev/badge/github.com/certinia/asist.svg)](https://pkg.go.dev/github.com/certinia/asist)
[![License: BSD-3-Clause](https://img.shields.io/badge/license-BSD--3--Clause-blue)](https://opensource.org/license/bsd-3-clause)

ASIST is a regex-based, blazing-fast Static Application Security Testing (SAST) tool for securing Salesforce apps at developer speed.
ASIST is a regex-based, blazing-fast Static Application Security Testing (SAST) tool for securing Salesforce apps at developer speed.

Originally built for internal use at Certinia to support Security Reviews, we have now decided to release it to the community 🌍

Expand All @@ -25,7 +26,7 @@ Originally built for internal use at Certinia to support Security Reviews, we ha

## ▶️ VSCode extension demo

![ASIST scan via Extension](images/scan-using-extension.gif)
![ASIST scan via Extension](images/scan-using-extension.gif)

## ▶️ CLI demo

Expand Down Expand Up @@ -59,7 +60,6 @@ Alternatively:
- To just build the binary for your OS and architecture: `make`
- To cross-compile: `GOOS=windows GOARCH=amd64 go build -o asist.exe .`
- To build binaries for the most common platforms, run: `make build-binaries`


## 🕹️ Usage

Expand Down Expand Up @@ -201,12 +201,12 @@ Configuration files can also be explicitly specified using the `-c` argument (no

Within the config file, you can:

* Enable/disable all the standard rules
* Override certain properties of standard rules
* Exclude files or directories for all rules
* Exclude files or directories for specific rules
* Add custom regex rules
* Define rules to be run in CI/CD mode
- Enable/disable all the standard rules
- Override certain properties of standard rules
- Exclude files or directories for all rules
- Exclude files or directories for specific rules
- Add custom regex rules
- Define rules to be run in CI/CD mode

See our [example config file](.asist.example.yaml) for a walkthrough of all config options.

Expand All @@ -215,6 +215,7 @@ See our [example config file](.asist.example.yaml) for a walkthrough of all conf
Users can override certain properties of standard rules according to their needs, allowing them to customize the behavior of specific rules by:

- Disabling rules entirely: `enabled`
- Limiting the number of allowed rule violations: [`cicdmaxissues`](#rule-max-issues)
- Tweaking rule severity: `severity`
- Tweaking what files should be scanned: `includepattern`
- Tweaking what files should not be scanned: `excludepattern`
Expand All @@ -238,7 +239,6 @@ customregexrules:

You can test this specific rule like this:


```shell
asist -c .asist.yaml -r doNotDebug <file>
```
Expand Down Expand Up @@ -290,13 +290,35 @@ In this mode, by default, all enabled runs will be run if `cicdrules` property i

```yaml
cicdrules:
- "XSSDomHtml"
- "XSSLabel"
- "XSSMergeField"
```

This allows developers to add a subset of the overall ruleset to ASIST to their CI/CD pipelines, and gradually add more rules to CI/CD as they start clearing out findings for other rules. This prevents any issues for rules defined in `cicdrules` from creeping back into the codebase.

### 📊 Baseline scans
## Rule Max Issues

When introducing ASIST to an existing codebase, you may have pre-existing security issues that you want to prevent from increasing while you work on fixing them. The `cicdmaxissues` property in [`ruleoverrides`](#-customizing-standard-rules) allows you to set maximum allowed issue counts for specific rules for CI/CD mode (with option -j ) scanning only.

**By default, rules have a limit of 0 issues.** When a rule exceeds its `cicdmaxissues` threshold, ASIST will exit with an error code (see [Exit Codes](#-exit-codes)). You only need to set `cicdmaxissues` if you want to allow existing issues while preventing them from growing.

```yaml
ruleoverrides:
XSSLabel:
cicdmaxissues: 150 # Allow up to 150 XSSTooltip issues (grandfather existing issues)
XSSMergeField:
cicdmaxissues: 0 # Explicitly set to 0 (same as default - no issues allowed)
# XSSDomHtml has no cicdmaxissues set, defaults to 0 (no issues allowed)
```

This feature allows you to:

- Gradually introduce stricter security requirements by lowering cicdmaxissues over time
- Prevent technical debt from growing while you address existing issues
- Start enforcing security on a codebase with 150 existing issues, then reduce to 100, 50, and eventually 0

## 📊 Baseline scans

This mode is intended for SecOps teams to create benchmarks across multiple projects and measure the adoption of ASIST.

Expand All @@ -314,32 +336,32 @@ This command will output a JSON like this (when formatted):

```json
[
{
"RepositoryName": "certinia/asist",
"RepositoryURL": "git@github.com:certinia/asist.git",
"RecordType": "Finding",
"Content": {
"FindingID": "b17fe249915712219aca7e",
"IsCustom": false,
"IsFalsePositive": true,
"RuleID": "LwcNonStandardPositioning",
"Severity": "Medium",
"RuleCategory": "Security"
}
},
{
"RepositoryName": "certinia/asist",
"RepositoryURL": "git@github.com:certinia/asist.git",
"RecordType": "Finding",
"Content": {
"FindingID": "3a2861bee641864816b86d",
"IsCustom": false,
"IsFalsePositive": true,
"RuleID": "LwcNonStandardPositioning",
"Severity": "Medium",
"RuleCategory": "Security"
}
}
{
"RepositoryName": "certinia/asist",
"RepositoryURL": "git@github.com:certinia/asist.git",
"RecordType": "Finding",
"Content": {
"FindingID": "b17fe249915712219aca7e",
"IsCustom": false,
"IsFalsePositive": true,
"RuleID": "LwcNonStandardPositioning",
"Severity": "Medium",
"RuleCategory": "Security"
}
},
{
"RepositoryName": "certinia/asist",
"RepositoryURL": "git@github.com:certinia/asist.git",
"RecordType": "Finding",
"Content": {
"FindingID": "3a2861bee641864816b86d",
"IsCustom": false,
"IsFalsePositive": true,
"RuleID": "LwcNonStandardPositioning",
"Severity": "Medium",
"RuleCategory": "Security"
}
}
]
```

Expand All @@ -350,8 +372,7 @@ A few differences can be observed compared to regular scans:
- Each issue is assigned a `FindingID`, which is effectively a hash that uniquely identifies the finding based on the rule, the finding location, and if it's a false positive or not.
- A few more properties are added, such as if the rule is custom, or if the finding is marked as false positive or not.


### 🫣 .gitignore and .forceignore files
## 🫣 .gitignore and .forceignore files

By default, ASIST will ignore files and folders defined inside .gitignore and .forceignore. If you don't want ASIST to respect .gitignore and .forceignore, you can use the following properties in the config file:

Expand All @@ -367,7 +388,6 @@ By default, ASIST will ignore files and folders defined inside .gitignore and .f
| 3 | ASIST failed due to internal error (file a bug report!) |
| 4 | ASIST failed due to user error (review input and config) |


## 🏗️ [CONTRIBUTING](CONTRIBUTING.md)

## 🎫 [LICENSE](LICENSE.txt)
Expand Down Expand Up @@ -465,4 +485,4 @@ A big thank you to everyone who has contributed to ASIST!
</a>
</td>
</tr>
</table>
</table>
5 changes: 5 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## \[Unreleased\]

### Added

* Added property to `cicdmaxissues` in `ruleoverrides` config, allowing a maximum number of issues to be permitted per rule in CI/CD mode. This enables gradual remediation of existing issues by setting a threshold that can be reduced over time. Exceeding the threshold exits with a non-zero code and prints a violation summary to stderr.
* When running `--list-rules`, each rule now displays its `CicdMaxIssues` value. Rules without a `cicdmaxissues` override show a default value of `0`.

### Fixed

* Enhanced the regex to be case-insensitive and to support `.` in repository names, enabling correct extraction of the repository name from SSH URLs in baseline scan.
Expand Down
26 changes: 22 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func ParseConfig(path string) (*Config, error) {
}

/**
* GetConfigFilePath - Returns the file path of the config file (JSON or YAML) if it exists, otherwise an empty string.
* GetConfigFilePath - Returns the file path of the config file (JSON or YAML) if it exists, otherwise an empty string.
*/
func GetConfigFilePath(rootPath string, configFilePath string, isBaselineEnabled bool) (string, error) {
if configFilePath != "" || !isBaselineEnabled {
Expand All @@ -88,7 +88,7 @@ func GetConfigFilePath(rootPath string, configFilePath string, isBaselineEnabled
}

/**
* FilterExcludedFilesAndFolders - Filter out the paths from the provided list that are present in the ExcludeFilesAndFolders property of config file.
* FilterExcludedFilesAndFolders - Filter out the paths from the provided list that are present in the ExcludeFilesAndFolders property of config file.
*/
func (c *Config) FilterExcludedFilesAndFolders(paths []string) []string {
var filteredPaths []string
Expand Down Expand Up @@ -130,8 +130,26 @@ func (c *Config) GetCICDRuleIds() []rules.RuleID {
}

/**
* GetEnabledOverridedStandardRuleIds - Return the standard rule Ids
* Where RuleOveride property is defined and override rules enabled property is set to true or nil
* Returns ruleoverrides.<rule>.cicdmaxissues if set, otherwise 0.
*/
func (c *Config) GetRuleCicdMaxIssues(ruleId rules.RuleID) int {
if c == nil || c.RuleOverrides == nil {
return 0
}

// Check if cicdmaxissues is explicitly set in ruleoverrides
if override, exists := c.RuleOverrides[string(ruleId)]; exists {
if override.CicdMaxIssues != nil {
return *override.CicdMaxIssues
}
}

return 0
}

/**
* GetEnabledOverridedStandardRuleIds - Return the standard rule Ids
* Where RuleOveride property is defined and override rules enabled property is set to true or nil
*/
func (c *Config) GetEnabledOverridedStandardRuleIds(standarRuleIds []rules.RuleID) []rules.RuleID {
enabledRuleIds := []rules.RuleID{}
Expand Down
Loading
Loading