db2db5095b
Regression guard for bootstrap.js's jump-secrets.js template: its ldap block must use ldaps:// (implicit TLS, :636), not ldap:// (:389), as long as tlsOptions is set alongside it. ldapts treats a non-empty tlsOptions as "use implicit TLS" regardless of URL scheme, and jump-host's LDAP client always sets tlsOptions -- so this exact combination broke every SSH login to jump-host (any account, any password) before being root-caused against a real deployment. Static (parses bootstrap.js as text), not a require()+exec of it -- bootstrap.js is a self-running provisioning script with real side effects (LDAP writes, live API calls), not a library, so there's nothing safe to import and call in CI. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
67 lines
3.0 KiB
JavaScript
67 lines
3.0 KiB
JavaScript
#!/usr/bin/env node
|
|
'use strict';
|
|
|
|
// Regression guard for bootstrap.js's generated jump-secrets.js template:
|
|
// its ldap block must use ldaps:// (implicit TLS, :636), never ldap:// (:389),
|
|
// as long as tlsOptions is set alongside it.
|
|
//
|
|
// ldapts treats a non-empty tlsOptions as "use implicit TLS" regardless of URL
|
|
// scheme, and jump-host's LDAP client always sets tlsOptions -- so ldap://
|
|
// + tlsOptions opens a raw TLS handshake against a port serving plaintext
|
|
// LDAP. The server silently drops the connection before any LDAP message
|
|
// parses, and every operation (getUser, checkPassword, ...) then fails
|
|
// identically -- indistinguishable from a wrong password. This shipped once
|
|
// (every SSH login to jump-host failed, for any account, any password) before
|
|
// being root-caused against a real deployment. Static, not a require()+exec
|
|
// of bootstrap.js, because bootstrap.js is a self-running provisioning script
|
|
// with real side effects (LDAP writes, API calls), not a library.
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const BOOTSTRAP_PATH = path.join(__dirname, '..', 'bootstrap', 'bootstrap.js');
|
|
const src = fs.readFileSync(BOOTSTRAP_PATH, 'utf8');
|
|
|
|
// Isolate the generated jump-secrets.js template (the backtick string
|
|
// assigned to `body` inside writeJumpSecrets) rather than scanning the whole
|
|
// file, so this only ever looks at what's actually written to the deployed
|
|
// config -- not, say, a comment or an unrelated ldap:// URL elsewhere.
|
|
// bootstrap.js's own source has literal backslash-t escape sequences inside
|
|
// the backtick string (they only become real tabs when the template
|
|
// literal is actually evaluated) -- so these patterns match `\t` as two
|
|
// literal characters, not a real tab byte.
|
|
const bodyMatch = /const body = `([\s\S]*?)`;\n\tfs\.writeFileSync\(JUMP_SECRETS/.exec(src);
|
|
if (!bodyMatch) {
|
|
console.error('check_jump_ldap_tls: could not locate the jump-secrets.js template in bootstrap.js — did writeJumpSecrets change shape?');
|
|
process.exit(1);
|
|
}
|
|
const template = bodyMatch[1];
|
|
|
|
// Bounded by the next top-level key (sso:) rather than the ldap block's own
|
|
// closing brace, which is more robust to exactly how it's indented/escaped.
|
|
const ldapBlockMatch = /ldap:\s*\{([\s\S]*?)\\tsso:\s*\{/.exec(template);
|
|
if (!ldapBlockMatch) {
|
|
console.error('check_jump_ldap_tls: could not find the ldap: {...} block in the jump-secrets.js template.');
|
|
process.exit(1);
|
|
}
|
|
const ldapBlock = ldapBlockMatch[1];
|
|
|
|
const hasTlsOptions = /tlsOptions\s*:/.test(ldapBlock);
|
|
const urlMatch = /url:\s*'([^']+)'/.exec(ldapBlock);
|
|
const url = urlMatch ? urlMatch[1] : null;
|
|
|
|
if (!url) {
|
|
console.error('check_jump_ldap_tls: no url found in the ldap block.');
|
|
process.exit(1);
|
|
}
|
|
|
|
if (hasTlsOptions && !url.startsWith('ldaps://')) {
|
|
console.error(
|
|
`check_jump_ldap_tls: jump-secrets.js template sets tlsOptions but url is "${url}" (not ldaps://). ` +
|
|
'This is the exact bug that broke every SSH login to jump-host -- see the comment above this check.'
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`check_jump_ldap_tls: OK (url=${url}, tlsOptions=${hasTlsOptions})`);
|