/**
 * Phase 9a — connector config schema (WARN-MODE).
 *
 * Registry-driven validator that flags secret-shaped material in a connector
 * config blob (HTTP or stdio). Reuses the connector-leak walker that powers
 * the export sanitizer and import gate (`connectorImportLeaks`) — the two
 * MUST agree so a literal token can't slip through one path while another
 * rejects it.
 *
 * Coverage:
 *   - headers / query / oauth.client_secret / token: secret-named keys MUST
 *     be `$ENV_VAR` placeholders
 *   - stdio env / args: raw token-prefixed values flagged
 *   - URL with embedded credentials anywhere: flagged
 *
 * In 9a the validator only logs; Phase 9b routes writers through it, 9c
 * flips rejection on.
 */
import { z } from 'zod';
import { connectorImportLeaks } from '../secrets/bundle.js';
import { formatViolation, isSchemaStrict, SchemaViolationError } from './workspace.js';
/**
 * Loose top-level shape — connector configs come in two flavours (http and
 * stdio) and we want both to pass through. Strict shape enforcement is for
 * Phase 9b once we know what the wire-data actually looks like.
 */
export const ConnectorConfigSchema = z
    .object({
    name: z.string(),
    type: z.enum(['http', 'stdio']).optional(),
    url: z.string().optional(),
    headers: z.record(z.string(), z.string()).optional(),
    query: z.record(z.string(), z.string()).optional(),
    env: z.record(z.string(), z.string()).optional(),
    args: z.array(z.string()).optional(),
    oauth: z
        .object({
        client_id: z.string().optional(),
        client_secret: z.string().optional(),
    })
        .passthrough()
        .optional(),
    token: z.string().optional(),
})
    .passthrough();
/**
 * Walk a single connector config and return structured violations.
 * `connectorImportLeaks` is designed for an array of connectors and returns
 * paths prefixed with `connectors.<i>.…` — we wrap the single config in a
 * one-element array and strip the prefix before returning.
 */
export function validateConnectorConfig(input) {
    if (!input || typeof input !== 'object')
        return [];
    const leaks = connectorImportLeaks([input]);
    return leaks.map((path) => {
        // Drop the `connectors.0.` prefix produced by connectorImportLeaks so
        // the violation reads naturally for a single-connector save.
        const stripped = path.replace(/^connectors\.0\./, '');
        return {
            path: stripped,
            reason: 'value-shape',
        };
    });
}
/**
 * Warn-mode entry point: validate + log each violation. Returns the
 * violations so callers can inspect.
 */
export function warnOnConnectorConfigViolations(input) {
    const violations = validateConnectorConfig(input);
    for (const v of violations) {
        // eslint-disable-next-line no-console
        console.warn(formatViolation('connector_config', v));
    }
    return violations;
}
/**
 * Phase 9c — strict-or-warn entry point used by save sites.
 *
 * When `STUDIOGRAPH_SCHEMA_STRICT` is on (default), throws
 * `SchemaViolationError` on the first non-empty violation list. Otherwise
 * delegates to the warn-mode logger.
 *
 * `ConnectorManager.saveWorkspaceConfig` should call this. Strict mode
 * means a connector with a literal Authorization header (post-strip) is
 * a bug — `stripSecrets` failed to do its job — and we reject loudly
 * instead of silently writing a leak.
 */
export function enforceConnectorConfig(input) {
    if (!isSchemaStrict()) {
        return warnOnConnectorConfigViolations(input);
    }
    const violations = validateConnectorConfig(input);
    if (violations.length > 0) {
        throw new SchemaViolationError('connector_config', violations);
    }
    return violations;
}
//# sourceMappingURL=connector.js.map