fix(cloudwatch): awsJson1_0 protocol and request validation parity (CW-X12, CW-X13) - #1371
Merged
Merged
Conversation
… (CW-X12) Adds a JSON codec over the shared CBOR per-op cores and unwraps gzip request bodies on all three protocols.
| } | ||
|
|
||
| func (j *jsonWriter) Header() http.Header { return j.w.Header() } | ||
| func (j *jsonWriter) Write(b []byte) (int, error) { return j.w.Write(b) } |
…ity (CW-X13) Maps the Granite target to cloudwatch in the authz gate, tightens the JSON codec, and fixes tag, dimension, alarm period and statistic, dashboard body and metric stream error codes on every protocol. Adds AlarmConfigurationUpdatedTimestamp to MetricAlarm output.
…k on metric streams
NitinKumar004
marked this pull request as ready for review
September 27, 2026 13:08
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes tracker rows CW-X12 and CW-X13.
CW-X12: botocore 1.43+ (boto3, awscli v1) talks to CloudWatch over awsJson1_0: a POST with
X-Amz-Target: GraniteServiceVersion20100801.<Op>andContent-Type: application/x-amz-json-1.0. The CloudWatch handler only served query and rpc-v2-cbor, so every such call got a 501 "no handler registered".boto3.client("cloudwatch", endpoint_url=...).describe_alarms()failed on the first call.CW-X13: a set of request-validation and error-code gaps that looked the same on every protocol. These are listed below.
What changed
awsJson1_0 codec (CW-X12)
server/aws/cloudwatch/json_protocol.go: a third codec over the same per-op cores. CloudWatch's JSON and CBOR shapes share member names, so the codec turns the JSON body into CBOR, runs the same per-op handler and<op>Coreas the CBOR path, and turns the result back into JSON. Every op served on query or CBOR now works on JSON, and there is no per-op JSON twin to drift.20.0, not20). Integral numbers such as60.0are accepted for int members.[]/{}. Null members are dropped.{}. Anything after the top-level object is rejected with SerializationException.{"__type","message"}withX-Amzn-Errortypeand the right HTTP status. CloudWatch is awsQueryCompatible, so__typeholds the model shape name (for exampleInvalidParameterValueException) andX-Amzn-Query-Errorcarries the query code (InvalidParameterValue;Sender). As a result botocore'sClientErrorcode and modeled exception class match what the query protocol gives. The sharedwire.WriteJSONErroralready setsX-Amzn-Errortype.handler.go:Matchesclaims only targets that start withGraniteServiceVersion20100801., so requests for other awsJson services are left alone.server/aws/authzgate.go: mapsGraniteServiceVersion20100801.to thecloudwatchIAM service. Without this, every boto3 CloudWatch call underserve -enforce-authfailed closed with AccessDenied, even when a policy allowedcloudwatch:*. SigV4 verification needs no change, because it checks the signature against whatever credential scope the client signed with (monitoring).request_encoding.go: PutMetricData has the requestCompression trait, so SDKs gzip bodies over 10 KiB. The handler now unwrapsContent-Encoding: gzipon all three protocols. Before this, a large PutMetricData failed on JSON, on query, and on the Go SDK's CBOR path too.Validation and error parity (CW-X13), same on every protocol
ResourceNotFoundException. The CBOR tag handlers now go through the same routing helpers as query, so the two copies are gone.InvalidParameterValue).ValidationErrorin these cases:InvalidParameterInput(the DashboardInvalidInputError shape).InvalidParameterValuecode, and their messages no longer carry the internalInvalidArgument:prefix. PutMetricStream also rejects a FirehoseArn or RoleArn that is not an ARN.AlarmConfigurationUpdatedTimestamp.mondriver.AlarmInfogets the field and the AWS provider fills it from the stored config time.GetMetricWidgetImage stays out of scope (CW-8).
Tests (all fail on the old code)
json_protocol_test.go: a lifecycle table that drives all 29 ops over JSON. It also covers ListMetrics paging, error envelopes (status,__type, both headers, message), trailing data, empty collections, and Matches.json_transcode_test.go: value rules for timestamps, blobs, doubles vs ints,60.0into an int member, empty maps and lists, and bad or trailing bodies.request_compression_test.go: gzip PutMetricData on JSON, query and the Go SDK (CBOR).validation_parity_test.go: every CW-X13 case plus the accepted edges (Period 30, 30 dimensions), each run over query, CBOR and JSON. It also checksAlarmConfigurationUpdatedTimestampon all three.server/aws/cloudwatch_json_dispatch_test.go: on the full AWS server, a Granite target reaches CloudWatch, while DynamoDB, Logs and Kinesis targets still reach their own handlers.server/aws/authzgate_cloudwatch_test.go: under enforce-auth,cloudwatch:*allows DescribeAlarms and PutMetricData, and an explicit deny still blocks DeleteAlarms.E2E against
cloudemu serveserve -enforce-authwith IAM users restored from--persist:cloudwatch:*can put and describe, and gets AccessDenied on the explicitly denied DeleteAlarms.aws_cloudwatch_metric_alarm(Go SDK, CBOR): apply, then a clean plan (exit 0), then destroy.