opencode-dashboard-server 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.
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/PKG-INFO +22 -3
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/README.md +19 -2
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/app.py +18 -13
- opencode_dashboard_server-0.3.0/cli.py +126 -0
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/opencode_dashboard_server.egg-info/PKG-INFO +22 -3
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/opencode_dashboard_server.egg-info/SOURCES.txt +2 -0
- opencode_dashboard_server-0.3.0/opencode_dashboard_server.egg-info/entry_points.txt +2 -0
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/opencode_dashboard_server.egg-info/requires.txt +2 -0
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/opencode_dashboard_server.egg-info/top_level.txt +1 -0
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/pyproject.toml +7 -2
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/tests/test_app.py +12 -0
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/aggregate.py +0 -0
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/db.py +0 -0
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/opencode_dashboard_server.egg-info/dependency_links.txt +0 -0
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/setup.cfg +0 -0
- {opencode_dashboard_server-0.2.0 → opencode_dashboard_server-0.3.0}/tests/test_aggregate.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencode-dashboard-server
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: FastAPI aggregator over opencode's SQLite storage
|
|
5
5
|
Project-URL: Homepage, https://github.com/GCS-ZHN/opencode-dashboard
|
|
6
6
|
Project-URL: Repository, https://github.com/GCS-ZHN/opencode-dashboard
|
|
@@ -9,6 +9,8 @@ Requires-Python: >=3.10
|
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
Requires-Dist: fastapi<1,>=0.115
|
|
11
11
|
Requires-Dist: uvicorn<1,>=0.30
|
|
12
|
+
Requires-Dist: platformdirs<5,>=4
|
|
13
|
+
Requires-Dist: PyYAML<7,>=6
|
|
12
14
|
|
|
13
15
|
# opencode-dashboard-server
|
|
14
16
|
|
|
@@ -20,6 +22,8 @@ API for the dashboard front end.
|
|
|
20
22
|
|
|
21
23
|
```bash
|
|
22
24
|
pip install opencode-dashboard-server
|
|
25
|
+
# or with uv:
|
|
26
|
+
uv tool install opencode-dashboard-server
|
|
23
27
|
```
|
|
24
28
|
|
|
25
29
|
Requires:
|
|
@@ -30,14 +34,29 @@ Requires:
|
|
|
30
34
|
|
|
31
35
|
## Quick start
|
|
32
36
|
|
|
37
|
+
Configure once (interactive; writes `~/.config/opencode-dashboard/server.yaml`), then serve:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
opencode-dashboard-server configure
|
|
41
|
+
opencode-dashboard-server serve
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`configure` walks you through `port` (default `8791`), `host` (default `0.0.0.0`),
|
|
45
|
+
`cors_origins` (comma-separated; empty = built-in loopback whitelist), `poll_seconds`
|
|
46
|
+
(default `5`), and `opencode_bin` (default `opencode`). Empty input keeps the default.
|
|
47
|
+
|
|
48
|
+
`serve` accepts overrides: `--port N`, `--host H`, `--config PATH` (instead of the XDG file).
|
|
49
|
+
Precedence for port/host: CLI flag > env `PORT`/`HOST` > config file > default.
|
|
50
|
+
|
|
33
51
|
Run one aggregator per opencode host:
|
|
34
52
|
|
|
35
53
|
```bash
|
|
36
54
|
uvicorn app:app --port 8791
|
|
37
55
|
```
|
|
38
56
|
|
|
39
|
-
|
|
40
|
-
`dashboard.
|
|
57
|
+
or directly with uvicorn (still works — reads env/defaults only). Run on more hosts with
|
|
58
|
+
different ports (`8792`, `8793`, …) and list each in the front end's config (`opencode-dashboard configure`).
|
|
59
|
+
Environment switches (used when no config file value is set):
|
|
41
60
|
|
|
42
61
|
- `DASHBOARD_CORS_ORIGINS` — comma-separated CORS allow-list (defaults to the loopback dev origins `localhost/127.0.0.1:5173` and `:4173`; tighten or widen for your deployment).
|
|
43
62
|
- `DASHBOARD_POLL_SECONDS` — SSE poll interval in seconds (default `5`).
|
|
@@ -8,6 +8,8 @@ API for the dashboard front end.
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
pip install opencode-dashboard-server
|
|
11
|
+
# or with uv:
|
|
12
|
+
uv tool install opencode-dashboard-server
|
|
11
13
|
```
|
|
12
14
|
|
|
13
15
|
Requires:
|
|
@@ -18,14 +20,29 @@ Requires:
|
|
|
18
20
|
|
|
19
21
|
## Quick start
|
|
20
22
|
|
|
23
|
+
Configure once (interactive; writes `~/.config/opencode-dashboard/server.yaml`), then serve:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
opencode-dashboard-server configure
|
|
27
|
+
opencode-dashboard-server serve
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`configure` walks you through `port` (default `8791`), `host` (default `0.0.0.0`),
|
|
31
|
+
`cors_origins` (comma-separated; empty = built-in loopback whitelist), `poll_seconds`
|
|
32
|
+
(default `5`), and `opencode_bin` (default `opencode`). Empty input keeps the default.
|
|
33
|
+
|
|
34
|
+
`serve` accepts overrides: `--port N`, `--host H`, `--config PATH` (instead of the XDG file).
|
|
35
|
+
Precedence for port/host: CLI flag > env `PORT`/`HOST` > config file > default.
|
|
36
|
+
|
|
21
37
|
Run one aggregator per opencode host:
|
|
22
38
|
|
|
23
39
|
```bash
|
|
24
40
|
uvicorn app:app --port 8791
|
|
25
41
|
```
|
|
26
42
|
|
|
27
|
-
|
|
28
|
-
`dashboard.
|
|
43
|
+
or directly with uvicorn (still works — reads env/defaults only). Run on more hosts with
|
|
44
|
+
different ports (`8792`, `8793`, …) and list each in the front end's config (`opencode-dashboard configure`).
|
|
45
|
+
Environment switches (used when no config file value is set):
|
|
29
46
|
|
|
30
47
|
- `DASHBOARD_CORS_ORIGINS` — comma-separated CORS allow-list (defaults to the loopback dev origins `localhost/127.0.0.1:5173` and `:4173`; tighten or widen for your deployment).
|
|
31
48
|
- `DASHBOARD_POLL_SECONDS` — SSE poll interval in seconds (default `5`).
|
|
@@ -22,7 +22,7 @@ logger = logging.getLogger("dashboard")
|
|
|
22
22
|
|
|
23
23
|
# Comma-separated CORS allow-list; defaults to the loopback dev origins. Tight
|
|
24
24
|
# by default so a random webpage can't exfiltrate local project/session data.
|
|
25
|
-
def
|
|
25
|
+
def default_cors_origins() -> list[str]:
|
|
26
26
|
env = os.environ.get("DASHBOARD_CORS_ORIGINS", "").strip()
|
|
27
27
|
if env:
|
|
28
28
|
return [o.strip() for o in env.split(",") if o.strip()]
|
|
@@ -32,27 +32,32 @@ def cors_origins() -> list[str]:
|
|
|
32
32
|
]
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@lru_cache(maxsize=1)
|
|
39
|
-
def opencode_version() -> str:
|
|
35
|
+
@lru_cache(maxsize=8)
|
|
36
|
+
def opencode_version(executable: str = "opencode") -> str:
|
|
40
37
|
try:
|
|
41
38
|
return subprocess.run(
|
|
42
|
-
[
|
|
39
|
+
[executable, "--version"], capture_output=True, text=True, check=True
|
|
43
40
|
).stdout.strip()
|
|
44
41
|
except (OSError, subprocess.CalledProcessError):
|
|
45
42
|
return "unknown" # e.g. CI without the opencode CLI; don't fail the request
|
|
46
43
|
|
|
47
44
|
|
|
48
|
-
def create_app(runner=None) -> FastAPI:
|
|
49
|
-
|
|
45
|
+
def create_app(runner=None, cors_origins=None, poll_seconds=None, opencode_bin=None) -> FastAPI:
|
|
46
|
+
bin = opencode_bin or os.environ.get("OPENCODE_BIN") or "opencode"
|
|
47
|
+
if runner is None:
|
|
48
|
+
runner = CliRunner(executable=bin)
|
|
49
|
+
origins = cors_origins if cors_origins is not None else default_cors_origins()
|
|
50
|
+
if poll_seconds is None:
|
|
51
|
+
try:
|
|
52
|
+
poll_seconds = float(os.environ.get("DASHBOARD_POLL_SECONDS", "5"))
|
|
53
|
+
except ValueError:
|
|
54
|
+
poll_seconds = 5.0
|
|
50
55
|
app = FastAPI(title="opencode token dashboard")
|
|
51
56
|
# Loopback-only API; restrict origins so a random webpage can't exfiltrate
|
|
52
57
|
# local project/session data from the browser (the client runs from Vite).
|
|
53
58
|
app.add_middleware(
|
|
54
59
|
CORSMiddleware,
|
|
55
|
-
allow_origins=
|
|
60
|
+
allow_origins=origins,
|
|
56
61
|
allow_methods=["*"],
|
|
57
62
|
allow_headers=["*"],
|
|
58
63
|
)
|
|
@@ -68,14 +73,14 @@ def create_app(runner=None) -> FastAPI:
|
|
|
68
73
|
|
|
69
74
|
@app.get("/health")
|
|
70
75
|
def health():
|
|
71
|
-
return {"status": "ok", "version": opencode_version()}
|
|
76
|
+
return {"status": "ok", "version": opencode_version(bin)}
|
|
72
77
|
|
|
73
78
|
@app.get("/overview")
|
|
74
79
|
def overview():
|
|
75
80
|
def run():
|
|
76
81
|
data = aggregate.overview(runner)
|
|
77
82
|
data["host"] = socket.gethostname()
|
|
78
|
-
data["opencodeVersion"] = opencode_version()
|
|
83
|
+
data["opencodeVersion"] = opencode_version(bin)
|
|
79
84
|
return data
|
|
80
85
|
|
|
81
86
|
return handle(run)
|
|
@@ -128,7 +133,7 @@ def create_app(runner=None) -> FastAPI:
|
|
|
128
133
|
except Exception:
|
|
129
134
|
logger.exception("stream poll failed")
|
|
130
135
|
try:
|
|
131
|
-
await asyncio.wait_for(stop.wait(),
|
|
136
|
+
await asyncio.wait_for(stop.wait(), poll_seconds)
|
|
132
137
|
except asyncio.TimeoutError:
|
|
133
138
|
pass
|
|
134
139
|
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""opencode-dashboard-server CLI: interactive configure + serve.
|
|
2
|
+
|
|
3
|
+
Run: uv tool install opencode-dashboard-server
|
|
4
|
+
opencode-dashboard-server configure
|
|
5
|
+
opencode-dashboard-server serve [--port N] [--host H] [--config PATH]
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import yaml
|
|
14
|
+
from platformdirs import user_config_path
|
|
15
|
+
|
|
16
|
+
from app import create_app
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def config_path() -> Path:
|
|
20
|
+
# Force XDG semantics so the backend shares ~/.config/opencode-dashboard
|
|
21
|
+
# with the front end; platformdirs would otherwise use ~/Library/Application
|
|
22
|
+
# Support on macOS. setdefault keeps a user-set XDG_CONFIG_HOME intact.
|
|
23
|
+
os.environ.setdefault("XDG_CONFIG_HOME", str(Path.home() / ".config"))
|
|
24
|
+
return user_config_path("opencode-dashboard") / "server.yaml"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def load_config(path: Path) -> dict:
|
|
28
|
+
if not path.exists():
|
|
29
|
+
return {}
|
|
30
|
+
return yaml.safe_load(path.read_text()) or {}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _prompt(label: str, current, default) -> str:
|
|
34
|
+
hint = current if current != "" else default
|
|
35
|
+
try:
|
|
36
|
+
value = input(f"{label} [{hint}]: ").strip()
|
|
37
|
+
except EOFError:
|
|
38
|
+
return hint
|
|
39
|
+
return value if value else hint
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _prompt_num(label: str, current, default, conv):
|
|
43
|
+
while True:
|
|
44
|
+
try:
|
|
45
|
+
return conv(_prompt(label, current, default))
|
|
46
|
+
except ValueError:
|
|
47
|
+
print(f"Invalid {label}; enter a number.")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def cmd_configure(args) -> None:
|
|
51
|
+
path = config_path()
|
|
52
|
+
existing = load_config(path)
|
|
53
|
+
cur = {
|
|
54
|
+
"port": existing.get("port", 8791),
|
|
55
|
+
"host": existing.get("host", "0.0.0.0"),
|
|
56
|
+
"cors_origins": existing.get("cors_origins", ""),
|
|
57
|
+
"poll_seconds": existing.get("poll_seconds", 5),
|
|
58
|
+
"opencode_bin": existing.get("opencode_bin", "opencode"),
|
|
59
|
+
}
|
|
60
|
+
if existing:
|
|
61
|
+
print(f"Current config at {path}:")
|
|
62
|
+
print(yaml.safe_dump(cur, sort_keys=False).rstrip())
|
|
63
|
+
print()
|
|
64
|
+
cur["port"] = _prompt_num("port", cur["port"], 8791, int)
|
|
65
|
+
cur["host"] = _prompt("host", cur["host"], "0.0.0.0")
|
|
66
|
+
cur["cors_origins"] = _prompt(
|
|
67
|
+
"cors_origins (comma-separated; empty = built-in loopback whitelist)",
|
|
68
|
+
cur["cors_origins"], "",
|
|
69
|
+
)
|
|
70
|
+
cur["poll_seconds"] = _prompt_num("poll_seconds", cur["poll_seconds"], 5, float)
|
|
71
|
+
cur["opencode_bin"] = _prompt("opencode_bin", cur["opencode_bin"], "opencode")
|
|
72
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
path.write_text(yaml.safe_dump(cur, sort_keys=False))
|
|
74
|
+
print(f"Wrote {path}")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def cmd_serve(args) -> None:
|
|
78
|
+
path = args.config or config_path()
|
|
79
|
+
cfg = load_config(path)
|
|
80
|
+
try:
|
|
81
|
+
port = args.port or int(os.environ.get("PORT") or cfg.get("port") or 8791)
|
|
82
|
+
except ValueError:
|
|
83
|
+
print(f"invalid port: {os.environ.get('PORT') or cfg.get('port')!r}")
|
|
84
|
+
sys.exit(2)
|
|
85
|
+
host = args.host or os.environ.get("HOST") or cfg.get("host") or "0.0.0.0"
|
|
86
|
+
|
|
87
|
+
import uvicorn
|
|
88
|
+
|
|
89
|
+
# cors_origins is stored comma-separated; create_app expects a list.
|
|
90
|
+
cors = [o.strip() for o in str(cfg.get("cors_origins", "")).split(",") if o.strip()]
|
|
91
|
+
|
|
92
|
+
uvicorn.run(
|
|
93
|
+
create_app(
|
|
94
|
+
cors_origins=cors or None,
|
|
95
|
+
poll_seconds=cfg.get("poll_seconds"),
|
|
96
|
+
opencode_bin=cfg.get("opencode_bin") or None,
|
|
97
|
+
),
|
|
98
|
+
host=host,
|
|
99
|
+
port=port,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def main(argv=None) -> int:
|
|
104
|
+
parser = argparse.ArgumentParser(
|
|
105
|
+
prog="opencode-dashboard-server",
|
|
106
|
+
description="opencode token dashboard aggregation backend",
|
|
107
|
+
)
|
|
108
|
+
sub = parser.add_subparsers(dest="cmd")
|
|
109
|
+
sub.add_parser("configure", help="interactively write the XDG config file")
|
|
110
|
+
serve = sub.add_parser("serve", help="run the server (FastAPI + uvicorn)")
|
|
111
|
+
serve.add_argument("--config", metavar="PATH", help="config file (default: XDG server.yaml)")
|
|
112
|
+
serve.add_argument("--port", type=int, help="listen port")
|
|
113
|
+
serve.add_argument("--host", help="bind host")
|
|
114
|
+
args = parser.parse_args(argv)
|
|
115
|
+
if args.cmd == "configure":
|
|
116
|
+
cmd_configure(args)
|
|
117
|
+
elif args.cmd == "serve":
|
|
118
|
+
cmd_serve(args)
|
|
119
|
+
else:
|
|
120
|
+
parser.print_usage()
|
|
121
|
+
return 2
|
|
122
|
+
return 0
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
sys.exit(main())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencode-dashboard-server
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: FastAPI aggregator over opencode's SQLite storage
|
|
5
5
|
Project-URL: Homepage, https://github.com/GCS-ZHN/opencode-dashboard
|
|
6
6
|
Project-URL: Repository, https://github.com/GCS-ZHN/opencode-dashboard
|
|
@@ -9,6 +9,8 @@ Requires-Python: >=3.10
|
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
Requires-Dist: fastapi<1,>=0.115
|
|
11
11
|
Requires-Dist: uvicorn<1,>=0.30
|
|
12
|
+
Requires-Dist: platformdirs<5,>=4
|
|
13
|
+
Requires-Dist: PyYAML<7,>=6
|
|
12
14
|
|
|
13
15
|
# opencode-dashboard-server
|
|
14
16
|
|
|
@@ -20,6 +22,8 @@ API for the dashboard front end.
|
|
|
20
22
|
|
|
21
23
|
```bash
|
|
22
24
|
pip install opencode-dashboard-server
|
|
25
|
+
# or with uv:
|
|
26
|
+
uv tool install opencode-dashboard-server
|
|
23
27
|
```
|
|
24
28
|
|
|
25
29
|
Requires:
|
|
@@ -30,14 +34,29 @@ Requires:
|
|
|
30
34
|
|
|
31
35
|
## Quick start
|
|
32
36
|
|
|
37
|
+
Configure once (interactive; writes `~/.config/opencode-dashboard/server.yaml`), then serve:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
opencode-dashboard-server configure
|
|
41
|
+
opencode-dashboard-server serve
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`configure` walks you through `port` (default `8791`), `host` (default `0.0.0.0`),
|
|
45
|
+
`cors_origins` (comma-separated; empty = built-in loopback whitelist), `poll_seconds`
|
|
46
|
+
(default `5`), and `opencode_bin` (default `opencode`). Empty input keeps the default.
|
|
47
|
+
|
|
48
|
+
`serve` accepts overrides: `--port N`, `--host H`, `--config PATH` (instead of the XDG file).
|
|
49
|
+
Precedence for port/host: CLI flag > env `PORT`/`HOST` > config file > default.
|
|
50
|
+
|
|
33
51
|
Run one aggregator per opencode host:
|
|
34
52
|
|
|
35
53
|
```bash
|
|
36
54
|
uvicorn app:app --port 8791
|
|
37
55
|
```
|
|
38
56
|
|
|
39
|
-
|
|
40
|
-
`dashboard.
|
|
57
|
+
or directly with uvicorn (still works — reads env/defaults only). Run on more hosts with
|
|
58
|
+
different ports (`8792`, `8793`, …) and list each in the front end's config (`opencode-dashboard configure`).
|
|
59
|
+
Environment switches (used when no config file value is set):
|
|
41
60
|
|
|
42
61
|
- `DASHBOARD_CORS_ORIGINS` — comma-separated CORS allow-list (defaults to the loopback dev origins `localhost/127.0.0.1:5173` and `:4173`; tighten or widen for your deployment).
|
|
43
62
|
- `DASHBOARD_POLL_SECONDS` — SSE poll interval in seconds (default `5`).
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
README.md
|
|
2
2
|
aggregate.py
|
|
3
3
|
app.py
|
|
4
|
+
cli.py
|
|
4
5
|
db.py
|
|
5
6
|
pyproject.toml
|
|
6
7
|
opencode_dashboard_server.egg-info/PKG-INFO
|
|
7
8
|
opencode_dashboard_server.egg-info/SOURCES.txt
|
|
8
9
|
opencode_dashboard_server.egg-info/dependency_links.txt
|
|
10
|
+
opencode_dashboard_server.egg-info/entry_points.txt
|
|
9
11
|
opencode_dashboard_server.egg-info/requires.txt
|
|
10
12
|
opencode_dashboard_server.egg-info/top_level.txt
|
|
11
13
|
tests/test_aggregate.py
|
|
@@ -4,13 +4,15 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "opencode-dashboard-server"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "FastAPI aggregator over opencode's SQLite storage"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
11
|
dependencies = [
|
|
12
12
|
"fastapi>=0.115,<1",
|
|
13
13
|
"uvicorn>=0.30,<1",
|
|
14
|
+
"platformdirs>=4,<5",
|
|
15
|
+
"PyYAML>=6,<7",
|
|
14
16
|
]
|
|
15
17
|
|
|
16
18
|
[project.urls]
|
|
@@ -18,8 +20,11 @@ Homepage = "https://github.com/GCS-ZHN/opencode-dashboard"
|
|
|
18
20
|
Repository = "https://github.com/GCS-ZHN/opencode-dashboard"
|
|
19
21
|
Issues = "https://github.com/GCS-ZHN/opencode-dashboard/issues"
|
|
20
22
|
|
|
23
|
+
[project.scripts]
|
|
24
|
+
opencode-dashboard-server = "cli:main"
|
|
25
|
+
|
|
21
26
|
[tool.setuptools]
|
|
22
|
-
py-modules = ["app", "aggregate", "db"]
|
|
27
|
+
py-modules = ["app", "aggregate", "db", "cli"]
|
|
23
28
|
|
|
24
29
|
[dependency-groups]
|
|
25
30
|
dev = [
|
|
@@ -46,3 +46,15 @@ def test_foreign_origin_not_allowed_by_cors():
|
|
|
46
46
|
"Access-Control-Request-Method": "GET",
|
|
47
47
|
})
|
|
48
48
|
assert "access-control-allow-origin" not in r.headers
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_cors_origins_injection():
|
|
52
|
+
conn = sqlite3.connect(":memory:", check_same_thread=False)
|
|
53
|
+
conn.executescript(SCHEMA)
|
|
54
|
+
seed(conn)
|
|
55
|
+
app = appmod.create_app(SqliteRunner(conn), cors_origins=["http://a.com"])
|
|
56
|
+
c = TestClient(app)
|
|
57
|
+
ok = c.options("/projects", headers={"Origin": "http://a.com", "Access-Control-Request-Method": "GET"})
|
|
58
|
+
assert ok.headers.get("access-control-allow-origin") == "http://a.com"
|
|
59
|
+
nope = c.options("/projects", headers={"Origin": "http://a.co", "Access-Control-Request-Method": "GET"})
|
|
60
|
+
assert "access-control-allow-origin" not in nope.headers
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|