git-watchtower 2.1.15 → 2.1.17
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/bin/git-watchtower.js +14 -1
- package/package.json +1 -1
- package/src/server/coordinator.js +33 -2
- package/src/utils/monitor-lock.js +9 -1
package/bin/git-watchtower.js
CHANGED
|
@@ -576,6 +576,18 @@ async function checkCliAuth(cmd) {
|
|
|
576
576
|
}
|
|
577
577
|
|
|
578
578
|
// Bulk-fetch PR statuses for all branches (parsing delegated to src/git/pr.js)
|
|
579
|
+
//
|
|
580
|
+
// PR_LIST_LIMIT is the cap passed to `gh pr list` / `glab mr list`. The
|
|
581
|
+
// previous values (200 for gh, glab's default of 30) silently truncated
|
|
582
|
+
// on any active OSS repo — branches whose PR was outside the most recent
|
|
583
|
+
// N rendered with no inline indicator and never sorted as merged.
|
|
584
|
+
// 1000 covers virtually any real-world repo while still keeping the
|
|
585
|
+
// single API call fast (gh streams JSON, no pagination overhead). If
|
|
586
|
+
// your repo somehow exceeds 1000 active PRs, the truncation is back —
|
|
587
|
+
// but at that scale the inline indicator is the smallest of your UX
|
|
588
|
+
// concerns.
|
|
589
|
+
const PR_LIST_LIMIT = '1000';
|
|
590
|
+
|
|
579
591
|
async function fetchAllPrStatuses() {
|
|
580
592
|
if (!cachedEnv) return null;
|
|
581
593
|
const { platform, hasGh, ghAuthed, hasGlab, glabAuthed } = cachedEnv;
|
|
@@ -584,7 +596,7 @@ async function fetchAllPrStatuses() {
|
|
|
584
596
|
try {
|
|
585
597
|
const { stdout } = await execCli('gh', [
|
|
586
598
|
'pr', 'list', '--state', 'all',
|
|
587
|
-
'--json', 'headRefName,number,title,state', '--limit',
|
|
599
|
+
'--json', 'headRefName,number,title,state', '--limit', PR_LIST_LIMIT,
|
|
588
600
|
]);
|
|
589
601
|
return parseGitHubPrList(JSON.parse(stdout));
|
|
590
602
|
} catch (e) { /* gh error */ }
|
|
@@ -594,6 +606,7 @@ async function fetchAllPrStatuses() {
|
|
|
594
606
|
try {
|
|
595
607
|
const { stdout } = await execCli('glab', [
|
|
596
608
|
'mr', 'list', '--state', 'all', '--output', 'json',
|
|
609
|
+
'--per-page', PR_LIST_LIMIT,
|
|
597
610
|
]);
|
|
598
611
|
return parseGitLabMrList(JSON.parse(stdout));
|
|
599
612
|
} catch (e) { /* glab error */ }
|
package/package.json
CHANGED
|
@@ -81,11 +81,28 @@ const LOCK_FILE = path.join(WATCHTOWER_DIR, 'web.lock');
|
|
|
81
81
|
const SOCKET_PATH = path.join(WATCHTOWER_DIR, 'web.sock');
|
|
82
82
|
|
|
83
83
|
/**
|
|
84
|
-
* Ensure the ~/.watchtower directory exists.
|
|
84
|
+
* Ensure the ~/.watchtower directory exists, restricted to the owner.
|
|
85
|
+
*
|
|
86
|
+
* The directory hosts the lock file and the Unix-domain IPC socket;
|
|
87
|
+
* both should only be reachable by the user running git-watchtower.
|
|
88
|
+
* On Linux, connect() to a Unix socket requires read+execute on the
|
|
89
|
+
* containing directory, so 0o700 is sufficient defense-in-depth even
|
|
90
|
+
* when the socket file itself ends up world-readable due to umask.
|
|
91
|
+
*
|
|
92
|
+
* mkdirSync's mode argument only applies when the directory is being
|
|
93
|
+
* created — it has no effect on a pre-existing dir. We chmod after
|
|
94
|
+
* the create check so installs that ran before this fix get migrated
|
|
95
|
+
* to the tighter mode on next launch.
|
|
85
96
|
*/
|
|
86
97
|
function ensureDir() {
|
|
87
98
|
if (!fs.existsSync(WATCHTOWER_DIR)) {
|
|
88
|
-
fs.mkdirSync(WATCHTOWER_DIR, { recursive: true });
|
|
99
|
+
fs.mkdirSync(WATCHTOWER_DIR, { recursive: true, mode: 0o700 });
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
fs.chmodSync(WATCHTOWER_DIR, 0o700);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
// chmod may fail on Windows or filesystems without POSIX perms; the
|
|
105
|
+
// permission semantics don't apply there anyway, so silently skip.
|
|
89
106
|
}
|
|
90
107
|
}
|
|
91
108
|
|
|
@@ -290,6 +307,20 @@ class Coordinator {
|
|
|
290
307
|
});
|
|
291
308
|
|
|
292
309
|
this.ipcServer.listen(this.socketPath, () => {
|
|
310
|
+
// Defense-in-depth: tighten the socket file's own perms after
|
|
311
|
+
// bind. Node's net.Server.listen() creates the socket file with
|
|
312
|
+
// perms derived from umask, which on shared workstations
|
|
313
|
+
// (umask 0022) yields 0o755 — world-readable. Linux ignores
|
|
314
|
+
// socket-file perms for connect() (the directory's perms are
|
|
315
|
+
// authoritative), but BSD honours them and other tooling may
|
|
316
|
+
// surface them in audit reports. Setting 0o600 explicitly
|
|
317
|
+
// matches the 0o700 directory perms set in ensureDir().
|
|
318
|
+
try {
|
|
319
|
+
fs.chmodSync(this.socketPath, 0o600);
|
|
320
|
+
} catch (e) {
|
|
321
|
+
// Non-POSIX filesystem or Windows — perm semantics don't
|
|
322
|
+
// apply, skip silently.
|
|
323
|
+
}
|
|
293
324
|
resolve();
|
|
294
325
|
});
|
|
295
326
|
});
|
|
@@ -52,8 +52,16 @@ function lockFilePath(repoRoot) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function ensureDir() {
|
|
55
|
+
// 0o700 keeps lock files (which contain pids and the cwd of running
|
|
56
|
+
// git-watchtower instances) unreadable to other local users. See
|
|
57
|
+
// src/server/coordinator.js for the rationale and Windows note.
|
|
55
58
|
if (!fs.existsSync(WATCHTOWER_DIR)) {
|
|
56
|
-
fs.mkdirSync(WATCHTOWER_DIR, { recursive: true });
|
|
59
|
+
fs.mkdirSync(WATCHTOWER_DIR, { recursive: true, mode: 0o700 });
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
fs.chmodSync(WATCHTOWER_DIR, 0o700);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
// chmod may fail on Windows / non-POSIX filesystems; skip silently.
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
67
|
|