github ministackorg/ministack v1.3.59

one hour ago

What's Changed

New Contributors

[1.3.59] — 2026-06-05

Added

  • CloudFormation — AWS::AppConfig::Environment, ConfigurationProfile, HostedConfigurationVersion, DeploymentStrategy, Deployment — five new provisioners closing the AppConfig CFN surface (Application was added in v1.3.55). Property names, defaults, Ref returns, and Fn::GetAtt attribute names (EnvironmentId; ConfigurationProfileId + KmsKeyArn; VersionNumber; Id; DeploymentNumber + State) match the AWS CFN reference verbatim. HostedConfigurationVersion enforces the optional LatestVersionNumber locking token against the current latest version. Deployment tags are stored against the AWS-shape ARN (arn:aws:appconfig:{region}:{account}:application/{app}/environment/{env}/deployment/{num}). Reported by @zdenekmartinec.
  • AppSync — full AWS-standard AppSyncResolverEvent for AWS_LAMBDA data sourcesarguments, source, request.headers, prev, stash, info.{fieldName, parentTypeName, variables} built per the AppSync Lambda-resolver tutorial. For AWS_LAMBDA auth mode, the authorizer Lambda is invoked first and its resolverContext is threaded into identity. The authorizer event matches the verbatim AWS shape: authorizationToken, requestHeaders, and requestContext with apiId / accountId / requestId / queryString / operationName / variables. Unhandled resolver exceptions surface as a GraphQL errors entry instead of leaking the RIE error payload as data. Contributed by @AdigaAkhil.
  • Glue — BatchUpdatePartition — closes the last partition action gap; matches AWS's per-entry shape (Entries[*].{PartitionValueList, PartitionInput} in, Errors[*].{PartitionValueList, ErrorDetail{ErrorCode, ErrorMessage}} out). Updates the matched partition in place preserving CreationTime and refreshing LastAccessTime; per-entry EntityNotFoundException on missing partition; request-level EntityNotFoundException on unknown table. Contributed by @yonatoasis.

Fixed

  • Lambda — layers mount inside the docker executor (DinD)_spawn_lambda_container extracted layers via container.put_archive(...), but the Docker API requires the destination path to already exist in the container; the base Lambda RIE image has /opt but no /opt/layer_N subdir, so the call returned 404 (Could not find the file /opt/layer_0 in container ...). The cp now extracts into the existing /opt with arcname=f"layer_{idx}", materialising /opt/layer_N/... from the tar. Also reaps the docker warm-container pool on UpdateFunctionConfiguration (worker-affecting field change) and DeleteFunction, mirroring the in-process worker invalidation from v1.3.58 — without this, the docker pool (keyed on acct:func:zip:CodeSha256) reuses pre-attach containers and the layer is never mounted on the reused container. Reported by @omargr299.
  • API Gateway v2 — JWT authorizer resolves JWKS via OIDC discovery for non-Cognito issuers_resolve_jwks_url hardcoded {issuer}/.well-known/jwks.json, which 404s for issuers whose keys live elsewhere (Salesforce /id/keys, Okta /oauth2/v1/keys). The resolver now fetches {issuer}/.well-known/openid-configuration, reads the published jwks_uri, and caches per-issuer for 2h; the Cognito short-circuit is preserved, and the conventional /.well-known/jwks.json path remains the fallback when discovery is unavailable. Contributed by @Pratham2703005.
  • S3 — PutObject checksums (SHA256 / SHA1 / CRC32) are stored and surfaced on GetObject / HeadObjectPutObject previously dropped every x-amz-checksum-* header on the floor and Get / HeadObject(ChecksumMode='ENABLED') returned no ChecksumSHA256 (or sibling), so SDK-side integrity checks always failed. Now the object record carries an AWS-shape checksums dict; client-supplied values are accepted; x-amz-sdk-checksum-algorithm: SHA256 | SHA1 | CRC32 triggers server-side compute; a mismatch between the supplied value and the server-computed one is rejected with BadDigest. CopyObject propagates the source's checksum (or accepts/computes a new algorithm against the copied body). Versioned reads (GetObject?versionId=X) return the per-version checksum. Get / HeadObject emit checksum headers only when the request carries x-amz-checksum-mode: ENABLED, and never on 206 Partial Content (a whole-object checksum can't validate a sliced response). Checksums persist across restart via the on-disk meta sidecar. CRC32C / CRC64NVME require optional native libs not in stdlib; rather than silently accept unverifiable client-supplied values for those, ministack rejects the put with a clear InvalidRequest pointing to the supported algorithms. Reported by @Guigoz.
  • S3 — on-disk bucket directory is account-scopedCreateBucket persisted its directory at DATA_DIR/<bucket> while every object write goes to the account-scoped DATA_DIR/<account>/<bucket>/<key> (via _object_disk_path). The unscoped makedirs left a spurious empty folder at the data-dir root that no code path ever used; DeleteBucket left it behind even after the bucket record was gone. _create_bucket / _delete_bucket now scope the directory to the current account, matching the object-write layout end-to-end. Reported by @rsking.
  • Glue — StartJobRun script resolution + crawler completion under non-default accounts_resolve_script built an unscoped on-disk path while S3 persists objects at DATA_DIR/<account>/<bucket>/<key>, so file-backed Glue scripts never resolved; and _finish_crawl runs on a threading.Timer which doesn't copy contextvars, so for any non-default account the account-scoped _crawlers guard missed and the crawler hung in RUNNING forever. The script path now includes get_account_id() to match the canonical writer; the job-run thread and crawler timer are wrapped with contextvars.copy_context().run(...) (the same idiom as stepfunctions.py / rds.py) so the request's account is carried into background work. Contributed by @AdigaAkhil.

Don't miss a new ministack release

NewReleases is sending notifications on new releases.