Secrets Manager

Lightweight, dependency-free fake of AWS Secrets Manager that speaks the real AWS JSON 1.1 wire protocol, so application code using @aws-sdk/client-secrets-manager can run against it with zero cost and zero side effects.

KeyValue
Port4572
ProtocolAWS JSON 1.1 (X-Amz-Target: secretsmanager.<Operation>) over HTTP
Compatible client@aws-sdk/client-secrets-manager (v3)
Size~80 KB
Startup< 100ms
StateIn-memory, ephemeral, resettable

Quick Start

Start the server:

import { SecretsmanagerServer } from "./services/secretsmanager/src/server.js";

const server = new SecretsmanagerServer(4572);
await server.start();
// ... use it ...
await server.stop();

Connect with the real AWS SDK client:

import {
  SecretsManagerClient,
  CreateSecretCommand,
  GetSecretValueCommand,
  PutSecretValueCommand,
  DescribeSecretCommand,
} from "@aws-sdk/client-secrets-manager";

const sm = new SecretsManagerClient({
  region: "us-east-1",
  endpoint: "http://127.0.0.1:4572",
  credentials: { accessKeyId: "parlel", secretAccessKey: "parlel" },
});

// Create a secret
const { ARN } = await sm.send(
  new CreateSecretCommand({ Name: "db/password", SecretString: "s3cr3t" }),
);

// Read it back
const { SecretString } = await sm.send(
  new GetSecretValueCommand({ SecretId: "db/password" }),
);
console.log(SecretString); // "s3cr3t"

// Rotate the stored value (creates a new AWSCURRENT version; the old one
// becomes AWSPREVIOUS)
await sm.send(
  new PutSecretValueCommand({ SecretId: "db/password", SecretString: "n3w-s3cr3t" }),
);

// Inspect metadata + version staging map
const meta = await sm.send(new DescribeSecretCommand({ SecretId: "db/password" }));
console.log(meta.VersionIdsToStages);

The SecretId parameter accepts either a bare secret name or a full ARN (arn:aws:secretsmanager:us-east-1:000000000000:secret:db/password-aB3xZ9).

Wire protocol

Implemented operations

All 23 operations exposed by @aws-sdk/client-secrets-manager are implemented.

Secret lifecycle

OperationNotes
CreateSecretName validation, tags, KMS key id, replica regions, ClientRequestToken idempotency, rejects duplicate names and SecretString+SecretBinary together.
UpdateSecretUpdates description/KMS key; a new value creates a fresh AWSCURRENT version (old → AWSPREVIOUS).
DescribeSecretFull metadata + VersionIdsToStages, tags, rotation config, replication status, deletion date.
DeleteSecretScheduled deletion with a 7–30 day recovery window (default 30), or ForceDeleteWithoutRecovery.
RestoreSecretCancels a scheduled deletion.

Secret values

OperationNotes
GetSecretValueBy VersionId or VersionStage (default AWSCURRENT); string or binary.
PutSecretValueNew version with optional VersionStages; rotates AWSCURRENT/AWSPREVIOUS; ClientRequestToken idempotency.
BatchGetSecretValueBy SecretIdList or Filters (not both); per-id Errors array for missing secrets.

Listing

OperationNotes
ListSecretsFilters (name/description/tag-key/tag-value/primary-region/owning-service/all, with ! negation), SortBy/SortOrder, MaxResults/NextToken pagination, IncludePlannedDeletion.
ListSecretVersionIdsVersion staging labels, IncludeDeprecated, pagination.

Version staging

OperationNotes
UpdateSecretVersionStageMove/remove a staging label across versions; AWSCURRENT move shifts AWSPREVIOUS.

Rotation

OperationNotes
RotateSecretEnables rotation, stores lambda ARN + rules, computes NextRotationDate, creates a new AWSCURRENT version when RotateImmediately (default).
CancelRotateSecretDisables rotation and removes any in-flight AWSPENDING version.

Resource policies

OperationNotes
PutResourcePolicyValidates JSON; BlockPublicPolicy rejects Principal: "*".
GetResourcePolicyReturns the attached policy document.
DeleteResourcePolicyDetaches the policy.
ValidateResourcePolicyReturns PolicyValidationPassed + ValidationErrors.

Replication

OperationNotes
ReplicateSecretToRegionsAdds replica regions with status; ForceOverwriteReplicaSecret.
RemoveRegionsFromReplicationRemoves replica regions.
StopReplicationToReplicaPromotes a replica to standalone (clears replication status).

Tagging & utility

OperationNotes
TagResourceAdd/overwrite tags.
UntagResourceRemove tags by key.
GetRandomPasswordLength, character-class exclusions, ExcludeCharacters, IncludeSpace, RequireEachIncludedType.

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatus
Secret CRUD (string + binary)✅ Supported
Version staging (AWSCURRENT/AWSPREVIOUS/AWSPENDING + custom)✅ Supported
ClientRequestToken idempotency✅ Supported
Scheduled deletion + recovery window + restore✅ Supported
Force delete✅ Supported
Filtering, sorting, pagination on ListSecrets✅ Supported
Tags✅ Supported
Resource policies + validation + public-policy blocking✅ Supported
GetRandomPassword✅ Supported
Rotation config + immediate rotation simulation✅ Supported (simulated)
Replication metadata (regions/status)✅ Supported (metadata only)
Bare-name and full-ARN SecretId resolution✅ Supported
Real KMS encryption of secret values✓ By design — Plain in-memory storage — transport/at-rest crypto is unnecessary locally
Actual rotation-Lambda invocation✓ By design — Intentional for a local, zero-cost test emulator
Real cross-region replication of data⟳ Roadmap — Not supported (status is tracked, no second store)
IAM / resource-policy enforcement✓ By design — Not supported (policies are stored, not enforced)
Persistence across restarts✓ By design — In-memory by design — fast, isolated, resets cleanly between tests

Error codes

Errors are returned as { "__type": "<Code>", "message": "<msg>" }. The SDK surfaces <Code> as the thrown error's name.

CodeHTTPWhen
ResourceNotFoundException400Secret or version not found (or found but marked for deletion).
ResourceExistsException400CreateSecret with a name that already exists.
InvalidParameterException400Invalid/missing parameters, conflicting SecretString+SecretBinary, bad recovery window, etc.
InvalidRequestException400e.g. creating a secret whose name is scheduled for deletion; malformed JSON body.
InvalidNextTokenException400Malformed pagination token.
MalformedPolicyDocumentException400Resource policy is not valid JSON.
PublicPolicyException400BlockPublicPolicy set and the policy grants public access.
LimitExceededException400Modeled (quota limits).
PreconditionNotMetException400Modeled.
EncryptionFailure / DecryptionFailure400Modeled (KMS faults).
InternalServiceError / InternalFailure500Unexpected server-side error.

Health & reset

Environment variables

The manifest publishes these defaults for AWS-SDK-based clients:

AWS_ACCESS_KEY_ID=parlel
AWS_SECRET_ACCESS_KEY=parlel
AWS_REGION=us-east-1
AWS_ENDPOINT_URL_SECRETS_MANAGER=http://127.0.0.1:4572
AWS_ENDPOINT_URL=http://127.0.0.1:4572
<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

AWS_ACCESS_KEY_ID=parlel
AWS_SECRET_ACCESS_KEY=parlel
AWS_REGION=us-east-1
AWS_ENDPOINT_URL_SECRETS_MANAGER=http://parlel-bridge:4572
AWS_ENDPOINT_URL=http://parlel-bridge:4572
<!-- parlel:testenv:end -->