diff --git a/src/lib/config-generator/toml-generator.ts b/src/lib/config-generator/toml-generator.ts index 64ba2f07..c3e8a2ee 100644 --- a/src/lib/config-generator/toml-generator.ts +++ b/src/lib/config-generator/toml-generator.ts @@ -52,6 +52,18 @@ export function generateVectorToml( ...nodeConfig, }; + // Strip empty nested objects (e.g. auth: {} when no auth is configured) + for (const [key, val] of Object.entries(entry)) { + if ( + val != null && + typeof val === "object" && + !Array.isArray(val) && + Object.values(val as Record).every((v) => v == null || v === "") + ) { + delete entry[key]; + } + } + if (componentDef.kind !== "source") { const inputs = enabledEdges .filter((e) => e.target === node.id) diff --git a/src/lib/config-generator/yaml-generator.ts b/src/lib/config-generator/yaml-generator.ts index 088a67fe..d2b687c9 100644 --- a/src/lib/config-generator/yaml-generator.ts +++ b/src/lib/config-generator/yaml-generator.ts @@ -59,6 +59,18 @@ export function generateVectorYaml( ...nodeConfig, }; + // Strip empty nested objects (e.g. auth: {} when no auth is configured) + for (const [key, val] of Object.entries(entry)) { + if ( + val != null && + typeof val === "object" && + !Array.isArray(val) && + Object.values(val as Record).every((v) => v == null || v === "") + ) { + delete entry[key]; + } + } + // For transforms and sinks, build inputs array from incoming edges if (componentDef.kind !== "source") { const inputs = enabledEdges diff --git a/src/lib/vector/schemas/shared.ts b/src/lib/vector/schemas/shared.ts index d21fee06..3f156f3f 100644 --- a/src/lib/vector/schemas/shared.ts +++ b/src/lib/vector/schemas/shared.ts @@ -301,6 +301,51 @@ export function authBasicBearerSchema() { }; } +/* ------------------------------------------------------------------ */ +/* Auth: HTTP Server (basic + custom — server-mode validation) */ +/* ------------------------------------------------------------------ */ + +/** + * Auth schema for Vector's http_server source. + * + * Server-mode auth validates *incoming* requests, so the field names and + * strategies differ from the outbound (client-mode) auth used by sinks: + * - `username` / `password` for basic (not `user`) + * - `source` (VRL expression) for custom + * - No bearer support + */ +export function authHttpServerSchema() { + return { + auth: { + type: "object", + properties: { + strategy: { + type: "string", + enum: ["basic", "custom"], + description: "Authentication strategy", + }, + username: { + type: "string", + description: "Basic auth username", + dependsOn: { field: "strategy", value: "basic" }, + }, + password: { + type: "string", + description: "Basic auth password", + sensitive: true, + dependsOn: { field: "strategy", value: "basic" }, + }, + source: { + type: "string", + description: "VRL boolean expression for custom auth validation", + dependsOn: { field: "strategy", value: "custom" }, + }, + }, + description: "Authentication configuration (optional — omit for no auth)", + }, + }; +} + /* ------------------------------------------------------------------ */ /* Auth: AWS */ /* ------------------------------------------------------------------ */ diff --git a/src/lib/vector/schemas/sources/network.ts b/src/lib/vector/schemas/sources/network.ts index 457d82fb..f50022f6 100644 --- a/src/lib/vector/schemas/sources/network.ts +++ b/src/lib/vector/schemas/sources/network.ts @@ -4,6 +4,7 @@ import { decodingSchema, framingSchema, authBasicBearerSchema, + authHttpServerSchema, } from "../shared"; export const networkSources: VectorComponentDef[] = [ @@ -121,7 +122,7 @@ export const networkSources: VectorComponentDef[] = [ description: "The HTTP status code to return on success", default: 200, }, - ...authBasicBearerSchema(), + ...authHttpServerSchema(), ...tlsSchema(), ...decodingSchema(), ...framingSchema(),