v0.0.1-alpha.34
Pre-releaseOvercast v0.0.1-alpha.34
Docker Images
Full image with the web management console:
- Pull:
ghcr.io/neaox/overcast:0.0.1-alpha.34 - Moving tag:
ghcr.io/neaox/overcast:alpha - Registry: overcast package
Headless slim image for CI pipelines:
- Pull:
ghcr.io/neaox/overcast-slim:0.0.1-alpha.34 - Moving tag:
ghcr.io/neaox/overcast-slim:alpha - Registry: overcast-slim package
docker run --rm -p 4566:4566 -p 4567:4567 ghcr.io/neaox/overcast:0.0.1-alpha.34
docker run --rm -p 4566:4566 ghcr.io/neaox/overcast-slim:0.0.1-alpha.34Native Binaries
Download a binary for your platform from the assets below and verify it with SHA256SUMS.
| Asset | SHA256 |
|---|---|
overcast-darwin-amd64 |
e73e204bae6770bd4216c313e4b6a88a7c5ec816c368061d2338d67152d7f6ce |
overcast-darwin-arm64 |
ca7708b8c3da8af9cb27d31c771ab3f37e447140a3a332f2e46dee3631acdbf5 |
overcast-linux-amd64 |
980bed4b05ee6b8702a3fc45c01fc5385c15a673155b027fbf57eb985ac8e522 |
overcast-linux-arm64 |
8151a8bf01fdcf597932a83768a0e7dfe844ca79b034c5e8da785ccf862b7bc5 |
overcast-windows-amd64.exe |
5e0763ab5851eefbf618a769a79c1d6fe5956e61d2ff3dcd120821b44fcb2ec5 |
overcastd-darwin-amd64 |
035d20679361ee8728c6b1a4cbb7173411ac225fe50ea7bb66a601987d488b22 |
overcastd-darwin-arm64 |
ea322f434da544c01f52943622d335d912b2acebee1e7accf2315ecf71c2e375 |
overcastd-linux-amd64 |
0bfa543587c9a67094d48e606b4642b955246a7d962977a528b5d07b0f8b1664 |
overcastd-linux-arm64 |
f6a4e419bfd5d166e7d68a0ff6f3760bb3ca9b608124e111f37773bf7ed2883b |
overcastd-windows-amd64.exe |
37309ebfff523d85625f92ec8c896c6e728524f2fadfe5edcbe51b28d5b9e479 |
Release Notes
Added
-
[acm]
TagResource,UntagResourceandListTagsForResource— the modern aliases of the*Certificatetag operations, addressing the certificate byResourceArn.RequestCertificateapplies inlineTagsat creation -
[cloudtrail] Trails are taggable:
AddTags,RemoveTagsandListTags, plus an inlineTagsListonCreateTrail -
[iam] Managed policies and instance profiles are taggable:
TagPolicy/UntagPolicy/ListPolicyTagsandTagInstanceProfile/UntagInstanceProfile/ListInstanceProfileTags; andCreateUser,CreateRole,CreatePolicyandCreateInstanceProfileapply inlineTagsat creation -
[kinesis]
TagResource,UntagResourceandListTagsForResource— the ARN-addressed tag operations the AWS CLI'skinesis tag-resourceuses, reading and writing the same tag set asAddTagsToStream— andCreateStreamapplies inlineTagsat creation -
[scheduler]
ListSchedulesandListScheduleGroupshonourMaxResults,NextTokenandNamePrefix, andListSchedulesalso filters onState; aNextTokenthat cannot be decoded gets aValidationExceptionin place of a silent restart at the first page -
[ses] SESv2 resource tagging:
TagResource,UntagResourceandListTagsForResourceon/v2/email/tags, for email identities.CreateEmailIdentityapplies inlineTagsat creation,GetEmailIdentityreports them, and deleting an identity drops them -
[sns]
CreateTopicapplies inlineTagsat creation, as AWS does; a repeat idempotent call leaves an existing topic's tags untouched -
[transfer] Transfer Family servers and users are taggable:
TagResource,UntagResourceandListTagsForResource, plus inlineTagsonCreateServerandCreateUser.DescribeServerandDescribeUserreport them -
[web/s3] the object inspector opens on a named version: it shows that version's metadata and body, its copy-URL carries
?versionId=, and a version that cannot be read is explained rather than left blank — a delete marker as the tombstone it is, an id that no longer exists as a listing that has gone stale -
[web/cloudwatch] a Clear button on the log events viewer empties the buffer on screen without stopping the tail, so a live stream can be read from a known point instead of scrolling past everything that came before. The events are hidden, not lost — "Show N earlier" puts them back, and so does Refresh
-
[web/s3] an expiry hint on noncurrent version rows, counted the way the sweeper counts it — from the moment the version's successor was written, and skipping the newest versions a rule's
NewerNoncurrentVersionsretains -
[web/s3] search and sort controls on the bucket object browser: filter by name or prefix, switch between this-folder and fully recursive listings, and sort by name, size or last modified
-
[web/s3] a Versioning panel on the bucket Configuration tab, which is the first way to enable or suspend versioning from the console rather than through the API. The state was already reported there; only the control was missing. Suspending says what it actually does — new writes are stored with version id
null, and every version already stored is kept, which is not the same as turning versioning off -
[ec2] each region seeds a default VPC on first use, with a default subnet per availability zone, an attached internet gateway, a main route table carrying the default route, and a default security group —
DescribeVpcs --filters Name=isDefault,Values=trueand CDK'sVpc.fromLookup(isDefault: true)previously found nothing. Its backing network is the shared data plane, so "no VPC" and "the default VPC" are the same place;DeleteVpcon it removes the record and leaves the network, and an internet-gateway change on it is ignored rather than recreating the network under every running container -
[eks] a live-mode cluster's API server carries DNS aliases on the shared data plane. The endpoint
DescribeClusterreturns is still the published host port, so this is groundwork rather than a complete path
Changed
-
BREAKING [docker]
overcast-slimhas no SQLite, so a volume mounted at/datano longer gives it persistent storage:autoresolves to memory, andhybridandpersistentrefuse to start. This is what the image was always documented to do — it only appeared to persist because the wrong binary was shipped
migration: usewal, which is durable and needs no SQLite, or switch to the fullovercastimage -
[ecr] the registry asks for a fixed host port (
OVERCAST_ECR_REGISTRY_PORT, default 4510 — LocalStack's registry port) sorepositoryUriis stable across restarts, falling back to an ephemeral port when it is taken; the portrepositoryUrithen advertises is selected by the Docker daemon itself proving it can dial it — a dual-stack ephemeral publish can split IPv4 and IPv6 onto different host ports, and only the daemon knows which family itslocalhostreaches — and a path nothing answers on is one actionable warning instead of aCannotPullContainerErrorin a later task launch -
[scheduler]
CreateScheduleandCreateScheduleGroupanswer 200, the status code their AWS models bind, in place of 201 -
BREAKING [scheduler]
UpdateSchedulereplaces the whole schedule, as AWS does. An optional member the caller leaves out of the request —Description,ScheduleExpressionTimezone,State,StartDate,EndDate, or anything insideTarget— ends up unset, where it used to keep its stored value; the schedule keeps its name, group, ARN andCreationDate
migration: send the whole schedule, not just the parts you are changing — read it withGetSchedule, change what you mean to change, and send the result back -
BREAKING [config]
LAMBDA_NETWORK,ECS_NETWORK,RDS_NETWORK,ELASTICACHE_NETWORK,MSK_NETWORK,EKS_NETWORKandEFS_NETWORKare replaced by a singleOVERCAST_NETWORK(defaultovercast). Every container Overcast starts now shares one data plane instead of one network per emulator service, which is what made cross-service reachability a per-service bug; the seven per-service networks are removed at startup once nothing is attached to them
migration: unset the old variables. If you set one to a custom value, setOVERCAST_NETWORKto it instead; if you joined a compose service toovercast_lambdaor another per-service network, joinovercastinstead. -
[lambda/ecs] containers are created on a control plane that carries the Runtime API and the emulator endpoint, separately from the data plane they reach other resources on — the split a VPC needs in order to restrict one without severing the other
Fixed
-
[acm] tagging a certificate that does not exist is a
ResourceNotFoundExceptioninstead of succeeding and stranding the tags under an ARN nothing owns, andListTagsForCertificatereturns tags in a stable key order instead of a different order per call -
[cloudformation] a create that fails with rollback disabled leaves
StackStatusReasonset to AWS's summary of which resources failed, rather than to the underlying service error — which stays on the resource and its event, where AWS keeps it -
[cloudformation] stack operations accept the stack ARN wherever AWS does —
DescribeStacks,DescribeStackEvents,ListStackResources,DescribeStackResources,GetTemplate,GetTemplateSummary,UpdateStack,DeleteStack,CreateChangeSet, andDeleteChangeSetresolvedStackNameby name only, so clients that poll by the stack ID (CDK's deploy monitor among them) gotValidationError: Stack [arn:…] does not existfor a stack that was right there. Conversely, aCREATE-typeCreateChangeSetnaming an unknown stack ARN no longer mints a placeholder stack literally named the ARN — an ARN is a handle to an existing stack, and now answers "does not exist" -
[cloudformation] mutating a deleted stack now behaves as on AWS —
UpdateStackon aDELETE_COMPLETEstack reports it does not exist instead of resurrecting it, and a repeatDeleteStackis a no-op success instead of re-running the delete and appending a second wave of delete events -
BREAKING [cloudformation] a stack operation is now checked against the stack's state: a
CREATEchange set naming a stack that already exists isAlreadyExistsException, atCreateChangeSetand atExecuteChangeSet, andUpdateStack(withCreateChangeSetforChangeSetType: UPDATE) isValidationErrorfrom anything but a last known stable state — or aCREATE_FAILED/UPDATE_FAILEDstack the update resumes withDisableRollback
migration: delete aROLLBACK_COMPLETEstack before deploying over it, as the AWS CLI and CDK already do; resume aCREATE_FAILEDorUPDATE_FAILEDstack with--disable-rollback, or recover it withRollbackStack -
[cloudformation] re-deploying a stack that failed replaces the previous attempt's resource records instead of adding to them — a second
cdk deployover aROLLBACK_COMPLETEstack left two records per logical ID, soDescribeStackResourcesanswered with the first run's failure reason rather than the reason this run actually failed for -
[cloudformation] an update re-provisions a resource the stack no longer has behind a record — one whose create failed before naming anything, or one a rollback deleted — instead of matching it by logical ID, reading the missing property hash as "unchanged" and skipping it
-
[cloudformation/cloudwatch] a stack update that changes an
AWS::CloudWatch::Alarm's tags now applies them, throughTagResource/UntagResourceas real CloudFormation does.PutMetricAlarmappliesTagsonly when it creates an alarm, so the update reachedUPDATE_COMPLETEhaving changed nothing -
[cloudwatch] alarm tagging works over the JSON protocol the AWS CLI and the SDKs speak, not only the Query form —
ListTagsForResource,TagResourceandUntagResourcewere absent from the JSON dispatch, so alarm tags were unreadable withaws cloudwatch list-tags-for-resource. The same operations now reject an unknown or non-CloudWatchResourceARNwith AWS'sResourceNotFoundException/InvalidParameterValueinstead of quietly tagging a resource that does not exist, and hold tag sets to AWS's rules — 50 tags per resource, noaws:key prefix, key and value length limits — onTagResourceand on theTagsaPutMetricAlarmapplies at creation -
[cloudwatch]
PutMetricDataaggregates datapoints that share a timestamp instead of keeping only the last one — two datums in one call with noTimestamptake the same clock reading on a coarse platform timer, and were recorded as one value rather than being summed into the period -
[docker] the published
overcast-slimimage is a slim build. Every caller that selected the slim stage had to pass a matchingNOSQLITE=1build arg as well, and the release workflow did not, so-slimshipped the console binary — embedded web console,/_mcp, SQLite and all, the same size as the console image. The build target now decides the flavour on its own, and each builder asserts what it produced -
[docker] container start failures now carry the daemon's error message instead of a bare status code
-
[ecr] the emulated registry is reachable from the Docker daemon in the shapes that previously failed outright. Its port is published dual-stack instead of IPv4-only — the v4-only binding was invisible to Docker Desktop's port forwarding, leaving the daemon unable to reach its own registry at
localhost, so everydocker pushand every ECS pull of an ECR image died on a dial. Its htpasswd file is copied into the container rather than bind-mounted from a path only Overcast's own filesystem has, sodocker pushno longer refuses on every containerised deployment. AndListImages/DescribeImages/BatchGetImagereconcile pushed images when Overcast itself runs in a container, probing the addresses the registry can actually be at rather than assuming Overcast's own loopback -
[ecr] two Overcast instances sharing one Docker daemon no longer interfere with each other. The registry container's name is per-claim — port-derived for a fixed port, random for an ephemeral one — instead of a shared singleton, so startup removes nothing but a legacy singleton-named leftover and shutdown removes only the instance's own container; and the port
repositoryUriadvertises is proved to be this instance's registry rather than merely a registry, because the daemon-vantage startup probe carries the instance's own credentials. Interleaved ephemeral dual-stack publishes could previously leave one instance advertising a port serving the other's registry, and every token it then issued failed authentication against that registry's htpasswd -
[ecr] the registry's startup is no longer raced or silent:
GetAuthorizationTokenandrepositoryUriwait for it to actually answer before they are served — a token handed out ahead of a still-booting registry madedocker loginfail with EOF on loaded machines — a container name still held by a predecessor being removed is waited out rather than treated as fatal, and every startup step that fails says so in the log -
[ecs/ecr] a task definition whose image is a CDK container asset now starts: the
{account}.dkr.ecr.{region}.amazonaws.com/…reference CDK synthesises is resolved to the registry Overcast serves and pulled with the credentialsGetAuthorizationTokenissues, instead of reaching real AWS and failing withCannotPullContainerError: … no basic auth credentials -
[ecs]
awslogslog lines longer than 16 KiB are reassembled the same way, having had the same stamps spliced into them -
[lambda] an execution environment that fails to initialise is now explained: the container, the Runtime API endpoint it was handed, whether anything ever connected there, and what it printed
-
[lambda/ecr] a
PackageType=Imagefunction whose image is a CDK container asset now runs: the{account}.dkr.ecr.{region}.amazonaws.com/…reference CDK synthesises intoCode.ImageUriis resolved to the registry Overcast serves and pulled with the credentialsGetAuthorizationTokenissues, and the container is created from that reference, instead of the pull reaching real AWS and failing withno basic auth credentials. The function still reportsCode.ImageUriexactly as it was deployed -
[lambda] a log line longer than 16 KiB reaches CloudWatch as the function wrote it, instead of with an RFC3339Nano timestamp spliced through the middle of it at every chunk boundary — Docker stamps each 16 KiB frame rather than each message, and reassembling the frames carried the continuation stamps into the line, cutting tokens of a serialized error object in half
-
[lambda] a log stream is named with the 32 hex characters AWS uses for the execution environment GUID (
2026/08/10/[$LATEST]312c2d81e2e64af58dbe557754f9aa13) rather than 26, which failed a caller matching stream names against AWS's shape -
[lambda] an invoke that asks for a log tail (
X-Amz-Log-Type: Tail) carries the function's own output, not only the START / END / REPORT lines. A warm invocation arriving while the log reader was still working through the previous one's output was reported as a function that had printed nothing, and answered with a tail missing itsconsole.log -
[scheduler] every EventBridge Scheduler operation is served at AWS's own path, so an unmodified SDK, CDK construct or
aws scheduler …call reaches it instead of answering 501 -
BREAKING [scheduler]
CreateScheduleandUpdateSchedulevalidate the schedule name, the schedule expression,FlexibleTimeWindow.ModeandState, answeringValidationExceptionwhere a schedule that could never fire used to be stored
migration: correct the offending field — a name is 1-64 characters of[0-9a-zA-Z-_.], an expression must berate(...),cron(...)orat(...),FlexibleTimeWindow.Modemust beOFForFLEXIBLE, andStatemust beENABLEDorDISABLED -
[scheduler]
DeleteScheduleGroupdeletes the schedules inside the group, as AWS does; they used to be left behind, unreachable through the API and still firing on every engine tick -
[scheduler]
StartDateandEndDatesurvive aCreateSchedulemade over the JSON/CBOR protocols, the path CloudFormation takes; the REST routes and that dispatch now run one implementation rather than two copies that had drifted -
[scheduler] a store failure while reading a schedule or a group is reported as
InternalErrorin place ofResourceNotFoundException, and a single undecodable record is skipped and logged instead of disappearing from a listing without trace -
[scheduler] a schedule whose target is slow, unreachable or working through its
RetryPolicyno longer holds up every other schedule in the emulator: the engine hands each due firing to a pool of delivery workers instead of delivering them one after another on the tick itself. A schedule is still never fired twice at once, so its own firings stay in order -
[scheduler] a sparse
cron(...)schedule no longer burns CPU on every engine tick. The evaluator advanced a minute at a time until something matched, so it cost one iteration per minute between now and the next firing — around 525,000 of them, once a second, for a yearly schedule. It now advances field by field, and parsing a cron expression allocates nothing. That rewrite also fixed a step over a range:cron(0 9-17/4 * * ? *)now fires at 09:00, 13:00 and 17:00, where the range was unreadable to the old parser, which fell back to stepping the whole field from zero and fired at 00:00, 04:00, 08:00, 12:00, 16:00 and 20:00 -
[scheduler] deleting a schedule sticks even when an
UpdateSchedulefor the same schedule is in flight. The update read the record, built its replacement and wrote it back without holding a lock, so aDeleteSchedulethat landed in between was written over — the caller was told the delete had succeeded and the schedule stayed stored and kept firing -
[sns] the notification envelope's
UnsubscribeURLnames the port the publisher reached Overcast on, rather than the configured one — on an instance published on a remapped port the link pointed at a port nothing was listening on -
[web/s3] the version-history view addresses each row by its version id, so downloading or inspecting a revision returns that revision. Every row resolved by key alone, which S3 answers with whichever version is current — a key with three stored revisions handed out the newest one whichever row was clicked
-
[web] the stack page's failure banner reports the most recent failure rather than the first resource listed
-
[web/cloudwatch] the log viewer's level badge labels every row whose level it detects, including a runtime's plain-text
console.*lines — previously only a JSON document was labelled and a text line got the row tint alone — and the badges are legible in light mode, where the warning badge used to be lighter than the row behind it. A long log stream name no longer overflows its column into the message text in the all-streams view -
[web] a log event carried by both a Live Tail session and a refresh of the events list is shown once, in place of a duplicate row
-
[web/s3] lifecycle rules that act on version history are no longer drawn as rules with no actions. NoncurrentVersionExpiration, NoncurrentVersionTransition and ExpiredObjectDeleteMarker were dropped on the way into the console, so a versioned bucket whose entire retention policy is one of them showed a rule that appeared to do nothing
-
[web/s3] the version column shows the end of a version id rather than the start, so two versions of one key can be told apart. Overcast mints ids with the timestamp leading, so versions written moments apart share their first characters — three versions of one key all rendered as the same eight characters followed by an ellipsis
-
[elasticache] the support matrix no longer advertises
DescribeCacheEngineVersionsandRebootCacheClusteras supported — both are routed to a NotImplemented stub and always answer 501, so they are marked Unsupported until they are emulated -
[elasticache] a cache node is reachable from an ECS task, and under every hostname its endpoint could have been minted with — previously it was attached only to the Lambda network and registered only the configured name, so an ECS task resolving it reached Overcast on the Redis port and hung rather than failing (#872)
-
[ses]
CreateEmailIdentityis served atPOST /v2/email/identities, the binding AWS models, so the SDKs andaws sesv2 create-email-identityreach it instead of an error. It was registered underPUT, which no client sends, leaving the operation — and the inlineTagsit applies at creation — unreachable. ThePUTbinding is gone; AWS never had one. -
[ec2]
DescribeVpcshonoursVpcId.Nand thevpc-idandisDefaultfilters, and reportsisDefaultfrom the record instead of alwaysfalse— CDK's VPC lookup treats the response as already filtered and needs exactly one VPC back, so an unfiltered response would breakVpc.fromLookupfor anyone holding more than one VPC -
[efs] NFS mount-target exports are resolvable by name from sibling containers, not only by container address
-
[eks] a live-mode cluster's endpoint aliases use the cluster's own region rather than the configured default, so a cluster created in another region resolves
-
[eks] live mode pulls the k3s image before it creates a control plane, so a cluster can be created on a machine that has never run one. Docker answered
No such imageto the create and the cluster then reportedCREATINGindefinitely, with the reason only in a log line — a start that fails now reachesFAILEDand carries the Docker error incluster.health.issues, so a waiter gets an answer instead of hanging -
[eks] a containerised Overcast can bring up a live-mode cluster at all. It probed the k3s API on
127.0.0.1:<published port>, which inside its own network namespace is itself, so a healthy control plane never leftCREATING; it now dials the container address on the control plane when it runs beside the daemon, the same lookup the RDS, ElastiCache, MSK and EFS health checks use.DescribeClusterstill returns the published host port -
[msk]
GetBootstrapBrokersreturns an address the caller can actually dial: a resolvable broker hostname on 9092 for a sibling container, the published port for the host. It previously returnedOVERCAST_HOSTNAME:hostPortto everyone, which inside any container resolves to Overcast — a process that serves no Kafka
Removed
- BREAKING [scheduler] the emulator-only
/_scheduler/*path prefix
migration: use AWS's paths —/schedules/{Name}withGroupNamein the body on create/update and?groupNameon get/delete,/schedules,/schedule-groups/{Name},/schedule-groups, and/tags/{ResourceArn}
Release: https://github.com/Neaox/overcast/releases/tag/v0.0.1-alpha.34