Skip to content

Commit d3fdb20

Browse files
committed
feat(dashboard,security): load file config defaults in serve & add CSP frame-ancestors
Signed-off-by: Damian Skrzyński <polprog.tech@gmail.com>
1 parent fa565cb commit d3fdb20

2 files changed

Lines changed: 54 additions & 2 deletions

File tree

src/releasepilot/cli/cmd_dashboard.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,50 @@ def serve(
127127
"""Start the interactive web dashboard server."""
128128
import uvicorn
129129

130+
from releasepilot.config.file_config import load_config
130131
from releasepilot.shared.logging import configure_root_logger
131132
from releasepilot.web.server import create_app
132133

133134
configure_root_logger(verbose)
134-
config: dict[str, str] = {"repo_path": str(Path(repo).resolve())}
135+
136+
# Load project config file as base defaults (.releasepilot.json, etc.)
137+
repo_resolved = str(Path(repo).resolve())
138+
file_cfg = load_config(repo_resolved)
139+
config: dict[str, str] = {"repo_path": repo_resolved}
140+
141+
# File config provides defaults for fields not specified via CLI
142+
if file_cfg.app_name:
143+
config["app_name"] = file_cfg.app_name
144+
if file_cfg.audience:
145+
config["audience"] = file_cfg.audience
146+
if file_cfg.format:
147+
config["format"] = file_cfg.format
148+
if file_cfg.language:
149+
config["language"] = file_cfg.language
150+
if file_cfg.title:
151+
config["title"] = file_cfg.title
152+
if file_cfg.version:
153+
config["version"] = file_cfg.version
154+
if file_cfg.branch:
155+
config["branch"] = file_cfg.branch
156+
config["show_authors"] = str(file_cfg.show_authors).lower()
157+
config["show_hashes"] = str(file_cfg.show_hashes).lower()
158+
if file_cfg.accent_color:
159+
config["accent_color"] = file_cfg.accent_color
160+
if file_cfg.output_dir:
161+
config["output_dir"] = file_cfg.output_dir
162+
if file_cfg.overwrite:
163+
config["overwrite"] = "true"
164+
if file_cfg.repos:
165+
config["repos"] = ",".join(file_cfg.repos)
166+
if file_cfg.export_formats:
167+
config["export_formats"] = ",".join(file_cfg.export_formats)
168+
if not file_cfg.gitlab_ssl_verify:
169+
config["gitlab_ssl_verify"] = "false"
170+
if not file_cfg.github_ssl_verify:
171+
config["github_ssl_verify"] = "false"
172+
173+
# CLI args override file config
135174
if from_ref:
136175
config["from_ref"] = from_ref
137176
if to_ref and to_ref != "HEAD":

src/releasepilot/web/middleware.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ def __init__(self, app: Any) -> None:
2929
"true",
3030
"yes",
3131
)
32+
# Portal origin(s) allowed to embed this app in an iframe.
33+
self._frame_ancestors = self._build_frame_ancestors()
34+
35+
def _build_frame_ancestors(self) -> str:
36+
"""Build frame-ancestors value from environment."""
37+
if not self._allow_framing:
38+
return "'none'"
39+
origins_env = os.environ.get("RELEASEPILOT_CORS_ORIGINS", "").strip()
40+
if origins_env:
41+
origins = " ".join(o.strip() for o in origins_env.split(",") if o.strip())
42+
return f"'self' {origins}"
43+
return "'self'"
3244

3345
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
3446
if scope["type"] != "http":
@@ -53,7 +65,8 @@ async def send_with_headers(message: dict) -> None:
5365
f"style-src 'self' 'nonce-{nonce}'; "
5466
f"style-src-attr 'unsafe-inline'; "
5567
f"script-src 'self' 'nonce-{nonce}'; "
56-
f"script-src-attr 'unsafe-inline'"
68+
f"script-src-attr 'unsafe-inline'; "
69+
f"frame-ancestors {self._frame_ancestors}"
5770
)
5871
headers.append((b"content-security-policy", csp.encode()))
5972
headers.append((b"referrer-policy", b"strict-origin-when-cross-origin"))

0 commit comments

Comments
 (0)