v1.0.19
This commit is contained in:
1 parent
4b430340db
commit
9c451aedf9
120 files changed
+7777
-6046
No files matched your search
+83
-11
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
import * as http from 'node:http';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
// Cache the host data dir to avoid repeated API calls
|
||||
@@ -29,6 +30,11 @@ let detectionAttempted = false;
|
||||
// Cache ALL mounts for path translation (not just DATA_DIR)
|
||||
let cachedMounts: Array<{ source: string; destination: string }> | null = null;
|
||||
|
||||
// Cache Dockhand's own Docker access method (detected from container inspect)
|
||||
// Used by scanner to replicate how Dockhand connects to Docker
|
||||
let cachedOwnDockerHost: string | null = null;
|
||||
let cachedOwnNetworkMode: string | null = null;
|
||||
|
||||
/**
|
||||
* Get our own container ID
|
||||
*/
|
||||
@@ -95,25 +101,48 @@ export async function detectHostDataDir(): Promise<string | null> {
|
||||
|
||||
try {
|
||||
// Query Docker API to inspect our own container
|
||||
// Try unix socket first, fall back to TCP if DOCKER_HOST is set
|
||||
const socketPath = process.env.DOCKER_SOCKET || '/var/run/docker.sock';
|
||||
const dockerHost = process.env.DOCKER_HOST;
|
||||
|
||||
// Use fetch with unix socket
|
||||
const response = await fetch(`http://localhost/containers/${containerId}/json`, {
|
||||
// @ts-ignore - Bun supports unix sockets
|
||||
unix: socketPath
|
||||
});
|
||||
const containerInfo = await new Promise<any>((resolvePromise, reject) => {
|
||||
const reqOptions: http.RequestOptions = dockerHost?.startsWith('tcp://')
|
||||
? (() => {
|
||||
const u = new URL(dockerHost.replace('tcp://', 'http://'));
|
||||
return { hostname: u.hostname, port: u.port, path: `/containers/${containerId}/json`, method: 'GET' };
|
||||
})()
|
||||
: { socketPath, path: `/containers/${containerId}/json`, method: 'GET' };
|
||||
|
||||
if (!response.ok) {
|
||||
console.warn(`[HostPath] Failed to inspect container: ${response.status}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const containerInfo = await response.json() as {
|
||||
const req = http.request(reqOptions, (res) => {
|
||||
const chunks: Buffer[] = [];
|
||||
res.on('data', (chunk: Buffer) => chunks.push(chunk));
|
||||
res.on('end', () => {
|
||||
if (res.statusCode === 200) {
|
||||
try {
|
||||
resolvePromise(JSON.parse(Buffer.concat(chunks).toString('utf-8')));
|
||||
} catch {
|
||||
reject(new Error('Failed to parse container inspect response'));
|
||||
}
|
||||
} else {
|
||||
reject(new Error(`Container inspect failed: ${res.statusCode}`));
|
||||
}
|
||||
});
|
||||
res.on('error', reject);
|
||||
});
|
||||
req.on('error', reject);
|
||||
req.end();
|
||||
}) as {
|
||||
Mounts?: Array<{
|
||||
Type: string;
|
||||
Source: string;
|
||||
Destination: string;
|
||||
}>;
|
||||
Config?: {
|
||||
Env?: string[];
|
||||
};
|
||||
NetworkSettings?: {
|
||||
Networks?: Record<string, unknown>;
|
||||
};
|
||||
};
|
||||
|
||||
// Cache ALL mounts for later path translation (used by rewriteComposeVolumePaths)
|
||||
@@ -123,6 +152,30 @@ export async function detectHostDataDir(): Promise<string | null> {
|
||||
}));
|
||||
console.log(`[HostPath] Cached ${cachedMounts.length} mount(s)`);
|
||||
|
||||
// Cache DOCKER_HOST from Dockhand's own env vars (if set)
|
||||
// This tells us how Dockhand was configured to reach Docker
|
||||
const envVars = containerInfo.Config?.Env || [];
|
||||
for (const v of envVars) {
|
||||
if (v.startsWith('DOCKER_HOST=')) {
|
||||
cachedOwnDockerHost = v.substring('DOCKER_HOST='.length);
|
||||
console.log(`[HostPath] Detected own DOCKER_HOST: ${cachedOwnDockerHost}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache Dockhand's network (prefer non-default for service discovery)
|
||||
const networks = containerInfo.NetworkSettings?.Networks;
|
||||
if (networks) {
|
||||
const custom = Object.keys(networks).filter(
|
||||
n => n !== 'bridge' && n !== 'none' && n !== 'host'
|
||||
);
|
||||
cachedOwnNetworkMode = custom.length > 0 ? custom[0]
|
||||
: networks.bridge ? 'bridge' : null;
|
||||
if (cachedOwnNetworkMode) {
|
||||
console.log(`[HostPath] Detected own network: ${cachedOwnNetworkMode}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Find the mount for our DATA_DIR
|
||||
const dataMount = containerInfo.Mounts?.find(m => m.Destination === dataDir);
|
||||
|
||||
@@ -157,6 +210,25 @@ export function getHostDataDir(): string | null {
|
||||
return cachedHostDataDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DOCKER_HOST from Dockhand's own container config (if set).
|
||||
* Returns the TCP address (e.g., "tcp://socket-proxy:2375") or null.
|
||||
* Populated by detectHostDataDir() at startup.
|
||||
*/
|
||||
export function getOwnDockerHost(): string | null {
|
||||
return cachedOwnDockerHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Docker network Dockhand is attached to.
|
||||
* Used to place scanner containers on the same network so they can reach
|
||||
* TCP-based Docker endpoints (e.g., socket proxy).
|
||||
* Populated by detectHostDataDir() at startup.
|
||||
*/
|
||||
export function getOwnNetworkMode(): string | null {
|
||||
return cachedOwnNetworkMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a container path to host path
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user