termify-agent 1.0.50 → 1.0.54
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/agent.d.ts +1 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +20 -1
- package/dist/agent.js.map +1 -1
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/dist/network/wireguard-manager.d.ts +6 -0
- package/dist/network/wireguard-manager.d.ts.map +1 -1
- package/dist/network/wireguard-manager.js +18 -7
- package/dist/network/wireguard-manager.js.map +1 -1
- package/dist/network/wireguard-manager.test.d.ts +2 -0
- package/dist/network/wireguard-manager.test.d.ts.map +1 -0
- package/dist/network/wireguard-manager.test.js +24 -0
- package/dist/network/wireguard-manager.test.js.map +1 -0
- package/dist/ssh/platform-openssh.d.ts +16 -0
- package/dist/ssh/platform-openssh.d.ts.map +1 -0
- package/dist/ssh/platform-openssh.js +51 -0
- package/dist/ssh/platform-openssh.js.map +1 -0
- package/dist/ssh/platform-openssh.test.d.ts +2 -0
- package/dist/ssh/platform-openssh.test.d.ts.map +1 -0
- package/dist/ssh/platform-openssh.test.js +42 -0
- package/dist/ssh/platform-openssh.test.js.map +1 -0
- package/dist/ssh/system-ssh.d.ts +58 -0
- package/dist/ssh/system-ssh.d.ts.map +1 -0
- package/dist/ssh/system-ssh.js +328 -0
- package/dist/ssh/system-ssh.js.map +1 -0
- package/dist/ssh/system-ssh.test.d.ts +2 -0
- package/dist/ssh/system-ssh.test.d.ts.map +1 -0
- package/dist/ssh/system-ssh.test.js +189 -0
- package/dist/ssh/system-ssh.test.js.map +1 -0
- package/package.json +1 -1
- package/scripts/postinstall.js +39 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
import { SystemSSHManager } from './system-ssh.js';
|
|
7
|
+
test('creates local SSH key material and stores issued bootstrap certificates', async (t) => {
|
|
8
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'termify-agent-system-ssh-'));
|
|
9
|
+
const manager = new SystemSSHManager(tempDir);
|
|
10
|
+
t.after(() => {
|
|
11
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
12
|
+
});
|
|
13
|
+
const keyPairs = await manager.ensureLocalKeyPairs();
|
|
14
|
+
assert.ok(keyPairs.userPublicKey.startsWith('ssh-ed25519 '));
|
|
15
|
+
assert.ok(keyPairs.hostPublicKey.startsWith('ssh-ed25519 '));
|
|
16
|
+
assert.equal(existsSync(manager.getPaths().userPrivateKeyPath), true);
|
|
17
|
+
assert.equal(existsSync(manager.getPaths().hostPrivateKeyPath), true);
|
|
18
|
+
const bootstrap = {
|
|
19
|
+
accountPrincipal: 'termify-account:user-123',
|
|
20
|
+
userCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestUserCa termify-user-ca',
|
|
21
|
+
hostCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestHostCa termify-host-ca',
|
|
22
|
+
userCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAUserCert termify-user-cert\n',
|
|
23
|
+
hostCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAHostCert termify-host-cert\n',
|
|
24
|
+
userValidForSeconds: 3600,
|
|
25
|
+
hostValidForSeconds: 86400,
|
|
26
|
+
};
|
|
27
|
+
await manager.applyBootstrap(bootstrap);
|
|
28
|
+
assert.equal(manager.readAccountPrincipal(), 'termify-account:user-123');
|
|
29
|
+
assert.equal(readFileSync(manager.getPaths().userCertificatePath, 'utf8'), bootstrap.userCertificate);
|
|
30
|
+
assert.equal(readFileSync(manager.getPaths().hostCertificatePath, 'utf8'), bootstrap.hostCertificate);
|
|
31
|
+
assert.equal(readFileSync(manager.getPaths().userCaPublicKeyPath, 'utf8'), `${bootstrap.userCaPublicKey}\n`);
|
|
32
|
+
assert.equal(readFileSync(manager.getPaths().hostCaPublicKeyPath, 'utf8'), `${bootstrap.hostCaPublicKey}\n`);
|
|
33
|
+
});
|
|
34
|
+
test('separates client and server SSH state so sshd does not depend on user HOME', async (t) => {
|
|
35
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'termify-agent-ssh-layout-'));
|
|
36
|
+
const homeDir = join(tempDir, 'home');
|
|
37
|
+
const manager = new SystemSSHManager(join(tempDir, 'user-state'), homeDir, {
|
|
38
|
+
systemRootDir: join(tempDir, 'system-state'),
|
|
39
|
+
reloadSshd: false,
|
|
40
|
+
});
|
|
41
|
+
t.after(() => {
|
|
42
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
43
|
+
});
|
|
44
|
+
await manager.ensureLocalKeyPairs();
|
|
45
|
+
await manager.applyBootstrap({
|
|
46
|
+
accountPrincipal: 'termify-account:user-123',
|
|
47
|
+
userCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestUserCa termify-user-ca',
|
|
48
|
+
hostCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestHostCa termify-host-ca',
|
|
49
|
+
userCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAUserCert termify-user-cert\n',
|
|
50
|
+
hostCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAHostCert termify-host-cert\n',
|
|
51
|
+
userValidForSeconds: 3600,
|
|
52
|
+
hostValidForSeconds: 86400,
|
|
53
|
+
});
|
|
54
|
+
const paths = manager.getPaths();
|
|
55
|
+
assert.equal(paths.userRootDir, join(tempDir, 'user-state'));
|
|
56
|
+
assert.equal(paths.systemRootDir, join(tempDir, 'system-state'));
|
|
57
|
+
assert.equal(paths.userPrivateKeyPath.startsWith(paths.userRootDir), true);
|
|
58
|
+
assert.equal(paths.userCertificatePath.startsWith(paths.userRootDir), true);
|
|
59
|
+
assert.equal(paths.hostPrivateKeyPath.startsWith(paths.systemRootDir), true);
|
|
60
|
+
assert.equal(paths.hostCertificatePath.startsWith(paths.systemRootDir), true);
|
|
61
|
+
assert.equal(paths.metadataPath.startsWith(paths.systemRootDir), true);
|
|
62
|
+
assert.equal(manager.readAccountPrincipal(), 'termify-account:user-123');
|
|
63
|
+
});
|
|
64
|
+
test('installs managed OpenSSH blocks into user and server config files', async (t) => {
|
|
65
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'termify-agent-ssh-install-'));
|
|
66
|
+
const homeDir = join(tempDir, 'home');
|
|
67
|
+
const sshdConfigPath = join(tempDir, 'etc', 'ssh', 'sshd_config');
|
|
68
|
+
const manager = new SystemSSHManager(join(tempDir, 'state'), homeDir, {
|
|
69
|
+
systemRootDir: join(tempDir, 'system-state'),
|
|
70
|
+
sshdConfigPath,
|
|
71
|
+
reloadSshd: false,
|
|
72
|
+
});
|
|
73
|
+
t.after(() => {
|
|
74
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
75
|
+
});
|
|
76
|
+
await manager.ensureLocalKeyPairs();
|
|
77
|
+
await manager.applyBootstrap({
|
|
78
|
+
accountPrincipal: 'termify-account:user-123',
|
|
79
|
+
userCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestUserCa termify-user-ca',
|
|
80
|
+
hostCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestHostCa termify-host-ca',
|
|
81
|
+
userCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAUserCert termify-user-cert\n',
|
|
82
|
+
hostCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAHostCert termify-host-cert\n',
|
|
83
|
+
userValidForSeconds: 3600,
|
|
84
|
+
hostValidForSeconds: 86400,
|
|
85
|
+
});
|
|
86
|
+
await manager.installOpenSshIntegration();
|
|
87
|
+
const userConfig = readFileSync(join(homeDir, '.ssh', 'config'), 'utf8');
|
|
88
|
+
const sshdConfig = readFileSync(sshdConfigPath, 'utf8');
|
|
89
|
+
const paths = manager.getPaths();
|
|
90
|
+
assert.match(userConfig, /# >>> termify:ssh-client >>>/);
|
|
91
|
+
assert.match(userConfig, /Host 10\.100\.\*/);
|
|
92
|
+
assert.match(userConfig, /IdentityFile/);
|
|
93
|
+
assert.match(sshdConfig, /# >>> termify:sshd >>>/);
|
|
94
|
+
assert.match(sshdConfig, /TrustedUserCAKeys/);
|
|
95
|
+
assert.match(sshdConfig, new RegExp(`AuthorizedPrincipalsFile ${paths.authorizedPrincipalsPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`));
|
|
96
|
+
assert.doesNotMatch(sshdConfig, /AuthorizedPrincipalsCommand/);
|
|
97
|
+
assert.equal(readFileSync(paths.authorizedPrincipalsPath, 'utf8'), 'termify-account:user-123\n');
|
|
98
|
+
});
|
|
99
|
+
test('defaults client state to the invoking user home under sudo', async (t) => {
|
|
100
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'termify-agent-ssh-sudo-'));
|
|
101
|
+
const sudoHomeDir = join(tempDir, 'sudo-home');
|
|
102
|
+
const originalGetuid = process.getuid;
|
|
103
|
+
const originalHome = process.env.TERMIFY_SSH_HOME_DIR;
|
|
104
|
+
const originalSudoUser = process.env.SUDO_USER;
|
|
105
|
+
const originalSudoUid = process.env.SUDO_UID;
|
|
106
|
+
const originalSudoGid = process.env.SUDO_GID;
|
|
107
|
+
const ownedPaths = [];
|
|
108
|
+
process.env.TERMIFY_SSH_HOME_DIR = sudoHomeDir;
|
|
109
|
+
process.env.SUDO_USER = 'ubuntu';
|
|
110
|
+
process.env.SUDO_UID = String(originalGetuid?.() ?? 0);
|
|
111
|
+
process.env.SUDO_GID = String(process.getgid?.() ?? 0);
|
|
112
|
+
Object.defineProperty(process, 'getuid', { value: () => 0 });
|
|
113
|
+
t.after(() => {
|
|
114
|
+
if (originalHome === undefined)
|
|
115
|
+
delete process.env.TERMIFY_SSH_HOME_DIR;
|
|
116
|
+
else
|
|
117
|
+
process.env.TERMIFY_SSH_HOME_DIR = originalHome;
|
|
118
|
+
if (originalSudoUser === undefined)
|
|
119
|
+
delete process.env.SUDO_USER;
|
|
120
|
+
else
|
|
121
|
+
process.env.SUDO_USER = originalSudoUser;
|
|
122
|
+
if (originalSudoUid === undefined)
|
|
123
|
+
delete process.env.SUDO_UID;
|
|
124
|
+
else
|
|
125
|
+
process.env.SUDO_UID = originalSudoUid;
|
|
126
|
+
if (originalSudoGid === undefined)
|
|
127
|
+
delete process.env.SUDO_GID;
|
|
128
|
+
else
|
|
129
|
+
process.env.SUDO_GID = originalSudoGid;
|
|
130
|
+
Object.defineProperty(process, 'getuid', { value: originalGetuid });
|
|
131
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
132
|
+
});
|
|
133
|
+
const manager = new SystemSSHManager({
|
|
134
|
+
systemRootDir: join(tempDir, 'system-state'),
|
|
135
|
+
sshdConfigPath: join(tempDir, 'etc', 'ssh', 'sshd_config'),
|
|
136
|
+
reloadSshd: false,
|
|
137
|
+
applyUserOwnership: async (filePath) => {
|
|
138
|
+
ownedPaths.push(filePath);
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
await manager.ensureLocalKeyPairs();
|
|
142
|
+
await manager.applyBootstrap({
|
|
143
|
+
accountPrincipal: 'termify-account:user-123',
|
|
144
|
+
userCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestUserCa termify-user-ca',
|
|
145
|
+
hostCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestHostCa termify-host-ca',
|
|
146
|
+
userCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAUserCert termify-user-cert\n',
|
|
147
|
+
hostCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAHostCert termify-host-cert\n',
|
|
148
|
+
userValidForSeconds: 3600,
|
|
149
|
+
hostValidForSeconds: 86400,
|
|
150
|
+
});
|
|
151
|
+
await manager.installOpenSshIntegration();
|
|
152
|
+
const paths = manager.getPaths();
|
|
153
|
+
assert.equal(paths.userRootDir, join(sudoHomeDir, '.termify', 'ssh'));
|
|
154
|
+
assert.equal(paths.clientConfigPath, join(sudoHomeDir, '.ssh', 'config'));
|
|
155
|
+
assert.equal(ownedPaths.includes(paths.userPrivateKeyPath), true);
|
|
156
|
+
assert.equal(ownedPaths.includes(paths.userCertificatePath), true);
|
|
157
|
+
assert.equal(ownedPaths.includes(paths.knownHostsPath), true);
|
|
158
|
+
assert.equal(ownedPaths.includes(paths.clientConfigPath), true);
|
|
159
|
+
});
|
|
160
|
+
test('uses AuthorizedPrincipalsFile on Windows too', async (t) => {
|
|
161
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'termify-agent-ssh-windows-'));
|
|
162
|
+
const manager = new SystemSSHManager({
|
|
163
|
+
homeDir: join(tempDir, 'home'),
|
|
164
|
+
systemRootDir: join(tempDir, 'programdata', 'Termify', 'ssh'),
|
|
165
|
+
sshdConfigPath: join(tempDir, 'programdata', 'ssh', 'sshd_config'),
|
|
166
|
+
platformOverride: 'win32',
|
|
167
|
+
reloadSshd: false,
|
|
168
|
+
});
|
|
169
|
+
t.after(() => {
|
|
170
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
171
|
+
});
|
|
172
|
+
await manager.ensureLocalKeyPairs();
|
|
173
|
+
await manager.applyBootstrap({
|
|
174
|
+
accountPrincipal: 'termify-account:user-123',
|
|
175
|
+
userCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestUserCa termify-user-ca',
|
|
176
|
+
hostCaPublicKey: 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAITestHostCa termify-host-ca',
|
|
177
|
+
userCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAUserCert termify-user-cert\n',
|
|
178
|
+
hostCertificate: 'ssh-ed25519-cert-v01@openssh.com AAAAHostCert termify-host-cert\n',
|
|
179
|
+
userValidForSeconds: 3600,
|
|
180
|
+
hostValidForSeconds: 86400,
|
|
181
|
+
});
|
|
182
|
+
await manager.installOpenSshIntegration();
|
|
183
|
+
const paths = manager.getPaths();
|
|
184
|
+
const sshdConfig = readFileSync(join(tempDir, 'programdata', 'ssh', 'sshd_config'), 'utf8');
|
|
185
|
+
assert.equal(readFileSync(paths.authorizedPrincipalsPath, 'utf8'), 'termify-account:user-123\n');
|
|
186
|
+
assert.match(sshdConfig, /AuthorizedPrincipalsFile/);
|
|
187
|
+
assert.doesNotMatch(sshdConfig, /AuthorizedPrincipalsCommand/);
|
|
188
|
+
});
|
|
189
|
+
//# sourceMappingURL=system-ssh.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-ssh.test.js","sourceRoot":"","sources":["../../src/ssh/system-ssh.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,IAAI,CAAC,yEAAyE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC1F,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC,CAAC,CAAC;IACzE,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAE9C,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QACX,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAErD,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC;IAC7D,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,kBAAkB,CAAC,EAAE,IAAI,CAAC,CAAC;IACtE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,kBAAkB,CAAC,EAAE,IAAI,CAAC,CAAC;IAEtE,MAAM,SAAS,GAA8B;QAC3C,gBAAgB,EAAE,0BAA0B;QAC5C,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,mEAAmE;QACpF,eAAe,EAAE,mEAAmE;QACpF,mBAAmB,EAAE,IAAI;QACzB,mBAAmB,EAAE,KAAK;KAC3B,CAAC;IAEF,MAAM,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAExC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,0BAA0B,CAAC,CAAC;IACzE,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,mBAAmB,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,CAAC;IACtG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,mBAAmB,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,CAAC;IACtG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,mBAAmB,EAAE,MAAM,CAAC,EAAE,GAAG,SAAS,CAAC,eAAe,IAAI,CAAC,CAAC;IAC7G,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,mBAAmB,EAAE,MAAM,CAAC,EAAE,GAAG,SAAS,CAAC,eAAe,IAAI,CAAC,CAAC;AAC/G,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4EAA4E,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC7F,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC,CAAC,CAAC;IACzE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE;QACzE,aAAa,EAAE,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC;QAC5C,UAAU,EAAE,KAAK;KACX,CAAC,CAAC;IAEV,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QACX,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,mBAAmB,EAAE,CAAC;IACpC,MAAM,OAAO,CAAC,cAAc,CAAC;QAC3B,gBAAgB,EAAE,0BAA0B;QAC5C,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,mEAAmE;QACpF,eAAe,EAAE,mEAAmE;QACpF,mBAAmB,EAAE,IAAI;QACzB,mBAAmB,EAAE,KAAK;KAC3B,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAS,CAAC;IACxC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;IACjE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3E,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;IAC5E,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC;IAC7E,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9E,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC;IACvE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,0BAA0B,CAAC,CAAC;AAC3E,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mEAAmE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACpF,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,4BAA4B,CAAC,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE;QACpE,aAAa,EAAE,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC;QAC5C,cAAc;QACd,UAAU,EAAE,KAAK;KACX,CAAC,CAAC;IAEV,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QACX,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,mBAAmB,EAAE,CAAC;IACpC,MAAM,OAAO,CAAC,cAAc,CAAC;QAC3B,gBAAgB,EAAE,0BAA0B;QAC5C,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,mEAAmE;QACpF,eAAe,EAAE,mEAAmE;QACpF,mBAAmB,EAAE,IAAI;QACzB,mBAAmB,EAAE,KAAK;KAC3B,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,yBAAyB,EAAE,CAAC;IAE1C,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;IACzE,MAAM,UAAU,GAAG,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAS,CAAC;IAExC,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,8BAA8B,CAAC,CAAC;IACzD,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAEzC,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,wBAAwB,CAAC,CAAC;IACnD,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,mBAAmB,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,MAAM,CAAC,4BAA4B,KAAK,CAAC,wBAAwB,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1I,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,6BAA6B,CAAC,CAAC;IAC/D,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,wBAAwB,EAAE,MAAM,CAAC,EAAE,4BAA4B,CAAC,CAAC;AACnG,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4DAA4D,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC7E,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAAC,CAAC;IACvE,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC/C,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IACtC,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACtD,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;IAC/C,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC7C,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC7C,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,WAAW,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC,cAAc,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IACvD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAE7D,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QACX,IAAI,YAAY,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;;YACnE,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,YAAY,CAAC;QACrD,IAAI,gBAAgB,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;;YAC5D,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,gBAAgB,CAAC;QAC9C,IAAI,eAAe,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;;YAC1D,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,eAAe,CAAC;QAC5C,IAAI,eAAe,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;;YAC1D,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,eAAe,CAAC;QAC5C,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;QACpE,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC;QACnC,aAAa,EAAE,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC;QAC5C,cAAc,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC;QAC1D,UAAU,EAAE,KAAK;QACjB,kBAAkB,EAAE,KAAK,EAAE,QAAgB,EAAE,EAAE;YAC7C,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;KACK,CAAC,CAAC;IAEV,MAAM,OAAO,CAAC,mBAAmB,EAAE,CAAC;IACpC,MAAM,OAAO,CAAC,cAAc,CAAC;QAC3B,gBAAgB,EAAE,0BAA0B;QAC5C,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,mEAAmE;QACpF,eAAe,EAAE,mEAAmE;QACpF,mBAAmB,EAAE,IAAI;QACzB,mBAAmB,EAAE,KAAK;KAC3B,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,yBAAyB,EAAE,CAAC;IAE1C,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;IACtE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC1E,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,IAAI,CAAC,CAAC;IAClE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,IAAI,CAAC,CAAC;IACnE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,8CAA8C,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC/D,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,4BAA4B,CAAC,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC;QACnC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC;QAC9B,aAAa,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,CAAC;QAC7D,cAAc,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,CAAC;QAClE,gBAAgB,EAAE,OAAO;QACzB,UAAU,EAAE,KAAK;KACX,CAAC,CAAC;IAEV,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QACX,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,mBAAmB,EAAE,CAAC;IACpC,MAAM,OAAO,CAAC,cAAc,CAAC;QAC3B,gBAAgB,EAAE,0BAA0B;QAC5C,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,iEAAiE;QAClF,eAAe,EAAE,mEAAmE;QACpF,eAAe,EAAE,mEAAmE;QACpF,mBAAmB,EAAE,IAAI;QACzB,mBAAmB,EAAE,KAAK;KAC3B,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,yBAAyB,EAAE,CAAC;IAE1C,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAS,CAAC;IACxC,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC;IAE5F,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,wBAAwB,EAAE,MAAM,CAAC,EAAE,4BAA4B,CAAC,CAAC;IACjG,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,0BAA0B,CAAC,CAAC;IACrD,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,6BAA6B,CAAC,CAAC;AACjE,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { execSync } from 'child_process';
|
|
18
|
-
import { createWriteStream, mkdirSync, chmodSync, existsSync, unlinkSync, copyFileSync, rmSync, readFileSync, readlinkSync, writeFileSync, symlinkSync, lstatSync } from 'fs';
|
|
18
|
+
import { createWriteStream, mkdirSync, chmodSync, existsSync, unlinkSync, copyFileSync, rmSync, readFileSync, readlinkSync, writeFileSync, symlinkSync, lstatSync, readdirSync } from 'fs';
|
|
19
19
|
import { isAbsolute, join, dirname, resolve } from 'path';
|
|
20
20
|
import { homedir, platform, arch } from 'os';
|
|
21
21
|
import { get } from 'https';
|
|
@@ -75,6 +75,36 @@ function resolveNodePtyDir() {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Clean up node-pty build artifacts that npm can't remove from staging dirs.
|
|
80
|
+
* node-gyp creates .target.mk, Makefile, config.gypi etc. that may be owned
|
|
81
|
+
* by root (when postinstall runs with elevated privileges), causing EACCES
|
|
82
|
+
* errors during npm's post-install cleanup. We remove these build artifacts
|
|
83
|
+
* since node-pty only needs build/Release/pty.node at runtime.
|
|
84
|
+
*/
|
|
85
|
+
function cleanNodePtyBuildArtifacts(dir) {
|
|
86
|
+
if (!dir || !existsSync(dir)) return;
|
|
87
|
+
try {
|
|
88
|
+
// Remove node-addon-api build artifacts (*.target.mk, *.Makefile)
|
|
89
|
+
const nodeAddonApiDir = join(dir, 'node-addon-api');
|
|
90
|
+
if (existsSync(nodeAddonApiDir)) {
|
|
91
|
+
rmSync(nodeAddonApiDir, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
// Remove build directory artifacts except Release/*.node binaries
|
|
94
|
+
const buildDir = join(dir, 'build');
|
|
95
|
+
if (existsSync(buildDir)) {
|
|
96
|
+
const keepPatterns = ['Release'];
|
|
97
|
+
for (const entry of readdirSync(buildDir)) {
|
|
98
|
+
if (!keepPatterns.includes(entry)) {
|
|
99
|
+
rmSync(join(buildDir, entry), { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
// Best effort — if this fails, npm will just show cleanup warnings
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
78
108
|
/**
|
|
79
109
|
* Step 1: Rebuild node-pty with improved error handling
|
|
80
110
|
* For Node.js v24+, prebuilds may not be compatible, so we compile from source
|
|
@@ -90,6 +120,7 @@ function rebuildNodePty() {
|
|
|
90
120
|
// Fast path: already works (cached or live test)
|
|
91
121
|
if (testNodePty()) {
|
|
92
122
|
console.log('[termify-agent] node-pty is working.');
|
|
123
|
+
cleanNodePtyBuildArtifacts(nodePtyDir);
|
|
93
124
|
return true;
|
|
94
125
|
}
|
|
95
126
|
|
|
@@ -111,6 +142,7 @@ function rebuildNodePty() {
|
|
|
111
142
|
|
|
112
143
|
if (testNodePty()) {
|
|
113
144
|
console.log('[termify-agent] node-pty rebuilt successfully.');
|
|
145
|
+
cleanNodePtyBuildArtifacts(nodePtyDir);
|
|
114
146
|
return true;
|
|
115
147
|
}
|
|
116
148
|
} catch (err) {
|
|
@@ -132,6 +164,7 @@ function rebuildNodePty() {
|
|
|
132
164
|
|
|
133
165
|
if (testNodePty()) {
|
|
134
166
|
console.log('[termify-agent] node-pty rebuilt successfully from module directory.');
|
|
167
|
+
cleanNodePtyBuildArtifacts(nodePtyDir);
|
|
135
168
|
return true;
|
|
136
169
|
}
|
|
137
170
|
} catch (err) {
|
|
@@ -151,6 +184,7 @@ function rebuildNodePty() {
|
|
|
151
184
|
|
|
152
185
|
if (testNodePty()) {
|
|
153
186
|
console.log('[termify-agent] node-pty compiled from source successfully.');
|
|
187
|
+
cleanNodePtyBuildArtifacts(nodePtyDir);
|
|
154
188
|
return true;
|
|
155
189
|
}
|
|
156
190
|
} catch (err) {
|
|
@@ -184,12 +218,16 @@ function rebuildNodePty() {
|
|
|
184
218
|
|
|
185
219
|
if (testNodePty()) {
|
|
186
220
|
console.log('[termify-agent] node-pty reinstalled and compiled successfully.');
|
|
221
|
+
cleanNodePtyBuildArtifacts(reinstalledNodePtyDir);
|
|
187
222
|
return true;
|
|
188
223
|
}
|
|
189
224
|
} catch (err2) {
|
|
190
225
|
// Continue to error message
|
|
191
226
|
}
|
|
192
227
|
|
|
228
|
+
// Fix permissions even on failure so npm can clean up staging directory
|
|
229
|
+
cleanNodePtyBuildArtifacts(nodePtyDir);
|
|
230
|
+
|
|
193
231
|
console.error('[termify-agent] CRITICAL: node-pty installation failed.');
|
|
194
232
|
console.error('[termify-agent] Terminal features will NOT work.');
|
|
195
233
|
console.error('[termify-agent] ');
|