typescript-virtual-container 1.5.3 → 1.5.5

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.
Files changed (371) hide show
  1. package/README.md +44 -532
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/SSHMimic/executor.js +23 -5
  4. package/dist/VirtualPackageManager/index.js +10 -0
  5. package/dist/VirtualShell/shell.js +158 -11
  6. package/dist/commands/basename.d.ts +13 -0
  7. package/dist/commands/basename.js +45 -0
  8. package/dist/commands/bc.d.ts +2 -0
  9. package/dist/commands/bc.js +28 -0
  10. package/dist/commands/file.d.ts +8 -0
  11. package/dist/commands/file.js +57 -0
  12. package/dist/commands/fun.d.ts +32 -0
  13. package/dist/commands/fun.js +172 -0
  14. package/dist/commands/ip.d.ts +7 -0
  15. package/dist/commands/ip.js +52 -0
  16. package/dist/commands/jobs.d.ts +4 -0
  17. package/dist/commands/jobs.js +27 -0
  18. package/dist/commands/last.d.ts +13 -0
  19. package/dist/commands/last.js +68 -0
  20. package/dist/commands/manuals-bundle.js +598 -6
  21. package/dist/commands/registry.js +30 -2
  22. package/dist/commands/runtime.js +24 -3
  23. package/dist/commands/set.js +20 -0
  24. package/dist/commands/sh.js +74 -1
  25. package/dist/commands/tput.d.ts +13 -0
  26. package/dist/commands/tput.js +76 -0
  27. package/dist/commands/w.d.ts +7 -0
  28. package/dist/commands/w.js +38 -0
  29. package/dist/utils/expand.d.ts +12 -0
  30. package/dist/utils/expand.js +87 -1
  31. package/package.json +9 -3
  32. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -50
  33. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -31
  34. package/.github/dependabot.yml +0 -27
  35. package/.github/pull_request_template.md +0 -21
  36. package/.github/workflows/create-pull-request.yml +0 -85
  37. package/.github/workflows/publish.yml +0 -25
  38. package/.github/workflows/test-battery.yml +0 -102
  39. package/.vscode/settings.json +0 -20
  40. package/CODE_OF_CONDUCT.md +0 -39
  41. package/CONTRIBUTING.md +0 -59
  42. package/HONEYPOT.md +0 -358
  43. package/SECURITY.md +0 -33
  44. package/benchmark-results.txt +0 -40
  45. package/benchmark-virtualshell.ts +0 -88
  46. package/biome.json +0 -37
  47. package/build.js +0 -22
  48. package/builds/fortune-nyx-v1.5.3-directbash-k6.1.0.mjs +0 -1764
  49. package/builds/fortune-nyx-v1.5.3-ssh-nosftp.js +0 -1764
  50. package/builds/fortune-nyx-v1.5.3-ssh.cjs +0 -1765
  51. package/builds/fortune-nyx-v1.5.3-web.min.js +0 -17036
  52. package/bun.lock +0 -244
  53. package/docs/.nojekyll +0 -1
  54. package/docs/app.js +0 -1751
  55. package/docs/assets/hierarchy.js +0 -1
  56. package/docs/assets/highlight.css +0 -162
  57. package/docs/assets/icons.js +0 -18
  58. package/docs/assets/icons.svg +0 -1
  59. package/docs/assets/main.js +0 -60
  60. package/docs/assets/navigation.js +0 -1
  61. package/docs/assets/search.js +0 -1
  62. package/docs/assets/style.css +0 -1633
  63. package/docs/classes/HoneyPot.html +0 -31
  64. package/docs/classes/IdleManager.html +0 -162
  65. package/docs/classes/SshClient.html +0 -66
  66. package/docs/classes/VirtualFileSystem.html +0 -279
  67. package/docs/classes/VirtualPackageManager.html +0 -63
  68. package/docs/classes/VirtualSftpServer.html +0 -169
  69. package/docs/classes/VirtualShell.html +0 -285
  70. package/docs/classes/VirtualSshServer.html +0 -182
  71. package/docs/classes/VirtualUserManager.html +0 -276
  72. package/docs/demo.html +0 -82
  73. package/docs/functions/assertDiff.html +0 -6
  74. package/docs/functions/diffSnapshots.html +0 -7
  75. package/docs/functions/formatDiff.html +0 -6
  76. package/docs/functions/getArg.html +0 -13
  77. package/docs/functions/getFlag.html +0 -15
  78. package/docs/functions/ifFlag.html +0 -11
  79. package/docs/hierarchy.html +0 -1
  80. package/docs/index.html +0 -1869
  81. package/docs/interfaces/AuditLogEntry.html +0 -6
  82. package/docs/interfaces/CommandContext.html +0 -22
  83. package/docs/interfaces/CommandResult.html +0 -26
  84. package/docs/interfaces/ExecStream.html +0 -11
  85. package/docs/interfaces/HoneyPotStats.html +0 -16
  86. package/docs/interfaces/IdleManagerOptions.html +0 -7
  87. package/docs/interfaces/InstalledPackage.html +0 -20
  88. package/docs/interfaces/NanoEditorSession.html +0 -8
  89. package/docs/interfaces/PackageDefinition.html +0 -30
  90. package/docs/interfaces/PackageFile.html +0 -8
  91. package/docs/interfaces/PasswordChallenge.html +0 -16
  92. package/docs/interfaces/RemoveOptions.html +0 -4
  93. package/docs/interfaces/ShellEnv.html +0 -6
  94. package/docs/interfaces/ShellModule.html +0 -14
  95. package/docs/interfaces/ShellProperties.html +0 -14
  96. package/docs/interfaces/ShellStream.html +0 -11
  97. package/docs/interfaces/SudoChallenge.html +0 -24
  98. package/docs/interfaces/VfsBaseNode.html +0 -12
  99. package/docs/interfaces/VfsDiff.html +0 -10
  100. package/docs/interfaces/VfsDiffEntry.html +0 -6
  101. package/docs/interfaces/VfsDiffModified.html +0 -10
  102. package/docs/interfaces/VfsDirectoryNode.html +0 -15
  103. package/docs/interfaces/VfsFileNode.html +0 -17
  104. package/docs/interfaces/VfsOptions.html +0 -26
  105. package/docs/interfaces/VfsSnapshot.html +0 -3
  106. package/docs/interfaces/VfsSnapshotBaseNode.html +0 -8
  107. package/docs/interfaces/VfsSnapshotDirectoryNode.html +0 -10
  108. package/docs/interfaces/VfsSnapshotFileNode.html +0 -12
  109. package/docs/interfaces/VirtualActiveSession.html +0 -12
  110. package/docs/interfaces/VirtualSftpServerOptions.html +0 -7
  111. package/docs/interfaces/VirtualShellVfsLike.html +0 -15
  112. package/docs/interfaces/VirtualShellVfsOptions.html +0 -3
  113. package/docs/interfaces/WriteFileOptions.html +0 -6
  114. package/docs/media/LICENSE +0 -21
  115. package/docs/modules.html +0 -1
  116. package/docs/types/ArgParseOptions.html +0 -4
  117. package/docs/types/CommandMode.html +0 -2
  118. package/docs/types/CommandOutcome.html +0 -2
  119. package/docs/types/IdleState.html +0 -1
  120. package/docs/types/VfsNodeStats.html +0 -2
  121. package/docs/types/VfsNodeType.html +0 -2
  122. package/docs/types/VfsPersistenceMode.html +0 -5
  123. package/docs/types/VfsSnapshotNode.html +0 -2
  124. package/examples/README.md +0 -288
  125. package/examples/app.js +0 -1751
  126. package/examples/app.ts +0 -299
  127. package/examples/build.js +0 -27
  128. package/examples/demo.html +0 -33
  129. package/examples/honeypot-audit.ts +0 -180
  130. package/examples/honeypot-export.ts +0 -253
  131. package/examples/honeypot-quickstart.ts +0 -110
  132. package/examples/index.html +0 -82
  133. package/examples/server.js +0 -55
  134. package/polyfills/buffer.js +0 -117
  135. package/polyfills/node_child_process/index.js +0 -2
  136. package/polyfills/node_crypto/index.js +0 -167
  137. package/polyfills/node_events/index.js +0 -9
  138. package/polyfills/node_fs/index.js +0 -202
  139. package/polyfills/node_fs/promises.js +0 -4
  140. package/polyfills/node_os/index.js +0 -9
  141. package/polyfills/node_path/index.js +0 -28
  142. package/polyfills/node_vm/index.js +0 -7
  143. package/polyfills/node_zlib/index.js +0 -3
  144. package/polyfills/process.js +0 -14
  145. package/polyfills/ssh2/index.js +0 -75
  146. package/scripts/build-all.mjs +0 -226
  147. package/scripts/build-names.mjs +0 -43
  148. package/scripts/generate-manuals-bundle.mjs +0 -49
  149. package/scripts/postinstall.js +0 -42
  150. package/scripts/publish-package.sh +0 -70
  151. package/src/Honeypot/index.ts +0 -457
  152. package/src/SSHClient/index.ts +0 -270
  153. package/src/SSHMimic/exec.ts +0 -49
  154. package/src/SSHMimic/executor.ts +0 -251
  155. package/src/SSHMimic/hostKey.ts +0 -21
  156. package/src/SSHMimic/index.ts +0 -337
  157. package/src/SSHMimic/loginBanner.ts +0 -36
  158. package/src/SSHMimic/loginFormat.ts +0 -10
  159. package/src/SSHMimic/prompt.ts +0 -14
  160. package/src/SSHMimic/sftp.ts +0 -883
  161. package/src/VirtualFileSystem/binaryPack.ts +0 -258
  162. package/src/VirtualFileSystem/index.ts +0 -1193
  163. package/src/VirtualFileSystem/internalTypes.ts +0 -43
  164. package/src/VirtualFileSystem/journal.ts +0 -171
  165. package/src/VirtualFileSystem/path.ts +0 -74
  166. package/src/VirtualPackageManager/index.ts +0 -996
  167. package/src/VirtualShell/idleManager.ts +0 -137
  168. package/src/VirtualShell/index.ts +0 -475
  169. package/src/VirtualShell/shell.ts +0 -700
  170. package/src/VirtualShell/shellParser.ts +0 -285
  171. package/src/VirtualUserManager/index.ts +0 -758
  172. package/src/bun.d.ts +0 -1
  173. package/src/commands/adduser.ts +0 -103
  174. package/src/commands/alias.ts +0 -69
  175. package/src/commands/apt.ts +0 -233
  176. package/src/commands/awk.ts +0 -168
  177. package/src/commands/base64.ts +0 -29
  178. package/src/commands/cat.ts +0 -52
  179. package/src/commands/cd.ts +0 -25
  180. package/src/commands/chmod.ts +0 -85
  181. package/src/commands/clear.ts +0 -15
  182. package/src/commands/command-helpers.ts +0 -286
  183. package/src/commands/cp.ts +0 -83
  184. package/src/commands/curl.ts +0 -147
  185. package/src/commands/cut.ts +0 -36
  186. package/src/commands/date.ts +0 -30
  187. package/src/commands/declare.ts +0 -49
  188. package/src/commands/deluser.ts +0 -98
  189. package/src/commands/df.ts +0 -23
  190. package/src/commands/diff.ts +0 -43
  191. package/src/commands/dpkg.ts +0 -180
  192. package/src/commands/du.ts +0 -56
  193. package/src/commands/echo.ts +0 -58
  194. package/src/commands/env.ts +0 -23
  195. package/src/commands/exit.ts +0 -18
  196. package/src/commands/export.ts +0 -34
  197. package/src/commands/find.ts +0 -68
  198. package/src/commands/free.ts +0 -47
  199. package/src/commands/grep.ts +0 -116
  200. package/src/commands/groups.ts +0 -19
  201. package/src/commands/gzip.ts +0 -88
  202. package/src/commands/head.ts +0 -52
  203. package/src/commands/help.ts +0 -152
  204. package/src/commands/helpers.ts +0 -234
  205. package/src/commands/history.ts +0 -34
  206. package/src/commands/hostname.ts +0 -14
  207. package/src/commands/htop.ts +0 -20
  208. package/src/commands/id.ts +0 -19
  209. package/src/commands/index.ts +0 -9
  210. package/src/commands/kill.ts +0 -19
  211. package/src/commands/ln.ts +0 -71
  212. package/src/commands/ls.ts +0 -243
  213. package/src/commands/lsb-release.ts +0 -63
  214. package/src/commands/man.ts +0 -31
  215. package/src/commands/manuals/adduser.txt +0 -11
  216. package/src/commands/manuals/apt-cache.txt +0 -12
  217. package/src/commands/manuals/apt.txt +0 -20
  218. package/src/commands/manuals/awk.txt +0 -13
  219. package/src/commands/manuals/cat.txt +0 -14
  220. package/src/commands/manuals/cd.txt +0 -16
  221. package/src/commands/manuals/chmod.txt +0 -16
  222. package/src/commands/manuals/clear.txt +0 -10
  223. package/src/commands/manuals/cp.txt +0 -10
  224. package/src/commands/manuals/curl.txt +0 -20
  225. package/src/commands/manuals/date.txt +0 -14
  226. package/src/commands/manuals/declare.txt +0 -12
  227. package/src/commands/manuals/deluser.txt +0 -10
  228. package/src/commands/manuals/df.txt +0 -10
  229. package/src/commands/manuals/dpkg-query.txt +0 -11
  230. package/src/commands/manuals/dpkg.txt +0 -14
  231. package/src/commands/manuals/du.txt +0 -11
  232. package/src/commands/manuals/echo.txt +0 -11
  233. package/src/commands/manuals/false.txt +0 -10
  234. package/src/commands/manuals/find.txt +0 -11
  235. package/src/commands/manuals/free.txt +0 -12
  236. package/src/commands/manuals/grep.txt +0 -13
  237. package/src/commands/manuals/groups.txt +0 -10
  238. package/src/commands/manuals/gzip.txt +0 -11
  239. package/src/commands/manuals/head.txt +0 -10
  240. package/src/commands/manuals/help.txt +0 -11
  241. package/src/commands/manuals/history.txt +0 -11
  242. package/src/commands/manuals/hostname.txt +0 -10
  243. package/src/commands/manuals/id.txt +0 -10
  244. package/src/commands/manuals/kill.txt +0 -13
  245. package/src/commands/manuals/ls.txt +0 -20
  246. package/src/commands/manuals/lsb_release.txt +0 -14
  247. package/src/commands/manuals/mkdir.txt +0 -10
  248. package/src/commands/manuals/mv.txt +0 -10
  249. package/src/commands/manuals/nano.txt +0 -11
  250. package/src/commands/manuals/neofetch.txt +0 -10
  251. package/src/commands/manuals/node.txt +0 -13
  252. package/src/commands/manuals/npm.txt +0 -13
  253. package/src/commands/manuals/npx.txt +0 -13
  254. package/src/commands/manuals/passwd.txt +0 -11
  255. package/src/commands/manuals/ping.txt +0 -10
  256. package/src/commands/manuals/printf.txt +0 -11
  257. package/src/commands/manuals/ps.txt +0 -10
  258. package/src/commands/manuals/pwd.txt +0 -10
  259. package/src/commands/manuals/python3.txt +0 -13
  260. package/src/commands/manuals/readlink.txt +0 -10
  261. package/src/commands/manuals/return.txt +0 -10
  262. package/src/commands/manuals/rm.txt +0 -10
  263. package/src/commands/manuals/sed.txt +0 -11
  264. package/src/commands/manuals/set.txt +0 -11
  265. package/src/commands/manuals/shift.txt +0 -10
  266. package/src/commands/manuals/sleep.txt +0 -10
  267. package/src/commands/manuals/sort.txt +0 -12
  268. package/src/commands/manuals/source.txt +0 -11
  269. package/src/commands/manuals/ssh.txt +0 -11
  270. package/src/commands/manuals/stat.txt +0 -10
  271. package/src/commands/manuals/su.txt +0 -13
  272. package/src/commands/manuals/sudo.txt +0 -11
  273. package/src/commands/manuals/tail.txt +0 -10
  274. package/src/commands/manuals/tar.txt +0 -19
  275. package/src/commands/manuals/tee.txt +0 -10
  276. package/src/commands/manuals/test.txt +0 -11
  277. package/src/commands/manuals/touch.txt +0 -11
  278. package/src/commands/manuals/tr.txt +0 -10
  279. package/src/commands/manuals/trap.txt +0 -10
  280. package/src/commands/manuals/true.txt +0 -10
  281. package/src/commands/manuals/type.txt +0 -10
  282. package/src/commands/manuals/uname.txt +0 -12
  283. package/src/commands/manuals/uniq.txt +0 -12
  284. package/src/commands/manuals/unset.txt +0 -10
  285. package/src/commands/manuals/uptime.txt +0 -11
  286. package/src/commands/manuals/wc.txt +0 -12
  287. package/src/commands/manuals/wget.txt +0 -12
  288. package/src/commands/manuals/which.txt +0 -10
  289. package/src/commands/manuals/whoami.txt +0 -10
  290. package/src/commands/manuals/xargs.txt +0 -10
  291. package/src/commands/manuals-bundle.ts +0 -898
  292. package/src/commands/mkdir.ts +0 -31
  293. package/src/commands/mv.ts +0 -50
  294. package/src/commands/nano.ts +0 -38
  295. package/src/commands/neofetch.ts +0 -53
  296. package/src/commands/node.ts +0 -341
  297. package/src/commands/npm.ts +0 -132
  298. package/src/commands/passwd.ts +0 -50
  299. package/src/commands/ping.ts +0 -32
  300. package/src/commands/printf.ts +0 -129
  301. package/src/commands/ps.ts +0 -58
  302. package/src/commands/pwd.ts +0 -9
  303. package/src/commands/python.ts +0 -2229
  304. package/src/commands/read.ts +0 -46
  305. package/src/commands/registry.ts +0 -249
  306. package/src/commands/rm.ts +0 -42
  307. package/src/commands/runtime.ts +0 -421
  308. package/src/commands/sed.ts +0 -68
  309. package/src/commands/seq.ts +0 -43
  310. package/src/commands/set.ts +0 -29
  311. package/src/commands/sh.ts +0 -467
  312. package/src/commands/shift.ts +0 -63
  313. package/src/commands/sleep.ts +0 -20
  314. package/src/commands/sort.ts +0 -46
  315. package/src/commands/source.ts +0 -52
  316. package/src/commands/stat.ts +0 -61
  317. package/src/commands/su.ts +0 -72
  318. package/src/commands/sudo.ts +0 -76
  319. package/src/commands/tail.ts +0 -53
  320. package/src/commands/tar.ts +0 -102
  321. package/src/commands/tee.ts +0 -36
  322. package/src/commands/test.ts +0 -137
  323. package/src/commands/touch.ts +0 -28
  324. package/src/commands/tr.ts +0 -70
  325. package/src/commands/tree.ts +0 -20
  326. package/src/commands/true.ts +0 -27
  327. package/src/commands/type.ts +0 -48
  328. package/src/commands/uname.ts +0 -29
  329. package/src/commands/uniq.ts +0 -39
  330. package/src/commands/unset.ts +0 -17
  331. package/src/commands/uptime.ts +0 -54
  332. package/src/commands/wc.ts +0 -55
  333. package/src/commands/wget.ts +0 -148
  334. package/src/commands/which.ts +0 -37
  335. package/src/commands/who.ts +0 -25
  336. package/src/commands/whoami.ts +0 -14
  337. package/src/commands/xargs.ts +0 -31
  338. package/src/index.ts +0 -67
  339. package/src/modules/linuxRootfs.ts +0 -1961
  340. package/src/modules/neofetch.ts +0 -358
  341. package/src/modules/shellInteractive.ts +0 -57
  342. package/src/modules/shellRuntime.ts +0 -76
  343. package/src/self-standalone.ts +0 -542
  344. package/src/standalone-wo-sftp.ts +0 -38
  345. package/src/standalone.ts +0 -72
  346. package/src/types/commands.ts +0 -146
  347. package/src/types/pipeline.ts +0 -52
  348. package/src/types/streams.ts +0 -32
  349. package/src/types/tar-stream.d.ts +0 -38
  350. package/src/types/vfs.ts +0 -98
  351. package/src/utils/expand.ts +0 -491
  352. package/src/utils/perfLogger.ts +0 -72
  353. package/src/utils/tokenize.ts +0 -98
  354. package/src/utils/vfsDiff.ts +0 -275
  355. package/tests/command-helpers.test.ts +0 -116
  356. package/tests/commands-admin-net.test.ts +0 -441
  357. package/tests/commands-advanced.test.ts +0 -456
  358. package/tests/commands-core.test.ts +0 -562
  359. package/tests/commands-missing.test.ts +0 -570
  360. package/tests/commands-specific-units.test.ts +0 -327
  361. package/tests/commands-text-sys.test.ts +0 -445
  362. package/tests/expand.test.ts +0 -170
  363. package/tests/helpers.test.ts +0 -97
  364. package/tests/new-features.test.ts +0 -1036
  365. package/tests/parser-executor.test.ts +0 -37
  366. package/tests/sftp.test.ts +0 -323
  367. package/tests/ssh-exec.test.ts +0 -45
  368. package/tests/test-helper.ts +0 -79
  369. package/tests/users.test.ts +0 -86
  370. package/tsconfig.json +0 -49
  371. package/typedoc.json +0 -47
@@ -1,37 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import { VirtualShell } from "../src";
3
- import { executePipeline } from "../src/SSHMimic/executor";
4
- import { parseShellPipeline } from "../src/VirtualShell/shellParser";
5
-
6
- describe("Pipeline parser and executor", () => {
7
- test("parses simple pipeline", () => {
8
- const pipeline = parseShellPipeline("echo hello | grep h");
9
- expect(pipeline.isValid).toBe(true);
10
- expect(pipeline.commands).toHaveLength(2);
11
- expect(pipeline.commands[0]?.name).toBe("echo");
12
- expect(pipeline.commands[1]?.name).toBe("grep");
13
- });
14
-
15
- test("handles invalid syntax", () => {
16
- const pipeline = parseShellPipeline("echo hello |");
17
- expect(pipeline.isValid).toBe(false);
18
- expect(pipeline.error).toBeDefined();
19
- });
20
-
21
- test("executes simple pipeline", async () => {
22
- const shell = new VirtualShell("localhost");
23
- const pipeline = parseShellPipeline("echo hello | grep h");
24
-
25
- const result = await executePipeline(
26
- pipeline,
27
- "root",
28
- "localhost",
29
- "shell",
30
- "/",
31
- shell,
32
- );
33
-
34
- expect(result.exitCode).toBe(0);
35
- expect(result.stdout).toContain("hello");
36
- });
37
- });
@@ -1,323 +0,0 @@
1
- /// <reference types="bun" />
2
- import { describe, expect, test } from "bun:test";
3
- import type { FileEntryWithStats, SFTPWrapper } from "ssh2";
4
- import { Client } from "ssh2";
5
- import { SftpMimic } from "../src/SSHMimic/sftp";
6
- import VirtualFileSystem from "../src/VirtualFileSystem";
7
- import { VirtualUserManager } from "../src/VirtualUserManager";
8
-
9
- // VirtualFileSystem is now pure in-memory — no temp dir or cleanup needed.
10
-
11
- function connectSftp(
12
- port: number,
13
- ): Promise<{ client: Client; sftp: SFTPWrapper }> {
14
- return new Promise((resolve, reject) => {
15
- const client = new Client();
16
- client.on("ready", () => {
17
- client.sftp((err, sftp) => {
18
- if (err) {
19
- client.end();
20
- reject(err);
21
- return;
22
- }
23
- resolve({ client, sftp });
24
- });
25
- });
26
- client.on("error", reject);
27
- client.connect({
28
- host: "127.0.0.1",
29
- port,
30
- username: "root",
31
- password: "", // root has no password — any value or empty is accepted
32
- hostVerifier: () => true,
33
- });
34
- });
35
- }
36
-
37
- function connectSftpWithUser(
38
- port: number,
39
- username: string,
40
- password: string,
41
- ): Promise<{ client: Client; sftp: SFTPWrapper }> {
42
- return new Promise((resolve, reject) => {
43
- const client = new Client();
44
- client.on("ready", () => {
45
- client.sftp((err, sftp) => {
46
- if (err) {
47
- client.end();
48
- reject(err);
49
- return;
50
- }
51
- resolve({ client, sftp });
52
- });
53
- });
54
- client.on("error", reject);
55
- client.connect({
56
- host: "127.0.0.1",
57
- port,
58
- username,
59
- password,
60
- hostVerifier: () => true,
61
- });
62
- });
63
- }
64
-
65
- describe("SftpMimic", () => {
66
- test("authenticates with VirtualUserManager and serves files from the VirtualFileSystem", async () => {
67
- const vfs = new VirtualFileSystem();
68
- const users = new VirtualUserManager(vfs);
69
-
70
- await users.initialize();
71
-
72
- const rootPath = "/root";
73
- if (!vfs.exists(rootPath)) {
74
- vfs.mkdir(rootPath, 0o755);
75
- }
76
- vfs.writeFile(`${rootPath}/TEST.txt`, "hello world");
77
-
78
- const server = new SftpMimic({
79
- port: 0,
80
- hostname: "test-sftp",
81
- vfs,
82
- users,
83
- });
84
- const port = await server.start();
85
-
86
- try {
87
- const { client, sftp } = await connectSftp(port);
88
-
89
- const list = await new Promise<FileEntryWithStats[]>(
90
- (resolve, reject) => {
91
- sftp.readdir(
92
- "/root",
93
- (err?: Error | null, list?: FileEntryWithStats[]) => {
94
- if (err) {
95
- reject(err);
96
- return;
97
- }
98
- resolve(list || []);
99
- },
100
- );
101
- },
102
- );
103
-
104
- expect(list.map((entry) => entry.filename)).toContain("TEST.txt");
105
-
106
- const content = await new Promise<string>((resolve, reject) => {
107
- sftp.readFile(
108
- "/root/TEST.txt",
109
- "utf8",
110
- (err?: Error | null, data?: Buffer) => {
111
- if (err) {
112
- reject(err);
113
- return;
114
- }
115
- resolve((data || Buffer.alloc(0)).toString("utf8"));
116
- },
117
- );
118
- });
119
-
120
- expect(content).toBe("hello world");
121
- client.end();
122
- } finally {
123
- server.stop();
124
- }
125
- });
126
-
127
- test("blocks path traversal attempts outside home directory", async () => {
128
- const vfs = new VirtualFileSystem();
129
- const users = new VirtualUserManager(vfs);
130
-
131
- await users.initialize();
132
-
133
- const rootPath = "/root";
134
- if (!vfs.exists(rootPath)) {
135
- vfs.mkdir(rootPath, 0o755);
136
- }
137
-
138
- const server = new SftpMimic({
139
- port: 0,
140
- hostname: "test-sftp",
141
- vfs,
142
- users,
143
- });
144
- const port = await server.start();
145
-
146
- try {
147
- const { client, sftp } = await connectSftp(port);
148
-
149
- // /etc/passwd is outside /root — should be rejected
150
- const traversalAttempt = await new Promise<Error | null>((resolve) => {
151
- sftp.stat("/etc/passwd", (err?: Error | null) => {
152
- resolve(err ?? null);
153
- });
154
- });
155
-
156
- expect(traversalAttempt).not.toBeNull();
157
- expect(traversalAttempt?.message).toContain("Permission denied");
158
-
159
- // /root itself should work
160
- const homeAccess = await new Promise<FileEntryWithStats[]>(
161
- (resolve, reject) => {
162
- sftp.readdir(
163
- "/root",
164
- (err?: Error | null, list?: FileEntryWithStats[]) => {
165
- if (err) {
166
- reject(err);
167
- return;
168
- }
169
- resolve(list || []);
170
- },
171
- );
172
- },
173
- );
174
- expect(homeAccess).toBeDefined();
175
-
176
- // Path traversal via ../.. should also be rejected
177
- const upTraversalAttempt = await new Promise<Error | null>((resolve) => {
178
- sftp.readdir("/root/../../etc", (err?: Error | null) => {
179
- resolve(err ?? null);
180
- });
181
- });
182
- expect(upTraversalAttempt).not.toBeNull();
183
-
184
- client.end();
185
- } finally {
186
- server.stop();
187
- }
188
- });
189
-
190
- test("allows a user with a password to authenticate", async () => {
191
- const vfs = new VirtualFileSystem();
192
- const users = new VirtualUserManager(vfs);
193
-
194
- await users.initialize();
195
- await users.addUser("alice", "alice-pass");
196
-
197
- // Ensure alice's home exists (addUser should create it, but let's be explicit)
198
- if (!vfs.exists("/home/alice")) {
199
- vfs.mkdir("/home/alice", 0o755);
200
- }
201
- vfs.writeFile("/home/alice/hello.txt", "hi alice");
202
-
203
- const server = new SftpMimic({
204
- port: 0,
205
- hostname: "test-sftp",
206
- vfs,
207
- users,
208
- });
209
- const port = await server.start();
210
-
211
- try {
212
- const { client, sftp } = await connectSftpWithUser(
213
- port,
214
- "alice",
215
- "alice-pass",
216
- );
217
-
218
- const list = await new Promise<FileEntryWithStats[]>(
219
- (resolve, reject) => {
220
- sftp.readdir(
221
- "/home/alice",
222
- (err?: Error | null, list?: FileEntryWithStats[]) => {
223
- if (err) {
224
- reject(err);
225
- return;
226
- }
227
- resolve(list || []);
228
- },
229
- );
230
- },
231
- );
232
-
233
- expect(list.map((e) => e.filename)).toContain("hello.txt");
234
-
235
- client.end();
236
- } finally {
237
- server.stop();
238
- }
239
- });
240
-
241
- test("rejects a user with a wrong password", async () => {
242
- const vfs = new VirtualFileSystem();
243
- const users = new VirtualUserManager(vfs);
244
-
245
- await users.initialize();
246
- await users.addUser("bob", "correct-pass");
247
-
248
- const server = new SftpMimic({
249
- port: 0,
250
- hostname: "test-sftp",
251
- vfs,
252
- users,
253
- });
254
- const port = await server.start();
255
-
256
- try {
257
- const connectPromise = connectSftpWithUser(port, "bob", "wrong-pass");
258
- await expect(connectPromise).rejects.toThrow();
259
- } finally {
260
- server.stop();
261
- }
262
- });
263
-
264
- test("allows writing and reading back a file over SFTP", async () => {
265
- const vfs = new VirtualFileSystem();
266
- const users = new VirtualUserManager(vfs);
267
-
268
- await users.initialize();
269
-
270
- if (!vfs.exists("/root")) {
271
- vfs.mkdir("/root", 0o755);
272
- }
273
-
274
- const server = new SftpMimic({
275
- port: 0,
276
- hostname: "test-sftp",
277
- vfs,
278
- users,
279
- });
280
- const port = await server.start();
281
-
282
- try {
283
- const { client, sftp } = await connectSftp(port);
284
-
285
- await new Promise<void>((resolve, reject) => {
286
- sftp.writeFile(
287
- "/root/written.txt",
288
- Buffer.from("written via sftp"),
289
- (err?: Error | null) => {
290
- if (err) {
291
- reject(err);
292
- return;
293
- }
294
- resolve();
295
- },
296
- );
297
- });
298
-
299
- const content = await new Promise<string>((resolve, reject) => {
300
- sftp.readFile(
301
- "/root/written.txt",
302
- "utf8",
303
- (err?: Error | null, data?: Buffer) => {
304
- if (err) {
305
- reject(err);
306
- return;
307
- }
308
- resolve((data || Buffer.alloc(0)).toString("utf8"));
309
- },
310
- );
311
- });
312
-
313
- expect(content).toBe("written via sftp");
314
-
315
- // Also verify it landed in the in-memory VFS
316
- expect(vfs.readFile("/root/written.txt")).toBe("written via sftp");
317
-
318
- client.end();
319
- } finally {
320
- server.stop();
321
- }
322
- });
323
- });
@@ -1,45 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import { VirtualShell } from "../src";
3
- import { runExec } from "../src/SSHMimic/exec";
4
-
5
- describe("SSH exec inline commands", () => {
6
- test("runExec sends stdout, stderr, and exit code for inline commands", async () => {
7
- const shell = new VirtualShell("localhost");
8
- const stdout: string[] = [];
9
- const stderr: string[] = [];
10
- let exitCode: number = -1;
11
-
12
- const stream = {
13
- write(data: string) {
14
- stdout.push(data);
15
- },
16
- stderr: {
17
- write(data: string) {
18
- stderr.push(data);
19
- },
20
- },
21
- exit(code: number) {
22
- exitCode = code;
23
- },
24
- end() {
25
- return undefined;
26
- },
27
- };
28
-
29
- await shell.ensureInitialized();
30
-
31
- const endPromise = new Promise<void>((resolve) => {
32
- stream.end = () => {
33
- resolve();
34
- return;
35
- };
36
- });
37
-
38
- runExec(stream as never, "echo hello", "root", "localhost", shell);
39
- await endPromise;
40
-
41
- expect(stdout.join("")).toContain("hello");
42
- expect(stderr.join("")).toBe("");
43
- expect(exitCode).toBe(0);
44
- });
45
- });
@@ -1,79 +0,0 @@
1
- import { VirtualShell } from "../src";
2
- import { SshClient } from "../src/SSHClient";
3
-
4
- /**
5
- * Test helper: creates a fresh shell & client for each test
6
- */
7
- export async function createTestEnv(vmName = "test-shell") {
8
- const shell = new VirtualShell(vmName);
9
- await shell.ensureInitialized();
10
- const client = new SshClient(shell, "root");
11
- return { shell, client };
12
- }
13
-
14
- /**
15
- * Helper: run a single command via SshClient
16
- * @param client SshClient instance
17
- * @param cmd Command string (e.g., "ls /tmp")
18
- * @returns { exitCode, stdout, stderr }
19
- */
20
- export async function runCmd(client: InstanceType<typeof SshClient>, cmd: string) {
21
- return client.exec(cmd);
22
- }
23
-
24
- /**
25
- * Helper: run a piped command
26
- * @param client SshClient instance
27
- * @param cmd Command with pipes (e.g., "echo hello | grep h")
28
- * @returns { exitCode, stdout, stderr }
29
- */
30
- export async function runPipedCmd(client: InstanceType<typeof SshClient>, cmd: string) {
31
- return client.exec(cmd);
32
- }
33
-
34
- /**
35
- * Helper: create a test file in the shell
36
- * @param shell VirtualShell instance
37
- * @param path File path
38
- * @param content File content
39
- */
40
- export function createTestFile(shell: VirtualShell, path: string, content: string) {
41
- shell.vfs.writeFile(path, content);
42
- }
43
-
44
- /**
45
- * Helper: create a test directory
46
- * @param shell VirtualShell instance
47
- * @param path Directory path
48
- */
49
- export function createTestDir(shell: VirtualShell, path: string) {
50
- shell.vfs.mkdir(path);
51
- }
52
-
53
- /**
54
- * Helper: read file from shell
55
- * @param shell VirtualShell instance
56
- * @param path File path
57
- * @returns File content
58
- */
59
- export function readTestFile(shell: VirtualShell, path: string): string {
60
- return shell.vfs.readFile(path);
61
- }
62
-
63
- /**
64
- * Helper: check if path exists
65
- * @param shell VirtualShell instance
66
- * @param path Path to check
67
- * @returns true if exists
68
- */
69
- export function pathExists(shell: VirtualShell, path: string): boolean {
70
- return shell.vfs.exists(path);
71
- }
72
-
73
- /**
74
- * Helper: cleanup test environment
75
- * @param shell VirtualShell instance
76
- */
77
- export function cleanupTestEnv(shell: VirtualShell) {
78
- // No cleanup needed for now, VirtualShell is ephemeral
79
- }
@@ -1,86 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import VirtualFileSystem from "../src/VirtualFileSystem";
3
- import { VirtualUserManager } from "../src/VirtualUserManager";
4
-
5
- function makeVfs() {
6
- return new VirtualFileSystem();
7
- }
8
-
9
- describe("VirtualUserManager auto sudo", () => {
10
- test("adds new users to sudoers by default", async () => {
11
- const vfs = makeVfs();
12
- const users = new VirtualUserManager(vfs);
13
- await users.initialize();
14
- await users.addUser("alice", "alice-pass");
15
- expect(users.isSudoer("alice")).toBe(true);
16
- });
17
-
18
- test("does not auto-add sudoers when disabled", async () => {
19
- const vfs = makeVfs();
20
- const users = new VirtualUserManager(vfs, false);
21
- await users.initialize();
22
- await users.addUser("bob", "bob-pass");
23
- expect(users.isSudoer("bob")).toBe(false);
24
- });
25
-
26
- test("updates password for existing user", async () => {
27
- const vfs = makeVfs();
28
- const users = new VirtualUserManager(vfs);
29
- await users.initialize();
30
- await users.addUser("alice", "alice-pass");
31
- await users.setPassword("alice", "new-pass");
32
- expect(users.verifyPassword("alice", "new-pass")).toBe(true);
33
- expect(users.verifyPassword("alice", "alice-pass")).toBe(false);
34
- });
35
- });
36
-
37
- describe("VirtualUserManager quotas", () => {
38
- test("enforces quota for writes inside user home", async () => {
39
- const vfs = makeVfs();
40
- const users = new VirtualUserManager(vfs);
41
- await users.initialize();
42
- await users.addUser("alice", "alice-pass");
43
- const startingUsage = users.getUsageBytes("alice");
44
- await users.setQuotaBytes("alice", startingUsage + 5);
45
- expect(() => {
46
- users.assertWriteWithinQuota("alice", "/home/alice/note.txt", "hello");
47
- }).not.toThrow();
48
- vfs.writeFile("/home/alice/note.txt", "hello");
49
- expect(() => {
50
- users.assertWriteWithinQuota(
51
- "alice",
52
- "/home/alice/note.txt",
53
- "this exceeds the configured quota",
54
- );
55
- }).toThrow("quota exceeded for 'alice'");
56
- });
57
-
58
- test("does not enforce home quota outside user home", async () => {
59
- const vfs = makeVfs();
60
- const users = new VirtualUserManager(vfs);
61
- await users.initialize();
62
- await users.addUser("bob", "bob-pass");
63
- await users.setQuotaBytes("bob", 1);
64
- expect(() => {
65
- users.assertWriteWithinQuota("bob", "/tmp/shared.txt", "large-content");
66
- }).not.toThrow();
67
- });
68
-
69
- test("clearQuota removes enforced limit", async () => {
70
- const vfs = makeVfs();
71
- const users = new VirtualUserManager(vfs);
72
- await users.initialize();
73
- await users.addUser("charlie", "charlie-pass");
74
- await users.setQuotaBytes("charlie", 2);
75
- expect(users.getQuotaBytes("charlie")).toBe(2);
76
- await users.clearQuota("charlie");
77
- expect(users.getQuotaBytes("charlie")).toBeNull();
78
- expect(() => {
79
- users.assertWriteWithinQuota(
80
- "charlie",
81
- "/home/charlie/file.txt",
82
- "long-content",
83
- );
84
- }).not.toThrow();
85
- });
86
- });
package/tsconfig.json DELETED
@@ -1,49 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- // Environment setup & latest features
4
- "lib": [
5
- "ESNext",
6
- "DOM",
7
- "DOM.Iterable"
8
- ],
9
- "target": "ESNext",
10
- "module": "Preserve",
11
- "moduleDetection": "force",
12
- "jsx": "react-jsx",
13
- "allowJs": true,
14
-
15
- // Bundler mode
16
- "moduleResolution": "bundler",
17
- "verbatimModuleSyntax": true,
18
- "noEmit": false,
19
- "rewriteRelativeImportExtensions": true,
20
-
21
- // Best practices
22
- "strict": true,
23
- "skipLibCheck": true,
24
- "noFallthroughCasesInSwitch": true,
25
- "noUncheckedIndexedAccess": true,
26
- "noImplicitOverride": true,
27
-
28
- // Some stricter flags (disabled by default)
29
- "noUnusedLocals": false,
30
- "noUnusedParameters": false,
31
- "noPropertyAccessFromIndexSignature": false,
32
- "types": [
33
- "node",
34
- "bun"
35
- ],
36
-
37
- "esModuleInterop": true,
38
- "forceConsistentCasingInFileNames": true,
39
- "resolveJsonModule": true,
40
- "declaration": true,
41
- "declarationMap": false,
42
- "rootDir": "src",
43
- "outDir": "dist",
44
- "sourceMap": false,
45
- "composite": true,
46
- "tsBuildInfoFile": "dist/.tsbuildinfo"
47
- },
48
- "include": ["src/**/*"]
49
- }
package/typedoc.json DELETED
@@ -1,47 +0,0 @@
1
- {
2
- "entryPoints": [
3
- "src/index.ts"
4
- ],
5
- "out": "docs",
6
- "name": "typescript-virtual-container",
7
- "includeVersion": true,
8
- "readme": "README.md",
9
- "blockTags": [
10
- "@abstract",
11
- "@alpha",
12
- "@async",
13
- "@beta",
14
- "@decorator",
15
- "@deprecated",
16
- "@eventProperty",
17
- "@example",
18
- "@experimental",
19
- "@fires",
20
- "@ignore",
21
- "@inheritDoc",
22
- "@internal",
23
- "@label",
24
- "@link",
25
- "@module",
26
- "@namespace",
27
- "@override",
28
- "@packageDocumentation",
29
- "@param",
30
- "@privateRemarks",
31
- "@property",
32
- "@public",
33
- "@readonly",
34
- "@remarks",
35
- "@returns",
36
- "@satisfies",
37
- "@sealed",
38
- "@since",
39
- "@throws",
40
- "@typeParam",
41
- "@virtual"
42
- ],
43
- "excludePrivate": true,
44
- "excludeInternal": true,
45
- "treatWarningsAsErrors": false,
46
- "skipErrorChecking": false
47
- }