Skip to content

Commit

Permalink
Merge pull request #1 from coreruleset/refactor/add-tests
Browse files Browse the repository at this point in the history
refactor: add tests as pytests
  • Loading branch information
fzipi authored Jan 13, 2025
2 parents 2dc8491 + 8ba6d76 commit ff3db38
Show file tree
Hide file tree
Showing 12 changed files with 653 additions and 448 deletions.
51 changes: 51 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
name: "CodeQL"

on:
push:
branches: [ "master" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
schedule:
- cron: '18 7 * * 5'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support

steps:
- name: Checkout repository
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.

# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
23 changes: 23 additions & 0 deletions .github/workflows/pypi-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Publish to PyPI
on:
release:
types: [published]
workflow_dispatch:
inputs:
publish:
description: "Publish to pypi.org? (will not work from forks!)"
required: false
default: 'false'

jobs:
test:
name: Test Release
runs-on: ubuntu-latest
steps:
- name: Publish to pypi
uses: coveooss/[email protected]
with:
project-name: secrules-parsing
pypi-token: ${{ secrets.PYPI_TOKEN }}
pre-release: ${{ github.ref != 'refs/heads/master' }}
dry-run: ${{ github.ref != 'refs/heads/master' && github.event.inputs.publish != 'true' }}
42 changes: 42 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
name: Regression Tests

on: [push, pull_request]

jobs:
regression:
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
crs-version: ['4.10.0']
python-version: ['3.9', '3.10', '3.11', '3.12']

steps:
- name: "Checkout repo"
uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-glob: "uv.lock"

- name: Set up Python 3
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
uv sync --all-extras --dev
- name: "Run unit tests"
run: |
uv run pytest -vs
- name: "Run crs linter tests for ${{ matrix.crs-version }}"
run: |
curl -SLs https://github.com/coreruleset/coreruleset/archive/refs/tags/v${{ matrix.crs-version }}.tar.gz -o - | \
tar xzvf - --strip-components=1 --wildcards "*/rules/*" --wildcards "*/crs-setup.conf.example" --wildcards "*/util/APPROVED_TAGS"
uv run crs-linter --output=github -r crs-setup.conf.example -r rules/*.conf -t util/APPROVED_TAGS -v ${{ matrix.crs-version }}
46 changes: 19 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
crs_rules_check
===============
# CRS Linter

Welcome to the `crs_rules_check` documentation.
Welcome to the CRS Linter documentation.

Prerequisites
=============
## Prerequisites

To run the tool, you need:

+ a **Python 3** interpreter
+ **msc_pyparser** - a SecRule parser (>=1.2.1)

`msc_pyparser` was written in Python 3 and has not been tested with Python 2, therefore you have to use Python 3.
To run this tool, you need Python 3.7 or later.

The best way to install the required packages just run

```
pip3 install -r requirements.txt
pip3 install
```

How does it work
================
## How does it work

The script expects an argument at least - this would be a single file or a file list, eg: `/path/to/coreruleset/*.conf`.

Expand Down Expand Up @@ -71,13 +63,13 @@ If everything is fine, rule returns with 0.
Normally, you should run the script:

```
./util/crs-rules-check/rules-check.py -r crs-setup.conf.example -r rules/*.conf
crs-linter -r crs-setup.conf.example -r rules/*.conf
```

Optionally, you can add the option `--output=github` (default value is `native`):

```
./util/crs-rules-check/rules-check.py --output=github -r crs-setup.conf.example -r rules/*.conf
crs-linter --output=github -r crs-setup.conf.example -r rules/*.conf
```

In this case, each line will have a prefix, which could be `::debug` or `::error`. See [this](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message).
Expand Down Expand Up @@ -107,7 +99,7 @@ As you can see, there are two `"` missing above: the first one after the `chain`
Check it:

```
$ ./rules-check.py -r examples/test1.conf
crs-linter -r examples/test1.conf
Config file: examples/test1.conf
Can't parse config file: examples/test1.conf
file=examples/test1.conf, line=8, endLine=8, title=Parser error: can't parse file
Expand All @@ -129,7 +121,7 @@ SecRule REQUEST_URI "@beginswith /index.php" \
In this rule the operator is lowercase. Mod_security allows both form.

```
$ ./rules-check.py -r examples/test2.conf
crs-linter -r examples/test2.conf
Config file: examples/test2.conf
Parsing ok.
Ignore case check found error(s)
Expand All @@ -154,7 +146,7 @@ SecRule REQUEST_URI "@beginsWith /index.php" \
In this rule, the `phase` and `id` are interchanged. As [documentation](https://github.com/coreruleset/coreruleset/wiki/Order-of-ModSecurity-Actions-in-CRS-rules) says, the first action **must** be the `id`, the second one is the `phase`.

```
$ ./rules-check.py -r examples/test3.conf
crs-linter -r examples/test3.conf
Config file: examples/test3.conf
Parsing ok.
Ignore case check ok.
Expand Down Expand Up @@ -190,7 +182,7 @@ SecRule ARGS "@rx foo" \
In this rule set, the first line and the rule with `id:3` first action have an extra leading space. As [documentation](https://github.com/coreruleset/coreruleset/blob/v3.4/dev/CONTRIBUTING.md#general-formatting-guidelines-for-rules-contributions) describes, CRS has a strict indentation rules. The script checks the indentation with help of Python's [difflib](https://docs.python.org/3.9/library/difflib.html).

```
$ ./rules-check.py -r examples/test4.conf
crs-linter -r examples/test4.conf
Config file: examples/test4.conf
Parsing ok.
Ignore case check ok.
Expand Down Expand Up @@ -233,7 +225,7 @@ SecRule REQUEST_URI "index.php" \
In this rule, the operator is missing. As [ModSecurity documentation](https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#rx) says "the rules that do not explicitly specify an operator default to @rx". In CRS, this isn't allowed.

```
$ ./rules-check.py -r examples/test5.conf
$ crs-linter -r examples/test5.conf
Config file: examples/test5.conf
Parsing ok.
Ignore case check found error(s)
Expand Down Expand Up @@ -294,7 +286,7 @@ SecRule ARGS_NAMES "@rx bar" \
In this rule file, there are two rules with same `id`.

```
$ util/crs-rules-check/rules-check.py -r util/crs-rules-check/examples/test7.conf
crs-linter -r util/crs-rules-check/examples/test7.conf
Config file: util/crs-rules-check/examples/test7.conf
Parsing ok.
Checking parsed rules...
Expand Down Expand Up @@ -380,7 +372,7 @@ In this rule file, there are more problems:
* rule 920162 increments anomaly_score_pl2, but it's in PL1

```
$ ./rules-check.py -r examples/test8.conf
crs-linter -r examples/test8.conf
Config file: examples/test8.conf
Parsing ok.
Checking parsed rules...
Expand Down Expand Up @@ -442,7 +434,7 @@ SecRule ARGS "@rx (?i)foo" \
Rule 1 uses a combination of t:lowercase and the (?i) in the regex

```
./rules-check.py -r examples/test10.conf
crs-linter -r examples/test10.conf
Config file: examples/test10.conf
Parsing ok.
Checking parsed rules...
Expand Down Expand Up @@ -480,7 +472,7 @@ SecRule REQUEST_URI "@rx index.php" \
Rule 1 does not have `tag:OWASP_CRS`

```
$ ./rules-check.py -r examples/test11.conf -t ../APPROVED_TAGS
crs-linter -r examples/test11.conf -t ../APPROVED_TAGS
Config file: examples/test11.conf
Parsing ok.
Checking parsed rules...
Expand Down Expand Up @@ -532,7 +524,7 @@ Rule 1 does not have `ver`.
Rule 2 has incorrect `ver` value.

```
$ ./rules-check.py -r examples/test12.conf -t ../APPROVED_TAGS
crs-linter -r examples/test12.conf -t ../APPROVED_TAGS
Config file: examples/test12.conf
Parsing ok.
Checking parsed rules...
Expand Down Expand Up @@ -601,7 +593,7 @@ Rule 2 is the valid form.
Rule 3 is a chained rule and it uses `TX:0` in second rule, but first rule does not have `capture`.

```
$ ./rules-check.py -r examples/test13.conf -t ../APPROVED_TAGS -v "4.7.0-dev"
crs-linter -r examples/test13.conf -t ../APPROVED_TAGS -v "4.7.0-dev"
Config file: examples/test13.conf
Parsing ok.
Checking parsed rules...
Expand Down
46 changes: 46 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[project]
name = "crs-linter"
version = "0.1.0"
description = "CRS linter"
authors = [
{name = "Ervin Hegedus", email = "[email protected]"}
]
requires-python = ">=3.9"
license = "Apache-2.0"
readme = "README.md"
Issues = "https://github.com/coreruleset/crs-linter/issues"
Homepage = "https://github.com/coreruleset/crs-linter"
Repository = "https://github.com/coreruleset/crs-linter.git"

keywords = ["OWASP", "CRS", "linter"]

classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
]

packages = [
{ include = "crs_linter", from = "src" }
]

# Requirements
dependencies = [
"msc_pyparser >=1.2.1"
]

[project.scripts]
crs-linter = 'crs_linter.cli:main'

[dependency-groups]
dev = [
"pytest >=8.1.1,<9"
]

[tool.semantic_release]
version_variable = "pyproject.toml:version"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

1 change: 0 additions & 1 deletion requirements.txt

This file was deleted.

Empty file added src/crs_linter/__init__.py
Empty file.
Loading

0 comments on commit ff3db38

Please sign in to comment.