fix(issuer): raise SignMetadata's metadata_json size limit from 64KB to 2MiB - #535
Conversation
…to 2MiB apigw's 55-minute VCI signed-metadata refresh ticker (StartSignedMetadataRefresher in internal/apigw/apiv1/sign_metadata.go) calls signMetadataViaIssuer, sending the full CredentialIssuerMetadataParameters JSON over gRPC to the issuer service's SignMetadata RPC. That JSON includes one CredentialConfigurationsSupported entry per configured VCTM/MDDL scope with multi-language Display/ClaimDescription/ ClaimDisplayProperties per claim (pkg/openid4vci/issuer_metadata.go), so a real deployment with ~10 configured scopes easily produces a payload over 64KB. internal/issuer/apiv1/sign_metadata.go hardcoded a 64KB cap on metadata_json (added in ecd6668, "Add constrains to signmetadata.", with no rationale for the specific figure and evidently only ever exercised with 1-2 scopes configured). Once a deployment grows past that, apigw logs a recurring: failed to refresh VCI signed metadata {"error": "failed to sign metadata via issuer: rpc error: code = InvalidArgument desc = metadata_json is too large"} This is a hardcoded application-level guard, not gRPC's own transport-level message-size limit — no MaxRecvMsgSize/MaxSendMsgSize is configured anywhere in internal/issuer/grpcserver or the apigw gRPC client, so grpc-go's ~4MiB default applies there and isn't what's firing. Raise the constant to 2 MiB (extracted into maxMetadataJSONBytes): generous headroom for realistic multi-scope metadata, while staying comfortably under gRPC's own 4 MiB default so this check — not gRPC's — is the one that fires and gives a clear, specific error instead of a generic transport failure. Testing: go build ./... clean; go test ./internal/issuer/apiv1/... and ./internal/apigw/apiv1/... pass; full `make test` scope (verifier, registry, apigw, issuer cmd+internal packages) passes. Added a boundary test asserting a payload exactly at the new limit clears the size check (fails at JSON parsing instead, since it's not valid JSON) and one byte over is still rejected as "too large". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
Independent review: verified the root-cause analysis (no other stale/hardcoded size limits elsewhere in the metadata_json path that would need the same bump), rebuilt and re-ran the full test suite from a clean worktree — build, vet, and `make test` all green, including the new boundary test. No merge conflicts against `main`. No issues found — this looks correct as-is. |
There was a problem hiding this comment.
Pull request overview
Raises the Issuer service’s application-level SignMetadata request-size guard to accommodate real-world Credential Issuer Metadata payloads that exceed the previous 64KB cap, while keeping a clear InvalidArgument failure mode under the gRPC transport limit.
Changes:
- Increased
metadata_jsonsize limit from 64KB to 2 MiB and extracted it into a named constant (maxMetadataJSONBytes) with rationale. - Updated/added validation tests to cover the new boundary conditions (exactly-at-limit vs. one-byte-over).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| internal/issuer/apiv1/sign_metadata.go | Replaces the hardcoded 64KB guard with a documented 2 MiB constant used by SignMetadata. |
| internal/issuer/apiv1/sign_metadata_test.go | Adds boundary payload setup and a test case asserting “exactly at limit” passes the size gate while “over limit” is rejected. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.



Symptom
apigw logs a recurring error:
Root cause
StartSignedMetadataRefresher→refreshSignedMetadataatinternal/apigw/apiv1/sign_metadata.go:154) callssignMetadataViaIssuer(lines 39-60), which sends the fullCredentialIssuerMetadataParametersJSON (built ininternal/apigw/apiv1/client.go) over gRPC to the issuer service'sSignMetadataRPC.CredentialConfigurationsSupportedentry per configured VCTM/MDDL scope, each with multi-languageDisplay/ClaimDescription/ClaimDisplayPropertiesper claim (seepkg/openid4vci/issuer_metadata.go). A real deployment with ~10 configured credential-type scopes easily produces a combined metadata JSON over 64KB.internal/issuer/apiv1/sign_metadata.go(previously lines 53-55) hardcoded:ecd66687("Add constrains to signmetadata."), with no rationale given for the specific figure — it was evidently only ever exercised with 1-2 scopes configured.MaxRecvMsgSize/MaxSendMsgSizeis configured anywhere ininternal/issuer/grpcserver/service.goor the apigw gRPC client, so grpc-go's ~4MiB default applies there and isn't what's firing.Fix
Raised the hardcoded 64KB constant to 2 MiB, extracted into a named constant
maxMetadataJSONByteswith a comment explaining the rationale:InvalidArgumenterror instead of a generic gRPC transport failure.Added a boundary test (
TestSignMetadata_Validation/metadata_json_exactly_at_size_limit_is_not_rejected_for_size) asserting a payload exactly at the new limit clears the size check (and instead fails one stage later at JSON parsing, since the boundary payload isn't valid JSON — proving the size gate itself let it through), alongside the existing "one byte over the limit is rejected as too large" case (updated to use the new limit).Testing
go build ./...— clean, no errors.go test ./internal/issuer/apiv1/...— all pass, including the new/updated boundary tests.go test ./internal/apigw/apiv1/...— all pass.make testscope (verifier, registry, apigw, issuer — bothcmd/...andinternal/...) — all pass.go vetandgofmt -lon changed files — clean.