appledger 0.1.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.
- appledger-0.1.0/.gitignore +20 -0
- appledger-0.1.0/LICENSE +21 -0
- appledger-0.1.0/PKG-INFO +98 -0
- appledger-0.1.0/README.md +73 -0
- appledger-0.1.0/plugin/LICENSE +21 -0
- appledger-0.1.0/plugin/README.md +26 -0
- appledger-0.1.0/pyproject.toml +44 -0
- appledger-0.1.0/src/appledger/__init__.py +6 -0
- appledger-0.1.0/src/appledger/__main__.py +3 -0
- appledger-0.1.0/src/appledger/client.py +78 -0
- appledger-0.1.0/src/appledger/scanner.py +851 -0
- appledger-0.1.0/src/appledger/server.py +145 -0
- appledger-0.1.0/src/appledger/service.py +61 -0
- appledger-0.1.0/src/appledger/usage.py +219 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
|
|
10
|
+
# AppLedger check output
|
|
11
|
+
.appledger/
|
|
12
|
+
|
|
13
|
+
# Local deploy settings (server, key, site)
|
|
14
|
+
deploy/.env.local
|
|
15
|
+
|
|
16
|
+
# Editors and OS
|
|
17
|
+
.vscode/
|
|
18
|
+
.idea/
|
|
19
|
+
.DS_Store
|
|
20
|
+
Thumbs.db
|
appledger-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Contenta Software
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
appledger-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: appledger
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The ledger for the AI app explosion: honest security checks, in plain language, for apps your people build with AI.
|
|
5
|
+
Project-URL: Homepage, https://appledger.net/
|
|
6
|
+
Project-URL: Repository, https://github.com/contentasoftware/appledger
|
|
7
|
+
Project-URL: Privacy, https://appledger.net/privacy.html
|
|
8
|
+
Author: Contenta Software
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: claude,codex,governance,mcp,opengrep,security,trivy,vibe-coding
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Information Technology
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Topic :: Security
|
|
18
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: anyio>=4
|
|
21
|
+
Requires-Dist: mcp<2,>=1.20
|
|
22
|
+
Requires-Dist: packaging>=23
|
|
23
|
+
Requires-Dist: pyyaml>=6
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# AppLedger honest check
|
|
27
|
+
|
|
28
|
+
Honest security feedback, in plain language, for apps people build with AI tools such as Claude Code, Codex, Cursor and Lovable.
|
|
29
|
+
|
|
30
|
+
AppLedger checks your app folder with independent scanners and explains what they find in everyday words: what is wrong, why it matters, and what to do. It also writes a fix request you can hand straight to the AI tool that built the app, then checks again.
|
|
31
|
+
|
|
32
|
+
## What it checks
|
|
33
|
+
|
|
34
|
+
| Scanner | Finds |
|
|
35
|
+
|---|---|
|
|
36
|
+
| [Trivy](https://trivy.dev) | Leaked passwords and keys, outdated libraries with known security problems, risky container setup |
|
|
37
|
+
| [Opengrep](https://github.com/opengrep/opengrep) | Dangerous code patterns: SQL injection, command injection, unsafe data loading, debug mode left on |
|
|
38
|
+
| SonarQube (optional, local mode) | Code quality and more security hotspots, if you already run a SonarQube server |
|
|
39
|
+
|
|
40
|
+
Each run produces, in `<your-app>/.appledger/`:
|
|
41
|
+
|
|
42
|
+
- `report.html`: a score, who may use the app right now (only you, your team, the whole company), and every problem in plain words
|
|
43
|
+
- `fix-prompt.md`: a ready-made fix request for your coding agent
|
|
44
|
+
- `findings.json`: the same findings for tools and dashboards
|
|
45
|
+
|
|
46
|
+
## AI effort behind the app
|
|
47
|
+
|
|
48
|
+
Every check also reports how many AI tokens went into the app and what they would cost at API list prices. It reads the coding agents' own logs on your computer (Claude Code in `~/.claude/projects`, Codex in `~/.codex/sessions`), counts sessions that ran in the app's folder, and prices each reply by model, including cache reads and writes. These logs never leave your computer. On a flat-rate plan (Claude Pro, Max or Team) you pay your plan price instead, so the figure shows the work's value at API rates.
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
python -m appledger path/to/your-app --ai-cost
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Codex support follows Codex's documented log format and hasn't been tested against real Codex logs yet.
|
|
55
|
+
|
|
56
|
+
## Two ways to run
|
|
57
|
+
|
|
58
|
+
| Mode | What you install | Where your code goes |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| **Hosted** (default) | Only this package | Source files are zipped, sent over HTTPS to the AppLedger service, scanned and deleted right after |
|
|
61
|
+
| **Local** (`--local` or `APPLEDGER_MODE=local`) | Also Trivy, Opengrep and the Opengrep rules | Nowhere: everything runs on your computer |
|
|
62
|
+
|
|
63
|
+
## Use it
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
pip install appledger
|
|
67
|
+
python -m appledger path/to/your-app
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Add it to Claude Code as an MCP server:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
claude mcp add appledger -- uvx --from appledger appledger-mcp
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Then ask: "Is my app safe to share?" Or install the full plugin with the guided skill from `plugin/`.
|
|
77
|
+
|
|
78
|
+
## Local mode setup
|
|
79
|
+
|
|
80
|
+
1. Trivy: `winget install AquaSecurity.Trivy` (Windows) or `brew install trivy` (Mac)
|
|
81
|
+
2. Opengrep: download from the [releases page](https://github.com/opengrep/opengrep/releases) and put it on your PATH
|
|
82
|
+
3. Rules: `git clone --depth 1 https://github.com/opengrep/opengrep-rules.git ~/.appledger/opengrep-rules`
|
|
83
|
+
4. Check: `python -m appledger --doctor`
|
|
84
|
+
|
|
85
|
+
## Repository layout
|
|
86
|
+
|
|
87
|
+
| Path | What |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `src/appledger/scanner.py` | Scanners, plain-language translation, report and fix request |
|
|
90
|
+
| `src/appledger/client.py` | Sends a project to the hosted service |
|
|
91
|
+
| `src/appledger/service.py` | Server side: unpacks an upload safely and scans it |
|
|
92
|
+
| `src/appledger/server.py` | Local MCP server used by the plugin |
|
|
93
|
+
| `plugin/` | Claude Code / Codex plugin with the `check-my-app` skill |
|
|
94
|
+
| `tests/mcp_smoke.py` | Calls every MCP tool like an agent would |
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT. The Opengrep community rules used by the scanner have their own license (Commons Clause); check it before using them in a paid service.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# AppLedger honest check
|
|
2
|
+
|
|
3
|
+
Honest security feedback, in plain language, for apps people build with AI tools such as Claude Code, Codex, Cursor and Lovable.
|
|
4
|
+
|
|
5
|
+
AppLedger checks your app folder with independent scanners and explains what they find in everyday words: what is wrong, why it matters, and what to do. It also writes a fix request you can hand straight to the AI tool that built the app, then checks again.
|
|
6
|
+
|
|
7
|
+
## What it checks
|
|
8
|
+
|
|
9
|
+
| Scanner | Finds |
|
|
10
|
+
|---|---|
|
|
11
|
+
| [Trivy](https://trivy.dev) | Leaked passwords and keys, outdated libraries with known security problems, risky container setup |
|
|
12
|
+
| [Opengrep](https://github.com/opengrep/opengrep) | Dangerous code patterns: SQL injection, command injection, unsafe data loading, debug mode left on |
|
|
13
|
+
| SonarQube (optional, local mode) | Code quality and more security hotspots, if you already run a SonarQube server |
|
|
14
|
+
|
|
15
|
+
Each run produces, in `<your-app>/.appledger/`:
|
|
16
|
+
|
|
17
|
+
- `report.html`: a score, who may use the app right now (only you, your team, the whole company), and every problem in plain words
|
|
18
|
+
- `fix-prompt.md`: a ready-made fix request for your coding agent
|
|
19
|
+
- `findings.json`: the same findings for tools and dashboards
|
|
20
|
+
|
|
21
|
+
## AI effort behind the app
|
|
22
|
+
|
|
23
|
+
Every check also reports how many AI tokens went into the app and what they would cost at API list prices. It reads the coding agents' own logs on your computer (Claude Code in `~/.claude/projects`, Codex in `~/.codex/sessions`), counts sessions that ran in the app's folder, and prices each reply by model, including cache reads and writes. These logs never leave your computer. On a flat-rate plan (Claude Pro, Max or Team) you pay your plan price instead, so the figure shows the work's value at API rates.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
python -m appledger path/to/your-app --ai-cost
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Codex support follows Codex's documented log format and hasn't been tested against real Codex logs yet.
|
|
30
|
+
|
|
31
|
+
## Two ways to run
|
|
32
|
+
|
|
33
|
+
| Mode | What you install | Where your code goes |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| **Hosted** (default) | Only this package | Source files are zipped, sent over HTTPS to the AppLedger service, scanned and deleted right after |
|
|
36
|
+
| **Local** (`--local` or `APPLEDGER_MODE=local`) | Also Trivy, Opengrep and the Opengrep rules | Nowhere: everything runs on your computer |
|
|
37
|
+
|
|
38
|
+
## Use it
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
pip install appledger
|
|
42
|
+
python -m appledger path/to/your-app
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Add it to Claude Code as an MCP server:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
claude mcp add appledger -- uvx --from appledger appledger-mcp
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Then ask: "Is my app safe to share?" Or install the full plugin with the guided skill from `plugin/`.
|
|
52
|
+
|
|
53
|
+
## Local mode setup
|
|
54
|
+
|
|
55
|
+
1. Trivy: `winget install AquaSecurity.Trivy` (Windows) or `brew install trivy` (Mac)
|
|
56
|
+
2. Opengrep: download from the [releases page](https://github.com/opengrep/opengrep/releases) and put it on your PATH
|
|
57
|
+
3. Rules: `git clone --depth 1 https://github.com/opengrep/opengrep-rules.git ~/.appledger/opengrep-rules`
|
|
58
|
+
4. Check: `python -m appledger --doctor`
|
|
59
|
+
|
|
60
|
+
## Repository layout
|
|
61
|
+
|
|
62
|
+
| Path | What |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `src/appledger/scanner.py` | Scanners, plain-language translation, report and fix request |
|
|
65
|
+
| `src/appledger/client.py` | Sends a project to the hosted service |
|
|
66
|
+
| `src/appledger/service.py` | Server side: unpacks an upload safely and scans it |
|
|
67
|
+
| `src/appledger/server.py` | Local MCP server used by the plugin |
|
|
68
|
+
| `plugin/` | Claude Code / Codex plugin with the `check-my-app` skill |
|
|
69
|
+
| `tests/mcp_smoke.py` | Calls every MCP tool like an agent would |
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT. The Opengrep community rules used by the scanner have their own license (Commons Clause); check it before using them in a paid service.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Contenta Software
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# AppLedger honest check (plugin)
|
|
2
|
+
|
|
3
|
+
Honest security checks, in plain language, for apps you build with AI in Claude Code or Codex.
|
|
4
|
+
|
|
5
|
+
Ask your agent "Is my app safe to share?" and AppLedger checks your project with independent scanners: Trivy for leaked keys, outdated libraries and risky container setup, and Opengrep for dangerous code patterns such as SQL injection or command injection. Your agent then explains each problem in everyday words, offers to fix it, and checks again so you can see the score improve.
|
|
6
|
+
|
|
7
|
+
Nothing to install besides the plugin: the scanners run on the AppLedger service.
|
|
8
|
+
|
|
9
|
+
## Data handling
|
|
10
|
+
|
|
11
|
+
**When you run a check, your project's source files are uploaded to the AppLedger scanning service** at `appledger.net` over HTTPS. Dependencies, build output, media and files over 1 MB are left out. The upload is scanned and deleted right after; we keep no copy of your code. We log only the time, a one-way hash of your IP address, the upload size, how long the check took and whether it succeeded.
|
|
12
|
+
|
|
13
|
+
Results are written to a `.appledger/` folder inside your project, which is excluded from version control.
|
|
14
|
+
|
|
15
|
+
Prefer to keep everything on your computer? Set `APPLEDGER_MODE=local` and install [Trivy](https://trivy.dev) and [Opengrep](https://github.com/opengrep/opengrep/releases) yourself.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- Python 3.10+ and [uv](https://docs.astral.sh/uv/) (the plugin starts its local MCP server with `uvx`)
|
|
20
|
+
|
|
21
|
+
## What's included
|
|
22
|
+
|
|
23
|
+
- `check-my-app` skill: runs the check, explains it, fixes problems with your permission and checks again
|
|
24
|
+
- `appledger` MCP server with four tools: `check_app`, `get_fix_prompt`, `ai_cost` (AI tokens and cost behind the app, read from your local Claude Code and Codex logs, never uploaded), `scanner_status`
|
|
25
|
+
|
|
26
|
+
More: https://appledger.net/
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "appledger"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "The ledger for the AI app explosion: honest security checks, in plain language, for apps your people build with AI."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [{ name = "Contenta Software" }]
|
|
14
|
+
keywords = ["security", "mcp", "claude", "codex", "trivy", "opengrep", "vibe-coding", "governance"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: Information Technology",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Topic :: Security",
|
|
22
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"mcp>=1.20,<2",
|
|
26
|
+
"pyyaml>=6",
|
|
27
|
+
"packaging>=23",
|
|
28
|
+
"anyio>=4",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://appledger.net/"
|
|
33
|
+
Repository = "https://github.com/contentasoftware/appledger"
|
|
34
|
+
Privacy = "https://appledger.net/privacy.html"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
appledger = "appledger.scanner:main"
|
|
38
|
+
appledger-mcp = "appledger.server:main"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/appledger"]
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.sdist]
|
|
44
|
+
include = ["src/appledger", "README.md", "LICENSE", "pyproject.toml"]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Send a project to the hosted AppLedger scanning service and get the findings back.
|
|
2
|
+
|
|
3
|
+
The project is zipped (without dependencies, build output, media or other large files),
|
|
4
|
+
sent over HTTPS, scanned with Trivy and Opengrep, and deleted on the server right after.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import io
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
import uuid
|
|
11
|
+
import urllib.error
|
|
12
|
+
import urllib.request
|
|
13
|
+
import zipfile
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from . import __version__
|
|
17
|
+
from .scanner import ScanError, app_files
|
|
18
|
+
|
|
19
|
+
API_URL = os.environ.get("APPLEDGER_API", "https://appledger.net/api/check.php")
|
|
20
|
+
MAX_FILE_BYTES = 1_000_000
|
|
21
|
+
MAX_ZIP_BYTES = 10_000_000
|
|
22
|
+
SKIP_SUFFIXES = {
|
|
23
|
+
".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".svg", ".mp4", ".mov", ".mp3", ".wav", ".pdf",
|
|
24
|
+
".zip", ".gz", ".tgz", ".7z", ".rar", ".exe", ".dll", ".so", ".dylib", ".bin", ".class", ".jar",
|
|
25
|
+
".pyc", ".db", ".sqlite", ".sqlite3", ".woff", ".woff2", ".ttf", ".otf", ".psd", ".xlsx", ".docx",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def build_zip(app_dir):
|
|
30
|
+
"""Zip the files the scanners need. Returns (zip bytes, number of files, skipped files)."""
|
|
31
|
+
app_dir = Path(app_dir)
|
|
32
|
+
buf = io.BytesIO()
|
|
33
|
+
count, skipped = 0, []
|
|
34
|
+
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
35
|
+
for path in sorted(app_files(app_dir)):
|
|
36
|
+
rel = path.relative_to(app_dir).as_posix()
|
|
37
|
+
if path.suffix.lower() in SKIP_SUFFIXES or path.is_symlink():
|
|
38
|
+
continue
|
|
39
|
+
if path.stat().st_size > MAX_FILE_BYTES:
|
|
40
|
+
skipped.append(rel)
|
|
41
|
+
continue
|
|
42
|
+
zf.write(path, rel)
|
|
43
|
+
count += 1
|
|
44
|
+
data = buf.getvalue()
|
|
45
|
+
if count == 0:
|
|
46
|
+
raise ScanError(f"No files to check in {app_dir}.")
|
|
47
|
+
if len(data) > MAX_ZIP_BYTES:
|
|
48
|
+
raise ScanError(f"The project is too big to send ({len(data) // 1_000_000} MB after compression, "
|
|
49
|
+
f"limit {MAX_ZIP_BYTES // 1_000_000} MB). Check a smaller folder, or use local mode.")
|
|
50
|
+
return data, count, skipped
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def hosted_scan(app_dir):
|
|
54
|
+
"""Returns (findings, scanner names) from the AppLedger service."""
|
|
55
|
+
data, count, skipped = build_zip(app_dir)
|
|
56
|
+
boundary = uuid.uuid4().hex
|
|
57
|
+
body = (f"--{boundary}\r\nContent-Disposition: form-data; name=\"project\"; filename=\"project.zip\"\r\n"
|
|
58
|
+
f"Content-Type: application/zip\r\n\r\n").encode() + data + f"\r\n--{boundary}--\r\n".encode()
|
|
59
|
+
req = urllib.request.Request(API_URL, data=body, method="POST", headers={
|
|
60
|
+
"Content-Type": f"multipart/form-data; boundary={boundary}",
|
|
61
|
+
"Accept": "application/json",
|
|
62
|
+
"User-Agent": f"appledger/{__version__}",
|
|
63
|
+
})
|
|
64
|
+
try:
|
|
65
|
+
with urllib.request.urlopen(req, timeout=180) as resp:
|
|
66
|
+
result = json.load(resp)
|
|
67
|
+
except urllib.error.HTTPError as e:
|
|
68
|
+
try:
|
|
69
|
+
message = json.load(e).get("error", "")
|
|
70
|
+
except (ValueError, AttributeError):
|
|
71
|
+
message = ""
|
|
72
|
+
raise ScanError(message or f"The AppLedger service answered with an error ({e.code}). Try again later.")
|
|
73
|
+
except (urllib.error.URLError, TimeoutError) as e:
|
|
74
|
+
raise ScanError(f"Couldn't reach the AppLedger service ({getattr(e, 'reason', e)}). "
|
|
75
|
+
"Check your internet connection, or run in local mode.")
|
|
76
|
+
if not result.get("ok"):
|
|
77
|
+
raise ScanError(result.get("error", "The AppLedger service couldn't check this project."))
|
|
78
|
+
return result["findings"], result["scanners"]
|