jaymd96-pants-baseline 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,78 @@
1
+ """Audit goal for uv security scanning."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Iterable
6
+
7
+ from pants.engine.console import Console
8
+ from pants.engine.goal import Goal, GoalSubsystem
9
+ from pants.engine.rules import Get, collect_rules, goal_rule
10
+ from pants.engine.target import Targets
11
+
12
+ from pants_baseline.rules.audit_rules import AuditResult, UvAuditRequest
13
+ from pants_baseline.subsystems.baseline import BaselineSubsystem
14
+ from pants_baseline.subsystems.uv import UvSubsystem
15
+
16
+
17
+ class BaselineAuditSubsystem(GoalSubsystem):
18
+ """Subsystem for the baseline-audit goal."""
19
+
20
+ name = "baseline-audit"
21
+ help = "Run uv security audit on dependencies."
22
+
23
+
24
+ class BaselineAudit(Goal):
25
+ """Goal to run uv security audit."""
26
+
27
+ subsystem_cls = BaselineAuditSubsystem
28
+
29
+
30
+ @goal_rule
31
+ async def run_baseline_audit(
32
+ console: Console,
33
+ targets: Targets,
34
+ baseline_subsystem: BaselineSubsystem,
35
+ uv_subsystem: UvSubsystem,
36
+ ) -> BaselineAudit:
37
+ """Run uv security audit on dependencies."""
38
+ if not baseline_subsystem.enabled:
39
+ console.print_stdout("Python baseline is disabled.")
40
+ return BaselineAudit(exit_code=0)
41
+
42
+ if not uv_subsystem.audit_enabled:
43
+ console.print_stdout("Security audit is disabled.")
44
+ return BaselineAudit(exit_code=0)
45
+
46
+ console.print_stdout("Running uv security audit...")
47
+ console.print_stdout(f" Lock file: {uv_subsystem.lock_file}")
48
+ if uv_subsystem.audit_ignore_vulns:
49
+ console.print_stdout(f" Ignoring: {', '.join(uv_subsystem.audit_ignore_vulns)}")
50
+ console.print_stdout("")
51
+
52
+ result = await Get(
53
+ AuditResult,
54
+ UvAuditRequest(
55
+ lock_file=uv_subsystem.lock_file,
56
+ ignore_vulns=tuple(uv_subsystem.audit_ignore_vulns),
57
+ output_format=uv_subsystem.output_format,
58
+ ),
59
+ )
60
+
61
+ if result.stdout:
62
+ console.print_stdout(result.stdout)
63
+ if result.stderr:
64
+ console.print_stderr(result.stderr)
65
+
66
+ if result.exit_code == 0:
67
+ console.print_stdout("\nNo vulnerabilities found.")
68
+ else:
69
+ console.print_stderr(
70
+ f"\nFound {result.vulnerabilities_found} vulnerabilities!"
71
+ )
72
+
73
+ return BaselineAudit(exit_code=result.exit_code)
74
+
75
+
76
+ def rules() -> Iterable:
77
+ """Return all audit goal rules."""
78
+ return collect_rules()
@@ -0,0 +1,56 @@
1
+ """Format goal for Ruff formatting."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Iterable
6
+
7
+ from pants.engine.console import Console
8
+ from pants.engine.goal import Goal, GoalSubsystem
9
+ from pants.engine.rules import collect_rules, goal_rule
10
+ from pants.engine.target import Targets
11
+
12
+ from pants_baseline.subsystems.baseline import BaselineSubsystem
13
+ from pants_baseline.subsystems.ruff import RuffSubsystem
14
+
15
+
16
+ class BaselineFmtSubsystem(GoalSubsystem):
17
+ """Subsystem for the baseline-fmt goal."""
18
+
19
+ name = "baseline-fmt"
20
+ help = "Run Ruff formatting with baseline configuration."
21
+
22
+
23
+ class BaselineFmt(Goal):
24
+ """Goal to run Ruff formatting."""
25
+
26
+ subsystem_cls = BaselineFmtSubsystem
27
+
28
+
29
+ @goal_rule
30
+ async def run_baseline_fmt(
31
+ console: Console,
32
+ targets: Targets,
33
+ baseline_subsystem: BaselineSubsystem,
34
+ ruff_subsystem: RuffSubsystem,
35
+ ) -> BaselineFmt:
36
+ """Run Ruff formatting on all targets."""
37
+ if not baseline_subsystem.enabled:
38
+ console.print_stdout("Python baseline is disabled.")
39
+ return BaselineFmt(exit_code=0)
40
+
41
+ console.print_stdout("Running Ruff formatter...")
42
+ console.print_stdout(f" Target Python version: {baseline_subsystem.python_version}")
43
+ console.print_stdout(f" Line length: {baseline_subsystem.line_length}")
44
+ console.print_stdout(f" Quote style: {ruff_subsystem.quote_style}")
45
+ console.print_stdout(f" Indent style: {ruff_subsystem.indent_style}")
46
+ console.print_stdout("")
47
+
48
+ # The actual formatting is handled by the FmtTargetsRequest mechanism
49
+ # This goal just provides a user-friendly entry point
50
+
51
+ return BaselineFmt(exit_code=0)
52
+
53
+
54
+ def rules() -> Iterable:
55
+ """Return all fmt goal rules."""
56
+ return collect_rules()
@@ -0,0 +1,59 @@
1
+ """Lint goal for Ruff linting."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Iterable
6
+
7
+ from pants.core.goals.lint import LintFilesRequest, LintResult
8
+ from pants.engine.console import Console
9
+ from pants.engine.fs import PathGlobs, Paths
10
+ from pants.engine.goal import Goal, GoalSubsystem
11
+ from pants.engine.rules import Get, collect_rules, goal_rule
12
+ from pants.engine.target import Targets
13
+ from pants.util.logging import LogLevel
14
+
15
+ from pants_baseline.rules.lint_rules import RuffLintRequest
16
+ from pants_baseline.subsystems.baseline import BaselineSubsystem
17
+ from pants_baseline.subsystems.ruff import RuffSubsystem
18
+
19
+
20
+ class BaselineLintSubsystem(GoalSubsystem):
21
+ """Subsystem for the baseline-lint goal."""
22
+
23
+ name = "baseline-lint"
24
+ help = "Run Ruff linting with baseline configuration."
25
+
26
+
27
+ class BaselineLint(Goal):
28
+ """Goal to run Ruff linting."""
29
+
30
+ subsystem_cls = BaselineLintSubsystem
31
+
32
+
33
+ @goal_rule
34
+ async def run_baseline_lint(
35
+ console: Console,
36
+ targets: Targets,
37
+ baseline_subsystem: BaselineSubsystem,
38
+ ruff_subsystem: RuffSubsystem,
39
+ ) -> BaselineLint:
40
+ """Run Ruff linting on all targets."""
41
+ if not baseline_subsystem.enabled:
42
+ console.print_stdout("Python baseline is disabled.")
43
+ return BaselineLint(exit_code=0)
44
+
45
+ console.print_stdout("Running Ruff linter...")
46
+ console.print_stdout(f" Target Python version: {baseline_subsystem.python_version}")
47
+ console.print_stdout(f" Line length: {baseline_subsystem.line_length}")
48
+ console.print_stdout(f" Rules: {', '.join(ruff_subsystem.select[:5])}...")
49
+ console.print_stdout("")
50
+
51
+ # The actual linting is handled by the LintTargetsRequest mechanism
52
+ # This goal just provides a user-friendly entry point
53
+
54
+ return BaselineLint(exit_code=0)
55
+
56
+
57
+ def rules() -> Iterable:
58
+ """Return all lint goal rules."""
59
+ return collect_rules()
@@ -0,0 +1,53 @@
1
+ """Test goal for pytest testing."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Iterable
6
+
7
+ from pants.engine.console import Console
8
+ from pants.engine.goal import Goal, GoalSubsystem
9
+ from pants.engine.rules import collect_rules, goal_rule
10
+ from pants.engine.target import Targets
11
+
12
+ from pants_baseline.subsystems.baseline import BaselineSubsystem
13
+
14
+
15
+ class BaselineTestSubsystem(GoalSubsystem):
16
+ """Subsystem for the baseline-test goal."""
17
+
18
+ name = "baseline-test"
19
+ help = "Run pytest with coverage and baseline configuration."
20
+
21
+
22
+ class BaselineTest(Goal):
23
+ """Goal to run pytest tests."""
24
+
25
+ subsystem_cls = BaselineTestSubsystem
26
+
27
+
28
+ @goal_rule
29
+ async def run_baseline_test(
30
+ console: Console,
31
+ targets: Targets,
32
+ baseline_subsystem: BaselineSubsystem,
33
+ ) -> BaselineTest:
34
+ """Run pytest on all test targets."""
35
+ if not baseline_subsystem.enabled:
36
+ console.print_stdout("Python baseline is disabled.")
37
+ return BaselineTest(exit_code=0)
38
+
39
+ console.print_stdout("Running pytest with coverage...")
40
+ console.print_stdout(f" Source roots: {', '.join(baseline_subsystem.src_roots)}")
41
+ console.print_stdout(f" Test roots: {', '.join(baseline_subsystem.test_roots)}")
42
+ console.print_stdout(f" Coverage threshold: {baseline_subsystem.coverage_threshold}%")
43
+ console.print_stdout("")
44
+
45
+ # The actual testing is handled by the TestRequest mechanism
46
+ # This goal just provides a user-friendly entry point
47
+
48
+ return BaselineTest(exit_code=0)
49
+
50
+
51
+ def rules() -> Iterable:
52
+ """Return all test goal rules."""
53
+ return collect_rules()
@@ -0,0 +1,55 @@
1
+ """Type check goal for ty type checking."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Iterable
6
+
7
+ from pants.engine.console import Console
8
+ from pants.engine.goal import Goal, GoalSubsystem
9
+ from pants.engine.rules import collect_rules, goal_rule
10
+ from pants.engine.target import Targets
11
+
12
+ from pants_baseline.subsystems.baseline import BaselineSubsystem
13
+ from pants_baseline.subsystems.ty import TySubsystem
14
+
15
+
16
+ class BaselineTypecheckSubsystem(GoalSubsystem):
17
+ """Subsystem for the baseline-typecheck goal."""
18
+
19
+ name = "baseline-typecheck"
20
+ help = "Run ty type checking with baseline configuration."
21
+
22
+
23
+ class BaselineTypecheck(Goal):
24
+ """Goal to run ty type checking."""
25
+
26
+ subsystem_cls = BaselineTypecheckSubsystem
27
+
28
+
29
+ @goal_rule
30
+ async def run_baseline_typecheck(
31
+ console: Console,
32
+ targets: Targets,
33
+ baseline_subsystem: BaselineSubsystem,
34
+ ty_subsystem: TySubsystem,
35
+ ) -> BaselineTypecheck:
36
+ """Run ty type checking on all targets."""
37
+ if not baseline_subsystem.enabled:
38
+ console.print_stdout("Python baseline is disabled.")
39
+ return BaselineTypecheck(exit_code=0)
40
+
41
+ console.print_stdout("Running ty type checker...")
42
+ console.print_stdout(f" Target Python version: {baseline_subsystem.python_version}")
43
+ console.print_stdout(f" Strict mode: {ty_subsystem.strict}")
44
+ console.print_stdout(f" Output format: {ty_subsystem.output_format}")
45
+ console.print_stdout("")
46
+
47
+ # The actual type checking is handled by the CheckRequest mechanism
48
+ # This goal just provides a user-friendly entry point
49
+
50
+ return BaselineTypecheck(exit_code=0)
51
+
52
+
53
+ def rules() -> Iterable:
54
+ """Return all typecheck goal rules."""
55
+ return collect_rules()
@@ -0,0 +1,46 @@
1
+ """Register the Python Baseline plugin with Pants.
2
+
3
+ This module is the entry point for the Pants plugin system.
4
+ It registers all rules, targets, and subsystems provided by this plugin.
5
+ """
6
+
7
+ from typing import Iterable
8
+
9
+ from pants.engine.rules import Rule, collect_rules
10
+
11
+ from pants_baseline.goals import audit as audit_goal
12
+ from pants_baseline.goals import fmt as fmt_goal
13
+ from pants_baseline.goals import lint as lint_goal
14
+ from pants_baseline.goals import test as test_goal
15
+ from pants_baseline.goals import typecheck as typecheck_goal
16
+ from pants_baseline.rules import audit_rules, fmt_rules, lint_rules, test_rules, typecheck_rules
17
+ from pants_baseline.subsystems.baseline import BaselineSubsystem
18
+ from pants_baseline.subsystems.ruff import RuffSubsystem
19
+ from pants_baseline.subsystems.ty import TySubsystem
20
+ from pants_baseline.subsystems.uv import UvSubsystem
21
+ from pants_baseline.targets import BaselinePythonProject
22
+
23
+
24
+ def rules() -> Iterable[Rule]:
25
+ """Return all rules provided by this plugin."""
26
+ return [
27
+ *collect_rules(lint_rules),
28
+ *collect_rules(fmt_rules),
29
+ *collect_rules(typecheck_rules),
30
+ *collect_rules(test_rules),
31
+ *collect_rules(audit_rules),
32
+ *collect_rules(lint_goal),
33
+ *collect_rules(fmt_goal),
34
+ *collect_rules(typecheck_goal),
35
+ *collect_rules(test_goal),
36
+ *collect_rules(audit_goal),
37
+ *BaselineSubsystem.rules(),
38
+ *RuffSubsystem.rules(),
39
+ *TySubsystem.rules(),
40
+ *UvSubsystem.rules(),
41
+ ]
42
+
43
+
44
+ def target_types() -> Iterable[type]:
45
+ """Return all custom target types provided by this plugin."""
46
+ return [BaselinePythonProject]
@@ -0,0 +1,11 @@
1
+ """Rules for the Python Baseline plugin."""
2
+
3
+ from pants_baseline.rules import audit_rules, fmt_rules, lint_rules, test_rules, typecheck_rules
4
+
5
+ __all__ = [
6
+ "audit_rules",
7
+ "fmt_rules",
8
+ "lint_rules",
9
+ "test_rules",
10
+ "typecheck_rules",
11
+ ]
@@ -0,0 +1,135 @@
1
+ """Rules for uv security auditing."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Iterable
7
+
8
+ from pants.engine.console import Console
9
+ from pants.engine.fs import Digest
10
+ from pants.engine.goal import Goal, GoalSubsystem
11
+ from pants.engine.process import FallibleProcessResult, Process
12
+ from pants.engine.rules import Get, collect_rules, goal_rule, rule
13
+ from pants.engine.target import Targets
14
+ from pants.util.logging import LogLevel
15
+
16
+ from pants_baseline.subsystems.baseline import BaselineSubsystem
17
+ from pants_baseline.subsystems.uv import UvSubsystem
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class AuditResult:
22
+ """Result of running uv audit."""
23
+
24
+ exit_code: int
25
+ stdout: str
26
+ stderr: str
27
+ vulnerabilities_found: int
28
+
29
+
30
+ class AuditSubsystem(GoalSubsystem):
31
+ """Subsystem for the audit goal."""
32
+
33
+ name = "baseline-audit"
34
+ help = "Run security audit on dependencies using uv."
35
+
36
+
37
+ class Audit(Goal):
38
+ """Goal to run security audit."""
39
+
40
+ subsystem_cls = AuditSubsystem
41
+
42
+
43
+ @dataclass(frozen=True)
44
+ class UvAuditRequest:
45
+ """Request to run uv audit."""
46
+
47
+ lock_file: str
48
+ ignore_vulns: tuple[str, ...]
49
+ output_format: str
50
+
51
+
52
+ @rule(desc="Audit dependencies with uv", level=LogLevel.DEBUG)
53
+ async def run_uv_audit(
54
+ request: UvAuditRequest,
55
+ ) -> AuditResult:
56
+ """Run uv audit on dependencies."""
57
+ # Build ignore args
58
+ ignore_args = []
59
+ for vuln in request.ignore_vulns:
60
+ ignore_args.extend(["--ignore", vuln])
61
+
62
+ argv = [
63
+ "uv",
64
+ "audit",
65
+ f"--output-format={request.output_format}",
66
+ *ignore_args,
67
+ ]
68
+
69
+ process = Process(
70
+ argv=argv,
71
+ description="Run uv security audit",
72
+ level=LogLevel.DEBUG,
73
+ )
74
+
75
+ result = await Get(FallibleProcessResult, Process, process)
76
+
77
+ stdout = result.stdout.decode()
78
+ stderr = result.stderr.decode()
79
+
80
+ # Parse vulnerability count from output (simplified)
81
+ vulnerabilities_found = 0
82
+ if result.exit_code != 0:
83
+ # Count lines that look like vulnerability reports
84
+ for line in stdout.split("\n"):
85
+ if "vulnerability" in line.lower() or "CVE-" in line or "GHSA-" in line:
86
+ vulnerabilities_found += 1
87
+
88
+ return AuditResult(
89
+ exit_code=result.exit_code,
90
+ stdout=stdout,
91
+ stderr=stderr,
92
+ vulnerabilities_found=vulnerabilities_found,
93
+ )
94
+
95
+
96
+ @goal_rule
97
+ async def run_audit_goal(
98
+ console: Console,
99
+ targets: Targets,
100
+ uv_subsystem: UvSubsystem,
101
+ baseline_subsystem: BaselineSubsystem,
102
+ ) -> Audit:
103
+ """Execute the security audit goal."""
104
+ if not baseline_subsystem.enabled or not uv_subsystem.audit_enabled:
105
+ console.print_stdout("Security audit is disabled.")
106
+ return Audit(exit_code=0)
107
+
108
+ console.print_stdout("Running security audit with uv...")
109
+
110
+ result = await Get(
111
+ AuditResult,
112
+ UvAuditRequest(
113
+ lock_file=uv_subsystem.lock_file,
114
+ ignore_vulns=tuple(uv_subsystem.audit_ignore_vulns),
115
+ output_format=uv_subsystem.output_format,
116
+ ),
117
+ )
118
+
119
+ console.print_stdout(result.stdout)
120
+ if result.stderr:
121
+ console.print_stderr(result.stderr)
122
+
123
+ if result.vulnerabilities_found > 0:
124
+ console.print_stderr(
125
+ f"\nFound {result.vulnerabilities_found} vulnerabilities!"
126
+ )
127
+ else:
128
+ console.print_stdout("\nNo vulnerabilities found.")
129
+
130
+ return Audit(exit_code=result.exit_code)
131
+
132
+
133
+ def rules() -> Iterable:
134
+ """Return all audit rules."""
135
+ return collect_rules()
@@ -0,0 +1,122 @@
1
+ """Rules for Ruff formatting."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Iterable
7
+
8
+ from pants.core.goals.fmt import FmtResult, FmtTargetsRequest
9
+ from pants.core.util_rules.source_files import SourceFiles, SourceFilesRequest
10
+ from pants.engine.fs import Digest, Snapshot
11
+ from pants.engine.process import FallibleProcessResult, Process
12
+ from pants.engine.rules import Get, collect_rules, rule
13
+ from pants.engine.target import FieldSet
14
+ from pants.engine.unions import UnionRule
15
+ from pants.util.logging import LogLevel
16
+
17
+ from pants_baseline.subsystems.baseline import BaselineSubsystem
18
+ from pants_baseline.subsystems.ruff import RuffSubsystem
19
+ from pants_baseline.targets import BaselineSourcesField, SkipFormatField
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class RuffFmtFieldSet(FieldSet):
24
+ """Field set for Ruff formatting."""
25
+
26
+ required_fields = (BaselineSourcesField,)
27
+
28
+ sources: BaselineSourcesField
29
+ skip_fmt: SkipFormatField
30
+
31
+
32
+ class RuffFmtRequest(FmtTargetsRequest):
33
+ """Request to run Ruff formatting."""
34
+
35
+ field_set_type = RuffFmtFieldSet
36
+ tool_name = "ruff"
37
+
38
+
39
+ @rule(desc="Format with Ruff", level=LogLevel.DEBUG)
40
+ async def run_ruff_fmt(
41
+ request: RuffFmtRequest,
42
+ ruff_subsystem: RuffSubsystem,
43
+ baseline_subsystem: BaselineSubsystem,
44
+ ) -> FmtResult:
45
+ """Run Ruff formatter on Python files."""
46
+ if not baseline_subsystem.enabled:
47
+ return FmtResult(
48
+ input=request.snapshot,
49
+ output=request.snapshot,
50
+ stdout="",
51
+ stderr="",
52
+ formatter_name="ruff",
53
+ )
54
+
55
+ # Filter out skipped targets
56
+ field_sets = [fs for fs in request.field_sets if not fs.skip_fmt.value]
57
+
58
+ if not field_sets:
59
+ return FmtResult(
60
+ input=request.snapshot,
61
+ output=request.snapshot,
62
+ stdout="No targets to format",
63
+ stderr="",
64
+ formatter_name="ruff",
65
+ )
66
+
67
+ # Get source files
68
+ sources = await Get(
69
+ SourceFiles,
70
+ SourceFilesRequest(
71
+ sources_fields=[fs.sources for fs in field_sets],
72
+ for_sources_types=(BaselineSourcesField,),
73
+ ),
74
+ )
75
+
76
+ if not sources.files:
77
+ return FmtResult(
78
+ input=request.snapshot,
79
+ output=request.snapshot,
80
+ stdout="No files to format",
81
+ stderr="",
82
+ formatter_name="ruff",
83
+ )
84
+
85
+ # Build Ruff format command
86
+ argv = [
87
+ "ruff",
88
+ "format",
89
+ f"--target-version={baseline_subsystem.get_python_target_version()}",
90
+ f"--line-length={baseline_subsystem.line_length}",
91
+ f"--quote-style={ruff_subsystem.quote_style}",
92
+ f"--indent-style={ruff_subsystem.indent_style}",
93
+ *sources.files,
94
+ ]
95
+
96
+ process = Process(
97
+ argv=argv,
98
+ input_digest=sources.snapshot.digest,
99
+ output_files=sources.files,
100
+ description=f"Run Ruff format on {len(sources.files)} files",
101
+ level=LogLevel.DEBUG,
102
+ )
103
+
104
+ result = await Get(FallibleProcessResult, Process, process)
105
+
106
+ output_snapshot = await Get(Snapshot, Digest, result.output_digest)
107
+
108
+ return FmtResult(
109
+ input=sources.snapshot,
110
+ output=output_snapshot,
111
+ stdout=result.stdout.decode(),
112
+ stderr=result.stderr.decode(),
113
+ formatter_name="ruff",
114
+ )
115
+
116
+
117
+ def rules() -> Iterable:
118
+ """Return all format rules."""
119
+ return [
120
+ *collect_rules(),
121
+ UnionRule(FmtTargetsRequest, RuffFmtRequest),
122
+ ]