@lamalibre/portlama-agent 1.0.18 → 1.0.20
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/package.json +1 -1
- package/src/commands/setup.js +14 -0
- package/src/lib/cert-store.js +3 -2
- package/src/lib/keychain.js +21 -4
package/package.json
CHANGED
package/src/commands/setup.js
CHANGED
|
@@ -246,6 +246,19 @@ async function runTokenSetup(flags) {
|
|
|
246
246
|
await mkdir(logsDir, { recursive: true, mode: 0o700 });
|
|
247
247
|
},
|
|
248
248
|
},
|
|
249
|
+
{
|
|
250
|
+
title: 'Requesting macOS login password',
|
|
251
|
+
skip: () => !isDarwin() && 'Not macOS',
|
|
252
|
+
task: async (_ctx, task) => {
|
|
253
|
+
task.output = chalk.dim('Required to authorize curl access to the Keychain certificate');
|
|
254
|
+
ctx._keychainPassword = await prompt('macOS login password (for Keychain access)');
|
|
255
|
+
if (!ctx._keychainPassword) {
|
|
256
|
+
throw new Error('Keychain password is required on macOS to grant curl access to the certificate.');
|
|
257
|
+
}
|
|
258
|
+
task.output = 'Password received';
|
|
259
|
+
},
|
|
260
|
+
rendererOptions: { persistentOutput: true },
|
|
261
|
+
},
|
|
249
262
|
{
|
|
250
263
|
title: isDarwin() ? 'Importing certificate into Keychain' : 'Storing certificate',
|
|
251
264
|
task: async (_ctx, task) => {
|
|
@@ -255,6 +268,7 @@ async function runTokenSetup(flags) {
|
|
|
255
268
|
ctx._caCertPem,
|
|
256
269
|
ctx.resolvedLabel,
|
|
257
270
|
console,
|
|
271
|
+
{ keychainPassword: ctx._keychainPassword },
|
|
258
272
|
);
|
|
259
273
|
if (result.identity) {
|
|
260
274
|
ctx.keychainIdentity = result.identity;
|
package/src/lib/cert-store.js
CHANGED
|
@@ -22,12 +22,13 @@ import { secureDelete } from './keychain.js';
|
|
|
22
22
|
* @param {string} caCertPem - PEM-encoded CA certificate
|
|
23
23
|
* @param {string} label - Agent label
|
|
24
24
|
* @param {import('pino').Logger | Console} logger
|
|
25
|
+
* @param {{ keychainPassword?: string }} [options]
|
|
25
26
|
* @returns {Promise<{ identity?: string, p12Path?: string, p12Password?: string }>}
|
|
26
27
|
*/
|
|
27
|
-
export async function storeEnrolledCert(keyPath, certPem, caCertPem, label, logger) {
|
|
28
|
+
export async function storeEnrolledCert(keyPath, certPem, caCertPem, label, logger, options = {}) {
|
|
28
29
|
if (isDarwin()) {
|
|
29
30
|
const { importIdentityToKeychain } = await import('./keychain.js');
|
|
30
|
-
const { identity } = await importIdentityToKeychain(keyPath, certPem, caCertPem, label, logger);
|
|
31
|
+
const { identity } = await importIdentityToKeychain(keyPath, certPem, caCertPem, label, logger, options);
|
|
31
32
|
return { identity };
|
|
32
33
|
}
|
|
33
34
|
return storeP12Linux(keyPath, certPem, caCertPem, label, logger);
|
package/src/lib/keychain.js
CHANGED
|
@@ -82,9 +82,10 @@ export async function generateKeypairAndCSR(label) {
|
|
|
82
82
|
* @param {string} caCertPem - PEM-encoded CA certificate
|
|
83
83
|
* @param {string} label - Agent label
|
|
84
84
|
* @param {import('pino').Logger | Console} logger
|
|
85
|
+
* @param {{ keychainPassword?: string }} [options]
|
|
85
86
|
* @returns {Promise<{ identity: string }>}
|
|
86
87
|
*/
|
|
87
|
-
export async function importIdentityToKeychain(keyPath, certPem, caCertPem, label, logger) {
|
|
88
|
+
export async function importIdentityToKeychain(keyPath, certPem, caCertPem, label, logger, options = {}) {
|
|
88
89
|
const suffix = crypto.randomBytes(8).toString('hex');
|
|
89
90
|
const certPath = path.join(AGENT_DIR, `.tmp-cert-${suffix}.pem`);
|
|
90
91
|
const caPath = path.join(AGENT_DIR, `.tmp-ca-${suffix}.pem`);
|
|
@@ -142,16 +143,32 @@ export async function importIdentityToKeychain(keyPath, certPem, caCertPem, labe
|
|
|
142
143
|
p12Password,
|
|
143
144
|
]);
|
|
144
145
|
|
|
146
|
+
// Trust the Portlama CA so macOS considers the agent identity valid.
|
|
147
|
+
// Without this, `security find-identity -v -p ssl-client` marks the
|
|
148
|
+
// identity as CSSMERR_TP_NOT_TRUSTED and curl exits with code 58.
|
|
149
|
+
// `add-trusted-cert` is idempotent — safe to call on every import.
|
|
150
|
+
try {
|
|
151
|
+
await execa('security', [
|
|
152
|
+
'add-trusted-cert',
|
|
153
|
+
'-p',
|
|
154
|
+
'ssl', // trust for SSL/TLS
|
|
155
|
+
caPath,
|
|
156
|
+
]);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
logger.warn?.({ err, label }, 'Could not set CA trust — curl may fail with exit 58') ??
|
|
159
|
+
logger.log?.(`Warning: Could not trust CA certificate for ${label}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
145
162
|
// Set the key partition list so curl can access the identity without prompts.
|
|
146
|
-
//
|
|
147
|
-
|
|
163
|
+
// Requires the login Keychain password — callers should prompt the user for it.
|
|
164
|
+
const keychainPassword = options.keychainPassword ?? '';
|
|
148
165
|
try {
|
|
149
166
|
await execa('security', [
|
|
150
167
|
'set-key-partition-list',
|
|
151
168
|
'-S',
|
|
152
169
|
'apple-tool:,apple:', // apple-tool: for /usr/bin/curl, apple: for GUI apps
|
|
153
170
|
'-k',
|
|
154
|
-
|
|
171
|
+
keychainPassword,
|
|
155
172
|
'-l', // match by Label (friendly name from -name), not -D (Description)
|
|
156
173
|
identityName,
|
|
157
174
|
]);
|