nx 22.7.7 → 22.7.9
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/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +2 -1
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +1 -1
- package/dist/src/command-line/init/init-v2.js +1 -1
- package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
- package/dist/src/command-line/reset/reset.js +6 -1
- package/dist/src/daemon/client/client.d.ts +45 -3
- package/dist/src/daemon/client/client.js +138 -42
- package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
- package/dist/src/daemon/message-types/daemon-message.d.ts +33 -0
- package/dist/src/daemon/message-types/daemon-message.js +48 -0
- package/dist/src/daemon/server/latest-nx.js +3 -1
- package/dist/src/daemon/server/server.js +22 -0
- package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
- package/dist/src/daemon/server/shutdown-utils.js +11 -4
- package/dist/src/daemon/socket-utils.d.ts +1 -0
- package/dist/src/daemon/socket-utils.js +24 -3
- package/dist/src/daemon/tmp-dir.d.ts +43 -3
- package/dist/src/daemon/tmp-dir.js +437 -15
- package/dist/src/devkit-internals.d.ts +1 -0
- package/dist/src/devkit-internals.js +4 -1
- package/dist/src/native/index.js +71 -28
- package/dist/src/native/native-file-cache-location.d.ts +17 -1
- package/dist/src/native/native-file-cache-location.js +86 -12
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/project-graph/file-utils.js +5 -1
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -1
- package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
- package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
- package/dist/src/project-graph/project-graph.js +20 -0
- package/dist/src/utils/command-line-utils.js +30 -20
- package/dist/src/utils/git-revision.d.ts +12 -0
- package/dist/src/utils/git-revision.js +25 -0
- package/dist/src/utils/git-utils.d.ts +1 -3
- package/dist/src/utils/git-utils.js +83 -47
- package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
- package/dist/src/utils/nx-tmp-dir.js +40 -0
- package/dist/src/utils/owned-private-dir.d.ts +132 -0
- package/dist/src/utils/owned-private-dir.js +323 -0
- package/dist/src/utils/package-json.d.ts +3 -3
- package/dist/src/utils/package-json.js +30 -12
- package/dist/src/utils/package-manager.d.ts +13 -0
- package/dist/src/utils/package-manager.js +27 -0
- package/dist/src/utils/safe-spawn.d.ts +24 -0
- package/dist/src/utils/safe-spawn.js +104 -0
- package/dist/src/utils/shell-quoting.d.ts +15 -0
- package/dist/src/utils/shell-quoting.js +35 -0
- package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
- package/dist/src/utils/wait-for-socket-connection.js +14 -8
- package/package.json +17 -13
|
@@ -9,9 +9,9 @@ exports.getLatestCommitSha = getLatestCommitSha;
|
|
|
9
9
|
const child_process_1 = require("child_process");
|
|
10
10
|
const path_1 = require("path");
|
|
11
11
|
const logger_1 = require("./logger");
|
|
12
|
-
function
|
|
12
|
+
function execFileAsync(file, args, execOptions) {
|
|
13
13
|
return new Promise((res, rej) => {
|
|
14
|
-
(0, child_process_1.
|
|
14
|
+
(0, child_process_1.execFile)(file, args, { ...execOptions, windowsHide: true }, (err, stdout) => {
|
|
15
15
|
if (err) {
|
|
16
16
|
return rej(err);
|
|
17
17
|
}
|
|
@@ -22,7 +22,14 @@ function execAsync(command, execOptions) {
|
|
|
22
22
|
async function cloneFromUpstream(url, destination, { originName, depth } = {
|
|
23
23
|
originName: 'origin',
|
|
24
24
|
}) {
|
|
25
|
-
await
|
|
25
|
+
await execFileAsync('git', [
|
|
26
|
+
'clone',
|
|
27
|
+
url,
|
|
28
|
+
destination,
|
|
29
|
+
...(depth ? ['--depth', `${depth}`] : []),
|
|
30
|
+
'--origin',
|
|
31
|
+
originName,
|
|
32
|
+
], {
|
|
26
33
|
cwd: (0, path_1.dirname)(destination),
|
|
27
34
|
maxBuffer: 10 * 1024 * 1024,
|
|
28
35
|
});
|
|
@@ -34,7 +41,7 @@ class GitRepository {
|
|
|
34
41
|
this.root = this.getGitRootPath(this.directory);
|
|
35
42
|
}
|
|
36
43
|
getGitRootPath(cwd) {
|
|
37
|
-
return (0, child_process_1.
|
|
44
|
+
return (0, child_process_1.execFileSync)('git', ['rev-parse', '--show-toplevel'], {
|
|
38
45
|
cwd,
|
|
39
46
|
windowsHide: true,
|
|
40
47
|
})
|
|
@@ -42,17 +49,22 @@ class GitRepository {
|
|
|
42
49
|
.trim();
|
|
43
50
|
}
|
|
44
51
|
async hasUncommittedChanges() {
|
|
45
|
-
const data = await this.
|
|
52
|
+
const data = await this.execGit(['status', '--porcelain']);
|
|
46
53
|
return data.trim() !== '';
|
|
47
54
|
}
|
|
48
55
|
async addFetchRemote(remoteName, branch) {
|
|
49
|
-
return await this.
|
|
56
|
+
return await this.execGit([
|
|
57
|
+
'config',
|
|
58
|
+
'--add',
|
|
59
|
+
`remote.${remoteName}.fetch`,
|
|
60
|
+
`+refs/heads/${branch}:refs/remotes/${remoteName}/${branch}`,
|
|
61
|
+
]);
|
|
50
62
|
}
|
|
51
63
|
async showStat() {
|
|
52
|
-
return await this.
|
|
64
|
+
return await this.execGit(['show', '--stat']);
|
|
53
65
|
}
|
|
54
66
|
async listBranches() {
|
|
55
|
-
return (await this.
|
|
67
|
+
return (await this.execGit(['ls-remote', '--heads', '--quiet']))
|
|
56
68
|
.trim()
|
|
57
69
|
.split('\n')
|
|
58
70
|
.map((s) => s
|
|
@@ -63,45 +75,58 @@ class GitRepository {
|
|
|
63
75
|
async getGitFiles(path) {
|
|
64
76
|
// Use -z to return file names exactly as they are stored in git, separated by NULL (\x00) character.
|
|
65
77
|
// This avoids problems with special characters in file names.
|
|
66
|
-
return (await this.
|
|
78
|
+
return (await this.execGit(['ls-files', '-z', '--', path]))
|
|
67
79
|
.trim()
|
|
68
80
|
.split('\x00')
|
|
69
81
|
.map((s) => s.trim())
|
|
70
82
|
.filter(Boolean);
|
|
71
83
|
}
|
|
72
84
|
async reset(ref) {
|
|
73
|
-
return await this.
|
|
85
|
+
return await this.execGit(['reset', '--hard', ref]);
|
|
74
86
|
}
|
|
75
87
|
async mergeUnrelatedHistories(ref, message) {
|
|
76
|
-
return await this.
|
|
88
|
+
return await this.execGit([
|
|
89
|
+
'merge',
|
|
90
|
+
ref,
|
|
91
|
+
'-X',
|
|
92
|
+
'ours',
|
|
93
|
+
'--allow-unrelated-histories',
|
|
94
|
+
'-m',
|
|
95
|
+
message,
|
|
96
|
+
]);
|
|
77
97
|
}
|
|
78
98
|
async fetch(remote, ref) {
|
|
79
|
-
return await this.
|
|
99
|
+
return await this.execGit(['fetch', remote, ...(ref ? [ref] : [])]);
|
|
80
100
|
}
|
|
81
101
|
async checkout(branch, opts) {
|
|
82
|
-
return await this.
|
|
102
|
+
return await this.execGit([
|
|
103
|
+
'checkout',
|
|
104
|
+
...(opts.new ? ['-b'] : []),
|
|
105
|
+
branch,
|
|
106
|
+
...(opts.base ? [opts.base] : []),
|
|
107
|
+
]);
|
|
83
108
|
}
|
|
84
109
|
async move(path, destination) {
|
|
85
|
-
return await this.
|
|
110
|
+
return await this.execGit(['mv', '--', path, destination]);
|
|
86
111
|
}
|
|
87
112
|
async push(ref, remoteName) {
|
|
88
|
-
return await this.
|
|
113
|
+
return await this.execGit(['push', '-u', '-f', remoteName, ref]);
|
|
89
114
|
}
|
|
90
115
|
async commit(message) {
|
|
91
|
-
return await this.
|
|
116
|
+
return await this.execGit(['commit', '-am', message]);
|
|
92
117
|
}
|
|
93
118
|
async amendCommit() {
|
|
94
|
-
return await this.
|
|
119
|
+
return await this.execGit(['commit', '--amend', '-a', '--no-edit']);
|
|
95
120
|
}
|
|
96
121
|
async deleteGitRemote(name) {
|
|
97
|
-
return await this.
|
|
122
|
+
return await this.execGit(['remote', 'rm', name]);
|
|
98
123
|
}
|
|
99
124
|
async addGitRemote(name, url) {
|
|
100
|
-
return await this.
|
|
125
|
+
return await this.execGit(['remote', 'add', name, url]);
|
|
101
126
|
}
|
|
102
127
|
async hasFilterRepoInstalled() {
|
|
103
128
|
try {
|
|
104
|
-
await this.
|
|
129
|
+
await this.execGit(['filter-repo', '--help']);
|
|
105
130
|
return true;
|
|
106
131
|
}
|
|
107
132
|
catch {
|
|
@@ -114,35 +139,57 @@ class GitRepository {
|
|
|
114
139
|
// NOTE: filter-repo requires POSIX path to work
|
|
115
140
|
const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
|
|
116
141
|
const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
142
|
+
const sourcePath = ensureTrailingSlash(sourcePosixPath);
|
|
143
|
+
const destinationPath = ensureTrailingSlash(destinationPosixPath);
|
|
144
|
+
await this.execGit([
|
|
145
|
+
'filter-repo',
|
|
146
|
+
'-f',
|
|
147
|
+
...(source !== '' ? ['--path', sourcePosixPath] : []),
|
|
148
|
+
...(source !== destination
|
|
149
|
+
? ['--path-rename', `${sourcePath}:${destinationPath}`]
|
|
150
|
+
: []),
|
|
151
|
+
]);
|
|
120
152
|
}
|
|
121
153
|
async filterBranch(source, destination, branchName) {
|
|
122
154
|
// We need non-ASCII file names to not be quoted, or else filter-branch will exclude them.
|
|
123
|
-
await this.
|
|
155
|
+
await this.execGit(['config', 'core.quotepath', 'false']);
|
|
124
156
|
// NOTE: filter-repo requires POSIX path to work
|
|
125
157
|
const sourcePosixPath = source.split(path_1.sep).join(path_1.posix.sep);
|
|
126
158
|
const destinationPosixPath = destination.split(path_1.sep).join(path_1.posix.sep);
|
|
127
159
|
// First, if the source is not a root project, then only include commits relevant to the subdirectory.
|
|
128
160
|
if (source !== '') {
|
|
129
|
-
const indexFilterCommand =
|
|
130
|
-
await this.
|
|
161
|
+
const indexFilterCommand = `node ${quoteForShell((0, path_1.join)(__dirname, 'git-utils.index-filter.js'))}`;
|
|
162
|
+
await this.execGit([
|
|
163
|
+
'filter-branch',
|
|
164
|
+
'-f',
|
|
165
|
+
'--index-filter',
|
|
166
|
+
indexFilterCommand,
|
|
167
|
+
'--prune-empty',
|
|
168
|
+
'--',
|
|
169
|
+
branchName,
|
|
170
|
+
], {
|
|
131
171
|
NX_IMPORT_SOURCE: sourcePosixPath,
|
|
132
172
|
NX_IMPORT_DESTINATION: destinationPosixPath,
|
|
133
173
|
});
|
|
134
174
|
}
|
|
135
175
|
// Then, move files to their new location if necessary.
|
|
136
176
|
if (source === '' || source !== destination) {
|
|
137
|
-
const treeFilterCommand =
|
|
138
|
-
await this.
|
|
177
|
+
const treeFilterCommand = `node ${quoteForShell((0, path_1.join)(__dirname, 'git-utils.tree-filter.js'))}`;
|
|
178
|
+
await this.execGit([
|
|
179
|
+
'filter-branch',
|
|
180
|
+
'-f',
|
|
181
|
+
'--tree-filter',
|
|
182
|
+
treeFilterCommand,
|
|
183
|
+
'--',
|
|
184
|
+
branchName,
|
|
185
|
+
], {
|
|
139
186
|
NX_IMPORT_SOURCE: sourcePosixPath,
|
|
140
187
|
NX_IMPORT_DESTINATION: destinationPosixPath,
|
|
141
188
|
});
|
|
142
189
|
}
|
|
143
190
|
}
|
|
144
|
-
|
|
145
|
-
return
|
|
191
|
+
execGit(args, env) {
|
|
192
|
+
return execFileAsync('git', args, {
|
|
146
193
|
cwd: this.root,
|
|
147
194
|
maxBuffer: 10 * 1024 * 1024,
|
|
148
195
|
env: {
|
|
@@ -151,25 +198,14 @@ class GitRepository {
|
|
|
151
198
|
},
|
|
152
199
|
});
|
|
153
200
|
}
|
|
154
|
-
quotePath(path, ensureTrailingSlash) {
|
|
155
|
-
return this.quoteArg(ensureTrailingSlash && path !== '' && !path.endsWith('/')
|
|
156
|
-
? `${path}/`
|
|
157
|
-
: path);
|
|
158
|
-
}
|
|
159
|
-
quoteArg(arg) {
|
|
160
|
-
return process.platform === 'win32'
|
|
161
|
-
? // Windows/CMD only understands double-quotes, single-quotes are treated as part of the file name
|
|
162
|
-
// Bash and other shells will substitute `$` in file names with a variable value.
|
|
163
|
-
`"${arg
|
|
164
|
-
// Need to keep two slashes for Windows or else the path will be invalid.
|
|
165
|
-
// e.g. 'C:\Users\bob\projects\repo' is invalid, but 'C:\\Users\\bob\\projects\\repo' is valid
|
|
166
|
-
.replaceAll('\\', '\\\\')}"`
|
|
167
|
-
: // e.g. `git mv "$$file.txt" "libs/a/$$file.txt"` will not work since `$$` is swapped with the PID of the last process.
|
|
168
|
-
// Using single-quotes prevents this substitution.
|
|
169
|
-
`'${arg}'`;
|
|
170
|
-
}
|
|
171
201
|
}
|
|
172
202
|
exports.GitRepository = GitRepository;
|
|
203
|
+
function ensureTrailingSlash(path) {
|
|
204
|
+
return path !== '' && !path.endsWith('/') ? `${path}/` : path;
|
|
205
|
+
}
|
|
206
|
+
function quoteForShell(arg) {
|
|
207
|
+
return `'${arg.replaceAll("'", "'\"'\"'")}'`;
|
|
208
|
+
}
|
|
173
209
|
function parseVcsRemoteUrl(url) {
|
|
174
210
|
// Remove whitespace and handle common URL formats
|
|
175
211
|
const cleanUrl = url.trim();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable root for Nx runtime artifacts that need an OS tmp location. On POSIX a
|
|
3
|
+
* literal `/tmp`, not `os.tmpdir()`, which honours `$TMPDIR` — per-user on
|
|
4
|
+
* macOS, rewritten by sandboxes, stripped from the daemon env, so client and
|
|
5
|
+
* daemon would disagree. Windows has no `/tmp`, and `%TMP%` is already per-user
|
|
6
|
+
* and stable, so it keeps `os.tmpdir()`.
|
|
7
|
+
*
|
|
8
|
+
* Consumed by the native binding loader, so keep this file limited to local
|
|
9
|
+
* helpers that themselves use Node builtins only.
|
|
10
|
+
*/
|
|
11
|
+
export declare const NX_TMP_DIR: string;
|
|
12
|
+
/**
|
|
13
|
+
* Owner-only runtime root for the current user. No user segment on Windows —
|
|
14
|
+
* `%TMP%` is already per-account, and the segment would only cost path length.
|
|
15
|
+
*/
|
|
16
|
+
export declare const NX_USER_TMP_DIR: string;
|
|
17
|
+
/** Runtime root under the user's home, used when the shared container cannot be established. */
|
|
18
|
+
export declare const NX_HOME_TMP_DIR: string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NX_HOME_TMP_DIR = exports.NX_USER_TMP_DIR = exports.NX_TMP_DIR = void 0;
|
|
4
|
+
const node_os_1 = require("node:os");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const owned_private_dir_1 = require("./owned-private-dir");
|
|
7
|
+
/**
|
|
8
|
+
* Stable root for Nx runtime artifacts that need an OS tmp location. On POSIX a
|
|
9
|
+
* literal `/tmp`, not `os.tmpdir()`, which honours `$TMPDIR` — per-user on
|
|
10
|
+
* macOS, rewritten by sandboxes, stripped from the daemon env, so client and
|
|
11
|
+
* daemon would disagree. Windows has no `/tmp`, and `%TMP%` is already per-user
|
|
12
|
+
* and stable, so it keeps `os.tmpdir()`.
|
|
13
|
+
*
|
|
14
|
+
* Consumed by the native binding loader, so keep this file limited to local
|
|
15
|
+
* helpers that themselves use Node builtins only.
|
|
16
|
+
*/
|
|
17
|
+
exports.NX_TMP_DIR = (0, node_os_1.platform)() === 'win32' ? (0, node_path_1.join)((0, node_os_1.tmpdir)(), '.nx') : '/tmp/.nx';
|
|
18
|
+
/**
|
|
19
|
+
* Owner-only runtime root for the current user. No user segment on Windows —
|
|
20
|
+
* `%TMP%` is already per-account, and the segment would only cost path length.
|
|
21
|
+
*/
|
|
22
|
+
exports.NX_USER_TMP_DIR = (0, node_os_1.platform)() === 'win32' ? exports.NX_TMP_DIR : (0, node_path_1.join)(exports.NX_TMP_DIR, (0, owned_private_dir_1.getUserSegment)());
|
|
23
|
+
/** Runtime root under the user's home, used when the shared container cannot be established. */
|
|
24
|
+
exports.NX_HOME_TMP_DIR = resolveHomeTmpDir();
|
|
25
|
+
/**
|
|
26
|
+
* Absolute, not merely non-empty: a relative `$HOME` would make `join` return
|
|
27
|
+
* `.nx`, putting sockets under the cwd and aiming `removeSocketDir`'s recursive
|
|
28
|
+
* delete at it. A rootless container has no `$HOME` and no passwd entry, so
|
|
29
|
+
* `homedir()` throws or returns empty — caught here because this runs at module
|
|
30
|
+
* scope and the native binding loader imports this file.
|
|
31
|
+
*/
|
|
32
|
+
function resolveHomeTmpDir() {
|
|
33
|
+
try {
|
|
34
|
+
const home = (0, node_os_1.homedir)();
|
|
35
|
+
return home && (0, node_path_1.isAbsolute)(home) ? (0, node_path_1.join)(home, '.nx') : undefined;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
declare const safeSharedRootBrand: unique symbol;
|
|
2
|
+
declare const sharedRootEstablishedBrand: unique symbol;
|
|
3
|
+
declare const ownedRealDirBrand: unique symbol;
|
|
4
|
+
declare const ownedPrivateDirBrand: unique symbol;
|
|
5
|
+
/** Verified safe to keep an owner-only directory under. Not created. */
|
|
6
|
+
export type SafeSharedRoot = string & {
|
|
7
|
+
readonly [safeSharedRootBrand]: true;
|
|
8
|
+
};
|
|
9
|
+
/** Created if absent, then verified safe as above. */
|
|
10
|
+
export type EstablishedSharedRoot = string & {
|
|
11
|
+
readonly [sharedRootEstablishedBrand]: true;
|
|
12
|
+
};
|
|
13
|
+
/** An existing real directory owned by us. Mode is *not* checked. */
|
|
14
|
+
export type OwnedRealDir = string & {
|
|
15
|
+
readonly [ownedRealDirBrand]: true;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* POSIX: created if absent, owned by us, and carrying no group or other bits —
|
|
19
|
+
* re-locked first if it was looser. The mode is checked on whichever branch
|
|
20
|
+
* produced it, so the brand does not depend on who created the directory.
|
|
21
|
+
*
|
|
22
|
+
* Windows: only *is a real directory*. `getuid` is unavailable there, so
|
|
23
|
+
* neither ownership nor mode is checked; `%TMP%` is already per-account.
|
|
24
|
+
*/
|
|
25
|
+
export type OwnedPrivateDir = string & {
|
|
26
|
+
readonly [ownedPrivateDirBrand]: true;
|
|
27
|
+
};
|
|
28
|
+
/** Why a guard refused a directory. Data, not a sentence: `remedyFor` decides on it. */
|
|
29
|
+
export type DirRefusal = {
|
|
30
|
+
kind: 'not-created';
|
|
31
|
+
dir: string;
|
|
32
|
+
code?: string;
|
|
33
|
+
} | {
|
|
34
|
+
kind: 'not-inspectable';
|
|
35
|
+
dir: string;
|
|
36
|
+
code?: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'not-a-directory';
|
|
39
|
+
dir: string;
|
|
40
|
+
symlink?: true;
|
|
41
|
+
} | {
|
|
42
|
+
kind: 'foreign-owner';
|
|
43
|
+
dir: string;
|
|
44
|
+
uid: number;
|
|
45
|
+
} | {
|
|
46
|
+
kind: 'foreign-shared-container';
|
|
47
|
+
dir: string;
|
|
48
|
+
uid: number;
|
|
49
|
+
} | {
|
|
50
|
+
kind: 'not-tightenable';
|
|
51
|
+
dir: string;
|
|
52
|
+
mode: number;
|
|
53
|
+
} | {
|
|
54
|
+
kind: 'peer-writable-not-sticky';
|
|
55
|
+
dir: string;
|
|
56
|
+
mode: number;
|
|
57
|
+
};
|
|
58
|
+
/** A guard's verdict. */
|
|
59
|
+
export type GuardResult<T> = {
|
|
60
|
+
status: 'ok';
|
|
61
|
+
path: T;
|
|
62
|
+
} | {
|
|
63
|
+
status: 'refused';
|
|
64
|
+
refusal: DirRefusal;
|
|
65
|
+
};
|
|
66
|
+
/** The user-facing sentence for a refusal. The only place wording is decided. */
|
|
67
|
+
export declare function describeRefusal(r: DirRefusal): string;
|
|
68
|
+
/** What the user can do about a refusal, or `undefined` when there is nothing. */
|
|
69
|
+
export declare function remedyFor(r: DirRefusal): string | undefined;
|
|
70
|
+
/** One refusal as an `Error`, so several can travel in an `AggregateError`. */
|
|
71
|
+
export declare class DirectoryRefusedError extends Error {
|
|
72
|
+
readonly refusal: DirRefusal;
|
|
73
|
+
constructor(refusal: DirRefusal);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Whether a shared container is safe to keep an owner-only directory under.
|
|
77
|
+
*
|
|
78
|
+
* On POSIX, a container writable by other users must be sticky, and it must be
|
|
79
|
+
* owned by either root or the current user. Windows short-circuits after the
|
|
80
|
+
* directory test — the OS temp root is already scoped to one account, so there
|
|
81
|
+
* is no shared level whose ownership could matter.
|
|
82
|
+
*
|
|
83
|
+
* Sticky directories still let the directory's own owner rename entries, so a
|
|
84
|
+
* container owned by another unprivileged user could replace a previously
|
|
85
|
+
* verified private directory beneath it.
|
|
86
|
+
*/
|
|
87
|
+
export declare function isSafeSharedRoot(dir: string): GuardResult<SafeSharedRoot>;
|
|
88
|
+
/**
|
|
89
|
+
* Whether other users on this machine can write into `dir`. Gates whether a
|
|
90
|
+
* refusal message may cite other users, so it must not over-report: `false` on
|
|
91
|
+
* Windows, where libuv synthesizes `st_mode` from the READONLY attribute and
|
|
92
|
+
* reports an ordinary per-account directory as `0666`, and `false` on a path
|
|
93
|
+
* that cannot be inspected.
|
|
94
|
+
*
|
|
95
|
+
* `statSync`, not `lstatSync`: the question is about the directory that will be
|
|
96
|
+
* used, not the link pointing at it. Link modes mislead in both directions —
|
|
97
|
+
* Linux creates symlinks `0777`, macOS applies the umask. Nothing here decides
|
|
98
|
+
* whether a path is accepted, so following the link costs nothing the guards
|
|
99
|
+
* do not already re-check.
|
|
100
|
+
*/
|
|
101
|
+
export declare function isPeerWritable(dir: string): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Create a shared container as sticky + world-writable if it does not exist,
|
|
104
|
+
* and report whether the resulting path is safe for the current user.
|
|
105
|
+
*
|
|
106
|
+
* **A container that already exists is never modified — only judged.** Do not
|
|
107
|
+
* chmod before deciding trust: `CAP_FOWNER` (root's default in Docker and most
|
|
108
|
+
* CI images) can chmod a directory it does not own, so a peer-owned root would
|
|
109
|
+
* be widened to `1777` and then refused, and an operator who deliberately
|
|
110
|
+
* tightened this root would have it re-widened on every `nx` process.
|
|
111
|
+
*/
|
|
112
|
+
export declare function ensureSafeSharedRoot(dir: string): GuardResult<EstablishedSharedRoot>;
|
|
113
|
+
/**
|
|
114
|
+
* Whether `dir` is an existing real directory owned by us. Unlike
|
|
115
|
+
* `ensureOwnedPrivateDir` it creates nothing and repairs nothing — for callers
|
|
116
|
+
* that only want to know whether a path is safe to act on, such as deleting.
|
|
117
|
+
*/
|
|
118
|
+
export declare function isOwnedRealDirectory(dir: string): OwnedRealDir | null;
|
|
119
|
+
/** The path segment separating one user's Nx runtime state from another's. */
|
|
120
|
+
export declare function getUserSegment(): string;
|
|
121
|
+
/**
|
|
122
|
+
* Ensure `dir` exists, is a real directory owned by us, and carries no group or
|
|
123
|
+
* other bits at all — read and search alone reach a socket inside it, so 0755 is
|
|
124
|
+
* re-locked rather than accepted. A `refused` status carries which check said
|
|
125
|
+
* no — usually `foreign-owner` for a directory another user planted, but also
|
|
126
|
+
* `not-created`/`not-inspectable` for a filesystem error, `not-a-directory`, or
|
|
127
|
+
* `not-tightenable` when the re-lock did not land.
|
|
128
|
+
*
|
|
129
|
+
* Node builtins only: reached from the native binding loader.
|
|
130
|
+
*/
|
|
131
|
+
export declare function ensureOwnedPrivateDir(dir: string): GuardResult<OwnedPrivateDir>;
|
|
132
|
+
export {};
|