@ours.network/install 1.2.1-nightly.5 → 1.2.1-nightly.6
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/assets/release.json +1 -1
- package/assets/sources.json +1 -1
- package/lib/docker-runtime-repair.mjs +27 -7
- package/package.json +1 -1
package/assets/release.json
CHANGED
package/assets/sources.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Qualify cached images before reuse; repair only the known root-owned 0600 policy. */
|
|
2
|
-
import { lstatSync, readFileSync, writeFileSync, mkdtempSync, rmSync } from 'node:fs';
|
|
2
|
+
import { lstatSync, readFileSync, writeFileSync, mkdtempSync, rmSync, realpathSync, openSync, closeSync, fstatSync, fchmodSync, constants } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { createHash, randomUUID } from 'node:crypto';
|
|
5
5
|
import { isDeepStrictEqual } from 'node:util';
|
|
@@ -11,12 +11,32 @@ const fail = message => { throw new Error(`Docker runtime verification refused:
|
|
|
11
11
|
const imageId = value => /^sha256:[0-9a-f]{64}$/.test(value ?? '');
|
|
12
12
|
|
|
13
13
|
export function refreshDockerPolicyCopy(record) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
if (record.workDir !== join(record.root, 'runtime')) fail('Unsafe retained Dockerfile: runtime directory differs from installation record');
|
|
15
|
+
for (const directory of [record.root, record.workDir]) {
|
|
16
|
+
const stat = lstatSync(directory);
|
|
17
|
+
if (!stat.isDirectory() || realpathSync(directory) !== directory) fail('Unsafe retained Dockerfile: installation directory is linked or not canonical');
|
|
18
|
+
if (stat.uid !== process.getuid()) fail('Unsafe retained Dockerfile: installation directory belongs to another user');
|
|
19
|
+
if (stat.mode & 0o7077) fail('Unsafe retained Dockerfile: installation directory must be owner-private (0700)');
|
|
20
|
+
}
|
|
21
|
+
const path = join(record.workDir, 'Dockerfile');
|
|
22
|
+
let fd;
|
|
23
|
+
try { fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK); }
|
|
24
|
+
catch (error) { fail(`Unsafe retained Dockerfile: cannot open a regular unlinked file (${error.code})`); }
|
|
25
|
+
try {
|
|
26
|
+
const stat = fstatSync(fd);
|
|
27
|
+
if (!stat.isFile()) fail('Unsafe retained Dockerfile: expected a regular file');
|
|
28
|
+
if (stat.nlink !== 1) fail('Unsafe retained Dockerfile: hard links are not supported');
|
|
29
|
+
if (stat.uid !== process.getuid()) fail(`Unsafe retained Dockerfile: file owner ${stat.uid} differs from current user ${process.getuid()}`);
|
|
30
|
+
if (stat.mode & 0o7000) fail('Unsafe retained Dockerfile: special permission bits are not supported');
|
|
31
|
+
// Asset copies can retain 0664 under umask 002. Private canonical ancestors
|
|
32
|
+
// exclude other users; normalize this owned inode without following links.
|
|
33
|
+
fchmodSync(fd, 0o600);
|
|
34
|
+
const text = readFileSync(fd, 'utf8');
|
|
35
|
+
const current = lstatSync(path);
|
|
36
|
+
if (current.dev !== stat.dev || current.ino !== stat.ino || current.nlink !== 1) fail('Unsafe retained Dockerfile: file changed during normalization');
|
|
37
|
+
const oldLine = /^COPY sources\.json \/opt\/ours\/sources\.json$/m;
|
|
38
|
+
if (oldLine.test(text)) atomicWriteConfig(path, text.replace(oldLine, 'COPY --chmod=644 sources.json /opt/ours/sources.json'));
|
|
39
|
+
} finally { closeSync(fd); }
|
|
20
40
|
}
|
|
21
41
|
|
|
22
42
|
const probeScript = `
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/install",
|
|
3
|
-
"version": "1.2.1-nightly.
|
|
3
|
+
"version": "1.2.1-nightly.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The all-in-one ours.network installer: one shared daemon, MCP, cowork, Telegram, Fleet initialization, harness plugins, Human identity, progress UI, and guided next steps.",
|
|
6
6
|
"type": "module",
|