Skip to content

Centralizar decrypt de Secret em @decocms/start/sdk/crypto:resolveSecret (em vez de cada app reimplementar) #70

Description

@JonasJesus42

Resumo

@decocms/apps-start/website/loaders/secret.ts não decripta secrets — apenas lê process.env[name] ou retorna o encrypted hex as-is. Todos os inits/clients que precisam de credenciais (magento, vtex, algolia que vão sendo portados) reimplementam a mesma função resolveSecret local que também só lê env var.

Enquanto isso, @decocms/start/sdk/crypto.ts já tem resolveSecret(value, envVarName) e decryptSecret(encryptedHex) que:

  • Decriptam AES-CBC via DECO_CRYPTO_KEY (mesma chave do deco-cx/apps Fresh)
  • Cacheam o resultado em memória
  • Fazem fallback pra env var quando encrypted falha

Resultado prático: sites que não setam env var pra cada secret têm o site quebrado em prod, mesmo tendo o encrypted válido no bloco do CMS.

Comparação

deco-cx/apps (Fresh/Deno)website/loaders/secret.ts:

const getSecret = async (props: Props): Promise<string | null> => {
  if (name && Deno.env.has(name)) return Deno.env.get(name)!;
  // ...
  return moduleCache[encrypted] ??= decryptFromHex(encrypted).then(d => d.decrypted);
};

Decripta de fato — decryptFromHex usa DECO_CRYPTO_KEY.

@decocms/apps-startwebsite/loaders/secret.ts:

const getSecret = (props: Props): string | null => {
  if (name && process.env[name] !== undefined) return process.env[name]!;
  // ...
  if (process.env.NODE_ENV !== "production") console.warn(...);
  return encrypted;  // ← devolve o hex sem decriptar!
};

Só lê env var. Devolve o hex sem decriptar (o consumidor não tem como saber que é encrypted e não plaintext).

@decocms/start/sdk/crypto.tsresolveSecret:

export async function resolveSecret(value: unknown, envVarName?: string): Promise<string | null> {
  if (typeof value === "string" && value.length > 0) return value;
  if (value && typeof value === "object") {
    if (typeof obj.get === "function") { /* old Secret loader pattern */ }
    if (typeof obj.encrypted === "string") {
      const decrypted = await decryptSecret(obj.encrypted);
      if (decrypted) return decrypted;
    }
  }
  if (envVarName) return process.env[envVarName] ?? null;
  return null;
}

Faz tudo certo — decripta, faz fallback, cacheia.

Proposta

  1. Substituir website/loaders/secret.ts em apps-start por uma versão que chama resolveSecret do framework e expõe a interface Secret { get() } por compat com call sites legados.
  2. Migrar magento/client.ts:resolveSecret interno pra delegar pro framework — mesma função, com decrypt grátis.
  3. Mesma migração para algolia/client.ts (PR feat(algolia)!: migrate to algoliasearch v5 for CF Workers compat #69 / feat(algolia): initial scaffold port from deco-cx/apps #66 follow-up).
  4. (Opcional) Remover website/actions/secrets/encrypt.ts do roadmap de port — admin de criação de segredos roda no painel decocms, não precisa estar no client storefront.

Impacto

Desbloqueia sites em CF Workers que dependem só do DECO_CRYPTO_KEY env var (já setado nos deploys do decocms) sem precisar setar cada secret name individualmente. Em granadobr-tanstack: MAGENTO_API_KEY, ORIGIN_HEADER, ADMIN_KEY (algolia) — todos viriam decriptados automaticamente.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions