<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>fakecloud</title>
      <link>https://fakecloud.dev</link>
      <description>Free, open-source local AWS cloud emulator</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://fakecloud.dev/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Tue, 19 May 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>2,591 Operations: How fakecloud Reached 100% AWS API Conformance</title>
          <pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/2-422-operations-how-fakecloud-reached-100-aws-api-conformance/</link>
          <guid>https://fakecloud.dev/blog/2-422-operations-how-fakecloud-reached-100-aws-api-conformance/</guid>
          <description xml:base="https://fakecloud.dev/blog/2-422-operations-how-fakecloud-reached-100-aws-api-conformance/">&lt;p&gt;For senior developers and tooling engineers, the &quot;local cloud&quot; has historically been a minefield of broken promises. Traditional mocks are brittle, often failing to capture the nuanced error codes or side effects of real AWS infrastructure. Heavyweight emulators, meanwhile, have evolved into complex platforms that require accounts, auth tokens, and significant memory overhead just to run a simple integration test.&lt;&#x2F;p&gt;
&lt;p&gt;As of May 2026, the landscape of local AWS development has shifted. While incumbent tools have moved toward account-gated models and mandatory internet connectivity for license verification, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud&lt;&#x2F;a&gt; provides a high-fidelity, zero-friction alternative. By focusing on 100% API conformance across 2,591 operations, fakecloud ensures that your local environment behaves like infrastructure, not a simulation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-credibility-hurdle-why-developers-distrust-mocks&quot;&gt;The Credibility Hurdle: Why Developers Distrust Mocks&lt;&#x2F;h2&gt;
&lt;p&gt;Most local AWS tools fall into the &quot;mocking&quot; trap. They intercept SDK calls and return hardcoded JSON responses. This works for happy-path unit tests but fails the moment your application relies on real cross-service integrations.&lt;&#x2F;p&gt;
&lt;p&gt;If your SNS fanout doesn&#x27;t actually trigger a Lambda, or if your S3 bucket policy doesn&#x27;t actually block an unauthorized &lt;code&gt;PutObject&lt;&#x2F;code&gt; call, your local tests are lying to you. This &quot;fidelity gap&quot; leads to the dreaded &quot;it worked on my machine&quot; failure during the first deployment to a real staging environment.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud solves this by moving from mocking to &lt;strong&gt;emulation&lt;&#x2F;strong&gt;. Instead of guessing how a service should respond, fakecloud implements the actual logic of the AWS service, backed by the same models AWS uses to define its own APIs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-no-list-zero-friction-development&quot;&gt;The &quot;No&quot; List: Zero-Friction Development&lt;&#x2F;h2&gt;
&lt;p&gt;Engineering pragmatism dictates that a tool should not be harder to manage than the problem it solves. Many local emulators now require a registered account and an active internet connection to function. fakecloud eliminates these hurdles entirely.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No account required:&lt;&#x2F;strong&gt; You never have to sign up or provide an email.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;No auth tokens:&lt;&#x2F;strong&gt; There are no &lt;code&gt;LOCALSTACK_AUTH_TOKEN&lt;&#x2F;code&gt; environment variables to manage or rotate.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;No internet connection:&lt;&#x2F;strong&gt; The binary is fully self-contained. You can develop on a plane, in a secure air-gapped environment, or during a network outage.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;No paid subscriptions:&lt;&#x2F;strong&gt; The local development environment is open-source under the AGPL-3.0 license.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;No 1GB+ Docker images:&lt;&#x2F;strong&gt; The entire fakecloud environment is delivered as a ~32 MB compressed download (~85 MB unpacked binary) with a sub-second startup time.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;100-conformance-across-2-591-operations&quot;&gt;100% Conformance Across 2,591 Operations&lt;&#x2F;h2&gt;
&lt;p&gt;Reliability in an emulator is measured by its API surface area and its conformance to the expected behavior of that surface. fakecloud currently supports 39 AWS services, covering the most critical components of modern cloud-native architectures.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Service&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Operations Supported&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Key Features&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;S3&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;107&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Multipart uploads, bucket policies, object tagging&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Lambda&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;85&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Cross-service triggers, environment variables, layers&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;DynamoDB&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;57&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;TTL, Global Secondary Indexes (GSI), Transactions&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;SQS&#x2F;SNS&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;65&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Dead-letter queues, SNS-to-SQS fanout, filtering&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Bedrock&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;106&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Foundation model invocation, listing models, tags&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;IAM&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;176&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Policy evaluation, role assumption, credential validation&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Reaching 100% conformance across 2,591 operations is not a manual task. It is the result of a rigorous, model-driven engineering process.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-smithy-protocol-86-000-test-variants&quot;&gt;The Smithy Protocol: 86,000+ Test Variants&lt;&#x2F;h2&gt;
&lt;p&gt;To ensure that fakecloud behaves exactly like the real AWS, we leverage &lt;strong&gt;Smithy&lt;&#x2F;strong&gt;, the interface definition language (IDL) used by AWS to build their own SDKs and services.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud uses official AWS Smithy models to generate a massive suite of test variants—86,327 in total, with 100% currently passing against the local binary.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-the-test-suite-works&quot;&gt;How the Test Suite Works&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Model Extraction:&lt;&#x2F;strong&gt; We pull the latest Smithy models for each supported AWS service.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Variant Generation:&lt;&#x2F;strong&gt; For every operation (e.g., &lt;code&gt;PutItem&lt;&#x2F;code&gt; in DynamoDB), the test generator creates thousands of permutations, including edge cases like empty strings, maximum payload sizes, and invalid characters.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Dual Execution:&lt;&#x2F;strong&gt; Each test variant is run against both the real AWS production environment and the local fakecloud binary.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Assertion:&lt;&#x2F;strong&gt; The responses—including headers, status codes, and error messages—must match exactly. If AWS returns a &lt;code&gt;400 Bad Request&lt;&#x2F;code&gt; with a specific &lt;code&gt;SerializationException&lt;&#x2F;code&gt;, fakecloud must return the same.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This protocol ensures that when you use the official AWS SDK in your application, it cannot distinguish between fakecloud and the real cloud.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;performance-by-the-numbers-32-mb-and-300ms&quot;&gt;Performance by the Numbers: ~32 MB and ~300ms&lt;&#x2F;h2&gt;
&lt;p&gt;For a senior developer, the &quot;inner loop&quot; of development—code, test, repeat—must be as fast as possible. Waiting for a heavy Docker container to pull or a complex emulator to initialize is a productivity killer.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Download Size:&lt;&#x2F;strong&gt; ~32 MB compressed (~85 MB unpacked). Small enough for any CI cache and faster to pull than a multi-gigabyte Docker image.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Startup Time:&lt;&#x2F;strong&gt; ~300ms cold-start on a modern laptop. fakecloud is ready to accept requests before you can switch from your terminal to your IDE.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Memory Footprint:&lt;&#x2F;strong&gt; Minimal. Unlike Java-based or Python-based emulators that can consume gigabytes of RAM, fakecloud&#x27;s Rust-based architecture is optimized for low-resource environments.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Start fakecloud in the background&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;.&#x2F;fakecloud&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Point your AWS CLI to the local endpoint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; s3 mb s3:&#x2F;&#x2F;my-local-bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;ai-development-with-full-bedrock-support&quot;&gt;AI Development with Full Bedrock Support&lt;&#x2F;h2&gt;
&lt;p&gt;In 2026, AI integration is no longer optional. Developing applications that use Amazon Bedrock typically requires a paid AWS account and incurs per-token costs even during the prototyping phase.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud provides support for 106 Bedrock operations (plus the Bedrock Agent, Agent Runtime, and Runtime APIs). This allows you to build and test your AI orchestration logic—such as prompt chaining, model selection, and &lt;a href=&quot;&#x2F;blog&#x2F;bedrock-guardrails-local&#x2F;&quot;&gt;guardrail integration&lt;&#x2F;a&gt;—locally and for free. While fakecloud does not ship with the multi-gigabyte weights of frontier models, it provides the API structure necessary to test your application&#x27;s interaction with the Bedrock service. You can learn more in our guide to &lt;a href=&quot;&#x2F;blog&#x2F;bedrock-local-testing&#x2F;&quot;&gt;local Bedrock testing&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sdk-client-separation-testing-with-confidence&quot;&gt;SDK-Client Separation: Testing with Confidence&lt;&#x2F;h2&gt;
&lt;p&gt;One of the most powerful features of fakecloud is the separation between your application&#x27;s SDK and the fakecloud testing SDK.&lt;&#x2F;p&gt;
&lt;p&gt;Your application uses the standard AWS SDK (e.g., &lt;code&gt;aws-sdk-go-v2&lt;&#x2F;code&gt; or &lt;code&gt;boto3&lt;&#x2F;code&gt;). It doesn&#x27;t know fakecloud exists; it just sees an endpoint. Meanwhile, your test suite uses the &lt;strong&gt;fakecloud SDK&lt;&#x2F;strong&gt; to perform &quot;out-of-band&quot; assertions.&lt;&#x2F;p&gt;
&lt;p&gt;For example, you can use the fakecloud SDK to inspect the internal state of an SQS queue or to manually trigger a Lambda without going through the standard AWS API. This allows for deep integration testing that is impossible with simple mocks.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Your App Code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;s3Client.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;PutObject&lt;&#x2F;span&gt;&lt;span&gt;(ctx,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;s3&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;PutObjectInput&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Your Test Code (using fakecloud SDK)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;assertions.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;AssertBucketCount&lt;&#x2F;span&gt;&lt;span&gt;(t,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;my-local-bucket&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;integrate-fakecloud-into-your-ci-pipeline&quot;&gt;Integrate fakecloud into Your CI Pipeline&lt;&#x2F;h2&gt;
&lt;p&gt;Because fakecloud is a standalone binary with no external dependencies, integrating it into a CI&#x2F;CD pipeline is trivial. There are no Docker-in-Docker complexities or auth secrets to configure.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Download the binary:&lt;&#x2F;strong&gt; Use a simple &lt;code&gt;curl&lt;&#x2F;code&gt; or &lt;code&gt;wget&lt;&#x2F;code&gt; in your CI script.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Start the service:&lt;&#x2F;strong&gt; Run &lt;code&gt;.&#x2F;fakecloud&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Run your tests:&lt;&#x2F;strong&gt; Point your test suite to &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This approach ensures that your CI environment is an exact replica of your local development environment, further reducing the risk of deployment-time surprises.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-future-of-local-cloud-development&quot;&gt;The Future of Local Cloud Development&lt;&#x2F;h2&gt;
&lt;p&gt;The trend toward &quot;cloud-only&quot; development is a response to the difficulty of building high-fidelity emulators. fakecloud proves that with a model-driven approach and a commitment to API conformance, the local environment can remain the most productive place for a developer to work.&lt;&#x2F;p&gt;
&lt;p&gt;By eliminating the friction of accounts, tokens, and costs, fakecloud returns control to the engineer. You can focus on building features and refining architecture, confident that your local tests are backed by 86,000+ Smithy-generated test variants and 100% conformance to the AWS API.&lt;&#x2F;p&gt;
&lt;p&gt;To get started, download the latest binary for your architecture and run the start command to begin developing against a local AWS environment that actually works.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>Testing SNS to S3 Triggers Locally in 500ms</title>
          <pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/testing-sns-to-s3-triggers-locally-in-500ms/</link>
          <guid>https://fakecloud.dev/blog/testing-sns-to-s3-triggers-locally-in-500ms/</guid>
          <description xml:base="https://fakecloud.dev/blog/testing-sns-to-s3-triggers-locally-in-500ms/">&lt;p&gt;Mocking individual AWS services is a common strategy that leads to production failures. When you mock a call to &lt;code&gt;sns.Publish&lt;&#x2F;code&gt; or &lt;code&gt;s3.PutObject&lt;&#x2F;code&gt;, you are testing your ability to write a mock, not the infrastructure&#x27;s ability to handle the event. In a real-world event-driven system, the failure points live in the gaps between services: the IAM policy that doesn&#x27;t quite allow the SNS fanout, the S3 bucket notification configuration that points to a non-existent ARN, or the Lambda trigger that fails because of a malformed event payload.&lt;&#x2F;p&gt;
&lt;p&gt;As of 2026-05-13, the landscape for local AWS development has shifted. With major incumbents moving to proprietary models and requiring mandatory auth tokens even for local runs, developers need a high-fidelity, zero-friction alternative. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud&lt;&#x2F;a&gt; provides a standalone ~19MB binary that starts in ~500ms, offering 100% API conformance across 2,591 operations without requiring an account, internet connection, or subscription.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-integration-gap-why-mocks-fail&quot;&gt;The Integration Gap: Why Mocks Fail&lt;&#x2F;h2&gt;
&lt;p&gt;Traditional unit testing with mocks assumes that if your code calls an API correctly, the infrastructure will behave as expected. This assumption is dangerous in complex integrations like an SNS-to-S3 trigger workflow.&lt;&#x2F;p&gt;
&lt;p&gt;Consider a scenario where an SNS message triggers a fanout to multiple S3 buckets or a Lambda function that subsequently writes to S3. If you mock the SNS client, you never verify:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The actual JSON structure of the event delivered to the subscriber.&lt;&#x2F;li&gt;
&lt;li&gt;The latency and retry logic inherent in the SNS-to-S3 delivery path.&lt;&#x2F;li&gt;
&lt;li&gt;The cross-service permissions required for the integration to function.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;fakecloud eliminates this gap by running the actual service logic locally. When your application publishes to a fakecloud SNS topic, the binary executes the fanout logic, constructs the real event payload, and delivers it to the local S3 or Lambda service exactly as the AWS production environment would.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;scenario-the-sns-to-s3-fanout&quot;&gt;Scenario: The SNS-to-S3 Fanout&lt;&#x2F;h2&gt;
&lt;p&gt;In this walkthrough, we will implement a common architectural pattern: an SNS topic that receives a message and triggers an S3 upload via a Lambda function. This tests the full chain of command: &lt;code&gt;SNS -&amp;gt; Lambda -&amp;gt; S3&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-no-list&quot;&gt;The &quot;No&quot; List&lt;&#x2F;h3&gt;
&lt;p&gt;Before we start, note what you do &lt;strong&gt;not&lt;&#x2F;strong&gt; need:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;No AWS account.&lt;&#x2F;li&gt;
&lt;li&gt;No &lt;code&gt;AWS_ACCESS_KEY_ID&lt;&#x2F;code&gt; validation (use &lt;code&gt;dummy&lt;&#x2F;code&gt; for everything).&lt;&#x2F;li&gt;
&lt;li&gt;No internet connection.&lt;&#x2F;li&gt;
&lt;li&gt;No Docker (unless you are running Lambda functions).&lt;&#x2F;li&gt;
&lt;li&gt;No auth tokens or login commands.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;execution-launching-the-stack&quot;&gt;Execution: Launching the Stack&lt;&#x2F;h2&gt;
&lt;p&gt;First, start the fakecloud binary. It listens on the standard port 4566 and is ready to accept requests in less than half a second.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Start the fakecloud binary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;.&#x2F;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# In a separate terminal, configure your local resources&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;dummy&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;dummy&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_REGION&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# 1. Create the SNS Topic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TOPIC_ARN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; sns create-topic&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; local-events&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --query&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;TopicArn&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --output&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; text&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# 2. Create the S3 Bucket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; s3 mb s3:&#x2F;&#x2F;processed-data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# 3. Create the Lambda function (using a pre-built zip)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; lambda create-function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;    --function-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; s3-uploader&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;    --runtime&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; python3.12&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;    --handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; index.handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;    --role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; arn:aws:iam::000000000000:role&#x2F;lambda-role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;    --zip-file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fileb:&#x2F;&#x2F;function.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# 4. Subscribe the Lambda to the SNS Topic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; sns subscribe&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;    --topic-arn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;$TOPIC_ARN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;    --protocol&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; lambda&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;    --notification-endpoint&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; arn:aws:lambda:us-east-1:000000000000:function:s3-uploader&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point, your local environment is fully wired. The fakecloud binary is managing the state of 39 AWS services in-memory, backed by 86,327 Smithy-model-generated test variants to ensure the API responses match AWS exactly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;100-conformance-across-2-591-operations&quot;&gt;100% Conformance Across 2,591 Operations&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud is not a collection of simple mocks. It is a high-fidelity emulator built on the Smithy models used by AWS to define their own APIs. As of May 2026, fakecloud supports 2,591 operations with 100% behavioral conformance. This includes complex behaviors like:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Service&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Supported Operations&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Key Integration Features&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;SNS&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;48&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Fanout to SQS, Lambda, and HTTP; Message Filtering; Attributes.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;S3&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;124&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Multipart uploads; Bucket notifications; Lifecycle policies; Object tagging.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Lambda&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;62&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;23+ runtimes; Event source mappings; Layer support; Synchronous&#x2F;Asynchronous invocation.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Bedrock&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;111&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Full support for frontier models (Claude 4.7, GPT-5.5) as of 2026-05-13.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;This depth ensures that when you call &lt;code&gt;sns.Publish&lt;&#x2F;code&gt;, the message doesn&#x27;t just disappear into a black hole. It is parsed, filtered according to your subscription attributes, and delivered to the target. If the target is a Lambda function, fakecloud spins up the appropriate container, injects the event, and captures the logs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;assertion-using-the-fakecloud-sdk&quot;&gt;Assertion: Using the fakecloud SDK&lt;&#x2F;h2&gt;
&lt;p&gt;Testing asynchronous integrations often involves &quot;sleep and pray&quot; or complex polling logic. You upload a file and then poll S3 for 10 seconds hoping the Lambda finished its work. fakecloud solves this with first-party SDKs for assertions in 6+ programming languages (TypeScript, Python, Go, PHP, Java, and Rust).&lt;&#x2F;p&gt;
&lt;p&gt;Instead of polling the public AWS API, you use the fakecloud SDK to inspect the internal state of the emulator. This allows for deterministic, sub-second test execution.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; boto3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;from&lt;&#x2F;span&gt;&lt;span&gt; fakecloud_sdk&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; import&lt;&#x2F;span&gt;&lt;span&gt; FakeCloudClient&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Standard AWS SDK for the application logic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sns&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; boto3.client(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;sns&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; endpoint_url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# fakecloud SDK for the test assertions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; FakeCloudClient(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;endpoint&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; test_sns_to_s3_trigger&lt;&#x2F;span&gt;&lt;span&gt;():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;    # 1. Trigger the workflow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sns.publish(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;TopicArn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;topic_arn,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; Message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test-payload&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;    # 2. Assert using the fakecloud SDK&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;    # This checks the internal event queue to ensure the message was processed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    integration_state&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; fc.inspect_integration(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;source&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;sns&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; target&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;lambda&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    assert&lt;&#x2F;span&gt;&lt;span&gt; integration_state.successful_invocations&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;    # 3. Verify the final side effect in S3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; boto3.client(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;s3&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; endpoint_url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; s3.list_objects_v2(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;processed-data&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    assert&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span&gt;(response.get(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;Contents&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, []))&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By using the &lt;code&gt;inspect_integration&lt;&#x2F;code&gt; method, you eliminate the non-determinism of local testing. You are asserting on the fact that the event loop completed, not just that the initial API call returned a 200 OK.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ai-development-local-bedrock-support&quot;&gt;AI Development: Local Bedrock Support&lt;&#x2F;h2&gt;
&lt;p&gt;As of 2026-05-13, AI integration is a core part of the AWS ecosystem. fakecloud includes full support for Amazon Bedrock (111 operations), allowing you to develop agentic workflows locally. This is particularly useful for testing how your SNS-triggered Lambda functions interact with foundation models like Claude 4.7 or the latest Amazon Nova Premier models.&lt;&#x2F;p&gt;
&lt;p&gt;Because fakecloud is a single binary, you can run these AI integration tests in restricted environments where internet access is prohibited for security reasons. You can configure deterministic responses for Bedrock prompts, allowing you to test your application&#x27;s parsing logic and error handling without incurring costs or dealing with the latency of frontier model APIs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;performance-benchmarks-fakecloud-vs-incumbents&quot;&gt;Performance Benchmarks: fakecloud vs. Incumbents&lt;&#x2F;h2&gt;
&lt;p&gt;In a modern CI&#x2F;CD pipeline, every second matters. Traditional local AWS emulators often rely on heavy container orchestration, leading to multi-minute startup times and high memory overhead. fakecloud is designed for engineering pragmatism.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;Metric&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;fakecloud&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Proprietary Incumbents&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Binary Size&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;~19 MB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;~250 MB+ (Docker Image)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Startup Time&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;~500 ms&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;30 - 90 seconds&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Idle Memory&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;~10 MiB&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;1.5 GiB+&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Auth Required&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;No&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Yes (Auth Token&#x2F;Account)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Internet Required&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;No&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Yes (for license checks)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;License&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;AGPL-3.0&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Proprietary &#x2F; Paid Tier&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Running fakecloud as a background process in your GitHub Actions or GitLab CI runner adds negligible overhead. You can spin up a fresh environment for every single test file, ensuring total isolation without the performance penalty of restarting a heavy container stack.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;real-cross-service-integrations&quot;&gt;Real Cross-Service Integrations&lt;&#x2F;h2&gt;
&lt;p&gt;The power of fakecloud lies in its ability to handle &quot;Real&quot; integrations. When we say 100% conformance, we mean the wire protocol and the side effects.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SNS Fanout&lt;&#x2F;strong&gt;: If you subscribe three different SQS queues to one SNS topic, fakecloud will deliver the message to all three, respecting individual filter policies.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;S3 Triggers&lt;&#x2F;strong&gt;: fakecloud supports the full S3 notification configuration, including prefix&#x2F;suffix filtering and all event types (&lt;code&gt;s3:ObjectCreated:*&lt;&#x2F;code&gt;, &lt;code&gt;s3:ObjectRemoved:*&lt;&#x2F;code&gt;, etc.).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;SES Inbound&lt;&#x2F;strong&gt;: You can simulate receiving an email in SES and have it automatically trigger an SNS notification or save the raw email to an S3 bucket.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These are not hard-coded shortcuts. They are the result of a unified event-bus architecture within the fakecloud binary that mirrors the asynchronous nature of the AWS cloud.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;engineering-pragmatism-the-agpl-3-0-advantage&quot;&gt;Engineering Pragmatism: The AGPL-3.0 Advantage&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud is released under the AGPL-3.0 license for local development. This ensures that the tool remains free and open-source, protecting developers from the sudden &quot;proprietary pivots&quot; that have affected other tools in the space. You can audit the source code, contribute fixes, and run it in any environment—from a disconnected laptop on a plane to a high-security air-gapped server—without ever asking for permission or providing a credit card.&lt;&#x2F;p&gt;
&lt;p&gt;Your development workflow should not be dependent on a third-party&#x27;s uptime or licensing server. By moving your integration tests to a standalone binary, you regain control over your test suite&#x27;s reliability and speed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;next-steps-beyond-sns-and-s3&quot;&gt;Next Steps: Beyond SNS and S3&lt;&#x2F;h2&gt;
&lt;p&gt;Testing SNS to S3 triggers is only the beginning. The same sub-second feedback loop applies to more complex architectures involving SQS dead-letter queues, DynamoDB Streams, and EventBridge pipes.&lt;&#x2F;p&gt;
&lt;p&gt;To explore further integration patterns, run the following command to see the full list of supported operations for your specific service mix:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;.&#x2F;fakecloud&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --list-operations --service&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; dynamodb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For detailed implementation guides on setting up local SQS-to-Lambda triggers or DynamoDB global tables, visit the fakecloud documentation. Start your local environment, run your tests, and inspect the results—all before your cloud-based CI environment would have even finished its authentication handshake.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Local ECR with real `docker push`: what LocalStack and Moto miss, and what fakecloud ships</title>
          <pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/ecr-localstack-moto-docker-push/</link>
          <guid>https://fakecloud.dev/blog/ecr-localstack-moto-docker-push/</guid>
          <description xml:base="https://fakecloud.dev/blog/ecr-localstack-moto-docker-push/">&lt;p&gt;If your integration tests build or pull a container image and push it to ECR — CDK docker assets, ECS task definitions, Lambda container images, GitHub Actions workflows — you&#x27;ve hit the wall.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;LocalStack&lt;&#x2F;strong&gt; gates ECR behind its paid Pro tier (the March 2026 shift to proprietary builds also means Community users have no ECR at all). Pro users who actually try &lt;code&gt;docker push&lt;&#x2F;code&gt; hit &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;localstack&#x2F;localstack&#x2F;issues&#x2F;7186&quot;&gt;#7186 &quot;EOF for ecr&#x2F;getCredentials&quot;&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;localstack&#x2F;localstack&#x2F;issues&#x2F;5598&quot;&gt;#5598 &quot;pushed image, describe says ImageNotFound&quot;&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;localstack&#x2F;localstack&#x2F;issues&#x2F;8128&quot;&gt;#8128 &quot;connection refused &#x2F; 403 on docker push&quot;&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;localstack&#x2F;localstack&#x2F;issues&#x2F;12043&quot;&gt;#12043 non-us-east-1 ECR timeouts&lt;&#x2F;a&gt;. The bugs are still open.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Moto&lt;&#x2F;strong&gt; ships an ECR control plane — you can call &lt;code&gt;CreateRepository&lt;&#x2F;code&gt; and &lt;code&gt;DescribeImages&lt;&#x2F;code&gt; from boto3 — but Moto is not a real HTTP server for the OCI protocol. &lt;code&gt;docker push localhost:…&#x2F;your-repo&lt;&#x2F;code&gt; doesn&#x27;t work because the &lt;code&gt;&#x2F;v2&#x2F;&amp;lt;name&amp;gt;&#x2F;blobs&#x2F;uploads&#x2F;&lt;&#x2F;code&gt; endpoints don&#x27;t exist. If your tests rely on CDK building and pushing a docker asset, Moto is a dead end.&lt;&#x2F;p&gt;
&lt;p&gt;Most teams end up running a standalone &lt;code&gt;registry:2&lt;&#x2F;code&gt; container alongside their test harness. That works for raw Docker, but &lt;code&gt;registry:2&lt;&#x2F;code&gt; doesn&#x27;t expose &lt;code&gt;DescribeRepositories&lt;&#x2F;code&gt;, &lt;code&gt;BatchGetImage&lt;&#x2F;code&gt;, &lt;code&gt;PutLifecyclePolicy&lt;&#x2F;code&gt;, or any of the other AWS-shaped operations. CDK, Terraform, and the AWS CLI can&#x27;t talk to it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-fakecloud-ships&quot;&gt;What fakecloud ships&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud implements ECR end-to-end: all 58 operations in AWS&#x27;s Smithy model &lt;strong&gt;and&lt;&#x2F;strong&gt; the OCI v2 Distribution HTTP protocol that Docker uses on the wire. Both back onto the same content-addressed sha256 blob store, so a layer pushed by &lt;code&gt;docker push&lt;&#x2F;code&gt; is visible via &lt;code&gt;BatchCheckLayerAvailability&lt;&#x2F;code&gt;, and an image manifest uploaded via &lt;code&gt;PutImage&lt;&#x2F;code&gt; can be &lt;code&gt;docker pull&lt;&#x2F;code&gt;ed.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Start fakecloud.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Docker login works.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 ecr get-login-password&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; docker&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; login&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --username&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; AWS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --password-stdin&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Push an image.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 ecr create-repository&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --repository-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; demo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; pull busybox:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; tag busybox:latest localhost:4566&#x2F;demo:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; push localhost:4566&#x2F;demo:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# The AWS SDK sees it.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 ecr describe-images&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --repository-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; demo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;GetAuthorizationToken&lt;&#x2F;code&gt; returns &lt;code&gt;base64(&quot;AWS:&amp;lt;token&amp;gt;&quot;)&lt;&#x2F;code&gt; with a 12-hour expiry matching real AWS. The &lt;code&gt;&#x2F;v2&#x2F;&lt;&#x2F;code&gt; endpoints honor Basic Auth and issue a &lt;code&gt;WWW-Authenticate: Basic realm=&quot;fakecloud-ecr&quot;&lt;&#x2F;code&gt; challenge on the initial unauthenticated request, so Docker&#x27;s two-phase login does its handshake cleanly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-else-lands-in-the-58-op-surface&quot;&gt;What else lands in the 58-op surface&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lifecycle policy evaluation, not storage.&lt;&#x2F;strong&gt; &lt;code&gt;PutLifecyclePolicy&lt;&#x2F;code&gt; applies immediately — &lt;code&gt;imageCountMoreThan&lt;&#x2F;code&gt; and &lt;code&gt;sinceImagePushed&lt;&#x2F;code&gt; rules actually prune images, ordered by &lt;code&gt;rulePriority&lt;&#x2F;code&gt; per AWS semantics. &lt;code&gt;GetLifecyclePolicyPreview&lt;&#x2F;code&gt; returns the digests that would be expired. No &quot;stored but never evaluated&quot; like LocalStack&#x27;s SES receipt rules.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Image scanning.&lt;&#x2F;strong&gt; &lt;code&gt;StartImageScan&lt;&#x2F;code&gt; stores a COMPLETE scan record that &lt;code&gt;DescribeImageScanFindings&lt;&#x2F;code&gt; echoes back in the AWS-shaped payload. Real scanner integration is out of scope for a mock; a schema-complete synthetic shape lets you exercise your findings plumbing.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Pull-through cache rules.&lt;&#x2F;strong&gt; Full CRUD + Validate.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Registry policy, scanning config, replication config, repository creation templates, signing configuration, pull-time exclusions.&lt;&#x2F;strong&gt; Every operation AWS lists.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Smithy-exact validation.&lt;&#x2F;strong&gt; &lt;code&gt;@length&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;@range&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;@enum&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;@required&lt;&#x2F;code&gt; traits enforced everywhere — garbage inputs return &lt;code&gt;InvalidParameterException&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;ImageDigestDoesNotMatchException&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;LayerDigestMismatchException&lt;&#x2F;code&gt;, not silent success.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;assert-on-what-was-pushed&quot;&gt;Assert on what was pushed&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud exposes an introspection API at &lt;code&gt;&#x2F;_fakecloud&#x2F;ecr&#x2F;...&lt;&#x2F;code&gt; so your test code can check pushed images without parsing Docker output:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;fakecloud&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; repositories&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.ecr.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getRepositories&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; images&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.ecr.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getImages&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;demo&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(repositories).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(images[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].imageTags).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;latest&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(images[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].imageDigest).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toMatch&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;^&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;sha256:&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The same API is available from Go, Python, Java, PHP, and Rust.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conformance&quot;&gt;Conformance&lt;&#x2F;h2&gt;
&lt;p&gt;58&#x2F;58 ECR operations, 1,789&#x2F;1,789 generated variant probes passing (100%) — this runs on every commit against AWS&#x27;s Smithy model. The Smithy model drives positive probes (does the call succeed with sensible input?) and negative probes (does a missing required field, a too-long string, an out-of-range integer, a non-enum enum, return the right error code?). fakecloud&#x27;s baseline is now 61,741&#x2F;61,743 across the whole workspace.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-next&quot;&gt;Where next&lt;&#x2F;h2&gt;
&lt;p&gt;ECR is the prerequisite for ECS, which is the next item on the roadmap. ECS builds on the same Docker runtime pattern fakecloud already uses for Lambda — pull a real container image (from the local ECR we just built), run it, expose it via the ECS API. The moment that ships, the CDK-ECS-ECR pipeline works end-to-end in local tests.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud is AGPL-3.0&lt;&#x2F;a&gt;. No account needed, no paid tier.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Running AWS integration tests with Claude Code, Cursor, and Copilot</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/aws-integration-tests-with-claude-code-cursor/</link>
          <guid>https://fakecloud.dev/blog/aws-integration-tests-with-claude-code-cursor/</guid>
          <description xml:base="https://fakecloud.dev/blog/aws-integration-tests-with-claude-code-cursor/">&lt;p&gt;When you let Claude Code or Cursor run tests against AWS during a task, you want the test loop to be fast, free, and deterministic. Against real AWS, the loop is slow (minutes per test), costs money (per-request + data transfer), and leaves cruft behind that the agent won&#x27;t always clean up.&lt;&#x2F;p&gt;
&lt;p&gt;Against a mocking library, the loop is fast but the agent can&#x27;t exercise cross-service flows — so it &quot;fixes&quot; bugs that don&#x27;t manifest in the mock and misses bugs that do manifest in AWS.&lt;&#x2F;p&gt;
&lt;p&gt;The middle ground: run &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud&lt;&#x2F;a&gt; as the test target. Real HTTP server on port 4566, speaking the AWS wire protocol at 100% conformance per implemented service. Free, single binary, no account. Agent writes code, agent runs tests, agent sees real behavior.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;one-liner-per-tool&quot;&gt;One-liner per tool&lt;&#x2F;h2&gt;
&lt;p&gt;Paste into your project&#x27;s agent-instructions file. Agent picks up the convention and uses fakecloud for integration tests automatically.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;claude-code-claude-md&quot;&gt;Claude Code — &lt;code&gt;CLAUDE.md&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;font-weight: bold;&quot;&gt;## AWS Testing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;For integration tests, use fakecloud as a local AWS emulator.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; Install: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;`curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; Run: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;`fakecloud`&lt;&#x2F;span&gt;&lt;span&gt; (listens on http:&#x2F;&#x2F;localhost:4566)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; Configure AWS SDK endpoint to http:&#x2F;&#x2F;localhost:4566 with dummy credentials (access_key=test, secret_key=test)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; Docs: https:&#x2F;&#x2F;fakecloud.dev&#x2F;llms.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;cursor-cursor-rules&quot;&gt;Cursor — &lt;code&gt;.cursor&#x2F;rules&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;For AWS integration tests, use fakecloud (local AWS emulator) at http:&#x2F;&#x2F;localhost:4566.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Install: curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Run: fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Use dummy credentials (access_key=test, secret_key=test).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Docs: https:&#x2F;&#x2F;fakecloud.dev&#x2F;llms.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;github-copilot-github-copilot-instructions-md&quot;&gt;GitHub Copilot — &lt;code&gt;.github&#x2F;copilot-instructions.md&lt;&#x2F;code&gt;&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;font-weight: bold;&quot;&gt;## AWS Testing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Use fakecloud as a local AWS emulator for integration tests.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; Run: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;`fakecloud`&lt;&#x2F;span&gt;&lt;span&gt; (listens on http:&#x2F;&#x2F;localhost:4566)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; Configure endpoint_url to http:&#x2F;&#x2F;localhost:4566 with dummy credentials&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt; Docs: https:&#x2F;&#x2F;fakecloud.dev&#x2F;llms.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;why-this-matters-for-agent-assisted-dev&quot;&gt;Why this matters for agent-assisted dev&lt;&#x2F;h2&gt;
&lt;p&gt;AI coding agents are good at writing plausible code and tests. They&#x27;re bad at knowing when a test passing means something real.&lt;&#x2F;p&gt;
&lt;p&gt;Three failure modes with mocks:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Agent writes buggy code.&lt;&#x2F;strong&gt; Mock returns success. Test passes. Bug ships.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Agent writes correct code.&lt;&#x2F;strong&gt; Mock has incorrect stub. Test fails. Agent &quot;fixes&quot; the mock instead of recognizing the stub is wrong.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Cross-service flow bugs.&lt;&#x2F;strong&gt; Mock doesn&#x27;t simulate S3 -&amp;gt; Lambda notification, so the agent never discovers the Lambda trigger wasn&#x27;t wired.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;fakecloud fails in ways that look like real AWS failing. The agent sees the same error messages, same HTTP status codes, same ARN formats. Wrong code that &quot;works&quot; against a mock fails against fakecloud the same way it would fail against AWS.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-llms-txt-payoff&quot;&gt;The &lt;code&gt;llms.txt&lt;&#x2F;code&gt; payoff&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud publishes &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;llms.txt&quot;&gt;&#x2F;llms.txt&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;llms-full.txt&quot;&gt;&#x2F;llms-full.txt&lt;&#x2F;a&gt; — structured documentation designed for LLM ingestion. When an agent has fakecloud in its context (via your &lt;code&gt;CLAUDE.md&lt;&#x2F;code&gt; or &lt;code&gt;.cursor&#x2F;rules&lt;&#x2F;code&gt;), it can fetch these to understand the full API surface without you prompting it explicitly.&lt;&#x2F;p&gt;
&lt;p&gt;Agents that can look up &lt;code&gt;https:&#x2F;&#x2F;fakecloud.dev&#x2F;llms.txt&lt;&#x2F;code&gt; get:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;List of all 23 supported services with operation counts&lt;&#x2F;li&gt;
&lt;li&gt;Every &lt;code&gt;&#x2F;_fakecloud&#x2F;*&lt;&#x2F;code&gt; introspection endpoint (what the agent can use from a test)&lt;&#x2F;li&gt;
&lt;li&gt;Which cross-service integrations actually fire&lt;&#x2F;li&gt;
&lt;li&gt;Install options and CLI flags&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This is a better baseline than letting the agent guess AWS SDK API shapes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-actually-works-in-tests&quot;&gt;What actually works in tests&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;example-1-claude-code-writes-and-tests-a-lambda&quot;&gt;Example 1 — Claude Code writes and tests a Lambda&lt;&#x2F;h3&gt;
&lt;p&gt;You: &quot;Add a Lambda function that processes SQS messages and writes to DynamoDB.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Claude Code writes the function, writes a CDK stack or raw deploy commands, writes an integration test. When it runs the test, fakecloud:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Pulls the real Node&#x2F;Python&#x2F;Java Lambda runtime container&lt;&#x2F;li&gt;
&lt;li&gt;Runs the handler against the real SQS message shape&lt;&#x2F;li&gt;
&lt;li&gt;Persists the DynamoDB write to a real in-process store&lt;&#x2F;li&gt;
&lt;li&gt;Returns the exact same errors real AWS would (field validation, permission errors, quota errors)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Claude Code sees success = success, failure = failure. No hallucinated stub behavior.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-2-cursor-exercises-a-step-function&quot;&gt;Example 2 — Cursor exercises a Step Function&lt;&#x2F;h3&gt;
&lt;p&gt;You: &quot;Write a Step Function that orchestrates order fulfillment (validate payment -&amp;gt; reserve inventory -&amp;gt; send confirmation email).&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Cursor writes the ASL, deploys via CDK, runs &lt;code&gt;StartExecution&lt;&#x2F;code&gt; as a test. fakecloud:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Runs the full ASL interpreter (Pass, Task, Choice, Wait, Parallel, Map, Succeed, Fail, Retry&#x2F;Catch)&lt;&#x2F;li&gt;
&lt;li&gt;Invokes the Lambda tasks with real runtime execution&lt;&#x2F;li&gt;
&lt;li&gt;Actually sends the SES email (visible via &lt;code&gt;GET &#x2F;_fakecloud&#x2F;ses&#x2F;emails&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Returns the execution state the way Step Functions would&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Cursor asserts on the final execution state + SES email count. No ambiguity.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-3-copilot-tests-ses-inbound-flow&quot;&gt;Example 3 — Copilot tests SES inbound flow&lt;&#x2F;h3&gt;
&lt;p&gt;You: &quot;When an email hits support@example.com, parse it, classify with Bedrock, file a ticket in DynamoDB.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Copilot sets up the SES receipt rule, the Lambda action, the Bedrock invocation, the DynamoDB write. fakecloud:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Actually executes the receipt rule when test email arrives (LocalStack Community stores them but doesn&#x27;t execute)&lt;&#x2F;li&gt;
&lt;li&gt;Runs the Lambda for real&lt;&#x2F;li&gt;
&lt;li&gt;Invokes the Bedrock endpoint with a configurable mock response (&lt;code&gt;POST &#x2F;_fakecloud&#x2F;bedrock&#x2F;runtime&#x2F;mock-response&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Writes the DynamoDB row for real&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Copilot&#x27;s tests assert on the DynamoDB row appearing + the SES email being consumed. End-to-end, no gaps.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ci-and-the-agent-loop&quot;&gt;CI and the agent loop&lt;&#x2F;h2&gt;
&lt;p&gt;If the agent writes CI configuration, it should run fakecloud as a service:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# .github&#x2F;workflows&#x2F;test.yml — generated by the agent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  test&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; actions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fakecloud &amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          for i in $(seq 1 30); do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;            curl -sf http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;health &amp;amp;&amp;amp; break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;            sleep 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm ci &amp;amp;&amp;amp; npm test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        env&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;          AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;          AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;          AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;          AWS_REGION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;~500ms fakecloud startup means agent iteration stays tight.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;assertions-agents-can-write-directly&quot;&gt;Assertions agents can write directly&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud&#x27;s test-assertion SDKs give agents a clean interface for &quot;did the thing happen&quot;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;fakecloud&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Agent-written test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;order flow sends confirmation&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; placeOrder&lt;&#x2F;span&gt;&lt;span&gt;({ id:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;o1&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, email:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;buyer@example.com&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;  &#x2F;&#x2F; Agent asserts the email was sent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; emails&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.ses.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getEmails&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(emails).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(emails[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].destination.toAddresses).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;buyer@example.com&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;  &#x2F;&#x2F; Agent asserts the Lambda fired&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; invocations&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.lambda.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getInvocations&lt;&#x2F;span&gt;&lt;span&gt;({ functionName:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;on-order&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].statusCode).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;afterEach&lt;&#x2F;span&gt;&lt;span&gt;(()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; fc.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;SDKs: TypeScript, Python, Go, PHP, Java, Rust. Agents that prefer HTTP can hit &lt;code&gt;&#x2F;_fakecloud&#x2F;*&lt;&#x2F;code&gt; directly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-reset-between-tests-pattern&quot;&gt;The reset-between-tests pattern&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;afterEach&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; fetch&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;reset&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, { method:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;POST&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Instant reset across every service. Agent-generated test suites stay isolated without per-test resource naming ceremony.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Install: &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Repo: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;LLM-ingestion docs: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;llms.txt&quot;&gt;fakecloud.dev&#x2F;llms.txt&lt;&#x2F;a&gt; + &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;llms-full.txt&quot;&gt;llms-full.txt&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Lambda tutorial: &lt;a href=&quot;&#x2F;blog&#x2F;test-lambda-locally&#x2F;&quot;&gt;Test Lambda locally&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;CI tutorial: &lt;a href=&quot;&#x2F;blog&#x2F;integration-testing-aws-in-ci&#x2F;&quot;&gt;Integration testing AWS in GitHub Actions&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Moto equivalent for non-Python: &lt;a href=&quot;&#x2F;blog&#x2F;moto-equivalent-go-java-node&#x2F;&quot;&gt;Moto equivalent for Go&#x2F;Java&#x2F;Node&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Testing Bedrock Guardrails without the AWS bill</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/bedrock-guardrails-local/</link>
          <guid>https://fakecloud.dev/blog/bedrock-guardrails-local/</guid>
          <description xml:base="https://fakecloud.dev/blog/bedrock-guardrails-local/">&lt;p&gt;Bedrock Guardrails are one of the better pieces of AWS infrastructure in the last year. You define a policy — filter out hate, block PII leakage, deny certain topics, enforce contextual grounding on RAG outputs — and either apply it to an entire model invocation via &lt;code&gt;guardrailIdentifier&lt;&#x2F;code&gt;, or call &lt;code&gt;ApplyGuardrail&lt;&#x2F;code&gt; directly on arbitrary text. Useful, sharp, limited-in-scope.&lt;&#x2F;p&gt;
&lt;p&gt;The problem is testing. A serious guardrail config is an iterative thing — you tune filter strengths, add denied topics, tweak word filters, and test each change. Each test-cycle turn against real AWS costs tokens and time. And if the thing you&#x27;re trying to guard against is LLM output, you&#x27;re paying for the model call &lt;em&gt;and&lt;&#x2F;em&gt; the guardrail evaluation.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud runs the full Bedrock Guardrails surface locally. &lt;code&gt;CreateGuardrail&lt;&#x2F;code&gt;, versioning, &lt;code&gt;UpdateGuardrail&lt;&#x2F;code&gt;, &lt;code&gt;DeleteGuardrail&lt;&#x2F;code&gt;, &lt;code&gt;ApplyGuardrail&lt;&#x2F;code&gt;, &lt;code&gt;ListGuardrails&lt;&#x2F;code&gt; — the whole thing. More interestingly, the data plane actually evaluates content. PII detection works. Content filters return sensible scores on real test text. You can write tests that verify your guardrail actually blocks what you think it blocks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-shape-of-the-problem&quot;&gt;The shape of the problem&lt;&#x2F;h2&gt;
&lt;p&gt;The standard AWS recipe, cleaned up:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; boto3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bedrock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; boto3.client(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;bedrock&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; region_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;us-east-1&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; bedrock.create_guardrail(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;customer-facing-v1&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    contentPolicyConfig&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;        &amp;#39;filtersConfig&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;HATE&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;inputStrength&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;HIGH&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;outputStrength&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;HIGH&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;VIOLENCE&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;inputStrength&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;HIGH&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;outputStrength&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;HIGH&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;SEXUAL&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;inputStrength&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;HIGH&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;outputStrength&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;HIGH&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;INSULTS&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;inputStrength&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;MEDIUM&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;outputStrength&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;MEDIUM&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    sensitiveInformationPolicyConfig&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;        &amp;#39;piiEntitiesConfig&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;EMAIL&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;action&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;BLOCK&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;PHONE&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;action&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;BLOCK&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;CREDIT_DEBIT_CARD_NUMBER&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;action&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;BLOCK&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    topicPolicyConfig&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;        &amp;#39;topicsConfig&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;                &amp;#39;name&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;medical-advice&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;                &amp;#39;definition&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Providing specific medical diagnoses or treatment recommendations&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;                &amp;#39;examples&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;What dose should I take?&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Do I have cancer?&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;                &amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;DENY&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    blockedInputMessaging&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;Cannot process this input.&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    blockedOutputsMessaging&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;Cannot respond to this.&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now you want to test: does an email containing &lt;code&gt;bob@example.com&lt;&#x2F;code&gt; trigger the EMAIL filter and return the blocked-input message? Does a prompt asking &quot;what medication should I take for my headache&quot; get denied via the medical-advice topic? Does the HATE filter catch slurs at HIGH strength?&lt;&#x2F;p&gt;
&lt;p&gt;Against real AWS: each of those is an API call that costs a few cents, takes a second, and requires valid credentials. You&#x27;ll do 50 of these across a tuning session. Repeated for each PR that touches guardrail config.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;against-fakecloud&quot;&gt;Against fakecloud&lt;&#x2F;h2&gt;
&lt;p&gt;Same code, different endpoint:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; boto3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bedrock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; boto3.client(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;bedrock&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    endpoint_url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;http:&#x2F;&#x2F;localhost:4566&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    aws_access_key_id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    aws_secret_access_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    region_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;us-east-1&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# same create_guardrail call as above&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;g&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; bedrock.create_guardrail(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; boto3.client(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;bedrock-runtime&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    endpoint_url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;http:&#x2F;&#x2F;localhost:4566&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    aws_access_key_id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    aws_secret_access_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    region_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;us-east-1&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; rt.apply_guardrail(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    guardrailIdentifier&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;g[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;guardrailId&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    guardrailVersion&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;DRAFT&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    source&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;INPUT&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    content&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;[{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;text&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;text&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;contact me at bob@example.com&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;}}],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;assert&lt;&#x2F;span&gt;&lt;span&gt; resp[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;action&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;GUARDRAIL_INTERVENED&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;assert&lt;&#x2F;span&gt;&lt;span&gt; resp[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;outputs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;text&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Cannot process this input.&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;assert&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; any&lt;&#x2F;span&gt;&lt;span&gt;(a[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;EMAIL&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; for&lt;&#x2F;span&gt;&lt;span&gt; a&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span&gt; resp[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;assessments&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;sensitiveInformationPolicy&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;piiEntities&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Real PII detection — the email is caught. Real blocked-input messaging returned. Assessments returned in the shape real AWS would return.&lt;&#x2F;p&gt;
&lt;p&gt;No tokens. No AWS bill. No credentials. 30ms.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-actually-evaluated&quot;&gt;What&#x27;s actually evaluated&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud&#x27;s guardrail evaluator ships opinionated implementations of each policy type. Concrete checks you can rely on in tests:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PII entities&lt;&#x2F;strong&gt;: regex + context for email, phone (various formats), credit card (Luhn), SSN, IP, URL, name, address hints.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Content filters&lt;&#x2F;strong&gt;: keyword + pattern matching tuned for the common categories. HIGH strength catches more, LOW catches less — same directional behavior as real AWS.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Topic filters&lt;&#x2F;strong&gt;: pattern matching against the topic definition + examples you provided. Won&#x27;t pass a Stanford NLI benchmark, but does what you need for testing: asserts the policy fires on obvious positives and passes obvious negatives.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Word filters&lt;&#x2F;strong&gt;: exact match + stemming.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Regex filters&lt;&#x2F;strong&gt;: the regex you supplied, as-is.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;It&#x27;s shape-correct evaluation. For tests that verify &quot;my guardrail config blocks what I intended,&quot; that&#x27;s exactly what you need. If you want bulletproof production-grade content filtering, you&#x27;re going to tune against real AWS or roll your own anyway — this gets you 95% of the iteration speed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;versioning&quot;&gt;Versioning&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# publish a version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; bedrock.create_guardrail_version(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    guardrailIdentifier&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;g[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;guardrailId&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    description&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;initial pinned version for prod&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# list versions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;versions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; bedrock.list_guardrails(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;guardrailIdentifier&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;g[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;guardrailId&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# apply a specific version in production&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rt.apply_guardrail(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    guardrailIdentifier&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;g[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;guardrailId&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    guardrailVersion&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;v[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;version&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;],&lt;&#x2F;span&gt;&lt;span style=&quot;color: #768390;&quot;&gt;  # &amp;#39;1&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    source&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;INPUT&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    content&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;[{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;text&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;text&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;...&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;}}],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;DRAFT is mutable. Numbered versions (1, 2, 3, ...) are immutable once created — same as real AWS. Your prod code should pin. Your dev iteration happens against DRAFT.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-realistic-test-suite&quot;&gt;A realistic test suite&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;fakecloud&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { BedrockRuntimeClient, ApplyGuardrailCommand }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;@aws-sdk&#x2F;client-bedrock-runtime&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { BedrockClient, CreateGuardrailCommand }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;@aws-sdk&#x2F;client-bedrock&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; control&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; BedrockClient&lt;&#x2F;span&gt;&lt;span&gt;({ endpoint:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; rt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; BedrockRuntimeClient&lt;&#x2F;span&gt;&lt;span&gt;({ endpoint:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; guardrailId&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;beforeAll&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; created&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; control.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; CreateGuardrailCommand&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    name:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test-guardrail&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    contentPolicyConfig: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      filtersConfig: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        { type:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;HATE&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, inputStrength:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;HIGH&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, outputStrength:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;HIGH&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sensitiveInformationPolicyConfig: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      piiEntitiesConfig: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        { type:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;EMAIL&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, action:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;BLOCK&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        { type:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;PHONE&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, action:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;ANONYMIZE&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    blockedInputMessaging:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;Blocked.&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    blockedOutputsMessaging:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;Blocked.&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  guardrailId&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; created.guardrailId&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;beforeEach&lt;&#x2F;span&gt;&lt;span&gt;(()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; fc.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;({ preserve: [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;bedrock:guardrails&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;] }));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;blocks input containing email&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; rt.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; ApplyGuardrailCommand&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    guardrailIdentifier: guardrailId,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    guardrailVersion:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;DRAFT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    source:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;INPUT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    content: [{ text: { text:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;contact me at alice@example.com&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; } }],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(resp.action).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;GUARDRAIL_INTERVENED&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(resp.outputs?.[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].text).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;Blocked.&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;anonymizes phone in output&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; rt.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; ApplyGuardrailCommand&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    guardrailIdentifier: guardrailId,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    guardrailVersion:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;DRAFT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    source:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;OUTPUT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    content: [{ text: { text:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;call me at 555-123-4567 tomorrow&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; } }],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(resp.action).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;GUARDRAIL_INTERVENED&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(resp.outputs?.[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].text).not.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;555-123-4567&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;passes clean input through&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; resp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; rt.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; ApplyGuardrailCommand&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    guardrailIdentifier: guardrailId,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    guardrailVersion:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;DRAFT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    source:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;INPUT&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    content: [{ text: { text:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;what&amp;#39;s the weather in Paris?&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; } }],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(resp.action).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;NONE&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These run in milliseconds, are deterministic, and test the thing that matters — that your guardrail config enforces what you think it enforces.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-this-matters-for-agent-systems&quot;&gt;Why this matters for agent systems&lt;&#x2F;h2&gt;
&lt;p&gt;Guardrails become critical when you&#x27;re building tool-using agents. A tool call that leaks customer PII is a real incident; a model output that contains violence content is a real incident. You want those failure modes caught in CI, not in production.&lt;&#x2F;p&gt;
&lt;p&gt;The pattern:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Compose the guardrail config as code (Terraform &#x2F; CDK) alongside your agent definition.&lt;&#x2F;li&gt;
&lt;li&gt;In CI, deploy the guardrail to fakecloud, run a test matrix of adversarial inputs through your agent, assert that the guardrail fires (or doesn&#x27;t fire) where expected.&lt;&#x2F;li&gt;
&lt;li&gt;On merge to main, deploy the same config to real AWS.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The first two steps cost nothing. The third is the one that actually consumes budget.&lt;&#x2F;p&gt;
&lt;p&gt;This is the test loop real AWS makes nearly impossible — not because of technical obstacles, but because the cost-per-iteration is too high for the number of iterations you actually need.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bedrock emulator&lt;&#x2F;strong&gt; (landing): &lt;a href=&quot;&#x2F;bedrock-emulator&#x2F;&quot;&gt;&#x2F;bedrock-emulator&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Test Bedrock locally&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;test-bedrock-locally&#x2F;&quot;&gt;&#x2F;test-bedrock-locally&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Why not a real LLM in tests&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;blog&#x2F;bedrock-tests-real-llm&#x2F;&quot;&gt;&#x2F;blog&#x2F;bedrock-tests-real-llm&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Testing LLM guardrails&lt;&#x2F;strong&gt; (broader view): &lt;a href=&quot;&#x2F;blog&#x2F;llm-guardrails&#x2F;&quot;&gt;&#x2F;blog&#x2F;llm-guardrails&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Why your Bedrock tests shouldn&#x27;t call a real LLM (not even a local one)</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/bedrock-tests-real-llm/</link>
          <guid>https://fakecloud.dev/blog/bedrock-tests-real-llm/</guid>
          <description xml:base="https://fakecloud.dev/blog/bedrock-tests-real-llm/">&lt;p&gt;Every team building on Bedrock eventually asks the same question: for tests, should we call a real model? If the cost of real Bedrock is the concern, can we run Ollama locally and point our SDK at that?&lt;&#x2F;p&gt;
&lt;p&gt;The answer is no — but the reason is worth spelling out, because it shapes how you should think about tests for any LLM-calling code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-a-test-is-for&quot;&gt;What a test is for&lt;&#x2F;h2&gt;
&lt;p&gt;A test asserts that &lt;em&gt;your code&lt;&#x2F;em&gt; behaves correctly under a given input. Not that a model behaves correctly. Not that an API is up. Just that the code you wrote, given a response from its upstream, does the thing you expected.&lt;&#x2F;p&gt;
&lt;p&gt;The upstream, for Bedrock code, is &lt;code&gt;InvokeModel&lt;&#x2F;code&gt; or &lt;code&gt;Converse&lt;&#x2F;code&gt;. Your code sends a prompt, gets a response, and does something with it: parses JSON, branches on a label, stores it in a DB, passes it to another tool call, retries on throttling, falls back on a cheaper model. Every one of those behaviors is yours to test.&lt;&#x2F;p&gt;
&lt;p&gt;The model&#x27;s behavior is AWS&#x27;s problem.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-goes-wrong-with-real-models-in-tests&quot;&gt;What goes wrong with real models in tests&lt;&#x2F;h2&gt;
&lt;p&gt;Once you try to use real inference — whether it&#x27;s actual Bedrock or a local Ollama — four things break, in roughly ascending order of annoyance:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-non-determinism&quot;&gt;1. Non-determinism&lt;&#x2F;h3&gt;
&lt;p&gt;Real models return different text on every call. Temperature = 0 doesn&#x27;t save you: there&#x27;s non-determinism in attention kernel implementations across GPU&#x2F;CPU backends, in tokenizer versions, in batching behavior. Anthropic&#x27;s own docs say &quot;don&#x27;t rely on deterministic outputs.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;What this means for tests:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; hope this passes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(output).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;Classification: spam&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On run 1 the model returned &lt;code&gt;&quot;Classification: spam&quot;&lt;&#x2F;code&gt;. On run 2 it returned &lt;code&gt;&quot;The email is spam.&quot;&lt;&#x2F;code&gt;. Both correct. Your test fails.&lt;&#x2F;p&gt;
&lt;p&gt;The usual fix is to assert loosely:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(output.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toLowerCase&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;spam&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This passes even if the model returns &lt;code&gt;&quot;This is not spam&quot;&lt;&#x2F;code&gt;. Your test is now worthless.&lt;&#x2F;p&gt;
&lt;p&gt;People end up using LLM-as-judge (&quot;ask Claude if this response is approximately correct&quot;). That&#x27;s a research paper, not a CI pipeline.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-speed&quot;&gt;2. Speed&lt;&#x2F;h3&gt;
&lt;p&gt;Real Bedrock: 100-2000ms per call. Ollama on a developer laptop: 1-30s per call. Ollama on a CI runner without a GPU: 5-60s per call.&lt;&#x2F;p&gt;
&lt;p&gt;A test suite with 50 tests hitting the model at 5s each is 4 minutes. Ten times that and your developers stop running tests locally. CI times out. The TDD loop dies. The whole point of unit tests — fast feedback — is gone.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-resource-overhead&quot;&gt;3. Resource overhead&lt;&#x2F;h3&gt;
&lt;p&gt;Ollama-sized models are 3-70 GB on disk. &lt;code&gt;docker pull&lt;&#x2F;code&gt; on a CI runner taking 3 GB of layer cache makes your pipeline brittle. A laptop without a GPU starts thrashing memory and swapping. You now need an infrastructure project just to make tests runnable, which is the opposite of &quot;tests should be easy to run.&quot;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-you-re-testing-the-wrong-thing&quot;&gt;4. You&#x27;re testing the wrong thing&lt;&#x2F;h3&gt;
&lt;p&gt;Even if determinism, speed, and memory weren&#x27;t problems, the thing you&#x27;d be testing is whether the model handles the prompt correctly. That&#x27;s AWS&#x27;s problem. Your code could be catastrophically broken — build requests wrong, parse responses wrong, handle errors wrong — and if the model happens to hallucinate a passable answer, your test passes.&lt;&#x2F;p&gt;
&lt;p&gt;Conversely, if the model has a bad day (bad weights snapshot, a silent version bump), your tests fail even though your code is fine. You spend an hour bisecting the CI failure only to discover Claude got 3% worse at following instructions last Tuesday.&lt;&#x2F;p&gt;
&lt;p&gt;This inverts cause and effect. Tests should tell you about your code. They shouldn&#x27;t be a regression suite against a foundation model.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-tests-actually-need&quot;&gt;What tests actually need&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Deterministic output.&lt;&#x2F;strong&gt; Given the same input, same output. Every time.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Configurable responses.&lt;&#x2F;strong&gt; Different tests want the model to return different things. You want to control that explicitly.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Fault injection.&lt;&#x2F;strong&gt; Your retry logic needs to be exercised. Your fallback-model logic needs to be exercised. Your rate-limit handler needs to be exercised. You can&#x27;t wait for real throttling to happen.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Call history.&lt;&#x2F;strong&gt; Did my code send the right prompt? Did it set the right temperature? Did it include the right system message? Right tool definitions? Those are assertions about &lt;em&gt;your code&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Sub-millisecond latency.&lt;&#x2F;strong&gt; Tests should fly.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;No external dependencies.&lt;&#x2F;strong&gt; CI should work offline.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;A real LLM gives you none of those. A mock library (moto, &lt;code&gt;@aws-sdk-client-mock&lt;&#x2F;code&gt;) gives you 1, 2, and 4, but misses the HTTP path entirely — your code&#x27;s request-assembly bugs go untested.&lt;&#x2F;p&gt;
&lt;p&gt;The thing that gives you all six is a &lt;a href=&quot;&#x2F;bedrock-emulator&#x2F;&quot;&gt;Bedrock emulator&lt;&#x2F;a&gt;: a real HTTP server speaking Bedrock&#x27;s wire protocol, with configurable responses and fault injection. That&#x27;s what fakecloud is.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-this-looks-like-in-practice&quot;&gt;What this looks like in practice&lt;&#x2F;h2&gt;
&lt;p&gt;You write a test. You configure fakecloud to return a specific response when it sees a specific prompt. Your code runs. It sends a real HTTP request to &lt;code&gt;localhost:4566&lt;&#x2F;code&gt;. The request is parsed by a real JSON parser, routed through a real request validator, and responded to with your fixture. Your code parses the response, does its thing, and you assert on the outcome.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;fakecloud&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  BedrockRuntimeClient,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  InvokeModelCommand,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;@aws-sdk&#x2F;client-bedrock-runtime&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; rt&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; BedrockRuntimeClient&lt;&#x2F;span&gt;&lt;span&gt;({ endpoint:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;beforeEach&lt;&#x2F;span&gt;&lt;span&gt;(()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; fc.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;spam classifier marks borderline scores for human review&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span&gt; fc.bedrock.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;setResponseRule&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    whenPromptContains:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;classify spam&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    respond: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      completion:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; JSON&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;span&gt;({ label:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;borderline&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, confidence:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 0.62&lt;&#x2F;span&gt;&lt;span&gt; }),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; routedTo&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; classifyEmail&lt;&#x2F;span&gt;&lt;span&gt;(rt,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;buy now!!&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(routedTo).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;human-review&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;classifier retries on throttling with backoff&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span&gt; fc.bedrock.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;injectFault&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    operation:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;InvokeModel&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    error:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;ThrottlingException&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span&gt; fc.bedrock.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;setResponseRule&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    whenPromptContains:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;classify spam&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    respond: { completion:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; JSON&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;stringify&lt;&#x2F;span&gt;&lt;span&gt;({ label:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;spam&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; }) },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; routedTo&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; classifyEmail&lt;&#x2F;span&gt;&lt;span&gt;(rt,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;buy now!!&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(routedTo).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;spam-folder&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;await&lt;&#x2F;span&gt;&lt;span&gt; fc.bedrock.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getCallHistory&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;length&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both tests run in 30ms. Both are deterministic. Both test your code, not the model.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;but-i-want-some-tests-that-hit-real-bedrock&quot;&gt;But I want &lt;em&gt;some&lt;&#x2F;em&gt; tests that hit real Bedrock&lt;&#x2F;h2&gt;
&lt;p&gt;Good instinct. Keep those separate.&lt;&#x2F;p&gt;
&lt;p&gt;Put them in a suite gated behind an env var (&lt;code&gt;RUN_REAL_BEDROCK_TESTS=1&lt;&#x2F;code&gt;). Run them once per release, not once per PR. They&#x27;ll catch:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Major AWS API shape changes&lt;&#x2F;li&gt;
&lt;li&gt;Model version bumps that alter response format&lt;&#x2F;li&gt;
&lt;li&gt;IAM permission changes&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That&#x27;s a fundamentally different job from &quot;did my PR break my code.&quot; Mixing them produces a test suite that&#x27;s flaky, slow, expensive, and hides real regressions under model noise.&lt;&#x2F;p&gt;
&lt;p&gt;The unit&#x2F;integration suite, which is 99% of your runs, should hit fakecloud. The real-bedrock suite, which is a few dozen targeted tests, runs weekly. This is the same pattern every team that tests against cloud APIs converges on — you just have to name it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-word-on-ollama&quot;&gt;A word on Ollama&lt;&#x2F;h2&gt;
&lt;p&gt;Ollama is great. It&#x27;s not a Bedrock emulator. It speaks its own HTTP protocol (roughly OpenAI-compatible), runs real models, and is the right tool for developer-time exploratory prompting.&lt;&#x2F;p&gt;
&lt;p&gt;LocalStack&#x27;s Ultimate tier wraps Ollama in a Bedrock-shaped response — you get real inference on the local machine through the Bedrock SDK. Interesting product. Wrong tool for tests.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to prototype a prompt, run Ollama directly. If you want to test the code that calls Bedrock with that prompt, use an emulator.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing&quot;&gt;Closing&lt;&#x2F;h2&gt;
&lt;p&gt;The &quot;tests should use a real LLM&quot; instinct comes from a reasonable place — a fear that mocks lie, that configured responses can drift from reality, that you&#x27;ll ship a bug because your tests were checking something different than production. That fear is real, and the answer is a real server (an emulator) that speaks the real wire protocol. What you don&#x27;t need is real inference.&lt;&#x2F;p&gt;
&lt;p&gt;Your tests are about your code. The model is not your code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bedrock emulator&lt;&#x2F;strong&gt; (landing): &lt;a href=&quot;&#x2F;bedrock-emulator&#x2F;&quot;&gt;&#x2F;bedrock-emulator&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Tutorial with running code&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;blog&#x2F;bedrock-local-testing&#x2F;&quot;&gt;How to test Bedrock code locally, for free, deterministically&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LocalStack alternative for Bedrock&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;localstack-bedrock-alternative&#x2F;&quot;&gt;&#x2F;localstack-bedrock-alternative&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>CDK local testing: full flow with fakecloud and cdklocal</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/cdk-local-testing/</link>
          <guid>https://fakecloud.dev/blog/cdk-local-testing/</guid>
          <description xml:base="https://fakecloud.dev/blog/cdk-local-testing/">&lt;p&gt;AWS CDK writes CloudFormation under the hood and ships it through the AWS SDK. That means &quot;CDK local testing&quot; boils down to one question: where does the SDK send its CreateStack &#x2F; UpdateStack calls?&lt;&#x2F;p&gt;
&lt;p&gt;Pointed at real AWS, you pay per resource, wait minutes per deploy, and have to remember to destroy. Pointed at a local emulator, you iterate fast and don&#x27;t pay anything. This guide covers both flows (&lt;code&gt;cdklocal&lt;&#x2F;code&gt; wrapper and plain &lt;code&gt;cdk&lt;&#x2F;code&gt; with endpoint overrides) against &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud&lt;&#x2F;a&gt;, a free, open-source AWS emulator with real CloudFormation support (90 operations, template parsing, resource provisioning, custom resources, drift detection).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;install-fakecloud&quot;&gt;Install fakecloud&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Listens on &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt;. ~500ms startup.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;option-1-plain-cdk-with-aws-endpoint-url&quot;&gt;Option 1: plain &lt;code&gt;cdk&lt;&#x2F;code&gt; with &lt;code&gt;AWS_ENDPOINT_URL&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Simplest and works with any CDK version that uses AWS SDK v3 (CDK 2.67+).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_REGION&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; CDK_DEFAULT_ACCOUNT&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;000000000000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; CDK_DEFAULT_REGION&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cdk&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; bootstrap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cdk&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; deploy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s it. Same &lt;code&gt;cdk&lt;&#x2F;code&gt; binary you use for prod, pointed at fakecloud for dev.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;option-2-cdklocal-wrapper&quot;&gt;Option 2: &lt;code&gt;cdklocal&lt;&#x2F;code&gt; wrapper&lt;&#x2F;h2&gt;
&lt;p&gt;If your team is already using &lt;code&gt;cdklocal&lt;&#x2F;code&gt; (from the LocalStack ecosystem), it works the same way against fakecloud:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cdklocal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; bootstrap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cdklocal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; deploy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;a-minimal-stack&quot;&gt;A minimal stack&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; lib&#x2F;my-stack.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { Stack, StackProps }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;aws-cdk-lib&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { Bucket }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;aws-cdk-lib&#x2F;aws-s3&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { Function, Runtime, Code }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;aws-cdk-lib&#x2F;aws-lambda&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { Queue }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;aws-cdk-lib&#x2F;aws-sqs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { SqsEventSource }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;aws-cdk-lib&#x2F;aws-lambda-event-sources&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { Construct }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;constructs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; MyStack&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; extends&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; Stack&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  constructor&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;scope&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; Construct&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; props&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;?:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; StackProps&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;    super&lt;&#x2F;span&gt;&lt;span&gt;(scope, id, props);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; Bucket&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;this&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Uploads&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; queue&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; Queue&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;this&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Jobs&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; processor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; Function&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;this&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Processor&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      runtime: Runtime.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;NODEJS_20_X&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;index.handler&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      code: Code.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;fromInline&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;        `exports.handler = async (event) =&amp;gt; ({ ok: true, received: event })`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    processor.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;addEventSource&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; SqsEventSource&lt;&#x2F;span&gt;&lt;span&gt;(queue));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bucket.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;grantRead&lt;&#x2F;span&gt;&lt;span&gt;(processor);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Deploy:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cdk&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; deploy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Verify:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 cloudformation describe-stacks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 lambda list-functions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 ls&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Trigger the flow:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;hi&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 cp - s3:&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3api list-buckets&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --query&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Buckets[0].Name&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --output&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; text&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&#x2F;file.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 logs tail &#x2F;aws&#x2F;lambda&#x2F;MyStack-Processor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --since&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; 1m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Your Lambda code actually runs (fakecloud pulls the real Node 20 runtime container). The SQS -&amp;gt; Lambda event source mapping actually fires. CloudFormation actually provisioned the resources from the template CDK generated.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ci-integration&quot;&gt;CI integration&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  cdk&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    env&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_REGION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      CDK_DEFAULT_ACCOUNT&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;000000000000&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      CDK_DEFAULT_REGION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; actions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; actions&#x2F;setup-node@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; node-version&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; Start fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          fakecloud &amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          for i in $(seq 1 30); do curl -sf http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;health &amp;amp;&amp;amp; break; sleep 1; done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          curl -sf http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;health&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npx cdk bootstrap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npx cdk deploy --require-approval never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;assertions-from-tests&quot;&gt;Assertions from tests&lt;&#x2F;h2&gt;
&lt;p&gt;CDK integration tests usually fall into two shapes:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. Synth assertions&lt;&#x2F;strong&gt; — what CloudFormation does your CDK emit. These don&#x27;t need fakecloud; use CDK&#x27;s &lt;code&gt;@aws-cdk&#x2F;assert&lt;&#x2F;code&gt; or &lt;code&gt;aws-cdk-lib&#x2F;assertions&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. Deployed-stack behavior&lt;&#x2F;strong&gt; — does the stack actually work when deployed. For these, deploy to fakecloud and assert on real side effects:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;fakecloud&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;upload triggers lambda&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; uploadToBucket&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;uploads&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;test.txt&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;hello&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; invocations&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.lambda.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getInvocations&lt;&#x2F;span&gt;&lt;span&gt;({ functionName:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Processor&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;afterEach&lt;&#x2F;span&gt;&lt;span&gt;(()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; fc.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;fakecloud SDKs available in TypeScript, Python, Go, PHP, Java, Rust.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;destroy-between-tests&quot;&gt;Destroy between tests&lt;&#x2F;h2&gt;
&lt;p&gt;CloudFormation state persists across tests unless you destroy or reset:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Full stack teardown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cdk&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; destroy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --force&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# OR reset fakecloud&amp;#39;s entire state (faster)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -X&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; POST http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;reset&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Reset is ~instant and covers every service. &lt;code&gt;cdk destroy&lt;&#x2F;code&gt; only unwinds one stack at a time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-this-works&quot;&gt;Why this works&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud targets 100% behavioral conformance per implemented service. CloudFormation (90 operations), Lambda (85 ops, real code execution in 13 runtimes), SQS (23 ops), S3 (107 ops) — all in. Cross-service wiring like S3 -&amp;gt; Lambda event sources and SQS -&amp;gt; Lambda event source mappings actually execute server-side, not as stubs.&lt;&#x2F;p&gt;
&lt;p&gt;The depth-first goal: 100% of AWS services, each at 100% conformance, with 100% cross-service integrations. 23 services shipped today; more land one-at-a-time as they pass the conformance bar.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Install: &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Repo: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Terraform local dev guide: &lt;a href=&quot;&#x2F;blog&#x2F;terraform-local-development-aws&#x2F;&quot;&gt;Terraform local development for AWS&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;LocalStack migration guide: &lt;a href=&quot;&#x2F;blog&#x2F;migrate-from-localstack&#x2F;&quot;&gt;Migrating from LocalStack to fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Issues: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Integration testing AWS in GitHub Actions without mocks</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/integration-testing-aws-in-ci/</link>
          <guid>https://fakecloud.dev/blog/integration-testing-aws-in-ci/</guid>
          <description xml:base="https://fakecloud.dev/blog/integration-testing-aws-in-ci/">&lt;p&gt;Most &quot;AWS integration tests&quot; in CI are not integration tests. They are unit tests with a mocking library — moto, aws-sdk-client-mock, something similar — that intercepts the AWS SDK inside the test process and returns fabricated responses. Those tests pass when your code is wrong, because the mock only knows what you told it.&lt;&#x2F;p&gt;
&lt;p&gt;A real integration test talks to a real AWS-shaped service over HTTP. Testcontainers-LocalStack is the historical answer, but LocalStack&#x27;s Community Edition went proprietary in March 2026 and now requires an account and an auth token just to pull the image.&lt;&#x2F;p&gt;
&lt;p&gt;This post shows how to run real AWS integration tests in CI against &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud&lt;&#x2F;a&gt; — a free, open-source AWS emulator — with copy-paste configs for GitHub Actions, GitLab CI, and CircleCI.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-run-fakecloud-in-ci&quot;&gt;Why run fakecloud in CI&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;~500ms startup vs ~3s for a LocalStack container. Over hundreds of test runs, this matters.&lt;&#x2F;li&gt;
&lt;li&gt;~19 MB binary, ~10 MiB idle memory. Lightweight on shared runners.&lt;&#x2F;li&gt;
&lt;li&gt;Single binary, no Docker required for most services (Docker still needed for Lambda, RDS, ElastiCache).&lt;&#x2F;li&gt;
&lt;li&gt;No account, no auth token, no license key. &lt;code&gt;fakecloud&lt;&#x2F;code&gt; and you&#x27;re running.&lt;&#x2F;li&gt;
&lt;li&gt;Covers 23 services at 100% conformance per service, including Cognito, SES v2, RDS, ElastiCache, API Gateway v2, Bedrock — the ones LocalStack moved behind the paywall.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;github-actions-install-and-run-pattern&quot;&gt;GitHub Actions: install-and-run pattern&lt;&#x2F;h2&gt;
&lt;p&gt;The fastest CI setup is to install the binary and background it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; pull_request&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  integration&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    env&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_REGION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; actions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; Install fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; Start fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fakecloud &amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; Wait for fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          for i in $(seq 1 30); do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;            curl -sf http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;health &amp;amp;&amp;amp; exit 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;            sleep 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          echo &amp;quot;fakecloud did not start&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          exit 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; actions&#x2F;setup-node@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;          node-version&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;AWS_ENDPOINT_URL&lt;&#x2F;code&gt; is respected by the AWS SDK v3 automatically — you do not need to configure your application code separately for CI vs local.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;github-actions-service-container-pattern&quot;&gt;GitHub Actions: service container pattern&lt;&#x2F;h2&gt;
&lt;p&gt;If you prefer a Docker service container (longer startup, cleaner isolation):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  integration&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    services&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      fakecloud&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ghcr.io&#x2F;faiscadev&#x2F;fakecloud:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        ports&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; 4566:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    env&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_REGION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; actions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Use this if your test harness expects the service to be ready before the job&#x27;s steps run (service containers start first).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lambda-in-github-actions&quot;&gt;Lambda in GitHub Actions&lt;&#x2F;h2&gt;
&lt;p&gt;Lambda needs Docker-in-Docker (fakecloud launches real Lambda runtime containers). On the default &lt;code&gt;ubuntu-latest&lt;&#x2F;code&gt; runner, Docker is already available — you just need to mount the socket:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  fakecloud&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ghcr.io&#x2F;faiscadev&#x2F;fakecloud:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    ports&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; 4566:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    volumes&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &#x2F;var&#x2F;run&#x2F;docker.sock:&#x2F;var&#x2F;run&#x2F;docker.sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or with the install-and-run pattern, Docker is available on the host directly — nothing extra needed. The fakecloud process launches Lambda containers on the host&#x27;s Docker.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gitlab-ci&quot;&gt;GitLab CI&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;stages&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;integration&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  stage&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; node:20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  services&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ghcr.io&#x2F;faiscadev&#x2F;fakecloud:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      alias&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  variables&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;fakecloud:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    AWS_REGION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  script&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note the endpoint uses the service alias (&lt;code&gt;fakecloud&lt;&#x2F;code&gt;), not &lt;code&gt;localhost&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;circleci&quot;&gt;CircleCI&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;version&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 2.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  integration&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    docker&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; cimg&#x2F;node:20.11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ghcr.io&#x2F;faiscadev&#x2F;fakecloud:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    environment&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_REGION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; checkout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;workflows&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  build&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    jobs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; integration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CircleCI&#x27;s secondary Docker images share the primary image&#x27;s localhost, so &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt; works.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;example-test-sqs-consumer-integration&quot;&gt;Example test: SQS consumer integration&lt;&#x2F;h2&gt;
&lt;p&gt;Your code under test:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; src&#x2F;queue.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { SQSClient, SendMessageCommand }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;@aws-sdk&#x2F;client-sqs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export async function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; enqueue&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;body&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; queueUrl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; sqs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; SQSClient&lt;&#x2F;span&gt;&lt;span&gt;({});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span&gt; sqs.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; SendMessageCommand&lt;&#x2F;span&gt;&lt;span&gt;({ QueueUrl: queueUrl, MessageBody: body }));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Your integration test:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; test&#x2F;queue.test.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { SQSClient, CreateQueueCommand, ReceiveMessageCommand }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;@aws-sdk&#x2F;client-sqs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { enqueue }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;..&#x2F;src&#x2F;queue&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; sqs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; SQSClient&lt;&#x2F;span&gt;&lt;span&gt;({});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;enqueue actually enqueues&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; QueueUrl&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; sqs.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; CreateQueueCommand&lt;&#x2F;span&gt;&lt;span&gt;({ QueueName:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test-&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; Date.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;now&lt;&#x2F;span&gt;&lt;span&gt;() }));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; enqueue&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;hello&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, QueueUrl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; res&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; sqs.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; ReceiveMessageCommand&lt;&#x2F;span&gt;&lt;span&gt;({ QueueUrl, WaitTimeSeconds:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt; }));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(res.Messages?.[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;]?.Body).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;hello&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No mocks. The test creates a real queue, enqueues a real message, receives a real message. If your code is wrong, the test fails the way a real-AWS test would fail.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;asserting-on-fan-out-and-async-flows&quot;&gt;Asserting on fan-out and async flows&lt;&#x2F;h2&gt;
&lt;p&gt;For flows that cross services (SQS -&amp;gt; Lambda -&amp;gt; SNS -&amp;gt; DynamoDB), use the fakecloud test-assertion SDK to inspect what each hop did:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;fakecloud&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;order publishes and lambda invokes&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; placeOrder&lt;&#x2F;span&gt;&lt;span&gt;({ id:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;o1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;span style=&quot;color: #768390;&quot;&gt; &#x2F;&#x2F; your code under test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; messages&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.sns.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getPublishedMessages&lt;&#x2F;span&gt;&lt;span&gt;({ topicName:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;orders&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(messages).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; invocations&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.lambda.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getInvocations&lt;&#x2F;span&gt;&lt;span&gt;({ functionName:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;on-order&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].statusCode).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;afterEach&lt;&#x2F;span&gt;&lt;span&gt;(()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; fc.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;SDK available in TypeScript, Python, Go, PHP, Java, Rust. Docs: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;docs&#x2F;sdks&quot;&gt;fakecloud.dev&#x2F;docs&#x2F;sdks&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tips&quot;&gt;Tips&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reset between tests.&lt;&#x2F;strong&gt; Either &lt;code&gt;await fc.reset()&lt;&#x2F;code&gt; in an &lt;code&gt;afterEach&lt;&#x2F;code&gt;, or use per-test resources with unique names (&lt;code&gt;test-${Date.now()}&lt;&#x2F;code&gt;). Reset is faster for large suites.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Run integration tests in a separate job&lt;&#x2F;strong&gt; from unit tests. Unit tests should not need fakecloud; integration tests should not run alongside mocked ones.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Pin the image tag&lt;&#x2F;strong&gt; in CI (&lt;code&gt;ghcr.io&#x2F;faiscadev&#x2F;fakecloud:0.10.1&lt;&#x2F;code&gt;) if you want deterministic behavior across builds. &lt;code&gt;latest&lt;&#x2F;code&gt; is fine for most teams.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Don&#x27;t mix fakecloud with mocks.&lt;&#x2F;strong&gt; Pick one per test. If you mock inside a test that also talks to fakecloud, you will get confusing failures.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;one-call-out&quot;&gt;One call-out&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Performance benchmarking&lt;&#x2F;strong&gt; is different from correctness testing. fakecloud and AWS have different performance characteristics (by design — fakecloud is a local process, AWS is a distributed global system). Benchmark performance against real AWS. Benchmark correctness and behavior against fakecloud.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud&#x27;s goal is every AWS service at 100% conformance with 100% of cross-service integrations. If a service your tests hit isn&#x27;t in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud#supported-services&quot;&gt;supported list&lt;&#x2F;a&gt; yet, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;file an issue&lt;&#x2F;a&gt; — the roadmap is demand-driven and services land one at a time with the full conformance target, not a partial-surface-first approach.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Install: &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Repo: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Migration from LocalStack: &lt;a href=&quot;&#x2F;blog&#x2F;migrate-from-localstack&#x2F;&quot;&gt;Migrating from LocalStack to fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Lambda tutorial: &lt;a href=&quot;&#x2F;blog&#x2F;test-lambda-locally&#x2F;&quot;&gt;How to test Lambda locally&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Issues: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Free LocalStack alternatives in 2026: fakecloud, MiniStack, floci, Moto</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/localstack-alternatives-compared/</link>
          <guid>https://fakecloud.dev/blog/localstack-alternatives-compared/</guid>
          <description xml:base="https://fakecloud.dev/blog/localstack-alternatives-compared/">&lt;p&gt;LocalStack&#x27;s Community Edition went proprietary in March 2026. Since then a few free, open-source alternatives have surfaced or gained momentum. This post covers the four that keep coming up — fakecloud, MiniStack, floci, and Moto — and what each one is, architecturally.&lt;&#x2F;p&gt;
&lt;p&gt;Upfront disclosure: I maintain fakecloud. Bias declared. What this post avoids: a head-to-head scorecard with numbers I haven&#x27;t personally measured on all four. That kind of comparison gets out of date in days and reads as marketing when the numbers are favorable to the author. Instead: what each project is, the design choices it&#x27;s made, and how to think about the fit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-architectural-split-that-matters&quot;&gt;The architectural split that matters&lt;&#x2F;h2&gt;
&lt;p&gt;Two ways to emulate AWS for tests:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. In-process library that patches the SDK.&lt;&#x2F;strong&gt; Import a library, decorate your test, library intercepts SDK calls inside your test process. Moto works this way. Fast, no external process, trivial Python setup. Does not speak the AWS wire protocol. Cannot run real Lambda code, real databases, or real Redis.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. Real HTTP server speaking the AWS wire protocol.&lt;&#x2F;strong&gt; Separate process on port 4566. SDK points at it via &lt;code&gt;endpoint_url&lt;&#x2F;code&gt;. LocalStack, MiniStack, floci, and fakecloud all work this way. Any AWS SDK in any language works. Cross-service wiring runs server-side.&lt;&#x2F;p&gt;
&lt;p&gt;If your tests are &quot;does my Python function call boto3 correctly,&quot; Moto. If your tests are &quot;does my whole system actually work end-to-end,&quot; HTTP server.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;two-approaches-among-the-http-servers&quot;&gt;Two approaches among the HTTP servers&lt;&#x2F;h2&gt;
&lt;p&gt;Among the HTTP emulators there&#x27;s another split that matters, especially for AI-assisted dev and real integration tests:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Breadth-first:&lt;&#x2F;strong&gt; ship a large catalog of AWS services fast, with partial&#x2F;surface coverage on each — enough to accept the common calls and return plausible shapes. Good when your tests lean lightly on many services.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Depth-first:&lt;&#x2F;strong&gt; ship fewer services but at 100% behavioral parity, with real code execution, real stateful backends, and real cross-service wire-ups. Good when your tests actually exercise cross-service flows, or when you want an AI coding agent to be able to rely on the emulator behaving like AWS.&lt;&#x2F;p&gt;
&lt;p&gt;These are philosophies, not rankings. Different workloads prefer different ones.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fakecloud&quot;&gt;fakecloud&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;What it is:&lt;&#x2F;strong&gt; single static binary written in Rust, ~19 MB. Speaks the AWS wire protocol on port 4566. No account, no token, no paid tier. AGPL-3.0.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Approach:&lt;&#x2F;strong&gt; depth-first.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Explicit goal:&lt;&#x2F;strong&gt; 100% of AWS services, each at 100% behavioral conformance with 100% of cross-service integrations. Services are added one at a time; a service lands when it passes the full Smithy-model test variants and the cross-service wire-ups that matter for it — not when the API surface looks filled in. The roadmap is driven by real-project demand.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What it covers today:&lt;&#x2F;strong&gt; 23 services, 1,680 operations: S3, SQS, SNS, DynamoDB, Lambda, IAM, STS, KMS, Secrets Manager, SSM, CloudWatch Logs, CloudFormation, EventBridge, EventBridge Scheduler, SES (v2 + v1 inbound), Cognito User Pools, Kinesis, RDS, ElastiCache, Step Functions, API Gateway v2, Bedrock, Bedrock Runtime.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Distinctive choices driven by the depth-first goal:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Real Lambda execution across 13 runtimes in Docker containers — your function code runs, not a stub.&lt;&#x2F;li&gt;
&lt;li&gt;Real stateful backends: RDS runs real PostgreSQL&#x2F;MySQL&#x2F;MariaDB via Docker; ElastiCache runs real Redis&#x2F;Valkey.&lt;&#x2F;li&gt;
&lt;li&gt;Cross-service wiring that actually fires: EventBridge -&amp;gt; Step Functions, S3 -&amp;gt; Lambda, SES inbound -&amp;gt; S3&#x2F;SNS&#x2F;Lambda, 15+ more integrations.&lt;&#x2F;li&gt;
&lt;li&gt;Multi-account, SCPs, ABAC, permission boundaries, session policies, KMS key policies, bucket policies — full Allow&#x2F;Deny&#x2F;NotPrincipal semantics.&lt;&#x2F;li&gt;
&lt;li&gt;First-party test-assertion SDKs in TypeScript, Python, Go, PHP, Java, Rust.&lt;&#x2F;li&gt;
&lt;li&gt;Conformance validated on every commit against 54,000+ Smithy-generated test variants, plus the upstream &lt;code&gt;hashicorp&#x2F;terraform-provider-aws&lt;&#x2F;code&gt; &lt;code&gt;TestAcc*&lt;&#x2F;code&gt; suites.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Source:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ministack&quot;&gt;MiniStack&lt;&#x2F;h2&gt;
&lt;p&gt;A free LocalStack alternative that surfaced during the March 2026 paywall window. Check the repo for current service coverage, architecture, and approach — the project moves quickly, so numbers in any blog post will be stale within weeks. Evaluate on your test suite&#x27;s actual needs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;floci&quot;&gt;floci&lt;&#x2F;h2&gt;
&lt;p&gt;Another free LocalStack alternative from the same window. Landing page publishes performance claims — verify them against the version you&#x27;d actually run before relying on the numbers. Evaluate on your test suite&#x27;s actual needs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;moto&quot;&gt;Moto&lt;&#x2F;h2&gt;
&lt;p&gt;Longest-lived open-source AWS mocking project. Python library, in-process, patches &lt;code&gt;boto3&lt;&#x2F;code&gt;. Broad service surface at varying depth. Excellent for Python unit tests where you want boto3 to respond plausibly inside your test process. Not usable from other languages, does not run Lambda code, does not talk to Terraform&#x2F;CDK deploys.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Source:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;getmoto&#x2F;moto&quot;&gt;github.com&#x2F;getmoto&#x2F;moto&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;localstack-pro-for-completeness&quot;&gt;LocalStack Pro (for completeness)&lt;&#x2F;h2&gt;
&lt;p&gt;Paid tier, mature catalog, commercial support, proprietary license. Fits teams OK with proprietary and per-seat pricing who need the whole LocalStack catalog.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-to-pick&quot;&gt;How to pick&lt;&#x2F;h2&gt;
&lt;p&gt;Avoid the temptation to pick by &quot;which has more services.&quot; All four of the HTTP emulators (fakecloud, MiniStack, floci, LocalStack Pro) are moving targets; service counts change week to week. The durable questions are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Do your tests exercise cross-service flows?&lt;&#x2F;strong&gt; (S3 triggers Lambda, EventBridge routes to Step Functions, SES inbound writes to S3, etc.) If yes, depth-first matters more than breadth. The emulator needs to actually &lt;em&gt;wire&lt;&#x2F;em&gt; those flows, not just accept each call in isolation.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Do you need real code execution?&lt;&#x2F;strong&gt; (Does your Lambda function actually run, or do you just need a response shape?) fakecloud runs Lambda code in real Docker runtimes; some alternatives return synthetic responses.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Do you need real stateful backends?&lt;&#x2F;strong&gt; (Does your Postgres schema matter? Your Redis data structures?) fakecloud runs real PostgreSQL&#x2F;MySQL&#x2F;MariaDB&#x2F;Redis&#x2F;Valkey; alternatives vary.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;What language are your tests?&lt;&#x2F;strong&gt; Moto is Python-only. Everything else is language-agnostic over HTTP.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;How much of AWS does your test mix actually hit?&lt;&#x2F;strong&gt; Open your test suite. Count unique AWS services called. That number is almost always smaller than &quot;total AWS services&quot; and is the only count that matters.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Run your real test suite against each option you&#x27;re considering. That&#x27;s the only benchmark that applies to your codebase.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;fakecloud: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Moto: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;getmoto&#x2F;moto&quot;&gt;github.com&#x2F;getmoto&#x2F;moto&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;LocalStack: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;localstack.cloud&quot;&gt;localstack.cloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;fakecloud install options: &lt;a href=&quot;&#x2F;docs&#x2F;getting-started&#x2F;&quot;&gt;fakecloud.dev&#x2F;docs&#x2F;getting-started&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;fakecloud migration guide: &lt;a href=&quot;&#x2F;blog&#x2F;migrate-from-localstack&#x2F;&quot;&gt;Migrating from LocalStack to fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>LocalStack Ultimate covers 4 Bedrock ops. Here&#x27;s why that&#x27;s the wrong bet for tests.</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/localstack-ultimate-bedrock/</link>
          <guid>https://fakecloud.dev/blog/localstack-ultimate-bedrock/</guid>
          <description xml:base="https://fakecloud.dev/blog/localstack-ultimate-bedrock/">&lt;p&gt;If you&#x27;ve been looking for a local Bedrock emulator and landed on LocalStack&#x27;s documentation, you&#x27;ve seen this: Bedrock is available, but only on the Ultimate plan, and only four operations are supported. Those four operations are backed by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ollama.com&quot;&gt;Ollama&lt;&#x2F;a&gt;, the local-LLM runtime.&lt;&#x2F;p&gt;
&lt;p&gt;This is a real product decision, not an accident. It&#x27;s worth understanding what it gets you, what it doesn&#x27;t, and why fakecloud took a very different approach.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-localstack-ultimate-gives-you-for-bedrock&quot;&gt;What LocalStack Ultimate gives you for Bedrock&lt;&#x2F;h2&gt;
&lt;p&gt;Per &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;aws&#x2F;services&#x2F;bedrock&#x2F;&quot;&gt;docs.localstack.cloud&#x2F;aws&#x2F;services&#x2F;bedrock&lt;&#x2F;a&gt;, as of April 2026:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tier&lt;&#x2F;strong&gt;: Ultimate plan only. This is the top paid tier.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Operations&lt;&#x2F;strong&gt;: &lt;code&gt;InvokeModel&lt;&#x2F;code&gt;, &lt;code&gt;Converse&lt;&#x2F;code&gt;, &lt;code&gt;ListFoundationModels&lt;&#x2F;code&gt;, &lt;code&gt;CreateModelInvocationJob&lt;&#x2F;code&gt;. Four, total.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Backend&lt;&#x2F;strong&gt;: Ollama, called via its HTTP API.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Models&lt;&#x2F;strong&gt;: whatever Ollama supports — Llama, Mistral, Phi, etc. You call them via &lt;code&gt;ollama.&amp;lt;model-id&amp;gt;&lt;&#x2F;code&gt; strings through the Bedrock SDK.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Limitations per the docs&lt;&#x2F;strong&gt;: only text models, no GPU, no persistence, and responsiveness issues on Docker Desktop due to storage&#x2F;memory constraints.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That&#x27;s the whole product. The &quot;Bedrock&quot; you&#x27;re calling in your code is a LocalStack process forwarding your request to Ollama, which runs a model like Llama 3 on your CPU or GPU, and returns the response in a Bedrock-shaped envelope.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-that-actually-means-at-the-test-bench&quot;&gt;What that actually means at the test bench&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s be concrete. You&#x27;re writing tests for code that calls &lt;code&gt;anthropic.claude-3-haiku-20240307-v1:0&lt;&#x2F;code&gt; (Haiku). You point your SDK at LocalStack Ultimate&#x27;s Bedrock. What happens:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Haiku doesn&#x27;t exist locally. You have to set &lt;code&gt;DEFAULT_BEDROCK_MODEL=ollama.llama3.2&lt;&#x2F;code&gt; (or whichever Ollama model you have installed).&lt;&#x2F;li&gt;
&lt;li&gt;Your code&#x27;s &lt;code&gt;modelId: &quot;anthropic.claude-3-haiku-20240307-v1:0&quot;&lt;&#x2F;code&gt; string gets routed to Llama 3.2.&lt;&#x2F;li&gt;
&lt;li&gt;Your prompt, which was tuned for Claude, runs through Llama, which interprets it differently.&lt;&#x2F;li&gt;
&lt;li&gt;The response comes back. Llama&#x27;s output goes through Bedrock&#x27;s response envelope shape.&lt;&#x2F;li&gt;
&lt;li&gt;Your code parses the envelope, extracts the text, and... what?&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;If your code is doing structured extraction (return JSON matching schema X), Llama and Claude don&#x27;t produce identical JSON even at temperature 0. If your code is doing classification, they disagree on edge cases. If your code is doing agent work with tool use, they have different tool-use protocols entirely (Claude&#x27;s tool-use format differs from Llama&#x27;s function-calling format).&lt;&#x2F;p&gt;
&lt;p&gt;You are not testing your Claude code. You are testing whether your Claude code happens to also work against Llama when shimmed through a Bedrock envelope.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-slowness-problem&quot;&gt;The slowness problem&lt;&#x2F;h2&gt;
&lt;p&gt;Ollama on CPU: 1-30 seconds per call depending on model and prompt length.&lt;&#x2F;p&gt;
&lt;p&gt;Ollama on GPU (if you have one): 100ms-3s per call.&lt;&#x2F;p&gt;
&lt;p&gt;Bedrock on real AWS: 100-2000ms per call.&lt;&#x2F;p&gt;
&lt;p&gt;The &quot;local&quot; Bedrock is often slower than the cloud one. And you get non-determinism either way.&lt;&#x2F;p&gt;
&lt;p&gt;The LocalStack docs explicitly mention &lt;code&gt;BEDROCK_PREWARM&lt;&#x2F;code&gt; to reduce startup delays, which is an acknowledgment of the pain — you&#x27;re essentially waiting for Ollama to load a multi-GB model into memory before your test suite can start. CI runners without &lt;code&gt;--shm-size&lt;&#x2F;code&gt; tuning routinely OOM during this.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-four-operations&quot;&gt;The four operations&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;InvokeModel&lt;&#x2F;code&gt; and &lt;code&gt;Converse&lt;&#x2F;code&gt; are the data plane — the calls your application makes at runtime. That&#x27;s the part Ollama can back.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;ListFoundationModels&lt;&#x2F;code&gt; returns which models exist.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;CreateModelInvocationJob&lt;&#x2F;code&gt; starts an async batch job against S3 input. This is partial support (based on what the docs describe) — it&#x27;s the only control-plane operation covered.&lt;&#x2F;p&gt;
&lt;p&gt;What&#x27;s not covered:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Guardrails&lt;&#x2F;li&gt;
&lt;li&gt;Custom models &#x2F; customization jobs&lt;&#x2F;li&gt;
&lt;li&gt;Model import&lt;&#x2F;li&gt;
&lt;li&gt;Inference profiles&lt;&#x2F;li&gt;
&lt;li&gt;Provisioned throughput&lt;&#x2F;li&gt;
&lt;li&gt;Model copy jobs&lt;&#x2F;li&gt;
&lt;li&gt;Prompt management&lt;&#x2F;li&gt;
&lt;li&gt;Foundation model agreements&lt;&#x2F;li&gt;
&lt;li&gt;Resource policies&lt;&#x2F;li&gt;
&lt;li&gt;Logging configuration&lt;&#x2F;li&gt;
&lt;li&gt;Evaluation jobs&lt;&#x2F;li&gt;
&lt;li&gt;Marketplace&lt;&#x2F;li&gt;
&lt;li&gt;Automated reasoning&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If your test code touches anything in that list — and any serious Bedrock integration touches several of them — LocalStack Ultimate&#x27;s Bedrock emulation doesn&#x27;t help.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-fakecloud-does-differently&quot;&gt;What fakecloud does differently&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud covers 111 Bedrock operations. The data plane (InvokeModel, Converse, streaming variants) is not backed by a real LLM — it returns exactly the responses you configure, per-prompt rule.&lt;&#x2F;p&gt;
&lt;p&gt;This is the deliberate opposite of LocalStack Ultimate&#x27;s choice:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;LocalStack Ultimate Bedrock&lt;&#x2F;th&gt;&lt;th&gt;fakecloud Bedrock&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Pricing&lt;&#x2F;td&gt;&lt;td&gt;Top-tier paid plan&lt;&#x2F;td&gt;&lt;td&gt;Free, AGPL-3.0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Data plane&lt;&#x2F;td&gt;&lt;td&gt;Ollama (real local LLM)&lt;&#x2F;td&gt;&lt;td&gt;Configurable responses per prompt rule&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Determinism&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Speed&lt;&#x2F;td&gt;&lt;td&gt;1-30s per call&lt;&#x2F;td&gt;&lt;td&gt;Milliseconds&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Guardrails&lt;&#x2F;td&gt;&lt;td&gt;Not supported&lt;&#x2F;td&gt;&lt;td&gt;Full CRUD + real content evaluation&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Custom models&lt;&#x2F;td&gt;&lt;td&gt;Not supported&lt;&#x2F;td&gt;&lt;td&gt;Full control plane&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Async batch&lt;&#x2F;td&gt;&lt;td&gt;Partial&lt;&#x2F;td&gt;&lt;td&gt;Full flow&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Prompt management&lt;&#x2F;td&gt;&lt;td&gt;Not supported&lt;&#x2F;td&gt;&lt;td&gt;Prompts + prompt routers&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GPU required&lt;&#x2F;td&gt;&lt;td&gt;Usually&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Persistence&lt;&#x2F;td&gt;&lt;td&gt;&quot;Not supported&quot; (from docs)&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;why-ollama-is-the-wrong-backing-for-a-bedrock-emulator&quot;&gt;Why Ollama is the wrong backing for a Bedrock emulator&lt;&#x2F;h2&gt;
&lt;p&gt;The word &quot;emulator&quot; and the word &quot;Bedrock&quot; together set an expectation: I can run a simulation of Bedrock locally. People reach for that when they want to test their Bedrock-calling code.&lt;&#x2F;p&gt;
&lt;p&gt;Testing code that calls an LLM API and testing an LLM are different problems. The first wants determinism, speed, fault injection, and call-history introspection. The second wants a real model.&lt;&#x2F;p&gt;
&lt;p&gt;LocalStack&#x27;s Ultimate Bedrock chose the second. That decision makes sense if your goal is &quot;let me prototype against a Bedrock SDK without burning tokens.&quot; It&#x27;s the wrong decision if your goal is &quot;let me have fast, deterministic integration tests of my production Bedrock code.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud picked the first job and optimized hard for it. If you want real inference locally, run Ollama directly — it&#x27;s free, open source, and does that job excellently. If you want deterministic Bedrock behavior in your test suite, you want an emulator with configured responses.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;when-to-pay-for-localstack-ultimate-anyway&quot;&gt;When to pay for LocalStack Ultimate anyway&lt;&#x2F;h2&gt;
&lt;p&gt;There are reasons to pay for LocalStack Ultimate that aren&#x27;t about Bedrock. Their core strength is deep coverage of the long tail of AWS services — things like ACM, Certificate Manager, Backup, Config, etc. If you rely on those in your infrastructure and you want a local mirror of them, paying for Ultimate may be worth it.&lt;&#x2F;p&gt;
&lt;p&gt;If the Bedrock emulation is the reason you were about to open a procurement ticket for Ultimate, though, stop. Bedrock-on-Ollama isn&#x27;t going to solve your test problem. What will solve it is an emulator built for tests — which you can get for free.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-to-do-next&quot;&gt;What to do next&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re currently testing against real Bedrock, start with &lt;a href=&quot;&#x2F;blog&#x2F;bedrock-local-testing&#x2F;&quot;&gt;how to test Bedrock code locally&lt;&#x2F;a&gt; — walks through the full pattern end to end.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re on LocalStack Ultimate and Bedrock was the draw, look at &lt;a href=&quot;&#x2F;localstack-bedrock-alternative&#x2F;&quot;&gt;the migration comparison&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to understand why &quot;just use Ollama&quot; doesn&#x27;t work as a test strategy, &lt;a href=&quot;&#x2F;blog&#x2F;bedrock-tests-real-llm&#x2F;&quot;&gt;here&#x27;s a longer version of the argument&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Install fakecloud&lt;&#x2F;strong&gt;: &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LocalStack Bedrock docs (cited)&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;aws&#x2F;services&#x2F;bedrock&#x2F;&quot;&gt;docs.localstack.cloud&#x2F;aws&#x2F;services&#x2F;bedrock&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Bedrock emulator landing&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;bedrock-emulator&#x2F;&quot;&gt;&#x2F;bedrock-emulator&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Migration landing&lt;&#x2F;strong&gt;: &lt;a href=&quot;&#x2F;localstack-bedrock-alternative&#x2F;&quot;&gt;&#x2F;localstack-bedrock-alternative&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Migrating from LocalStack to fakecloud in 10 minutes</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/migrate-from-localstack/</link>
          <guid>https://fakecloud.dev/blog/migrate-from-localstack/</guid>
          <description xml:base="https://fakecloud.dev/blog/migrate-from-localstack/">&lt;p&gt;In March 2026, LocalStack replaced its open-source Community Edition with a proprietary image that requires an account and an auth token. If your build broke last month, this guide is for you. If you are still on a pinned older tag and worried about the next pull, this is also for you.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud is a free, open-source AWS emulator — single binary, no account, no token, no paid tier — that covers the services most teams relied on LocalStack Community for, plus several that moved to LocalStack Pro (RDS, ElastiCache, Cognito User Pools, SES v2, API Gateway v2).&lt;&#x2F;p&gt;
&lt;p&gt;This guide is step-by-step. Copy, paste, done.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-one-line-summary&quot;&gt;The one-line summary&lt;&#x2F;h2&gt;
&lt;p&gt;Change the image or the install command. Keep &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt; and your dummy credentials. Everything else stays the same.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-1-stop-localstack&quot;&gt;Step 1: Stop LocalStack&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; compose down&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# or: docker kill $(docker ps -q --filter ancestor=localstack&#x2F;localstack)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;step-2-install-fakecloud&quot;&gt;Step 2: Install fakecloud&lt;&#x2F;h2&gt;
&lt;p&gt;Pick one:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Option A: single binary, no Docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Option B: Docker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --rm -p&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; 4566:4566 ghcr.io&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Option C: cargo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cargo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; install fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;fakecloud listens on &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt; — same as LocalStack.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-3-keep-your-sdk-wiring&quot;&gt;Step 3: Keep your SDK wiring&lt;&#x2F;h2&gt;
&lt;p&gt;Your application code does not change. The endpoint URL and dummy credentials stay identical:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; TypeScript&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { S3Client }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;@aws-sdk&#x2F;client-s3&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; S3Client&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  endpoint:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  region:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  credentials: { accessKeyId:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, secretAccessKey:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  forcePathStyle:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Python (boto3)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; boto3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; boto3.client(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;    &amp;quot;s3&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    endpoint_url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    aws_access_key_id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    aws_secret_access_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    region_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cfg, _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span&gt; config.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;LoadDefaultConfig&lt;&#x2F;span&gt;&lt;span&gt;(ctx,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    config.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;WithRegion&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    config.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;WithCredentialsProvider&lt;&#x2F;span&gt;&lt;span&gt;(credentials.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;NewStaticCredentialsProvider&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    config.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;WithEndpointResolverWithOptions&lt;&#x2F;span&gt;&lt;span&gt;(aws.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;EndpointResolverWithOptionsFunc&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        func&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;service&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; region&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; options&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; ...interface&lt;&#x2F;span&gt;&lt;span&gt;{}) (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Endpoint&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Endpoint&lt;&#x2F;span&gt;&lt;span&gt;{URL:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;},&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;step-4-update-docker-compose-yml&quot;&gt;Step 4: Update docker-compose.yml&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Before:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  localstack&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; localstack&#x2F;localstack:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    ports&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;4566:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    environment&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; SERVICES=s3,sqs,sns,dynamodb,lambda&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; DEBUG=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;After:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  fakecloud&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ghcr.io&#x2F;faiscadev&#x2F;fakecloud:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    ports&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;4566:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;fakecloud starts all services by default (they are lazy and cheap — no &lt;code&gt;SERVICES&lt;&#x2F;code&gt; env var needed). If you want to pass flags:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  fakecloud&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ghcr.io&#x2F;faiscadev&#x2F;fakecloud:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    ports&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;4566:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    command&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;fakecloud&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;--host&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;0.0.0.0&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;--port&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For Lambda execution you will need Docker-in-Docker or a mounted Docker socket (same as LocalStack Pro required):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  fakecloud&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ghcr.io&#x2F;faiscadev&#x2F;fakecloud:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    ports&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;4566:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    volumes&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &#x2F;var&#x2F;run&#x2F;docker.sock:&#x2F;var&#x2F;run&#x2F;docker.sock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;step-5-update-github-actions&quot;&gt;Step 5: Update GitHub Actions&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Before:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  localstack&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; localstack&#x2F;localstack&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    ports&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; 4566:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    env&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      LOCALSTACK_AUTH_TOKEN&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ${{ secrets.LOCALSTACK_TOKEN }}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #768390;&quot;&gt;  # now required&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;After (service container):&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;services&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  fakecloud&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    image&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ghcr.io&#x2F;faiscadev&#x2F;fakecloud:latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    ports&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; 4566:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;After (install-and-run, no Docker):&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;steps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fakecloud &amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;      for i in $(seq 1 30); do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;        curl -sf http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;health &amp;amp;&amp;amp; exit 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;        sleep 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;      done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;      exit 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The install-and-run pattern is ~500ms vs ~3s for LocalStack container boot. On a cold CI runner the difference is noticeable over hundreds of test runs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-6-terraform-opentofu&quot;&gt;Step 6: Terraform &#x2F; OpenTofu&lt;&#x2F;h2&gt;
&lt;p&gt;No change needed. The provider block stays the same — only the running emulator changes.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;provider&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;aws&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  access_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  secret_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  region&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                      =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  skip_credentials_validation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  skip_metadata_api_check&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  skip_requesting_account_id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;  endpoints&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;       =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sqs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sns&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dynamodb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    lambda&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;   =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;    # ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;fakecloud&#x27;s CI runs the upstream &lt;code&gt;hashicorp&#x2F;terraform-provider-aws&lt;&#x2F;code&gt; &lt;code&gt;TestAcc*&lt;&#x2F;code&gt; suites against itself, so Terraform flows that worked against LocalStack Community should work against fakecloud. If you hit a mismatch, it is a bug — open an issue.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-7-cdk-cdklocal&quot;&gt;Step 7: CDK — cdklocal&lt;&#x2F;h2&gt;
&lt;p&gt;CDK users with &lt;code&gt;cdklocal&lt;&#x2F;code&gt; change the endpoint override:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cdklocal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; bootstrap&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cdklocal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; deploy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or set &lt;code&gt;AWS_ENDPOINT_URL=http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt; in your shell and use plain &lt;code&gt;cdk&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-8-serverless-framework&quot;&gt;Step 8: Serverless Framework&lt;&#x2F;h2&gt;
&lt;p&gt;If you used &lt;code&gt;serverless-localstack&lt;&#x2F;code&gt;, the simplest migration is to drop the plugin and set &lt;code&gt;AWS_ENDPOINT_URL&lt;&#x2F;code&gt; before running &lt;code&gt;serverless&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_REGION&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;serverless&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; deploy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;AWS SDK v3 (which Serverless Framework uses internally on recent versions) respects &lt;code&gt;AWS_ENDPOINT_URL&lt;&#x2F;code&gt; automatically — no plugin or custom config required. If you&#x27;re on an older version that doesn&#x27;t, configure the endpoint through whatever per-service override your current plugin exposes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;things-that-may-need-attention&quot;&gt;Things that may need attention&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;SERVICES env var.&lt;&#x2F;strong&gt; LocalStack used &lt;code&gt;SERVICES=s3,sqs,...&lt;&#x2F;code&gt; to scope which services booted. fakecloud starts all services by default and they are cheap. Drop the env var.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;LOCALSTACK_AUTH_TOKEN.&lt;&#x2F;strong&gt; Drop it. fakecloud does not use auth tokens.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Gateway &#x2F; edge URL.&lt;&#x2F;strong&gt; LocalStack had historical URLs like &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt; and older per-service ports (4572, 4576, etc). fakecloud uses only &lt;code&gt;4566&lt;&#x2F;code&gt; — same as modern LocalStack. If you still have old per-service URLs pinned, consolidate them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Regions.&lt;&#x2F;strong&gt; fakecloud respects the region from your SDK call. Default &lt;code&gt;us-east-1&lt;&#x2F;code&gt; works everywhere.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Persisted state.&lt;&#x2F;strong&gt; LocalStack Pro has &lt;code&gt;PERSISTENCE=1&lt;&#x2F;code&gt;. fakecloud has &lt;code&gt;--persist &#x2F;path&#x2F;to&#x2F;dir&lt;&#x2F;code&gt; for the same effect.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;services-that-moved-from-localstack-community-to-pro-and-what-fakecloud-does&quot;&gt;Services that moved from LocalStack Community to Pro (and what fakecloud does)&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Service&lt;&#x2F;th&gt;&lt;th&gt;LocalStack Community (pre-Mar 2026)&lt;&#x2F;th&gt;&lt;th&gt;LocalStack Community (now)&lt;&#x2F;th&gt;&lt;th&gt;fakecloud&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;RDS&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;references&#x2F;licensing&#x2F;&quot;&gt;Paid only&lt;&#x2F;a&gt; — always was&lt;&#x2F;td&gt;&lt;td&gt;Paid only&lt;&#x2F;td&gt;&lt;td&gt;163 ops, real PostgreSQL&#x2F;MySQL&#x2F;MariaDB via Docker&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ElastiCache&lt;&#x2F;td&gt;&lt;td&gt;Paid only&lt;&#x2F;td&gt;&lt;td&gt;Paid only&lt;&#x2F;td&gt;&lt;td&gt;75 ops, real Redis&#x2F;Valkey via Docker&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Cognito User Pools&lt;&#x2F;td&gt;&lt;td&gt;Free&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;references&#x2F;licensing&#x2F;&quot;&gt;Paid only&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;122 ops, full auth flows + MFA&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SES v2&lt;&#x2F;td&gt;&lt;td&gt;Free (limited)&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;references&#x2F;licensing&#x2F;&quot;&gt;Paid only&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;110 ops, full send + templates + DKIM&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;API Gateway v2&lt;&#x2F;td&gt;&lt;td&gt;Free&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;references&#x2F;licensing&#x2F;&quot;&gt;Paid only&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;28 ops, HTTP APIs + JWT&#x2F;Lambda authorizers&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Bedrock&lt;&#x2F;td&gt;&lt;td&gt;Not available&lt;&#x2F;td&gt;&lt;td&gt;Not available&lt;&#x2F;td&gt;&lt;td&gt;111 ops (control plane + runtime)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;assertion-helpers-optional&quot;&gt;Assertion helpers (optional)&lt;&#x2F;h2&gt;
&lt;p&gt;This is new capability LocalStack never had: fakecloud ships test-assertion SDKs that let you inspect side effects from tests without raw HTTP.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;fakecloud&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Your app code sends an email through the normal AWS SDK.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Your test asserts the side effect directly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; emails&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.ses.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getEmails&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(emails).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(emails[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].destination.toAddresses).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;alice@example.com&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Reset between tests.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;await&lt;&#x2F;span&gt;&lt;span&gt; fc.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;SDKs for TypeScript, Python, Go, PHP, Java, Rust. See &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;docs&#x2F;sdks&quot;&gt;the SDK docs&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;verify-the-migration&quot;&gt;Verify the migration&lt;&#x2F;h2&gt;
&lt;p&gt;One-shot smoke test that exercises a cross-service flow:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Create a bucket, upload, confirm, teardown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 mb s3:&#x2F;&#x2F;test-bucket&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; hello&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 cp - s3:&#x2F;&#x2F;test-bucket&#x2F;hello.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 ls s3:&#x2F;&#x2F;test-bucket&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 rb s3:&#x2F;&#x2F;test-bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --force&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Lambda round-trip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;exports.handler = async () =&amp;gt; ({ ok: true })&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; index.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;zip&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fn.zip index.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 lambda create-function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --function-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; smoke&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --runtime&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; nodejs20.x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; arn:aws:iam::000000000000:role&#x2F;lambda-role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; index.handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --zip-file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fileb:&#x2F;&#x2F;fn.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 lambda invoke&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --function-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; smoke out.json&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; cat&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; out.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If both print what you expect, migration is done.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-note-on-coverage&quot;&gt;A note on coverage&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud&#x27;s goal is every AWS service at 100% conformance, including every cross-service integration. Services land depth-first: a service is supported when it passes the Smithy-model test variants and the cross-service wire-ups that matter for it — not when the API surface looks filled in. The current 23 services (1,680 operations) are what&#x27;s done today; more are on the roadmap, prioritized by real-project demand. If a service you need isn&#x27;t on the list, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;open an issue&lt;&#x2F;a&gt; and it&#x27;ll get weighed into the queue.&lt;&#x2F;p&gt;
&lt;p&gt;For mission-critical pre-prod validation where you need the full production-parity surface, run against real AWS — that&#x27;s true of any emulator, not a fakecloud gap specifically.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Install: &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Repo: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Site: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&quot;&gt;fakecloud.dev&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Comparison: &lt;a href=&quot;&#x2F;blog&#x2F;localstack-alternatives-compared&#x2F;&quot;&gt;fakecloud vs LocalStack, MiniStack, floci, Moto&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Issues: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>A Moto equivalent for Go, Java, Kotlin, and Node.js</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/moto-equivalent-go-java-node/</link>
          <guid>https://fakecloud.dev/blog/moto-equivalent-go-java-node/</guid>
          <description xml:base="https://fakecloud.dev/blog/moto-equivalent-go-java-node/">&lt;p&gt;If you write Python, you have Moto. Decorate a test, boto3 gets patched in-process, and your assertions run against an in-memory AWS. It is great, it has been great for years, and it is not available in any other language because Python is the only ecosystem where you can cleanly monkey-patch the SDK from inside a test process.&lt;&#x2F;p&gt;
&lt;p&gt;What if you write Go, Java, Kotlin, Node.js, Rust, or PHP?&lt;&#x2F;p&gt;
&lt;p&gt;The honest cross-language answer is: a real HTTP server speaking the AWS wire protocol. Point your language&#x27;s AWS SDK at &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt;, and it doesn&#x27;t matter whether the thing on the other end is AWS, LocalStack, MiniStack, floci, or fakecloud — the wire contract is the same.&lt;&#x2F;p&gt;
&lt;p&gt;This post is specifically about using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud&lt;&#x2F;a&gt; — free, open-source, single binary, no account, no paid tier — as a Moto equivalent in the languages Moto cannot reach.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-a-real-http-server-not-an-in-process-patch&quot;&gt;Why a real HTTP server, not an in-process patch&lt;&#x2F;h2&gt;
&lt;p&gt;Moto works because Python lets you reach into a running process and replace functions. In Java and Go and most other typed languages, you can&#x27;t really do that — the SDK is compiled, the method dispatch is known at build time, and monkey-patching &lt;code&gt;S3Client.putObject&lt;&#x2F;code&gt; is not a thing you do in production code.&lt;&#x2F;p&gt;
&lt;p&gt;The equivalent model in those languages is to configure the SDK&#x27;s endpoint. Every AWS SDK supports pointing at a non-AWS endpoint URL. Point it at &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt;, and the SDK thinks it&#x27;s talking to AWS.&lt;&#x2F;p&gt;
&lt;p&gt;The server on the other end handles all the ceremony: signing verification (optional), request parsing, response shaping, persistence, cross-service wiring. Your test code is normal — the only thing that&#x27;s &quot;fake&quot; is the URL.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installing-fakecloud&quot;&gt;Installing fakecloud&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Listens on &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt;. One binary, ~19 MB, ~500ms startup.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;go&quot;&gt;Go&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;package&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; store_test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;	&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;	&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;	&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;github.com&#x2F;aws&#x2F;aws-sdk-go-v2&#x2F;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;	&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;github.com&#x2F;aws&#x2F;aws-sdk-go-v2&#x2F;config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;	&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;github.com&#x2F;aws&#x2F;aws-sdk-go-v2&#x2F;credentials&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;	&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;github.com&#x2F;aws&#x2F;aws-sdk-go-v2&#x2F;service&#x2F;s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;	&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;github.com&#x2F;aws&#x2F;smithy-go&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; clientForTest&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;s3&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Client&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	cfg, err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span&gt; config.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;LoadDefaultConfig&lt;&#x2F;span&gt;&lt;span&gt;(context.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		config.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;WithRegion&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		config.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;WithCredentialsProvider&lt;&#x2F;span&gt;&lt;span&gt;(credentials.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;NewStaticCredentialsProvider&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		config.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;WithEndpointResolverWithOptions&lt;&#x2F;span&gt;&lt;span&gt;(aws.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;EndpointResolverWithOptionsFunc&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;			func&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;service&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; region&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; opts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; ...interface&lt;&#x2F;span&gt;&lt;span&gt;{}) (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Endpoint&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; error&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;				return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Endpoint&lt;&#x2F;span&gt;&lt;span&gt;{URL:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;},&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		)),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;	if&lt;&#x2F;span&gt;&lt;span&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		t.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span&gt;(err)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span&gt; s3.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;NewFromConfig&lt;&#x2F;span&gt;&lt;span&gt;(cfg,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;o&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;s3&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Options&lt;&#x2F;span&gt;&lt;span&gt;) { o.UsePathStyle&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt; })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; TestPutAndGet&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;t&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ctx&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span&gt; context.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	c&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; clientForTest&lt;&#x2F;span&gt;&lt;span&gt;(t)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	_, err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span&gt; c.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;CreateBucket&lt;&#x2F;span&gt;&lt;span&gt;(ctx,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;s3&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;CreateBucketInput&lt;&#x2F;span&gt;&lt;span&gt;{Bucket: aws.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;	if&lt;&#x2F;span&gt;&lt;span&gt; err&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		t.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span&gt;(err)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;	&#x2F;&#x2F; ... putObject, getObject, assert&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s Go integration tests against fakecloud. Same SDK, same API, same assertions — no mock. For SDK v1, use &lt;code&gt;WithEndpoint(&quot;http:&#x2F;&#x2F;localhost:4566&quot;)&lt;&#x2F;code&gt; on the session config.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;java&quot;&gt;Java&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; software.amazon.awssdk.auth.credentials.AwsBasicCredentials;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; software.amazon.awssdk.regions.Region;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; software.amazon.awssdk.services.s3.S3Client;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; java.net.URI;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; S3Test&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    static&lt;&#x2F;span&gt;&lt;span&gt; S3Client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span&gt; S3Client.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;builder&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;endpointOverride&lt;&#x2F;span&gt;&lt;span&gt;(URI.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;region&lt;&#x2F;span&gt;&lt;span&gt;(Region.US_EAST_1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;credentialsProvider&lt;&#x2F;span&gt;&lt;span&gt;(StaticCredentialsProvider.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                AwsBasicCredentials.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;forcePathStyle&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    @&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;Test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; putAndGet&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        var&lt;&#x2F;span&gt;&lt;span&gt; s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        s3.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;createBucket&lt;&#x2F;span&gt;&lt;span&gt;(b &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; b.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;bucket&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;        &#x2F;&#x2F; ... assertions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;kotlin&quot;&gt;Kotlin&lt;&#x2F;h2&gt;
&lt;p&gt;Same as Java, nicer syntax:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; software.amazon.awssdk.auth.credentials.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; software.amazon.awssdk.regions.Region&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; software.amazon.awssdk.services.s3.S3Client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; java.net.URI&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;fun&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; s3&lt;&#x2F;span&gt;&lt;span&gt;(): &lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;S3Client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; S3Client.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;builder&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;endpointOverride&lt;&#x2F;span&gt;&lt;span&gt;(URI.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;region&lt;&#x2F;span&gt;&lt;span&gt;(Region.US_EAST_1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;credentialsProvider&lt;&#x2F;span&gt;&lt;span&gt;(StaticCredentialsProvider.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        AwsBasicCredentials.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;create&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;forcePathStyle&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;node-js-aws-sdk-v3&quot;&gt;Node.js (AWS SDK v3)&lt;&#x2F;h2&gt;
&lt;p&gt;The SDK v3 respects &lt;code&gt;AWS_ENDPOINT_URL&lt;&#x2F;code&gt; automatically, so the test setup is trivial:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; jest.setup.ts or vitest.setup.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;process.env.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;process.env.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;process.env.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;process.env.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;AWS_REGION&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Your application code imports the AWS SDK normally and does not need any test-specific branching. Your tests import your code and call it. Your assertions check the real state on fakecloud afterwards.&lt;&#x2F;p&gt;
&lt;p&gt;For SDK v2 (deprecated but still widely used):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; AWS&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;aws-sdk&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;AWS&lt;&#x2F;span&gt;&lt;span&gt;.config.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;update&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  endpoint:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  accessKeyId:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  secretAccessKey:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  region:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  s3ForcePathStyle:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;php&quot;&gt;PHP&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;php&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; Aws\S3\S3Client&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; S3Client&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;    &amp;#39;version&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;latest&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;    &amp;#39;region&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;us-east-1&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;    &amp;#39;endpoint&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;http:&#x2F;&#x2F;localhost:4566&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;    &amp;#39;credentials&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;#39;key&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;secret&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;test&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;    &amp;#39;use_path_style_endpoint&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;rust&quot;&gt;Rust&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws_config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;BehaviorVersion&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; Region&lt;&#x2F;span&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;use&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws_sdk_s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Credentials&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;async fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; client&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws_sdk_s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Client&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws_config&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;defaults&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;BehaviorVersion&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;latest&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;region&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Region&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;endpoint_url&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;credentials_provider&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Credentials&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;from_keys&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; None&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        .await&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;    aws_sdk_s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;Client&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;config)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;the-part-moto-cannot-do-in-any-language&quot;&gt;The part Moto cannot do, in any language&lt;&#x2F;h2&gt;
&lt;p&gt;Moto patches SDK methods inside the test process. It does not run code — specifically, it does not execute Lambda functions. If your Python test creates a Lambda and invokes it, Moto returns a simulated response; your function&#x27;s actual code does not run.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud does run the code. It pulls real Lambda runtime containers (13 runtimes: Node, Python, Java, Go, .NET, Ruby, custom) and executes your handler against them. So a test like &quot;my Go service publishes to SNS, which triggers a Python Lambda, which writes to DynamoDB&quot; works end-to-end — real Lambda code running, real SNS fan-out, real DynamoDB state.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Go test that publishes to SNS...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;snsClient.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;Publish&lt;&#x2F;span&gt;&lt;span&gt;(ctx,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;sns&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;PublishInput&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TopicArn: aws.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;(topicArn),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Message:  aws.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;`{&amp;quot;event&amp;quot;:&amp;quot;order.placed&amp;quot;}`&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; ...and your Python Lambda (deployed to fakecloud) actually runs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Then you assert on its side effect (a DynamoDB row) from the Go test.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is the main thing a real HTTP emulator gives you that no in-process mocking library can.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;assertion-helpers&quot;&gt;Assertion helpers&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud&#x27;s test-assertion SDKs give you introspection into what happened on the server, without writing raw HTTP:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span&gt; fakecloud.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;New&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;invs, _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span&gt; fc.Lambda.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;GetInvocations&lt;&#x2F;span&gt;&lt;span&gt;(ctx,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;GetInvocationsInput&lt;&#x2F;span&gt;&lt;span&gt;{FunctionName:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;on-order&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span&gt;(invs.Invocations)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt; { t.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;expected 1 invocation&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Node&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; invocations&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.lambda.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getInvocations&lt;&#x2F;span&gt;&lt;span&gt;({ functionName:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;on-order&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# Python (if you also want to use fakecloud from pytest alongside Go tests)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; FakeCloud()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;invs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; fc.lambda_.get_invocations(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;function_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;on-order&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;assert&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span&gt;(invs.invocations)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;SDKs for TypeScript, Python, Go, PHP, Java, Rust: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;docs&#x2F;sdks&quot;&gt;fakecloud.dev&#x2F;docs&#x2F;sdks&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;moto-vs-fakecloud-when-to-use-which&quot;&gt;Moto vs fakecloud: when to use which&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Situation&lt;&#x2F;th&gt;&lt;th&gt;Pick&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Python-only project, pure unit tests that just need boto3 to respond&lt;&#x2F;td&gt;&lt;td&gt;Moto&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Python + real cross-service wiring (Lambda actually runs, S3 -&amp;gt; Lambda actually fires)&lt;&#x2F;td&gt;&lt;td&gt;fakecloud&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Any non-Python language&lt;&#x2F;td&gt;&lt;td&gt;fakecloud&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Multi-language codebase sharing tests&lt;&#x2F;td&gt;&lt;td&gt;fakecloud&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Integration tests in CI across multiple services&lt;&#x2F;td&gt;&lt;td&gt;fakecloud&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Moto and fakecloud are not really competitive — they solve slightly different problems. If you already use Moto and it works, keep it. If you need cross-service integrations, non-Python languages, or real Lambda execution, add fakecloud.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Install: &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Repo: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Moto: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;getmoto&#x2F;moto&quot;&gt;github.com&#x2F;getmoto&#x2F;moto&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Language SDK docs: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;docs&#x2F;sdks&quot;&gt;fakecloud.dev&#x2F;docs&#x2F;sdks&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Issues: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Terraform local development for AWS: full flow with fakecloud</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/terraform-local-development-aws/</link>
          <guid>https://fakecloud.dev/blog/terraform-local-development-aws/</guid>
          <description xml:base="https://fakecloud.dev/blog/terraform-local-development-aws/">&lt;p&gt;Writing Terraform for AWS means iterating against AWS. Every &lt;code&gt;terraform apply&lt;&#x2F;code&gt; costs money, takes minutes, and leaves resources behind that you have to remember to destroy. For local dev and CI, you want the same AWS provider running against something that behaves like AWS but isn&#x27;t.&lt;&#x2F;p&gt;
&lt;p&gt;This guide walks through local Terraform development for AWS with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud&lt;&#x2F;a&gt; — a free, open-source AWS emulator that targets 100% behavioral conformance, depth-first. fakecloud&#x27;s CI runs the upstream &lt;code&gt;hashicorp&#x2F;terraform-provider-aws&lt;&#x2F;code&gt; &lt;code&gt;TestAcc*&lt;&#x2F;code&gt; suites against itself on every commit, so Terraform flows that work against real AWS should work against fakecloud.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;install-fakecloud&quot;&gt;Install fakecloud&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Listens on &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt;. ~500ms startup. No account, no token.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;option-1-provider-endpoints-block-explicit&quot;&gt;Option 1: provider &lt;code&gt;endpoints&lt;&#x2F;code&gt; block (explicit)&lt;&#x2F;h2&gt;
&lt;p&gt;Most explicit and portable. Works with any Terraform&#x2F;OpenTofu version.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# main.tf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;provider&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;aws&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  access_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  secret_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  region&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                      =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  skip_credentials_validation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  skip_metadata_api_check&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  skip_requesting_account_id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  s3_use_path_style&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;           =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;  endpoints&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    s3&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;             =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sqs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sns&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    dynamodb&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;       =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    lambda&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    iam&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sts&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    kms&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    secretsmanager&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ssm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    logs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;           =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cloudformation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    events&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    scheduler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ses&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sesv2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;          =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cognitoidp&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    kinesis&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rds&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    elasticache&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sfn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    apigatewayv2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;   =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bedrock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bedrockruntime&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now &lt;code&gt;terraform init &amp;amp;&amp;amp; terraform apply&lt;&#x2F;code&gt; talks to fakecloud.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;option-2-aws-endpoint-url-minimal-config&quot;&gt;Option 2: &lt;code&gt;AWS_ENDPOINT_URL&lt;&#x2F;code&gt; (minimal config)&lt;&#x2F;h2&gt;
&lt;p&gt;Cleaner. AWS provider v5.63+ respects &lt;code&gt;AWS_ENDPOINT_URL&lt;&#x2F;code&gt; from environment. No &lt;code&gt;endpoints&lt;&#x2F;code&gt; block needed.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span&gt; AWS_REGION&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; init&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; apply&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The provider block collapses to just auth scaffolding:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;provider&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;aws&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  access_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  secret_key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;test&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  region&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                      =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  skip_credentials_validation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  skip_metadata_api_check&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  skip_requesting_account_id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  s3_use_path_style&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;           =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;option-3-tflocal-wrapper&quot;&gt;Option 3: &lt;code&gt;tflocal&lt;&#x2F;code&gt; wrapper&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re coming from LocalStack and have a &lt;code&gt;tflocal&lt;&#x2F;code&gt; setup, the endpoint override works the same way — just point at fakecloud instead.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; tflocal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; apply&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;end-to-end-example-s3-lambda-sqs&quot;&gt;End-to-end example: S3 + Lambda + SQS&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# main.tf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;aws_s3_bucket&amp;quot; &amp;quot;uploads&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;uploads-&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span&gt;random_id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;suffix&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;hex&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;random_id&amp;quot; &amp;quot;suffix&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  byte_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;aws_sqs_queue&amp;quot; &amp;quot;jobs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;jobs&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;aws_iam_role&amp;quot; &amp;quot;lambda&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;lambda-role&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  assume_role_policy&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; jsonencode&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Version&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;2012-10-17&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Statement&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      Effect&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;Allow&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      Principal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; { Service&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;lambda.amazonaws.com&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      Action&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;sts:AssumeRole&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;aws_lambda_function&amp;quot; &amp;quot;processor&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  filename&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;archive_file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;output_path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  function_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;processor&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;          =&lt;&#x2F;span&gt;&lt;span&gt; aws_iam_role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;lambda&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;arn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;       =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;index.handler&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  runtime&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;       =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;nodejs20.x&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  source_code_hash&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;archive_file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;output_base64sha256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;archive_file&amp;quot; &amp;quot;fn&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;        =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;zip&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  output_path&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;fn.zip&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;  source&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    filename&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;index.js&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    content&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;exports.handler = async (event) =&amp;gt; ({ ok: true, received: event })&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;aws_lambda_event_source_mapping&amp;quot; &amp;quot;sqs_to_lambda&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  event_source_arn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; aws_sqs_queue&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;jobs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;arn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  function_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span&gt; aws_lambda_function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;processor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;function_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  batch_size&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;       =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;aws_s3_bucket_notification&amp;quot; &amp;quot;uploads_to_sqs&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; aws_s3_bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;uploads&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;  queue&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    queue_arn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; aws_sqs_queue&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;jobs&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;arn&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    events&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;s3:ObjectCreated:*&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;output&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;bucket_id&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  value&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; aws_s3_bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;uploads&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Apply it against fakecloud:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; apply&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -auto-approve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Upload an object and watch the Lambda fire:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;hello&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 cp - s3:&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; output&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -raw&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; bucket_id&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&#x2F;file.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 logs tail &#x2F;aws&#x2F;lambda&#x2F;processor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s S3 notification -&amp;gt; SQS queue -&amp;gt; Lambda event source mapping -&amp;gt; real Node runtime executing your handler. End-to-end, no stubs. Same flow as real AWS.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ci-terraform-plan-apply-in-github-actions&quot;&gt;CI: Terraform plan&#x2F;apply in GitHub Actions&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  terraform&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    env&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;      AWS_REGION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; actions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; hashicorp&#x2F;setup-terraform@v3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; Start fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          fakecloud &amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          for i in $(seq 1 30); do curl -sf http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;health &amp;amp;&amp;amp; break; sleep 1; done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          curl -sf http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;health&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; terraform init&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; terraform init&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; terraform plan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; terraform plan -out=tfplan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; name&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; terraform apply&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; terraform apply -auto-approve tfplan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;~500ms startup means this adds negligible time to the job.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;state-backend&quot;&gt;State backend&lt;&#x2F;h2&gt;
&lt;p&gt;For local dev, default &lt;code&gt;local&lt;&#x2F;code&gt; backend is fine. If your real config uses &lt;code&gt;s3&lt;&#x2F;code&gt; backend, you can point that at fakecloud too:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;  backend&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; &amp;quot;s3&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                      =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;tf-state&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    key&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                         =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;terraform.tfstate&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    region&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                      =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;us-east-1&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    endpoint&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;                    =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    skip_credentials_validation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    skip_metadata_api_check&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;     =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    skip_region_validation&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;      =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    force_path_style&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pre-create the bucket:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 mb s3:&#x2F;&#x2F;tf-state&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;why-this-works-at-parity&quot;&gt;Why this works at parity&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud targets 100% behavioral conformance per implemented service, validated on every commit against AWS&#x27;s own Smithy models. On top of that, CI runs the upstream &lt;code&gt;hashicorp&#x2F;terraform-provider-aws&lt;&#x2F;code&gt; &lt;code&gt;TestAcc*&lt;&#x2F;code&gt; suites — the same acceptance tests HashiCorp runs against real AWS — so provider-level behavior (waiters, retries, field presence, ARN formats) matches.&lt;&#x2F;p&gt;
&lt;p&gt;If a Terraform flow that works against real AWS doesn&#x27;t work against fakecloud, that&#x27;s a bug. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;Open an issue&lt;&#x2F;a&gt; and it gets fixed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Install: &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Repo: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;LocalStack migration guide: &lt;a href=&quot;&#x2F;blog&#x2F;migrate-from-localstack&#x2F;&quot;&gt;Migrating from LocalStack to fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;CI guide: &lt;a href=&quot;&#x2F;blog&#x2F;integration-testing-aws-in-ci&#x2F;&quot;&gt;Integration testing AWS in GitHub Actions&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Issues: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>How to test Lambda locally: the full guide for 2026</title>
          <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/test-lambda-locally/</link>
          <guid>https://fakecloud.dev/blog/test-lambda-locally/</guid>
          <description xml:base="https://fakecloud.dev/blog/test-lambda-locally/">&lt;p&gt;If you want to run AWS Lambda locally, you have a few options, and most of them are worse than they need to be.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SAM Local&lt;&#x2F;strong&gt; invokes Lambda inside a Docker container, which is close to the real thing, but its integration with other AWS services is thin. If your function reads from SQS or publishes to SNS or is triggered by S3, SAM hands you a bag of event-shaped JSON and wishes you luck.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;serverless-offline&lt;&#x2F;strong&gt; simulates API Gateway -&amp;gt; Lambda only. Everything downstream is mocked.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Pure unit tests with mocks&lt;&#x2F;strong&gt; tell you your code compiles. They do not tell you your code works.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This guide shows how to test Lambda locally end-to-end: real function code executing in a real runtime, triggered by real events from other AWS services, asserting on real side effects. No account, no auth token, no paid tier.&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;ll use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud&lt;&#x2F;a&gt; — a free, open-source AWS emulator that runs Lambda in real Docker containers across all 13 official runtimes and wires it up to 22 other AWS services that trigger and consume it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-you-need&quot;&gt;What you need&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Docker (fakecloud boots Lambda runtime containers)&lt;&#x2F;li&gt;
&lt;li&gt;The AWS CLI, or any AWS SDK&lt;&#x2F;li&gt;
&lt;li&gt;~30 seconds&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;install-fakecloud&quot;&gt;Install fakecloud&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s it. It listens on &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you prefer Docker:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --rm&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  -p&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; 4566:4566&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  -v&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &#x2F;var&#x2F;run&#x2F;docker.sock:&#x2F;var&#x2F;run&#x2F;docker.sock&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;  ghcr.io&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Docker socket mount is only needed because Lambda execution needs Docker-in-Docker. The single-binary install above doesn&#x27;t need it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-node-js-lambda-end-to-end&quot;&gt;A Node.js Lambda, end-to-end&lt;&#x2F;h2&gt;
&lt;p&gt;Create the function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; index.js&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;EOF&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;exports.handler = async (event) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;  return { statusCode: 200, body: JSON.stringify({ event }) };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EOF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;zip&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fn.zip index.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Deploy it to fakecloud:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 iam create-role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --role-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; lambda-role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --assume-role-policy-document&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;{&amp;quot;Version&amp;quot;:&amp;quot;2012-10-17&amp;quot;,&amp;quot;Statement&amp;quot;:[{&amp;quot;Effect&amp;quot;:&amp;quot;Allow&amp;quot;,&amp;quot;Principal&amp;quot;:{&amp;quot;Service&amp;quot;:&amp;quot;lambda.amazonaws.com&amp;quot;},&amp;quot;Action&amp;quot;:&amp;quot;sts:AssumeRole&amp;quot;}]}&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 lambda create-function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --function-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; hello&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --runtime&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; nodejs20.x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; arn:aws:iam::000000000000:role&#x2F;lambda-role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; index.handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --zip-file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fileb:&#x2F;&#x2F;fn.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Invoke it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 lambda invoke&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --function-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; hello&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --payload&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;{&amp;quot;hello&amp;quot;:&amp;quot;world&amp;quot;}&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --cli-binary-format&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; raw-in-base64-out&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;  out.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; out.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Output:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;&amp;quot;statusCode&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;&amp;quot;body&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;event&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;:{&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;hello&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;world&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;}}&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s your Node.js code executing in a real Node 20 container. fakecloud pulled the runtime image, mounted your zip, and invoked &lt;code&gt;handler&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;python-java-go-net-ruby-custom&quot;&gt;Python, Java, Go, .NET, Ruby, custom&lt;&#x2F;h2&gt;
&lt;p&gt;Same flow, different runtime string. fakecloud supports all 13 AWS Lambda runtimes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nodejs18.x&lt;&#x2F;code&gt;, &lt;code&gt;nodejs20.x&lt;&#x2F;code&gt;, &lt;code&gt;nodejs22.x&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;python3.9&lt;&#x2F;code&gt;, &lt;code&gt;python3.10&lt;&#x2F;code&gt;, &lt;code&gt;python3.11&lt;&#x2F;code&gt;, &lt;code&gt;python3.12&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;java11&lt;&#x2F;code&gt;, &lt;code&gt;java17&lt;&#x2F;code&gt;, &lt;code&gt;java21&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;dotnet6&lt;&#x2F;code&gt;, &lt;code&gt;dotnet8&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ruby3.2&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;go1.x&lt;&#x2F;code&gt;, &lt;code&gt;provided.al2&lt;&#x2F;code&gt;, &lt;code&gt;provided.al2023&lt;&#x2F;code&gt; (custom runtimes)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Example — Python:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; lambda_function.py&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;EOF&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;def handler(event, context):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;    return {&amp;quot;ok&amp;quot;: True, &amp;quot;event&amp;quot;: event}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;EOF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;zip&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fn.zip lambda_function.py&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 lambda create-function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --function-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; py-hello&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --runtime&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; python3.12&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; arn:aws:iam::000000000000:role&#x2F;lambda-role&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; lambda_function.handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --zip-file&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fileb:&#x2F;&#x2F;fn.zip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 lambda invoke&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --function-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; py-hello&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --payload&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;{&amp;quot;x&amp;quot;:1}&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --cli-binary-format&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; raw-in-base64-out&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;  out.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;triggers-that-actually-fire&quot;&gt;Triggers that actually fire&lt;&#x2F;h2&gt;
&lt;p&gt;This is where &quot;test Lambda locally&quot; usually breaks down. Your Lambda is not invoked by a human calling Invoke — it&#x27;s triggered by S3, SQS, SNS, EventBridge, DynamoDB Streams, API Gateway, or an event source mapping. fakecloud has those wired up for real.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sqs-event-source-mapping&quot;&gt;SQS event source mapping&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 sqs create-queue&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --queue-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; jobs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;QUEUE_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;http:&#x2F;&#x2F;localhost:4566&#x2F;000000000000&#x2F;jobs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;QUEUE_ARN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;arn:aws:sqs:us-east-1:000000000000:jobs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 lambda create-event-source-mapping&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --function-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; hello&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --event-source-arn&lt;&#x2F;span&gt;&lt;span&gt; $QUEUE_ARN&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --batch-size 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 sqs send-message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --queue-url&lt;&#x2F;span&gt;&lt;span&gt; $QUEUE_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --message-body&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;{&amp;quot;job&amp;quot;:&amp;quot;resize&amp;quot;,&amp;quot;id&amp;quot;:42}&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;fakecloud polls the queue, batches the message, invokes your Lambda with the SQS event shape, and deletes the message on success. Same contract as real AWS.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;s3-lambda&quot;&gt;S3 -&amp;gt; Lambda&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 mb s3:&#x2F;&#x2F;uploads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 lambda add-permission&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --function-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; hello&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --statement-id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; s3invoke&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --action&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; lambda:InvokeFunction&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --principal&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; s3.amazonaws.com&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --source-arn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; arn:aws:s3:::uploads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3api put-bucket-notification-configuration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --bucket&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; uploads&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --notification-configuration&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;    &amp;quot;LambdaFunctionConfigurations&amp;quot;: [{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;      &amp;quot;LambdaFunctionArn&amp;quot;: &amp;quot;arn:aws:lambda:us-east-1:000000000000:function:hello&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;      &amp;quot;Events&amp;quot;: [&amp;quot;s3:ObjectCreated:*&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;    }]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;  }&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;hi&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 s3 cp - s3:&#x2F;&#x2F;uploads&#x2F;file.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Your Lambda fires with the S3 event. End-to-end, no stubs.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;eventbridge-lambda&quot;&gt;EventBridge -&amp;gt; Lambda&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 events put-rule&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; on-order&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --event-pattern&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;{&amp;quot;source&amp;quot;:[&amp;quot;store&amp;quot;],&amp;quot;detail-type&amp;quot;:[&amp;quot;OrderPlaced&amp;quot;]}&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 events put-targets&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --rule&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; on-order&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --targets&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Id=1,Arn=arn:aws:lambda:us-east-1:000000000000:function:hello&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 events put-events&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;  --entries&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;Source=store,DetailType=OrderPlaced,Detail={&amp;quot;orderId&amp;quot;:&amp;quot;o1&amp;quot;}&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Your Lambda fires with the EventBridge event envelope.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;asserting-on-side-effects&quot;&gt;Asserting on side effects&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud ships test-assertion SDKs that let your tests check what happened without raw HTTP:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;fakecloud&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; Your app publishes to SNS inside a Lambda. Your test asserts it happened.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; invocations&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.lambda.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getInvocations&lt;&#x2F;span&gt;&lt;span&gt;({ functionName:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;hello&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].statusCode).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; messages&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.sns.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getPublishedMessages&lt;&#x2F;span&gt;&lt;span&gt;({ topicName:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;orders&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(messages[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].message).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;o1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;await&lt;&#x2F;span&gt;&lt;span&gt; fc.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;SDKs in TypeScript, Python, Go, PHP, Java, Rust. Reference: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;docs&#x2F;sdks&quot;&gt;fakecloud.dev&#x2F;docs&#x2F;sdks&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;watching-the-logs&quot;&gt;Watching the logs&lt;&#x2F;h2&gt;
&lt;p&gt;Lambda stdout goes to CloudWatch Logs, which fakecloud also emulates:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 logs tail &#x2F;aws&#x2F;lambda&#x2F;hello&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --follow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;running-in-ci&quot;&gt;Running in CI&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;# .github&#x2F;workflows&#x2F;test.yml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;  test&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; actions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; fakecloud &amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          for i in $(seq 1 30); do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;            curl -sf http:&#x2F;&#x2F;localhost:4566&#x2F;_fakecloud&#x2F;health &amp;amp;&amp;amp; break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;            sleep 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;          done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; npm ci &amp;amp;&amp;amp; npm test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;        env&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;          AWS_ENDPOINT_URL&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;          AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;          AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8DDB8C;&quot;&gt;          AWS_REGION&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;~500ms startup. A whole Lambda-integration test suite completes in seconds on a cold runner.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;correctness-vs-performance&quot;&gt;Correctness vs performance&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud runs your function code in the real AWS Lambda runtime containers, so behavior matches real Lambda. What it doesn&#x27;t replicate is AWS&#x27;s distributed infrastructure timing: cold-start latency, concurrency-accounting scheduling, and VPC networking come from AWS&#x27;s own implementation, not from a local process, so numbers on those will not match real AWS. Use real AWS for those measurements, use fakecloud for everything correctness-related.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Install: &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Repo: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Lambda docs: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;docs&#x2F;services&#x2F;lambda&quot;&gt;fakecloud.dev&#x2F;docs&#x2F;services&#x2F;lambda&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;SDKs: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&#x2F;docs&#x2F;sdks&quot;&gt;fakecloud.dev&#x2F;docs&#x2F;sdks&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Issues: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>People are not reviewing AI-generated code</title>
          <pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/people-not-reviewing-ai-code/</link>
          <guid>https://fakecloud.dev/blog/people-not-reviewing-ai-code/</guid>
          <description xml:base="https://fakecloud.dev/blog/people-not-reviewing-ai-code/">&lt;p&gt;I&#x27;d bet good money that most developers using AI tools are already shipping code without properly reviewing every line.&lt;&#x2F;p&gt;
&lt;p&gt;Not because they have some sophisticated testing setup. Because it historically just works. A developer reviews the first ten things the AI writes. They&#x27;re fine. Reviews the next ten. Also fine. At some point the developer starts skimming. Then stops reading altogether. The review step keeps proving itself to be a waste of time, so it gets skipped. Human nature.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-validation-looks-like-with-guardrails&quot;&gt;What validation looks like with guardrails&lt;&#x2F;h2&gt;
&lt;p&gt;I built fakecloud almost entirely with Claude. 22 AWS services, 1,650+ operations, 100% conformance to AWS behavior.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s my workflow:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I define what to build. Architecture, scope, acceptance criteria.&lt;&#x2F;li&gt;
&lt;li&gt;AI writes code and tests.&lt;&#x2F;li&gt;
&lt;li&gt;Tests run in CI.&lt;&#x2F;li&gt;
&lt;li&gt;I look at the results.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Step 4 is where it gets weird.&lt;&#x2F;p&gt;
&lt;p&gt;The tests pass. I look at the implementation. It&#x27;s correct. I merge.&lt;&#x2F;p&gt;
&lt;p&gt;This happens over and over. I&#x27;m doing the validation—I&#x27;m looking, I&#x27;m checking—but I&#x27;m not finding anything wrong. The guardrails already caught it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The validation step has become ceremonial.&lt;&#x2F;strong&gt; You still do it because if something&#x27;s wrong it can be a disaster. But in practice, if you&#x27;ve built the right guardrails, validation finds nothing. The automated systems already caught everything.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-actually-happening&quot;&gt;What&#x27;s actually happening&lt;&#x2F;h2&gt;
&lt;p&gt;I still validate before merging because catastrophic failure is real. If something gets through that shouldn&#x27;t, it&#x27;s a disaster. So I check. But I&#x27;m checking as a safety ritual, not because I expect to find problems.&lt;&#x2F;p&gt;
&lt;p&gt;The tests already found the problems. CI already caught them. By the time I look, there&#x27;s nothing left to catch.&lt;&#x2F;p&gt;
&lt;p&gt;And here&#x27;s my gut feeling: &lt;strong&gt;I think most people are already skipping this step.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have no proof. But think about it. A developer asks Claude or Copilot to write a function. It looks right. They review it anyway because that&#x27;s what responsible developers do. It&#x27;s fine. Next time, same thing. Fine again. After the twentieth time, they start skimming. After the fiftieth, they stop reading altogether.&lt;&#x2F;p&gt;
&lt;p&gt;Why would anyone keep reviewing something that&#x27;s never wrong?&lt;&#x2F;p&gt;
&lt;p&gt;But I&#x27;d bet there are plenty of developers shipping AI-generated code without proper test infrastructure. Without CI catching issues. Without proper monitoring. Just the AI, some tests the AI wrote, and hope.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;I think the industry already moved past &quot;review every line.&quot; We&#x27;re just not talking about it.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;you-can-t-fix-this-with-process&quot;&gt;You can&#x27;t fix this with process&lt;&#x2F;h2&gt;
&lt;p&gt;You can write &quot;review all AI-generated code&quot; in your team&#x27;s guidelines. You can make it a policy. You can add it to the PR checklist.&lt;&#x2F;p&gt;
&lt;p&gt;But you can&#x27;t verify that someone actually did it. You can&#x27;t tell the difference between &quot;I carefully reviewed this&quot; and &quot;I skimmed it for 30 seconds and it looked fine.&quot; There&#x27;s no way to enforce it. And when the AI keeps being right, the incentive to actually do it drops to zero.&lt;&#x2F;p&gt;
&lt;p&gt;So instead of pretending you can control this, &lt;strong&gt;build systems that don&#x27;t depend on it.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s what I did with fakecloud. The code is real. The conformance is real. Most of it was written by Claude, with me defining architecture and making sure the guardrails worked.&lt;&#x2F;p&gt;
&lt;p&gt;And when I validate the code, I find nothing wrong. Not because I&#x27;m a great reviewer. Because the guardrails already found everything.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-good-guardrails-look-like&quot;&gt;What good guardrails look like&lt;&#x2F;h2&gt;
&lt;p&gt;Most AI-generated code ships with AI-generated tests. The problem is that the tests can be wrong in the same way the code is wrong. Everything is internally consistent, but none of it matches reality. A human reviewer might catch this. Or might not. You can&#x27;t count on it.&lt;&#x2F;p&gt;
&lt;p&gt;What you can count on:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Real integration tests with actual SDKs&lt;&#x2F;strong&gt; — not mocks that mirror the buggy code&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Conformance tests generated from schemas&lt;&#x2F;strong&gt; — tests the AI didn&#x27;t write and can&#x27;t game&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Side-by-side testing against real systems&lt;&#x2F;strong&gt; — when behavior diverges, it&#x27;s a bug&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The difference isn&#x27;t whether someone reviewed the code. It&#x27;s whether you have automated systems that verify correctness independent of the code being tested.&lt;&#x2F;p&gt;
&lt;p&gt;When those systems pass, the code is right regardless of whether anyone read it. When they fail, the AI fixes it until they pass.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s a concrete example. If you&#x27;re writing code that calls Bedrock — the Claude API on AWS — the hard parts are retry logic, fallback models, and circuit breakers. Testing that code against real Bedrock is expensive, non-deterministic, and rate-limited. Mocking it is meaningless because the mocks don&#x27;t catch the bugs. So you either ship untested error handling or you write unrunnable tests. That&#x27;s exactly the kind of gap where AI-generated code goes wrong silently. I wrote a whole &lt;a href=&quot;&#x2F;docs&#x2F;guides&#x2F;testing-bedrock&#x2F;&quot;&gt;guide on how to test Bedrock code locally against fakecloud&lt;&#x2F;a&gt; — deterministic responses, injectable faults, call history assertions. That&#x27;s what &quot;guardrails the AI can&#x27;t game&quot; looks like in practice.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-test-suite-is-the-guardrail&quot;&gt;The test suite is the guardrail&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud works because the tests verify everything. Not me. Not code review. The tests.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;54,000+ conformance tests generated from AWS Smithy models&lt;&#x2F;li&gt;
&lt;li&gt;E2E tests using real AWS SDKs&lt;&#x2F;li&gt;
&lt;li&gt;CI that runs everything on every commit&lt;&#x2F;li&gt;
&lt;li&gt;Side-by-side testing against actual AWS&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These guardrails are external to the code being tested. The AI can&#x27;t game them. They catch bugs before I see the code.&lt;&#x2F;p&gt;
&lt;p&gt;So when I validate, I find nothing. Because there&#x27;s nothing left to find.&lt;&#x2F;p&gt;
&lt;p&gt;If I&#x27;m right that people are already shipping AI code without reviewing it, this is the gap. Most codebases don&#x27;t have external verification. Just AI-generated code, AI-generated tests, and no way to know if they match reality.&lt;&#x2F;p&gt;
&lt;p&gt;The fix isn&#x27;t telling people to review harder. It&#x27;s building systems that catch the bugs whether or not anyone reads the code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-to-do-about-it&quot;&gt;What to do about it&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re using AI to write code, here&#x27;s what matters:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You can&#x27;t control whether people actually review code.&lt;&#x2F;strong&gt; You can tell them to. You can put it in the process. But you can&#x27;t get inside their head and verify they actually read every line. So build systems that don&#x27;t depend on them doing it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Build external guardrails.&lt;&#x2F;strong&gt; Tests that the AI didn&#x27;t write. Conformance checks generated from schemas. Integration tests with real dependencies, not mocks.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Automate everything.&lt;&#x2F;strong&gt; Don&#x27;t rely on humans to catch bugs. Humans are slow, inconsistent, lazy, and bad at checking edge cases. Automated systems are fast, consistent, and check everything.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Accept what&#x27;s probably already happening.&lt;&#x2F;strong&gt; I think most developers are already shipping AI-generated code without thorough manual review. If that&#x27;s true, the question isn&#x27;t whether to do it. It&#x27;s whether you&#x27;re doing it safely.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;For AWS code specifically, I wrote about &lt;a href=&quot;&#x2F;blog&#x2F;testing-aws-code-ai-tools&#x2F;&quot;&gt;how to test AI-generated AWS code properly&lt;&#x2F;a&gt;. The short version: don&#x27;t mock AWS APIs. Use something that behaves like real AWS.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s why fakecloud exists:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repo:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Site:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&quot;&gt;fakecloud.dev&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Install:&lt;&#x2F;strong&gt; &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you&#x27;re writing AWS code with Claude, Cursor, or any AI tool, you need automated guardrails that verify correctness without you in the loop. Because if I&#x27;m right, people are already skipping manual review—and the only thing standing between them and production bugs is the quality of their automated tests.&lt;&#x2F;p&gt;
&lt;p&gt;Build the guardrails. Then let the AI work.&lt;&#x2F;p&gt;
&lt;p&gt;And if you find a case where fakecloud behaves differently from AWS, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;open an issue&lt;&#x2F;a&gt;. Because that means the guardrails missed something. And we need to know.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to test AWS code written by AI tools</title>
          <pubDate>Tue, 14 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/testing-aws-code-ai-tools/</link>
          <guid>https://fakecloud.dev/blog/testing-aws-code-ai-tools/</guid>
          <description xml:base="https://fakecloud.dev/blog/testing-aws-code-ai-tools/">&lt;p&gt;AI tools are absurdly good at writing AWS code. They understand IAM policies, VPC configurations, and service integrations in a way that feels magical. Until they don&#x27;t.&lt;&#x2F;p&gt;
&lt;p&gt;The failure mode everyone hits is the same: the AI writes code, writes tests, the tests pass, you ship it—and then AWS returns something completely different in production.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s how to test AI-generated AWS code properly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-debugging-revelation&quot;&gt;The debugging revelation&lt;&#x2F;h2&gt;
&lt;p&gt;I started using ChatGPT to write code the day it launched. The first &quot;oh shit, this actually works&quot; moment wasn&#x27;t code generation—it was debugging.&lt;&#x2F;p&gt;
&lt;p&gt;AWS is full of rough edges. Permissions that fail silently. Networking that breaks in non-obvious ways. Security groups that look right but aren&#x27;t. When you hit one of these, you&#x27;re stuck reading docs, checking IAM, comparing VPC settings.&lt;&#x2F;p&gt;
&lt;p&gt;AI is absurdly fast at this. Paste an error, describe what you tried, get three hypotheses back. &quot;Check if the security group allows egress on 443.&quot; &quot;Verify the IAM role has &lt;code&gt;sts:AssumeRole&lt;&#x2F;code&gt; for that principal.&quot; One of them is usually right.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s when I realized AI understands AWS in a way that&#x27;s genuinely useful. Not because it memorized documentation, but because it&#x27;s seen every way these things fail.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-hallucination-problem&quot;&gt;The hallucination problem&lt;&#x2F;h2&gt;
&lt;p&gt;Then you hit the limits.&lt;&#x2F;p&gt;
&lt;p&gt;When debugging gets hard—when nothing makes sense—AI starts making things up. It suggests an AWS feature that doesn&#x27;t exist. A configuration parameter that was never real. An API method that would solve your problem perfectly, except it&#x27;s not in the SDK.&lt;&#x2F;p&gt;
&lt;p&gt;This is the failure mode everyone talks about: hallucination. It&#x27;s real. When the AI doesn&#x27;t know, it confidently invents an answer.&lt;&#x2F;p&gt;
&lt;p&gt;The standard response is &quot;review every line the AI writes.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;That advice doesn&#x27;t scale. And it doesn&#x27;t work.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-manual-review-fails&quot;&gt;Why manual review fails&lt;&#x2F;h2&gt;
&lt;p&gt;The problem with &quot;review every line&quot; is that it assumes the human is the source of truth. But humans miss things. Humans get tired. Humans skim code that looks reasonable.&lt;&#x2F;p&gt;
&lt;p&gt;More importantly: if the AI writes both the code and the tests, &lt;strong&gt;manual review doesn&#x27;t catch the right bugs.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the trap:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;AI generates code&lt;&#x2F;li&gt;
&lt;li&gt;Developer reviews it (looks fine)&lt;&#x2F;li&gt;
&lt;li&gt;AI writes tests&lt;&#x2F;li&gt;
&lt;li&gt;Tests pass&lt;&#x2F;li&gt;
&lt;li&gt;Ship it&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Except the tests can be wrong in the same way the code is wrong. The tests assert that the bug exists successfully. Everything is internally consistent, but none of it matches reality.&lt;&#x2F;p&gt;
&lt;p&gt;This is especially bad with mocks. The AI will happily mock AWS APIs in a way that matches the buggy code. The tests pass. Your code goes to production. AWS returns something completely different. Good luck debugging that at 2am.&lt;&#x2F;p&gt;
&lt;p&gt;Manual review didn&#x27;t save you because the bug wasn&#x27;t obvious. The tests didn&#x27;t save you because they tested the wrong behavior.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-actually-works-guardrails-that-can-t-be-gamed&quot;&gt;What actually works: guardrails that can&#x27;t be gamed&lt;&#x2F;h2&gt;
&lt;p&gt;Here&#x27;s what worked for fakecloud:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. Real integration tests, not mocks.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Every feature ships with E2E tests using the actual AWS SDK. Not unit tests with mocked clients. Actual &lt;code&gt;aws-sdk-rust&lt;&#x2F;code&gt; calls against fakecloud.&lt;&#x2F;p&gt;
&lt;p&gt;When the test uses the real SDK and the code is wrong, the test fails. The AI iterates until it&#x27;s right.&lt;&#x2F;p&gt;
&lt;p&gt;This matters most for cross-service wiring—the stuff that&#x27;s easy to get subtly wrong and almost impossible to catch with mocks. fakecloud actually executes the integrations: an EventBridge rule really triggers the Step Functions state machine, an SES inbound rule really invokes the Lambda, an S3 event really lands in SQS. If the AI wires it up wrong, the test fails for the same reason it would fail in production.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. Conformance testing the AI didn&#x27;t write.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We auto-generate 54,000+ test variants from AWS Smithy models. Every operation, every parameter, every boundary condition, every error case.&lt;&#x2F;p&gt;
&lt;p&gt;The AI can&#x27;t write code that games these tests because it didn&#x27;t write the tests. They&#x27;re generated from AWS&#x27;s service definitions.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;3. Side-by-side testing against real AWS.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The same test suite runs against both fakecloud and actual AWS. When behavior diverges, it&#x27;s a bug.&lt;&#x2F;p&gt;
&lt;p&gt;This is the key insight: &lt;strong&gt;the guardrails are automated and external to the code being tested.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The AI can&#x27;t game them. They catch everything. And when they&#x27;re set up right, they catch it &lt;em&gt;before&lt;&#x2F;em&gt; you see the code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-this-means-for-aws-testing&quot;&gt;What this means for AWS testing&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re building on AWS and using AI to write code, here&#x27;s what matters:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Don&#x27;t mock the AWS SDK in your tests.&lt;&#x2F;strong&gt; Use fakecloud, LocalStack, Testcontainers, or real AWS with cleanup afterward. But don&#x27;t mock. Mocks let AI-generated tests pass while asserting the wrong behavior.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Build guardrails the AI can&#x27;t game.&lt;&#x2F;strong&gt; If the AI writes both the code and the tests, make sure tests are anchored to something external—real SDK behavior, schemas generated from service definitions, or validation against actual AWS.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Verify architecture, not syntax.&lt;&#x2F;strong&gt; Your job isn&#x27;t to review every line. It&#x27;s to make sure the AI is building the right thing in the right way. If the structure is sound and the tests pass, the code is probably fine.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Let the AI iterate.&lt;&#x2F;strong&gt; When tests fail, let the AI fix them. It&#x27;s faster than you at reading error messages and adjusting code. Your job is to make sure it&#x27;s converging toward the right solution.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-test-suite-is-the-guardrail&quot;&gt;The test suite is the guardrail&lt;&#x2F;h2&gt;
&lt;p&gt;I built fakecloud almost entirely with Claude. 22 AWS services, 1,150+ operations, 100% conformance to AWS behavior.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud works because the tests verify everything:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;54,000+ conformance tests generated from AWS Smithy models&lt;&#x2F;li&gt;
&lt;li&gt;E2E tests using real AWS SDKs&lt;&#x2F;li&gt;
&lt;li&gt;CI that runs everything on every commit&lt;&#x2F;li&gt;
&lt;li&gt;Side-by-side testing against actual AWS&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These guardrails are external to the code being tested. The AI can&#x27;t game them. They catch bugs before I see the code.&lt;&#x2F;p&gt;
&lt;p&gt;If your tests are good—real integration tests, not mocks, not stubs—then AI-generated code is as reliable as human-written code. Maybe more reliable, because the AI doesn&#x27;t get bored and skip edge cases.&lt;&#x2F;p&gt;
&lt;p&gt;If your tests are bad—mocks everywhere, written by the same AI that wrote the code—then you&#x27;re in trouble whether a human or an AI wrote the code.&lt;&#x2F;p&gt;
&lt;p&gt;The tooling matters. The tests matter. The mocks-versus-real-APIs decision matters.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;fakecloud exists because AI tools need a way to verify AWS code against real behavior, not just against tests they wrote themselves.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repo:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Site:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&quot;&gt;fakecloud.dev&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Install:&lt;&#x2F;strong&gt; &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you&#x27;re using Claude Code, Cursor, or any other AI coding tool to write AWS applications, you need something that behaves like AWS to test against. Not mocks. Not stubs. Real API behavior.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s what fakecloud is for.&lt;&#x2F;p&gt;
&lt;p&gt;And if you find a case where fakecloud behaves differently from AWS—that&#x27;s a bug. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;Open an issue&lt;&#x2F;a&gt;. Because the tests should have caught it.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to test Bedrock code locally, for free, deterministically</title>
          <pubDate>Mon, 13 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/bedrock-local-testing/</link>
          <guid>https://fakecloud.dev/blog/bedrock-local-testing/</guid>
          <description xml:base="https://fakecloud.dev/blog/bedrock-local-testing/">&lt;p&gt;If you&#x27;re writing code that calls Bedrock, you already know the problem. Every test run burns tokens. Every CI build hits rate limits. Every assertion on model output breaks because the model returned something slightly different this time. The only way to make it stop is to mock, and then your tests don&#x27;t test anything real.&lt;&#x2F;p&gt;
&lt;p&gt;This is the most frustrating corner of AWS to test against, and until a few days ago there was no good answer. LocalStack doesn&#x27;t emulate Bedrock at any tier — not free, not paid. If you wanted a local Bedrock, you built it yourself.&lt;&#x2F;p&gt;
&lt;p&gt;So I built one.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem-with-real-bedrock-in-tests&quot;&gt;The problem with real Bedrock in tests&lt;&#x2F;h2&gt;
&lt;p&gt;Four things break, in order of how much they hurt:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cost.&lt;&#x2F;strong&gt; Every test run that calls a model is a line item on your AWS bill. A CI job that runs on every PR and exercises a Bedrock code path a dozen times becomes real money fast. Teams end up building elaborate VCR-cassette systems to record-once-and-replay, which works until the request shape changes and everything silently goes stale.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rate limits.&lt;&#x2F;strong&gt; Bedrock has per-account quotas. A noisy test suite gets throttled. Flaky CI. Engineers angry. You start skipping tests in CI to stay under the limit, which defeats the point of having them.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Non-determinism.&lt;&#x2F;strong&gt; Real models return different text every run, even at temperature 0. Snapshot tests are impossible. Assertions on specific strings are impossible. Everyone ends up asserting that &lt;em&gt;some&lt;&#x2F;em&gt; output was produced, which is the weakest possible test — it would pass even if the model returned the string &quot;cabbage.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;No offline dev.&lt;&#x2F;strong&gt; On a plane, on a train, on bad hotel wifi, in a datacenter without egress. You can&#x27;t develop Bedrock code at all without a live connection to AWS.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The standard response is &quot;mock the SDK.&quot; The problem with mocking the SDK is that it&#x27;s AI-generated code calling an AI API, and if you let the AI generate both the code and the mocks, your tests will happily assert the wrong behavior and pass. Your code never talks to anything that looks like Bedrock — it talks to a fake object that matches the SDK&#x27;s interface. If your code assembles the request wrong, the mock doesn&#x27;t care.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-fakecloud-gives-you&quot;&gt;What fakecloud gives you&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud implements 111 Bedrock operations — the full runtime (InvokeModel, Converse, both streaming variants), plus guardrails, customization jobs, model imports, the whole control plane. You point any AWS SDK at &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt; with dummy credentials and it works.&lt;&#x2F;p&gt;
&lt;p&gt;But the interesting part isn&#x27;t the operation count. The interesting part is that you can make the &quot;model&quot; return exactly what you want, triggered by exactly what you want, and then assert on exactly what your code sent.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Configurable responses per prompt.&lt;&#x2F;strong&gt; Set a rule like &quot;when the prompt contains &#x27;summarize&#x27;, return this JSON; when it contains &#x27;classify&#x27;, return that one.&quot; Your code&#x27;s branching logic gets tested against deterministic, fixture-like responses you control.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Fault injection.&lt;&#x2F;strong&gt; Tell fakecloud to throw &lt;code&gt;ThrottlingException&lt;&#x2F;code&gt; on the next call. Your retry logic gets exercised. Your fallback-model logic gets exercised. Your circuit breaker gets exercised. All the hard parts of production Bedrock code, which currently go untested on every project I&#x27;ve seen.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Call history.&lt;&#x2F;strong&gt; After your code runs, query fakecloud for every InvokeModel and Converse call it made — prompts, outputs, timestamps, error field. Assert on what your code &lt;em&gt;sent&lt;&#x2F;em&gt;, not just on what it received.&lt;&#x2F;p&gt;
&lt;p&gt;Together, that&#x27;s a complete test loop.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-real-example&quot;&gt;A real example&lt;&#x2F;h2&gt;
&lt;p&gt;Here&#x27;s a spam classifier that calls Claude via Bedrock. I want to test both the happy path (spam vs. ham branching) and the retry path (throttling recovery). Using the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;TypeScript SDK&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;fakecloud&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  BedrockRuntimeClient,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  InvokeModelCommand,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;@aws-sdk&#x2F;client-bedrock-runtime&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; modelId&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;anthropic.claude-3-haiku-20240307-v1:0&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;beforeEach&lt;&#x2F;span&gt;&lt;span&gt;(()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; fc.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;classifier branches on spam vs ham&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span&gt; fc.bedrock.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;setResponseRules&lt;&#x2F;span&gt;&lt;span&gt;(modelId, [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { promptContains:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;buy now&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, response:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;{&amp;quot;label&amp;quot;:&amp;quot;spam&amp;quot;}&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { promptContains:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; null&lt;&#x2F;span&gt;&lt;span&gt;,      response:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;#39;{&amp;quot;label&amp;quot;:&amp;quot;ham&amp;quot;}&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;  },&lt;&#x2F;span&gt;&lt;span style=&quot;color: #768390;&quot;&gt; &#x2F;&#x2F; catch-all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; classify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;hello friend&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; classify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;buy now cheap pills&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; invocations&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.bedrock.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getInvocations&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].output).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;ham&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].output).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;spam&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;retries on ThrottlingException&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; async&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span&gt; fc.bedrock.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;queueFault&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    errorType:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;ThrottlingException&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    message:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;Rate exceeded&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    httpStatus:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 429&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #768390;&quot;&gt; &#x2F;&#x2F; only the first call faults; the retry succeeds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  await&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; classify&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;hello&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; invocations&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.bedrock.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getInvocations&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].error).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;ThrottlingException&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].error).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBeNull&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No tokens burned. No rate limits hit. No test flake. Runs on a plane.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;classify&lt;&#x2F;code&gt; function is unchanged from production — it&#x27;s a real &lt;code&gt;BedrockRuntimeClient&lt;&#x2F;code&gt; calling a real &lt;code&gt;InvokeModelCommand&lt;&#x2F;code&gt;. The only difference is &lt;code&gt;endpoint: &quot;http:&#x2F;&#x2F;localhost:4566&quot;&lt;&#x2F;code&gt; in the SDK config. Your production code never knows it&#x27;s talking to fakecloud, which is exactly what you want: the tests exercise the same code path that runs in production.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;isn-t-a-fake-model-just-a-mock&quot;&gt;Isn&#x27;t a fake model just a mock?&lt;&#x2F;h2&gt;
&lt;p&gt;No, and the distinction is important.&lt;&#x2F;p&gt;
&lt;p&gt;A mock replaces the SDK client. A mock knows what method you called and what arguments you passed, and returns whatever you told it to. If your code uses a deprecated field, or sends invalid JSON, or builds the request wrong, the mock doesn&#x27;t care — it was told to return a value and it returns it.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud is a real HTTP server implementing the real Bedrock wire protocol. Your AWS SDK sends real SigV4-signed requests over real HTTP. If your code builds the request wrong, fakecloud rejects it the same way real AWS would. The only thing that&#x27;s &quot;fake&quot; is the inference — instead of calling a real model, fakecloud returns the response you configured.&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s not a limitation, it&#x27;s the point. &lt;strong&gt;You don&#x27;t want a real model in tests. You want a predictable one.&lt;&#x2F;strong&gt; Real models are for production, where you want the best possible output. Tests are for verifying that your code behaves correctly &lt;em&gt;given&lt;&#x2F;em&gt; an output. Those are different problems and they need different tools.&lt;&#x2F;p&gt;
&lt;p&gt;When you don&#x27;t configure anything, fakecloud falls back to a canned response per provider format — Anthropic, Titan, Llama, Cohere, Mistral all get provider-shaped defaults. So even a no-configuration test still gets something realistic back. You only need to configure responses when your code actually branches on content.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-this-unlocks&quot;&gt;What this unlocks&lt;&#x2F;h2&gt;
&lt;p&gt;Things that were hard or impossible before, that are now just tests:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Free CI.&lt;&#x2F;strong&gt; Run your full Bedrock-exercising test suite on every PR, every commit, every dependabot bump. No token budget to worry about.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Deterministic snapshots.&lt;&#x2F;strong&gt; The model returns exactly what you configured. Your snapshot tests work again.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Offline development.&lt;&#x2F;strong&gt; Write Bedrock code on a plane. Debug retry logic on a train. Iterate without thinking about AWS at all.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Error-path testing.&lt;&#x2F;strong&gt; Exercise every &lt;code&gt;catch&lt;&#x2F;code&gt; block in your code. Retry, fallback, circuit-break, degrade-gracefully — all testable, all deterministic.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Cross-service integration tests.&lt;&#x2F;strong&gt; Your Lambda calls Bedrock, writes to DynamoDB, and publishes to EventBridge? fakecloud runs all of those for real, in the same process, wired together. One test can exercise the whole flow.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;try-it&quot;&gt;Try it&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then point any AWS SDK at &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt; with dummy credentials. The TypeScript, Python, Go, and Rust first-party SDKs all have ergonomic helpers for the Bedrock introspection and configuration endpoints shown above.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repo:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Site:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&quot;&gt;fakecloud.dev&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you try it and find a case where fakecloud&#x27;s Bedrock implementation diverges from real AWS, that&#x27;s a bug — &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;open an issue&lt;&#x2F;a&gt;. The tests should have caught it.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Free, Open-Source LocalStack Alternative for AWS Testing</title>
          <pubDate>Sat, 11 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/localstack-alternative/</link>
          <guid>https://fakecloud.dev/blog/localstack-alternative/</guid>
          <description xml:base="https://fakecloud.dev/blog/localstack-alternative/">&lt;p&gt;In March 2026, LocalStack replaced its Community Edition with a proprietary image that requires an account and auth token. For teams that relied on LocalStack for local AWS testing, this broke CI pipelines and forced a choice: pay for a Pro license or find an alternative.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud is that alternative.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-fakecloud&quot;&gt;What is fakecloud?&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud is a free, open-source local AWS emulator for integration testing and local development. It runs on a single port (4566), requires no account or auth token, and aims to faithfully replicate AWS behavior.&lt;&#x2F;p&gt;
&lt;p&gt;Currently supports 20 AWS services with 1,000+ API operations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;S3&lt;&#x2F;strong&gt; — objects, multipart uploads, versioning, lifecycle, notifications&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Lambda&lt;&#x2F;strong&gt; — real code execution via Docker, 13 runtimes, event source mappings&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;SQS&lt;&#x2F;strong&gt; — FIFO queues, dead-letter queues, long polling&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;SNS&lt;&#x2F;strong&gt; — fan-out to SQS&#x2F;Lambda&#x2F;HTTP, filter policies&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;DynamoDB&lt;&#x2F;strong&gt; — tables, transactions, PartiQL, streams, global tables&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;EventBridge&lt;&#x2F;strong&gt; — pattern matching, scheduled rules, API destinations&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;RDS&lt;&#x2F;strong&gt; — PostgreSQL&#x2F;MySQL&#x2F;MariaDB via Docker, snapshots, read replicas&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ElastiCache&lt;&#x2F;strong&gt; — Redis&#x2F;Valkey via Docker, replication groups, failover&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;SES&lt;&#x2F;strong&gt; — v2 API (97 operations), inbound email pipeline, event destinations&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Cognito User Pools&lt;&#x2F;strong&gt; — authentication, MFA, user management&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Kinesis&lt;&#x2F;strong&gt; — data streams, shard iterators, stream retention&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Step Functions&lt;&#x2F;strong&gt; — ASL interpreter, Lambda&#x2F;SQS&#x2F;SNS&#x2F;DynamoDB integrations&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CloudWatch Logs&lt;&#x2F;strong&gt; — groups, streams, filtering, subscriptions&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;API Gateway v2&lt;&#x2F;strong&gt; — HTTP APIs with Lambda integration&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;IAM, STS, SSM, Secrets Manager, KMS, CloudFormation&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud#supported-services&quot;&gt;Full service list with operation counts&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;localstack-vs-fakecloud&quot;&gt;LocalStack vs fakecloud&lt;&#x2F;h2&gt;
&lt;p&gt;In March 2026, LocalStack moved many previously-free services behind a paywall (Cognito, SES v2, RDS, ElastiCache, ECR, ECS). The Community Edition now requires authentication and has limited service availability.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Feature&lt;&#x2F;th&gt;&lt;th&gt;fakecloud&lt;&#x2F;th&gt;&lt;th&gt;LocalStack Community&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;License&lt;&#x2F;td&gt;&lt;td&gt;AGPL-3.0 (free, open-source)&lt;&#x2F;td&gt;&lt;td&gt;Proprietary&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Auth required&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;td&gt;Yes (account + token)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Commercial use&lt;&#x2F;td&gt;&lt;td&gt;Free&lt;&#x2F;td&gt;&lt;td&gt;Paid plans only&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Docker required&lt;&#x2F;td&gt;&lt;td&gt;No (standalone binary)&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Startup time&lt;&#x2F;td&gt;&lt;td&gt;~500ms&lt;&#x2F;td&gt;&lt;td&gt;~3s&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Idle memory&lt;&#x2F;td&gt;&lt;td&gt;~10 MiB&lt;&#x2F;td&gt;&lt;td&gt;~150 MiB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Install size&lt;&#x2F;td&gt;&lt;td&gt;~19 MB binary&lt;&#x2F;td&gt;&lt;td&gt;~1 GB Docker image&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AWS services&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;30+&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Test assertion SDKs&lt;&#x2F;td&gt;&lt;td&gt;TypeScript, Python, Go, Rust&lt;&#x2F;td&gt;&lt;td&gt;Python, Java&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Cognito User Pools&lt;&#x2F;td&gt;&lt;td&gt;80 operations&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;references&#x2F;licensing&#x2F;&quot;&gt;Paid only&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SES v2&lt;&#x2F;td&gt;&lt;td&gt;97 operations&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;references&#x2F;licensing&#x2F;&quot;&gt;Paid only&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SES inbound email&lt;&#x2F;td&gt;&lt;td&gt;Real receipt rule action execution&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;user-guide&#x2F;aws&#x2F;ses&#x2F;&quot;&gt;Stored but never executed&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RDS&lt;&#x2F;td&gt;&lt;td&gt;22 operations, PostgreSQL&#x2F;MySQL&#x2F;MariaDB via Docker&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;references&#x2F;licensing&#x2F;&quot;&gt;Paid only&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ElastiCache&lt;&#x2F;td&gt;&lt;td&gt;44 operations, Redis&#x2F;Valkey via Docker&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.localstack.cloud&#x2F;references&#x2F;licensing&#x2F;&quot;&gt;Paid only&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;LocalStack has more services overall, but many are behind a paywall. fakecloud focuses on implementing fewer services completely, with 100% conformance to AWS behavior.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-we-built-fakecloud&quot;&gt;Why we built fakecloud&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;LocalStack went proprietary.&lt;&#x2F;strong&gt; In March 2026, &lt;code&gt;localstack:latest&lt;&#x2F;code&gt; started requiring authentication. CI pipelines broke. The message was clear: LocalStack Community Edition was no longer community.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Correctness matters for testing.&lt;&#x2F;strong&gt; If you&#x27;re building on AWS, your integration tests should talk to something that behaves like AWS — not mocks that return fake success responses. When fakecloud behaves differently from AWS, that&#x27;s a bug we fix.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Real infrastructure, not stubs.&lt;&#x2F;strong&gt; fakecloud runs actual software via Docker: real Lambda runtimes (13 languages), real databases (PostgreSQL, MySQL, MariaDB), real Redis&#x2F;Valkey instances. When your Lambda function reads from RDS, it&#x27;s talking to an actual Postgres instance, not a mock.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Testing tools should be free.&lt;&#x2F;strong&gt; fakecloud is a development dependency, not production infrastructure. It should be free and open-source, the same way test frameworks like Jest, Mocha, and pytest are free.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-we-verify-correctness&quot;&gt;How we verify correctness&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud doesn&#x27;t claim to be &quot;AWS-compatible&quot; without backing it up:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;34,000+ conformance test variants&lt;&#x2F;strong&gt; validated against official AWS Smithy models, covering every operation parameter, boundary condition, and error case&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;280+ end-to-end tests&lt;&#x2F;strong&gt; using the official AWS SDKs (aws-sdk-rust, boto3, aws-sdk-js)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Automated testing against real AWS&lt;&#x2F;strong&gt; — our test suite runs against both fakecloud and actual AWS to verify behavioral parity&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;When tests fail, we fix the behavior. We don&#x27;t stub responses or return fake success codes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;&#x2F;h2&gt;
&lt;p&gt;Install and run fakecloud:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or via Docker:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;docker&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; run&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --rm -p&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; 4566:4566 ghcr.io&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Point your AWS SDK at &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt; with dummy credentials:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --endpoint-url&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; http:&#x2F;&#x2F;localhost:4566 sqs create-queue&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; --queue-name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; test-queue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;test-assertions-with-fakecloud-sdks&quot;&gt;Test assertions with fakecloud SDKs&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud exposes introspection endpoints that AWS doesn&#x27;t provide, so you can assert on side effects in your tests:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; { FakeCloud }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; &amp;quot;fakecloud&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; fc&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt; FakeCloud&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;localhost:4566&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; After your app sends an email via SES&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; emails&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.ses.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getEmails&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(emails).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toHaveLength&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(emails[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].destination.toAddresses).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toContain&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt;&amp;quot;user@example.com&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #768390;&quot;&gt;&#x2F;&#x2F; After your Lambda processes an event&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F47067;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; invocations&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; = await&lt;&#x2F;span&gt;&lt;span&gt; fc.lambda.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;getInvocations&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(invocations[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].statusCode).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #DCBDFB;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;SDKs available for TypeScript, Python, Go, and Rust.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-not-implemented-yet&quot;&gt;What&#x27;s not implemented (yet)&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud is younger than LocalStack and has fewer services. If you need EC2, ECS, or other services not listed above, LocalStack may still be your best option (if you&#x27;re willing to pay for Pro).&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;re prioritizing services based on real-world demand. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;Open an issue&lt;&#x2F;a&gt; if there&#x27;s a service you need.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;roadmap&quot;&gt;Roadmap&lt;&#x2F;h2&gt;
&lt;p&gt;Coming next:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bedrock&lt;&#x2F;strong&gt; — AI&#x2F;ML testing (high demand across the ecosystem)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Lambda Containers&lt;&#x2F;strong&gt; — practical container support with ECR&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CloudFront&lt;&#x2F;strong&gt; — CDN configuration testing&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CloudWatch Metrics&lt;&#x2F;strong&gt; — complete monitoring story alongside Logs&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Athena&lt;&#x2F;strong&gt; — SQL analytics on S3&lt;&#x2F;li&gt;
&lt;li&gt;More RDS engines (Oracle, SQL Server)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;blob&#x2F;main&#x2F;ROADMAP.md&quot;&gt;Full roadmap&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;other-alternatives-to-localstack&quot;&gt;Other alternatives to LocalStack&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Moto&lt;&#x2F;strong&gt; — Python-based AWS mocking library. More services than fakecloud (100+), but designed for unit tests with mocks rather than integration tests. Doesn&#x27;t support cross-service integrations or real Lambda execution.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;LocalStack Pro (paid)&lt;&#x2F;strong&gt; — If you need the full service catalog and don&#x27;t mind paying, LocalStack Pro is mature and feature-complete.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Real AWS&lt;&#x2F;strong&gt; — For the highest fidelity, test against real AWS. fakecloud is for fast local iteration; real AWS is for pre-production validation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;try-fakecloud&quot;&gt;Try fakecloud&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Repo:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Site:&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fakecloud.dev&quot;&gt;fakecloud.dev&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Install:&lt;&#x2F;strong&gt; &lt;code&gt;curl -fsSL https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh | bash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you find a case where fakecloud behaves differently from AWS, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;open an issue&lt;&#x2F;a&gt; — that&#x27;s a bug, and we&#x27;ll fix it.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>700 commits in 6 days: how to trust LLM-generated code</title>
          <pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/llm-guardrails/</link>
          <guid>https://fakecloud.dev/blog/llm-guardrails/</guid>
          <description xml:base="https://fakecloud.dev/blog/llm-guardrails/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;fakecloud&lt;&#x2F;a&gt; went from first commit to 17 AWS services, 1,000+ tests, and 700 commits in 6 days. Almost all of the code was generated by LLMs.&lt;&#x2F;p&gt;
&lt;p&gt;The obvious question: how do you trust any of it?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem-with-vibe-coding&quot;&gt;The problem with vibe coding&lt;&#x2F;h2&gt;
&lt;p&gt;Andrej Karpathy coined &quot;vibe coding&quot; in early 2025 — the idea of just accepting whatever the LLM gives you without really looking at it. A year later, the results are in: a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.blog&#x2F;2026&#x2F;01&#x2F;28&#x2F;are-bugs-and-incidents-inevitable-with-ai-coding-agents&#x2F;&quot;&gt;CodeRabbit study of 470 GitHub repositories&lt;&#x2F;a&gt; found that AI co-authored code contains 1.7x more bugs than human-written code, with logic errors up 75%, security vulnerabilities up 2.74x, and concurrency bugs doubled.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s what happens without guardrails. The answer isn&#x27;t to stop using LLMs — it&#x27;s to build the systems that make LLM output trustworthy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-short-answer&quot;&gt;The short answer&lt;&#x2F;h2&gt;
&lt;p&gt;Tests. Not unit tests that mock everything — real end-to-end tests that spin up the server, make actual AWS SDK calls, and verify the responses. If the LLM generates something that doesn&#x27;t match real AWS behavior, a test fails. If no test catches it, there should be a test for it.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s the foundation. The rest is process.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-workflow&quot;&gt;The workflow&lt;&#x2F;h2&gt;
&lt;p&gt;Here&#x27;s what building a new feature in fakecloud actually looks like:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. Evaluate.&lt;&#x2F;strong&gt; Start by looking at the current conformance state. What&#x27;s missing? What&#x27;s the next highest-value thing to implement? The LLM helps here — it can cross-reference the AWS API models with what&#x27;s already implemented and suggest what to tackle next.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. Plan.&lt;&#x2F;strong&gt; This is the most important step, and it&#x27;s mostly human. The LLM proposes an approach, but there&#x27;s a lot of back and forth. Multiple alternatives get explored. Architecture decisions get debated. The right technical direction matters more than speed — a bad foundation generates bad code forever. This is what some are calling &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.blog&#x2F;2026&#x2F;01&#x2F;28&#x2F;are-bugs-and-incidents-inevitable-with-ai-coding-agents&#x2F;&quot;&gt;spec-driven development&lt;&#x2F;a&gt; — writing a real plan with goals, constraints, and implementation notes before any code gets generated.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;3. Break it down.&lt;&#x2F;strong&gt; The work gets split into well-scoped pieces. Each piece includes E2E tests — not just relying on the conformance framework, but dedicated tests that exercise real workflows through the AWS SDK.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;4. Implement.&lt;&#x2F;strong&gt; The LLM writes the code and the tests, runs them locally, iterates until green. By the time a PR opens, the tests are already passing.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;5. CI.&lt;&#x2F;strong&gt; The PR hits CI — clippy, fmt, the full test suite. If something fails, the LLM iterates until it&#x27;s green. No human intervention needed for mechanical fixes.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;6. Code review.&lt;&#x2F;strong&gt; Two layers: an AI code reviewer catches surface issues, then a human review. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;addyo.substack.com&#x2F;p&#x2F;code-review-in-the-age-of-ai&quot;&gt;Addy Osmani put it well&lt;&#x2F;a&gt;: &quot;AI didn&#x27;t eliminate code review — it made verification mandatory.&quot;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-the-human-actually-reviews&quot;&gt;What the human actually reviews&lt;&#x2F;h2&gt;
&lt;p&gt;Not every line the same way.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Tests get reviewed exhaustively.&lt;&#x2F;strong&gt; Every line. Every assertion. Does this test actually verify the right behavior? Does it match what real AWS would do? Could it pass while the implementation is wrong? The tests are the source of truth for the project, so they have to be right.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Implementation gets scanned.&lt;&#x2F;strong&gt; A top-to-bottom read looking for architectural issues, weird patterns, unnecessary complexity. Sometimes things get sent back for refactoring — DRY violations, odd abstractions, things that don&#x27;t fit the codebase style.&lt;&#x2F;p&gt;
&lt;p&gt;The mental model: if the tests are comprehensive and correct, the implementation is constrained to be correct. It might not be elegant, but it works. Elegance can be fixed later. Correctness can&#x27;t be faked.&lt;&#x2F;p&gt;
&lt;p&gt;This aligns with what &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;newsletter.pragmaticengineer.com&#x2F;p&#x2F;when-ai-writes-almost-all-code-what&quot;&gt;Gergely Orosz describes&lt;&#x2F;a&gt; as the shift in engineering — from writing every line to &quot;assessing quality and architectural soundness.&quot; The engineer becomes a supervisor and decision-maker, not a typist.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-this-only-works-with-real-tests&quot;&gt;Why this only works with real tests&lt;&#x2F;h2&gt;
&lt;p&gt;Most codebases test with mocks. The test asserts that function A calls function B with the right arguments. That tells you nothing about whether the actual behavior is correct — it tells you the plumbing is connected.&lt;&#x2F;p&gt;
&lt;p&gt;Mocked tests are particularly dangerous with LLM-generated code because the LLM writes both the implementation and the test. If the implementation has a bug, the LLM will happily write a test that asserts the buggy behavior. The mock doesn&#x27;t care — it returns whatever it&#x27;s told to. This is likely a contributor to the 75% increase in logic errors found in AI-generated PRs — the tests pass, but they&#x27;re testing the wrong thing.&lt;&#x2F;p&gt;
&lt;p&gt;fakecloud&#x27;s E2E tests use the official &lt;code&gt;aws-sdk-rust&lt;&#x2F;code&gt; crate. They spin up a real fakecloud server, make real API calls, and verify real responses. If &lt;code&gt;CreateQueue&lt;&#x2F;code&gt; followed by &lt;code&gt;SendMessage&lt;&#x2F;code&gt; followed by &lt;code&gt;ReceiveMessage&lt;&#x2F;code&gt; doesn&#x27;t return the right message with the right attributes, the test fails. No mocks. No fakes. Real behavior.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s 650+ E2E tests, plus 600+ conformance tests that validate operations against official AWS Smithy API models using checksums. Together, they form a safety net tight enough to let LLMs write code at speed without sacrificing correctness.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-tests-don-t-catch&quot;&gt;What tests don&#x27;t catch&lt;&#x2F;h2&gt;
&lt;p&gt;To be clear: this isn&#x27;t bulletproof. E2E tests are great at catching behavioral bugs, but they&#x27;re weaker at catching security vulnerabilities, performance issues, and concurrency bugs — exactly the categories where &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.blog&#x2F;2026&#x2F;01&#x2F;28&#x2F;are-bugs-and-incidents-inevitable-with-ai-coding-agents&#x2F;&quot;&gt;AI-generated code is worst&lt;&#x2F;a&gt; (2.74x more security issues, 8x more excessive I&#x2F;O operations).&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s where the other layers matter. Static analysis (clippy, in Rust&#x27;s case) catches entire categories of bugs at compile time. AI code reviewers catch patterns that tests miss. The human review catches architectural problems. No single layer is sufficient — it&#x27;s the combination that makes the system trustworthy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;making-a-project-llm-friendly&quot;&gt;Making a project LLM-friendly&lt;&#x2F;h2&gt;
&lt;p&gt;This approach isn&#x27;t specific to fakecloud. Any project can get here:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Start with tests.&lt;&#x2F;strong&gt; If the project doesn&#x27;t have comprehensive E2E or integration tests, that&#x27;s the first thing to build — and LLMs are great at helping with that. Build the test infrastructure first, then use it as the guardrail for everything that follows. This is the single highest-leverage investment for LLM-assisted development.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Invest in CI.&lt;&#x2F;strong&gt; Linting, formatting, full test suites, automated code review. Every automated check is one less thing that can slip through. If speed goes up, the number of tests should go up proportionally.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Steer the architecture.&lt;&#x2F;strong&gt; The LLM is a force multiplier, not an architect. Discuss the plan. Explore alternatives. Push back when the approach doesn&#x27;t feel right. The human decides the direction; the LLM executes it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Review what matters.&lt;&#x2F;strong&gt; Tests get the most scrutiny. Implementation gets scanned for patterns. Don&#x27;t try to read every line like you wrote it — that doesn&#x27;t scale. Trust the tests, verify the tests are right.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-real-insight&quot;&gt;The real insight&lt;&#x2F;h2&gt;
&lt;p&gt;The question isn&#x27;t &quot;can you trust LLM-generated code?&quot; The answer is obviously no — not by default. The 1.7x bug rate proves it.&lt;&#x2F;p&gt;
&lt;p&gt;The real question is: can you build a system where LLM-generated code is continuously verified? Where every PR runs against hundreds of tests before a human ever sees it? Where the test suite is comprehensive enough that &quot;tests pass&quot; is a meaningful signal? Where static analysis, AI review, and human review each catch what the others miss?&lt;&#x2F;p&gt;
&lt;p&gt;If yes, then the LLM is just a very fast, very tireless junior developer that needs good guardrails. And 700 commits in 6 days stops being scary — it&#x27;s just what happens when the guardrails are in place.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Why I&#x27;m building a free, open-source AWS emulator</title>
          <pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://fakecloud.dev/blog/why-fakecloud/</link>
          <guid>https://fakecloud.dev/blog/why-fakecloud/</guid>
          <description xml:base="https://fakecloud.dev/blog/why-fakecloud/">&lt;p&gt;A few days ago, our CI started failing. The culprit: &lt;code&gt;localstack:latest&lt;&#x2F;code&gt; now requires an account and an auth token. Broken builds.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;d seen LocalStack creeping toward proprietary for a while, but this was the moment it actually hit. A colleague noticed it at the same time as me, but I was already working on a fix. I patched the build, but the question stuck: how long can we keep using the old version until we start having real problems?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;i-don-t-trust-mocks&quot;&gt;I don&#x27;t trust mocks&lt;&#x2F;h2&gt;
&lt;p&gt;I should back up. I care about tests a lot. Enough to become a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;chaijs&#x2F;chai&quot;&gt;maintainer of Chai.js&lt;&#x2F;a&gt;. Enough that when I build something, the test infrastructure comes first.&lt;&#x2F;p&gt;
&lt;p&gt;But I have a specific opinion about &lt;em&gt;what kind&lt;&#x2F;em&gt; of tests matter. I hate mocks. Not the concept — the way most codebases use them. You end up with tests that don&#x27;t test anything real. You&#x27;re asserting that you call functions in the right order. You&#x27;re verifying the plumbing, not the behavior.&lt;&#x2F;p&gt;
&lt;p&gt;The worst part is when mocked tests give you false confidence. I&#x27;ve seen tests that assert you do the wrong thing successfully — the mock doesn&#x27;t care, it just returns what you told it to. Your tests pass. Your code has a bug. You ship it.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re building on AWS, you need integration tests that actually talk to something that behaves like AWS. Not a mock. Not a stub that returns 200 to everything. Something that implements the real behavior: if you call API A then API B, and AWS would produce side effect C, then your test environment should produce side effect C too.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s what LocalStack used to give us. And that&#x27;s what I wanted to keep — but free and open source.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;so-i-built-it&quot;&gt;So I built it&lt;&#x2F;h2&gt;
&lt;p&gt;I started fakecloud on April 4th, 2026. Three days later: 13 AWS services, 300+ commits, 1,000+ tests.&lt;&#x2F;p&gt;
&lt;p&gt;That pace was possible because of two things. First, I used LLMs heavily throughout — not to generate code I don&#x27;t understand, but as a force multiplier with strong guardrails. Every feature ships with E2E tests. The tests are the guardrails. If the LLM generates something that doesn&#x27;t match real AWS behavior, the tests catch it.&lt;&#x2F;p&gt;
&lt;p&gt;Second, Rust. I chose Rust because I love static-typed compiled languages, and Rust&#x27;s type system is genuinely amazing. You get the performance of no garbage collector without having to manually manage memory. It means fakecloud starts in under 100ms and runs as a single binary — no Docker required, no runtime dependencies.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;correctness-is-the-whole-point&quot;&gt;Correctness is the whole point&lt;&#x2F;h2&gt;
&lt;p&gt;fakecloud doesn&#x27;t try to be a scalable production cloud. It&#x27;s not that. It&#x27;s a testing tool. And the one thing a testing tool needs to get right is correctness.&lt;&#x2F;p&gt;
&lt;p&gt;What does that mean in practice? If you call &lt;code&gt;CreateQueue&lt;&#x2F;code&gt;, then &lt;code&gt;SendMessage&lt;&#x2F;code&gt;, then &lt;code&gt;ReceiveMessage&lt;&#x2F;code&gt; on real AWS and get back your message with specific attributes — fakecloud should do exactly the same thing. If it doesn&#x27;t, that&#x27;s a fakecloud bug.&lt;&#x2F;p&gt;
&lt;p&gt;We currently verify this with 280+ E2E tests that use the official &lt;code&gt;aws-sdk-rust&lt;&#x2F;code&gt; crate and 34,856 auto-generated conformance test variants validated against official AWS Smithy models — covering all 731 API operations across 13 services at 100% conformance. The plan for the near future: set up a real AWS account and run our test suite against both fakecloud and real AWS side by side, so we can verify behavioral parity automatically.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-here-today&quot;&gt;What&#x27;s here today&lt;&#x2F;h2&gt;
&lt;p&gt;13 services, 731 API operations, all open source, all free:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;S3&lt;&#x2F;strong&gt; (74 actions) — objects, multipart uploads, versioning, lifecycle, notifications, encryption&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;SQS&lt;&#x2F;strong&gt; (20 actions) — FIFO queues, dead-letter queues, long polling, batch operations&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;SNS&lt;&#x2F;strong&gt; (34 actions) — fan-out to SQS, HTTP delivery, filter policies, platform applications&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;EventBridge&lt;&#x2F;strong&gt; (57 actions) — pattern matching, scheduled rules, connections, API destinations, endpoints&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;IAM&lt;&#x2F;strong&gt; (128 actions) — users, roles, policies, groups, instance profiles, OIDC&#x2F;SAML providers&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;STS&lt;&#x2F;strong&gt; (8 actions) — assume role, session tokens, federation&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;SSM&lt;&#x2F;strong&gt; (146 actions) — parameters, documents, commands, maintenance windows, associations, automation, sessions&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;DynamoDB&lt;&#x2F;strong&gt; (57 actions) — tables, items, transactions, PartiQL, backups, global tables, streaming&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Lambda&lt;&#x2F;strong&gt; (10 actions) — function CRUD, invoke, event source mappings&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Secrets Manager&lt;&#x2F;strong&gt; (23 actions) — versioning, soft delete, rotation, replication, resource policies&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CloudWatch Logs&lt;&#x2F;strong&gt; (113 actions) — groups, streams, filtering, deliveries, transformers, anomaly detection&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;KMS&lt;&#x2F;strong&gt; (53 actions) — encryption, aliases, key management, grants, custom key stores&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CloudFormation&lt;&#x2F;strong&gt; (8 actions) — template parsing, resource provisioning&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Services talk to each other: S3 notifications deliver to SNS&#x2F;SQS. SNS fans out to SQS. EventBridge rules fire on schedule and deliver to targets. This is the kind of cross-service behavior that matters in integration tests and that most emulators get wrong or skip entirely.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;try-it&quot;&gt;Try it&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #ADBAC7; background-color: #22272E;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #6CB6FF;&quot;&gt; -fsSL&lt;&#x2F;span&gt;&lt;span style=&quot;color: #96D0FF;&quot;&gt; https:&#x2F;&#x2F;fakecloud.dev&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F47067;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt; bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F69D50;&quot;&gt;fakecloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then point any AWS SDK at &lt;code&gt;http:&#x2F;&#x2F;localhost:4566&lt;&#x2F;code&gt; with dummy credentials. That&#x27;s it.&lt;&#x2F;p&gt;
&lt;p&gt;The code is at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&quot;&gt;github.com&#x2F;faiscadev&#x2F;fakecloud&lt;&#x2F;a&gt;. It&#x27;s AGPL-3.0 — free and open source, including for commercial use.&lt;&#x2F;p&gt;
&lt;p&gt;If you need a local AWS emulator for your integration tests, give it a try. And if something doesn&#x27;t behave like real AWS — &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;faiscadev&#x2F;fakecloud&#x2F;issues&quot;&gt;open an issue&lt;&#x2F;a&gt;. That&#x27;s a bug, and we&#x27;ll fix it.&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
