// Phase F-2-B (B6): redact sensitive keys from workspace YAML before
// exposing via /api/workspaces.
//
// T11 mitigation. Workspace YAMLs may contain operator-set environment
// variables that include OAuth client secrets, API keys, deployment
// tokens, database passwords. These should NEVER cross the host-cp ↔
// browser boundary.
//
// Strategy: pattern-based recursive redaction. Any object key matching
// SENSITIVE_KEY_PATTERN replaces its value with `[redacted]`. Catches
// the standard naming conventions while remaining permissive on
// non-sensitive keys (we don't false-positive on legitimate config).
//
// The pattern is intentionally broad — it's defensive. If an operator
// names a non-sensitive var with a `_KEY`/`_SECRET`/`_TOKEN`/`_PASSWORD`/
// `_CREDENTIALS` suffix, it gets redacted. Operators get a clear signal
// (the value becomes `[redacted]`) and can rename the var if needed.
//
// We deliberately do NOT use the `PROTECTED_ENV_KEYS` set from
// packages/core/src/world/env-setup.ts — that set is for service-
// discovery host/port/URL keys (POSTGRES_HOST, REDIS_URL, etc.), not
// org secrets. The two filters address different surfaces:
//   - PROTECTED_ENV_KEYS in core: prevents manifest from overriding
//     service-discovery state on the world's runtime env
//   - SENSITIVE_KEY_PATTERN here: prevents the host CP API from leaking
//     org secrets to the browser
// Both are needed.

export const SENSITIVE_KEY_PATTERN = /(.*_KEY|.*_SECRET|.*_TOKEN|.*_PASSWORD|.*_CREDENTIALS|.*_AUTH|API_KEY|PASSWORD|SECRET|TOKEN)$/i;

/**
 * Recursively redact sensitive values in any JSON-like structure
 * (objects, arrays, primitives). Returns a new value; does not mutate
 * input.
 *
 * @param {unknown} value
 * @returns {unknown}
 */
export function redactSensitive(value) {
  if (Array.isArray(value)) {
    return value.map(redactSensitive);
  }
  if (value !== null && typeof value === 'object') {
    /** @type {Record<string, unknown>} */
    const out = {};
    for (const [k, v] of Object.entries(value)) {
      if (SENSITIVE_KEY_PATTERN.test(k)) {
        out[k] = '[redacted]';
      } else {
        out[k] = redactSensitive(v);
      }
    }
    return out;
  }
  return value;
}

/**
 * Quick predicate: does this key name look sensitive? Useful for
 * pre-screening when iterating large maps.
 *
 * @param {string} key
 * @returns {boolean}
 */
export function isSensitiveKey(key) {
  return SENSITIVE_KEY_PATTERN.test(key);
}
