@factiii/stack 0.1.203 → 0.7.2
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/README.md +56 -364
- package/dist/plugins/addons/auth/index.d.ts.map +1 -1
- package/dist/plugins/addons/auth/index.js +24 -5
- package/dist/plugins/addons/auth/index.js.map +1 -1
- package/dist/plugins/addons/auth/scanfix/secrets.d.ts +3 -0
- package/dist/plugins/addons/auth/scanfix/secrets.d.ts.map +1 -1
- package/dist/plugins/addons/auth/scanfix/secrets.js +54 -19
- package/dist/plugins/addons/auth/scanfix/secrets.js.map +1 -1
- package/dist/plugins/addons/auth/scanfix/validate.d.ts +3 -0
- package/dist/plugins/addons/auth/scanfix/validate.d.ts.map +1 -1
- package/dist/plugins/addons/auth/scanfix/validate.js +37 -18
- package/dist/plugins/addons/auth/scanfix/validate.js.map +1 -1
- package/dist/utils/ssh-helper.d.ts.map +1 -1
- package/dist/utils/ssh-helper.js +89 -41
- package/dist/utils/ssh-helper.js.map +1 -1
- package/package.json +6 -13
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* Manages authentication secrets in Ansible Vault:
|
|
6
6
|
* - JWT_SECRET: auto-generated 256-bit random key
|
|
7
7
|
* - OAuth keys: prompted from user (Google, Apple)
|
|
8
|
+
*
|
|
9
|
+
* Secret names are sourced from @factiii/auth's stack-plugin contract
|
|
10
|
+
* to avoid hardcoded strings drifting out of sync.
|
|
8
11
|
*/
|
|
9
12
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
13
|
if (k2 === undefined) k2 = k;
|
|
@@ -43,6 +46,34 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
43
46
|
exports.secretsFixes = void 0;
|
|
44
47
|
const crypto = __importStar(require("crypto"));
|
|
45
48
|
const config_helpers_js_1 = require("../../../../utils/config-helpers.js");
|
|
49
|
+
/**
|
|
50
|
+
* Load secret name constants from @factiii/auth's stack-plugin contract.
|
|
51
|
+
* Falls back to hardcoded values if auth is not installed.
|
|
52
|
+
*/
|
|
53
|
+
function loadAuthSecretNames() {
|
|
54
|
+
try {
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
56
|
+
const contract = require('@factiii/auth/stack-plugin');
|
|
57
|
+
return {
|
|
58
|
+
requiredEnvVars: [...contract.AUTH_REQUIRED_ENV_VARS],
|
|
59
|
+
oauthEnvVars: {
|
|
60
|
+
google: [...contract.AUTH_OAUTH_ENV_VARS.google],
|
|
61
|
+
apple: [...contract.AUTH_OAUTH_ENV_VARS.apple],
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Fallback if @factiii/auth not installed
|
|
67
|
+
return {
|
|
68
|
+
requiredEnvVars: ['JWT_SECRET'],
|
|
69
|
+
oauthEnvVars: {
|
|
70
|
+
google: ['GOOGLE_CLIENT_ID', 'GOOGLE_CLIENT_SECRET'],
|
|
71
|
+
apple: ['APPLE_CLIENT_ID'],
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const authSecrets = loadAuthSecretNames();
|
|
46
77
|
/**
|
|
47
78
|
* Get auth config from FactiiiConfig (handles undefined/null)
|
|
48
79
|
*/
|
|
@@ -79,16 +110,20 @@ async function getVault(config, rootDir) {
|
|
|
79
110
|
rootDir,
|
|
80
111
|
});
|
|
81
112
|
}
|
|
113
|
+
const JWT_SECRET = authSecrets.requiredEnvVars[0] ?? 'JWT_SECRET';
|
|
114
|
+
const GOOGLE_CLIENT_ID = authSecrets.oauthEnvVars.google[0] ?? 'GOOGLE_CLIENT_ID';
|
|
115
|
+
const GOOGLE_CLIENT_SECRET = authSecrets.oauthEnvVars.google[1] ?? 'GOOGLE_CLIENT_SECRET';
|
|
116
|
+
const APPLE_CLIENT_ID = authSecrets.oauthEnvVars.apple[0] ?? 'APPLE_CLIENT_ID';
|
|
82
117
|
exports.secretsFixes = [
|
|
83
118
|
{
|
|
84
119
|
id: 'auth-jwt-secret-missing',
|
|
85
120
|
stage: 'secrets',
|
|
86
121
|
severity: 'critical',
|
|
87
|
-
description:
|
|
122
|
+
description: JWT_SECRET + ' not found in Ansible Vault (required for auth)',
|
|
88
123
|
scan: async (config, rootDir) => {
|
|
89
124
|
try {
|
|
90
125
|
const vault = await getVault(config, rootDir);
|
|
91
|
-
const secret = await vault.getSecret(
|
|
126
|
+
const secret = await vault.getSecret(JWT_SECRET);
|
|
92
127
|
return !secret;
|
|
93
128
|
}
|
|
94
129
|
catch {
|
|
@@ -100,13 +135,13 @@ exports.secretsFixes = [
|
|
|
100
135
|
const vault = await getVault(config, rootDir);
|
|
101
136
|
// Auto-generate a cryptographically secure 256-bit secret
|
|
102
137
|
const jwtSecret = crypto.randomBytes(32).toString('hex');
|
|
103
|
-
const result = await vault.setSecret(
|
|
138
|
+
const result = await vault.setSecret(JWT_SECRET, jwtSecret);
|
|
104
139
|
if (result.success) {
|
|
105
|
-
console.log(' [OK] Generated and stored JWT_SECRET in Ansible Vault');
|
|
140
|
+
console.log(' [OK] Generated and stored ' + JWT_SECRET + ' in Ansible Vault');
|
|
106
141
|
console.log(' (256-bit random key, no manual input needed)');
|
|
107
142
|
return true;
|
|
108
143
|
}
|
|
109
|
-
console.log(' Failed to store JWT_SECRET in vault');
|
|
144
|
+
console.log(' Failed to store ' + JWT_SECRET + ' in vault');
|
|
110
145
|
return false;
|
|
111
146
|
}
|
|
112
147
|
catch (e) {
|
|
@@ -114,19 +149,19 @@ exports.secretsFixes = [
|
|
|
114
149
|
return false;
|
|
115
150
|
}
|
|
116
151
|
},
|
|
117
|
-
manualFix: 'Generate and store JWT secret: npx stack deploy --secrets set JWT_SECRET
|
|
152
|
+
manualFix: 'Generate and store JWT secret: npx stack deploy --secrets set ' + JWT_SECRET,
|
|
118
153
|
},
|
|
119
154
|
{
|
|
120
155
|
id: 'auth-oauth-google-missing',
|
|
121
156
|
stage: 'secrets',
|
|
122
157
|
severity: 'warning',
|
|
123
|
-
description: 'Google OAuth credentials not in vault (GOOGLE_CLIENT_ID)',
|
|
158
|
+
description: 'Google OAuth credentials not in vault (' + GOOGLE_CLIENT_ID + ')',
|
|
124
159
|
scan: async (config, rootDir) => {
|
|
125
160
|
if (!isOAuthEnabled(config, 'google'))
|
|
126
161
|
return false;
|
|
127
162
|
try {
|
|
128
163
|
const vault = await getVault(config, rootDir);
|
|
129
|
-
const clientId = await vault.getSecret(
|
|
164
|
+
const clientId = await vault.getSecret(GOOGLE_CLIENT_ID);
|
|
130
165
|
return !clientId;
|
|
131
166
|
}
|
|
132
167
|
catch {
|
|
@@ -141,12 +176,12 @@ exports.secretsFixes = [
|
|
|
141
176
|
console.log(' Google OAuth Setup');
|
|
142
177
|
console.log(' Get credentials from: https://console.cloud.google.com/apis/credentials');
|
|
143
178
|
console.log('');
|
|
144
|
-
const clientId = await promptForSecret(
|
|
145
|
-
const r1 = await vault.setSecret(
|
|
179
|
+
const clientId = await promptForSecret(GOOGLE_CLIENT_ID, config);
|
|
180
|
+
const r1 = await vault.setSecret(GOOGLE_CLIENT_ID, clientId);
|
|
146
181
|
if (!r1.success)
|
|
147
182
|
return false;
|
|
148
|
-
const clientSecret = await promptForSecret(
|
|
149
|
-
const r2 = await vault.setSecret(
|
|
183
|
+
const clientSecret = await promptForSecret(GOOGLE_CLIENT_SECRET, config);
|
|
184
|
+
const r2 = await vault.setSecret(GOOGLE_CLIENT_SECRET, clientSecret);
|
|
150
185
|
if (!r2.success)
|
|
151
186
|
return false;
|
|
152
187
|
console.log(' [OK] Stored Google OAuth credentials in vault');
|
|
@@ -157,21 +192,21 @@ exports.secretsFixes = [
|
|
|
157
192
|
}
|
|
158
193
|
},
|
|
159
194
|
manualFix: 'Store Google OAuth credentials:\n' +
|
|
160
|
-
' npx stack deploy --secrets set GOOGLE_CLIENT_ID\n' +
|
|
161
|
-
' npx stack deploy --secrets set GOOGLE_CLIENT_SECRET\n' +
|
|
195
|
+
' npx stack deploy --secrets set ' + GOOGLE_CLIENT_ID + '\n' +
|
|
196
|
+
' npx stack deploy --secrets set ' + GOOGLE_CLIENT_SECRET + '\n' +
|
|
162
197
|
' Get from: https://console.cloud.google.com/apis/credentials',
|
|
163
198
|
},
|
|
164
199
|
{
|
|
165
200
|
id: 'auth-oauth-apple-missing',
|
|
166
201
|
stage: 'secrets',
|
|
167
202
|
severity: 'warning',
|
|
168
|
-
description: 'Apple OAuth credentials not in vault (APPLE_CLIENT_ID)',
|
|
203
|
+
description: 'Apple OAuth credentials not in vault (' + APPLE_CLIENT_ID + ')',
|
|
169
204
|
scan: async (config, rootDir) => {
|
|
170
205
|
if (!isOAuthEnabled(config, 'apple'))
|
|
171
206
|
return false;
|
|
172
207
|
try {
|
|
173
208
|
const vault = await getVault(config, rootDir);
|
|
174
|
-
const clientId = await vault.getSecret(
|
|
209
|
+
const clientId = await vault.getSecret(APPLE_CLIENT_ID);
|
|
175
210
|
return !clientId;
|
|
176
211
|
}
|
|
177
212
|
catch {
|
|
@@ -186,8 +221,8 @@ exports.secretsFixes = [
|
|
|
186
221
|
console.log(' Apple OAuth Setup');
|
|
187
222
|
console.log(' Get credentials from: https://developer.apple.com/account/resources/identifiers');
|
|
188
223
|
console.log('');
|
|
189
|
-
const clientId = await promptForSecret(
|
|
190
|
-
const r1 = await vault.setSecret(
|
|
224
|
+
const clientId = await promptForSecret(APPLE_CLIENT_ID, config);
|
|
225
|
+
const r1 = await vault.setSecret(APPLE_CLIENT_ID, clientId);
|
|
191
226
|
if (!r1.success)
|
|
192
227
|
return false;
|
|
193
228
|
console.log(' [OK] Stored Apple OAuth credentials in vault');
|
|
@@ -198,7 +233,7 @@ exports.secretsFixes = [
|
|
|
198
233
|
}
|
|
199
234
|
},
|
|
200
235
|
manualFix: 'Store Apple OAuth credentials:\n' +
|
|
201
|
-
' npx stack deploy --secrets set APPLE_CLIENT_ID\n' +
|
|
236
|
+
' npx stack deploy --secrets set ' + APPLE_CLIENT_ID + '\n' +
|
|
202
237
|
' Get from: https://developer.apple.com/account/resources/identifiers',
|
|
203
238
|
},
|
|
204
239
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../../../../src/plugins/addons/auth/scanfix/secrets.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../../../../src/plugins/addons/auth/scanfix/secrets.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Validates that auth environment variables are properly
|
|
5
5
|
* configured on staging and production servers.
|
|
6
|
+
*
|
|
7
|
+
* Secret names are sourced from @factiii/auth's stack-plugin contract
|
|
8
|
+
* to avoid hardcoded strings drifting out of sync.
|
|
6
9
|
*/
|
|
7
10
|
import type { Fix } from '../../../../types/index.js';
|
|
8
11
|
export declare const validateFixes: Fix[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/addons/auth/scanfix/validate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/addons/auth/scanfix/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAiB,GAAG,EAAE,MAAM,4BAA4B,CAAC;AAmCrE,eAAO,MAAM,aAAa,EAAE,GAAG,EAiG9B,CAAC"}
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Validates that auth environment variables are properly
|
|
6
6
|
* configured on staging and production servers.
|
|
7
|
+
*
|
|
8
|
+
* Secret names are sourced from @factiii/auth's stack-plugin contract
|
|
9
|
+
* to avoid hardcoded strings drifting out of sync.
|
|
7
10
|
*/
|
|
8
11
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
12
|
if (k2 === undefined) k2 = k;
|
|
@@ -43,6 +46,22 @@ exports.validateFixes = void 0;
|
|
|
43
46
|
const fs = __importStar(require("fs"));
|
|
44
47
|
const path = __importStar(require("path"));
|
|
45
48
|
const config_helpers_js_1 = require("../../../../utils/config-helpers.js");
|
|
49
|
+
/**
|
|
50
|
+
* Load required env var names from @factiii/auth's stack-plugin contract.
|
|
51
|
+
* Falls back to hardcoded values if auth is not installed.
|
|
52
|
+
*/
|
|
53
|
+
function loadRequiredEnvVars() {
|
|
54
|
+
try {
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
56
|
+
const contract = require('@factiii/auth/stack-plugin');
|
|
57
|
+
return [...contract.AUTH_REQUIRED_ENV_VARS];
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return ['JWT_SECRET'];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const requiredEnvVars = loadRequiredEnvVars();
|
|
64
|
+
const JWT_SECRET = requiredEnvVars[0] ?? 'JWT_SECRET';
|
|
46
65
|
/**
|
|
47
66
|
* Check if an env file has a variable set (non-empty, non-EXAMPLE)
|
|
48
67
|
*/
|
|
@@ -62,10 +81,10 @@ exports.validateFixes = [
|
|
|
62
81
|
id: 'auth-env-jwt-staging',
|
|
63
82
|
stage: 'staging',
|
|
64
83
|
severity: 'critical',
|
|
65
|
-
description:
|
|
84
|
+
description: JWT_SECRET + ' not set in .env.staging (auth will not work)',
|
|
66
85
|
scan: async (_config, rootDir) => {
|
|
67
86
|
const envPath = path.join(rootDir, '.env.staging');
|
|
68
|
-
return !envFileHasVar(envPath,
|
|
87
|
+
return !envFileHasVar(envPath, JWT_SECRET);
|
|
69
88
|
},
|
|
70
89
|
fix: async (config, rootDir) => {
|
|
71
90
|
try {
|
|
@@ -75,9 +94,9 @@ exports.validateFixes = [
|
|
|
75
94
|
vault_password_file: config.ansible?.vault_password_file,
|
|
76
95
|
rootDir,
|
|
77
96
|
});
|
|
78
|
-
const jwtSecret = await vault.getSecret(
|
|
97
|
+
const jwtSecret = await vault.getSecret(JWT_SECRET);
|
|
79
98
|
if (!jwtSecret) {
|
|
80
|
-
console.log(' JWT_SECRET not in vault — run: npx stack fix --secrets');
|
|
99
|
+
console.log(' ' + JWT_SECRET + ' not in vault — run: npx stack fix --secrets');
|
|
81
100
|
return false;
|
|
82
101
|
}
|
|
83
102
|
// Append to .env.staging
|
|
@@ -86,15 +105,15 @@ exports.validateFixes = [
|
|
|
86
105
|
if (fs.existsSync(envPath)) {
|
|
87
106
|
content = fs.readFileSync(envPath, 'utf8');
|
|
88
107
|
}
|
|
89
|
-
if (content.includes('
|
|
108
|
+
if (content.includes(JWT_SECRET + '=')) {
|
|
90
109
|
// Replace existing (empty or EXAMPLE) value
|
|
91
|
-
content = content.replace(
|
|
110
|
+
content = content.replace(new RegExp('^' + JWT_SECRET + '\\s*=.*$', 'm'), JWT_SECRET + '=' + jwtSecret);
|
|
92
111
|
}
|
|
93
112
|
else {
|
|
94
|
-
content = content.trimEnd() + '\
|
|
113
|
+
content = content.trimEnd() + '\n' + JWT_SECRET + '=' + jwtSecret + '\n';
|
|
95
114
|
}
|
|
96
115
|
fs.writeFileSync(envPath, content, 'utf8');
|
|
97
|
-
console.log(' [OK] Set JWT_SECRET in .env.staging from vault');
|
|
116
|
+
console.log(' [OK] Set ' + JWT_SECRET + ' in .env.staging from vault');
|
|
98
117
|
return true;
|
|
99
118
|
}
|
|
100
119
|
catch (e) {
|
|
@@ -102,16 +121,16 @@ exports.validateFixes = [
|
|
|
102
121
|
return false;
|
|
103
122
|
}
|
|
104
123
|
},
|
|
105
|
-
manualFix: 'Add JWT_SECRET to .env.staging or run: npx stack fix --secrets && npx stack fix --staging',
|
|
124
|
+
manualFix: 'Add ' + JWT_SECRET + ' to .env.staging or run: npx stack fix --secrets && npx stack fix --staging',
|
|
106
125
|
},
|
|
107
126
|
{
|
|
108
127
|
id: 'auth-env-jwt-prod',
|
|
109
128
|
stage: 'prod',
|
|
110
129
|
severity: 'critical',
|
|
111
|
-
description:
|
|
130
|
+
description: JWT_SECRET + ' not set in .env.prod (auth will not work)',
|
|
112
131
|
scan: async (_config, rootDir) => {
|
|
113
132
|
const envPath = path.join(rootDir, '.env.prod');
|
|
114
|
-
return !envFileHasVar(envPath,
|
|
133
|
+
return !envFileHasVar(envPath, JWT_SECRET);
|
|
115
134
|
},
|
|
116
135
|
fix: async (config, rootDir) => {
|
|
117
136
|
try {
|
|
@@ -121,9 +140,9 @@ exports.validateFixes = [
|
|
|
121
140
|
vault_password_file: config.ansible?.vault_password_file,
|
|
122
141
|
rootDir,
|
|
123
142
|
});
|
|
124
|
-
const jwtSecret = await vault.getSecret(
|
|
143
|
+
const jwtSecret = await vault.getSecret(JWT_SECRET);
|
|
125
144
|
if (!jwtSecret) {
|
|
126
|
-
console.log(' JWT_SECRET not in vault — run: npx stack fix --secrets');
|
|
145
|
+
console.log(' ' + JWT_SECRET + ' not in vault — run: npx stack fix --secrets');
|
|
127
146
|
return false;
|
|
128
147
|
}
|
|
129
148
|
// Append to .env.prod
|
|
@@ -132,14 +151,14 @@ exports.validateFixes = [
|
|
|
132
151
|
if (fs.existsSync(envPath)) {
|
|
133
152
|
content = fs.readFileSync(envPath, 'utf8');
|
|
134
153
|
}
|
|
135
|
-
if (content.includes('
|
|
136
|
-
content = content.replace(
|
|
154
|
+
if (content.includes(JWT_SECRET + '=')) {
|
|
155
|
+
content = content.replace(new RegExp('^' + JWT_SECRET + '\\s*=.*$', 'm'), JWT_SECRET + '=' + jwtSecret);
|
|
137
156
|
}
|
|
138
157
|
else {
|
|
139
|
-
content = content.trimEnd() + '\
|
|
158
|
+
content = content.trimEnd() + '\n' + JWT_SECRET + '=' + jwtSecret + '\n';
|
|
140
159
|
}
|
|
141
160
|
fs.writeFileSync(envPath, content, 'utf8');
|
|
142
|
-
console.log(' [OK] Set JWT_SECRET in .env.prod from vault');
|
|
161
|
+
console.log(' [OK] Set ' + JWT_SECRET + ' in .env.prod from vault');
|
|
143
162
|
return true;
|
|
144
163
|
}
|
|
145
164
|
catch (e) {
|
|
@@ -147,7 +166,7 @@ exports.validateFixes = [
|
|
|
147
166
|
return false;
|
|
148
167
|
}
|
|
149
168
|
},
|
|
150
|
-
manualFix: 'Add JWT_SECRET to .env.prod or run: npx stack fix --secrets && npx stack fix --prod',
|
|
169
|
+
manualFix: 'Add ' + JWT_SECRET + ' to .env.prod or run: npx stack fix --secrets && npx stack fix --prod',
|
|
151
170
|
},
|
|
152
171
|
];
|
|
153
172
|
//# sourceMappingURL=validate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../../src/plugins/addons/auth/scanfix/validate.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../../src/plugins/addons/auth/scanfix/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssh-helper.d.ts","sourceRoot":"","sources":["../../src/utils/ssh-helper.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAKjF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAU5E;AA+BD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAS9E;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4BlF;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,aAAa,GACpB,iBAAiB,GAAG,IAAI,CAc1B;
|
|
1
|
+
{"version":3,"file":"ssh-helper.d.ts","sourceRoot":"","sources":["../../src/utils/ssh-helper.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAKjF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAU5E;AA+BD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAS9E;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4BlF;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,aAAa,GACpB,iBAAiB,GAAG,IAAI,CAc1B;AAwbD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA+2B/D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAC3B,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,KAAK,EACb,MAAM,CAAC,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAqMjB"}
|
package/dist/utils/ssh-helper.js
CHANGED
|
@@ -354,14 +354,15 @@ async function autoSetupSshKey(stage, host, user, config, rootDir) {
|
|
|
354
354
|
return null;
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
|
-
// Fix remote permissions
|
|
357
|
+
// Fix remote permissions using the key we just copied (avoid extra password prompt)
|
|
358
358
|
try {
|
|
359
359
|
(0, child_process_1.spawnSync)('ssh', [
|
|
360
|
+
'-i', keyPath,
|
|
360
361
|
'-o', 'StrictHostKeyChecking=no',
|
|
361
362
|
'-o', 'ConnectTimeout=5',
|
|
362
363
|
user + '@' + host,
|
|
363
364
|
'chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys',
|
|
364
|
-
], { stdio: '
|
|
365
|
+
], { encoding: 'utf8', stdio: 'pipe', timeout: 15000 });
|
|
365
366
|
}
|
|
366
367
|
catch { /* best effort */ }
|
|
367
368
|
// Verify key auth
|
|
@@ -426,6 +427,11 @@ async function promptAndValidatePassword(stage, host, user, config, rootDir) {
|
|
|
426
427
|
stdio: 'pipe',
|
|
427
428
|
timeout: 15000,
|
|
428
429
|
});
|
|
430
|
+
if (testResult.status === 5) {
|
|
431
|
+
// sshpass exit code 5 = wrong password
|
|
432
|
+
console.log(' [!] Incorrect password.');
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
429
435
|
if (testResult.status !== 0) {
|
|
430
436
|
// sshpass failed — likely keyboard-interactive auth (Mac servers)
|
|
431
437
|
// Fall back to auto SSH key setup so we never need sshpass again
|
|
@@ -513,16 +519,18 @@ async function promptAndValidatePassword(stage, host, user, config, rootDir) {
|
|
|
513
519
|
// Store password in vault anyway so sshExec can try it
|
|
514
520
|
return await storePasswordAndReturn(password, stage, config, rootDir);
|
|
515
521
|
}
|
|
516
|
-
// Step 2.5: Fix remote permissions (
|
|
522
|
+
// Step 2.5: Fix remote permissions using the key we just copied (avoid extra password prompt)
|
|
517
523
|
console.log(' Fixing remote SSH permissions...');
|
|
518
524
|
try {
|
|
519
525
|
(0, child_process_1.spawnSync)('ssh', [
|
|
526
|
+
'-i', keyPath,
|
|
520
527
|
'-o', 'StrictHostKeyChecking=no',
|
|
521
528
|
'-o', 'ConnectTimeout=5',
|
|
522
529
|
user + '@' + host,
|
|
523
530
|
'chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys',
|
|
524
531
|
], {
|
|
525
|
-
|
|
532
|
+
encoding: 'utf8',
|
|
533
|
+
stdio: 'pipe',
|
|
526
534
|
timeout: 15000,
|
|
527
535
|
});
|
|
528
536
|
}
|
|
@@ -879,47 +887,61 @@ async function sshRemoteFactiiiCommand(stage, config, command, rootDir) {
|
|
|
879
887
|
if (!password) {
|
|
880
888
|
password = await promptAndValidatePassword(stage, host, user, config, rootDir);
|
|
881
889
|
}
|
|
882
|
-
|
|
890
|
+
// promptAndValidatePassword may have set up an SSH key — check before falling back to sshpass
|
|
891
|
+
const candidateKey1 = path.join(os.homedir(), '.ssh', stage + '_deploy_key');
|
|
892
|
+
if (fs.existsSync(candidateKey1)) {
|
|
893
|
+
const kv = (0, child_process_1.spawnSync)('ssh', [
|
|
894
|
+
'-i', candidateKey1, '-o', 'BatchMode=yes', '-o', 'StrictHostKeyChecking=no',
|
|
895
|
+
'-o', 'ConnectTimeout=5', user + '@' + host, 'echo ok',
|
|
896
|
+
], { encoding: 'utf8', stdio: 'pipe', timeout: 10000 });
|
|
897
|
+
if (kv.status === 0) {
|
|
898
|
+
resolvedKeyPath = candidateKey1;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
// If we now have a key, skip sshpass and fall through to Step 3
|
|
902
|
+
if (!resolvedKeyPath) {
|
|
903
|
+
if (!password) {
|
|
904
|
+
return {
|
|
905
|
+
success: false,
|
|
906
|
+
stdout: '',
|
|
907
|
+
stderr: 'No SSH key for ' + stage + '. For EC2: provide the .pem file from AWS Console.',
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
console.log(' SSH (password): ' + user + '@' + host + ' → npx stack ' + command);
|
|
911
|
+
const pwStart = Date.now();
|
|
912
|
+
let pwResult;
|
|
913
|
+
if (process.platform === 'win32') {
|
|
914
|
+
// Windows: no sshpass — use interactive SSH so user types password
|
|
915
|
+
console.log(' You will be prompted for the password by SSH:');
|
|
916
|
+
console.log('');
|
|
917
|
+
pwResult = (0, child_process_1.spawnSync)('ssh', [
|
|
918
|
+
'-tt',
|
|
919
|
+
'-o', 'StrictHostKeyChecking=no',
|
|
920
|
+
'-o', 'ConnectTimeout=10',
|
|
921
|
+
'-o', 'ServerAliveInterval=60',
|
|
922
|
+
'-o', 'ServerAliveCountMax=5',
|
|
923
|
+
user + '@' + host,
|
|
924
|
+
pwRemoteCommand,
|
|
925
|
+
], { encoding: 'utf8', stdio: 'inherit', timeout: 600000 });
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
pwResult = (0, child_process_1.spawnSync)('sshpass', [
|
|
929
|
+
'-p', password, 'ssh', '-tt',
|
|
930
|
+
'-o', 'StrictHostKeyChecking=no',
|
|
931
|
+
'-o', 'ConnectTimeout=10',
|
|
932
|
+
'-o', 'ServerAliveInterval=60',
|
|
933
|
+
'-o', 'ServerAliveCountMax=5',
|
|
934
|
+
user + '@' + host,
|
|
935
|
+
pwRemoteCommand,
|
|
936
|
+
], { encoding: 'utf8', stdio: 'inherit', timeout: 600000 });
|
|
937
|
+
}
|
|
938
|
+
console.log(' SSH completed in ' + Math.floor((Date.now() - pwStart) / 1000) + 's');
|
|
883
939
|
return {
|
|
884
|
-
success:
|
|
940
|
+
success: pwResult.status === 0,
|
|
885
941
|
stdout: '',
|
|
886
|
-
stderr:
|
|
942
|
+
stderr: pwResult.status !== 0 ? 'SSH command exited with code ' + pwResult.status : '',
|
|
887
943
|
};
|
|
888
944
|
}
|
|
889
|
-
console.log(' SSH (password): ' + user + '@' + host + ' → npx stack ' + command);
|
|
890
|
-
const pwStart = Date.now();
|
|
891
|
-
let pwResult;
|
|
892
|
-
if (process.platform === 'win32') {
|
|
893
|
-
// Windows: no sshpass — use interactive SSH so user types password
|
|
894
|
-
console.log(' You will be prompted for the password by SSH:');
|
|
895
|
-
console.log('');
|
|
896
|
-
pwResult = (0, child_process_1.spawnSync)('ssh', [
|
|
897
|
-
'-tt',
|
|
898
|
-
'-o', 'StrictHostKeyChecking=no',
|
|
899
|
-
'-o', 'ConnectTimeout=10',
|
|
900
|
-
'-o', 'ServerAliveInterval=60',
|
|
901
|
-
'-o', 'ServerAliveCountMax=5',
|
|
902
|
-
user + '@' + host,
|
|
903
|
-
pwRemoteCommand,
|
|
904
|
-
], { encoding: 'utf8', stdio: 'inherit', timeout: 600000 });
|
|
905
|
-
}
|
|
906
|
-
else {
|
|
907
|
-
pwResult = (0, child_process_1.spawnSync)('sshpass', [
|
|
908
|
-
'-p', password, 'ssh', '-tt',
|
|
909
|
-
'-o', 'StrictHostKeyChecking=no',
|
|
910
|
-
'-o', 'ConnectTimeout=10',
|
|
911
|
-
'-o', 'ServerAliveInterval=60',
|
|
912
|
-
'-o', 'ServerAliveCountMax=5',
|
|
913
|
-
user + '@' + host,
|
|
914
|
-
pwRemoteCommand,
|
|
915
|
-
], { encoding: 'utf8', stdio: 'inherit', timeout: 600000 });
|
|
916
|
-
}
|
|
917
|
-
console.log(' SSH completed in ' + Math.floor((Date.now() - pwStart) / 1000) + 's');
|
|
918
|
-
return {
|
|
919
|
-
success: pwResult.status === 0,
|
|
920
|
-
stdout: '',
|
|
921
|
-
stderr: pwResult.status !== 0 ? 'SSH command exited with code ' + pwResult.status : '',
|
|
922
|
-
};
|
|
923
945
|
}
|
|
924
946
|
}
|
|
925
947
|
// Step 3: We have a key — build command and run
|
|
@@ -1156,6 +1178,32 @@ async function sshRemoteFactiiiCommand(stage, config, command, rootDir) {
|
|
|
1156
1178
|
if (!password) {
|
|
1157
1179
|
password = await promptAndValidatePassword(stage, host, user, config, rootDir);
|
|
1158
1180
|
}
|
|
1181
|
+
// promptAndValidatePassword may have set up an SSH key — use it directly instead of sshpass
|
|
1182
|
+
const candidateKey2 = path.join(os.homedir(), '.ssh', stage + '_deploy_key');
|
|
1183
|
+
if (fs.existsSync(candidateKey2)) {
|
|
1184
|
+
const kv2 = (0, child_process_1.spawnSync)('ssh', [
|
|
1185
|
+
'-i', candidateKey2, '-o', 'BatchMode=yes', '-o', 'StrictHostKeyChecking=no',
|
|
1186
|
+
'-o', 'ConnectTimeout=5', user + '@' + host, 'echo ok',
|
|
1187
|
+
], { encoding: 'utf8', stdio: 'pipe', timeout: 10000 });
|
|
1188
|
+
if (kv2.status === 0) {
|
|
1189
|
+
console.log(' [OK] Using SSH key set up during password auth');
|
|
1190
|
+
const ksStart = Date.now();
|
|
1191
|
+
const ksResult = (0, child_process_1.spawnSync)('ssh', [
|
|
1192
|
+
'-tt', '-i', candidateKey2,
|
|
1193
|
+
'-o', 'StrictHostKeyChecking=no',
|
|
1194
|
+
'-o', 'ConnectTimeout=10',
|
|
1195
|
+
'-o', 'ServerAliveInterval=60',
|
|
1196
|
+
'-o', 'ServerAliveCountMax=5',
|
|
1197
|
+
user + '@' + host, remoteCommand,
|
|
1198
|
+
], { encoding: 'utf8', stdio: 'inherit', timeout: 600000 });
|
|
1199
|
+
console.log(' SSH completed in ' + Math.floor((Date.now() - ksStart) / 1000) + 's');
|
|
1200
|
+
return {
|
|
1201
|
+
success: ksResult.status === 0,
|
|
1202
|
+
stdout: '',
|
|
1203
|
+
stderr: ksResult.status !== 0 ? 'SSH command exited with code ' + ksResult.status : '',
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1159
1207
|
if (password) {
|
|
1160
1208
|
console.log(' Falling back to SSH password auth...');
|
|
1161
1209
|
console.log(' SSH (password): ' + user + '@' + host + ' → npx stack ' + command);
|