@awcp/transport-sshfs 0.0.0-dev-202601300724

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.
@@ -0,0 +1,90 @@
1
+ /**
2
+ * SSH Credential Manager configuration
3
+ */
4
+ export interface CredentialManagerConfig {
5
+ /** Directory to store temporary keys (default: ~/.awcp/keys) */
6
+ keyDir?: string;
7
+ /** SSH server port (default: 22) */
8
+ sshPort?: number;
9
+ /** SSH server host (default: localhost) */
10
+ sshHost?: string;
11
+ /** SSH user for connections */
12
+ sshUser?: string;
13
+ /** Path to authorized_keys file (default: ~/.ssh/authorized_keys) */
14
+ authorizedKeysPath?: string;
15
+ }
16
+ /**
17
+ * Generated credential
18
+ */
19
+ export interface GeneratedCredential {
20
+ /** The private key content */
21
+ privateKey: string;
22
+ /** The public key content */
23
+ publicKey: string;
24
+ /** Path to the private key file */
25
+ privateKeyPath: string;
26
+ /** Path to the public key file */
27
+ publicKeyPath: string;
28
+ /** Delegation ID for tracking */
29
+ delegationId: string;
30
+ }
31
+ /**
32
+ * SSH Credential Manager
33
+ *
34
+ * Manages temporary SSH keys for AWCP delegations.
35
+ *
36
+ * TODO [Security]: Consider SSH certificates with built-in expiry for production.
37
+ */
38
+ export declare class CredentialManager {
39
+ private config;
40
+ private activeCredentials;
41
+ constructor(config?: CredentialManagerConfig);
42
+ /**
43
+ * Get the path to authorized_keys file
44
+ */
45
+ private getAuthorizedKeysPath;
46
+ /**
47
+ * Generate a temporary SSH key pair for a delegation
48
+ */
49
+ generateCredential(delegationId: string, _ttlSeconds: number): Promise<{
50
+ credential: string;
51
+ endpoint: {
52
+ host: string;
53
+ port: number;
54
+ user: string;
55
+ };
56
+ }>;
57
+ /**
58
+ * Revoke a credential
59
+ */
60
+ revokeCredential(delegationId: string): Promise<void>;
61
+ /**
62
+ * Get credential info for a delegation
63
+ */
64
+ getCredential(delegationId: string): GeneratedCredential | undefined;
65
+ /**
66
+ * Revoke all credentials
67
+ */
68
+ revokeAll(): Promise<void>;
69
+ /**
70
+ * Clean up stale AWCP keys from authorized_keys (call on startup)
71
+ */
72
+ cleanupStaleKeys(): Promise<number>;
73
+ /**
74
+ * Clean up stale key files from key directory (call on startup)
75
+ */
76
+ cleanupStaleKeyFiles(): Promise<number>;
77
+ /**
78
+ * Add a public key to authorized_keys
79
+ */
80
+ private addToAuthorizedKeys;
81
+ /**
82
+ * Remove a public key from authorized_keys by delegation ID
83
+ */
84
+ private removeFromAuthorizedKeys;
85
+ /**
86
+ * Execute ssh-keygen to generate a key pair
87
+ */
88
+ private execSshKeygen;
89
+ }
90
+ //# sourceMappingURL=credential-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-manager.d.ts","sourceRoot":"","sources":["../../src/delegator/credential-manager.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,kCAAkC;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;CACtB;AASD;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,iBAAiB,CAA0C;gBAEvD,MAAM,CAAC,EAAE,uBAAuB;IAI5C;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAI7B;;OAEG;IACG,kBAAkB,CACtB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QACT,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;KACxD,CAAC;IAsCF;;OAEG;IACG,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB3D;;OAEG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAIpE;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAMhC;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IA0BzC;;OAEG;IACG,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAkC7C;;OAEG;YACW,mBAAmB;IAcjC;;OAEG;YACW,wBAAwB;IAkBtC;;OAEG;IACH,OAAO,CAAC,aAAa;CAyBtB"}
@@ -0,0 +1,216 @@
1
+ import { unlink, mkdir, readFile, writeFile, appendFile, readdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { spawn } from 'node:child_process';
4
+ import { homedir } from 'node:os';
5
+ const DEFAULT_KEY_DIR = join(homedir(), '.awcp', 'keys');
6
+ /**
7
+ * Marker prefix for AWCP-managed keys in authorized_keys
8
+ */
9
+ const AWCP_KEY_COMMENT_PREFIX = 'awcp-temp-key-';
10
+ /**
11
+ * SSH Credential Manager
12
+ *
13
+ * Manages temporary SSH keys for AWCP delegations.
14
+ *
15
+ * TODO [Security]: Consider SSH certificates with built-in expiry for production.
16
+ */
17
+ export class CredentialManager {
18
+ config;
19
+ activeCredentials = new Map();
20
+ constructor(config) {
21
+ this.config = config ?? {};
22
+ }
23
+ /**
24
+ * Get the path to authorized_keys file
25
+ */
26
+ getAuthorizedKeysPath() {
27
+ return this.config.authorizedKeysPath ?? join(homedir(), '.ssh', 'authorized_keys');
28
+ }
29
+ /**
30
+ * Generate a temporary SSH key pair for a delegation
31
+ */
32
+ async generateCredential(delegationId, _ttlSeconds) {
33
+ const keyDir = this.config.keyDir ?? DEFAULT_KEY_DIR;
34
+ await mkdir(keyDir, { recursive: true, mode: 0o700 });
35
+ const privateKeyPath = join(keyDir, `${delegationId}`);
36
+ const publicKeyPath = join(keyDir, `${delegationId}.pub`);
37
+ // Generate key pair using ssh-keygen with AWCP marker comment
38
+ const keyComment = `${AWCP_KEY_COMMENT_PREFIX}${delegationId}`;
39
+ await this.execSshKeygen(privateKeyPath, keyComment);
40
+ // Read the generated keys
41
+ const privateKey = await readFile(privateKeyPath, 'utf-8');
42
+ const publicKey = await readFile(publicKeyPath, 'utf-8');
43
+ const credential = {
44
+ privateKey,
45
+ publicKey,
46
+ privateKeyPath,
47
+ publicKeyPath,
48
+ delegationId,
49
+ };
50
+ this.activeCredentials.set(delegationId, credential);
51
+ // Add public key to authorized_keys
52
+ await this.addToAuthorizedKeys(publicKey);
53
+ return {
54
+ credential: privateKey,
55
+ endpoint: {
56
+ host: this.config.sshHost ?? 'localhost',
57
+ port: this.config.sshPort ?? 22,
58
+ user: this.config.sshUser ?? process.env['USER'] ?? 'awcp',
59
+ },
60
+ };
61
+ }
62
+ /**
63
+ * Revoke a credential
64
+ */
65
+ async revokeCredential(delegationId) {
66
+ const credential = this.activeCredentials.get(delegationId);
67
+ if (!credential) {
68
+ return;
69
+ }
70
+ // Remove from authorized_keys first
71
+ await this.removeFromAuthorizedKeys(delegationId);
72
+ // Remove key files
73
+ try {
74
+ await unlink(credential.privateKeyPath);
75
+ }
76
+ catch {
77
+ // Ignore errors if file doesn't exist
78
+ }
79
+ try {
80
+ await unlink(credential.publicKeyPath);
81
+ }
82
+ catch {
83
+ // Ignore errors if file doesn't exist
84
+ }
85
+ this.activeCredentials.delete(delegationId);
86
+ }
87
+ /**
88
+ * Get credential info for a delegation
89
+ */
90
+ getCredential(delegationId) {
91
+ return this.activeCredentials.get(delegationId);
92
+ }
93
+ /**
94
+ * Revoke all credentials
95
+ */
96
+ async revokeAll() {
97
+ for (const delegationId of this.activeCredentials.keys()) {
98
+ await this.revokeCredential(delegationId);
99
+ }
100
+ }
101
+ /**
102
+ * Clean up stale AWCP keys from authorized_keys (call on startup)
103
+ */
104
+ async cleanupStaleKeys() {
105
+ const authorizedKeysPath = this.getAuthorizedKeysPath();
106
+ try {
107
+ const content = await readFile(authorizedKeysPath, 'utf-8');
108
+ const lines = content.split('\n');
109
+ const cleanedLines = lines.filter(line => {
110
+ // Keep lines that don't have AWCP marker
111
+ return !line.includes(AWCP_KEY_COMMENT_PREFIX);
112
+ });
113
+ const removedCount = lines.length - cleanedLines.length;
114
+ if (removedCount > 0) {
115
+ await writeFile(authorizedKeysPath, cleanedLines.join('\n'));
116
+ console.log(`[CredentialManager] Cleaned up ${removedCount} stale AWCP keys from authorized_keys`);
117
+ }
118
+ return removedCount;
119
+ }
120
+ catch {
121
+ // File doesn't exist or can't be read, nothing to clean
122
+ return 0;
123
+ }
124
+ }
125
+ /**
126
+ * Clean up stale key files from key directory (call on startup)
127
+ */
128
+ async cleanupStaleKeyFiles() {
129
+ const keyDir = this.config.keyDir ?? DEFAULT_KEY_DIR;
130
+ try {
131
+ const files = await readdir(keyDir);
132
+ let removedCount = 0;
133
+ for (const file of files) {
134
+ // Skip files that are currently active
135
+ const delegationId = file.replace(/\.pub$/, '');
136
+ if (this.activeCredentials.has(delegationId)) {
137
+ continue;
138
+ }
139
+ // Remove stale key files
140
+ try {
141
+ await unlink(join(keyDir, file));
142
+ removedCount++;
143
+ }
144
+ catch {
145
+ // Ignore errors
146
+ }
147
+ }
148
+ if (removedCount > 0) {
149
+ console.log(`[CredentialManager] Cleaned up ${removedCount} stale key files`);
150
+ }
151
+ return removedCount;
152
+ }
153
+ catch {
154
+ // Directory doesn't exist, nothing to clean
155
+ return 0;
156
+ }
157
+ }
158
+ /**
159
+ * Add a public key to authorized_keys
160
+ */
161
+ async addToAuthorizedKeys(publicKey) {
162
+ const authorizedKeysPath = this.getAuthorizedKeysPath();
163
+ // Ensure .ssh directory exists
164
+ const sshDir = join(homedir(), '.ssh');
165
+ await mkdir(sshDir, { recursive: true, mode: 0o700 });
166
+ // Ensure the key ends with newline
167
+ const keyLine = publicKey.trim() + '\n';
168
+ // Append to authorized_keys
169
+ await appendFile(authorizedKeysPath, keyLine, { mode: 0o600 });
170
+ }
171
+ /**
172
+ * Remove a public key from authorized_keys by delegation ID
173
+ */
174
+ async removeFromAuthorizedKeys(delegationId) {
175
+ const authorizedKeysPath = this.getAuthorizedKeysPath();
176
+ const keyMarker = `${AWCP_KEY_COMMENT_PREFIX}${delegationId}`;
177
+ try {
178
+ const content = await readFile(authorizedKeysPath, 'utf-8');
179
+ const lines = content.split('\n');
180
+ // Filter out lines containing this delegation's key marker
181
+ const filteredLines = lines.filter(line => !line.includes(keyMarker));
182
+ // Write back
183
+ await writeFile(authorizedKeysPath, filteredLines.join('\n'), { mode: 0o600 });
184
+ }
185
+ catch {
186
+ // File doesn't exist or can't be read, nothing to remove
187
+ }
188
+ }
189
+ /**
190
+ * Execute ssh-keygen to generate a key pair
191
+ */
192
+ execSshKeygen(keyPath, comment) {
193
+ return new Promise((resolve, reject) => {
194
+ const proc = spawn('ssh-keygen', [
195
+ '-t', 'ed25519',
196
+ '-f', keyPath,
197
+ '-N', '', // No passphrase
198
+ '-C', comment,
199
+ ]);
200
+ let stderr = '';
201
+ proc.stderr.on('data', (data) => {
202
+ stderr += data.toString();
203
+ });
204
+ proc.on('close', (code) => {
205
+ if (code === 0) {
206
+ resolve();
207
+ }
208
+ else {
209
+ reject(new Error(`ssh-keygen failed: ${stderr}`));
210
+ }
211
+ });
212
+ proc.on('error', reject);
213
+ });
214
+ }
215
+ }
216
+ //# sourceMappingURL=credential-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-manager.js","sourceRoot":"","sources":["../../src/delegator/credential-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { CredentialManager, type CredentialManagerConfig, type GeneratedCredential } from './credential-manager.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/delegator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,uBAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { CredentialManager } from './credential-manager.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/delegator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA0D,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { SshfsMountClient, type SshfsMountConfig, type MountParams } from './sshfs-client.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/executor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { SshfsMountClient } from './sshfs-client.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/executor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA2C,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * SSHFS Mount Client configuration
3
+ */
4
+ export interface SshfsMountConfig {
5
+ /** Directory to store temporary key files */
6
+ tempKeyDir?: string;
7
+ /** Additional sshfs options */
8
+ defaultOptions?: Record<string, string>;
9
+ /** Timeout for mount operation in ms (default: 30000) */
10
+ mountTimeout?: number;
11
+ }
12
+ /**
13
+ * Mount parameters
14
+ */
15
+ export interface MountParams {
16
+ endpoint: {
17
+ host: string;
18
+ port: number;
19
+ user: string;
20
+ };
21
+ exportLocator: string;
22
+ credential: string;
23
+ mountPoint: string;
24
+ options?: Record<string, string>;
25
+ }
26
+ /**
27
+ * SSHFS Mount Client
28
+ *
29
+ * Handles mounting remote filesystems via SSHFS on the Remote side.
30
+ */
31
+ export declare class SshfsMountClient {
32
+ private config;
33
+ private activeMounts;
34
+ constructor(config?: SshfsMountConfig);
35
+ /**
36
+ * Check if sshfs is available
37
+ */
38
+ checkDependency(): Promise<{
39
+ available: boolean;
40
+ version?: string;
41
+ error?: string;
42
+ }>;
43
+ /**
44
+ * Mount a remote filesystem
45
+ */
46
+ mount(params: MountParams): Promise<void>;
47
+ /**
48
+ * Unmount a filesystem
49
+ */
50
+ unmount(mountPoint: string): Promise<void>;
51
+ /**
52
+ * Check if a mount point is currently mounted
53
+ */
54
+ isMounted(mountPoint: string): Promise<boolean>;
55
+ /**
56
+ * Unmount all active mounts
57
+ */
58
+ unmountAll(): Promise<void>;
59
+ private execMount;
60
+ private execCommand;
61
+ }
62
+ //# sourceMappingURL=sshfs-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sshfs-client.d.ts","sourceRoot":"","sources":["../../src/executor/sshfs-client.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAcD;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,YAAY,CAAkC;gBAE1C,MAAM,CAAC,EAAE,gBAAgB;IAIrC;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAoC1F;;OAEG;IACG,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA+D/C;;OAEG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgChD;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUrD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC,OAAO,CAAC,SAAS;IAyDjB,OAAO,CAAC,WAAW;CAepB"}
@@ -0,0 +1,225 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { writeFile, unlink, mkdir, stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { MountFailedError, DependencyMissingError } from '@awcp/core';
5
+ const DEFAULT_TEMP_KEY_DIR = '/tmp/awcp/client-keys';
6
+ const DEFAULT_MOUNT_TIMEOUT = 30000;
7
+ /**
8
+ * SSHFS Mount Client
9
+ *
10
+ * Handles mounting remote filesystems via SSHFS on the Remote side.
11
+ */
12
+ export class SshfsMountClient {
13
+ config;
14
+ activeMounts = new Map();
15
+ constructor(config) {
16
+ this.config = config ?? {};
17
+ }
18
+ /**
19
+ * Check if sshfs is available
20
+ */
21
+ async checkDependency() {
22
+ return new Promise((resolve) => {
23
+ const proc = spawn('sshfs', ['--version']);
24
+ let output = '';
25
+ proc.stdout.on('data', (data) => {
26
+ output += data.toString();
27
+ });
28
+ proc.stderr.on('data', (data) => {
29
+ output += data.toString();
30
+ });
31
+ proc.on('close', (code) => {
32
+ if (code === 0 || output.includes('SSHFS')) {
33
+ const versionMatch = output.match(/SSHFS version ([\d.]+)/);
34
+ resolve({
35
+ available: true,
36
+ version: versionMatch?.[1],
37
+ });
38
+ }
39
+ else {
40
+ resolve({
41
+ available: false,
42
+ error: 'sshfs not found',
43
+ });
44
+ }
45
+ });
46
+ proc.on('error', () => {
47
+ resolve({
48
+ available: false,
49
+ error: 'sshfs not found in PATH',
50
+ });
51
+ });
52
+ });
53
+ }
54
+ /**
55
+ * Mount a remote filesystem
56
+ */
57
+ async mount(params) {
58
+ // Check dependency
59
+ const depCheck = await this.checkDependency();
60
+ if (!depCheck.available) {
61
+ throw new DependencyMissingError('sshfs', 'Install sshfs: brew install macfuse && brew install sshfs (macOS) or apt install sshfs (Linux)');
62
+ }
63
+ const tempKeyDir = this.config.tempKeyDir ?? DEFAULT_TEMP_KEY_DIR;
64
+ await mkdir(tempKeyDir, { recursive: true });
65
+ // Write credential to temp file
66
+ const keyPath = join(tempKeyDir, `mount-${Date.now()}`);
67
+ await writeFile(keyPath, params.credential, { mode: 0o600 });
68
+ try {
69
+ // Build sshfs command
70
+ const { host, port, user } = params.endpoint;
71
+ const remoteSpec = `${user}@${host}:${params.exportLocator}`;
72
+ const options = {
73
+ ...this.config.defaultOptions,
74
+ ...params.options,
75
+ };
76
+ const args = [
77
+ remoteSpec,
78
+ params.mountPoint,
79
+ '-o', `IdentityFile=${keyPath}`,
80
+ '-o', `Port=${port}`,
81
+ '-o', 'StrictHostKeyChecking=no',
82
+ '-o', 'UserKnownHostsFile=/dev/null',
83
+ '-o', 'reconnect',
84
+ '-o', 'ServerAliveInterval=15',
85
+ '-o', 'ServerAliveCountMax=3',
86
+ '-o', 'noappledouble', // Prevent macOS ._* metadata files
87
+ ];
88
+ // Add custom options
89
+ for (const [key, value] of Object.entries(options)) {
90
+ args.push('-o', `${key}=${value}`);
91
+ }
92
+ console.log(`[SSHFS] Mounting: sshfs ${args.join(' ')}`);
93
+ // Execute mount (SSHFS will daemonize and exit immediately on success)
94
+ await this.execMount(args, params.mountPoint);
95
+ // Track active mount
96
+ this.activeMounts.set(params.mountPoint, {
97
+ mountPoint: params.mountPoint,
98
+ keyPath,
99
+ });
100
+ }
101
+ catch (error) {
102
+ // Cleanup key on failure
103
+ await unlink(keyPath).catch(() => { });
104
+ throw error;
105
+ }
106
+ }
107
+ /**
108
+ * Unmount a filesystem
109
+ */
110
+ async unmount(mountPoint) {
111
+ const activeMount = this.activeMounts.get(mountPoint);
112
+ // Try different unmount methods
113
+ const unmountCommands = [
114
+ ['umount', mountPoint],
115
+ ['fusermount', '-u', mountPoint],
116
+ ['diskutil', 'unmount', mountPoint], // macOS
117
+ ];
118
+ let success = false;
119
+ for (const cmd of unmountCommands) {
120
+ try {
121
+ await this.execCommand(cmd[0], cmd.slice(1));
122
+ success = true;
123
+ break;
124
+ }
125
+ catch {
126
+ // Try next method
127
+ }
128
+ }
129
+ if (!success) {
130
+ console.warn(`Failed to unmount ${mountPoint}, may need manual cleanup`);
131
+ }
132
+ // Cleanup
133
+ if (activeMount) {
134
+ await unlink(activeMount.keyPath).catch(() => { });
135
+ this.activeMounts.delete(mountPoint);
136
+ }
137
+ }
138
+ /**
139
+ * Check if a mount point is currently mounted
140
+ */
141
+ async isMounted(mountPoint) {
142
+ try {
143
+ // Check if the mount point exists and is tracked
144
+ await stat(mountPoint);
145
+ return this.activeMounts.has(mountPoint);
146
+ }
147
+ catch {
148
+ return false;
149
+ }
150
+ }
151
+ /**
152
+ * Unmount all active mounts
153
+ */
154
+ async unmountAll() {
155
+ for (const mountPoint of this.activeMounts.keys()) {
156
+ await this.unmount(mountPoint);
157
+ }
158
+ }
159
+ execMount(args, mountPoint) {
160
+ const timeout = this.config.mountTimeout ?? DEFAULT_MOUNT_TIMEOUT;
161
+ return new Promise((resolve, reject) => {
162
+ // SSHFS without -f will daemonize and exit immediately with code 0 on success
163
+ const proc = spawn('sshfs', args, {
164
+ stdio: ['ignore', 'pipe', 'pipe'],
165
+ });
166
+ let stderr = '';
167
+ proc.stderr.on('data', (data) => {
168
+ stderr += data.toString();
169
+ });
170
+ const timer = setTimeout(async () => {
171
+ proc.kill();
172
+ // Clean up possible zombie mount
173
+ try {
174
+ await this.unmount(mountPoint);
175
+ }
176
+ catch {
177
+ // Ignore - mount may not exist
178
+ }
179
+ reject(new MountFailedError(`Mount timeout after ${timeout}ms`));
180
+ }, timeout);
181
+ proc.on('close', async (code) => {
182
+ clearTimeout(timer);
183
+ if (code !== 0) {
184
+ reject(new MountFailedError(stderr || `sshfs exited with code ${code}`));
185
+ return;
186
+ }
187
+ // SSHFS daemonized successfully (exit code 0)
188
+ // Now verify the mount is actually there
189
+ try {
190
+ const mountStat = await stat(mountPoint);
191
+ const parentStat = await stat(join(mountPoint, '..'));
192
+ if (mountStat.dev !== parentStat.dev) {
193
+ // Different device = mounted successfully
194
+ resolve();
195
+ }
196
+ else {
197
+ reject(new MountFailedError('SSHFS exited but mount not detected'));
198
+ }
199
+ }
200
+ catch (error) {
201
+ reject(new MountFailedError(`Mount verification failed: ${error}`));
202
+ }
203
+ });
204
+ proc.on('error', (error) => {
205
+ clearTimeout(timer);
206
+ reject(new MountFailedError(error.message));
207
+ });
208
+ });
209
+ }
210
+ execCommand(cmd, args) {
211
+ return new Promise((resolve, reject) => {
212
+ const proc = spawn(cmd, args);
213
+ proc.on('close', (code) => {
214
+ if (code === 0) {
215
+ resolve();
216
+ }
217
+ else {
218
+ reject(new Error(`${cmd} exited with code ${code}`));
219
+ }
220
+ });
221
+ proc.on('error', reject);
222
+ });
223
+ }
224
+ }
225
+ //# sourceMappingURL=sshfs-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sshfs-client.js","sourceRoot":"","sources":["../../src/executor/sshfs-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @awcp/transport-sshfs
3
+ *
4
+ * SSHFS Transport implementation for AWCP data plane
5
+ */
6
+ export { CredentialManager, type CredentialManagerConfig, type GeneratedCredential, } from './delegator/index.js';
7
+ export { SshfsMountClient, type SshfsMountConfig, type MountParams, } from './executor/index.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,iBAAiB,EACjB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,GACzB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,WAAW,GACjB,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @awcp/transport-sshfs
3
+ *
4
+ * SSHFS Transport implementation for AWCP data plane
5
+ */
6
+ // Delegator-side exports
7
+ export { CredentialManager, } from './delegator/index.js';
8
+ // Executor-side exports
9
+ export { SshfsMountClient, } from './executor/index.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yBAAyB;AACzB,OAAO,EACL,iBAAiB,GAGlB,MAAM,sBAAsB,CAAC;AAE9B,wBAAwB;AACxB,OAAO,EACL,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@awcp/transport-sshfs",
3
+ "version": "0.0.0-dev-202601300724",
4
+ "description": "AWCP SSHFS Transport - SSH/SFTP based data plane implementation",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./host": {
14
+ "types": "./dist/host/index.d.ts",
15
+ "import": "./dist/host/index.js"
16
+ },
17
+ "./remote": {
18
+ "types": "./dist/remote/index.d.ts",
19
+ "import": "./dist/remote/index.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.build.json",
28
+ "clean": "rm -rf dist *.tsbuildinfo",
29
+ "test": "vitest run",
30
+ "test:watch": "vitest"
31
+ },
32
+ "dependencies": {
33
+ "@awcp/core": "0.0.0-dev-202601300724"
34
+ },
35
+ "keywords": [
36
+ "awcp",
37
+ "sshfs",
38
+ "transport",
39
+ "sftp",
40
+ "mount"
41
+ ],
42
+ "license": "Apache-2.0",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/anthropics/awcp.git",
46
+ "directory": "packages/transport-sshfs"
47
+ }
48
+ }