@git.zone/tsrust 1.9.1 → 1.10.1
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_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/mod_artifact/classes.artifactassembler.d.ts +6 -0
- package/dist_ts/mod_artifact/classes.artifactassembler.js +169 -6
- package/dist_ts/mod_artifact/index.d.ts +1 -1
- package/dist_ts/mod_artifact/index.js +2 -2
- package/dist_ts/mod_cargo/classes.cargorunner.js +8 -5
- package/dist_ts/mod_cli/classes.tsrustcli.d.ts +1 -0
- package/dist_ts/mod_cli/classes.tsrustcli.js +30 -3
- package/dist_ts/mod_cli/helpers.targets.d.ts +2 -0
- package/dist_ts/mod_cli/helpers.targets.js +1 -1
- package/dist_ts/mod_matrix/classes.matrixcommandrunner.d.ts +25 -0
- package/dist_ts/mod_matrix/classes.matrixcommandrunner.js +266 -0
- package/dist_ts/mod_matrix/classes.nativematrixbuilder.d.ts +64 -0
- package/dist_ts/mod_matrix/classes.nativematrixbuilder.js +1078 -0
- package/dist_ts/mod_matrix/helpers.matrixconfig.d.ts +30 -0
- package/dist_ts/mod_matrix/helpers.matrixconfig.js +129 -0
- package/dist_ts/mod_matrix/index.d.ts +3 -0
- package/dist_ts/mod_matrix/index.js +4 -0
- package/dist_ts/mod_provenance/classes.gitstate.d.ts +1 -0
- package/dist_ts/mod_provenance/classes.gitstate.js +13 -3
- package/dist_ts/mod_provenance/classes.provenancestore.d.ts +1 -0
- package/dist_ts/mod_provenance/classes.provenancestore.js +5 -1
- package/dist_ts/mod_provenance/index.d.ts +1 -1
- package/dist_ts/mod_provenance/index.js +2 -2
- package/dist_ts/mod_toolchain/classes.toolchainmanager.d.ts +6 -0
- package/dist_ts/mod_toolchain/classes.toolchainmanager.js +215 -40
- package/package.json +2 -2
- package/readme.hints.md +12 -1
- package/readme.md +69 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +1 -0
- package/ts/mod_artifact/classes.artifactassembler.ts +201 -5
- package/ts/mod_artifact/index.ts +2 -0
- package/ts/mod_cargo/classes.cargorunner.ts +9 -4
- package/ts/mod_cli/classes.tsrustcli.ts +34 -2
- package/ts/mod_cli/helpers.targets.ts +3 -0
- package/ts/mod_matrix/classes.matrixcommandrunner.ts +294 -0
- package/ts/mod_matrix/classes.nativematrixbuilder.ts +1459 -0
- package/ts/mod_matrix/helpers.matrixconfig.ts +222 -0
- package/ts/mod_matrix/index.ts +23 -0
- package/ts/mod_provenance/classes.gitstate.ts +13 -2
- package/ts/mod_provenance/classes.provenancestore.ts +4 -0
- package/ts/mod_provenance/index.ts +1 -0
- package/ts/mod_toolchain/classes.toolchainmanager.ts +242 -43
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import * as crypto from 'crypto';
|
|
1
2
|
import * as fs from 'fs';
|
|
2
3
|
import * as os from 'os';
|
|
3
4
|
import * as path from 'path';
|
|
4
5
|
import * as plugins from '../plugins.js';
|
|
6
|
+
import { getHostIdentity, isLocalProcessRunning } from '../mod_provenance/index.js';
|
|
5
7
|
export class ToolchainManager {
|
|
6
8
|
static TOOLCHAIN_DIR = '/tmp/tsrust_toolchain';
|
|
7
9
|
static RUSTUP_HOME = '/tmp/tsrust_toolchain/rustup';
|
|
@@ -13,6 +15,158 @@ export class ToolchainManager {
|
|
|
13
15
|
executor: 'bash',
|
|
14
16
|
});
|
|
15
17
|
}
|
|
18
|
+
async ensureSecureToolchainDirectory() {
|
|
19
|
+
await fs.promises.mkdir(ToolchainManager.TOOLCHAIN_DIR, {
|
|
20
|
+
recursive: true,
|
|
21
|
+
mode: 0o700,
|
|
22
|
+
});
|
|
23
|
+
const directory = await fs.promises.lstat(ToolchainManager.TOOLCHAIN_DIR);
|
|
24
|
+
if (!directory.isDirectory() || directory.isSymbolicLink()) {
|
|
25
|
+
throw new Error('Bundled Rust toolchain root is not a regular directory');
|
|
26
|
+
}
|
|
27
|
+
if (typeof process.getuid === 'function' && directory.uid !== process.getuid()) {
|
|
28
|
+
throw new Error('Bundled Rust toolchain root is owned by another user');
|
|
29
|
+
}
|
|
30
|
+
await fs.promises.chmod(ToolchainManager.TOOLCHAIN_DIR, 0o700);
|
|
31
|
+
const physicalParent = await fs.promises.realpath(path.dirname(ToolchainManager.TOOLCHAIN_DIR));
|
|
32
|
+
const expectedPhysicalPath = path.join(physicalParent, path.basename(ToolchainManager.TOOLCHAIN_DIR));
|
|
33
|
+
if ((await fs.promises.realpath(ToolchainManager.TOOLCHAIN_DIR)) !== expectedPhysicalPath) {
|
|
34
|
+
throw new Error('Bundled Rust toolchain root traverses a symbolic link');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async isSecureToolchainExecutable(filePathArg) {
|
|
38
|
+
let entry;
|
|
39
|
+
try {
|
|
40
|
+
entry = await fs.promises.lstat(filePathArg);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error.code === 'ENOENT')
|
|
44
|
+
return false;
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
if (!entry.isFile() && !entry.isSymbolicLink()) {
|
|
48
|
+
throw new Error(`Bundled Rust toolchain entry is not a file: ${filePathArg}`);
|
|
49
|
+
}
|
|
50
|
+
const resolvedPath = await fs.promises.realpath(filePathArg);
|
|
51
|
+
const relativePath = path.relative(await fs.promises.realpath(ToolchainManager.TOOLCHAIN_DIR), resolvedPath);
|
|
52
|
+
if (relativePath === '' ||
|
|
53
|
+
relativePath.startsWith('..') ||
|
|
54
|
+
path.isAbsolute(relativePath)) {
|
|
55
|
+
throw new Error(`Bundled Rust toolchain entry escapes its root: ${filePathArg}`);
|
|
56
|
+
}
|
|
57
|
+
const resolved = await fs.promises.stat(resolvedPath);
|
|
58
|
+
if (!resolved.isFile() || (resolved.mode & 0o111) === 0 || (resolved.mode & 0o022) !== 0) {
|
|
59
|
+
throw new Error(`Bundled Rust toolchain executable is unsafe: ${filePathArg}`);
|
|
60
|
+
}
|
|
61
|
+
if (typeof process.getuid === 'function' && resolved.uid !== process.getuid()) {
|
|
62
|
+
throw new Error(`Bundled Rust toolchain executable is owned by another user: ${filePathArg}`);
|
|
63
|
+
}
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
async acquireInstallLock() {
|
|
67
|
+
const lockPath = `${ToolchainManager.TOOLCHAIN_DIR}.install.lock`;
|
|
68
|
+
const lockDirectory = path.dirname(lockPath);
|
|
69
|
+
const temporaryPrefix = `${path.basename(lockPath)}.`;
|
|
70
|
+
const hostIdentity = getHostIdentity();
|
|
71
|
+
for (const entry of await fs.promises.readdir(lockDirectory, { withFileTypes: true })) {
|
|
72
|
+
if (!entry.name.startsWith(temporaryPrefix) || !entry.name.endsWith('.tmp'))
|
|
73
|
+
continue;
|
|
74
|
+
const suffix = entry.name.slice(temporaryPrefix.length, -'.tmp'.length);
|
|
75
|
+
const [entryHostIdentity, pidText, token, ...unexpected] = suffix.split('.');
|
|
76
|
+
const pid = Number(pidText);
|
|
77
|
+
if (unexpected.length > 0 ||
|
|
78
|
+
entryHostIdentity !== hostIdentity ||
|
|
79
|
+
!Number.isSafeInteger(pid) ||
|
|
80
|
+
pid <= 0 ||
|
|
81
|
+
!/^[a-f0-9-]{36}$/.test(token || '') ||
|
|
82
|
+
isLocalProcessRunning(pid)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const temporaryPath = path.join(lockDirectory, entry.name);
|
|
86
|
+
const temporary = await fs.promises.lstat(temporaryPath);
|
|
87
|
+
if (temporary.isFile() &&
|
|
88
|
+
!temporary.isSymbolicLink() &&
|
|
89
|
+
(typeof process.getuid !== 'function' || temporary.uid === process.getuid())) {
|
|
90
|
+
await fs.promises.rm(temporaryPath, { force: true });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const deadline = Date.now() + 5 * 60 * 1000;
|
|
94
|
+
while (Date.now() < deadline) {
|
|
95
|
+
const owner = {
|
|
96
|
+
format: 'tsrust.toolchain-install-lock.v1',
|
|
97
|
+
pid: process.pid,
|
|
98
|
+
hostIdentity,
|
|
99
|
+
token: crypto.randomUUID(),
|
|
100
|
+
};
|
|
101
|
+
const temporaryPath = `${lockPath}.${owner.hostIdentity}.${owner.pid}.${owner.token}.tmp`;
|
|
102
|
+
try {
|
|
103
|
+
const handle = await fs.promises.open(temporaryPath, 'wx', 0o600);
|
|
104
|
+
try {
|
|
105
|
+
await handle.writeFile(`${JSON.stringify(owner)}\n`, 'utf8');
|
|
106
|
+
await handle.sync();
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
await handle.close();
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
await fs.promises.link(temporaryPath, lockPath);
|
|
113
|
+
return owner;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error.code !== 'EEXIST')
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
await fs.promises.rm(temporaryPath, { force: true });
|
|
122
|
+
}
|
|
123
|
+
let lock;
|
|
124
|
+
let contents;
|
|
125
|
+
try {
|
|
126
|
+
lock = await fs.promises.lstat(lockPath);
|
|
127
|
+
contents = await fs.promises.readFile(lockPath, 'utf8');
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (error.code === 'ENOENT')
|
|
131
|
+
continue;
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
if (!lock.isFile() ||
|
|
135
|
+
lock.isSymbolicLink() ||
|
|
136
|
+
(typeof process.getuid === 'function' && lock.uid !== process.getuid()) ||
|
|
137
|
+
(lock.mode & 0o077) !== 0 ||
|
|
138
|
+
lock.size > 4096) {
|
|
139
|
+
throw new Error(`Bundled Rust toolchain install lock is unsafe: ${lockPath}`);
|
|
140
|
+
}
|
|
141
|
+
let existing;
|
|
142
|
+
try {
|
|
143
|
+
existing = JSON.parse(contents);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
throw new Error(`Bundled Rust toolchain install lock is invalid: ${lockPath}`);
|
|
147
|
+
}
|
|
148
|
+
if (existing.format !== 'tsrust.toolchain-install-lock.v1' ||
|
|
149
|
+
!Number.isSafeInteger(existing.pid) ||
|
|
150
|
+
existing.pid <= 0 ||
|
|
151
|
+
!/^[a-f0-9]{64}$/.test(existing.hostIdentity) ||
|
|
152
|
+
!/^[a-f0-9-]{36}$/.test(existing.token)) {
|
|
153
|
+
throw new Error(`Bundled Rust toolchain install lock is invalid: ${lockPath}`);
|
|
154
|
+
}
|
|
155
|
+
if (existing.hostIdentity === hostIdentity && !isLocalProcessRunning(existing.pid)) {
|
|
156
|
+
throw new Error(`Bundled Rust toolchain install lock is stale; inspect and remove ${lockPath} before retrying`);
|
|
157
|
+
}
|
|
158
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
159
|
+
}
|
|
160
|
+
throw new Error('Timed out waiting for the bundled Rust toolchain install lock');
|
|
161
|
+
}
|
|
162
|
+
async releaseInstallLock(ownerArg) {
|
|
163
|
+
const lockPath = `${ToolchainManager.TOOLCHAIN_DIR}.install.lock`;
|
|
164
|
+
const contents = JSON.parse(await fs.promises.readFile(lockPath, 'utf8'));
|
|
165
|
+
if (contents.token !== ownerArg.token) {
|
|
166
|
+
throw new Error('Bundled Rust toolchain install lock ownership changed');
|
|
167
|
+
}
|
|
168
|
+
await fs.promises.unlink(lockPath);
|
|
169
|
+
}
|
|
16
170
|
/**
|
|
17
171
|
* Returns the Rust host triple for the current platform.
|
|
18
172
|
*/
|
|
@@ -32,62 +186,83 @@ export class ToolchainManager {
|
|
|
32
186
|
/**
|
|
33
187
|
* Checks if the bundled toolchain is already installed at TOOLCHAIN_DIR.
|
|
34
188
|
*/
|
|
189
|
+
async isInstalledUnlocked() {
|
|
190
|
+
await this.ensureSecureToolchainDirectory();
|
|
191
|
+
if (!(await this.isSecureToolchainExecutable(path.join(ToolchainManager.BIN_DIR, 'cargo'))) ||
|
|
192
|
+
!(await this.isSecureToolchainExecutable(path.join(ToolchainManager.BIN_DIR, 'rustup')))) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
const readiness = await this.shell.execSilent(`${this.getEnvPrefix()}cargo --version >/dev/null && rustup --version >/dev/null && rustup show active-toolchain >/dev/null`);
|
|
196
|
+
return readiness.exitCode === 0;
|
|
197
|
+
}
|
|
35
198
|
async isInstalled() {
|
|
36
|
-
const
|
|
199
|
+
const lockOwner = await this.acquireInstallLock();
|
|
37
200
|
try {
|
|
38
|
-
|
|
39
|
-
return stat.isFile();
|
|
201
|
+
return await this.isInstalledUnlocked();
|
|
40
202
|
}
|
|
41
|
-
|
|
42
|
-
|
|
203
|
+
finally {
|
|
204
|
+
await this.releaseInstallLock(lockOwner);
|
|
43
205
|
}
|
|
44
206
|
}
|
|
45
207
|
/**
|
|
46
208
|
* Downloads rustup-init and installs a minimal Rust toolchain to TOOLCHAIN_DIR.
|
|
47
209
|
*/
|
|
48
|
-
async
|
|
210
|
+
async installUnlocked() {
|
|
211
|
+
await this.ensureSecureToolchainDirectory();
|
|
49
212
|
const triple = this.getHostTriple();
|
|
50
213
|
const rustupInitUrl = `https://static.rust-lang.org/rustup/dist/${triple}/rustup-init`;
|
|
51
214
|
const rustupInitPath = path.join(ToolchainManager.TOOLCHAIN_DIR, 'rustup-init');
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
215
|
+
await fs.promises.rm(rustupInitPath, { force: true });
|
|
216
|
+
try {
|
|
217
|
+
console.log(`Downloading rustup-init for ${triple}...`);
|
|
218
|
+
const downloadResult = await this.shell.exec(`curl -sSf -o ${rustupInitPath} ${rustupInitUrl} && chmod +x ${rustupInitPath}`);
|
|
219
|
+
if (downloadResult.exitCode !== 0) {
|
|
220
|
+
throw new Error(`Failed to download rustup-init: ${downloadResult.stdout}`);
|
|
221
|
+
}
|
|
222
|
+
console.log('Installing minimal Rust toolchain to /tmp/tsrust_toolchain/...');
|
|
223
|
+
const installCmd = [
|
|
224
|
+
`RUSTUP_HOME="${ToolchainManager.RUSTUP_HOME}"`,
|
|
225
|
+
`CARGO_HOME="${ToolchainManager.CARGO_HOME}"`,
|
|
226
|
+
rustupInitPath,
|
|
227
|
+
'-y',
|
|
228
|
+
'--default-toolchain stable',
|
|
229
|
+
'--profile minimal',
|
|
230
|
+
'--no-modify-path',
|
|
231
|
+
].join(' ');
|
|
232
|
+
const installResult = await this.shell.exec(installCmd);
|
|
233
|
+
if (installResult.exitCode !== 0) {
|
|
234
|
+
throw new Error(`Failed to install Rust toolchain: ${installResult.stdout}`);
|
|
235
|
+
}
|
|
236
|
+
if (!(await this.isInstalledUnlocked())) {
|
|
237
|
+
throw new Error('Installed bundled Rust toolchain failed readiness validation.');
|
|
238
|
+
}
|
|
239
|
+
const verifyResult = await this.shell.execSilent(`${this.getEnvPrefix()}cargo --version`);
|
|
240
|
+
if (verifyResult.exitCode !== 0) {
|
|
241
|
+
throw new Error('Rust toolchain installation verification failed.');
|
|
242
|
+
}
|
|
243
|
+
console.log(`Installed: ${verifyResult.stdout.trim()}`);
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
await fs.promises.rm(rustupInitPath, { force: true });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async install() {
|
|
250
|
+
const lockOwner = await this.acquireInstallLock();
|
|
251
|
+
try {
|
|
252
|
+
if (await this.isInstalledUnlocked())
|
|
253
|
+
return;
|
|
254
|
+
await this.installUnlocked();
|
|
255
|
+
}
|
|
256
|
+
finally {
|
|
257
|
+
await this.releaseInstallLock(lockOwner);
|
|
258
|
+
}
|
|
81
259
|
}
|
|
82
260
|
/**
|
|
83
261
|
* Ensures the bundled toolchain is installed. Downloads if not present.
|
|
84
262
|
*/
|
|
85
263
|
async ensureInstalled() {
|
|
86
|
-
if (await this.isInstalled()) {
|
|
87
|
-
console.log('Using bundled Rust toolchain from /tmp/tsrust_toolchain/');
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
264
|
await this.install();
|
|
265
|
+
console.log('Using bundled Rust toolchain from /tmp/tsrust_toolchain/');
|
|
91
266
|
}
|
|
92
267
|
/**
|
|
93
268
|
* Returns a shell prefix string that sets RUSTUP_HOME, CARGO_HOME, and PATH
|
|
@@ -98,4 +273,4 @@ export class ToolchainManager {
|
|
|
98
273
|
`export PATH="${ToolchainManager.BIN_DIR}:$PATH" && `);
|
|
99
274
|
}
|
|
100
275
|
}
|
|
101
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50b29sY2hhaW5tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvbW9kX3Rvb2xjaGFpbi9jbGFzc2VzLnRvb2xjaGFpbm1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFFekMsTUFBTSxPQUFPLGdCQUFnQjtJQUNwQixNQUFNLENBQUMsYUFBYSxHQUFHLHVCQUF1QixDQUFDO0lBQy9DLE1BQU0sQ0FBQyxXQUFXLEdBQUcsOEJBQThCLENBQUM7SUFDcEQsTUFBTSxDQUFDLFVBQVUsR0FBRyw2QkFBNkIsQ0FBQztJQUNsRCxNQUFNLENBQUMsT0FBTyxHQUFHLGlDQUFpQyxDQUFDO0lBRWxELEtBQUssQ0FBZ0M7SUFFN0M7UUFDRSxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUM7WUFDN0MsUUFBUSxFQUFFLE1BQU07U0FDakIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0ksYUFBYTtRQUNsQixNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDL0IsTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDO1FBRXZCLElBQUksUUFBUSxLQUFLLE9BQU8sSUFBSSxJQUFJLEtBQUssS0FBSztZQUFFLE9BQU8sMEJBQTBCLENBQUM7UUFDOUUsSUFBSSxRQUFRLEtBQUssT0FBTyxJQUFJLElBQUksS0FBSyxPQUFPO1lBQUUsT0FBTywyQkFBMkIsQ0FBQztRQUNqRixJQUFJLFFBQVEsS0FBSyxRQUFRLElBQUksSUFBSSxLQUFLLEtBQUs7WUFB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
|
|
276
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50b29sY2hhaW5tYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvbW9kX3Rvb2xjaGFpbi9jbGFzc2VzLnRvb2xjaGFpbm1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDakMsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxFQUFFLGVBQWUsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBU3BGLE1BQU0sT0FBTyxnQkFBZ0I7SUFDcEIsTUFBTSxDQUFDLGFBQWEsR0FBRyx1QkFBdUIsQ0FBQztJQUMvQyxNQUFNLENBQUMsV0FBVyxHQUFHLDhCQUE4QixDQUFDO0lBQ3BELE1BQU0sQ0FBQyxVQUFVLEdBQUcsNkJBQTZCLENBQUM7SUFDbEQsTUFBTSxDQUFDLE9BQU8sR0FBRyxpQ0FBaUMsQ0FBQztJQUVsRCxLQUFLLENBQWdDO0lBRTdDO1FBQ0UsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLE9BQU8sQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDO1lBQzdDLFFBQVEsRUFBRSxNQUFNO1NBQ2pCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyxLQUFLLENBQUMsOEJBQThCO1FBQzFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsYUFBYSxFQUFFO1lBQ3RELFNBQVMsRUFBRSxJQUFJO1lBQ2YsSUFBSSxFQUFFLEtBQUs7U0FDWixDQUFDLENBQUM7UUFDSCxNQUFNLFNBQVMsR0FBRyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFD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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@git.zone/tsrust",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A tool for compiling Rust projects, detecting Cargo workspaces, building with cargo, and placing binaries in a conventional dist_rust directory.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"last 1 chrome versions"
|
|
58
58
|
],
|
|
59
59
|
"scripts": {
|
|
60
|
-
"test": "tstest test
|
|
60
|
+
"test": "tstest 'test/*.node.ts' --verbose",
|
|
61
61
|
"build": "tsbuild --web"
|
|
62
62
|
}
|
|
63
63
|
}
|
package/readme.hints.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
- Follows tsbuild patterns for the `cli.js` entry point and TypeScript module layout.
|
|
5
5
|
- Uses smartcli for CLI dispatch, smartshell for Cargo execution, native `child_process.execFile` for Git snapshots, and smol-toml for TOML parsing.
|
|
6
6
|
- `mod_artifact` owns strict multi-host assembly; `mod_provenance` owns byte-preserving, hash-bound sidecars and Git source snapshots.
|
|
7
|
+
- `mod_matrix` owns local/SSH worker scheduling, exact Git-bundle transport, capability checks, smoke execution, and artifact collection. It delegates final publication to `mod_artifact`.
|
|
7
8
|
|
|
8
9
|
## Key patterns
|
|
9
10
|
- smartshell `.exec()` streams output to terminal (non-silent)
|
|
@@ -12,4 +13,14 @@
|
|
|
12
13
|
- Binary targets: look for `[[bin]]` entries in member crate Cargo.toml files
|
|
13
14
|
- New builds never append provenance to binaries. Keep legacy `ProvenanceStamper` reads for tsrust 1.7/1.8 artifacts, but use `ProvenanceStore` sidecars for all writes.
|
|
14
15
|
- Host target precedence is CLI, exact host, OS family, legacy targets, then native. Assembly uses the union of all configured targets unless repeated CLI `--target` values define an explicit matrix, and rejects dirty or incomplete matrices.
|
|
15
|
-
- Assembly owns only `dist_rust/`, `.nogit/tsrust-assembly*`, and transient `.nogit/.tsrust-assembly-*.tmp` owner records. Its atomically linked owner lock, serialized recovery claim,
|
|
16
|
+
- Assembly owns only `dist_rust/`, `.nogit/tsrust-assembly*`, and transient `.nogit/.tsrust-assembly-*.tmp` owner records. Its atomically linked owner lock, serialized recovery claim, v2 phase journal, and digest manifest recover readable, owner-consistent transactions; committed v1 state is validated and migrated before completion, while malformed or inconsistent state fails closed.
|
|
17
|
+
- Matrix configuration commits logical host keys, transport selection, environment-variable names, optional explicitly forwarded worker-variable names, and optional smoke arguments. SSH destinations, values, and dedicated temporary roots remain operator-local.
|
|
18
|
+
- Project-controlled worker commands run with synthetic per-run home directories and a restricted baseline. Committed `matrix.forwardEnvironment` requests must be granted separately through operator-owned `TSRUST_MATRIX_ALLOWED_ENVIRONMENT`; never expose transport-only `HOME` or `SSH_AUTH_SOCK` to workload commands.
|
|
19
|
+
- Exact-commit bundle transport accepts regular self-contained files only. Reject submodules, tracked symlinks, checkout filters, and external-content pointer records before cloning workers.
|
|
20
|
+
- Matrix workers build isolated exact-commit clones. Failed local and remote workspaces are retained for diagnostics, capped at three runs per root; successful remote cleanup requires the exact path, commit, token, and regular owner marker.
|
|
21
|
+
- SSH builds use login shells for builder PATH setup and a heartbeat watchdog that kills the owned remote process group if the coordinator disconnects. Commands that deliberately create a new session or process group are outside that ownership boundary.
|
|
22
|
+
- SSH transport uses stdin/stdout streams, not scp. Artifact output is byte-bounded both remotely and locally; bundle input is streamed under the shared worker deadline. Every transfer validates expected architecture and the exact random workspace owner marker in the same connection.
|
|
23
|
+
- Matrix execution assumes the reviewed commit, dependency graph, lifecycle scripts, builders, toolchains, registries, and SSH configuration are trusted. Correctness checks are not same-UID sandboxing.
|
|
24
|
+
- Artifact assembly persists and revalidates an exact staged digest manifest before initial publication and committed-transaction recovery.
|
|
25
|
+
- Revalidate source compatibility and the clean Git snapshot around bundle creation so capability checks cannot leave a stale source decision.
|
|
26
|
+
- Failed matrix workspaces are not pruned automatically. Inspect and remove only the exact diagnostic paths printed by the failed invocation before retrying.
|
package/readme.md
CHANGED
|
@@ -76,7 +76,7 @@ Done in 29.2s
|
|
|
76
76
|
2. **No system toolchain** → checks `/tmp/tsrust_toolchain/` for a previously installed bundled toolchain
|
|
77
77
|
3. **No bundled toolchain** → downloads `rustup-init` and installs a minimal Rust toolchain (~70-90 MB download) to `/tmp/tsrust_toolchain/`
|
|
78
78
|
|
|
79
|
-
The bundled toolchain is stored in `/tmp/`, so it's cleaned up on reboot. Subsequent runs reuse the existing installation.
|
|
79
|
+
The bundled toolchain is stored in `/tmp/`, so it's cleaned up on reboot. Subsequent runs reuse the existing installation. Before executing it, tsrust requires the root to be a current-user-owned, non-symlink directory, restricts it to mode `0700`, verifies that cargo and rustup resolve to current-user-owned executables inside that root that are not group- or world-writable, and requires an active default toolchain. A securely resolved installation that lacks an active default toolchain is repaired through the normal rustup bootstrap path. An atomically published current-user-owned installation lock serializes validation and bootstrap. A dead installer fails closed with the exact lock path for operator inspection instead of risking concurrent stale-lock deletion.
|
|
80
80
|
|
|
81
81
|
Supported platforms for automatic install: Linux (x64, arm64) and macOS (x64, arm64).
|
|
82
82
|
|
|
@@ -199,7 +199,69 @@ The union of `targets` and `targetsByHost` defines the required target matrix. R
|
|
|
199
199
|
|
|
200
200
|
Assembly requires every Cargo binary for every expected target. It rejects missing, duplicate, unexpected, non-executable, symlinked, hash-mismatched, dirty, wrong-commit, wrong-package, and wrong-tsrust-version inputs. Validation and copying happen in a same-filesystem transaction under `.nogit/tsrust-assembly/`, guarded by the atomically published `.nogit/tsrust-assembly.lock`. The Git commit, clean worktree, and package identity are checked again immediately before publication. The previous output is retained until the complete staged matrix is ready, and successful publication removes files left by older matrices.
|
|
201
201
|
|
|
202
|
-
The transaction records a boot-scoped host identity, process, owner token, and
|
|
202
|
+
The transaction records a boot-scoped host identity, process, owner token, publication phase, and exact digest manifest for staged binaries and sidecars. A separate atomic recovery claim serializes dead-owner recovery. When the owner lock and state are readable and consistent, a later invocation on the owning host rejects a live process, rolls back an interrupted pre-commit publication after that process exits, and completes publication or cleanup after durable commit intent only after revalidating the manifest. Legacy committed v1 transactions from tsrust 1.9 are validated against the current exact assembly request, upgraded with a manifest, and then completed; incompatible legacy staging fails closed. A confirmed missing state file is safe to clean because the owner-lock protocol forbids output mutation before initial state persistence; malformed, non-regular, unreadable, owner-inconsistent, or manifest-inconsistent state fails closed. A transaction owned by another host is never taken over automatically because portable filesystem operations cannot fence a paused remote writer. If committed cleanup cannot finish immediately, the programmatic result reports `cleanupPending: true` and the CLI prints a warning; the owning process can retry it immediately.
|
|
203
|
+
|
|
204
|
+
### Native Build Matrix
|
|
205
|
+
|
|
206
|
+
`tsrust matrix` automates host-partitioned builds and strict assembly. Committed configuration identifies expected worker architectures and names the environment variables that contain operator-local SSH details:
|
|
207
|
+
|
|
208
|
+
```json
|
|
209
|
+
{
|
|
210
|
+
"@git.zone/tsrust": {
|
|
211
|
+
"targetsByHost": {
|
|
212
|
+
"linux": ["linux_amd64", "linux_arm64"],
|
|
213
|
+
"macos": ["macos_amd64", "macos_arm64"]
|
|
214
|
+
},
|
|
215
|
+
"locked": true,
|
|
216
|
+
"matrix": {
|
|
217
|
+
"builders": {
|
|
218
|
+
"linux_amd64": {
|
|
219
|
+
"transport": "local"
|
|
220
|
+
},
|
|
221
|
+
"macos_arm64": {
|
|
222
|
+
"transport": "ssh",
|
|
223
|
+
"destinationEnv": "TSRUST_MACOS_SSH",
|
|
224
|
+
"temporaryRootEnv": "TSRUST_MACOS_TEMP_ROOT"
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
"smokeTestArgs": ["--version"],
|
|
228
|
+
"forwardEnvironment": ["NPM_TOKEN"]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Set the referenced values outside the repository. The SSH destination may be an OpenSSH alias or `user@host`; the temporary root must be a dedicated absolute path owned by the remote account:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
export TSRUST_MACOS_SSH="release-user@mac-builder.example"
|
|
238
|
+
export TSRUST_MACOS_TEMP_ROOT="/Users/release-user/.git.zone/tsrust/my-project"
|
|
239
|
+
export TSRUST_MATRIX_ALLOWED_ENVIRONMENT="NPM_TOKEN"
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Builder keys are limited to `linux_amd64`, `linux_arm64`, `macos_amd64`, and `macos_arm64`. At most one worker may use `transport: "local"`. Worker target partitions must be non-empty, disjoint, complete, and from the worker's OS family. Matrix execution probes support the six predefined targets `linux_amd64`, `linux_arm64`, `linux_amd64_musl`, `linux_arm64_musl`, `macos_amd64`, and `macos_arm64`. Native GNU targets require `cc`; non-native GNU probes use their predefined `*-linux-gnu-gcc` command. Musl probes always use their predefined `*-linux-musl-gcc` command. Non-native architectures also require executable emulation.
|
|
243
|
+
|
|
244
|
+
Environment-variable names must match `[A-Za-z_][A-Za-z0-9_]*`. Committed `forwardEnvironment` entries are requests, not grants: every requested name must also appear in the operator-owned comma-separated `TSRUST_MATRIX_ALLOWED_ENVIRONMENT` value or matrix construction fails. Built-in worker and transport names cannot be requested, including `PATH`, `HOME`, `CI`, `RUSTUP_HOME`, `CARGO_HOME`, SSH agent variables, and the grant variable itself. Worker lifecycle commands receive only a small execution baseline, synthetic per-run `HOME` and `CARGO_HOME` directories, and operator-granted names; unrelated coordinator credentials are omitted. For SSH workers, granted values are made available to the SSH client and admitted into project commands only when the remote login environment supplies them, such as through deliberate OpenSSH `SendEnv`/`AcceptEnv` configuration. Values are never placed in the remote command line. SSH destinations are ASCII single aliases or `user@host` values without embedded options, ports, whitespace, or IPv6 syntax. Put ports, identity files, proxy jumps, host-key policy, credentials, and agent selection in OpenSSH configuration or an SSH agent. Temporary roots use an ASCII path whitelist and must be normalized, space-free, multi-component absolute paths whose physical resolution contains no symlink traversal. When present, `smokeTestArgs` must be a non-empty array of single-line, NUL-free strings and must not contain secrets.
|
|
245
|
+
|
|
246
|
+
`matrix check` verifies the exact project-local tsrust package version without executing its binary, the native linker, system Cargo plus rustup with an active default toolchain or the complete securely resolved bundled pair with the same readiness, worker identity, emulation or cross-execution, and remote-root ownership and permissions. It is a capability-only command: it does not require a clean worktree or compare the working configuration with the committed plan. If usable system Cargo is unavailable and the bundled executables are either absent or securely resolved but not ready, it verifies only that `curl` is available for tsrust bootstrap; it does not prove network access, install targets, or compile the project. The check creates the dedicated remote root with restrictive permissions when it is absent. Capability and cleanup commands have a five-minute limit. Dependency installation, compilation, per-binary smoke execution, bundle upload, and bounded artifact retrieval share each worker's one-hour build limit.
|
|
247
|
+
|
|
248
|
+
Run the capability-only check before release metadata is created:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
tsrust matrix check
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Build and atomically publish the complete matrix from a clean exact Git commit:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
tsrust matrix build
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Every worker receives the same exact commit through a streamed Git bundle, installs with `pnpm install --frozen-lockfile`, revalidates the installed tsrust package version, invokes the project-local `tsrust` with explicit targets, and optionally executes every binary with `smokeTestArgs`. Local and remote project commands run with the restricted worker environment. Local and remote workers build in isolated clones, so an incomplete matrix never replaces an existing `dist_rust`. SSH workers use `/bin/bash` on Linux or `/bin/zsh` on macOS in login mode for builds, normal OpenSSH host verification, architecture and random-owner-marker validation on every lifecycle and transfer connection, locally and remotely byte-bounded non-login SSH streams for artifact retrieval, a heartbeat-bound process-group watchdog, and a unique mode-0700 child below the configured root. Remote owner-validated cleanup is a pre-publication gate: failure preserves the prior `dist_rust` and reports retained diagnostics. After successful assembly, failure to remove local staging emits a warning but does not reverse the committed publication.
|
|
261
|
+
|
|
262
|
+
`matrix build` additionally requires the normalized resolved matrix policy to match committed `.smartconfig.json` at the captured commit, a clean Git worktree without `skip-worktree` or `assume-unchanged` flags, package name and version, a frozen pnpm lockfile, and at least one Cargo binary. Matrix transport rejects Git submodules, tracked symbolic links, checkout filters, and external-content pointer records because those inputs are not self-contained regular files in a plain exact-commit bundle. Source compatibility, index flags, and the clean Git snapshot are revalidated around bundle creation and after project-controlled build and smoke commands. Binaries are limited to 2 GiB each, provenance sidecars to 1 MiB each, and an assembly to 8 GiB total. Worker keys are expected host identities, not network addresses. Keep only the SSH destination and temporary root in the referenced variables; keys and credentials remain in OpenSSH configuration or an agent. Failed workspaces are intentionally retained and are not pruned automatically; each local and remote root admits at most three retained failed runs and then requires the operator to inspect and remove the exact reported paths before retrying.
|
|
263
|
+
|
|
264
|
+
Matrix workers are trusted execution principals, not sandboxes. A release therefore trusts the reviewed exact source commit, its lockfile-selected dependencies and lifecycle/build scripts, the selected local and SSH hosts, their toolchains and login configuration, and the registries they contact. Environment filtering, owner markers, source checks, bounded transfers, provenance digests, and transactional publication prevent accidental credential inheritance, stale or incomplete inputs, endpoint mix-ups, and partial publication; they do not contain deliberately malicious code already running as the same operating-system user. Use a separately isolated worker account or container when that trust assumption does not hold.
|
|
203
265
|
|
|
204
266
|
### Static Linking
|
|
205
267
|
|
|
@@ -341,6 +403,7 @@ import {
|
|
|
341
403
|
CargoRunner,
|
|
342
404
|
FsHelpers,
|
|
343
405
|
ProvenanceStore,
|
|
406
|
+
NativeMatrixBuilder,
|
|
344
407
|
TsRustCli,
|
|
345
408
|
configuredAssemblyTargets,
|
|
346
409
|
normalizeTargets,
|
|
@@ -378,6 +441,10 @@ Important exported build and artifact APIs:
|
|
|
378
441
|
| `normalizeTargets()` | Resolve friendly aliases and reject invalid or colliding target names. |
|
|
379
442
|
| `ProvenanceStore` | Write, hash-verify, and read byte-preserving provenance sidecars. |
|
|
380
443
|
| `ArtifactAssembler` | Validate and transactionally publish a complete exact-commit artifact matrix to `dist_rust/`. |
|
|
444
|
+
| `NativeMatrixBuilder` | Check and build an isolated local/SSH native matrix, then delegate publication to `ArtifactAssembler`. |
|
|
445
|
+
| `resolveMatrixPlan()` / `matrixHostKeys` | Validate matrix configuration and inspect its complete disjoint worker schedule. |
|
|
446
|
+
| `MatrixCommandRunner` | Execute bounded matrix subprocesses with process-group, signal, timeout, input, and heartbeat ownership. |
|
|
447
|
+
| Matrix configuration and result types | Type `NativeMatrixBuilder`, worker transports, resolved plans, and check/build results. |
|
|
381
448
|
| `captureGitSnapshot()` / `assertGitSnapshotUnchanged()` | Capture and compare Git commit and worktree state around a build. |
|
|
382
449
|
| `ProvenanceStamper` | Read legacy tsrust 1.7/1.8 embedded trailers; new builds use `ProvenanceStore`. |
|
|
383
450
|
|
package/ts/00_commitinfo_data.ts
CHANGED