Python & TypeScript · one contract, many providers
Python & TypeScript · um contrato, muitos cofres
Secret vault,
quick and easy.
Ler segredos,
rápido e fácil.
Your code asks for database/password. Whether that lives in AWS Secrets Manager, GCP Parameter Manager or a dictionary in a test does not change the call — only which distribution you install.
Seu código pede database/password. Se isso mora no AWS Secrets Manager, no GCP Parameter Manager ou num dicionário de teste, a chamada não muda — muda apenas qual distribuição você instala.
from secret_kernel.factory import ( CreateSecretClientConfig, create_secret_client, ) from secret_kernel.provider_aws_parameter_store import ( AwsParameterStoreProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="aws-parameter-store", env="prod", project="billing", options=AwsParameterStoreProviderOptions( region="us-east-1", ), ) ) secret = await client.get_secret("database/password") # secret.value — reads /prod/billing/database/password
import { SecretProvider, createSecretClient, } from '@secret-kernel/factory'; const client = await createSecretClient({ provider: SecretProvider.AwsParameterStore, env: 'prod', project: 'billing', options: { region: 'us-east-1' }, }); const secret = await client.getSecret('database/password'); // secret.value — reads /prod/billing/database/password
Why use Secret Kernel
Por que usar o Secret Kernel
One contract in front of five providers, and what that buys you.
Um contrato na frente de cinco cofres (no código, o provider), e o que você ganha com isso.
- Ask by name, get the value. One call returns the decrypted secret. There is no provider SDK to learn.
- Every provider behaves the same. The naming rules, the per-call options and the errors do not change with the provider: a missing secret is
SecretNotFoundError, codescrt_not_found, on AWS, on GCP and in memory. All five pass the same contract test suite. - Change providers, not code. Moving from AWS to GCP changes the provider, its options and the installed package. Every
get_secretgetSecretcall stays as written. - Tests without the cloud. The
in-memoryprovider follows the same contract, so tests and CI make the same calls the service makes, with no network and no credentials. - Python and TypeScript, one contract. Each follows its own convention —
get_secret,getSecret— and both share the behavior, the defaults and the error codes.
- Peça pelo nome, receba o valor. Uma chamada devolve o segredo já descriptografado. Não há SDK de cofre para aprender.
- Todo cofre se comporta igual. As regras de nome, as opções por chamada e os erros não mudam com o cofre: um segredo ausente é
SecretNotFoundError, códigoscrt_not_found, na AWS, no GCP e em memória. Os cinco passam pela mesma suíte de testes de contrato. - Troque o cofre, não o código. Sair da AWS para o GCP muda o cofre, suas opções e o pacote instalado. Toda chamada a
get_secretgetSecretcontinua como foi escrita. - Testes sem nuvem. O cofre
in-memorysegue o mesmo contrato, então testes e CI fazem as mesmas chamadas que o serviço, sem rede e sem credencial. - Python e TypeScript, um contrato. Cada um segue a convenção da sua linguagem —
get_secret,getSecret— e os dois compartilham comportamento, defaults e códigos de erro.
from secret_kernel.contracts import SecretNotFoundError from secret_kernel.factory import ( CreateSecretClientConfig, create_secret_client, ) from secret_kernel.provider_aws_parameter_store import ( AwsParameterStoreProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="aws-parameter-store", env="prod", project="billing", options=AwsParameterStoreProviderOptions( region="us-east-1", ), ) ) try: secret = await client.get_secret("database/password") except SecretNotFoundError as error: error.code # "scrt_not_found", on any provider
from secret_kernel.contracts import SecretNotFoundError from secret_kernel.factory import ( CreateSecretClientConfig, create_secret_client, ) from secret_kernel.provider_gcp_parameter_manager import ( GcpParameterManagerProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="gcp-parameter-manager", env="prod", project="billing", options=GcpParameterManagerProviderOptions( project_id="my-gcp-project", ), ) ) try: secret = await client.get_secret("database/password") except SecretNotFoundError as error: error.code # "scrt_not_found", on any provider
from secret_kernel.contracts import SecretNotFoundError from secret_kernel.factory import ( CreateSecretClientConfig, create_secret_client, ) from secret_kernel.provider_in_memory import ( InMemoryProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="in-memory", env="prod", project="billing", options=InMemoryProviderOptions( env_secrets=True, ), ) ) def load_env() -> None: # .env # SECRET_KERNEL_PROD_BILLING_DATABASE_PASSWORD=s3cr3t # SECRET_KERNEL_PROD_BILLING_API_TOKEN=local-token from dotenv import load_dotenv load_dotenv() try: load_env() secret = await client.get_secret("database/password") except SecretNotFoundError as error: error.code # "scrt_not_found", on any provider
import { SecretNotFoundError } from '@secret-kernel/contracts'; import { SecretProvider, createSecretClient, } from '@secret-kernel/factory'; const client = await createSecretClient({ provider: SecretProvider.AwsParameterStore, env: 'prod', project: 'billing', options: { region: 'us-east-1' }, }); try { const secret = await client.getSecret('database/password'); } catch (error) { if (error instanceof SecretNotFoundError) { error.code; // 'scrt_not_found', on any provider } }
import { SecretNotFoundError } from '@secret-kernel/contracts'; import { SecretProvider, createSecretClient, } from '@secret-kernel/factory'; const client = await createSecretClient({ provider: SecretProvider.GcpParameterManager, env: 'prod', project: 'billing', options: { projectId: 'my-gcp-project' }, }); try { const secret = await client.getSecret('database/password'); } catch (error) { if (error instanceof SecretNotFoundError) { error.code; // 'scrt_not_found', on any provider } }
import { SecretNotFoundError } from '@secret-kernel/contracts'; import { SecretProvider, createSecretClient, } from '@secret-kernel/factory'; const client = await createSecretClient({ provider: SecretProvider.InMemory, env: 'prod', project: 'billing', options: { envSecrets: true }, }); function loadEnv() { // .env // SECRET_KERNEL_PROD_BILLING_DATABASE_PASSWORD=s3cr3t // SECRET_KERNEL_PROD_BILLING_API_TOKEN=local-token process.loadEnvFile(); } try { loadEnv(); const secret = await client.getSecret('database/password'); } catch (error) { if (error instanceof SecretNotFoundError) { error.code; // 'scrt_not_found', on any provider } }
Install and first read
Instalação e primeira leitura
Nothing is bundled. Install the contract, the shared core, the factory and the one provider you need.
Nada vem embutido. Instale o contrato, o core compartilhado, a factory e o pacote do único cofre de que você precisa.
Step 1 · install the base
Passo 1 · instale a base
The contract, the shared core and the factory. No provider yet — that is step 2, and it is a separate distribution so an AWS-only service never pulls a GCP SDK.
O contrato, o core compartilhado e a factory. Nenhum cofre ainda — isso é o passo 2, e ele é uma distribuição separada, então um serviço só-AWS nunca baixa um SDK do GCP.
contracts depends on nothing. A consumer that only declares types or catches errors installs that one package alone.
contracts não depende de nada. Quem só declara tipos ou captura erros instala apenas esse pacote.
$ uv add secret-kernel-contracts secret-kernel-core \
secret-kernel-factory
$ npm install @secret-kernel/contracts @secret-kernel/core \
@secret-kernel/factory
Step 2 · add a provider and read
Passo 2 · adicione um cofre e leia
Pick where the secret lives. The call is identical on all five — only the provider alias and its typed options change, which is the whole point of the contract.
Escolha onde o segredo mora. A chamada é idêntica nos cinco — mudam apenas o alias do cofre e suas opções tipadas, que é justamente o propósito do contrato.
For local development, CI and tests. Reads preloaded values or environment variables, so nothing needs a cloud account.
Para desenvolvimento local, CI e testes. Lê valores pré-carregados ou variáveis de ambiente, então nada precisa de conta em nuvem.
With env_secretsenvSecrets, the key is the resolved name without the leading slash, non-alphanumerics replaced by _, uppercased and prefixed: /dev/my-app/database becomes SECRET_KERNEL_DEV_MY_APP_DATABASE. Preloaded secrets win over the environment.
Com env_secretsenvSecrets, a chave é o nome resolvido sem a barra inicial, não-alfanuméricos trocados por _, em maiúsculas e com prefixo: /dev/my-app/database vira SECRET_KERNEL_DEV_MY_APP_DATABASE. Segredos pré-carregados vencem o ambiente.
$ uv add secret-kernel-provider-in-memory
$ npm install @secret-kernel/provider-in-memory
from secret_kernel.contracts import SecretNotFoundError from secret_kernel.factory import ( CreateSecretClientConfig, create_secret_client, ) from secret_kernel.provider_in_memory import ( InMemoryProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="in-memory", env="prod", project="billing", options=InMemoryProviderOptions( env_secrets=True, ), ) ) def load_env() -> None: # .env # SECRET_KERNEL_PROD_BILLING_DATABASE_PASSWORD=s3cr3t # SECRET_KERNEL_PROD_BILLING_API_TOKEN=local-token from dotenv import load_dotenv load_dotenv() try: load_env() secret = await client.get_secret("database/password") except SecretNotFoundError as error: error.code # "scrt_not_found", on any provider
import { SecretNotFoundError } from '@secret-kernel/contracts'; import { SecretProvider, createSecretClient, } from '@secret-kernel/factory'; const client = await createSecretClient({ provider: SecretProvider.InMemory, env: 'prod', project: 'billing', options: { envSecrets: true }, }); function loadEnv() { // .env // SECRET_KERNEL_PROD_BILLING_DATABASE_PASSWORD=s3cr3t // SECRET_KERNEL_PROD_BILLING_API_TOKEN=local-token process.loadEnvFile(); } try { loadEnv(); const secret = await client.getSecret('database/password'); } catch (error) { if (error instanceof SecretNotFoundError) { error.code; // 'scrt_not_found', on any provider } }
For low-cost secrets in AWS. Reads SecureString parameters.
Para segredos de baixo custo na AWS. Lê parâmetros SecureString.
Pass credentials to be explicit, or leave it out and the AWS SDK's own chain applies. Explicit credentials take precedence.
Passe credentials para ser explícito, ou omita e a própria cadeia do SDK da AWS se aplica. Credenciais explícitas têm precedência.
$ uv add secret-kernel-provider-aws-parameter-store
$ npm install @secret-kernel/provider-aws-parameter-store
from secret_kernel.contracts import SecretNotFoundError from secret_kernel.factory import ( CreateSecretClientConfig, create_secret_client, ) from secret_kernel.provider_aws_parameter_store import ( AwsCredentials, AwsParameterStoreProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="aws-parameter-store", env="prod", project="billing", options=AwsParameterStoreProviderOptions( region="us-east-1", credentials=AwsCredentials( access_key_id="AKIAIOSFODNN7EXAMPLE", secret_access_key=( "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" ), ), ), ) ) try: secret = await client.get_secret("database/password") # reads /prod/billing/database/password except SecretNotFoundError as error: error.code # "scrt_not_found", on any provider
import { SecretNotFoundError } from '@secret-kernel/contracts'; import { SecretProvider, createSecretClient, } from '@secret-kernel/factory'; const client = await createSecretClient({ provider: SecretProvider.AwsParameterStore, env: 'prod', project: 'billing', options: { region: 'us-east-1', credentials: { accessKeyId: 'AKIAIOSFODNN7EXAMPLE', secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', }, }, }); try { const secret = await client.getSecret('database/password'); // reads /prod/billing/database/password } catch (error) { if (error instanceof SecretNotFoundError) { error.code; // 'scrt_not_found', on any provider } }
For AWS secrets that need rotation and a dedicated lifecycle. Reads the AWSCURRENT stage.
Para segredos da AWS que precisam de rotação e ciclo de vida próprio. Lê o estágio AWSCURRENT.
Same options as aws-parameter-store. A binary-only secret raises SecretCapabilityNotSupportedError: binary payloads are outside the base contract.
Mesmas opções do aws-parameter-store. Um segredo apenas binário levanta SecretCapabilityNotSupportedError: payloads binários ficam fora do contrato base.
$ uv add secret-kernel-provider-aws-secrets-manager
$ npm install @secret-kernel/provider-aws-secrets-manager
from secret_kernel.contracts import SecretNotFoundError from secret_kernel.factory import ( CreateSecretClientConfig, create_secret_client, ) from secret_kernel.provider_aws_secrets_manager import ( AwsCredentials, AwsSecretsManagerProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="aws-secrets-manager", env="prod", project="billing", options=AwsSecretsManagerProviderOptions( region="us-east-1", credentials=AwsCredentials( access_key_id="AKIAIOSFODNN7EXAMPLE", secret_access_key=( "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" ), ), ), ) ) try: secret = await client.get_secret("database/password") # reads /prod/billing/database/password, stage AWSCURRENT except SecretNotFoundError as error: error.code # "scrt_not_found", on any provider
import { SecretNotFoundError } from '@secret-kernel/contracts'; import { SecretProvider, createSecretClient, } from '@secret-kernel/factory'; const client = await createSecretClient({ provider: SecretProvider.AwsSecretsManager, env: 'prod', project: 'billing', options: { region: 'us-east-1', credentials: { accessKeyId: 'AKIAIOSFODNN7EXAMPLE', secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', }, }, }); try { const secret = await client.getSecret('database/password'); // reads /prod/billing/database/password, stage AWSCURRENT } catch (error) { if (error instanceof SecretNotFoundError) { error.code; // 'scrt_not_found', on any provider } }
For low-cost secrets in GCP. Reads the rendered payload of the latest version.
Para segredos de baixo custo no GCP. Lê o payload renderizado da última versão.
project_idprojectId has no default; location defaults to global. GCP does not accept / in a name, so the resolved name is joined with _.
project_idprojectId não tem padrão; location tem padrão global. O GCP não aceita / num nome, então o nome resolvido é unido com _.
credentials is the service account key file, as Google ships it. Leave it out and the Google SDK's own defaults apply.
credentials é o arquivo de chave da service account, como o Google o entrega. Omita e os próprios padrões do SDK do Google se aplicam.
$ uv add secret-kernel-provider-gcp-parameter-manager
$ npm install @secret-kernel/provider-gcp-parameter-manager
import json from pathlib import Path from secret_kernel.contracts import SecretNotFoundError from secret_kernel.factory import ( CreateSecretClientConfig, create_secret_client, ) from secret_kernel.provider_gcp_parameter_manager import ( GcpParameterManagerProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="gcp-parameter-manager", env="prod", project="billing", options=GcpParameterManagerProviderOptions( project_id="my-gcp-project", credentials=json.loads( Path("service-account.json").read_text() ), ), ) ) try: secret = await client.get_secret("database/password") # reads projects/my-gcp-project/locations/global/ # parameters/prod_billing_database_password/ # versions/latest except SecretNotFoundError as error: error.code # "scrt_not_found", on any provider
import { readFileSync } from 'node:fs'; import { SecretNotFoundError } from '@secret-kernel/contracts'; import { SecretProvider, createSecretClient, } from '@secret-kernel/factory'; const client = await createSecretClient({ provider: SecretProvider.GcpParameterManager, env: 'prod', project: 'billing', options: { projectId: 'my-gcp-project', credentials: JSON.parse( readFileSync('service-account.json', 'utf8'), ), }, }); try { const secret = await client.getSecret('database/password'); // reads projects/my-gcp-project/locations/global/ // parameters/prod_billing_database_password/ // versions/latest } catch (error) { if (error instanceof SecretNotFoundError) { error.code; // 'scrt_not_found', on any provider } }
For GCP secrets that need rotation and a dedicated lifecycle. Reads the latest version.
Para segredos do GCP que precisam de rotação e ciclo de vida próprio. Lê a última versão.
project_idprojectId has no default. GCP does not accept / in a name, so the resolved name is joined with _.
project_idprojectId não tem padrão. O GCP não aceita / num nome, então o nome resolvido é unido com _.
credentials is the service account key file, as Google ships it. Leave it out and the Google SDK's own defaults apply.
credentials é o arquivo de chave da service account, como o Google o entrega. Omita e os próprios padrões do SDK do Google se aplicam.
$ uv add secret-kernel-provider-gcp-secret-manager
$ npm install @secret-kernel/provider-gcp-secret-manager
import json from pathlib import Path from secret_kernel.contracts import SecretNotFoundError from secret_kernel.factory import ( CreateSecretClientConfig, create_secret_client, ) from secret_kernel.provider_gcp_secret_manager import ( GcpSecretManagerProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="gcp-secret-manager", env="prod", project="billing", options=GcpSecretManagerProviderOptions( project_id="my-gcp-project", credentials=json.loads( Path("service-account.json").read_text() ), ), ) ) try: secret = await client.get_secret("database/password") # reads projects/my-gcp-project/secrets/ # prod_billing_database_password/versions/latest except SecretNotFoundError as error: error.code # "scrt_not_found", on any provider
import { readFileSync } from 'node:fs'; import { SecretNotFoundError } from '@secret-kernel/contracts'; import { SecretProvider, createSecretClient, } from '@secret-kernel/factory'; const client = await createSecretClient({ provider: SecretProvider.GcpSecretManager, env: 'prod', project: 'billing', options: { projectId: 'my-gcp-project', credentials: JSON.parse( readFileSync('service-account.json', 'utf8'), ), }, }); try { const secret = await client.getSecret('database/password'); // reads projects/my-gcp-project/secrets/ // prod_billing_database_password/versions/latest } catch (error) { if (error instanceof SecretNotFoundError) { error.code; // 'scrt_not_found', on any provider } }
How a name is built
Como um nome é montado
A secret name is joined from what the client knows and what the call asks for.
O nome do segredo é montado a partir do que o client sabe e do que a chamada pede.
client = create_secret_client( CreateSecretClientConfig( provider="aws-parameter-store", env="prod", project="billing", ) ) secret = await client.get_secret("database/password") # reads /prod/billing/database/password
const client = await createSecretClient({ provider: SecretProvider.AwsParameterStore, env: 'prod', project: 'billing', }); const secret = await client.getSecret('database/password'); // reads /prod/billing/database/password
/prod /billing /— /database/password /prod/billing/database/password
All three leading parts are optional: a client with none of them reads /database/password.
As três primeiras partes são opcionais: um client sem nenhuma delas lê /database/password.
| Part | Parte | Optional | Opcional | Accepts a slash | Aceita barra | Rule | Regra |
|---|---|---|---|---|---|---|---|
env |
Yes | Sim | No | Não | The deployment context — prod, staging. A single segment. A slash here would silently add a level, and the caller would only find out through a secret that cannot be found. |
O contexto de deploy — prod, staging. Um único segmento. Uma barra aqui adicionaria um nível silenciosamente, e quem chamou só descobriria por um segredo que não é encontrado. |
|
project |
Yes | Sim | No | Não | Groups a set of secrets, usually one service or application. Same rule as env. |
Agrupa um conjunto de segredos, normalmente um serviço ou aplicação. Mesma regra do env. |
|
prefix |
Yes | Sim | Yes | Sim | Adds any further levels you want. A string or a list of segments. A per-call prefix replaces the client's rather than adding to it. | Adiciona quantos níveis você quiser. Uma string ou uma lista de segmentos. Um prefix por chamada substitui o do client em vez de somar a ele. | |
name | name |
No | Não | Yes | Sim | What the call asks for. Accepts /, because adding levels is exactly what it is for. |
O que a chamada pede. Aceita /, porque adicionar níveis é exatamente para isso que serve. |
Always use / as the separator
Use sempre / como separador
When you want separators in a name or a prefix — they are not required — use /, whatever the provider. One convention in your code, and nothing to rename when the provider changes. Each provider then converts the resolved name into the form its service accepts.
Quando quiser usar separadores no nome ou no prefix — eles não são obrigatórios —, use /, seja qual for o cofre. Assim o seu código escreve os nomes de um jeito só, e nada precisa ser renomeado quando você troca de cofre. Cada cofre então converte o nome resolvido para o formato que o seu serviço aceita.
GCP does not accept / in a secret or parameter ID, so both GCP providers drop the leading slash and join the levels with _. AWS takes the name as it is.
O GCP não aceita / no ID de um segredo ou parâmetro, então os dois cofres do GCP removem a barra inicial e juntam os níveis com _. A AWS recebe o nome como ele é.
your code seu código /prod/billing/database/password aws-secrets-manager /prod/billing/database/password aws-parameter-store /prod/billing/database/password gcp-secret-manager prod_billing_database_password gcp-parameter-manager prod_billing_database_password
The separator a provider uses in its service is a provider option, physical_name_separatorphysicalNameSeparator — GCP also accepts -, AWS also _ and -. A naming convention that is not the kernel's goes through resolve_nameresolveName on the GCP providers. See Providers.
O separador que cada cofre usa é uma opção dele, physical_name_separatorphysicalNameSeparator — o GCP também aceita -, a AWS também _ e -. Uma convenção de nomes que não é a do kernel passa por resolve_nameresolveName nos cofres do GCP. Veja Cofres.
Changing the name for one call
Mudando o nome para uma chamada
Each of the three client-level parts can be dropped, and each can be replaced.
Cada uma das três partes do nível do client pode ser derrubada, e cada uma pode ser substituída.
Omitting always wins over replacing. Passing both omit_projectomitProject and project drops the segment.
Omitir sempre vence substituir. Passar omit_projectomitProject e project juntos derruba o segmento.
Replacing env is never implicit: the client's value applies unless a call says otherwise, in that call alone. It exists for the caller who knows better than the process context — a local run reading the one secret that lives elsewhere.
Substituir o env nunca é implícito: o valor do client vale a menos que uma chamada diga o contrário, e só naquela chamada. Existe para quem chama e sabe mais que o contexto do processo — uma execução local lendo o único segredo que mora em outro lugar.
from secret_kernel.contracts import GetSecretOptions # /prod/billing/database — the client prefix is left out await client.get_secret( "database", GetSecretOptions(omit_prefix=True) ) # /prod/shared/api-key — read another project's secret await client.get_secret( "api-key", GetSecretOptions(project="shared") ) # /staging/billing/database/password — another environment, once await client.get_secret( "database/password", GetSecretOptions(env="staging") ) # /license-key — belongs to no environment or project await client.get_secret( "license-key", GetSecretOptions(omit_env=True, omit_project=True), )
// /prod/billing/database — the client prefix is left out await client.getSecret('database', { omitPrefix: true }); // /prod/shared/api-key — read another project's secret await client.getSecret('api-key', { project: 'shared' }); // /staging/billing/database/password — another environment, once await client.getSecret('database/password', { env: 'staging' }); // /license-key — belongs to no environment or project await client.getSecret('license-key', { omitEnv: true, omitProject: true, });
Reading structured secrets
Lendo segredos estruturados
A secret is a string by default. Ask for a parse mode and the value follows.
Um segredo é uma string por padrão. Peça um modo de parse e o valor será convertido.
Parse modes
Modos de parse
Two modes: JSON and KEY_VALUE. Keys and values are trimmed by default.
Dois modos: JSON e KEY_VALUE. Chaves e valores têm espaços removidos por padrão.
A secret that exists but cannot be parsed raises SecretParseError; parse results are never cached.
Um segredo que existe mas não pode ser parseado levanta SecretParseError; resultados de parse nunca são cacheados.
from secret_kernel.contracts import ( GetSecretOptions, SecretParseMode, ) # "s3cr3t" plain = await client.get_secret("database/password") # {"host": "db.internal", "port": 5432} config = await client.get_secret( "database/config", GetSecretOptions(parse=SecretParseMode.JSON) ) # {"user": "app", "password": "s3cr3t"} # from "user=app;password=s3cr3t" pairs = await client.get_secret( "database/credentials", GetSecretOptions(parse=SecretParseMode.KEY_VALUE), )
import { SecretParseMode } from '@secret-kernel/contracts'; // "s3cr3t" const plain = await client.getSecret('database/password'); // { host: 'db.internal', port: 5432 } type DbConfig = { host: string; port: number }; const config = await client.getSecret<DbConfig>( 'database/config', { parse: SecretParseMode.Json }, ); // { user: 'app', password: 's3cr3t' } // from "user=app;password=s3cr3t" const pairs = await client.getSecret( 'database/credentials', { parse: SecretParseMode.KeyValue }, );
Key-value conventions
Convenções chave-valor
If a project always stores key-value secrets the same way, set the convention once on the client instead of repeating it at every call.
Se um projeto sempre guarda segredos chave-valor do mesmo jeito, defina a convenção uma vez no client em vez de repeti-la em cada chamada.
A per-call parse_optionsparseOptions is merged over the client's field by field, so a call that needs one different separator does not have to restate the others.
Um parse_optionsparseOptions por chamada é mesclado sobre o do client campo por campo, então uma chamada que precisa de um separador diferente não precisa repetir os outros.
| Field | Campo | Default | Padrão |
|---|---|---|---|
pair_separatorpairSeparator | ";" | ||
key_value_separatorkeyValueSeparator | "=" | ||
keys | empty — names positional values that carry no separator | vazio — nomeia valores posicionais que não trazem separador | |
trim | Truetrue |
Empty pairs are ignored, empty values are kept as "", an empty key raises, and a repeated key keeps the last value.
Pares vazios são ignorados, valores vazios são mantidos como "", uma chave vazia levanta erro, e uma chave repetida mantém o último valor.
from secret_kernel.contracts import KeyValueParseOptions client = create_secret_client( CreateSecretClientConfig( provider="aws-parameter-store", env="prod", parse_options=KeyValueParseOptions( pair_separator="|", key_value_separator=":", ), options=AwsParameterStoreProviderOptions( region="us-east-1", ), ) ) # only the pair separator differs here; ":" is inherited await client.get_secret( "legacy", GetSecretOptions( parse=SecretParseMode.KEY_VALUE, parse_options=KeyValueParseOptions(pair_separator=";"), ), )
const client = await createSecretClient({ provider: SecretProvider.AwsParameterStore, env: 'prod', parseOptions: { pairSeparator: '|', keyValueSeparator: ':', }, options: { region: 'us-east-1' }, }); // only the pair separator differs here; ':' is inherited await client.getSecret('legacy', { parse: SecretParseMode.KeyValue, parseOptions: { pairSeparator: ';' }, });
Five providers, one call
Cinco cofres, uma chamada
Provider options are typed per provider and never leak into the shared contract.
As opções são tipadas por cofre e nunca vazam para o contrato compartilhado.
| Provider | Cofre | Distribution | Distribuição | Use for | Usar para |
|---|---|---|---|---|---|
in-memory |
secret-kernel-provider-in-memory@secret-kernel/provider-in-memory |
Local development, CI and tests. Reads preloaded values or environment variables. | Desenvolvimento local, CI e testes. Lê valores pré-carregados ou variáveis de ambiente. | ||
aws-parameter-store |
secret-kernel-provider-aws-parameter-store@secret-kernel/provider-aws-parameter-store |
Low-cost secrets in AWS, as SecureString parameters. |
Segredos de baixo custo na AWS, como parâmetros SecureString. |
||
aws-secrets-manager |
secret-kernel-provider-aws-secrets-manager@secret-kernel/provider-aws-secrets-manager |
AWS secrets that need rotation and a dedicated lifecycle. Reads the AWSCURRENT stage; a binary-only secret raises SecretCapabilityNotSupportedError. |
Segredos da AWS que precisam de rotação e ciclo de vida próprio. Lê o estágio AWSCURRENT; um segredo apenas binário levanta SecretCapabilityNotSupportedError. |
||
gcp-parameter-manager |
secret-kernel-provider-gcp-parameter-manager@secret-kernel/provider-gcp-parameter-manager |
Low-cost secrets in GCP. Takes a location, defaulting to global. |
Segredos de baixo custo no GCP. Recebe um location, com padrão global. |
||
gcp-secret-manager |
secret-kernel-provider-gcp-secret-manager@secret-kernel/provider-gcp-secret-manager |
GCP secrets that need rotation and a dedicated lifecycle. | Segredos do GCP que precisam de rotação e ciclo de vida próprio. |
Defaults
Padrões
region on both AWS providers defaults to us-east-1. The default is the kernel's, not the SDK's: AWS_REGION and the AWS profile are not consulted, so pass the region you mean. location on GCP Parameter Manager defaults to global. project_idprojectId on both GCP providers has no default.
region nos dois cofres da AWS tem padrão us-east-1. O padrão é do kernel, não do SDK: AWS_REGION e o perfil da AWS não são consultados, então passe a região que você quer. location no GCP Parameter Manager tem padrão global. project_idprojectId nos dois cofres do GCP não tem padrão.
A value you pass must say something. Noneundefined or blank text raises SecretKernelConfigurationError instead of falling back to the default, so an unset environment variable fails when the client is built rather than reading from the wrong place.
Um valor que você passa precisa dizer algo. Noneundefined ou texto em branco levanta SecretKernelConfigurationError em vez de cair no padrão, então uma variável de ambiente não definida falha quando o client é construído, e não lendo do lugar errado.
Credentials
Credenciais
Credentials are explicit when you pass them, and fall back to the cloud SDK's own chain when you do not. Explicit credentials take precedence.
As credenciais são explícitas quando você as passa, e caem para a própria cadeia do SDK da nuvem quando você não passa. Credenciais explícitas têm precedência.
Injecting a client keeps the SDK client under your lifecycle — the kernel closes only what it created.
Injetar um client mantém o client do SDK sob o seu ciclo de vida — o kernel fecha apenas o que ele mesmo criou.
Providers that cannot store / flatten the resolved name with a separator: AWS accepts /, _ and - and defaults to /; GCP accepts _ and - and defaults to _.
Cofres que não conseguem guardar / achatam o nome resolvido com um separador: a AWS aceita /, _ e - e usa / como padrão; o GCP aceita _ e - e usa _.
from secret_kernel.provider_gcp_secret_manager import ( GcpSecretManagerProviderOptions, ) client = create_secret_client( CreateSecretClientConfig( provider="gcp-secret-manager", env="prod", project="billing", options=GcpSecretManagerProviderOptions( project_id="my-gcp-project", physical_name_separator="_", ), ) ) # reads projects/my-gcp-project/secrets/ # prod_billing_database_password/versions/latest
const client = await createSecretClient({ provider: SecretProvider.GcpSecretManager, env: 'prod', project: 'billing', options: { projectId: 'my-gcp-project', physicalNameSeparator: '_', }, }); // reads projects/my-gcp-project/secrets/ // prod_billing_database_password/versions/latest
Caching
Cache
Reads hit the provider every time unless you enable the cache.
As leituras vão ao cofre todas as vezes, a menos que você habilite o cache.
The cache stores the decrypted string keyed by the resolved name, before any parsing, so the same secret read as JSON and as text costs one provider call.
O cache guarda a string descriptografada chaveada pelo nome resolvido, antes de qualquer parse, então o mesmo segredo lido como JSON e como texto custa uma chamada ao cofre.
A value served from cache reports no version and no metadata: the cache stores the string only.
Um valor servido do cache não reporta version nem metadata: o cache guarda apenas a string.
Failures are never cached. A missing secret that appears later is found on the next read.
Falhas nunca são cacheadas. Um segredo ausente que aparece depois é encontrado na leitura seguinte.
Encryption in memory
Criptografia em memória
For a process that holds secrets in memory for a long time, cached values can be encrypted with AES-256-GCM. Without an encryption_keyencryptionKey the client generates one and keeps it in memory only.
Para um processo que mantém segredos em memória por muito tempo, os valores cacheados podem ser criptografados com AES-256-GCM. Sem uma encryption_keyencryptionKey, o client gera uma e a mantém apenas em memória.
What it protects against: a heap snapshot, or an accidental object dump. What it does not: code running inside the same process.
Contra o que protege: um snapshot de heap, ou um dump acidental de objeto. Contra o que não protege: código rodando dentro do mesmo processo.
from secret_kernel.contracts import SecretCacheOptions client = create_secret_client( CreateSecretClientConfig( provider="aws-secrets-manager", env="prod", cache=SecretCacheOptions( enabled=True, ttl_ms=300_000, max_entries=100, encrypt_in_memory=True, ), options=AwsSecretsManagerProviderOptions( region="us-east-1", ), ) )
const client = await createSecretClient({ provider: SecretProvider.AwsSecretsManager, env: 'prod', cache: { enabled: true, ttlMs: 300_000, maxEntries: 100, encryptInMemory: true, }, options: { region: 'us-east-1' }, });
Errors are part of the contract
Erros fazem parte do contrato
Every error carries name, code, provider, secret_namesecretName, provider_codeproviderCode and cause.
Todo erro carrega name, code, provider, secret_namesecretName, provider_codeproviderCode e cause.
Three fields identify a failure, and each answers a different question. name is the class, and moves when the class is renamed. code is the kernel's own — scrt_not_found — frozen, always present, and spelled the same in both languages. provider_codeproviderCode is the vendor's — AccessDeniedException on AWS, PERMISSION_DENIED on GCP — and is there only when the SDK gave one.
Três campos identificam uma falha, e cada um responde a uma pergunta diferente. name é a classe, e muda quando a classe é renomeada. code é do próprio kernel — scrt_not_found — congelado, sempre presente e escrito igual nas duas linguagens. provider_codeproviderCode é do fornecedor — AccessDeniedException na AWS, PERMISSION_DENIED no GCP — e só existe quando o SDK deu um.
Catch by class inside your own process. Compare code at a boundary, where a partner writes the string into a comparison of their own and a renamed class would break them in silence.
Capture pela classe dentro do seu próprio processo. Compare code numa fronteira, onde um parceiro escreve a string numa comparação dele e uma classe renomeada o quebraria em silêncio.
Only not-found and permission are normalized. Every other failure keeps the message the SDK produced and gains provider, secret_namesecretName and, when the SDK offered one, provider_codeproviderCode, with the original error in cause.
Só não-encontrado e permissão são normalizados. Toda outra falha preserva a mensagem que o SDK produziu e ganha provider, secret_namesecretName e, quando o SDK ofereceu um, provider_codeproviderCode, com o erro original em cause.
A normalized message names the provider and the secret twice: the name your code asked for, and in parentheses the ID the provider looked up — on GCP, the one to search for in the console.
Uma mensagem normalizada nomeia o cofre e nomeia o segredo duas vezes: o nome que o seu código pediu e, entre parênteses, o ID que o cofre procurou — no GCP, o que você busca no console.
from secret_kernel.contracts import ( SecretKernelError, SecretNotFoundError, ) try: secret = await client.get_secret("database/password") except SecretNotFoundError: # in your process: the class secret = None except SecretKernelError as error: # at a boundary: the code respond(503, {"code": error.code}) # a missing secret, env "prod", on GCP # str(error) Secret not found in gcp-secret-manager: # database/password (full name: # prod_database_password) # error.name SecretNotFoundError # error.code scrt_not_found # error.secret_name database/password
import { SecretKernelError, SecretNotFoundError, } from '@secret-kernel/contracts'; let secret; try { secret = await client.getSecret('database/password'); } catch (error) { if (error instanceof SecretNotFoundError) { // in your process: the class secret = undefined; } else if (error instanceof SecretKernelError) { // at a boundary: the code respond(503, { code: error.code }); } else { throw error; } } // a missing secret, env 'prod', on GCP // error.message Secret not found in gcp-secret-manager: // database/password (full name: // prod_database_password) // error.name SecretNotFoundError // error.code scrt_not_found // error.secretName database/password
| Class | Classe | Code | Código | Raised when | Levantado quando |
|---|---|---|---|---|---|
SecretNotFoundError | scrt_not_found | The secret or parameter does not exist. | O segredo ou parâmetro não existe. | ||
SecretPermissionError | scrt_permission_denied | The provider refused the read. | O cofre recusou a leitura. | ||
SecretParseError | scrt_parse_failed | The secret was read but the requested parse failed. | O segredo foi lido, mas o parse pedido falhou. | ||
InvalidSecretNameError | scrt_invalid_name | The resolved name is empty or unusable. | O nome resolvido está vazio ou inutilizável. | ||
SecretCapabilityNotSupportedError | scrt_capability_not_supported | The provider cannot serve the request under the base contract. | O cofre não consegue atender ao pedido dentro do contrato base. | ||
SecretKernelConfigurationError | scrt_invalid_configuration | Required, invalid or mutually exclusive configuration. | Configuração obrigatória, inválida ou mutuamente exclusiva. | ||
SecretProviderError | scrt_unexpected | Any other provider failure. | Qualquer outra falha do cofre. |
Observability, and your own provider
Observabilidade, e seu próprio cofre
Silent until you attach a logger, and open to a provider the kernel has never heard of.
Silencioso até você anexar um logger, e aberto a um cofre que o kernel nunca viu.
Logging
Logs
Pass a logger and the client writes one plain sentence per event: the secret it is reading, a cache hit or miss, a missing secret at warningwarn, and a refused or failed read at error, carrying the error's own message. No line carries the secret value.
Passe um logger e o client escreve uma frase simples por evento: o segredo que está lendo, um acerto ou falta no cache, um segredo ausente em warningwarn, e uma leitura recusada ou que falhou em error, com a mensagem do próprio erro. Nenhuma linha carrega o valor do segredo.
One string per call, so the standard logger fits as it is — logging.getLogger(...)console, with no adapter.
Uma string por chamada, então o logger padrão serve como está — logging.getLogger(...)console, sem adapter.
The logger is the only sink. Without one the client is silent: there is no debug flag and no console fallback, because where a line lands and what it may expose belongs to the application that attached the logger. A level your logger does not implement is dropped, never raised.
O logger é o único destino. Sem ele, o client fica em silêncio: não existe flag debug nem fallback para o console, porque onde uma linha cai e o que ela pode expor é decisão da aplicação que anexou o logger. Um nível que o seu logger não implementa é descartado, nunca levantado.
Bring your own provider
Traga seu próprio cofre
The factory accepts a provider class directly, so a provider this package has never heard of is used through the same contract. The factory asserts the class declares the requested provider_nameproviderName.
A factory aceita diretamente a classe de um cofre, então um cofre que este pacote nunca viu é usado pelo mesmo contrato. A factory verifica que a classe declara o provider_nameproviderName pedido.
The shared contract suite in the testing package runs every portable guarantee against it — decrypted reads, prefix composition, both parse modes, and SecretNotFoundError on a missing secret.
A suíte de contrato compartilhada no pacote de testing roda todas as garantias portáveis contra ele — leituras descriptografadas, composição de prefix, os dois modos de parse, e SecretNotFoundError num segredo ausente.
import logging client = create_secret_client( CreateSecretClientConfig( provider="gcp-secret-manager", env="prod", logger=logging.getLogger("my-app"), options=GcpSecretManagerProviderOptions( project_id="my-project", ), ) ) # DEBUG Reading secret /prod/database/password # DEBUG Reading /prod/database/password from the provider # WARNING Secret not found in gcp-secret-manager: # database/password (full name: prod_database_password)
const client = await createSecretClient({ provider: SecretProvider.GcpSecretManager, env: 'prod', logger: console, options: { projectId: 'my-project' }, }); // debug Reading secret /prod/database/password // debug Reading /prod/database/password from the provider // warn Secret not found in gcp-secret-manager: // database/password (full name: prod_database_password)
create_secret_client( CreateSecretClientConfig( provider="my-vault", provider_class=MyVaultClient, ) )
await createSecretClient({ provider: 'my-vault', providerClass: MyVaultClient, });
What it refuses to do
O que ele se recusa a fazer
The scope is the feature. A narrow contract is one you can reason about.
O escopo é a feature. Um contrato estreito é um contrato sobre o qual você consegue raciocinar.
- Read-only. No write, no delete, no rotation, no batch read, no explicit historical version.
- Latest version only. When a provider supports versions, the kernel always reads the current one.
- Cross-environment reads are opt-in, one call at a time. The client's
envapplies unless a call says otherwise. Replacing it is never implicit and never a default, andomit_envomitEnvstill wins over it — a service reading another environment is usually a defect, but the caller sometimes knows better than the process context. - Provider options never leak.
regionbelongs to AWS,project_idprojectIdto GCP. The shared contract knows neither. - Failures are never cached. A missing secret that appears later is found on the next read.
- Somente leitura. Sem escrita, remoção, rotação, leitura em lote ou versão histórica explícita.
- Apenas a última versão. Quando o cofre suporta versões, o kernel sempre lê a atual.
- Leitura entre ambientes é opt-in, uma chamada por vez. O
envdo client vale a menos que uma chamada diga o contrário. Substituí-lo nunca é implícito nem default, eomit_envomitEnvcontinua vencendo — um serviço lendo outro ambiente é normalmente um defeito, mas quem chama às vezes sabe mais que o contexto do processo. - Opções do cofre não vazam.
regioné da AWS,project_idprojectIdé do GCP. O contrato compartilhado não conhece nenhuma das duas. - Falhas nunca são cacheadas. Um segredo ausente que aparece depois é encontrado na leitura seguinte.
Writing, rotating and versioning stay outside this contract by design.
Escrita, rotação e versionamento ficam fora deste contrato por decisão de projeto.
Changelog
Changelog
Early, and honest about it. Each implementation releases on its own, so this follows the language you picked above. Within one release every distribution shares a version.
No começo, e honesto sobre isso. Cada implementação lança por conta própria, então isto acompanha a linguagem escolhida acima. Dentro de um release, toda distribuição compartilha a versão.
Changed · breaking
Alterado · breaking
codechanged owner. It held the vendor's identifier, which moved toprovider_code.codeis now the kernel's own, always present and frozen:scrt_not_found,scrt_permission_denied,scrt_parse_failed,scrt_invalid_name,scrt_capability_not_supported,scrt_invalid_configuration,scrt_unexpected.SecretErrorCodeis aStrEnumof those seven.- A normalized failure names the secret you asked for and, in parentheses, the ID the provider looked up:
database/password (full name: dev_billing_database_password). - Errors are built from one
SecretKernelErrorOptions, andresolve_secret_full_nametakes(client_options, secret_name, options)— the same call shape as TypeScript. - Helpers drop the
secretprefix where the rest of the name is already this kernel's vocabulary —normalize_provider_error,assert_client_contractand six more. Breaking for a custom provider importing them. replace_secret_path_separatornever returns a leading separator. The AWS providers keep the resolved name themselves, so what they send is unchanged.SecretConfigurationErroris nowSecretKernelConfigurationError, with no alias. Itscodestaysscrt_invalid_configuration.regionon both AWS providers defaults tous-east-1, andAWS_REGIONor the AWS profile is no longer consulted. Breaking for a caller who left it out and relied on boto3 to find it.locationkeeps itsglobaldefault.region,locationorproject_idgiven asNoneor blank text raisesSecretKernelConfigurationErrorinstead of falling back to the default.
codemudou de dono. Ele guardava o identificador do fornecedor, que foi paraprovider_code.codeagora é do próprio kernel, sempre presente e congelado:scrt_not_found,scrt_permission_denied,scrt_parse_failed,scrt_invalid_name,scrt_capability_not_supported,scrt_invalid_configuration,scrt_unexpected.SecretErrorCodeé umStrEnumdesses sete.- Uma falha normalizada nomeia o segredo que você pediu e, entre parênteses, o ID que o cofre procurou:
database/password (full name: dev_billing_database_password). - Erros são construídos a partir de um único
SecretKernelErrorOptions, eresolve_secret_full_namerecebe(client_options, secret_name, options)— o mesmo formato de chamada do TypeScript. - Helpers perdem o prefixo
secretonde o resto do nome já é vocabulário deste kernel —normalize_provider_error,assert_client_contracte mais seis. Breaking para um cofre próprio que os importa. replace_secret_path_separatornunca devolve um separador inicial. Os cofres da AWS mantêm o nome resolvido por conta própria, então o que eles enviam não muda.SecretConfigurationErroragora éSecretKernelConfigurationError, sem alias. Ocodecontinuascrt_invalid_configuration.regionnos dois cofres da AWS tem padrãous-east-1, eAWS_REGIONou o perfil da AWS deixam de ser consultados. Breaking para quem omitia a região e contava com o boto3 para achá-la.locationmantém o padrãoglobal.region,locationouproject_idpassados comoNoneou texto em branco levantamSecretKernelConfigurationErrorem vez de cair no padrão.
Changed
Alterado
- Every third-party dependency declares a lower bound, the current release that supports Python 3.12; the three cloud SDKs had none.
- Toda dependência de terceiros declara um limite inferior, o release atual que suporta Python 3.12; os três SDKs de nuvem não tinham nenhum.
Fixed
Corrigido
- Configuration errors name the provider by its canonical name —
aws-parameter-store, notAWS Parameter Store— in the message and inprovider.
- Erros de configuração nomeiam o cofre pelo nome canônico —
aws-parameter-store, nãoAWS Parameter Store— na mensagem e emprovider.
Changed · breaking
Alterado · breaking
- A normalized failure names the provider and the secret:
Permission denied for aws-secrets-manager secret: /dev/billing/database/password, where it saidSecret provider denied the read. - A log line is one string, and the logger is the only sink. The context argument and the
debugoption are gone, and failures are logged — a missing secret atwarning, a refused or failed read aterror.logging.getLogger("my-app")is a drop-in. - Every error carries its class name in
name. - The public surface matches TypeScript name for name:
DEFAULT_CLIENT_CONFIG,AwsSecretsManagerClient,SecretProvider. The contract suite exports onlyassert_secret_client_contractandCreateClient.
- Uma falha normalizada nomeia o cofre e o segredo:
Permission denied for aws-secrets-manager secret: /dev/billing/database/password, onde diziaSecret provider denied the read. - Uma linha de log é uma string, e o logger é o único destino. O argumento de contexto e a opção
debugsaíram, e falhas são logadas — um segredo ausente emwarning, uma leitura recusada ou que falhou emerror.logging.getLogger("my-app")serve direto. - Todo erro carrega o nome da sua classe em
name. - A superfície pública bate com a do TypeScript nome a nome:
DEFAULT_CLIENT_CONFIG,AwsSecretsManagerClient,SecretProvider. A suíte de contrato exporta sóassert_secret_client_contracteCreateClient.
Added
Adicionado
- The factory declares one extra per provider, plus
all, and no longer depends onsecret-kernel-core.
- A factory declara um extra por cofre, mais
all, e não depende mais desecret-kernel-core.
Changed
Alterado
The Changelog link on the package page points here instead of at the raw file on GitHub, so every link on that page leads to where the reader already is.
O link Changelog na página do pacote aponta para cá em vez do arquivo bruto no GitHub, então todo link daquela página leva para onde quem lê já está.
Added
Adicionado
get_secret accepts an env that replaces the client's environment for one call. It is never implicit and never a default: the environment the client was built with applies unless a call says otherwise, in that call alone, and omit_env still wins over it.
get_secret aceita um env que substitui o ambiente do client por uma chamada. Nunca é implícito nem default: o ambiente com que o client foi construído vale a menos que uma chamada diga o contrário, e só naquela chamada, e o omit_env continua vencendo.
Changed
Alterado
- The API reference guard now checks both directions. It asserted that every export is documented and never that every documented name still exists, so a name that left the public surface stayed in the reference indefinitely.
- The integration suites hand credentials to the provider instead of expecting them in the environment, the same way an application injects configuration — which also exercises the documented precedence of explicit credentials over the SDK chain.
- O guard da referência de API agora checa nas duas direções. Ele afirmava que todo export está documentado e nunca que todo nome documentado ainda existe, então um nome que saiu da superfície pública ficava na referência indefinidamente.
- As suítes de integração passam credenciais ao cofre em vez de esperá-las no ambiente, do mesmo jeito que uma aplicação injeta configuração — o que também exercita a precedência documentada de credenciais explícitas sobre a cadeia do SDK.
The contract, the shared core, the factory, the five providers and the shared contract suite. Tagged before changelog fragments were being kept, which is why there is nothing itemised here.
O contrato, o core compartilhado, a factory, os cinco cofres e a suíte de contrato compartilhada. Tagueado antes de os fragmentos de changelog começarem a ser mantidos, e é por isso que não há itens detalhados aqui.
Changed · breaking
Alterado · breaking
codechanged owner. It held the vendor's identifier, which moved toproviderCode.codeis now the kernel's own, always present and frozen — the same sevenscrt_*values as Python.SecretErrorCodeis the constant map of them and the union of its values.- A normalized failure names the secret you asked for and, in parentheses, the ID the provider looked up:
database/password (full name: dev_billing_database_password). close()is required onSecretProviderReaderandSecretClient, as it already was in Python.- Helpers drop the
Secretprefix where the rest of the name is already this kernel's vocabulary —normalizeProviderError,defineProviderContractTestsand six more. Breaking for a custom provider importing them. SecretConfigurationErroris nowSecretKernelConfigurationError, with no alias. Itscodestaysscrt_invalid_configuration.regionon both AWS providers may be omitted and defaults tous-east-1;locationon GCP Parameter Manager may be omitted and defaults toglobal. Both were required. The default is the kernel's:AWS_REGIONis not consulted.region,locationorprojectIdgiven asundefined,nullor blank text throwsSecretKernelConfigurationErrorinstead of falling back to the default.
codemudou de dono. Ele guardava o identificador do fornecedor, que foi paraproviderCode.codeagora é do próprio kernel, sempre presente e congelado — os mesmos sete valoresscrt_*do Python.SecretErrorCodeé o mapa constante deles e a união dos seus valores.- Uma falha normalizada nomeia o segredo que você pediu e, entre parênteses, o ID que o cofre procurou:
database/password (full name: dev_billing_database_password). close()é obrigatório emSecretProviderReadereSecretClient, como já era no Python.- Helpers perdem o prefixo
Secretonde o resto do nome já é vocabulário deste kernel —normalizeProviderError,defineProviderContractTestse mais seis. Breaking para um cofre próprio que os importa. SecretConfigurationErroragora éSecretKernelConfigurationError, sem alias. Ocodecontinuascrt_invalid_configuration.regionnos dois cofres da AWS pode ser omitido e tem padrãous-east-1;locationno GCP Parameter Manager pode ser omitido e tem padrãoglobal. Os dois eram obrigatórios. O padrão é do kernel:AWS_REGIONnão é consultado.region,locationouprojectIdpassados comoundefined,nullou texto em branco lançamSecretKernelConfigurationErrorem vez de cair no padrão.
Fixed
Corrigido
- A cache at
maxEntriesno longer evicts an unrelated secret when one it already holds is read again. - Configuration errors name the provider by its canonical name, and a GCP provider created without options throws
SecretKernelConfigurationErrorinstead of a plainError.
- Um cache em
maxEntriesnão descarta mais um segredo não relacionado quando um que ele já guarda é lido de novo. - Erros de configuração nomeiam o cofre pelo nome canônico, e um cofre do GCP criado sem opções lança
SecretKernelConfigurationErrorem vez de umErrorcomum.
There is no 0.1.0-alpha.5: the number was skipped so this release matches 0.1.0a6 in Python.
Não existe 0.1.0-alpha.5: o número foi pulado para que este release case com o 0.1.0a6 do Python.
Changed · breaking
Alterado · breaking
- Provider failures are wrapped instead of rethrown raw. Every failure other than not-found and permission keeps the SDK's message and gains
provider,secretNameandcode, with the original error incause— the model Python always had. - A binary-only secret raises
SecretCapabilityNotSupportedErrorinstead of a plainError. - A normalized failure names the provider and the secret:
Permission denied for aws-secrets-manager secret: /dev/billing/database/password. - A log line is one string, and the logger is the only sink. The context argument and the
debugoption are gone, and failures are logged — a missing secret atwarn, a refused or failed read aterror.logger: consoleis a drop-in. - The
createClientalias is gone from every provider, andSecretMetadatanames the shape ofmetadata.
- Falhas do cofre são embrulhadas em vez de relançadas cruas. Toda falha que não seja não-encontrado ou permissão preserva a mensagem do SDK e ganha
provider,secretNameecode, com o erro original emcause— o modelo que o Python sempre teve. - Um segredo apenas binário levanta
SecretCapabilityNotSupportedErrorem vez de umErrorcomum. - Uma falha normalizada nomeia o cofre e o segredo:
Permission denied for aws-secrets-manager secret: /dev/billing/database/password. - Uma linha de log é uma string, e o logger é o único destino. O argumento de contexto e a opção
debugsaíram, e falhas são logadas — um segredo ausente emwarn, uma leitura recusada ou que falhou emerror.logger: consoleserve direto. - O alias
createClientsaiu de todos os pacotes de cofre, eSecretMetadatanomeia o formato demetadata.
Changed
Alterado
The homepage carries the language, so a reader arriving from the npm page lands on the TypeScript tab rather than on whichever one the site defaults to. The site reads that from the query ahead of a preference already stored in the browser, so the link decides even for a returning visitor. No source changes.
O homepage carrega a linguagem, então quem chega da página do npm cai na aba TypeScript em vez da que o site usa por padrão. O site lê isso da query antes de uma preferência já guardada no navegador, então o link decide mesmo para quem já visitou. Sem mudanças de código.
Added
Adicionado
getSecret accepts an env that replaces the client's environment for one call. It is never implicit and never a default: the environment the client was built with applies unless a call says otherwise, in that call alone, and omitEnv still wins over it.
getSecret aceita um env que substitui o ambiente do client por uma chamada. Nunca é implícito nem default: o ambiente com que o client foi construído vale a menos que uma chamada diga o contrário, e só naquela chamada, e o omitEnv continua vencendo.
The contract, the shared core, the factory, the five providers and the shared contract suite. Tagged before changelog fragments were being kept, which is why there is nothing itemised here.
O contrato, o core compartilhado, a factory, os cinco cofres e a suíte de contrato compartilhada. Tagueado antes de os fragmentos de changelog começarem a ser mantidos, e é por isso que não há itens detalhados aqui.