git-watchtower 2.3.12 → 2.3.13

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-watchtower",
3
- "version": "2.3.12",
3
+ "version": "2.3.13",
4
4
  "description": "Terminal-based Git branch monitor with activity sparklines and optional dev server with live reload",
5
5
  "main": "bin/git-watchtower.js",
6
6
  "bin": {
@@ -110,6 +110,13 @@ function disable() {
110
110
  // up to ~15 frames × 120 ms = 1.8 s after disable, and lossMessage stayed
111
111
  // set so isLossAnimating() reported true into the next session.
112
112
  resetLossState();
113
+ // Drop the marquee render callback so a stale closure to the previous
114
+ // session's render() doesn't survive across enable/disable cycles. In
115
+ // production this is mostly hygiene (bin/git-watchtower.js wires the
116
+ // callback exactly once at startup against a singleton render fn), but
117
+ // tests that re-use the casino module saw the previous test's callback
118
+ // persist into the next setRenderCallback assignment.
119
+ marqueeCallback = null;
113
120
  }
114
121
 
115
122
  /**
package/src/server/web.js CHANGED
@@ -46,6 +46,36 @@ const SSE_KEEPALIVE_INTERVAL = 15000;
46
46
  */
47
47
  const MAX_STALLED_PUSHES = 60;
48
48
 
49
+ /**
50
+ * Content-Security-Policy header for the dashboard HTML.
51
+ *
52
+ * The dashboard uses inline <script> and inline <style> blocks (the whole
53
+ * UI is bundled at build time), and makes XHR / EventSource calls to
54
+ * /api/... on the same origin. No external resources are loaded.
55
+ *
56
+ * `default-src 'none'` denies everything not explicitly allowed.
57
+ * `script-src` / `style-src` need 'unsafe-inline' for the bundled blocks.
58
+ * `connect-src 'self'` lets XHR + SSE hit /api/... .
59
+ * `base-uri 'none'` blocks <base> injection from rewriting URLs.
60
+ * `form-action 'none'` blocks any rogue form posts.
61
+ * `frame-ancestors 'none'` blocks embedding (defense vs. clickjacking).
62
+ *
63
+ * Defense-in-depth — the dashboard already escapes user-supplied content
64
+ * everywhere we render it, but a future regression that forgets escHtml
65
+ * is mitigated here.
66
+ */
67
+ const CONTENT_SECURITY_POLICY = [
68
+ "default-src 'none'",
69
+ "script-src 'self' 'unsafe-inline'",
70
+ "style-src 'self' 'unsafe-inline'",
71
+ "connect-src 'self'",
72
+ "img-src 'self' data:",
73
+ "font-src 'self'",
74
+ "base-uri 'none'",
75
+ "form-action 'none'",
76
+ "frame-ancestors 'none'",
77
+ ].join('; ');
78
+
49
79
  /**
50
80
  * Actions the web dashboard is allowed to POST to /api/action. Every entry
51
81
  * here MUST be matched by a `case` in `handleWebAction` in bin/git-watchtower.js
@@ -474,7 +504,12 @@ class WebDashboardServer {
474
504
 
475
505
  // Routes
476
506
  if (pathname === '/' && req.method === 'GET') {
477
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
507
+ res.writeHead(200, {
508
+ 'Content-Type': 'text/html; charset=utf-8',
509
+ 'Content-Security-Policy': CONTENT_SECURITY_POLICY,
510
+ 'X-Content-Type-Options': 'nosniff',
511
+ 'Referrer-Policy': 'no-referrer',
512
+ });
478
513
  res.end(this._cachedHtml);
479
514
  return;
480
515
  }
@@ -673,4 +708,5 @@ module.exports = {
673
708
  STATE_PUSH_INTERVAL,
674
709
  MAX_STALLED_PUSHES,
675
710
  ALLOWED_ACTIONS,
711
+ CONTENT_SECURITY_POLICY,
676
712
  };