@secure-exec/core 0.2.0-rc.1 → 0.2.0-rc.2
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/generated/isolate-runtime.d.ts +2 -2
- package/dist/generated/isolate-runtime.js +2 -2
- package/dist/isolate-runtime/require-setup.js +1351 -239
- package/dist/isolate-runtime/setup-dynamic-import.js +31 -0
- package/dist/kernel/file-lock.js +2 -3
- package/dist/kernel/kernel.js +7 -10
- package/dist/kernel/socket-table.d.ts +7 -0
- package/dist/kernel/socket-table.js +99 -35
- package/dist/shared/bridge-contract.d.ts +21 -3
- package/dist/shared/bridge-contract.js +2 -0
- package/dist/shared/global-exposure.js +95 -0
- package/dist/shared/in-memory-fs.d.ts +3 -0
- package/dist/shared/in-memory-fs.js +74 -39
- package/package.json +1 -1
|
@@ -480,6 +480,11 @@ export const NODE_CUSTOM_GLOBAL_INVENTORY = [
|
|
|
480
480
|
classification: "hardened",
|
|
481
481
|
rationale: "Host HTTP/2 session settings bridge reference.",
|
|
482
482
|
},
|
|
483
|
+
{
|
|
484
|
+
name: "_networkHttp2SessionSetLocalWindowSizeRaw",
|
|
485
|
+
classification: "hardened",
|
|
486
|
+
rationale: "Host HTTP/2 session local-window bridge reference.",
|
|
487
|
+
},
|
|
483
488
|
{
|
|
484
489
|
name: "_networkHttp2SessionGoawayRaw",
|
|
485
490
|
classification: "hardened",
|
|
@@ -500,6 +505,16 @@ export const NODE_CUSTOM_GLOBAL_INVENTORY = [
|
|
|
500
505
|
classification: "hardened",
|
|
501
506
|
rationale: "Host HTTP/2 session lifetime bridge reference.",
|
|
502
507
|
},
|
|
508
|
+
{
|
|
509
|
+
name: "_networkHttp2ServerPollRaw",
|
|
510
|
+
classification: "hardened",
|
|
511
|
+
rationale: "Host HTTP/2 server event-poll bridge reference.",
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
name: "_networkHttp2SessionPollRaw",
|
|
515
|
+
classification: "hardened",
|
|
516
|
+
rationale: "Host HTTP/2 session event-poll bridge reference.",
|
|
517
|
+
},
|
|
503
518
|
{
|
|
504
519
|
name: "_networkHttp2StreamRespondRaw",
|
|
505
520
|
classification: "hardened",
|
|
@@ -520,6 +535,31 @@ export const NODE_CUSTOM_GLOBAL_INVENTORY = [
|
|
|
520
535
|
classification: "hardened",
|
|
521
536
|
rationale: "Host HTTP/2 stream end bridge reference.",
|
|
522
537
|
},
|
|
538
|
+
{
|
|
539
|
+
name: "_networkHttp2StreamCloseRaw",
|
|
540
|
+
classification: "hardened",
|
|
541
|
+
rationale: "Host HTTP/2 stream close bridge reference.",
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
name: "_networkHttp2StreamPauseRaw",
|
|
545
|
+
classification: "hardened",
|
|
546
|
+
rationale: "Host HTTP/2 stream pause bridge reference.",
|
|
547
|
+
},
|
|
548
|
+
{
|
|
549
|
+
name: "_networkHttp2StreamResumeRaw",
|
|
550
|
+
classification: "hardened",
|
|
551
|
+
rationale: "Host HTTP/2 stream resume bridge reference.",
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
name: "_networkHttp2StreamRespondWithFileRaw",
|
|
555
|
+
classification: "hardened",
|
|
556
|
+
rationale: "Host HTTP/2 stream respondWithFile bridge reference.",
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
name: "_networkHttp2ServerRespondRaw",
|
|
560
|
+
classification: "hardened",
|
|
561
|
+
rationale: "Host HTTP/2 server-response bridge reference.",
|
|
562
|
+
},
|
|
523
563
|
{
|
|
524
564
|
name: "_upgradeSocketWriteRaw",
|
|
525
565
|
classification: "hardened",
|
|
@@ -610,6 +650,46 @@ export const NODE_CUSTOM_GLOBAL_INVENTORY = [
|
|
|
610
650
|
classification: "hardened",
|
|
611
651
|
rationale: "Host net server close bridge reference.",
|
|
612
652
|
},
|
|
653
|
+
{
|
|
654
|
+
name: "_dgramSocketCreateRaw",
|
|
655
|
+
classification: "hardened",
|
|
656
|
+
rationale: "Host dgram socket create bridge reference.",
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
name: "_dgramSocketBindRaw",
|
|
660
|
+
classification: "hardened",
|
|
661
|
+
rationale: "Host dgram socket bind bridge reference.",
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
name: "_dgramSocketRecvRaw",
|
|
665
|
+
classification: "hardened",
|
|
666
|
+
rationale: "Host dgram socket receive bridge reference.",
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
name: "_dgramSocketSendRaw",
|
|
670
|
+
classification: "hardened",
|
|
671
|
+
rationale: "Host dgram socket send bridge reference.",
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
name: "_dgramSocketCloseRaw",
|
|
675
|
+
classification: "hardened",
|
|
676
|
+
rationale: "Host dgram socket close bridge reference.",
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
name: "_dgramSocketAddressRaw",
|
|
680
|
+
classification: "hardened",
|
|
681
|
+
rationale: "Host dgram socket address bridge reference.",
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
name: "_dgramSocketSetBufferSizeRaw",
|
|
685
|
+
classification: "hardened",
|
|
686
|
+
rationale: "Host dgram socket buffer-size setter bridge reference.",
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
name: "_dgramSocketGetBufferSizeRaw",
|
|
690
|
+
classification: "hardened",
|
|
691
|
+
rationale: "Host dgram socket buffer-size getter bridge reference.",
|
|
692
|
+
},
|
|
613
693
|
{
|
|
614
694
|
name: "_batchResolveModules",
|
|
615
695
|
classification: "hardened",
|
|
@@ -715,11 +795,26 @@ export const NODE_CUSTOM_GLOBAL_INVENTORY = [
|
|
|
715
795
|
classification: "hardened",
|
|
716
796
|
rationale: "Network Response API global — must not be replaceable by sandbox code.",
|
|
717
797
|
},
|
|
798
|
+
{
|
|
799
|
+
name: "DOMException",
|
|
800
|
+
classification: "hardened",
|
|
801
|
+
rationale: "DOMException global stub for undici/bootstrap compatibility.",
|
|
802
|
+
},
|
|
803
|
+
{
|
|
804
|
+
name: "__importMetaResolve",
|
|
805
|
+
classification: "hardened",
|
|
806
|
+
rationale: "Internal import.meta.resolve helper for transformed ESM modules.",
|
|
807
|
+
},
|
|
718
808
|
{
|
|
719
809
|
name: "Blob",
|
|
720
810
|
classification: "hardened",
|
|
721
811
|
rationale: "Blob API global stub — must not be replaceable by sandbox code.",
|
|
722
812
|
},
|
|
813
|
+
{
|
|
814
|
+
name: "File",
|
|
815
|
+
classification: "hardened",
|
|
816
|
+
rationale: "File API global stub — must not be replaceable by sandbox code.",
|
|
817
|
+
},
|
|
723
818
|
{
|
|
724
819
|
name: "FormData",
|
|
725
820
|
classification: "hardened",
|
|
@@ -53,9 +53,12 @@ export declare class InMemoryFileSystem implements VirtualFileSystem {
|
|
|
53
53
|
private cloneInode;
|
|
54
54
|
private allocateFileInode;
|
|
55
55
|
private allocateDirectoryInode;
|
|
56
|
+
private allocateSymlinkInode;
|
|
56
57
|
private updateFileMetadata;
|
|
57
58
|
private requirePathInode;
|
|
58
59
|
private requireFileInode;
|
|
59
60
|
private requireInode;
|
|
61
|
+
private ensureDirectory;
|
|
62
|
+
private adjustParentDirectoryLinkCount;
|
|
60
63
|
}
|
|
61
64
|
export declare function createInMemoryFileSystem(): InMemoryFileSystem;
|
|
@@ -123,7 +123,7 @@ export class InMemoryFileSystem {
|
|
|
123
123
|
});
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
for (const linkPath of this.symlinks.
|
|
126
|
+
for (const [linkPath, link] of this.symlinks.entries()) {
|
|
127
127
|
if (!linkPath.startsWith(prefix))
|
|
128
128
|
continue;
|
|
129
129
|
const rest = linkPath.slice(prefix.length);
|
|
@@ -132,7 +132,7 @@ export class InMemoryFileSystem {
|
|
|
132
132
|
name: rest,
|
|
133
133
|
isDirectory: false,
|
|
134
134
|
isSymbolicLink: true,
|
|
135
|
-
ino:
|
|
135
|
+
ino: link.ino,
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
138
|
}
|
|
@@ -189,9 +189,7 @@ export class InMemoryFileSystem {
|
|
|
189
189
|
let current = "";
|
|
190
190
|
for (const part of parts) {
|
|
191
191
|
current += `/${part}`;
|
|
192
|
-
|
|
193
|
-
this.dirs.set(current, this.allocateDirectoryInode().ino);
|
|
194
|
-
}
|
|
192
|
+
this.ensureDirectory(current);
|
|
195
193
|
}
|
|
196
194
|
const inode = this.allocateFileInode();
|
|
197
195
|
this.files.set(resolved, inode.ino);
|
|
@@ -218,18 +216,14 @@ export class InMemoryFileSystem {
|
|
|
218
216
|
if (!this.dirs.has(parent)) {
|
|
219
217
|
throw new Error(`ENOENT: no such file or directory, mkdir '${normalized}'`);
|
|
220
218
|
}
|
|
221
|
-
|
|
222
|
-
this.dirs.set(normalized, this.allocateDirectoryInode().ino);
|
|
223
|
-
}
|
|
219
|
+
this.ensureDirectory(normalized);
|
|
224
220
|
}
|
|
225
221
|
async mkdir(path, _options) {
|
|
226
222
|
const parts = splitPath(path);
|
|
227
223
|
let current = "";
|
|
228
224
|
for (const part of parts) {
|
|
229
225
|
current += `/${part}`;
|
|
230
|
-
|
|
231
|
-
this.dirs.set(current, this.allocateDirectoryInode().ino);
|
|
232
|
-
}
|
|
226
|
+
this.ensureDirectory(current);
|
|
233
227
|
}
|
|
234
228
|
}
|
|
235
229
|
resolveIfSymlink(normalized) {
|
|
@@ -238,22 +232,23 @@ export class InMemoryFileSystem {
|
|
|
238
232
|
resolveSymlink(normalized, maxDepth = 16) {
|
|
239
233
|
let current = normalized;
|
|
240
234
|
for (let i = 0; i < maxDepth; i++) {
|
|
241
|
-
const
|
|
242
|
-
if (!
|
|
235
|
+
const link = this.symlinks.get(current);
|
|
236
|
+
if (!link)
|
|
243
237
|
return current;
|
|
244
|
-
current = target.startsWith("/")
|
|
245
|
-
? normalizePath(target)
|
|
246
|
-
: normalizePath(`${dirname(current)}/${target}`);
|
|
238
|
+
current = link.target.startsWith("/")
|
|
239
|
+
? normalizePath(link.target)
|
|
240
|
+
: normalizePath(`${dirname(current)}/${link.target}`);
|
|
247
241
|
}
|
|
248
242
|
throw new Error(`ELOOP: too many levels of symbolic links, stat '${normalized}'`);
|
|
249
243
|
}
|
|
250
244
|
statForInode(inode) {
|
|
251
245
|
const isDirectory = (inode.mode & 0o170000) === S_IFDIR;
|
|
246
|
+
const isSymbolicLink = (inode.mode & 0o170000) === S_IFLNK;
|
|
252
247
|
return {
|
|
253
248
|
mode: inode.mode,
|
|
254
249
|
size: isDirectory ? 4096 : inode.size,
|
|
255
250
|
isDirectory,
|
|
256
|
-
isSymbolicLink
|
|
251
|
+
isSymbolicLink,
|
|
257
252
|
atimeMs: inode.atime.getTime(),
|
|
258
253
|
mtimeMs: inode.mtime.getTime(),
|
|
259
254
|
ctimeMs: inode.ctime.getTime(),
|
|
@@ -295,7 +290,13 @@ export class InMemoryFileSystem {
|
|
|
295
290
|
}
|
|
296
291
|
async removeFile(path) {
|
|
297
292
|
const normalized = normalizePath(path);
|
|
298
|
-
|
|
293
|
+
const symlink = this.symlinks.get(normalized);
|
|
294
|
+
if (symlink) {
|
|
295
|
+
this.symlinks.delete(normalized);
|
|
296
|
+
this.inodeTable.decrementLinks(symlink.ino);
|
|
297
|
+
if (this.inodeTable.shouldDelete(symlink.ino)) {
|
|
298
|
+
this.inodeTable.delete(symlink.ino);
|
|
299
|
+
}
|
|
299
300
|
return;
|
|
300
301
|
}
|
|
301
302
|
const resolved = this.resolveSymlink(normalized);
|
|
@@ -337,6 +338,8 @@ export class InMemoryFileSystem {
|
|
|
337
338
|
const ino = this.dirs.get(normalized);
|
|
338
339
|
this.dirs.delete(normalized);
|
|
339
340
|
this.inodeTable.decrementLinks(ino);
|
|
341
|
+
this.inodeTable.decrementLinks(ino);
|
|
342
|
+
this.adjustParentDirectoryLinkCount(normalized, -1);
|
|
340
343
|
if (this.inodeTable.shouldDelete(ino)) {
|
|
341
344
|
this.inodeTable.delete(ino);
|
|
342
345
|
}
|
|
@@ -412,6 +415,10 @@ export class InMemoryFileSystem {
|
|
|
412
415
|
for (const [path, target] of symlinkEntries) {
|
|
413
416
|
this.symlinks.set(`${targetPrefix}${path.slice(sourcePrefix.length)}`, target);
|
|
414
417
|
}
|
|
418
|
+
if (dirname(oldNormalized) !== dirname(newNormalized)) {
|
|
419
|
+
this.adjustParentDirectoryLinkCount(oldNormalized, -1);
|
|
420
|
+
this.adjustParentDirectoryLinkCount(newNormalized, 1);
|
|
421
|
+
}
|
|
415
422
|
}
|
|
416
423
|
async symlink(target, linkPath) {
|
|
417
424
|
const normalized = normalizePath(linkPath);
|
|
@@ -421,35 +428,22 @@ export class InMemoryFileSystem {
|
|
|
421
428
|
throw new Error(`EEXIST: file already exists, symlink '${target}' -> '${normalized}'`);
|
|
422
429
|
}
|
|
423
430
|
await this.mkdir(dirname(normalized));
|
|
424
|
-
this.
|
|
431
|
+
const inode = this.allocateSymlinkInode(target);
|
|
432
|
+
this.symlinks.set(normalized, { target, ino: inode.ino });
|
|
425
433
|
}
|
|
426
434
|
async readlink(path) {
|
|
427
435
|
const normalized = normalizePath(path);
|
|
428
|
-
const
|
|
429
|
-
if (
|
|
436
|
+
const link = this.symlinks.get(normalized);
|
|
437
|
+
if (link === undefined) {
|
|
430
438
|
throw new Error(`EINVAL: invalid argument, readlink '${normalized}'`);
|
|
431
439
|
}
|
|
432
|
-
return target;
|
|
440
|
+
return link.target;
|
|
433
441
|
}
|
|
434
442
|
async lstat(path) {
|
|
435
443
|
const normalized = normalizePath(path);
|
|
436
|
-
const
|
|
437
|
-
if (
|
|
438
|
-
|
|
439
|
-
return {
|
|
440
|
-
mode: S_IFLNK | 0o777,
|
|
441
|
-
size: new TextEncoder().encode(target).byteLength,
|
|
442
|
-
isDirectory: false,
|
|
443
|
-
isSymbolicLink: true,
|
|
444
|
-
atimeMs: now,
|
|
445
|
-
mtimeMs: now,
|
|
446
|
-
ctimeMs: now,
|
|
447
|
-
birthtimeMs: now,
|
|
448
|
-
ino: 0,
|
|
449
|
-
nlink: 1,
|
|
450
|
-
uid: 0,
|
|
451
|
-
gid: 0,
|
|
452
|
-
};
|
|
444
|
+
const link = this.symlinks.get(normalized);
|
|
445
|
+
if (link !== undefined) {
|
|
446
|
+
return this.statForInode(this.requireInode(link.ino));
|
|
453
447
|
}
|
|
454
448
|
return this.statEntry(normalized);
|
|
455
449
|
}
|
|
@@ -532,11 +526,13 @@ export class InMemoryFileSystem {
|
|
|
532
526
|
reindexInodes(oldTable) {
|
|
533
527
|
const oldContents = new Map(this.fileContents);
|
|
534
528
|
const oldFiles = new Map(this.files);
|
|
529
|
+
const oldSymlinks = new Map(this.symlinks);
|
|
535
530
|
const oldDirs = Array.from(this.dirs.entries()).sort(([a], [b]) => a.length - b.length);
|
|
536
531
|
const inoMap = new Map();
|
|
537
532
|
this.files = new Map();
|
|
538
533
|
this.fileContents = new Map();
|
|
539
534
|
this.dirs = new Map();
|
|
535
|
+
this.symlinks = new Map();
|
|
540
536
|
for (const [dirPath, oldIno] of oldDirs) {
|
|
541
537
|
const ino = this.cloneInode(oldIno, oldTable, S_IFDIR | 0o755).ino;
|
|
542
538
|
this.dirs.set(dirPath, ino);
|
|
@@ -557,6 +553,11 @@ export class InMemoryFileSystem {
|
|
|
557
553
|
this.requireInode(mapped).size = content.byteLength;
|
|
558
554
|
}
|
|
559
555
|
}
|
|
556
|
+
for (const [path, link] of oldSymlinks) {
|
|
557
|
+
const mapped = this.cloneInode(link.ino, oldTable, S_IFLNK | 0o777).ino;
|
|
558
|
+
this.symlinks.set(path, { target: link.target, ino: mapped });
|
|
559
|
+
this.requireInode(mapped).size = new TextEncoder().encode(link.target).byteLength;
|
|
560
|
+
}
|
|
560
561
|
}
|
|
561
562
|
cloneInode(oldIno, oldTable, fallbackMode) {
|
|
562
563
|
const source = oldTable.get(oldIno);
|
|
@@ -575,9 +576,15 @@ export class InMemoryFileSystem {
|
|
|
575
576
|
}
|
|
576
577
|
allocateDirectoryInode() {
|
|
577
578
|
const inode = this.inodeTable.allocate(S_IFDIR | 0o755, 0, 0);
|
|
579
|
+
inode.nlink = 2;
|
|
578
580
|
inode.size = 4096;
|
|
579
581
|
return inode;
|
|
580
582
|
}
|
|
583
|
+
allocateSymlinkInode(target) {
|
|
584
|
+
const inode = this.inodeTable.allocate(S_IFLNK | 0o777, 0, 0);
|
|
585
|
+
inode.size = new TextEncoder().encode(target).byteLength;
|
|
586
|
+
return inode;
|
|
587
|
+
}
|
|
581
588
|
updateFileMetadata(ino, size) {
|
|
582
589
|
const inode = this.requireFileInode(ino);
|
|
583
590
|
const now = new Date();
|
|
@@ -609,6 +616,34 @@ export class InMemoryFileSystem {
|
|
|
609
616
|
}
|
|
610
617
|
return inode;
|
|
611
618
|
}
|
|
619
|
+
ensureDirectory(path) {
|
|
620
|
+
const normalized = normalizePath(path);
|
|
621
|
+
if (normalized === "/")
|
|
622
|
+
return;
|
|
623
|
+
if (this.dirs.has(normalized))
|
|
624
|
+
return;
|
|
625
|
+
const parent = dirname(normalized);
|
|
626
|
+
if (!this.dirs.has(parent)) {
|
|
627
|
+
throw new Error(`ENOENT: no such file or directory, mkdir '${normalized}'`);
|
|
628
|
+
}
|
|
629
|
+
this.dirs.set(normalized, this.allocateDirectoryInode().ino);
|
|
630
|
+
this.adjustParentDirectoryLinkCount(normalized, 1);
|
|
631
|
+
}
|
|
632
|
+
adjustParentDirectoryLinkCount(path, delta) {
|
|
633
|
+
const normalized = normalizePath(path);
|
|
634
|
+
if (normalized === "/")
|
|
635
|
+
return;
|
|
636
|
+
const parent = dirname(normalized);
|
|
637
|
+
const parentIno = this.dirs.get(parent);
|
|
638
|
+
if (parentIno === undefined)
|
|
639
|
+
return;
|
|
640
|
+
if (delta > 0) {
|
|
641
|
+
this.inodeTable.incrementLinks(parentIno);
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
this.inodeTable.decrementLinks(parentIno);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
612
647
|
}
|
|
613
648
|
export function createInMemoryFileSystem() {
|
|
614
649
|
return new InMemoryFileSystem();
|