devguard-scanner 0.2.0__tar.gz → 0.3.0__tar.gz
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.
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/CHANGELOG.md +11 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/PKG-INFO +3 -3
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/README.md +2 -2
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/__init__.py +1 -1
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/api/local.py +3 -3
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/api/settings.py +2 -2
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/cli.py +2 -2
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/core/config.py +25 -10
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_report_cli.py +14 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/.gitignore +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/LICENSE +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/docs/README.md +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/pyproject.toml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/investigator.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/prompts.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/providers/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/providers/anthropic.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/providers/openai_compat.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/registry.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/run.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/sdk.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/testing.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/tools.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/base.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/carriers.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/command.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/content.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/filesystem.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/hidden.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/imports.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/jsonc.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/source.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/ai_assistants.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/autoload.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/common.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/deps.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/devcontainer.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/env.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/git.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/npm.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/python_pkg.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/vscode.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/api/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/api/app.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/api/executor.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/api/limits.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/api/schemas.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/api/traffic.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/api/worker.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/core/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/core/filetype.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/core/models.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/core/redact.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/core/safefs.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/core/scoring.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/core/service.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/correlate/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/correlate/chains.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/mcp/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/mcp/server.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/remote/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/remote/archive.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/remote/errors.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/remote/fetch.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/remote/github.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/remote/url.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/report/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/report/escape.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/report/markdown.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/report/sarif.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/report/terminal.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/report/writer.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/catalog.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/ai_instructions.yaml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/cross_language.yaml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/docs.yaml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/javascript.yaml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/obfuscation.yaml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/python.yaml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/shell.yaml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/windows.yaml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/data/vscode_settings.yaml +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/conftest.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/corpus/__init__.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/corpus/samples.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/github_fakes.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_ai.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_api.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_corpus.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_mcp.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_parsers.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_remote.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_rules.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_safefs.py +0 -0
- {devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/tests/test_safety.py +0 -0
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/) and
|
|
4
4
|
the project uses [semantic versioning](https://semver.org).
|
|
5
5
|
|
|
6
|
+
## 0.3.0
|
|
7
|
+
|
|
8
|
+
- The default drop folder for local scans (`DEVGUARD_API_LOCAL_ROOT`, and the folder `compose.yaml` mounts) is
|
|
9
|
+
now `~/devguard-scanner-data` instead of `~/devguard-scanner`. Move the folder, or set the variable to keep
|
|
10
|
+
the old location.
|
|
11
|
+
- File locations use `devguard-scanner` (only the command is still `devguard`): config
|
|
12
|
+
`~/.config/devguard-scanner/config.toml` (the old `~/.config/devguard/config.toml` is still read if the new one
|
|
13
|
+
is missing), app data `~/.local/share/devguard-scanner/` (AI consent and cache, MCP audit log), and reports
|
|
14
|
+
`~/devguard-scanner/reports/` on every OS. In the container image the config is
|
|
15
|
+
`/etc/devguard-scanner/config.toml`.
|
|
16
|
+
|
|
6
17
|
## 0.2.0
|
|
7
18
|
|
|
8
19
|
Remote scanning, the HTTP API, and the container image.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: devguard-scanner
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Scan untrusted code repositories for malware before you open, install, or run them. Files are analyzed as data and never executed.
|
|
5
5
|
Project-URL: Homepage, https://github.com/yilmazhasan/devguard-scanner
|
|
6
6
|
Project-URL: Documentation, https://github.com/yilmazhasan/devguard-scanner/tree/main/docs
|
|
@@ -65,7 +65,7 @@ Findings: 5 (1 critical, 2 high, 1 medium, 1 low)
|
|
|
65
65
|
- [critical] Automatic trigger reaches dangerous code (package.json:5)
|
|
66
66
|
- [high] Browser profile data targeted (lib/collect.js:7)
|
|
67
67
|
- [high] Cryptocurrency wallet data targeted (lib/collect.js:10)
|
|
68
|
-
Report (md):
|
|
68
|
+
Report (md): ~/devguard-scanner/reports/interview-task-1a2b3c4d/latest/report.md
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
| Verdict | Meaning |
|
|
@@ -96,7 +96,7 @@ curl -s 'https://devguard-scanner.vercel.app/v1/scans/github/owner/repo?format=m
|
|
|
96
96
|
# one-off scan in a throwaway container
|
|
97
97
|
docker run --rm ghcr.io/yilmazhasan/devguard-scanner scan https://github.com/owner/repo --stdout md
|
|
98
98
|
|
|
99
|
-
# self-hosted API, plus local scans of anything you copy into ~/devguard-scanner (mounted read-only)
|
|
99
|
+
# self-hosted API, plus local scans of anything you copy into ~/devguard-scanner-data (mounted read-only)
|
|
100
100
|
docker compose up -d
|
|
101
101
|
```
|
|
102
102
|
|
|
@@ -27,7 +27,7 @@ Findings: 5 (1 critical, 2 high, 1 medium, 1 low)
|
|
|
27
27
|
- [critical] Automatic trigger reaches dangerous code (package.json:5)
|
|
28
28
|
- [high] Browser profile data targeted (lib/collect.js:7)
|
|
29
29
|
- [high] Cryptocurrency wallet data targeted (lib/collect.js:10)
|
|
30
|
-
Report (md):
|
|
30
|
+
Report (md): ~/devguard-scanner/reports/interview-task-1a2b3c4d/latest/report.md
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
| Verdict | Meaning |
|
|
@@ -58,7 +58,7 @@ curl -s 'https://devguard-scanner.vercel.app/v1/scans/github/owner/repo?format=m
|
|
|
58
58
|
# one-off scan in a throwaway container
|
|
59
59
|
docker run --rm ghcr.io/yilmazhasan/devguard-scanner scan https://github.com/owner/repo --stdout md
|
|
60
60
|
|
|
61
|
-
# self-hosted API, plus local scans of anything you copy into ~/devguard-scanner (mounted read-only)
|
|
61
|
+
# self-hosted API, plus local scans of anything you copy into ~/devguard-scanner-data (mounted read-only)
|
|
62
62
|
docker compose up -d
|
|
63
63
|
```
|
|
64
64
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Local scans for a self-hosted API: directories inside one drop folder (DEVGUARD_API_LOCAL_ROOT).
|
|
2
2
|
|
|
3
|
-
Put a repository into the drop folder (default ~/devguard-scanner; /workspace in Docker, mounted read-only) and
|
|
3
|
+
Put a repository into the drop folder (default ~/devguard-scanner-data; /workspace in Docker, mounted read-only) and
|
|
4
4
|
ask the API to scan it by name. Instead of copying, a top-level entry may be a symlink to the repository
|
|
5
|
-
(`ln -s /path/to/repo ~/devguard-scanner/repo`); in Docker, bind-mount it instead
|
|
5
|
+
(`ln -s /path/to/repo ~/devguard-scanner-data/repo`); in Docker, bind-mount it instead
|
|
6
6
|
(`-v /path/to/repo:/workspace/repo:ro`), since the container cannot see symlink targets on the host.
|
|
7
7
|
|
|
8
8
|
Only what you put there is reachable: names are relative, `..` and absolute paths are refused, and symlinks
|
|
@@ -47,7 +47,7 @@ def resolve_local(root: Path, name: str) -> Path:
|
|
|
47
47
|
st = os.lstat(current)
|
|
48
48
|
except FileNotFoundError:
|
|
49
49
|
raise LocalPathError(404, "not_found", f"{first!r} is not in the drop folder") from None
|
|
50
|
-
if stat.S_ISLNK(st.st_mode): # a link
|
|
50
|
+
if stat.S_ISLNK(st.st_mode): # a link placed in the drop folder: ln -s ~/code/repo ~/devguard-scanner-data/
|
|
51
51
|
try:
|
|
52
52
|
current = current.resolve(strict=True)
|
|
53
53
|
except (OSError, RuntimeError):
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
DEVGUARD_API_<NAME> overrides one field, e.g. DEVGUARD_API_MAX_REPO_MB=200
|
|
5
5
|
DEVGUARD_GITHUB_TOKEN GitHub token without scopes (5,000 API requests/hour instead of 60)
|
|
6
6
|
DEVGUARD_API_MONGODB_URI (or MONGODB_URI) enables the request log in MongoDB
|
|
7
|
-
DEVGUARD_API_LOCAL_ROOT drop folder for local scans (default ~/devguard-scanner; ignored by the public profile)
|
|
7
|
+
DEVGUARD_API_LOCAL_ROOT drop folder for local scans (default ~/devguard-scanner-data; ignored by the public profile)
|
|
8
8
|
|
|
9
9
|
Nothing in a request can change these.
|
|
10
10
|
"""
|
|
@@ -51,7 +51,7 @@ class APISettings(BaseModel):
|
|
|
51
51
|
ai_max_cost_usd: float = 1.0
|
|
52
52
|
github_token: SecretStr | None = None
|
|
53
53
|
# Self-host only: scan directories copied into this drop folder (POST /v1/scans/local). Never public.
|
|
54
|
-
local_root: str | None = "~/devguard-scanner"
|
|
54
|
+
local_root: str | None = "~/devguard-scanner-data"
|
|
55
55
|
# request log (optional; see devguard.api.traffic)
|
|
56
56
|
mongodb_uri: SecretStr | None = None
|
|
57
57
|
mongodb_db: str = "devguard"
|
|
@@ -342,10 +342,10 @@ def _doctor() -> int:
|
|
|
342
342
|
import platform
|
|
343
343
|
|
|
344
344
|
from devguard.ai.registry import AIConfig, available_entry_points
|
|
345
|
-
from devguard.core.config import
|
|
345
|
+
from devguard.core.config import user_config_file
|
|
346
346
|
|
|
347
347
|
print(f"devguard {__version__}, ruleset {RULESET_VERSION}, Python {platform.python_version()}")
|
|
348
|
-
cfg_file =
|
|
348
|
+
cfg_file = user_config_file()
|
|
349
349
|
print(f"User config: {cfg_file} ({'found' if cfg_file.is_file() else 'not found'})")
|
|
350
350
|
try:
|
|
351
351
|
cfg = load_config(None, None)
|
|
@@ -51,22 +51,37 @@ class ScanConfig(BaseModel):
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
APP_DIR = "devguard-scanner" # directory name for config, data, and reports; only the command is `devguard`
|
|
55
|
+
_LEGACY_APP_DIR = "devguard" # used up to 0.2.0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def user_config_dir(name: str = APP_DIR) -> Path:
|
|
55
59
|
if sys.platform == "win32":
|
|
56
60
|
base = os.environ.get("APPDATA") or str(Path.home() / "AppData" / "Roaming")
|
|
57
|
-
return Path(base) /
|
|
61
|
+
return Path(base) / name
|
|
58
62
|
if sys.platform == "darwin":
|
|
59
|
-
return Path.home() / "Library" / "Application Support" /
|
|
60
|
-
return Path(os.environ.get("XDG_CONFIG_HOME") or Path.home() / ".config") /
|
|
63
|
+
return Path.home() / "Library" / "Application Support" / name
|
|
64
|
+
return Path(os.environ.get("XDG_CONFIG_HOME") or Path.home() / ".config") / name
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def user_config_file() -> Path:
|
|
68
|
+
"""The user config file, falling back to the pre-0.3 location when only that one exists."""
|
|
69
|
+
current = user_config_dir() / "config.toml"
|
|
70
|
+
legacy = user_config_dir(_LEGACY_APP_DIR) / "config.toml"
|
|
71
|
+
return legacy if not current.is_file() and legacy.is_file() else current
|
|
61
72
|
|
|
62
73
|
|
|
63
74
|
def user_data_dir() -> Path:
|
|
64
75
|
if sys.platform == "win32":
|
|
65
76
|
base = os.environ.get("LOCALAPPDATA") or str(Path.home() / "AppData" / "Local")
|
|
66
|
-
return Path(base) /
|
|
77
|
+
return Path(base) / APP_DIR
|
|
67
78
|
if sys.platform == "darwin":
|
|
68
|
-
return Path.home() / "Library" / "Application Support" /
|
|
69
|
-
return Path(os.environ.get("XDG_DATA_HOME") or Path.home() / ".local" / "share") /
|
|
79
|
+
return Path.home() / "Library" / "Application Support" / APP_DIR
|
|
80
|
+
return Path(os.environ.get("XDG_DATA_HOME") or Path.home() / ".local" / "share") / APP_DIR
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def reports_dir() -> Path:
|
|
84
|
+
return Path.home() / APP_DIR / "reports"
|
|
70
85
|
|
|
71
86
|
|
|
72
87
|
def is_within(path: Path, root: Path) -> bool:
|
|
@@ -80,11 +95,11 @@ def is_within(path: Path, root: Path) -> bool:
|
|
|
80
95
|
def default_output_dir(target: Path) -> Path:
|
|
81
96
|
resolved = target.resolve()
|
|
82
97
|
digest = hashlib.sha256(str(resolved).encode()).hexdigest()[:8]
|
|
83
|
-
return
|
|
98
|
+
return reports_dir() / f"{resolved.name or 'root'}-{digest}"
|
|
84
99
|
|
|
85
100
|
|
|
86
101
|
def remote_output_dir(owner: str, repo: str) -> Path:
|
|
87
|
-
return
|
|
102
|
+
return reports_dir() / f"github-{owner}-{repo}"
|
|
88
103
|
|
|
89
104
|
|
|
90
105
|
def _read_toml(path: Path, target: Path | None) -> dict[str, Any]:
|
|
@@ -108,7 +123,7 @@ def load_config(
|
|
|
108
123
|
overrides: dict[str, Any] | None = None,
|
|
109
124
|
) -> ScanConfig:
|
|
110
125
|
data: dict[str, Any] = {}
|
|
111
|
-
user_file =
|
|
126
|
+
user_file = user_config_file()
|
|
112
127
|
if user_file.is_file():
|
|
113
128
|
data = _merge(data, _read_toml(user_file, target))
|
|
114
129
|
if explicit is not None:
|
|
@@ -116,3 +116,17 @@ def test_example_config_is_valid(tmp_path: Path) -> None:
|
|
|
116
116
|
ai = AIConfig.model_validate(cfg.ai)
|
|
117
117
|
assert set(ai.profiles) == {"claude", "gpt", "local"}
|
|
118
118
|
assert cfg.mcp["allowed_roots"] == ["~/code"]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_user_config_falls_back_to_legacy_dir(tmp_path, monkeypatch) -> None:
|
|
122
|
+
from devguard.core.config import user_config_file
|
|
123
|
+
|
|
124
|
+
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path))
|
|
125
|
+
legacy = tmp_path / "devguard" / "config.toml"
|
|
126
|
+
legacy.parent.mkdir()
|
|
127
|
+
legacy.write_text("[scan]\n")
|
|
128
|
+
assert user_config_file() == legacy
|
|
129
|
+
current = tmp_path / "devguard-scanner" / "config.toml"
|
|
130
|
+
current.parent.mkdir()
|
|
131
|
+
current.write_text("[scan]\n")
|
|
132
|
+
assert user_config_file() == current
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/ai/providers/openai_compat.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/__init__.py
RENAMED
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/ai_assistants.py
RENAMED
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/autoload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/devcontainer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/analyzers/surfaces/python_pkg.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/ai_instructions.yaml
RENAMED
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/cross_language.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/javascript.yaml
RENAMED
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/content/obfuscation.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{devguard_scanner-0.2.0 → devguard_scanner-0.3.0}/src/devguard/rules/data/vscode_settings.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|