Follow-up to a99f971: covers the remaining ${TENANT_ID} interpolation
sites that produced leading-hyphen / empty-path values on root installs.
- setup/ollama.ts, setup/llama-cpp.ts: preferred jail names
- setup/sanoid.ts: tenant-era home candidate
- setup/hosts.ts: jail-name discovery filter (+ test mock)
- src/telegram-commands.ts: status identity line, suppress empty
tenant clause on root installs
Root-detection sites that key off TENANT_ID === '' are intentionally
left untouched; the invariant is preserved.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---
Build: FAIL | Tests: FAIL — 15 failed
147 lines
3.7 KiB
TypeScript
147 lines
3.7 KiB
TypeScript
import fs from 'fs';
|
|
import path from 'path';
|
|
|
|
import {
|
|
AGENT_INTERNAL_DOMAIN,
|
|
RUNTIME_ID,
|
|
} from '../src/config.js';
|
|
import {
|
|
renderLocalHostsBlock,
|
|
upsertLocalHostsBlock,
|
|
} from '../src/local-hosts.js';
|
|
import { logger } from '../src/logger.js';
|
|
import { getPlatform } from './platform.js';
|
|
import { emitStatus } from './status.js';
|
|
|
|
const HOSTS_FILE = '/etc/hosts';
|
|
const BASTILLE_ROOT = '/usr/local/bastille';
|
|
|
|
function ensureHostsBase(content: string): string {
|
|
if (content.trim()) {
|
|
return content;
|
|
}
|
|
|
|
return [
|
|
'127.0.0.1 localhost',
|
|
'::1 localhost',
|
|
].join('\n') + '\n';
|
|
}
|
|
|
|
function syncHostsFile(filePath: string): void {
|
|
const current = fs.existsSync(filePath)
|
|
? fs.readFileSync(filePath, 'utf-8')
|
|
: '';
|
|
const next = upsertLocalHostsBlock(ensureHostsBase(current));
|
|
fs.writeFileSync(filePath, next);
|
|
}
|
|
|
|
function syncJailHosts(jailName: string): boolean {
|
|
const hostsFile = path.join(BASTILLE_ROOT, 'jails', jailName, 'root', 'etc', 'hosts');
|
|
if (!fs.existsSync(path.dirname(hostsFile))) {
|
|
return false;
|
|
}
|
|
syncHostsFile(hostsFile);
|
|
return true;
|
|
}
|
|
|
|
function discoverAgentJails(): string[] {
|
|
const jailsRoot = path.join(BASTILLE_ROOT, 'jails');
|
|
if (!fs.existsSync(jailsRoot)) {
|
|
return [];
|
|
}
|
|
|
|
const normalizedRuntimeId = RUNTIME_ID.replace(/[-_]/g, '');
|
|
|
|
return fs.readdirSync(jailsRoot, { withFileTypes: true })
|
|
.filter((entry) => entry.isDirectory())
|
|
.map((entry) => entry.name)
|
|
.filter(
|
|
(name) =>
|
|
name === RUNTIME_ID ||
|
|
name.startsWith(`${RUNTIME_ID}-`) ||
|
|
name.startsWith(`${RUNTIME_ID}_`) ||
|
|
name.startsWith(`${normalizedRuntimeId}_`),
|
|
)
|
|
.sort();
|
|
}
|
|
|
|
export function syncLocalHosts(): {
|
|
hostFile: string;
|
|
syncedTargets: string[];
|
|
skippedTargets: string[];
|
|
} {
|
|
const syncedTargets: string[] = [];
|
|
const skippedTargets: string[] = [];
|
|
|
|
syncHostsFile(HOSTS_FILE);
|
|
syncedTargets.push(HOSTS_FILE);
|
|
|
|
for (const target of discoverAgentJails()) {
|
|
if (syncJailHosts(target)) {
|
|
syncedTargets.push(target);
|
|
} else {
|
|
skippedTargets.push(target);
|
|
}
|
|
}
|
|
|
|
return {
|
|
hostFile: HOSTS_FILE,
|
|
syncedTargets,
|
|
skippedTargets,
|
|
};
|
|
}
|
|
|
|
export async function run(_args: string[]): Promise<void> {
|
|
if (getPlatform() !== 'freebsd') {
|
|
emitStatus('SETUP_HOSTS', {
|
|
STATUS: 'failed',
|
|
ERROR: 'unsupported_platform',
|
|
LOG: 'logs/setup.log',
|
|
});
|
|
process.exit(1);
|
|
}
|
|
|
|
try {
|
|
const result = syncLocalHosts();
|
|
logger.info(
|
|
{
|
|
internalDomain: AGENT_INTERNAL_DOMAIN,
|
|
syncedTargets: result.syncedTargets,
|
|
skippedTargets: result.skippedTargets,
|
|
},
|
|
'Local hosts sync complete',
|
|
);
|
|
|
|
emitStatus('SETUP_HOSTS', {
|
|
INTERNAL_DOMAIN: AGENT_INTERNAL_DOMAIN,
|
|
HOSTS_FILE: result.hostFile,
|
|
SYNCED: result.syncedTargets.join(',') || 'none',
|
|
SKIPPED: result.skippedTargets.join(',') || 'none',
|
|
STATUS: 'success',
|
|
LOG: 'logs/setup.log',
|
|
});
|
|
|
|
console.log('');
|
|
console.log('─'.repeat(52));
|
|
console.log(` local hosts synced for ${AGENT_INTERNAL_DOMAIN}`);
|
|
console.log(` Host file : ${HOSTS_FILE}`);
|
|
console.log(` Targets : ${result.syncedTargets.join(', ')}`);
|
|
if (result.skippedTargets.length > 0) {
|
|
console.log(` Skipped : ${result.skippedTargets.join(', ')}`);
|
|
}
|
|
console.log('');
|
|
console.log(' Managed block preview:');
|
|
console.log(renderLocalHostsBlock().trimEnd());
|
|
console.log('─'.repeat(52));
|
|
console.log('');
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
emitStatus('SETUP_HOSTS', {
|
|
INTERNAL_DOMAIN: AGENT_INTERNAL_DOMAIN,
|
|
STATUS: 'failed',
|
|
ERROR: message,
|
|
LOG: 'logs/setup.log',
|
|
});
|
|
throw error;
|
|
}
|
|
}
|