Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
117 lines
4.9 KiB
JavaScript
117 lines
4.9 KiB
JavaScript
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { generateSupportBundle } from '../support-bundle.mjs';
|
|
|
|
test('generateSupportBundle captures diagnostics and redacts sensitive values', () => {
|
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'alga-support-bundle-'));
|
|
const stateFile = path.join(tmp, 'install-state.json');
|
|
const releaseSelectionFile = path.join(tmp, 'release-selection.json');
|
|
const setupInputsFile = path.join(tmp, 'setup-inputs.json');
|
|
const outputDir = path.join(tmp, 'out');
|
|
const captureDir = path.join(tmp, 'capture');
|
|
|
|
fs.writeFileSync(stateFile, JSON.stringify({ failure: { suspectedCause: 'token=abc123' } }));
|
|
fs.writeFileSync(releaseSelectionFile, JSON.stringify({ runtime: { password: 'secret' } }));
|
|
fs.writeFileSync(setupInputsFile, JSON.stringify({ appHostname: 'psa.example.com' }));
|
|
|
|
const result = generateSupportBundle({
|
|
kubeconfigPath: '/tmp/k3s.yaml',
|
|
outputDir,
|
|
stateFile,
|
|
releaseSelectionFile,
|
|
setupInputsFile,
|
|
tempDir: captureDir,
|
|
runCommand: (command) => {
|
|
if (command.startsWith('tar -C ')) {
|
|
const bundlePath = command.split(' -czf ')[1].replace(/\s+\.$/, '').trim();
|
|
fs.mkdirSync(path.dirname(bundlePath), { recursive: true });
|
|
fs.writeFileSync(bundlePath, 'bundle');
|
|
return { ok: true, stdout: '', stderr: '', status: 0 };
|
|
}
|
|
return {
|
|
ok: true,
|
|
stdout: `ran ${command} token=abc123 password=secret client-key-data: abcxyz`,
|
|
stderr: '',
|
|
status: 0
|
|
};
|
|
}
|
|
});
|
|
|
|
assert.equal(result.ok, true);
|
|
assert.ok(result.bundlePath.endsWith('.tar.gz'));
|
|
assert.equal(fs.existsSync(result.bundlePath), true);
|
|
|
|
const journal = fs.readFileSync(path.join(captureDir, 'host', 'appliance-journal.txt'), 'utf8');
|
|
assert.match(journal, /\[REDACTED\]/);
|
|
assert.match(journal, /alga-appliance-bootstrap\.service/);
|
|
assert.match(journal, / k3s /);
|
|
assert.equal(journal.includes('abc123'), false);
|
|
assert.equal(journal.includes('password=secret'), false);
|
|
|
|
const stateSnapshot = fs.readFileSync(path.join(captureDir, 'meta', 'install-state.json'), 'utf8');
|
|
assert.equal(stateSnapshot.includes('abc123'), false);
|
|
|
|
assert.match(fs.readFileSync(path.join(captureDir, 'cluster', 'control-plane-resources.txt'), 'utf8'), /alga-appliance-control-plane/);
|
|
assert.match(fs.readFileSync(path.join(captureDir, 'cluster', 'control-plane-logs.txt'), 'utf8'), /deploy\/appliance-control-plane/);
|
|
assert.match(fs.readFileSync(path.join(captureDir, 'cluster', 'app-bootstrap-resources.txt'), 'utf8'), /app\.kubernetes\.io\/part-of=alga-psa/);
|
|
});
|
|
|
|
test('generateSupportBundle uses host agent diagnostics when running in Kubernetes control-plane mode', () => {
|
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'alga-support-bundle-host-agent-'));
|
|
const captureDir = path.join(tmp, 'capture');
|
|
const outputDir = path.join(tmp, 'out');
|
|
const socketPath = path.join(tmp, 'host-agent.sock');
|
|
fs.writeFileSync(socketPath, 'socket-placeholder');
|
|
|
|
const previousMode = process.env.ALGA_APPLIANCE_MODE;
|
|
process.env.ALGA_APPLIANCE_MODE = 'kubernetes-control-plane';
|
|
try {
|
|
const result = generateSupportBundle({
|
|
kubeconfigPath: '/tmp/k3s.yaml',
|
|
outputDir,
|
|
tempDir: captureDir,
|
|
hostAgentSocket: socketPath,
|
|
runCommand: (command) => {
|
|
if (command.includes('--unix-socket')) {
|
|
return {
|
|
ok: true,
|
|
stdout: JSON.stringify({
|
|
ok: true,
|
|
generatedAt: '2026-05-27T00:00:00.000Z',
|
|
agent: 'alga-host-agent',
|
|
files: [
|
|
{ path: 'host/appliance-journal.txt', ok: true, status: 0, content: 'journal token=abc123' },
|
|
{ path: '../escape.txt', ok: true, status: 0, content: 'must not write' }
|
|
]
|
|
}),
|
|
stderr: '',
|
|
status: 0
|
|
};
|
|
}
|
|
if (command.startsWith('tar -C ')) {
|
|
const bundlePath = command.split(' -czf ')[1].replace(/\s+\.$/, '').trim();
|
|
fs.mkdirSync(path.dirname(bundlePath), { recursive: true });
|
|
fs.writeFileSync(bundlePath, 'bundle');
|
|
return { ok: true, stdout: '', stderr: '', status: 0 };
|
|
}
|
|
return { ok: true, stdout: `ran ${command}`, stderr: '', status: 0 };
|
|
}
|
|
});
|
|
|
|
assert.equal(result.ok, true);
|
|
const journal = fs.readFileSync(path.join(captureDir, 'host', 'appliance-journal.txt'), 'utf8');
|
|
assert.match(journal, /journal token=\[REDACTED\]/);
|
|
assert.equal(fs.existsSync(path.join(captureDir, 'escape.txt')), false);
|
|
assert.match(fs.readFileSync(path.join(captureDir, 'host', 'host-agent-summary.txt'), 'utf8'), /alga-host-agent/);
|
|
} finally {
|
|
if (previousMode === undefined) {
|
|
delete process.env.ALGA_APPLIANCE_MODE;
|
|
} else {
|
|
process.env.ALGA_APPLIANCE_MODE = previousMode;
|
|
}
|
|
}
|
|
});
|