Skip to content

Commit aba3126

Browse files
authored
Merge pull request #5 from OPPIDA/fix/ci-docs
2 parents fc1b601 + 81ac1b8 commit aba3126

15 files changed

Lines changed: 159 additions & 67 deletions

File tree

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Run tests on Pull Request
1+
name: ci
22

33
on:
44
pull_request:
@@ -15,5 +15,14 @@ jobs:
1515
- name: Checkout code
1616
uses: actions/checkout@v3
1717

18+
- name: Install uv
19+
uses: astral-sh/setup-uv@v6
20+
21+
- name: Setup project
22+
run: uv sync --locked --all-extras
23+
24+
- name: Run check
25+
run: uv run ruff check && uv run ty check
26+
1827
- name: Run tests
1928
run: make test
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
name: Publish docs to GitHub Pages
1+
name: docs
22
on:
33
push:
44
branches:
55
- main
66
permissions:
77
contents: write
88
jobs:
9-
deploy:
9+
docs:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- uses: actions/checkout@v4

Makefile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@ check: ## Lint, format, and type-check the code
1414

1515
test: ## Run tests in a Docker container
1616
@docker compose build 1>/dev/null
17-
@docker compose run --rm test
17+
@docker compose run --rm no-sast
18+
@docker compose run --rm with-sast
1819

1920
test-force: ## Run tests in a Docker container while ignoring any stored state
2021
@docker volume rm codesectools_pytest-cache 2>&1 1>/dev/null || true
2122
@docker compose build 1>/dev/null
22-
@docker compose run --rm test
23+
@docker compose run --rm no-sast
24+
@docker compose run --rm with-sast
2325

2426
test-debug: ## Spawn an interactive shell in the test container to debug
2527
@docker compose build
2628
@docker compose run --rm test /bin/bash
2729

28-
doc-serve: ## Serve the documentation locally
30+
docs-serve: ## Serve the documentation locally
2931
@mkdocs serve

codesectools/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def get_downloadable() -> dict[str, DownloadableRequirement | Dataset]:
135135
sast = sast_data["sast"]
136136
for req in sast.requirements.all:
137137
if isinstance(req, DownloadableRequirement):
138-
if not req.is_fulfilled():
138+
if not req.is_fulfilled() and req.dependencies_fulfilled():
139139
downloadable[req.name] = req
140140

141141
for dataset_name, dataset in DATASETS_ALL.items():

codesectools/sasts/core/cli.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ def install() -> None:
114114
install_help += (
115115
f"{'❌' if req in missing_reqs else '✅'} [b]{req}[/b]\n"
116116
)
117-
if req.instruction:
117+
if req.depends_on:
118+
install_help += f"- Depends on: [red]{', '.join([str(r) for r in req.depends_on])}[/red]\n"
119+
elif req.instruction:
118120
install_help += f"- Instruction: [red]{req.instruction}[/red]\n"
119121
if req.url:
120122
install_help += f"- URL: [u]{req.url}[/u]\n"

codesectools/sasts/core/sast/requirements.py

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import shutil
44
from abc import ABC, abstractmethod
55
from pathlib import Path
6-
from typing import Any, Literal
6+
from typing import Any, Literal, Self
77

88
import requests
99
import typer
@@ -21,6 +21,7 @@ class SASTRequirement(ABC):
2121
def __init__(
2222
self,
2323
name: str,
24+
depends_on: list[Self] | None = None,
2425
instruction: str | None = None,
2526
url: str | None = None,
2627
doc: bool = False,
@@ -29,12 +30,14 @@ def __init__(
2930
3031
Args:
3132
name: The name of the requirement.
33+
depends_on: A list of other requirements that must be fulfilled first.
3234
instruction: A short instruction on how to download the requirement.
3335
url: A URL for more detailed instructions.
34-
doc: A flag indicating if the instruction is available in the documentaton.
36+
doc: A flag indicating if the instruction is available in the documentation.
3537
3638
"""
3739
self.name = name
40+
self.depends_on = depends_on
3841
self.instruction = instruction
3942
self.url = url
4043
self.doc = doc
@@ -44,6 +47,12 @@ def is_fulfilled(self, **kwargs: Any) -> bool:
4447
"""Check if the requirement is met."""
4548
pass
4649

50+
def dependencies_fulfilled(self) -> bool:
51+
"""Check if all dependencies for this requirement are fulfilled."""
52+
if not self.depends_on:
53+
return True
54+
return all(dependency.is_fulfilled() for dependency in self.depends_on)
55+
4756
def __repr__(self) -> str:
4857
"""Return a developer-friendly string representation of the requirement."""
4958
return f"{self.__class__.__name__}({self.name})"
@@ -55,6 +64,7 @@ class DownloadableRequirement(SASTRequirement):
5564
def __init__(
5665
self,
5766
name: str,
67+
depends_on: list[SASTRequirement] | None = None,
5868
instruction: str | None = None,
5969
url: str | None = None,
6070
doc: bool = False,
@@ -65,13 +75,16 @@ def __init__(
6575
6676
Args:
6777
name: The name of the requirement.
78+
depends_on: A list of other requirements that must be fulfilled first.
6879
instruction: A short instruction on how to download the requirement.
6980
url: A URL for more detailed instructions.
70-
doc: A flag indicating if the instruction is available in the documentaton.
81+
doc: A flag indicating if the instruction is available in the documentation.
7182
7283
"""
7384
instruction = f"cstools download {name}"
74-
super().__init__(name, instruction, url, doc)
85+
super().__init__(
86+
name=name, depends_on=depends_on, instruction=instruction, url=url, doc=doc
87+
)
7588

7689
@abstractmethod
7790
def download(self, **kwargs: Any) -> None:
@@ -85,6 +98,7 @@ class Config(SASTRequirement):
8598
def __init__(
8699
self,
87100
name: str,
101+
depends_on: list[SASTRequirement] | None = None,
88102
instruction: str | None = None,
89103
url: str | None = None,
90104
doc: bool = False,
@@ -93,12 +107,15 @@ def __init__(
93107
94108
Args:
95109
name: The name of the requirement.
110+
depends_on: A list of other requirements that must be fulfilled first.
96111
instruction: A short instruction on how to download the requirement.
97112
url: A URL for more detailed instructions.
98-
doc: A flag indicating if the instruction is available in the documentaton.
113+
doc: A flag indicating if the instruction is available in the documentation.
99114
100115
"""
101-
super().__init__(name, instruction, url, doc)
116+
super().__init__(
117+
name=name, depends_on=depends_on, instruction=instruction, url=url, doc=doc
118+
)
102119

103120
def is_fulfilled(self, sast_name: str, **kwargs: Any) -> bool:
104121
"""Check if the configuration file exists for the given SAST tool."""
@@ -111,6 +128,7 @@ class Binary(SASTRequirement):
111128
def __init__(
112129
self,
113130
name: str,
131+
depends_on: list[SASTRequirement] | None = None,
114132
instruction: str | None = None,
115133
url: str | None = None,
116134
doc: bool = False,
@@ -119,12 +137,15 @@ def __init__(
119137
120138
Args:
121139
name: The name of the requirement.
140+
depends_on: A list of other requirements that must be fulfilled first.
122141
instruction: A short instruction on how to download the requirement.
123142
url: A URL for more detailed instructions.
124-
doc: A flag indicating if the instruction is available in the documentaton.
143+
doc: A flag indicating if the instruction is available in the documentation.
125144
126145
"""
127-
super().__init__(name, instruction, url, doc)
146+
super().__init__(
147+
name=name, depends_on=depends_on, instruction=instruction, url=url, doc=doc
148+
)
128149

129150
def is_fulfilled(self, **kwargs: Any) -> bool:
130151
"""Check if the binary is available in the system's PATH."""
@@ -140,6 +161,7 @@ def __init__(
140161
repo_url: str,
141162
license: str,
142163
license_url: str,
164+
depends_on: list[SASTRequirement] | None = None,
143165
instruction: str | None = None,
144166
url: str | None = None,
145167
doc: bool = False,
@@ -151,12 +173,15 @@ def __init__(
151173
repo_url: The URL of the Git repository to clone.
152174
license: The license of the repository.
153175
license_url: A URL for the repository's license.
176+
depends_on: A list of other requirements that must be fulfilled first.
154177
instruction: A short instruction on how to download the requirement.
155178
url: A URL for more detailed instructions.
156-
doc: A flag indicating if the instruction is available in the documentaton.
179+
doc: A flag indicating if the instruction is available in the documentation.
157180
158181
"""
159-
super().__init__(name, instruction, url, doc)
182+
super().__init__(
183+
name=name, depends_on=depends_on, instruction=instruction, url=url, doc=doc
184+
)
160185
self.repo_url = repo_url
161186
self.license = license
162187
self.license_url = license_url
@@ -206,6 +231,7 @@ def __init__(
206231
file_url: str,
207232
license: str,
208233
license_url: str,
234+
depends_on: list[SASTRequirement] | None = None,
209235
instruction: str | None = None,
210236
url: str | None = None,
211237
doc: bool = False,
@@ -218,12 +244,15 @@ def __init__(
218244
file_url: The URL to download the file from.
219245
license: The license of the file.
220246
license_url: A URL for the file's license.
247+
depends_on: A list of other requirements that must be fulfilled first.
221248
instruction: A short instruction on how to download the requirement.
222249
url: A URL for more detailed instructions.
223-
doc: A flag indicating if the instruction is available in the documentaton.
250+
doc: A flag indicating if the instruction is available in the documentation.
224251
225252
"""
226-
super().__init__(name, instruction, url, doc)
253+
super().__init__(
254+
name=name, depends_on=depends_on, instruction=instruction, url=url, doc=doc
255+
)
227256
self.parent_dir = parent_dir
228257
self.file_url = file_url
229258
self.license = license

codesectools/sasts/tools/SpotBugs/sast.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@ class SpotBugsSAST(PrebuiltSAST):
4040
properties = SASTProperties(free=True, offline=True)
4141
requirements = SASTRequirements(
4242
full_reqs=[
43-
Binary("spotbugs", url="https://github.com/spotbugs/spotbugs"),
43+
binary := Binary("spotbugs", url="https://github.com/spotbugs/spotbugs"),
4444
File(
4545
name="findsecbugs-plugin-1.14.0.jar",
46-
parent_dir=Path(shutil.which("spotbugs")).parent.parent / "plugin",
46+
depends_on=[binary],
47+
parent_dir=Path(shutil.which("spotbugs")).parent.parent / "plugin"
48+
if shutil.which("spotbugs")
49+
else Path("/tmp"),
4750
file_url="https://search.maven.org/remotecontent?filepath=com/h3xstream/findsecbugs/findsecbugs-plugin/1.14.0/findsecbugs-plugin-1.14.0.jar",
4851
license="LGPL-3.0",
4952
license_url="https://find-sec-bugs.github.io/license.htm",

docker-compose.yml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
11
services:
2-
test:
3-
image: cstools_test
2+
no-sast:
3+
image: cstools_no-sast
44
build:
55
context: .
66
dockerfile: tests/Dockerfile
7+
target: no-sast
8+
9+
tty: true
10+
stdin_open: true
11+
12+
volumes:
13+
- pytest-cache:/app/.pytest_cache
14+
15+
environment:
16+
_TYPER_STANDARD_TRACEBACK: 1
17+
18+
with-sast:
19+
image: cstools_with-sast
20+
build:
21+
context: .
22+
dockerfile: tests/Dockerfile
23+
target: with-sast
724

825
tty: true
926
stdin_open: true

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "CodeSecTools"
3-
version = "0.10.0"
3+
version = "0.10.1"
44
description = "A framework for code security that provides abstractions for static analysis tools and datasets to support their integration, testing, and evaluation."
55
readme = "README.md"
66
license = "AGPL-3.0-only"

requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -497,9 +497,9 @@ tqdm==4.67.1 \
497497
--hash=sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2 \
498498
--hash=sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2
499499
# via codesectools
500-
typer==0.19.2 \
501-
--hash=sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9 \
502-
--hash=sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca
500+
typer==0.20.0 \
501+
--hash=sha256:1aaf6494031793e4876fb0bacfa6a912b551cf43c1e63c800df8b1a866720c37 \
502+
--hash=sha256:5b463df6793ec1dca6213a3cf4c0f03bc6e322ac5e16e13ddd622a889489784a
503503
# via codesectools
504504
typing-extensions==4.15.0 \
505505
--hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \

0 commit comments

Comments
 (0)