Skip to content

QuotaVersion/ResourceVersion lose their chain fields on JSON marshal (promoted MarshalJSON) #2

Description

@rchildress87

store.QuotaVersion embeds store.Quota, and Quota declares a
value-receiver MarshalJSON. Go promotes that method to the embedding
struct, and QuotaVersion declares none of its own — so json.Marshal of a
QuotaVersion emits only the Quota wire shape and silently drops every field
the version type adds.

Reproduction:

v := store.QuotaVersion{
    Quota:        store.Quota{ID: "abc", Provider: "aws", Name: "n"},
    RootID:       "abc",
    VersionRowID: "0197f0a2-1c3d-7e00-9a1b-2c3d4e5f6a7b",
    SupersededBy: &sup,
}
b, _ := json.Marshal(v)

Output — no rootId, no versionRowId, no supersededBy:

{"id":"abc","provider":"aws","accountId":"","accountName":null,"region":"",
 "serviceCode":"","serviceName":null,"quotaCode":"","name":"n",
 "description":null,"unit":null,"value":null,"defaultValue":null,
 "adjustable":false,"globalQuota":false,"appliedLevel":null,
 "discoveredAt":"","discoveredBy":"","attributes":{}}

Six fields are lost: versionRowId, rootId, previousVersionId,
supersededBy, verifiedAt, verifiedBy.

This matters most for the version chain, which is the reason the separate
quotas table keeps history at all. Without supersededBy a consumer cannot
tell which row is current, and without previousVersionId the chain cannot be
ordered except by discoveredAt. Any JSON output of GetQuotaVersions is
affected — disco history for a quota, and any downstream consumer.

store.ResourceVersion has the identical defect for the same reason, so a fix
should probably cover both rather than just this one.

Suggested fix: give QuotaVersion (and ResourceVersion) its own
MarshalJSON that starts from the embedded type's output and adds the chain
fields, rather than relying on promotion.

disco-saas currently works around this by assembling the wire object itself
(marshalQuotaVersion in internal/http/v1_quota_handlers.go), guarded by a
test that logs when the workaround becomes redundant. That wrapper can be
deleted once this is fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions