Skip to content

Commit d665364

Browse files
Merge branch 'main' into p--handle-499
2 parents a0fe49e + 211f98e commit d665364

30 files changed

Lines changed: 1217 additions & 1027 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ jobs:
3535

3636
- name: Run static analysis
3737
run: |
38-
# hatch fmt --check
39-
echo linter errors will be fixed in a separate PR
38+
hatch fmt --linter --check
4039
4140
- name: Run tests
4241
run: hatch test --python ${{ matrix.python-version }} --cover --randomize --parallel --retries 2 --retry-delay 1

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ The Seclab Taskflow Agent framework was primarily designed to fit the iterative
2222

2323
Its design philosophy is centered around the belief that a prompt level focus of capturing vulnerability patterns will greatly improve and scale security research results as frontier model capabilities evolve over time.
2424

25-
While the maintainer himself primarily uses this framework as a code auditing tool it also serves as a more generic swiss army knife for exploring Agentic workflows. For example, the GitHub Security Lab also uses this framework for automated code scanning alert triage.
25+
At GitHub Security Lab, we primarily use this framework as a code auditing tool, but it can also serve as a more generic swiss army knife for exploring Agentic workflows. For example, we also use this framework for automated code scanning alert triage.
2626

2727
The framework includes a [CodeQL](https://codeql.github.com/) MCP server that can be used for Agentic code review, see the [CVE-2023-2283](examples/taskflows/CVE-2023-2283.yaml) taskflow for an example of how to have an Agent review C code using a CodeQL database ([demo video](https://www.youtube.com/watch?v=eRSPSVW8RMo)).
2828

2929
Instead of generating CodeQL queries itself, the CodeQL MCP Server is used to provide CodeQL-query based MCP tools that allow an Agent to navigate and explore code. It leverages templated CodeQL queries to provide targeted context for model driven code analysis.
3030

3131
## Requirements
3232

33-
Python >= 3.9 or Docker
33+
Python >= 3.10 or Docker
3434

3535
## Configuration
3636

pyproject.toml

Lines changed: 90 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ name = "seclab-taskflow-agent"
77
dynamic = ["version"]
88
description = "A taskflow agent for the SecLab project, enabling secure and automated workflow execution."
99
readme = "README.md"
10-
requires-python = ">=3.9"
10+
requires-python = ">=3.10"
1111
license = "MIT"
1212
keywords = []
1313
authors = [
@@ -16,8 +16,6 @@ authors = [
1616
classifiers = [
1717
"Development Status :: 4 - Beta",
1818
"Programming Language :: Python",
19-
"Programming Language :: Python :: 3.8",
20-
"Programming Language :: Python :: 3.9",
2119
"Programming Language :: Python :: 3.10",
2220
"Programming Language :: Python :: 3.11",
2321
"Programming Language :: Python :: 3.12",
@@ -83,7 +81,7 @@ dependencies = [
8381
"python-dotenv==1.1.1",
8482
"python-lsp-jsonrpc==1.1.2",
8583
"python-lsp-server==1.12.2",
86-
"python-multipart==0.0.20",
84+
"python-multipart==0.0.22",
8785
"PyYAML==6.0.2",
8886
"referencing==0.36.2",
8987
"requests==2.32.4",
@@ -145,3 +143,91 @@ exclude_lines = [
145143
"if __name__ == .__main__.:",
146144
"if TYPE_CHECKING:",
147145
]
146+
147+
[tool.ruff]
148+
# Set target version to 3.10 to support match statements
149+
target-version = "py310"
150+
151+
[tool.ruff.lint]
152+
# Suppress all current linter errors to establish a baseline
153+
ignore = [
154+
"A001", # Variable shadows built-in
155+
"A002", # Argument shadows built-in
156+
"A004", # Import shadows built-in
157+
"ARG001", # Unused function argument
158+
"B006", # Mutable default argument
159+
"B007", # Unused loop control variable
160+
"B008", # Function call in argument defaults
161+
"B023", # Function uses loop variable
162+
"B904", # raise-without-from-inside-except
163+
"BLE001", # Blind except
164+
"C405", # Unnecessary literal set
165+
"C416", # Unnecessary comprehension
166+
"E721", # Type comparison using ==
167+
"E722", # Bare except
168+
"E741", # Ambiguous variable name
169+
"EM101", # Exception string literal
170+
"EM102", # Exception f-string
171+
"F541", # f-string without placeholders
172+
"F811", # Redefinition of unused name
173+
"F821", # Undefined name
174+
"F841", # Unused variable
175+
"FA100", # Missing from __future__ import annotations
176+
"FA102", # Missing from __future__ import annotations in stub
177+
"FBT001", # Boolean positional arg in function definition
178+
"FBT002", # Boolean default value in function definition
179+
"FURB188", # Prefer removeprefix over conditional slice
180+
"G004", # Logging with f-string
181+
"I001", # Import block unsorted or unformatted
182+
"INP001", # Implicit namespace package
183+
"LOG015", # root logger usage
184+
"N801", # Class name should use CapWords convention
185+
"N802", # Function name should be lowercase
186+
"N806", # Variable in function should be lowercase
187+
"N818", # Exception name should end with Error
188+
"PERF102", # Use keys() or values() instead of items()
189+
"PERF401", # Use list comprehension
190+
"PIE790", # Unnecessary pass statement
191+
"PLC0415", # Import should be at top of file
192+
"PLC1802", # Use of len(x) == 0
193+
"PLR2004", # Magic value used in comparison
194+
"PLW0602", # Global variable not assigned
195+
"PLW0603", # Using global statement
196+
"PLW1508", # Invalid envvar default
197+
"PLW2901", # Outer loop variable overwritten
198+
"PT011", # pytest.raises too broad
199+
"PYI041", # Use float instead of int | float
200+
"RET503", # Missing explicit return
201+
"RET504", # Unnecessary assignment before return
202+
"RET505", # Unnecessary else after return
203+
"RET506", # Unnecessary else after raise
204+
"RUF005", # Unpack instead of concatenation
205+
"RUF010", # Use explicit conversion flag
206+
"RUF015", # Prefer next() over single element slice
207+
"RUF059", # Use of private function/attribute
208+
"RUF100", # Unused noqa directive
209+
"S108", # Hardcoded temp file/directory
210+
"S607", # Starting process with partial path
211+
"SIM102", # Use single if statement
212+
"SIM115", # Use context handler for file
213+
"SIM210", # Use ternary operator
214+
"SLF001", # Private member access
215+
"T201", # print found
216+
"TID252", # Relative imports from parent modules
217+
"TRY003", # Raise vanilla args
218+
"TRY004", # Prefer TypeError for wrong type
219+
"TRY300", # Consider moving statement to else
220+
"TRY301", # Abstract raise to inner function
221+
"TRY400", # Use logging.exception instead of logging.error
222+
"UP004", # Use X | Y for union types
223+
"UP006", # Use X | Y for union types in isinstance
224+
"UP009", # UTF-8 encoding declaration
225+
"UP015", # Unnecessary mode argument
226+
"UP020", # Use builtin open
227+
"UP024", # Replace aliased errors with OSError
228+
"UP032", # Use f-string
229+
"UP035", # Import from collections.abc
230+
"UP045", # Use X | None for type annotations
231+
"W291", # Trailing whitespace
232+
"W293", # Blank line contains whitespace
233+
]

release_tools/copy_files.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33

44
import os
55
import shutil
6-
import sys
76
import subprocess
7+
import sys
8+
89

910
def read_file_list(list_path):
1011
"""
1112
Reads a file containing file paths, ignoring empty lines and lines starting with '#'.
1213
Returns a list of relative file paths.
1314
"""
14-
with open(list_path, "r") as f:
15+
with open(list_path) as f:
1516
lines = [line.strip() for line in f]
1617
return [line for line in lines if line and not line.startswith("#")]
1718

19+
1820
def copy_files(file_list, dest_dir):
1921
"""
2022
Copy files listed in file_list to dest_dir, preserving their relative paths.
@@ -29,6 +31,7 @@ def copy_files(file_list, dest_dir):
2931
shutil.copy2(abs_src, abs_dest)
3032
print(f"Copied {abs_src} -> {abs_dest}")
3133

34+
3235
def ensure_git_repo(dest_dir):
3336
"""
3437
Initializes a git repository in dest_dir if it's not already a git repo.
@@ -56,6 +59,7 @@ def ensure_git_repo(dest_dir):
5659
print(f"Failed to ensure 'main' branch in {dest_dir}: {e}")
5760
sys.exit(1)
5861

62+
5963
def git_add_files(file_list, dest_dir):
6064
"""
6165
Runs 'git add' on each file in file_list within dest_dir.
@@ -72,6 +76,7 @@ def git_add_files(file_list, dest_dir):
7276
finally:
7377
os.chdir(cwd)
7478

79+
7580
if __name__ == "__main__":
7681
if len(sys.argv) != 3:
7782
print("Usage: python copy_files.py <file_list.txt> <dest_dir>")

release_tools/publish_docker.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
11
# SPDX-FileCopyrightText: 2025 GitHub
22
# SPDX-License-Identifier: MIT
33

4-
import os
5-
import shutil
64
import subprocess
75
import sys
86

7+
98
def get_image_digest(image_name, tag):
109
result = subprocess.run(
1110
["docker", "buildx", "imagetools", "inspect", f"{image_name}:{tag}"],
12-
stdout=subprocess.PIPE, check=True, text=True
11+
stdout=subprocess.PIPE,
12+
check=True,
13+
text=True,
1314
)
1415
for line in result.stdout.splitlines():
1516
if line.strip().startswith("Digest:"):
1617
return line.strip().split(":", 1)[1].strip()
1718
return None
1819

20+
1921
def build_and_push_image(dest_dir, image_name, tag):
2022
# Build
21-
subprocess.run([
22-
"docker", "buildx", "build", "--platform", "linux/amd64", "-t", f"{image_name}:{tag}", dest_dir
23-
], check=True)
23+
subprocess.run(
24+
["docker", "buildx", "build", "--platform", "linux/amd64", "-t", f"{image_name}:{tag}", dest_dir], check=True
25+
)
2426
# Push
25-
subprocess.run([
26-
"docker", "push", f"{image_name}:{tag}"
27-
], check=True)
27+
subprocess.run(["docker", "push", f"{image_name}:{tag}"], check=True)
2828
print(f"Pushed {image_name}:{tag}")
2929
digest = get_image_digest(image_name, tag)
3030
print(f"Image digest: {digest}")
3131
with open("/tmp/digest.txt", "w") as f:
3232
f.write(digest)
3333

34+
3435
if __name__ == "__main__":
3536
if len(sys.argv) != 3:
3637
print("Usage: python build_and_publish_docker.py <ghcr_username/repo> <tag>")
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# SPDX-FileCopyrightText: 2025 GitHub
22
# SPDX-License-Identifier: MIT
3-
__version__ = "0.0.9"
3+
__version__ = "0.0.10"

0 commit comments

Comments
 (0)