@devalade/shipnode 2.0.0
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/cli/commands/backup.d.ts +14 -0
- package/dist/cli/commands/backup.d.ts.map +1 -0
- package/dist/cli/commands/backup.js +144 -0
- package/dist/cli/commands/backup.js.map +1 -0
- package/dist/cli/commands/ci.d.ts +5 -0
- package/dist/cli/commands/ci.d.ts.map +1 -0
- package/dist/cli/commands/ci.js +222 -0
- package/dist/cli/commands/ci.js.map +1 -0
- package/dist/cli/commands/cloudflare.d.ts +10 -0
- package/dist/cli/commands/cloudflare.d.ts.map +1 -0
- package/dist/cli/commands/cloudflare.js +166 -0
- package/dist/cli/commands/cloudflare.js.map +1 -0
- package/dist/cli/commands/config.d.ts +10 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +99 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/deploy.d.ts +6 -0
- package/dist/cli/commands/deploy.d.ts.map +1 -0
- package/dist/cli/commands/deploy.js +95 -0
- package/dist/cli/commands/deploy.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +5 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +86 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/eject.d.ts +2 -0
- package/dist/cli/commands/eject.d.ts.map +1 -0
- package/dist/cli/commands/eject.js +74 -0
- package/dist/cli/commands/eject.js.map +1 -0
- package/dist/cli/commands/env.d.ts +4 -0
- package/dist/cli/commands/env.d.ts.map +1 -0
- package/dist/cli/commands/env.js +50 -0
- package/dist/cli/commands/env.js.map +1 -0
- package/dist/cli/commands/harden.d.ts +4 -0
- package/dist/cli/commands/harden.d.ts.map +1 -0
- package/dist/cli/commands/harden.js +110 -0
- package/dist/cli/commands/harden.js.map +1 -0
- package/dist/cli/commands/help.d.ts +2 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +99 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/init.d.ts +5 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +246 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/logs.d.ts +5 -0
- package/dist/cli/commands/logs.d.ts.map +1 -0
- package/dist/cli/commands/logs.js +17 -0
- package/dist/cli/commands/logs.js.map +1 -0
- package/dist/cli/commands/metrics.d.ts +4 -0
- package/dist/cli/commands/metrics.d.ts.map +1 -0
- package/dist/cli/commands/metrics.js +21 -0
- package/dist/cli/commands/metrics.js.map +1 -0
- package/dist/cli/commands/migrate.d.ts +4 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +71 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/restart.d.ts +4 -0
- package/dist/cli/commands/restart.d.ts.map +1 -0
- package/dist/cli/commands/restart.js +14 -0
- package/dist/cli/commands/restart.js.map +1 -0
- package/dist/cli/commands/rollback.d.ts +5 -0
- package/dist/cli/commands/rollback.d.ts.map +1 -0
- package/dist/cli/commands/rollback.js +49 -0
- package/dist/cli/commands/rollback.js.map +1 -0
- package/dist/cli/commands/run.d.ts +5 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +69 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +4 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +46 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/status.d.ts +4 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +49 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +4 -0
- package/dist/cli/commands/stop.d.ts.map +1 -0
- package/dist/cli/commands/stop.js +14 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/commands/unlock.d.ts +4 -0
- package/dist/cli/commands/unlock.d.ts.map +1 -0
- package/dist/cli/commands/unlock.js +27 -0
- package/dist/cli/commands/unlock.js.map +1 -0
- package/dist/cli/commands/upgrade.d.ts +2 -0
- package/dist/cli/commands/upgrade.d.ts.map +1 -0
- package/dist/cli/commands/upgrade.js +63 -0
- package/dist/cli/commands/upgrade.js.map +1 -0
- package/dist/cli/commands/user.d.ts +17 -0
- package/dist/cli/commands/user.d.ts.map +1 -0
- package/dist/cli/commands/user.js +98 -0
- package/dist/cli/commands/user.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +218 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompt.d.ts +2 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +11 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/cli/runner.d.ts +34 -0
- package/dist/cli/runner.d.ts.map +1 -0
- package/dist/cli/runner.js +44 -0
- package/dist/cli/runner.js.map +1 -0
- package/dist/cli/ui.d.ts +9 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +26 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/config/assembly.d.ts +14 -0
- package/dist/config/assembly.d.ts.map +1 -0
- package/dist/config/assembly.js +62 -0
- package/dist/config/assembly.js.map +1 -0
- package/dist/config/builder.d.ts +33 -0
- package/dist/config/builder.d.ts.map +1 -0
- package/dist/config/builder.js +119 -0
- package/dist/config/builder.js.map +1 -0
- package/dist/config/loader.d.ts +3 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +20 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +416 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +75 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/domain/deploy/backend-strategy.d.ts +15 -0
- package/dist/domain/deploy/backend-strategy.d.ts.map +1 -0
- package/dist/domain/deploy/backend-strategy.js +110 -0
- package/dist/domain/deploy/backend-strategy.js.map +1 -0
- package/dist/domain/deploy/frontend-strategy.d.ts +13 -0
- package/dist/domain/deploy/frontend-strategy.d.ts.map +1 -0
- package/dist/domain/deploy/frontend-strategy.js +64 -0
- package/dist/domain/deploy/frontend-strategy.js.map +1 -0
- package/dist/domain/deploy/orchestrator.d.ts +34 -0
- package/dist/domain/deploy/orchestrator.d.ts.map +1 -0
- package/dist/domain/deploy/orchestrator.js +149 -0
- package/dist/domain/deploy/orchestrator.js.map +1 -0
- package/dist/domain/deploy/strategy.d.ts +44 -0
- package/dist/domain/deploy/strategy.d.ts.map +1 -0
- package/dist/domain/deploy/strategy.js +2 -0
- package/dist/domain/deploy/strategy.js.map +1 -0
- package/dist/domain/framework/detector.d.ts +7 -0
- package/dist/domain/framework/detector.d.ts.map +1 -0
- package/dist/domain/framework/detector.js +109 -0
- package/dist/domain/framework/detector.js.map +1 -0
- package/dist/domain/release/manager.d.ts +22 -0
- package/dist/domain/release/manager.d.ts.map +1 -0
- package/dist/domain/release/manager.js +100 -0
- package/dist/domain/release/manager.js.map +1 -0
- package/dist/domain/remote/executor.d.ts +16 -0
- package/dist/domain/remote/executor.d.ts.map +1 -0
- package/dist/domain/remote/executor.js +2 -0
- package/dist/domain/remote/executor.js.map +1 -0
- package/dist/domain/validation/ip.d.ts +5 -0
- package/dist/domain/validation/ip.d.ts.map +1 -0
- package/dist/domain/validation/ip.js +38 -0
- package/dist/domain/validation/ip.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/ssh/connection.d.ts +19 -0
- package/dist/infrastructure/ssh/connection.d.ts.map +1 -0
- package/dist/infrastructure/ssh/connection.js +89 -0
- package/dist/infrastructure/ssh/connection.js.map +1 -0
- package/dist/services/caddy.service.d.ts +12 -0
- package/dist/services/caddy.service.d.ts.map +1 -0
- package/dist/services/caddy.service.js +56 -0
- package/dist/services/caddy.service.js.map +1 -0
- package/dist/services/deploy.service.d.ts +19 -0
- package/dist/services/deploy.service.d.ts.map +1 -0
- package/dist/services/deploy.service.js +53 -0
- package/dist/services/deploy.service.js.map +1 -0
- package/dist/services/health.service.d.ts +13 -0
- package/dist/services/health.service.d.ts.map +1 -0
- package/dist/services/health.service.js +38 -0
- package/dist/services/health.service.js.map +1 -0
- package/dist/shared/constants.d.ts +127 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +85 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/errors.d.ts +27 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/errors.js +53 -0
- package/dist/shared/errors.js.map +1 -0
- package/dist/shared/types.d.ts +116 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +2 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { resolve } from 'path';
|
|
2
|
+
import { pathExists } from 'fs-extra';
|
|
3
|
+
import { runLocalCommand } from '../runner.js';
|
|
4
|
+
import { ui } from '../ui.js';
|
|
5
|
+
import { loadConfig } from '../../config/loader.js';
|
|
6
|
+
export async function cmdConfigShow(cwd, options) {
|
|
7
|
+
await runLocalCommand(cwd, async (config) => {
|
|
8
|
+
ui.heading('Shipnode Configuration');
|
|
9
|
+
ui.section('App', [
|
|
10
|
+
['app', config.app],
|
|
11
|
+
['nodeVersion', config.nodeVersion],
|
|
12
|
+
['envFile', config.envFile],
|
|
13
|
+
['zeroDowntime', String(config.zeroDowntime)],
|
|
14
|
+
['keepReleases', String(config.keepReleases)],
|
|
15
|
+
]);
|
|
16
|
+
ui.section('SSH', [
|
|
17
|
+
['ssh', `${config.ssh.user}@${config.ssh.host}:${config.ssh.port}`],
|
|
18
|
+
['remotePath', config.remotePath],
|
|
19
|
+
]);
|
|
20
|
+
if (config.pm2) {
|
|
21
|
+
ui.section('PM2', [
|
|
22
|
+
['name', config.pm2.name],
|
|
23
|
+
...(config.pm2.instances !== undefined ? [['instances', String(config.pm2.instances)]] : []),
|
|
24
|
+
...(config.pm2.maxMemory !== undefined ? [['maxMemory', config.pm2.maxMemory]] : []),
|
|
25
|
+
]);
|
|
26
|
+
}
|
|
27
|
+
if (config.backend) {
|
|
28
|
+
ui.section('Backend', [
|
|
29
|
+
['port', String(config.backend.port)],
|
|
30
|
+
]);
|
|
31
|
+
}
|
|
32
|
+
if (config.domain) {
|
|
33
|
+
ui.section('Domain', [
|
|
34
|
+
['domain', config.domain],
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
if (config.app === 'backend') {
|
|
38
|
+
ui.section('Health Check', [
|
|
39
|
+
['enabled', String(config.healthCheck.enabled)],
|
|
40
|
+
['path', config.healthCheck.path],
|
|
41
|
+
['timeout', String(config.healthCheck.timeout)],
|
|
42
|
+
['retries', String(config.healthCheck.retries)],
|
|
43
|
+
['startupDelay', String(config.healthCheck.startupDelay)],
|
|
44
|
+
]);
|
|
45
|
+
}
|
|
46
|
+
if (config.sharedDirs && config.sharedDirs.length > 0) {
|
|
47
|
+
ui.section('Shared Dirs', config.sharedDirs.map((d, i) => [`[${i}]`, d]));
|
|
48
|
+
}
|
|
49
|
+
if (config.sharedFiles && config.sharedFiles.length > 0) {
|
|
50
|
+
ui.section('Shared Files', config.sharedFiles.map((f, i) => [`[${i}]`, f]));
|
|
51
|
+
}
|
|
52
|
+
if (config.database) {
|
|
53
|
+
ui.section('Database', [
|
|
54
|
+
['type', config.database.type],
|
|
55
|
+
['host', config.database.host],
|
|
56
|
+
['port', String(config.database.port)],
|
|
57
|
+
['name', config.database.name],
|
|
58
|
+
['user', config.database.user],
|
|
59
|
+
]);
|
|
60
|
+
}
|
|
61
|
+
}, { configPath: options.config });
|
|
62
|
+
}
|
|
63
|
+
export async function cmdConfigValidate(cwd, options) {
|
|
64
|
+
try {
|
|
65
|
+
await loadConfig(cwd, options.config);
|
|
66
|
+
ui.success('Configuration is valid');
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
70
|
+
ui.error(message);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export async function cmdConfigPath(cwd, options) {
|
|
75
|
+
if (options.config) {
|
|
76
|
+
const exists = await pathExists(options.config);
|
|
77
|
+
if (exists) {
|
|
78
|
+
console.log(options.config);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
ui.error(`Config file not found: ${options.config}`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const tsPath = resolve(cwd, 'shipnode.config.ts');
|
|
87
|
+
const jsPath = resolve(cwd, 'shipnode.config.js');
|
|
88
|
+
if (await pathExists(tsPath)) {
|
|
89
|
+
console.log(tsPath);
|
|
90
|
+
}
|
|
91
|
+
else if (await pathExists(jsPath)) {
|
|
92
|
+
console.log(jsPath);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
ui.error(`No shipnode.config.ts or shipnode.config.js found in ${cwd}`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/deploy.ts"],"names":[],"mappings":"AAMA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB/H"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { loadConfig } from '../../config/loader.js';
|
|
2
|
+
import { DeployService } from '../../services/deploy.service.js';
|
|
3
|
+
import { runRemoteCommand } from '../runner.js';
|
|
4
|
+
import { ui } from '../ui.js';
|
|
5
|
+
export async function cmdDeploy(cwd, options) {
|
|
6
|
+
const config = await loadConfig(cwd, options.config);
|
|
7
|
+
if (options.dryRun) {
|
|
8
|
+
printDryRun(config, options.skipBuild ?? false);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
await runRemoteCommand(cwd, async ({ config, executor }) => {
|
|
12
|
+
ui.info(`Deploying ${config.app} to ${config.ssh.user}@${config.ssh.host}...`);
|
|
13
|
+
ui.info('Connecting to server...');
|
|
14
|
+
ui.success('Connected');
|
|
15
|
+
const deployer = new DeployService(executor, config, cwd);
|
|
16
|
+
await deployer.execute(options.skipBuild ?? false);
|
|
17
|
+
ui.success('Deployment complete');
|
|
18
|
+
}, { configPath: options.config });
|
|
19
|
+
}
|
|
20
|
+
function printDryRun(config, skipBuild) {
|
|
21
|
+
console.log('\n===========================================');
|
|
22
|
+
console.log(' DEPLOYMENT DRY RUN MODE');
|
|
23
|
+
console.log('===========================================\n');
|
|
24
|
+
console.log('Configuration:');
|
|
25
|
+
console.log(` App Type: ${config.app}`);
|
|
26
|
+
console.log(` SSH User: ${config.ssh.user}`);
|
|
27
|
+
console.log(` SSH Host: ${config.ssh.host}`);
|
|
28
|
+
console.log(` SSH Port: ${config.ssh.port}`);
|
|
29
|
+
console.log(` Remote Path: ${config.remotePath}`);
|
|
30
|
+
console.log(` Zero Downtime: ${config.zeroDowntime}`);
|
|
31
|
+
if (config.app === 'backend') {
|
|
32
|
+
console.log(` PM2 App Name: ${config.pm2?.name ?? 'N/A'}`);
|
|
33
|
+
console.log(` Backend Port: ${config.backend?.port ?? 3000}`);
|
|
34
|
+
}
|
|
35
|
+
if (config.domain) {
|
|
36
|
+
console.log(` Domain: ${config.domain}`);
|
|
37
|
+
}
|
|
38
|
+
console.log('\nLocal Build Commands:');
|
|
39
|
+
if (skipBuild) {
|
|
40
|
+
console.log(' [SKIPPED via --skip-build flag]');
|
|
41
|
+
}
|
|
42
|
+
else if (config.app === 'frontend') {
|
|
43
|
+
console.log(' 1. npm run build (or detected package manager)');
|
|
44
|
+
console.log(' 2. Detected build output: dist/');
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log(' [Backend builds happen on remote server]');
|
|
48
|
+
}
|
|
49
|
+
console.log('\nRemote Deployment Commands:');
|
|
50
|
+
if (config.zeroDowntime) {
|
|
51
|
+
console.log(' Mode: Zero-Downtime Deployment');
|
|
52
|
+
console.log('\n Deployment Flow:');
|
|
53
|
+
console.log(' 1. Acquire deployment lock');
|
|
54
|
+
console.log(' 2. Create new release directory');
|
|
55
|
+
console.log(' 3. Setup release structure');
|
|
56
|
+
console.log(' 4. Rsync local files to release directory');
|
|
57
|
+
console.log(' 5. Link shared resources');
|
|
58
|
+
console.log(' 6. Install dependencies');
|
|
59
|
+
if (config.app === 'backend') {
|
|
60
|
+
console.log(' 7. Run pre-deploy hook (if configured)');
|
|
61
|
+
console.log(' 8. Atomic symlink switch');
|
|
62
|
+
console.log(' 9. Reload PM2');
|
|
63
|
+
console.log(' 10. Health check');
|
|
64
|
+
console.log(' 11. Record release');
|
|
65
|
+
console.log(' 12. Cleanup old releases');
|
|
66
|
+
console.log(' 13. Run post-deploy hook (if configured)');
|
|
67
|
+
console.log(' 14. Release deployment lock');
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.log(' 7. Atomic symlink switch');
|
|
71
|
+
console.log(' 8. Record release');
|
|
72
|
+
console.log(' 9. Cleanup old releases');
|
|
73
|
+
console.log(' 10. Run post-deploy hook (if configured)');
|
|
74
|
+
console.log(' 11. Release deployment lock');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
console.log(' Mode: Legacy Deployment (Non-Zero-Downtime)');
|
|
79
|
+
console.log('\n Deployment Steps:');
|
|
80
|
+
console.log(' 1. Rsync files to remote path');
|
|
81
|
+
console.log(' 2. Install dependencies');
|
|
82
|
+
if (config.app === 'backend') {
|
|
83
|
+
console.log(' 3. Reload PM2');
|
|
84
|
+
}
|
|
85
|
+
console.log(' 4. Run post-deploy hook (if configured)');
|
|
86
|
+
}
|
|
87
|
+
if (config.domain) {
|
|
88
|
+
console.log('\nCaddy Configuration:');
|
|
89
|
+
console.log(` - Reverse proxy: ${config.domain} -> localhost:${config.backend?.port ?? 3000}`);
|
|
90
|
+
}
|
|
91
|
+
console.log('\n===========================================');
|
|
92
|
+
console.log(' DRY RUN COMPLETE - No changes made');
|
|
93
|
+
console.log('===========================================\n');
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=deploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../../src/cli/commands/deploy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAGA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5G"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { runRemoteCommand } from '../runner.js';
|
|
2
|
+
import { ui } from '../ui.js';
|
|
3
|
+
export async function cmdDoctor(cwd, options) {
|
|
4
|
+
await runRemoteCommand(cwd, async ({ config, executor }) => {
|
|
5
|
+
ui.heading('ShipNode Doctor');
|
|
6
|
+
await checkLocal(config);
|
|
7
|
+
if (!options.security) {
|
|
8
|
+
await checkRemote(config, executor);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
await checkSecurity(config, executor);
|
|
12
|
+
}
|
|
13
|
+
}, { configPath: options.config });
|
|
14
|
+
}
|
|
15
|
+
function checkLocal(config) {
|
|
16
|
+
ui.info('Checking local configuration...');
|
|
17
|
+
const issues = [];
|
|
18
|
+
if (!config.ssh.host) {
|
|
19
|
+
issues.push('SSH host is not configured');
|
|
20
|
+
}
|
|
21
|
+
if (!config.ssh.user) {
|
|
22
|
+
issues.push('SSH user is not configured');
|
|
23
|
+
}
|
|
24
|
+
if (!config.remotePath) {
|
|
25
|
+
issues.push('Remote path is not configured');
|
|
26
|
+
}
|
|
27
|
+
if (config.app === 'backend' && !config.pm2?.name) {
|
|
28
|
+
issues.push('PM2 app name is not configured for backend app');
|
|
29
|
+
}
|
|
30
|
+
if (issues.length === 0) {
|
|
31
|
+
ui.success('Local configuration looks good');
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
for (const issue of issues) {
|
|
35
|
+
ui.warn(issue);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function checkRemote(config, executor) {
|
|
40
|
+
ui.info('Checking remote server...');
|
|
41
|
+
const checks = [
|
|
42
|
+
{ name: 'Node', cmd: 'node --version' },
|
|
43
|
+
{ name: 'PM2', cmd: 'pm2 --version' },
|
|
44
|
+
{ name: 'Caddy', cmd: 'caddy version' },
|
|
45
|
+
{ name: 'rsync', cmd: 'rsync --version' },
|
|
46
|
+
{ name: 'jq', cmd: 'jq --version' },
|
|
47
|
+
];
|
|
48
|
+
for (const check of checks) {
|
|
49
|
+
try {
|
|
50
|
+
const result = await executor.exec(check.cmd, { timeout: 5000 });
|
|
51
|
+
if (result.exitCode === 0) {
|
|
52
|
+
ui.success(`${check.name}: ${result.stdout.split('\n')[0]}`);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
ui.warn(`${check.name}: not installed`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
ui.warn(`${check.name}: not installed`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
ui.info('Checking deployment directory...');
|
|
63
|
+
const dirResult = await executor.exec(`test -d "${config.remotePath}" && echo "exists" || echo "missing"`);
|
|
64
|
+
if (dirResult.stdout === 'exists') {
|
|
65
|
+
ui.success(`Deployment directory exists: ${config.remotePath}`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
ui.warn(`Deployment directory does not exist. Run 'shipnode setup' first.`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function checkSecurity(config, executor) {
|
|
72
|
+
ui.info('Running security audit...');
|
|
73
|
+
const sshdResult = await executor.exec('sudo grep -E "^(PermitRootLogin|PasswordAuthentication|Port)" /etc/ssh/sshd_config 2>/dev/null || echo "not found"');
|
|
74
|
+
ui.info('SSH Configuration:');
|
|
75
|
+
console.log(` ${sshdResult.stdout.replace(/\n/g, '\n ')}`);
|
|
76
|
+
const firewallResult = await executor.exec('sudo ufw status 2>/dev/null || sudo iptables -L -n 2>/dev/null || echo "no firewall detected"');
|
|
77
|
+
ui.info('Firewall Status:');
|
|
78
|
+
console.log(` ${firewallResult.stdout.split('\n').slice(0, 5).join('\n ')}`);
|
|
79
|
+
const fail2banResult = await executor.exec('sudo fail2ban-client status 2>/dev/null || echo "fail2ban not installed"');
|
|
80
|
+
ui.info('Fail2ban:');
|
|
81
|
+
console.log(` ${fail2banResult.stdout.split('\n')[0]}`);
|
|
82
|
+
const permResult = await executor.exec(`stat -c "%a %U:%G" "${config.remotePath}/shared/.env" 2>/dev/null || echo "no .env found"`);
|
|
83
|
+
ui.info('Env file permissions:');
|
|
84
|
+
console.log(` ${permResult.stdout}`);
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eject.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/eject.ts"],"names":[],"mappings":"AA4CA,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAqC1F"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { writeFile, pathExists, mkdir } from 'fs-extra';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { ui } from '../ui.js';
|
|
4
|
+
const ECOSYSTEM_CONFIG = `// ShipNode PM2 Ecosystem — customize and commit this file
|
|
5
|
+
// Placeholders auto-replaced on deploy: {{APP_NAME}} {{BACKEND_PORT}} {{REMOTE_PATH}}
|
|
6
|
+
module.exports = {
|
|
7
|
+
apps: [{
|
|
8
|
+
name: '{{APP_NAME}}',
|
|
9
|
+
script: 'index.js',
|
|
10
|
+
instances: 1,
|
|
11
|
+
exec_mode: 'cluster',
|
|
12
|
+
max_memory_restart: '512M',
|
|
13
|
+
env: {
|
|
14
|
+
NODE_ENV: 'production',
|
|
15
|
+
PORT: '{{BACKEND_PORT}}',
|
|
16
|
+
},
|
|
17
|
+
}],
|
|
18
|
+
};
|
|
19
|
+
`;
|
|
20
|
+
const CADDYFILE_BACKEND = `# ShipNode Caddy — backend reverse proxy template
|
|
21
|
+
# Placeholder auto-replaced: {{DOMAIN}} {{BACKEND_PORT}}
|
|
22
|
+
{{DOMAIN}} {
|
|
23
|
+
reverse_proxy localhost:{{BACKEND_PORT}}
|
|
24
|
+
encode gzip
|
|
25
|
+
header {
|
|
26
|
+
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
|
27
|
+
X-Content-Type-Options "nosniff"
|
|
28
|
+
X-Frame-Options "DENY"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
const CADDYFILE_FRONTEND = `# ShipNode Caddy — frontend static files template
|
|
33
|
+
# Placeholder auto-replaced: {{DOMAIN}} {{REMOTE_PATH}}
|
|
34
|
+
{{DOMAIN}} {
|
|
35
|
+
root * {{REMOTE_PATH}}/current
|
|
36
|
+
file_server
|
|
37
|
+
encode gzip
|
|
38
|
+
try_files {path} /index.html
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
export async function cmdEject(cwd, target) {
|
|
42
|
+
const templatesDir = resolve(cwd, '.shipnode', 'templates');
|
|
43
|
+
await mkdir(templatesDir, { recursive: true });
|
|
44
|
+
const ejected = [];
|
|
45
|
+
const skipped = [];
|
|
46
|
+
async function writeTemplate(filename, content) {
|
|
47
|
+
const filePath = resolve(templatesDir, filename);
|
|
48
|
+
if (await pathExists(filePath)) {
|
|
49
|
+
ui.warn(`Skipping ${filename} — file already exists`);
|
|
50
|
+
skipped.push(filename);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
await writeFile(filePath, content, 'utf8');
|
|
54
|
+
ejected.push(filename);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (target === 'pm2' || target === 'all') {
|
|
58
|
+
await writeTemplate('ecosystem.config.cjs', ECOSYSTEM_CONFIG);
|
|
59
|
+
}
|
|
60
|
+
if (target === 'caddy' || target === 'all') {
|
|
61
|
+
await writeTemplate('Caddyfile.backend', CADDYFILE_BACKEND);
|
|
62
|
+
await writeTemplate('Caddyfile.frontend', CADDYFILE_FRONTEND);
|
|
63
|
+
}
|
|
64
|
+
if (ejected.length > 0) {
|
|
65
|
+
ui.success(`Ejected templates to .shipnode/templates/:`);
|
|
66
|
+
for (const f of ejected) {
|
|
67
|
+
ui.info(` ${f}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (skipped.length > 0) {
|
|
71
|
+
ui.info(`Skipped (already exist): ${skipped.join(', ')}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=eject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eject.js","sourceRoot":"","sources":["../../../src/cli/commands/eject.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAE9B,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;CAexB,CAAC;AAEF,MAAM,iBAAiB,GAAG;;;;;;;;;;;CAWzB,CAAC;AAEF,MAAM,kBAAkB,GAAG;;;;;;;;CAQ1B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW,EAAE,MAA+B;IACzE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;IAC5D,MAAM,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;QAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QACjD,IAAI,MAAM,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,EAAE,CAAC,IAAI,CAAC,YAAY,QAAQ,wBAAwB,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACzC,MAAM,aAAa,CAAC,sBAAsB,EAAE,gBAAgB,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QAC3C,MAAM,aAAa,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,CAAC;QAC5D,MAAM,aAAa,CAAC,oBAAoB,EAAE,kBAAkB,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,EAAE,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;QACzD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,EAAE,CAAC,IAAI,CAAC,4BAA4B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/env.ts"],"names":[],"mappings":"AAKA,wBAAsB,MAAM,CAC1B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CA2Df"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readFile, pathExists } from 'fs-extra';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { runRemoteCommand } from '../runner.js';
|
|
4
|
+
import { ui } from '../ui.js';
|
|
5
|
+
export async function cmdEnv(cwd, options) {
|
|
6
|
+
await runRemoteCommand(cwd, async ({ config, executor }) => {
|
|
7
|
+
const localEnvPath = resolve(cwd, config.envFile);
|
|
8
|
+
if (!(await pathExists(localEnvPath))) {
|
|
9
|
+
throw new Error(`Environment file not found: ${config.envFile}`);
|
|
10
|
+
}
|
|
11
|
+
ui.info(`Uploading ${config.envFile} to server...`);
|
|
12
|
+
const content = await readFile(localEnvPath);
|
|
13
|
+
const b64 = content.toString('base64');
|
|
14
|
+
if (config.zeroDowntime) {
|
|
15
|
+
const sharedEnv = `${config.remotePath}/shared/.env`;
|
|
16
|
+
await executor.exec(`mkdir -p "${config.remotePath}/shared"`);
|
|
17
|
+
await executor.exec(`echo "${b64}" | base64 -d > "${sharedEnv}"`);
|
|
18
|
+
await executor.exec(`chmod 600 "${sharedEnv}"`);
|
|
19
|
+
ui.success(`Uploaded to ${sharedEnv}`);
|
|
20
|
+
// Link into current release if it exists
|
|
21
|
+
const linkResult = await executor.exec(`if [ -d "${config.remotePath}/current" ]; then ` +
|
|
22
|
+
`ln -sfn "${sharedEnv}" "${config.remotePath}/current/.env" && echo "linked"; ` +
|
|
23
|
+
`fi`);
|
|
24
|
+
if (linkResult.stdout === 'linked') {
|
|
25
|
+
ui.success('Linked shared .env to current release');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const targetEnv = `${config.remotePath}/.env`;
|
|
30
|
+
await executor.exec(`mkdir -p "${config.remotePath}"`);
|
|
31
|
+
await executor.exec(`echo "${b64}" | base64 -d > "${targetEnv}"`);
|
|
32
|
+
await executor.exec(`chmod 600 "${targetEnv}"`);
|
|
33
|
+
ui.success(`Uploaded to ${targetEnv}`);
|
|
34
|
+
}
|
|
35
|
+
if (config.app === 'backend' && config.pm2?.name) {
|
|
36
|
+
const nodeVersion = config.nodeVersion === 'lts' ? '24' : config.nodeVersion;
|
|
37
|
+
const mise = `export PATH="$HOME/.local/bin:$HOME/.local/share/mise/shims:$PATH"`;
|
|
38
|
+
const checkResult = await executor.exec(`${mise}; mise exec node@${nodeVersion} -- pm2 describe ${config.pm2.name} 2>/dev/null && echo "running" || echo "stopped"`);
|
|
39
|
+
if (checkResult.stdout.includes('running')) {
|
|
40
|
+
ui.info('Restarting app to reload environment variables...');
|
|
41
|
+
await executor.exec(`${mise}; mise exec node@${nodeVersion} -- pm2 reload ${config.pm2.name} --update-env`);
|
|
42
|
+
ui.success('App restarted with new environment variables');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
ui.warn('App not running. Variables will be loaded on next deploy.');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}, { configPath: options.config });
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../../src/cli/commands/env.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harden.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/harden.ts"],"names":[],"mappings":"AAMA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8IxF"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { confirm } from '../prompt.js';
|
|
2
|
+
import { runRemoteCommand } from '../runner.js';
|
|
3
|
+
import { ui } from '../ui.js';
|
|
4
|
+
const SUDO = 'SUDO=""; [ "$EUID" -ne 0 ] && SUDO="sudo"';
|
|
5
|
+
export async function cmdHarden(cwd, options) {
|
|
6
|
+
await runRemoteCommand(cwd, async ({ executor }) => {
|
|
7
|
+
const changes = [];
|
|
8
|
+
// ── 1. SSH service check ──────────────────────────────────────────────
|
|
9
|
+
ui.heading('SSH Hardening');
|
|
10
|
+
const sshActiveResult = await executor.exec(`systemctl is-active ssh 2>/dev/null || systemctl is-active sshd 2>/dev/null && echo "active" || echo "inactive"`);
|
|
11
|
+
const sshActive = sshActiveResult.stdout.includes('active');
|
|
12
|
+
ui.info(`SSH service: ${sshActive ? 'active' : 'inactive'}`);
|
|
13
|
+
const sshdResult = await executor.exec(`grep -E "^(PermitRootLogin|PasswordAuthentication)" /etc/ssh/sshd_config 2>/dev/null || echo "defaults"`);
|
|
14
|
+
ui.info(`Current SSH config:\n ${sshdResult.stdout.split('\n').join('\n ')}`);
|
|
15
|
+
const hardenSsh = await confirm('Harden SSH?');
|
|
16
|
+
if (hardenSsh) {
|
|
17
|
+
// Check for sudo users before disabling root
|
|
18
|
+
const sudoUsersResult = await executor.exec(`getent group sudo 2>/dev/null | cut -d: -f4 | tr ',' '\\n' | grep -v '^$'`);
|
|
19
|
+
const sudoUsers = sudoUsersResult.stdout.trim();
|
|
20
|
+
if (sudoUsers) {
|
|
21
|
+
ui.info(`Sudo users found: ${sudoUsers.split('\n').join(', ')}`);
|
|
22
|
+
const disableRoot = await confirm('Disable root login?');
|
|
23
|
+
if (disableRoot) {
|
|
24
|
+
await executor.exec(`${SUDO}; $SUDO sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config`);
|
|
25
|
+
await executor.exec(`${SUDO}; $SUDO systemctl restart ssh 2>/dev/null || $SUDO systemctl restart sshd 2>/dev/null || true`);
|
|
26
|
+
ui.success('Root login disabled');
|
|
27
|
+
changes.push('SSH: PermitRootLogin set to no');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
ui.warn('No sudo users found — skipping root login disable (would lock you out).');
|
|
32
|
+
}
|
|
33
|
+
const disablePassAuth = await confirm('Disable password authentication (keys only)?');
|
|
34
|
+
if (disablePassAuth) {
|
|
35
|
+
await executor.exec(`${SUDO}; $SUDO sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config`);
|
|
36
|
+
await executor.exec(`${SUDO}; $SUDO systemctl restart ssh 2>/dev/null || $SUDO systemctl restart sshd 2>/dev/null || true`);
|
|
37
|
+
ui.success('Password authentication disabled');
|
|
38
|
+
changes.push('SSH: PasswordAuthentication set to no');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// ── 2. UFW firewall ───────────────────────────────────────────────────
|
|
42
|
+
ui.heading('Firewall (UFW)');
|
|
43
|
+
const ufwResult = await executor.exec(`command -v ufw &>/dev/null && ufw status || echo "NOT_INSTALLED"`);
|
|
44
|
+
if (ufwResult.stdout.includes('NOT_INSTALLED')) {
|
|
45
|
+
ui.warn('UFW is not installed.');
|
|
46
|
+
const installUfw = await confirm('Install UFW?');
|
|
47
|
+
if (installUfw) {
|
|
48
|
+
await executor.exec(`${SUDO}; $SUDO apt-get install -y ufw`);
|
|
49
|
+
ui.success('UFW installed');
|
|
50
|
+
changes.push('UFW: installed');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
ui.info(`UFW status:\n ${ufwResult.stdout.split('\n').slice(0, 3).join('\n ')}`);
|
|
55
|
+
}
|
|
56
|
+
const configureUfw = await confirm('Configure UFW (allow SSH/80/443, deny all else, enable)?');
|
|
57
|
+
if (configureUfw) {
|
|
58
|
+
await executor.exec(`${SUDO}; $SUDO ufw default deny incoming`);
|
|
59
|
+
await executor.exec(`${SUDO}; $SUDO ufw default allow outgoing`);
|
|
60
|
+
await executor.exec(`${SUDO}; $SUDO ufw allow ssh`);
|
|
61
|
+
await executor.exec(`${SUDO}; $SUDO ufw allow 80/tcp`);
|
|
62
|
+
await executor.exec(`${SUDO}; $SUDO ufw allow 443/tcp`);
|
|
63
|
+
await executor.exec(`${SUDO}; $SUDO ufw --force enable`);
|
|
64
|
+
ui.success('UFW configured and enabled');
|
|
65
|
+
changes.push('UFW: configured (SSH, 80, 443 allowed; deny incoming by default)');
|
|
66
|
+
}
|
|
67
|
+
// ── 3. Fail2ban ───────────────────────────────────────────────────────
|
|
68
|
+
ui.heading('Fail2ban');
|
|
69
|
+
const fail2banResult = await executor.exec(`command -v fail2ban-server &>/dev/null && systemctl is-active fail2ban && echo "ACTIVE" || echo "NOT_ACTIVE"`);
|
|
70
|
+
if (!fail2banResult.stdout.includes('ACTIVE')) {
|
|
71
|
+
ui.warn('Fail2ban is not active.');
|
|
72
|
+
const installFail2ban = await confirm('Install and configure fail2ban?');
|
|
73
|
+
if (installFail2ban) {
|
|
74
|
+
await executor.exec(`${SUDO}; $SUDO apt-get install -y fail2ban`);
|
|
75
|
+
const jailConfig = [
|
|
76
|
+
'[DEFAULT]',
|
|
77
|
+
'maxretry = 5',
|
|
78
|
+
'findtime = 600',
|
|
79
|
+
'bantime = 3600',
|
|
80
|
+
'',
|
|
81
|
+
'[sshd]',
|
|
82
|
+
'enabled = true',
|
|
83
|
+
'port = ssh',
|
|
84
|
+
'filter = sshd',
|
|
85
|
+
'logpath = /var/log/auth.log',
|
|
86
|
+
'maxretry = 5',
|
|
87
|
+
].join('\\n');
|
|
88
|
+
await executor.exec(`${SUDO}; printf '${jailConfig}' | $SUDO tee /etc/fail2ban/jail.local > /dev/null`);
|
|
89
|
+
await executor.exec(`${SUDO}; $SUDO systemctl enable fail2ban && $SUDO systemctl restart fail2ban`);
|
|
90
|
+
ui.success('Fail2ban installed and configured');
|
|
91
|
+
changes.push('Fail2ban: installed, configured (maxretry=5, bantime=3600s), sshd jail enabled');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
ui.success('Fail2ban is already active');
|
|
96
|
+
}
|
|
97
|
+
// ── Summary ───────────────────────────────────────────────────────────
|
|
98
|
+
ui.heading('Hardening Summary');
|
|
99
|
+
if (changes.length === 0) {
|
|
100
|
+
ui.info('No changes were made.');
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
for (const change of changes) {
|
|
104
|
+
ui.success(change);
|
|
105
|
+
}
|
|
106
|
+
ui.info(`${changes.length} change(s) applied.`);
|
|
107
|
+
}
|
|
108
|
+
}, { configPath: options.config });
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=harden.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harden.js","sourceRoot":"","sources":["../../../src/cli/commands/harden.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,OAAO,IAAI,IAAI,CAgG9B"}
|