@eighty4/c2 0.0.3-0 → 0.0.3-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/CHANGELOG.md +4 -2
- package/lib/attachments.ts +2 -2
- package/lib/build.ts +2 -2
- package/lib/c2.api.ts +1 -1
- package/lib/c2.bin.ts +4 -4
- package/lib/expression.ts +1 -1
- package/lib/http.ts +1 -1
- package/lib_js/attachments.js +2 -2
- package/lib_js/build.js +2 -2
- package/lib_js/c2.api.js +1 -1
- package/lib_js/c2.bin.js +4 -4
- package/lib_js/expression.js +1 -1
- package/lib_js/http.js +1 -1
- package/lib_types/c2.api.d.ts +1 -1
- package/lib_types/c2.api.d.ts.map +1 -1
- package/lib_types/http.d.ts +1 -1
- package/lib_types/http.d.ts.map +1 -1
- package/package.json +4 -9
- package/lib/attachments.spec.ts +0 -111
- package/lib/build.spec.ts +0 -90
- package/lib/cli.spec.ts +0 -116
- package/lib/expression.spec.ts +0 -82
- package/lib/http.spec.ts +0 -57
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
### Fixed
|
|
6
6
|
|
|
7
|
-
- TypeScript type declarations were broken
|
|
8
|
-
|
|
7
|
+
- TypeScript type declarations were broken because subpath imports
|
|
8
|
+
used internally in package were output in `.d.ts` files and
|
|
9
|
+
`package.json` pointed `types` to a directory instead of the
|
|
10
|
+
export entrypoint `.d.ts` file
|
|
9
11
|
|
|
10
12
|
## [v0.0.2] - 2025-06-07
|
|
11
13
|
|
package/lib/attachments.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { evalTemplateExpressions } from '
|
|
2
|
-
import { readDirListing, readToString } from '
|
|
1
|
+
import { evalTemplateExpressions } from './expression.ts'
|
|
2
|
+
import { readDirListing, readToString } from './fs.ts'
|
|
3
3
|
|
|
4
4
|
export type AttachmentType = 'cloud-config' | 'x-shellscript'
|
|
5
5
|
|
package/lib/build.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { collectAttachments } from '
|
|
2
|
-
import { MultipartMessage } from '
|
|
1
|
+
import { collectAttachments } from './attachments.ts'
|
|
2
|
+
import { MultipartMessage } from './http.ts'
|
|
3
3
|
|
|
4
4
|
export type BuildUserDataOpts = {
|
|
5
5
|
attachmentBoundary?: string
|
package/lib/c2.api.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { type BuildUserDataOpts, buildUserData } from '
|
|
1
|
+
export { type BuildUserDataOpts, buildUserData } from './build.ts'
|
package/lib/c2.bin.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { buildUserData } from '
|
|
4
|
-
import { parseArgs, type ParsedArgs } from '
|
|
5
|
-
import { doesDirExist } from '
|
|
6
|
-
import { startUserDataHttp } from '
|
|
3
|
+
import { buildUserData } from './build.ts'
|
|
4
|
+
import { parseArgs, type ParsedArgs } from './cli.ts'
|
|
5
|
+
import { doesDirExist } from './fs.ts'
|
|
6
|
+
import { startUserDataHttp } from './http.ts'
|
|
7
7
|
|
|
8
8
|
let args: ParsedArgs | undefined
|
|
9
9
|
try {
|
package/lib/expression.ts
CHANGED
package/lib/http.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto'
|
|
2
2
|
import { createServer, type ServerResponse } from 'node:http'
|
|
3
|
-
import { type Attachment, collectAttachments } from '
|
|
3
|
+
import { type Attachment, collectAttachments } from './attachments.ts'
|
|
4
4
|
|
|
5
5
|
export function startUserDataHttp(port: number, userDataDir: string) {
|
|
6
6
|
const server = createServer((req, res) => {
|
package/lib_js/attachments.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { evalTemplateExpressions } from
|
|
2
|
-
import { readDirListing, readToString } from
|
|
1
|
+
import { evalTemplateExpressions } from "./expression.js";
|
|
2
|
+
import { readDirListing, readToString } from "./fs.js";
|
|
3
3
|
export async function collectAttachments(dir) {
|
|
4
4
|
const filenames = await readDirListing(dir);
|
|
5
5
|
const attachments = await Promise.all(filenames.map(async (filename) => {
|
package/lib_js/build.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { collectAttachments } from
|
|
2
|
-
import { MultipartMessage } from
|
|
1
|
+
import { collectAttachments } from "./attachments.js";
|
|
2
|
+
import { MultipartMessage } from "./http.js";
|
|
3
3
|
export async function buildUserData(userDataDir, opts) {
|
|
4
4
|
const attachments = await collectAttachments(userDataDir);
|
|
5
5
|
switch (attachments.length) {
|
package/lib_js/c2.api.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { buildUserData } from
|
|
1
|
+
export { buildUserData } from "./build.js";
|
package/lib_js/c2.bin.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { buildUserData } from
|
|
3
|
-
import { parseArgs } from
|
|
4
|
-
import { doesDirExist } from
|
|
5
|
-
import { startUserDataHttp } from
|
|
2
|
+
import { buildUserData } from "./build.js";
|
|
3
|
+
import { parseArgs } from "./cli.js";
|
|
4
|
+
import { doesDirExist } from "./fs.js";
|
|
5
|
+
import { startUserDataHttp } from "./http.js";
|
|
6
6
|
let args;
|
|
7
7
|
try {
|
|
8
8
|
args = parseArgs();
|
package/lib_js/expression.js
CHANGED
package/lib_js/http.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
|
-
import { collectAttachments } from
|
|
3
|
+
import { collectAttachments } from "./attachments.js";
|
|
4
4
|
export function startUserDataHttp(port, userDataDir) {
|
|
5
5
|
const server = createServer((req, res) => {
|
|
6
6
|
console.log(req.method, req.url);
|
package/lib_types/c2.api.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { type BuildUserDataOpts, buildUserData } from '
|
|
1
|
+
export { type BuildUserDataOpts, buildUserData } from './build.ts';
|
|
2
2
|
//# sourceMappingURL=c2.api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"c2.api.d.ts","sourceRoot":"","sources":["../lib/c2.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"c2.api.d.ts","sourceRoot":"","sources":["../lib/c2.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA"}
|
package/lib_types/http.d.ts
CHANGED
package/lib_types/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../lib/http.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAsB,MAAM,
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../lib/http.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAsB,MAAM,kBAAkB,CAAA;AAEtE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QAoBlE;AAiBD,qBAAa,gBAAgB;;IACzB,MAAM,CAAC,cAAc,IAAI,MAAM;gBAQ3B,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,EAC9B,QAAQ,GAAE,MAA0C;IAMxD,IAAI,WAAW,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAE5C;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMpC;IAED,MAAM,IAAI,MAAM;IAShB,YAAY,IAAI,MAAM;CASzB;AAED,qBAAa,mBAAmB;;gBAGhB,UAAU,EAAE,UAAU;IAIlC,MAAM,IAAI,MAAM;CASnB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eighty4/c2",
|
|
3
|
-
"version": "0.0.3-
|
|
3
|
+
"version": "0.0.3-1",
|
|
4
4
|
"author": "Adam McKee <adam.be.g84d@gmail.com>",
|
|
5
5
|
"repository": "https://github.com/eighty4/c2",
|
|
6
6
|
"homepage": "https://github.com/eighty4/c2",
|
|
@@ -22,17 +22,11 @@
|
|
|
22
22
|
"bin": {
|
|
23
23
|
"c2": "./lib_js/c2.bin.js"
|
|
24
24
|
},
|
|
25
|
-
"types": "./lib_types/c2.api.d.ts",
|
|
26
25
|
"exports": {
|
|
27
26
|
".": {
|
|
28
27
|
"bun": "./lib/c2.api.ts",
|
|
29
|
-
"node": "./lib_js/c2.api.js"
|
|
30
|
-
|
|
31
|
-
},
|
|
32
|
-
"imports": {
|
|
33
|
-
"#c2/*": {
|
|
34
|
-
"bun": "./lib/*.ts",
|
|
35
|
-
"node": "./lib_js/*.js"
|
|
28
|
+
"node": "./lib_js/c2.api.js",
|
|
29
|
+
"types": "./lib_types/c2.api.d.ts"
|
|
36
30
|
}
|
|
37
31
|
},
|
|
38
32
|
"scripts": {
|
|
@@ -53,6 +47,7 @@
|
|
|
53
47
|
},
|
|
54
48
|
"files": [
|
|
55
49
|
"lib/*",
|
|
50
|
+
"!lib/*.spec.ts",
|
|
56
51
|
"lib_js/*",
|
|
57
52
|
"lib_types/*",
|
|
58
53
|
"CHANGELOG.md"
|
package/lib/attachments.spec.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, expect, test } from 'bun:test'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { collectAttachments } from '#c2/attachments'
|
|
4
|
-
import { makeFile, makeTempDir, removeDir } from '#c2/fs.testing'
|
|
5
|
-
|
|
6
|
-
let tmpDir: string
|
|
7
|
-
|
|
8
|
-
beforeEach(async () => (tmpDir = await makeTempDir()))
|
|
9
|
-
|
|
10
|
-
afterEach(async () => await removeDir(tmpDir))
|
|
11
|
-
|
|
12
|
-
test('collect throws error for unknown filetype', async () => {
|
|
13
|
-
await makeFile('init-cloud', 'whoopie', tmpDir)
|
|
14
|
-
await expect(() => collectAttachments(tmpDir)).toThrow(
|
|
15
|
-
'init-cloud is an unsupported file type',
|
|
16
|
-
)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('collect cloud config yml', async () => {
|
|
20
|
-
await makeFile('init-cloud.yml', '#cloud-config\nwhoopie', tmpDir)
|
|
21
|
-
expect(await collectAttachments(tmpDir)).toStrictEqual([
|
|
22
|
-
{
|
|
23
|
-
path: join(tmpDir, 'init-cloud.yml'),
|
|
24
|
-
content: '#cloud-config\nwhoopie',
|
|
25
|
-
filename: 'init-cloud.yml',
|
|
26
|
-
source: '#cloud-config\nwhoopie',
|
|
27
|
-
type: 'cloud-config',
|
|
28
|
-
},
|
|
29
|
-
])
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('collect cloud config yaml', async () => {
|
|
33
|
-
await makeFile('init-cloud.yaml', '#cloud-config\nwhoopie', tmpDir)
|
|
34
|
-
expect(await collectAttachments(tmpDir)).toStrictEqual([
|
|
35
|
-
{
|
|
36
|
-
path: join(tmpDir, 'init-cloud.yaml'),
|
|
37
|
-
content: '#cloud-config\nwhoopie',
|
|
38
|
-
filename: 'init-cloud.yaml',
|
|
39
|
-
source: '#cloud-config\nwhoopie',
|
|
40
|
-
type: 'cloud-config',
|
|
41
|
-
},
|
|
42
|
-
])
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
test('collect throws error when yml does not have #cloud-config comment', async () => {
|
|
46
|
-
await makeFile('init-cloud.yml', 'whoopie', tmpDir)
|
|
47
|
-
await expect(() => collectAttachments(tmpDir)).toThrow(
|
|
48
|
-
'YAML cloud config must start with a #cloud-config comment',
|
|
49
|
-
)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('collect throws error when yaml does not have #cloud-config comment', async () => {
|
|
53
|
-
await makeFile('init-cloud.yaml', 'whoopie', tmpDir)
|
|
54
|
-
await expect(() => collectAttachments(tmpDir)).toThrow(
|
|
55
|
-
'YAML cloud config must start with a #cloud-config comment',
|
|
56
|
-
)
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
test('collect shell script', async () => {
|
|
60
|
-
await makeFile('init-cloud.sh', 'whoopie', tmpDir)
|
|
61
|
-
expect(await collectAttachments(tmpDir)).toStrictEqual([
|
|
62
|
-
{
|
|
63
|
-
path: join(tmpDir, 'init-cloud.sh'),
|
|
64
|
-
content: 'whoopie',
|
|
65
|
-
filename: 'init-cloud.sh',
|
|
66
|
-
source: 'whoopie',
|
|
67
|
-
type: 'x-shellscript',
|
|
68
|
-
},
|
|
69
|
-
])
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
test('evals template expressions', async () => {
|
|
73
|
-
const resourceTmpDir = await makeTempDir()
|
|
74
|
-
await makeFile('whoopie', 'whoopie', resourceTmpDir)
|
|
75
|
-
await makeFile(
|
|
76
|
-
'init-cloud.sh',
|
|
77
|
-
`\${{ file('${resourceTmpDir}/whoopie') }}`,
|
|
78
|
-
tmpDir,
|
|
79
|
-
)
|
|
80
|
-
expect(await collectAttachments(tmpDir)).toStrictEqual([
|
|
81
|
-
{
|
|
82
|
-
path: tmpDir + '/init-cloud.sh',
|
|
83
|
-
content: 'whoopie',
|
|
84
|
-
filename: 'init-cloud.sh',
|
|
85
|
-
source: `\${{ file('${resourceTmpDir}/whoopie') }}`,
|
|
86
|
-
type: 'x-shellscript',
|
|
87
|
-
},
|
|
88
|
-
])
|
|
89
|
-
await removeDir(resourceTmpDir)
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
test('sorts attachments by filename', async () => {
|
|
93
|
-
await makeFile('01-init-cloud.sh', 'whoopie', tmpDir)
|
|
94
|
-
await makeFile('02-init-cloud.sh', 'whoopie', tmpDir)
|
|
95
|
-
expect(await collectAttachments(tmpDir)).toStrictEqual([
|
|
96
|
-
{
|
|
97
|
-
path: join(tmpDir, '01-init-cloud.sh'),
|
|
98
|
-
content: 'whoopie',
|
|
99
|
-
filename: '01-init-cloud.sh',
|
|
100
|
-
source: 'whoopie',
|
|
101
|
-
type: 'x-shellscript',
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
path: join(tmpDir, '02-init-cloud.sh'),
|
|
105
|
-
content: 'whoopie',
|
|
106
|
-
filename: '02-init-cloud.sh',
|
|
107
|
-
source: 'whoopie',
|
|
108
|
-
type: 'x-shellscript',
|
|
109
|
-
},
|
|
110
|
-
])
|
|
111
|
-
})
|
package/lib/build.spec.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, expect, test } from 'bun:test'
|
|
2
|
-
import { buildUserData } from '#c2/build'
|
|
3
|
-
import { makeFile, makeTempDir, removeDir } from '#c2/fs.testing'
|
|
4
|
-
|
|
5
|
-
let tmpDir: string
|
|
6
|
-
|
|
7
|
-
beforeEach(async () => {
|
|
8
|
-
tmpDir = await makeTempDir()
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
afterEach(async () => removeDir(tmpDir))
|
|
12
|
-
|
|
13
|
-
test('build user data of single file', async () => {
|
|
14
|
-
const initCloudYml = '#cloud-config\nwhoopie'
|
|
15
|
-
await makeFile('init-cloud.yml', initCloudYml, tmpDir)
|
|
16
|
-
expect(await buildUserData(tmpDir)).toStrictEqual(initCloudYml)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('build user data of single file with template expression', async () => {
|
|
20
|
-
const whoopie = await makeTempDir()
|
|
21
|
-
await makeFile('whoopie', 'whoopie', whoopie)
|
|
22
|
-
await makeFile(
|
|
23
|
-
'init-cloud.yml',
|
|
24
|
-
`#cloud-config\n\${{ file('${whoopie}/whoopie')}}`,
|
|
25
|
-
tmpDir,
|
|
26
|
-
)
|
|
27
|
-
expect(await buildUserData(tmpDir)).toStrictEqual('#cloud-config\nwhoopie')
|
|
28
|
-
await removeDir(whoopie)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
test('build user data multipart message', async () => {
|
|
32
|
-
await makeFile('1-init-cloud.yml', '#cloud-config\nwhoopie', tmpDir)
|
|
33
|
-
await makeFile('2-init-cloud.sh', 'cushion', tmpDir)
|
|
34
|
-
const boundary = Bun.randomUUIDv7()
|
|
35
|
-
expect(
|
|
36
|
-
await buildUserData(tmpDir, { attachmentBoundary: boundary }),
|
|
37
|
-
).toStrictEqual(
|
|
38
|
-
`Content-Type: multipart/mixed; boundary=${boundary}\r
|
|
39
|
-
MIME-Version: 1.0\r
|
|
40
|
-
Number-Attachments: 2\r
|
|
41
|
-
--${boundary}\r
|
|
42
|
-
Content-Type: text/cloud-config; charset="us-ascii"\r
|
|
43
|
-
Content-Transfer-Encoding: 7bit\r
|
|
44
|
-
Content-Disposition: attachment; filename="1-init-cloud.yml"\r
|
|
45
|
-
\r
|
|
46
|
-
#cloud-config
|
|
47
|
-
whoopie\r
|
|
48
|
-
--${boundary}\r
|
|
49
|
-
Content-Type: text/x-shellscript; charset="us-ascii"\r
|
|
50
|
-
Content-Transfer-Encoding: 7bit\r
|
|
51
|
-
Content-Disposition: attachment; filename="2-init-cloud.sh"\r
|
|
52
|
-
\r
|
|
53
|
-
cushion\r
|
|
54
|
-
--${boundary}\r
|
|
55
|
-
`,
|
|
56
|
-
)
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
test('build user data multipart with template expression', async () => {
|
|
60
|
-
const whoopie = await makeTempDir()
|
|
61
|
-
await makeFile('whoopie', 'whoopie', whoopie)
|
|
62
|
-
await makeFile(
|
|
63
|
-
'1-init-cloud.yml',
|
|
64
|
-
`#cloud-config\n\${{ file('${whoopie}/whoopie')}}`,
|
|
65
|
-
tmpDir,
|
|
66
|
-
)
|
|
67
|
-
await makeFile('2-init-cloud.sh', 'cushion', tmpDir)
|
|
68
|
-
const boundary = Bun.randomUUIDv7()
|
|
69
|
-
expect(
|
|
70
|
-
await buildUserData(tmpDir, { attachmentBoundary: boundary }),
|
|
71
|
-
).toStrictEqual(
|
|
72
|
-
`Content-Type: multipart/mixed; boundary=${boundary}\r
|
|
73
|
-
MIME-Version: 1.0\r
|
|
74
|
-
Number-Attachments: 2\r
|
|
75
|
-
--${boundary}\r
|
|
76
|
-
Content-Type: text/cloud-config; charset="us-ascii"\r
|
|
77
|
-
Content-Transfer-Encoding: 7bit\r
|
|
78
|
-
Content-Disposition: attachment; filename="1-init-cloud.yml"\r
|
|
79
|
-
\r
|
|
80
|
-
#cloud-config\nwhoopie\r
|
|
81
|
-
--${boundary}\r
|
|
82
|
-
Content-Type: text/x-shellscript; charset="us-ascii"\r
|
|
83
|
-
Content-Transfer-Encoding: 7bit\r
|
|
84
|
-
Content-Disposition: attachment; filename="2-init-cloud.sh"\r
|
|
85
|
-
\r
|
|
86
|
-
cushion\r
|
|
87
|
-
--${boundary}\r
|
|
88
|
-
`,
|
|
89
|
-
)
|
|
90
|
-
})
|
package/lib/cli.spec.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { expect, test } from 'bun:test'
|
|
2
|
-
import { parseArgs } from '#c2/cli'
|
|
3
|
-
|
|
4
|
-
test('parseArgs with ts entrypoint', () => {
|
|
5
|
-
expect(
|
|
6
|
-
parseArgs([
|
|
7
|
-
'/Users/who/.bun/bin/bun',
|
|
8
|
-
'/Users/who/user-data/lib/c2.bin.ts',
|
|
9
|
-
'user_data_dir',
|
|
10
|
-
]),
|
|
11
|
-
).toStrictEqual({
|
|
12
|
-
base64: false,
|
|
13
|
-
userDataDir: 'user_data_dir',
|
|
14
|
-
})
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
test('parseArgs with executable entrypoint', () => {
|
|
18
|
-
expect(
|
|
19
|
-
parseArgs([
|
|
20
|
-
'/Users/who/.nvm/versions/node/v23.7.0/bin/node',
|
|
21
|
-
'/Users/who/.nvm/versions/node/v23.7.0/bin/c2',
|
|
22
|
-
'user_data_dir',
|
|
23
|
-
]),
|
|
24
|
-
).toStrictEqual({
|
|
25
|
-
base64: false,
|
|
26
|
-
userDataDir: 'user_data_dir',
|
|
27
|
-
})
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
test('parseArgs with js entrypoint', () => {
|
|
31
|
-
expect(
|
|
32
|
-
parseArgs([
|
|
33
|
-
'/Users/who/.nvm/versions/node/v23.7.0/bin/node',
|
|
34
|
-
'/Users/who/user-data/lib_js/c2.bin.js',
|
|
35
|
-
'user_data_dir',
|
|
36
|
-
]),
|
|
37
|
-
).toStrictEqual({
|
|
38
|
-
base64: false,
|
|
39
|
-
userDataDir: 'user_data_dir',
|
|
40
|
-
})
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test('parseArgs with unexepected argv', () => {
|
|
44
|
-
expect(() => parseArgs(['tippity', 'doo', 'da'])).toThrow(
|
|
45
|
-
'unexpected program installation\nplease report at https://github.com/eighty4/c2/issues/new and include:\n\n[\n \"tippity\",\n \"doo\",\n \"da\"\n]',
|
|
46
|
-
)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
test('parseArgs errors without USER_DATA_DIR', () => {
|
|
50
|
-
expect(() =>
|
|
51
|
-
parseArgs([
|
|
52
|
-
'/Users/who/.bun/bin/bun',
|
|
53
|
-
'/Users/who/user-data/lib/c2.bin.ts',
|
|
54
|
-
]),
|
|
55
|
-
).toThrow()
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('parseArgs errors with extra USER_DATA_DIR', () => {
|
|
59
|
-
expect(() =>
|
|
60
|
-
parseArgs([
|
|
61
|
-
'/Users/who/.bun/bin/bun',
|
|
62
|
-
'/Users/who/user-data/lib/c2.bin.ts',
|
|
63
|
-
'user_data_dir',
|
|
64
|
-
'some_other_arg',
|
|
65
|
-
]),
|
|
66
|
-
).toThrow()
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test('parseArgs with --base64', () => {
|
|
70
|
-
expect(
|
|
71
|
-
parseArgs([
|
|
72
|
-
'/Users/who/.bun/bin/bun',
|
|
73
|
-
'/Users/who/user-data/lib/c2.bin.ts',
|
|
74
|
-
'--base64',
|
|
75
|
-
'user_data_dir',
|
|
76
|
-
]),
|
|
77
|
-
).toStrictEqual({
|
|
78
|
-
base64: true,
|
|
79
|
-
userDataDir: 'user_data_dir',
|
|
80
|
-
})
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
test('parseArgs with --http PORT', () => {
|
|
84
|
-
expect(
|
|
85
|
-
parseArgs([
|
|
86
|
-
'/Users/who/.bun/bin/bun',
|
|
87
|
-
'/Users/who/user-data/lib/c2.bin.ts',
|
|
88
|
-
'--http',
|
|
89
|
-
'6666',
|
|
90
|
-
'user_data_dir',
|
|
91
|
-
]),
|
|
92
|
-
).toStrictEqual({ httpPort: 6666, userDataDir: 'user_data_dir' })
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
test('parseArgs with --http bunk', () => {
|
|
96
|
-
expect(() =>
|
|
97
|
-
parseArgs([
|
|
98
|
-
'/Users/who/.bun/bin/bun',
|
|
99
|
-
'/Users/who/user-data/lib/c2.bin.ts',
|
|
100
|
-
'--http',
|
|
101
|
-
'bunk',
|
|
102
|
-
'user_data_dir',
|
|
103
|
-
]),
|
|
104
|
-
).toThrow('--http bunk is not a valid http port')
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
test('parseArgs with --http without PORT', () => {
|
|
108
|
-
expect(() =>
|
|
109
|
-
parseArgs([
|
|
110
|
-
'/Users/who/.bun/bin/bun',
|
|
111
|
-
'/Users/who/user-data/lib/c2.bin.ts',
|
|
112
|
-
'user_data_dir',
|
|
113
|
-
'--http',
|
|
114
|
-
]),
|
|
115
|
-
).toThrow('--http did not include a PORT')
|
|
116
|
-
})
|
package/lib/expression.spec.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { afterAll, afterEach, beforeEach, expect, test } from 'bun:test'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { evalTemplateExpressions } from './expression.ts'
|
|
4
|
-
import { makeFile, makeTempDir, removeDir } from './fs.testing.ts'
|
|
5
|
-
|
|
6
|
-
let files: Array<string> = []
|
|
7
|
-
let tmpDir: string
|
|
8
|
-
|
|
9
|
-
beforeEach(async () => (tmpDir = await makeTempDir()))
|
|
10
|
-
|
|
11
|
-
afterEach(async () => await removeDir(tmpDir))
|
|
12
|
-
|
|
13
|
-
afterAll(async () => {
|
|
14
|
-
for (const p of files) {
|
|
15
|
-
await Bun.file(p).delete()
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('env() found', async () => {
|
|
20
|
-
const envVar = 'C2_TEST_' + Bun.randomUUIDv7().substring(0, 8).toUpperCase()
|
|
21
|
-
Bun.env[envVar] = Bun.randomUUIDv7()
|
|
22
|
-
expect(await evalTemplateExpressions(`\${{ env('${envVar}') }}`)).toBe(
|
|
23
|
-
Bun.env[envVar],
|
|
24
|
-
)
|
|
25
|
-
delete Bun.env[envVar]
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test('env() not found', async () => {
|
|
29
|
-
const envVar = 'C2_TEST_' + Bun.randomUUIDv7().substring(0, 8).toUpperCase()
|
|
30
|
-
expect(() => evalTemplateExpressions(` \${{ env('${envVar}') }}`)).toThrow(
|
|
31
|
-
`env var \`${envVar}\` does not exist`,
|
|
32
|
-
)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('env() name not valid', async () => {
|
|
36
|
-
;['2_NOT_VALID', 'NOT=VALID', 'NOT@VALID'].forEach(envVar =>
|
|
37
|
-
expect(() =>
|
|
38
|
-
evalTemplateExpressions(`\${{ env('${envVar}') }}`),
|
|
39
|
-
).toThrow(`env var \`${envVar}\` is not a valid name`),
|
|
40
|
-
)
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test('file() not found', async () => {
|
|
44
|
-
const path = join(await makeTempDir(), 'whoopie')
|
|
45
|
-
expect(() => evalTemplateExpressions(`\${{ file('${path}') }}`)).toThrow(
|
|
46
|
-
`ENOENT: no such file or directory, open '${path}'`,
|
|
47
|
-
)
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
test('file() absolute', async () => {
|
|
51
|
-
const content = Bun.randomUUIDv7()
|
|
52
|
-
const path = await makeFile('.user-data', content, tmpDir)
|
|
53
|
-
expect(await evalTemplateExpressions(`\${{ file('${path}') }}`)).toBe(
|
|
54
|
-
content,
|
|
55
|
-
)
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('file() home', async () => {
|
|
59
|
-
const content = Bun.randomUUIDv7()
|
|
60
|
-
const filename = `.user-data.${Bun.randomUUIDv7()}`
|
|
61
|
-
const path = join(Bun.env.HOME!, filename)
|
|
62
|
-
await makeFile(path, content)
|
|
63
|
-
files.push(path)
|
|
64
|
-
expect(await evalTemplateExpressions(`\${{ file('~/${filename}') }}`)).toBe(
|
|
65
|
-
content,
|
|
66
|
-
)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
test('file() relative', async () => {
|
|
70
|
-
const content = Bun.randomUUIDv7()
|
|
71
|
-
const filename = `.user-data.${Bun.randomUUIDv7()}`
|
|
72
|
-
await makeFile(filename, content, tmpDir)
|
|
73
|
-
const prevPwd = process.cwd()
|
|
74
|
-
process.chdir(tmpDir)
|
|
75
|
-
try {
|
|
76
|
-
expect(
|
|
77
|
-
await evalTemplateExpressions(`\${{ file('${filename}') }}`),
|
|
78
|
-
).toBe(content)
|
|
79
|
-
} finally {
|
|
80
|
-
process.chdir(prevPwd)
|
|
81
|
-
}
|
|
82
|
-
})
|
package/lib/http.spec.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { beforeEach, expect, test } from 'bun:test'
|
|
2
|
-
import { MultipartMessage, MultipartAttachment } from '#c2/http'
|
|
3
|
-
|
|
4
|
-
let message: MultipartMessage
|
|
5
|
-
|
|
6
|
-
beforeEach(() => {
|
|
7
|
-
message = new MultipartMessage(
|
|
8
|
-
[
|
|
9
|
-
{
|
|
10
|
-
path: 'upgrades',
|
|
11
|
-
content: '#cloud-config\nupgrades',
|
|
12
|
-
filename: 'upgrades.yml',
|
|
13
|
-
source: '#cloud-config\nupgrades',
|
|
14
|
-
type: 'cloud-config',
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
path: 'security',
|
|
18
|
-
content: 'security',
|
|
19
|
-
filename: 'security.sh',
|
|
20
|
-
source: 'security',
|
|
21
|
-
type: 'x-shellscript',
|
|
22
|
-
},
|
|
23
|
-
],
|
|
24
|
-
'BOUNDARY',
|
|
25
|
-
)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test('multipart message creates cloud-init payload', () => {
|
|
29
|
-
expect(message.toHTTP()).toStrictEqual(
|
|
30
|
-
`Content-Type: multipart/mixed; boundary=BOUNDARY\r
|
|
31
|
-
MIME-Version: 1.0\r
|
|
32
|
-
Number-Attachments: 2\r
|
|
33
|
-
--BOUNDARY\r
|
|
34
|
-
Content-Type: text/cloud-config; charset="us-ascii"\r
|
|
35
|
-
Content-Transfer-Encoding: 7bit\r
|
|
36
|
-
Content-Disposition: attachment; filename="upgrades.yml"\r
|
|
37
|
-
\r
|
|
38
|
-
#cloud-config
|
|
39
|
-
upgrades\r
|
|
40
|
-
--BOUNDARY\r
|
|
41
|
-
Content-Type: text/x-shellscript; charset="us-ascii"\r
|
|
42
|
-
Content-Transfer-Encoding: 7bit\r
|
|
43
|
-
Content-Disposition: attachment; filename="security.sh"\r
|
|
44
|
-
\r
|
|
45
|
-
security\r
|
|
46
|
-
--BOUNDARY\r
|
|
47
|
-
`,
|
|
48
|
-
)
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('multipart message creates HTTP headers', () => {
|
|
52
|
-
expect(message.headers).toStrictEqual({
|
|
53
|
-
'Content-Type': 'multipart/mixed; boundary=BOUNDARY',
|
|
54
|
-
'MIME-Version': '1.0',
|
|
55
|
-
'Number-Attachments': '2',
|
|
56
|
-
})
|
|
57
|
-
})
|