Skip to content

Commit

Permalink
Add more CI checks
Browse files Browse the repository at this point in the history
As requested in #21, this verifies:

* generated rulesets files match the XML files. (In some sense it's just
a reimplementation of the `upstream/merge-rulesets.py` script, but
would
  stop a zero-length ruleset from being deployed)
* there are no extra nor missing signatures

Fixes #21.
  • Loading branch information
legoktm committed Sep 30, 2024
1 parent 4d39a13 commit 56bbd81
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ jobs:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
apt-get update && apt-get install --yes --no-install-recommends make openssl
apt-get update && apt-get install --yes --no-install-recommends make openssl python3 python3-poetry
poetry install --no-ansi
- name: Verify ruleset signature
run: |
make verify
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ serve: ## Builds Nginx container to serve generated files
verify: ## Verifies the signature of the latest ruleset. Requires openssl to be installed.
@echo "Attempting to verify ruleset signature using openssl."
@./scripts/verify
@poetry run pytest -v

.PHONY: help
help:
Expand Down
50 changes: 48 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pgpy = ">=0.6.0"

[tool.poetry.group.dev.dependencies]
black = "*"
pytest = "^8.3.3"

[tool.black]
line-length = 100
57 changes: 57 additions & 0 deletions test_rulesets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import gzip
import json
import xml.etree.ElementTree
from pathlib import Path

LATEST_TIMESTAMP = Path("latest-rulesets-timestamp").read_text().strip()


def load_xml_files():
xml_files = []
for ruleset in sorted(Path("rulesets").glob("*.xml")):
tree = xml.etree.ElementTree.parse(ruleset)
root = tree.getroot()
# Rebuild the JSON
expected = {
"name": root.attrib["name"],
"target": [root[0].attrib["host"]],
"rule": [{"from": root[1].attrib["from"], "to": root[1].attrib["to"]}],
}
xml_files.append(expected)
return xml_files


def test_compressed_matches_xml():
# Read the contents of the gzipped file
with gzip.open(f"default.rulesets.{LATEST_TIMESTAMP}.gz", "rb") as f:
rulesets = json.load(f)
xml_files = load_xml_files()

assert rulesets["rulesets"] == xml_files


def test_generated_matches_xml():
# Read the contents of the default file
rulesets = json.loads(Path("rulesets/default.rulesets").read_text())
xml_files = load_xml_files()

assert rulesets == xml_files


def test_unique_signature():
"""
For every default.rulesets.*.gz file, there should be a corresponding
rulesets-signature.*.sha256 file with no extras.
"""
rulesets = []
for path in sorted(Path(".").glob("default.rulesets.*.gz")):
rulesets.append(path.name.split(".")[2])

signatures = []
for path in sorted(Path(".").glob("rulesets-signature.*.sha256")):
signatures.append(path.name.split(".")[1])

# Just verify it found *something*
assert LATEST_TIMESTAMP in rulesets
# Now check they're equal
assert rulesets == signatures

0 comments on commit 56bbd81

Please sign in to comment.