Skip to content

fix: resolve OpenAPI allOf schema inheritance - #17

Merged
jpower432 merged 7 commits into
gemaraproj:mainfrom
gxmiranda:opsx/fix-allof-schema-inheritance
Sep 30, 2026
Merged

jpower432 merged 7 commits into
gemaraproj:mainfrom
gxmiranda:opsx/fix-allof-schema-inheritance

Conversation

@gxmiranda

@gxmiranda gxmiranda commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Generated schema reference pages now resolve local OpenAPI allOf composition so embedded CUE definitions retain inherited properties and required fields. The renderer also handles multi-level inheritance, derived-property overrides, cyclic references, and description-plus-allOf property wrappers.

Fixes #11

How to Test

  • Run cd tools && go test ./...
  • Run cd tools && go vet ./...
  • Generate documentation with make genmd
  • Inspect representative catalog and log pages for inherited fields
  • Run make test-links when Ruby/Bundler dependencies are installed

How to Demo

Generate schema documentation from the current Gemara OpenAPI release and inspect controlcatalog, threatcatalog, and log outputs. Confirm inherited metadata and catalog fields appear and required markers are preserved.

Key Files Changed

  • tools/internal/cmd/openapi2md.go: Resolve and merge local allOf schemas during rendering.
  • tools/internal/cmd/openapi2md_test.go: Add regression tests for inheritance, overrides, cycles, and wrappers.
  • tools/internal/cmd/testdata/allof.yaml: Add OpenAPI composition fixtures.
  • openspec/changes/fix-allof-schema-inheritance/: Record proposal, design, requirements, and completed implementation tasks.

This PR was generated by /uf.finale (AI-assisted).

Signed-off-by: Gustavo Miranda <48178298+gxmiranda@users.noreply.github.com>
@gxmiranda
gxmiranda force-pushed the opsx/fix-allof-schema-inheritance branch from 5862fbe to 3b1db37 Compare September 18, 2026 11:31
@jpower432
jpower432 self-requested a review September 18, 2026 13:08
@jpower432

Copy link
Copy Markdown
Contributor

@gxmiranda Just getting back to this. The blocking PR merged and the gold OpenAPI file was added as testdata that this change would need to handle. This is what I will be taking a look at in my feedback:

https://github.com/gemaraproj/gemara/blob/main/cmd/internal/cmd/testdata/openapi.golden.yaml

@jpower432 jpower432 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for submitting this! Mostly nits, but left one blocking comment on the spec files. I was able to testing locally and confirm that the schema pages are created properly.

I did notice one issue around the docs generation with the new projection.
The golden-input coverage for CUE-only projection notes (Enforced by the CUE schema; not by this OpenAPI projection.) are emitted verbatim in generated reference pages. Not blocking this PR particularly, but would be great if we could strip these.

Comment thread tools/internal/cmd/openapi2md.go
Comment thread tools/internal/cmd/openapi2md.go
Signed-off-by: Gustavo Miranda <48178298+gxmiranda@users.noreply.github.com>
Signed-off-by: Gustavo Miranda <48178298+gxmiranda@users.noreply.github.com>
Signed-off-by: Gustavo Miranda <48178298+gxmiranda@users.noreply.github.com>
Signed-off-by: Gustavo Miranda <48178298+gxmiranda@users.noreply.github.com>
@gxmiranda

Copy link
Copy Markdown
Contributor Author

The CUE projection note feedback was addressed in f534bbe (fix: strip CUE projection notes from docs). The new helper removes the internal annotation from schema and field descriptions while preserving the remaining user-facing text, with fixture and regression coverage.

@gxmiranda
gxmiranda requested a review from jpower432 September 23, 2026 09:27

@jpower432 jpower432 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making those changes @gxmiranda! Just found one more small issue and then I think this work is good to go.

Comment thread tools/internal/cmd/openapi2md.go
Signed-off-by: Gustavo Miranda <48178298+gxmiranda@users.noreply.github.com>
@gxmiranda
gxmiranda requested a review from jpower432 September 24, 2026 08:35

@jpower432 jpower432 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks @gxmiranda

@jpower432 jpower432 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies @gxmiranda. Found a bug looking the at generated pages one last time.

I noticed that for items that are inheriting from collection, the inherited array fields preserve the link to the correct object, but the normal inherited fields (Metadata, Target) lose specificity (i.e., object).

🤖

resolveSchemaComposition() expands an allOf $ref such as EntryMapping into its object schema, then mergeSchemas() discards the original $ref. By the time formatFieldType() runs, it sees only type: object, so it emits object.

Only the original reference for array items are preserved in formatFieldType():

firstPart, _ := parseSchema(itemsSchema.AllOf[0])
resolvedItems, _ := resolveSchemaComposition(...)
if firstPart.Ref != "" {
    resolvedItems.Ref = firstPart.Ref
}

That preservation is missing for normal fields such as AssessmentFinding.log, which has:

allOf:
  - $ref: "#/components/schemas/EntryMapping"
description: ...

Signed-off-by: Gustavo Miranda <48178298+gxmiranda@users.noreply.github.com>
@gxmiranda

Copy link
Copy Markdown
Contributor Author

Fixed in 49625b6 (fix: preserve allOf ref for non-array property type display). The property-level composition in generateRootSection now preserves the first allOf $ref on the resolved schema, matching the pattern already used for array items. Fields like AssessmentFinding.log now render as [EntryMapping](...) instead of bare object. Added a PropRefAllOf fixture and regression test asserting the linked type name and description are preserved.

@gxmiranda
gxmiranda requested a review from jpower432 September 25, 2026 10:20

@jpower432 jpower432 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jpower432
jpower432 merged commit 2d869d5 into gemaraproj:main Sep 30, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generated schema pages do not show inherited fields from embedded structs

2 participants