diffguard 0.1.3__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.
- diffguard/__init__.py +3 -0
- diffguard/cli.py +676 -0
- diffguard/engine/__init__.py +1 -0
- diffguard/engine/_types.py +36 -0
- diffguard/engine/classifier.py +87 -0
- diffguard/engine/deps.py +204 -0
- diffguard/engine/matcher.py +128 -0
- diffguard/engine/parser.py +47 -0
- diffguard/engine/pipeline.py +205 -0
- diffguard/engine/signatures.py +248 -0
- diffguard/engine/summarizer.py +412 -0
- diffguard/git.py +323 -0
- diffguard/languages/__init__.py +52 -0
- diffguard/languages/_utils.py +13 -0
- diffguard/languages/go/__init__.py +101 -0
- diffguard/languages/go/queries.scm +1 -0
- diffguard/languages/python/__init__.py +204 -0
- diffguard/languages/python/queries.scm +1 -0
- diffguard/languages/typescript/__init__.py +184 -0
- diffguard/languages/typescript/queries.scm +1 -0
- diffguard/schema.py +97 -0
- diffguard-0.1.3.dist-info/METADATA +142 -0
- diffguard-0.1.3.dist-info/RECORD +26 -0
- diffguard-0.1.3.dist-info/WHEEL +4 -0
- diffguard-0.1.3.dist-info/entry_points.txt +2 -0
- diffguard-0.1.3.dist-info/licenses/LICENSE +53 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""TypeScript/JavaScript language support."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import tree_sitter
|
|
6
|
+
import tree_sitter_javascript
|
|
7
|
+
import tree_sitter_typescript
|
|
8
|
+
|
|
9
|
+
from diffguard.engine._types import Symbol, compute_body_hash
|
|
10
|
+
from diffguard.languages._utils import node_text
|
|
11
|
+
|
|
12
|
+
# Default to TypeScript grammar (superset of JS)
|
|
13
|
+
_ts_lang = tree_sitter.Language(tree_sitter_typescript.language_typescript())
|
|
14
|
+
_js_lang = tree_sitter.Language(tree_sitter_javascript.language())
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_language() -> tree_sitter.Language:
|
|
18
|
+
"""Return the tree-sitter Language object for TypeScript."""
|
|
19
|
+
return _ts_lang
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_js_language() -> tree_sitter.Language:
|
|
23
|
+
"""Return the tree-sitter Language object for JavaScript."""
|
|
24
|
+
return _js_lang
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def extract_symbols(tree: tree_sitter.Tree, source: bytes) -> list[Symbol]:
|
|
28
|
+
"""Extract symbols from a parsed JavaScript/TypeScript tree."""
|
|
29
|
+
symbols: list[Symbol] = []
|
|
30
|
+
_walk_node(tree.root_node, source, symbols, parent_class=None)
|
|
31
|
+
return symbols
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _walk_node(
|
|
35
|
+
node: tree_sitter.Node,
|
|
36
|
+
source: bytes,
|
|
37
|
+
symbols: list[Symbol],
|
|
38
|
+
parent_class: str | None,
|
|
39
|
+
) -> None:
|
|
40
|
+
"""Recursively walk the tree and extract symbols."""
|
|
41
|
+
for child in node.children:
|
|
42
|
+
if child.type == "function_declaration":
|
|
43
|
+
_extract_function(child, symbols)
|
|
44
|
+
elif child.type == "class_declaration":
|
|
45
|
+
_extract_class(child, source, symbols)
|
|
46
|
+
elif child.type in ("lexical_declaration", "variable_declaration"):
|
|
47
|
+
_extract_arrow_functions(child, symbols)
|
|
48
|
+
elif child.type == "export_statement":
|
|
49
|
+
_walk_node(child, source, symbols, parent_class)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _extract_function(
|
|
53
|
+
node: tree_sitter.Node,
|
|
54
|
+
symbols: list[Symbol],
|
|
55
|
+
) -> None:
|
|
56
|
+
"""Extract a function declaration."""
|
|
57
|
+
name_node = node.child_by_field_name("name")
|
|
58
|
+
if name_node is None:
|
|
59
|
+
return
|
|
60
|
+
name = node_text(name_node)
|
|
61
|
+
params_node = node.child_by_field_name("parameters")
|
|
62
|
+
params = node_text(params_node) if params_node else "()"
|
|
63
|
+
signature = f"function {name}{params}"
|
|
64
|
+
body_node = node.child_by_field_name("body")
|
|
65
|
+
body_text = node_text(body_node) if body_node else ""
|
|
66
|
+
|
|
67
|
+
symbols.append(
|
|
68
|
+
Symbol(
|
|
69
|
+
name=name,
|
|
70
|
+
kind="function",
|
|
71
|
+
signature=signature,
|
|
72
|
+
start_line=node.start_point.row + 1,
|
|
73
|
+
end_line=node.end_point.row + 1,
|
|
74
|
+
body_hash=compute_body_hash(body_text),
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _extract_class(
|
|
80
|
+
node: tree_sitter.Node,
|
|
81
|
+
source: bytes,
|
|
82
|
+
symbols: list[Symbol],
|
|
83
|
+
) -> None:
|
|
84
|
+
"""Extract a class declaration and its methods."""
|
|
85
|
+
name_node = node.child_by_field_name("name")
|
|
86
|
+
if name_node is None:
|
|
87
|
+
return
|
|
88
|
+
class_name = node_text(name_node)
|
|
89
|
+
body_node = node.child_by_field_name("body")
|
|
90
|
+
body_text = node_text(body_node) if body_node else ""
|
|
91
|
+
|
|
92
|
+
heritage = ""
|
|
93
|
+
for child in node.children:
|
|
94
|
+
if child.type == "class_heritage":
|
|
95
|
+
heritage = f" {node_text(child)}"
|
|
96
|
+
break
|
|
97
|
+
|
|
98
|
+
symbols.append(
|
|
99
|
+
Symbol(
|
|
100
|
+
name=class_name,
|
|
101
|
+
kind="class",
|
|
102
|
+
signature=f"class {class_name}{heritage}",
|
|
103
|
+
start_line=node.start_point.row + 1,
|
|
104
|
+
end_line=node.end_point.row + 1,
|
|
105
|
+
body_hash=compute_body_hash(body_text),
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
if body_node:
|
|
110
|
+
for child in body_node.children:
|
|
111
|
+
if child.type == "method_definition":
|
|
112
|
+
_extract_method(child, symbols, class_name)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _extract_method(
|
|
116
|
+
node: tree_sitter.Node,
|
|
117
|
+
symbols: list[Symbol],
|
|
118
|
+
class_name: str,
|
|
119
|
+
) -> None:
|
|
120
|
+
"""Extract a method definition."""
|
|
121
|
+
name_node = node.child_by_field_name("name")
|
|
122
|
+
if name_node is None:
|
|
123
|
+
return
|
|
124
|
+
name = node_text(name_node)
|
|
125
|
+
params_node = node.child_by_field_name("parameters")
|
|
126
|
+
params = node_text(params_node) if params_node else "()"
|
|
127
|
+
signature = f"{name}{params}"
|
|
128
|
+
body_node = node.child_by_field_name("body")
|
|
129
|
+
body_text = node_text(body_node) if body_node else ""
|
|
130
|
+
|
|
131
|
+
symbols.append(
|
|
132
|
+
Symbol(
|
|
133
|
+
name=name,
|
|
134
|
+
kind="method",
|
|
135
|
+
signature=signature,
|
|
136
|
+
start_line=node.start_point.row + 1,
|
|
137
|
+
end_line=node.end_point.row + 1,
|
|
138
|
+
body_hash=compute_body_hash(body_text),
|
|
139
|
+
parent=class_name,
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _extract_arrow_functions(
|
|
145
|
+
node: tree_sitter.Node,
|
|
146
|
+
symbols: list[Symbol],
|
|
147
|
+
) -> None:
|
|
148
|
+
"""Extract arrow functions assigned to variables."""
|
|
149
|
+
# Detect keyword (const/let/var)
|
|
150
|
+
keyword = "const"
|
|
151
|
+
for sib in node.children:
|
|
152
|
+
if not sib.is_named:
|
|
153
|
+
t = node_text(sib)
|
|
154
|
+
if t in ("const", "let", "var"):
|
|
155
|
+
keyword = t
|
|
156
|
+
break
|
|
157
|
+
|
|
158
|
+
for child in node.children:
|
|
159
|
+
if child.type == "variable_declarator":
|
|
160
|
+
name_node = child.child_by_field_name("name")
|
|
161
|
+
value_node = child.child_by_field_name("value")
|
|
162
|
+
if name_node and value_node and value_node.type == "arrow_function":
|
|
163
|
+
name = node_text(name_node)
|
|
164
|
+
params_node = value_node.child_by_field_name("parameters")
|
|
165
|
+
if params_node:
|
|
166
|
+
params = node_text(params_node)
|
|
167
|
+
else:
|
|
168
|
+
param_node = value_node.child_by_field_name("parameter")
|
|
169
|
+
params = f"({node_text(param_node)})" if param_node else "()"
|
|
170
|
+
|
|
171
|
+
signature = f"{keyword} {name} = {params} =>"
|
|
172
|
+
body_node = value_node.child_by_field_name("body")
|
|
173
|
+
body_text = node_text(body_node) if body_node else ""
|
|
174
|
+
|
|
175
|
+
symbols.append(
|
|
176
|
+
Symbol(
|
|
177
|
+
name=name,
|
|
178
|
+
kind="function",
|
|
179
|
+
signature=signature,
|
|
180
|
+
start_line=node.start_point.row + 1,
|
|
181
|
+
end_line=node.end_point.row + 1,
|
|
182
|
+
body_hash=compute_body_hash(body_text),
|
|
183
|
+
)
|
|
184
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
; TypeScript tree-sitter queries — placeholder
|
diffguard/schema.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""DiffGuard output schema — Pydantic v2 models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Any, Literal
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class DiffStats(BaseModel):
|
|
12
|
+
"""Diff statistics."""
|
|
13
|
+
|
|
14
|
+
files: int
|
|
15
|
+
additions: int
|
|
16
|
+
deletions: int
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Meta(BaseModel):
|
|
20
|
+
"""Run metadata."""
|
|
21
|
+
|
|
22
|
+
ref_range: str
|
|
23
|
+
stats: DiffStats
|
|
24
|
+
warnings: list[str] = []
|
|
25
|
+
timing_ms: float | None = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SymbolChange(BaseModel):
|
|
29
|
+
"""A single symbol-level change."""
|
|
30
|
+
|
|
31
|
+
kind: Literal[
|
|
32
|
+
"function_added",
|
|
33
|
+
"function_removed",
|
|
34
|
+
"function_modified",
|
|
35
|
+
"class_added",
|
|
36
|
+
"class_removed",
|
|
37
|
+
"class_modified",
|
|
38
|
+
"signature_changed",
|
|
39
|
+
"moved",
|
|
40
|
+
]
|
|
41
|
+
name: str
|
|
42
|
+
signature: str | None = None
|
|
43
|
+
before_signature: str | None = None
|
|
44
|
+
after_signature: str | None = None
|
|
45
|
+
file_from: str | None = None
|
|
46
|
+
line: int | None = None
|
|
47
|
+
breaking: bool = False
|
|
48
|
+
detail: dict[str, Any] | None = None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class FileChange(BaseModel):
|
|
52
|
+
"""A changed file with its symbol-level changes."""
|
|
53
|
+
|
|
54
|
+
path: str
|
|
55
|
+
language: str | None = None
|
|
56
|
+
change_type: Literal["added", "removed", "modified", "renamed"]
|
|
57
|
+
generated: bool = False
|
|
58
|
+
binary: bool = False
|
|
59
|
+
parse_error: bool = False
|
|
60
|
+
unsupported_language: bool = False
|
|
61
|
+
changes: list[SymbolChange] = []
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Summary(BaseModel):
|
|
65
|
+
"""Aggregate summary of changes.
|
|
66
|
+
|
|
67
|
+
Migration note (v1.0 → v1.1): Added ``focus`` field — a short list of
|
|
68
|
+
the most important items for reviewer agents. Existing consumers that
|
|
69
|
+
ignore unknown fields are unaffected.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
change_types: dict[str, int] = {}
|
|
73
|
+
breaking_changes: list[SymbolChange] = []
|
|
74
|
+
focus: list[str] = []
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class TieredSummary(BaseModel):
|
|
78
|
+
"""Multi-tier human-readable summary."""
|
|
79
|
+
|
|
80
|
+
oneliner: str = ""
|
|
81
|
+
short: str = ""
|
|
82
|
+
detailed: str = ""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class DiffGuardOutput(BaseModel):
|
|
86
|
+
"""Top-level DiffGuard output."""
|
|
87
|
+
|
|
88
|
+
schema_version: str = "1.1"
|
|
89
|
+
meta: Meta
|
|
90
|
+
files: list[FileChange] = []
|
|
91
|
+
summary: Summary = Summary()
|
|
92
|
+
tiered: TieredSummary = TieredSummary()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def export_json_schema() -> str:
|
|
96
|
+
"""Export the JSON schema as a string."""
|
|
97
|
+
return json.dumps(DiffGuardOutput.model_json_schema(), indent=2)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: diffguard
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Catches the structural breaks that pass code review
|
|
5
|
+
Project-URL: Homepage, https://github.com/ostehost/diffguard
|
|
6
|
+
Project-URL: Repository, https://github.com/ostehost/diffguard
|
|
7
|
+
Project-URL: Issues, https://github.com/ostehost/diffguard/issues
|
|
8
|
+
Author: ostehost
|
|
9
|
+
License: BSL-1.1
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,ai,code-intelligence,code-review,git,tree-sitter
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: Other/Proprietary License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: click>=8.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0
|
|
25
|
+
Requires-Dist: rich>=13.0
|
|
26
|
+
Requires-Dist: tree-sitter-go
|
|
27
|
+
Requires-Dist: tree-sitter-javascript
|
|
28
|
+
Requires-Dist: tree-sitter-python
|
|
29
|
+
Requires-Dist: tree-sitter-typescript>=0.23.2
|
|
30
|
+
Requires-Dist: tree-sitter>=0.24
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/diffguard/)
|
|
34
|
+
[](LICENSE)
|
|
35
|
+
[](https://pypi.org/project/diffguard/)
|
|
36
|
+
|
|
37
|
+
# DiffGuard
|
|
38
|
+
|
|
39
|
+
**Catches the structural breaks that pass code review.**
|
|
40
|
+
|
|
41
|
+
## A real bug, in one line
|
|
42
|
+
|
|
43
|
+
This diff shipped in Flask ([PR #5898](https://github.com/pallets/flask/pull/5898)):
|
|
44
|
+
|
|
45
|
+
```diff
|
|
46
|
+
-def redirect(location, code=302, ...):
|
|
47
|
+
+def redirect(location, code=303, ...):
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
One line. Looks fine. A reviewer approves it.
|
|
51
|
+
|
|
52
|
+
**The real impact:** 7 endpoints silently change HTTP behavior. POST-to-POST redirects become POST-to-GET. No errors. No warnings. Just broken APIs in production.
|
|
53
|
+
|
|
54
|
+
**DiffGuard catches it:**
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
$ diffguard review eca5fd1d~1..eca5fd1d
|
|
58
|
+
|
|
59
|
+
⚠ DiffGuard: 2 changes need review
|
|
60
|
+
|
|
61
|
+
DEFAULT VALUE CHANGED: redirect(location, code=302) → redirect(location, code=303)
|
|
62
|
+
src/flask/helpers.py:241 — 7 callers rely on the default
|
|
63
|
+
|
|
64
|
+
DEFAULT VALUE CHANGED: App.redirect(self, location, code=302) → App.redirect(self, location, code=303)
|
|
65
|
+
src/flask/sansio/app.py:935 — 7 callers rely on the default
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Tree-sitter AST analysis. No LLM. No network calls. Runs in seconds.
|
|
69
|
+
|
|
70
|
+
## What it catches
|
|
71
|
+
|
|
72
|
+
Function signature changes, removed/renamed symbols, default value changes — and shows you every caller affected.
|
|
73
|
+
|
|
74
|
+
## What it doesn't catch
|
|
75
|
+
|
|
76
|
+
Logic bugs, behavioral changes beyond signatures, performance issues, security vulnerabilities. DiffGuard detects **structural breaks**, not all bugs.
|
|
77
|
+
|
|
78
|
+
When there's nothing structural to report, it stays silent (exit code 0, no output).
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install diffguard
|
|
84
|
+
diffguard review main..feature
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Exit codes: `0` = nothing noteworthy, `1` = findings, `2` = error.
|
|
88
|
+
|
|
89
|
+
## How It Works
|
|
90
|
+
|
|
91
|
+
1. **Parses the diff** using tree-sitter AST analysis (not regex)
|
|
92
|
+
2. **Extracts symbols** — functions, classes, signatures
|
|
93
|
+
3. **Detects high-signal changes** — signature changes, removed symbols, default value changes
|
|
94
|
+
4. **Scans for callers** — finds every file that references changed symbols
|
|
95
|
+
5. **Outputs actionable context** — or stays silent if nothing matters
|
|
96
|
+
|
|
97
|
+
## Agent Integration
|
|
98
|
+
|
|
99
|
+
Works with **Claude Code**, **Cursor**, **GitHub Actions**, or any agent that can run a CLI command.
|
|
100
|
+
|
|
101
|
+
Add one line to your agent config — DiffGuard is silent when nothing matters.
|
|
102
|
+
|
|
103
|
+
See the full [Agent Integration Guide](docs/agent-integration.md) for hooks, CI patterns, and snippets for [Claude Code](docs/claude-md-snippet.md) and [Cursor](docs/cursor-rule-snippet.md).
|
|
104
|
+
|
|
105
|
+
## GitHub Action
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
# .github/workflows/diffguard.yml
|
|
109
|
+
name: DiffGuard PR Review
|
|
110
|
+
on:
|
|
111
|
+
pull_request:
|
|
112
|
+
types: [opened, synchronize, reopened]
|
|
113
|
+
permissions:
|
|
114
|
+
contents: read
|
|
115
|
+
pull-requests: write
|
|
116
|
+
jobs:
|
|
117
|
+
diffguard:
|
|
118
|
+
runs-on: ubuntu-latest
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@v4
|
|
121
|
+
with:
|
|
122
|
+
fetch-depth: 0
|
|
123
|
+
- uses: ostehost/diffguard@main
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Languages
|
|
127
|
+
|
|
128
|
+
- **Python** (most mature — extensive real-world validation)
|
|
129
|
+
- TypeScript / JavaScript
|
|
130
|
+
- Go
|
|
131
|
+
- More planned (Rust, Java, C#)
|
|
132
|
+
|
|
133
|
+
## Philosophy
|
|
134
|
+
|
|
135
|
+
1. **Silence is a feature.** No findings? No output. Most diffs don't need structural analysis.
|
|
136
|
+
2. **Local-first.** Your code never leaves your machine. No SaaS, no API keys, no accounts.
|
|
137
|
+
3. **Agent-native.** CLI + JSON output. `pip install` and go.
|
|
138
|
+
4. **Precision over recall.** We'd rather miss a minor issue than cry wolf on every PR.
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
BSL 1.1 — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
diffguard/__init__.py,sha256=_vw6s8kAEZEWKaqdJTNGBUPL6gW1ywfRcUIcq-hbtYs,87
|
|
2
|
+
diffguard/cli.py,sha256=GqmApvmyNXnR1lxuVH4CoXnkg7U7P7MdMPJWzDCQbYk,23389
|
|
3
|
+
diffguard/git.py,sha256=b8SvW0jDh91NHslqbIVsGaGeM7jW3Ew9jjqVQ2laBP4,9786
|
|
4
|
+
diffguard/schema.py,sha256=aQPtehSqeA0UjKnuBhiNbSOZ8Pjv67QI9lyZ-xx8NYs,2258
|
|
5
|
+
diffguard/engine/__init__.py,sha256=8KkxYzAC3ZMTBiP5ysv1LlPXW4XMNf5GJ6K7aTyXmlc,33
|
|
6
|
+
diffguard/engine/_types.py,sha256=LgzAH20Z7a4mRezb_DodPBcD5ldnS4wDSRrd4NiGwo4,990
|
|
7
|
+
diffguard/engine/classifier.py,sha256=OXjvXnn3x5O99DPAg9nXFQ2LPkR4hQNP0gHl0_HoBOY,2637
|
|
8
|
+
diffguard/engine/deps.py,sha256=6rZiwm2MdicefKbveD2-2fIq2A7DtkU2r5M9dvuTjOY,6214
|
|
9
|
+
diffguard/engine/matcher.py,sha256=iYhLGLRGEt0qTejuWQB-AWKU5Y_2Fg9J7kFjZHmKbJ4,4220
|
|
10
|
+
diffguard/engine/parser.py,sha256=hzSNAI1c4rCboPLLszGF_Dil1EygFAXdE5PpDcB_B4c,1338
|
|
11
|
+
diffguard/engine/pipeline.py,sha256=-hhOyP7YyUoxfuCZWhoOc-zkoxJLSnKtRONvpv540gM,6508
|
|
12
|
+
diffguard/engine/signatures.py,sha256=cybi_p1pmWW_UOergRmRLM32xKOBc3GPLdOjHJcHcAU,8545
|
|
13
|
+
diffguard/engine/summarizer.py,sha256=ffkotlB_XwLP_YcREL5CI88L9j4etvXRT9_WwyQcZHs,13387
|
|
14
|
+
diffguard/languages/__init__.py,sha256=1vjO-694V0j6rBI5erxr5G2ctMl03_WpAC-xSsjTLy0,1485
|
|
15
|
+
diffguard/languages/_utils.py,sha256=XVStFVZpdcSVLgOxvpti9dT548SSNF8M_DralHO9Bts,294
|
|
16
|
+
diffguard/languages/go/__init__.py,sha256=kJOi4WWgrVSejQHegPBkHzTRrPuhjItfeIzO0u-r4B4,3466
|
|
17
|
+
diffguard/languages/go/queries.scm,sha256=5mEellIGMjVR7qA4Xt9LlpNEok7G1nfpxPg0vhcW2iQ,41
|
|
18
|
+
diffguard/languages/python/__init__.py,sha256=93M37cZwFjmGLdeXozVVtzBysRTuYTT77LrsZd3jSEo,6480
|
|
19
|
+
diffguard/languages/python/queries.scm,sha256=bv8GYn2bpL6lXW3OcVOEow-nZE3bdX1s3N2QYmyn21s,45
|
|
20
|
+
diffguard/languages/typescript/__init__.py,sha256=bkYxwkcxCCgRsdrUQ5zFjCbU_y4Lm6GFRZN74gHd1bc,6001
|
|
21
|
+
diffguard/languages/typescript/queries.scm,sha256=dJ6ZUwxpwDfDlj7e6irC5ivILomaocttuvAEcf5Nqz8,49
|
|
22
|
+
diffguard-0.1.3.dist-info/METADATA,sha256=OY8KSTYzKCB4MbPrqsDJqtgXNiyEqnYgw3DZ4teYtU4,4783
|
|
23
|
+
diffguard-0.1.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
24
|
+
diffguard-0.1.3.dist-info/entry_points.txt,sha256=iWYD-Yd6-jOpBE08rQv8I1SQsfCJ3BNWp4jh4sSPy84,49
|
|
25
|
+
diffguard-0.1.3.dist-info/licenses/LICENSE,sha256=lOYMmmcw26-zTcgA3ptu-f653iWyb9qO2LRPgu0R9gg,2508
|
|
26
|
+
diffguard-0.1.3.dist-info/RECORD,,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: ostehost
|
|
6
|
+
Licensed Work: DiffGuard v0.1.1 (and all subsequent versions)
|
|
7
|
+
Additional Use Grant: You may use the Licensed Work for any purpose other
|
|
8
|
+
than offering the functionality of the Licensed Work
|
|
9
|
+
to third parties as a managed or hosted service.
|
|
10
|
+
Change Date: 2029-02-11
|
|
11
|
+
Change License: Apache License 2.0
|
|
12
|
+
|
|
13
|
+
Terms
|
|
14
|
+
|
|
15
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
16
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
17
|
+
Licensor may make an Additional Use Grant, above, permitting limited
|
|
18
|
+
production use.
|
|
19
|
+
|
|
20
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
21
|
+
available distribution of a specific version of the Licensed Work under this
|
|
22
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
23
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
24
|
+
above terminate.
|
|
25
|
+
|
|
26
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
27
|
+
currently in effect as described in this License, you must purchase a
|
|
28
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
29
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
30
|
+
|
|
31
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
32
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
33
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
34
|
+
for each version of the Licensed Work released by Licensor.
|
|
35
|
+
|
|
36
|
+
You must conspicuously display this License on each original or modified copy
|
|
37
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
38
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
39
|
+
License apply to your use of that work.
|
|
40
|
+
|
|
41
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
42
|
+
terminate your rights under this License for the current and all other
|
|
43
|
+
versions of the Licensed Work.
|
|
44
|
+
|
|
45
|
+
This License does not grant you any right in any trademark or logo of
|
|
46
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
47
|
+
Licensor as expressly required by this License).
|
|
48
|
+
|
|
49
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
50
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
51
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
52
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
53
|
+
TITLE.
|