From e64b09282008812787b11a23f0f46d3bc8f7fa1c Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Fri, 19 Dec 2025 12:30:04 +0100 Subject: [PATCH 01/54] doc: announced new discord channel Signed-off-by: Frederic BIDON --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a877d28..13a2a17e 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,22 @@ [![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url] -[![GoDoc][godoc-badge]][godoc-url] [![Slack Channel][slack-logo]![slack-badge]][slack-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] +[![GoDoc][godoc-badge]][godoc-url] [![Discord Channel][discord-badge]][discord-url] [![go version][goversion-badge]][goversion-url] ![Top language][top-badge] ![Commits since latest release][commits-badge] --- The object model for OpenAPI v2 specification documents. +## Announcements + +* **2025-12-19** : new community chat on discord + * a new discord community channel is available to be notified of changes and support users + * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31** + +You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url] + +Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url] + ## Status API is stable. @@ -125,6 +135,9 @@ Maintainers can cut a new release by either: [slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png [slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM [slack-url]: https://goswagger.slack.com/archives/C04R30YMU +[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue +[discord-url]: https://discord.gg/DrafRmZx + [license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg [license-url]: https://github.com/go-openapi/spec/?tab=Apache-2.0-1-ov-file#readme From 90efd457a82293e78f860bda1c72f5488315d4e9 Mon Sep 17 00:00:00 2001 From: "bot-go-openapi[bot]" <246880138+bot-go-openapi[bot]@users.noreply.github.com> Date: Sat, 20 Dec 2025 04:42:04 +0000 Subject: [PATCH 02/54] doc: updated contributors file Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CONTRIBUTORS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 47d6a56d..d97b9d33 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 38 | 388 | +| 38 | 391 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 191 | https://github.com/go-openapi/spec/commits?author=casualjim | -| @fredbi | 86 | https://github.com/go-openapi/spec/commits?author=fredbi | +| @fredbi | 89 | https://github.com/go-openapi/spec/commits?author=fredbi | | @pytlesk4 | 26 | https://github.com/go-openapi/spec/commits?author=pytlesk4 | | @kul-amr | 10 | https://github.com/go-openapi/spec/commits?author=kul-amr | | @keramix | 10 | https://github.com/go-openapi/spec/commits?author=keramix | From 3b2ff60674feba6b4c7c62628f6860999b185409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20BIDON?= Date: Wed, 24 Dec 2025 16:52:47 +0100 Subject: [PATCH 03/54] fix: fixed key escaping in OrderedItems marshaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixes #216 Signed-off-by: Frédéric BIDON --- properties.go | 45 +++++++++++++++++++++++++++++++++------------ properties_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/properties.go b/properties.go index 4142308d..c4988180 100644 --- a/properties.go +++ b/properties.go @@ -25,21 +25,26 @@ type OrderSchemaItems []OrderSchemaItem // of the OrderSchemaItems slice, keeping the original order of the slice. func (items OrderSchemaItems) MarshalJSON() ([]byte, error) { buf := bytes.NewBuffer(nil) - buf.WriteString("{") - for i := range items { - if i > 0 { - buf.WriteString(",") - } - buf.WriteString("\"") - buf.WriteString(items[i].Name) - buf.WriteString("\":") - bs, err := json.Marshal(&items[i].Schema) - if err != nil { + buf.WriteByte('{') + + if len(items) == 0 { + buf.WriteByte('}') + + return buf.Bytes(), nil + } + + if err := items.marshalJSONItem(items[0], buf); err != nil { + return nil, err + } + + for _, item := range items[1:] { + buf.WriteByte(',') + if err := items.marshalJSONItem(item, buf); err != nil { return nil, err } - buf.Write(bs) } - buf.WriteString("}") + buf.WriteByte('}') + return buf.Bytes(), nil } @@ -69,6 +74,22 @@ func (items OrderSchemaItems) Less(i, j int) (ret bool) { return items[i].Name < items[j].Name } +func (items OrderSchemaItems) marshalJSONItem(item OrderSchemaItem, output *bytes.Buffer) error { + nameJSON, err := json.Marshal(item.Name) + if err != nil { + return err + } + output.Write(nameJSON) + output.WriteByte(':') + schemaJSON, err := json.Marshal(&item.Schema) + if err != nil { + return err + } + output.Write(schemaJSON) + + return nil +} + // SchemaProperties is a map representing the properties of a Schema object. // It knows how to transform its keys into an ordered slice. type SchemaProperties map[string]Schema diff --git a/properties_test.go b/properties_test.go index 2874a0de..8475dfe2 100644 --- a/properties_test.go +++ b/properties_test.go @@ -5,6 +5,8 @@ package spec import ( "testing" + + "github.com/go-openapi/testify/v2/require" ) func TestPropertySerialization(t *testing.T) { @@ -45,3 +47,25 @@ func TestPropertySerialization(t *testing.T) { } } + +func TestOrderedSchemaItem_Issue216(t *testing.T) { + stringSchema := new(Schema).Typed("string", "") + items := OrderSchemaItems{ + { + Name: "emails\n", // Key contains newline character + Schema: *stringSchema, + }, + { + Name: "regular", + Schema: *stringSchema, + }, + } + + jazon, err := items.MarshalJSON() + require.NoError(t, err) + + require.JSONEqBytes(t, + []byte(`{"emails\n":{"type":"string"},"regular":{"type":"string"}}`), + jazon, + ) +} From 5fc39a0db5dfd51bc3ed88cde72e7caed93a17f4 Mon Sep 17 00:00:00 2001 From: "bot-go-openapi[bot]" <246880138+bot-go-openapi[bot]@users.noreply.github.com> Date: Sat, 27 Dec 2025 04:46:15 +0000 Subject: [PATCH 04/54] doc: updated contributors file Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CONTRIBUTORS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index d97b9d33..26b16576 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 38 | 391 | +| 38 | 392 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 191 | https://github.com/go-openapi/spec/commits?author=casualjim | -| @fredbi | 89 | https://github.com/go-openapi/spec/commits?author=fredbi | +| @fredbi | 90 | https://github.com/go-openapi/spec/commits?author=fredbi | | @pytlesk4 | 26 | https://github.com/go-openapi/spec/commits?author=pytlesk4 | | @kul-amr | 10 | https://github.com/go-openapi/spec/commits?author=kul-amr | | @keramix | 10 | https://github.com/go-openapi/spec/commits?author=keramix | From 22037ac9dc317bc67dbb968baf0f67c7700b6189 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 09:22:53 +0000 Subject: [PATCH 05/54] build(deps): bump the development-dependencies group with 7 updates Bumps the development-dependencies group with 7 updates: | Package | From | To | | --- | --- | --- | | [go-openapi/ci-workflows/.github/workflows/auto-merge.yml](https://github.com/go-openapi/ci-workflows) | `0.1.2` | `0.2.3` | | [go-openapi/ci-workflows/.github/workflows/bump-release.yml](https://github.com/go-openapi/ci-workflows) | `0.1.2` | `0.2.3` | | [go-openapi/ci-workflows/.github/workflows/codeql.yml](https://github.com/go-openapi/ci-workflows) | `0.1.2` | `0.2.3` | | [go-openapi/ci-workflows/.github/workflows/contributors.yml](https://github.com/go-openapi/ci-workflows) | `0.1.2` | `0.2.3` | | [go-openapi/ci-workflows/.github/workflows/go-test.yml](https://github.com/go-openapi/ci-workflows) | `0.1.2` | `0.2.3` | | [go-openapi/ci-workflows/.github/workflows/scanner.yml](https://github.com/go-openapi/ci-workflows) | `0.1.2` | `0.2.3` | | [go-openapi/ci-workflows/.github/workflows/release.yml](https://github.com/go-openapi/ci-workflows) | `0.1.2` | `0.2.3` | Updates `go-openapi/ci-workflows/.github/workflows/auto-merge.yml` from 0.1.2 to 0.2.3 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/9e70984764198f45640ca9f0752a51a8ca159b99...19440f9c916774587dd68f6bec31f42fdada9d77) Updates `go-openapi/ci-workflows/.github/workflows/bump-release.yml` from 0.1.2 to 0.2.3 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/9e70984764198f45640ca9f0752a51a8ca159b99...19440f9c916774587dd68f6bec31f42fdada9d77) Updates `go-openapi/ci-workflows/.github/workflows/codeql.yml` from 0.1.2 to 0.2.3 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/9e70984764198f45640ca9f0752a51a8ca159b99...19440f9c916774587dd68f6bec31f42fdada9d77) Updates `go-openapi/ci-workflows/.github/workflows/contributors.yml` from 0.1.2 to 0.2.3 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/9e70984764198f45640ca9f0752a51a8ca159b99...19440f9c916774587dd68f6bec31f42fdada9d77) Updates `go-openapi/ci-workflows/.github/workflows/go-test.yml` from 0.1.2 to 0.2.3 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/9e70984764198f45640ca9f0752a51a8ca159b99...19440f9c916774587dd68f6bec31f42fdada9d77) Updates `go-openapi/ci-workflows/.github/workflows/scanner.yml` from 0.1.2 to 0.2.3 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/9e70984764198f45640ca9f0752a51a8ca159b99...19440f9c916774587dd68f6bec31f42fdada9d77) Updates `go-openapi/ci-workflows/.github/workflows/release.yml` from 0.1.2 to 0.2.3 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/9e70984764198f45640ca9f0752a51a8ca159b99...19440f9c916774587dd68f6bec31f42fdada9d77) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/auto-merge.yml dependency-version: 0.2.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/bump-release.yml dependency-version: 0.2.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/codeql.yml dependency-version: 0.2.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/contributors.yml dependency-version: 0.2.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/go-test.yml dependency-version: 0.2.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/scanner.yml dependency-version: 0.2.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/release.yml dependency-version: 0.2.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 3d5f6811..721ce625 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@9e70984764198f45640ca9f0752a51a8ca159b99 # v0.1.2 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index 7f5dfa79..6be13435 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -36,7 +36,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@9e70984764198f45640ca9f0752a51a8ca159b99 # v0.1.2 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 with: bump-patch: ${{ inputs.bump-patch }} bump-minor: ${{ inputs.bump-minor }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ba0aab9c..c148fcec 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@9e70984764198f45640ca9f0752a51a8ca159b99 # v0.1.2 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 375d6512..cd14a0c0 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@9e70984764198f45640ca9f0752a51a8ca159b99 # v0.1.2 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index f433ddeb..a62eaa05 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@9e70984764198f45640ca9f0752a51a8ca159b99 # v0.1.2 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index 7633b500..688c4ca1 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@9e70984764198f45640ca9f0752a51a8ca159b99 # V0.1.2 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # V0.2.3 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 4ef8bdf0..cd2ac933 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@9e70984764198f45640ca9f0752a51a8ca159b99 # v0.1.2 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 with: tag: ${{ github.ref_name }} secrets: inherit From 02c28f2fa3944826acac12e77361865d03497c4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 09:16:09 +0000 Subject: [PATCH 06/54] build(deps): bump github.com/go-openapi/testify/v2 Bumps the go-openapi-dependencies group with 1 update: [github.com/go-openapi/testify/v2](https://github.com/go-openapi/testify). Updates `github.com/go-openapi/testify/v2` from 2.0.2 to 2.1.8 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.0.2...v2.1.8) --- updated-dependencies: - dependency-name: github.com/go-openapi/testify/v2 dependency-version: 2.1.8 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d64d4eca..77aa9287 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-openapi/swag/jsonutils v0.25.4 github.com/go-openapi/swag/loading v0.25.4 github.com/go-openapi/swag/stringutils v0.25.4 - github.com/go-openapi/testify/v2 v2.0.2 + github.com/go-openapi/testify/v2 v2.1.8 go.yaml.in/yaml/v3 v3.0.4 ) diff --git a/go.sum b/go.sum index bcc47456..9e7dde5b 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtP github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= -github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= -github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/testify/v2 v2.1.8 h1:Ctu3hazcJy+DzbCPKjA5S5JW86UFY9PZ2LAfuMp3Ru8= +github.com/go-openapi/testify/v2 v2.1.8/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From d181245f63f6fd800ca4e6bd1ecb4b1262dafd9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 09:16:33 +0000 Subject: [PATCH 07/54] build(deps): bump the development-dependencies group with 7 updates Bumps the development-dependencies group with 7 updates: | Package | From | To | | --- | --- | --- | | [go-openapi/ci-workflows/.github/workflows/auto-merge.yml](https://github.com/go-openapi/ci-workflows) | `0.2.3` | `0.2.5` | | [go-openapi/ci-workflows/.github/workflows/bump-release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.3` | `0.2.5` | | [go-openapi/ci-workflows/.github/workflows/codeql.yml](https://github.com/go-openapi/ci-workflows) | `0.2.3` | `0.2.5` | | [go-openapi/ci-workflows/.github/workflows/contributors.yml](https://github.com/go-openapi/ci-workflows) | `0.2.3` | `0.2.5` | | [go-openapi/ci-workflows/.github/workflows/go-test.yml](https://github.com/go-openapi/ci-workflows) | `0.2.3` | `0.2.5` | | [go-openapi/ci-workflows/.github/workflows/scanner.yml](https://github.com/go-openapi/ci-workflows) | `0.2.3` | `0.2.5` | | [go-openapi/ci-workflows/.github/workflows/release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.3` | `0.2.5` | Updates `go-openapi/ci-workflows/.github/workflows/auto-merge.yml` from 0.2.3 to 0.2.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/19440f9c916774587dd68f6bec31f42fdada9d77...ea0dfc9a8f78335f47355d842b76bcf95d29c846) Updates `go-openapi/ci-workflows/.github/workflows/bump-release.yml` from 0.2.3 to 0.2.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/19440f9c916774587dd68f6bec31f42fdada9d77...ea0dfc9a8f78335f47355d842b76bcf95d29c846) Updates `go-openapi/ci-workflows/.github/workflows/codeql.yml` from 0.2.3 to 0.2.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/19440f9c916774587dd68f6bec31f42fdada9d77...ea0dfc9a8f78335f47355d842b76bcf95d29c846) Updates `go-openapi/ci-workflows/.github/workflows/contributors.yml` from 0.2.3 to 0.2.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/19440f9c916774587dd68f6bec31f42fdada9d77...ea0dfc9a8f78335f47355d842b76bcf95d29c846) Updates `go-openapi/ci-workflows/.github/workflows/go-test.yml` from 0.2.3 to 0.2.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/19440f9c916774587dd68f6bec31f42fdada9d77...ea0dfc9a8f78335f47355d842b76bcf95d29c846) Updates `go-openapi/ci-workflows/.github/workflows/scanner.yml` from 0.2.3 to 0.2.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/19440f9c916774587dd68f6bec31f42fdada9d77...ea0dfc9a8f78335f47355d842b76bcf95d29c846) Updates `go-openapi/ci-workflows/.github/workflows/release.yml` from 0.2.3 to 0.2.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/19440f9c916774587dd68f6bec31f42fdada9d77...ea0dfc9a8f78335f47355d842b76bcf95d29c846) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/auto-merge.yml dependency-version: 0.2.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/bump-release.yml dependency-version: 0.2.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/codeql.yml dependency-version: 0.2.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/contributors.yml dependency-version: 0.2.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/go-test.yml dependency-version: 0.2.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/scanner.yml dependency-version: 0.2.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/release.yml dependency-version: 0.2.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 721ce625..99be9912 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index 6be13435..bafc2293 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -36,7 +36,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 with: bump-patch: ${{ inputs.bump-patch }} bump-minor: ${{ inputs.bump-minor }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index c148fcec..73da0059 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index cd14a0c0..65d6f46f 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index a62eaa05..6dbce478 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index 688c4ca1..b20ede05 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # V0.2.3 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # V0.2.5 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index cd2ac933..4441d7af 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@19440f9c916774587dd68f6bec31f42fdada9d77 # v0.2.3 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 with: tag: ${{ github.ref_name }} secrets: inherit From d7081599a4b8be0edb5aabd486349ef1ad414be9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 09:17:11 +0000 Subject: [PATCH 08/54] build(deps): bump github.com/go-openapi/testify/v2 Bumps the go-openapi-dependencies group with 1 update: [github.com/go-openapi/testify/v2](https://github.com/go-openapi/testify). Updates `github.com/go-openapi/testify/v2` from 2.1.8 to 2.2.0 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.1.8...v2.2.0) --- updated-dependencies: - dependency-name: github.com/go-openapi/testify/v2 dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 77aa9287..6e6c0630 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-openapi/swag/jsonutils v0.25.4 github.com/go-openapi/swag/loading v0.25.4 github.com/go-openapi/swag/stringutils v0.25.4 - github.com/go-openapi/testify/v2 v2.1.8 + github.com/go-openapi/testify/v2 v2.2.0 go.yaml.in/yaml/v3 v3.0.4 ) diff --git a/go.sum b/go.sum index 9e7dde5b..f790304c 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtP github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= -github.com/go-openapi/testify/v2 v2.1.8 h1:Ctu3hazcJy+DzbCPKjA5S5JW86UFY9PZ2LAfuMp3Ru8= -github.com/go-openapi/testify/v2 v2.1.8/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/testify/v2 v2.2.0 h1:84LnzAhv4STcZTy3b6a1xs4rnzpS5HUvl24KzKqaYJo= +github.com/go-openapi/testify/v2 v2.2.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From 71eebab0e635b0951063dc9a170ee7968881bc59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 09:16:54 +0000 Subject: [PATCH 09/54] build(deps): bump github.com/go-openapi/testify/v2 Bumps the go-openapi-dependencies group with 1 update: [github.com/go-openapi/testify/v2](https://github.com/go-openapi/testify). Updates `github.com/go-openapi/testify/v2` from 2.2.0 to 2.3.0 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.2.0...v2.3.0) --- updated-dependencies: - dependency-name: github.com/go-openapi/testify/v2 dependency-version: 2.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6e6c0630..1fe94426 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-openapi/swag/jsonutils v0.25.4 github.com/go-openapi/swag/loading v0.25.4 github.com/go-openapi/swag/stringutils v0.25.4 - github.com/go-openapi/testify/v2 v2.2.0 + github.com/go-openapi/testify/v2 v2.3.0 go.yaml.in/yaml/v3 v3.0.4 ) diff --git a/go.sum b/go.sum index f790304c..4088a948 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtP github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= -github.com/go-openapi/testify/v2 v2.2.0 h1:84LnzAhv4STcZTy3b6a1xs4rnzpS5HUvl24KzKqaYJo= -github.com/go-openapi/testify/v2 v2.2.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/testify/v2 v2.3.0 h1:cZFOKhatfyVejoFNd8jqnHFosegN5vJZiPOTnkyT9hA= +github.com/go-openapi/testify/v2 v2.3.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From 7ca5d97aab7d1f2354c725e7fab54ecf8866f20b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 09:18:40 +0000 Subject: [PATCH 10/54] build(deps): bump the development-dependencies group with 7 updates Bumps the development-dependencies group with 7 updates: | Package | From | To | | --- | --- | --- | | [go-openapi/ci-workflows/.github/workflows/auto-merge.yml](https://github.com/go-openapi/ci-workflows) | `0.2.5` | `0.2.9` | | [go-openapi/ci-workflows/.github/workflows/bump-release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.5` | `0.2.9` | | [go-openapi/ci-workflows/.github/workflows/codeql.yml](https://github.com/go-openapi/ci-workflows) | `0.2.5` | `0.2.9` | | [go-openapi/ci-workflows/.github/workflows/contributors.yml](https://github.com/go-openapi/ci-workflows) | `0.2.5` | `0.2.9` | | [go-openapi/ci-workflows/.github/workflows/go-test.yml](https://github.com/go-openapi/ci-workflows) | `0.2.5` | `0.2.9` | | [go-openapi/ci-workflows/.github/workflows/scanner.yml](https://github.com/go-openapi/ci-workflows) | `0.2.5` | `0.2.9` | | [go-openapi/ci-workflows/.github/workflows/release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.5` | `0.2.9` | Updates `go-openapi/ci-workflows/.github/workflows/auto-merge.yml` from 0.2.5 to 0.2.9 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/ea0dfc9a8f78335f47355d842b76bcf95d29c846...84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff) Updates `go-openapi/ci-workflows/.github/workflows/bump-release.yml` from 0.2.5 to 0.2.9 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/ea0dfc9a8f78335f47355d842b76bcf95d29c846...84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff) Updates `go-openapi/ci-workflows/.github/workflows/codeql.yml` from 0.2.5 to 0.2.9 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/ea0dfc9a8f78335f47355d842b76bcf95d29c846...84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff) Updates `go-openapi/ci-workflows/.github/workflows/contributors.yml` from 0.2.5 to 0.2.9 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/ea0dfc9a8f78335f47355d842b76bcf95d29c846...84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff) Updates `go-openapi/ci-workflows/.github/workflows/go-test.yml` from 0.2.5 to 0.2.9 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/ea0dfc9a8f78335f47355d842b76bcf95d29c846...84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff) Updates `go-openapi/ci-workflows/.github/workflows/scanner.yml` from 0.2.5 to 0.2.9 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/ea0dfc9a8f78335f47355d842b76bcf95d29c846...84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff) Updates `go-openapi/ci-workflows/.github/workflows/release.yml` from 0.2.5 to 0.2.9 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/ea0dfc9a8f78335f47355d842b76bcf95d29c846...84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/auto-merge.yml dependency-version: 0.2.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/bump-release.yml dependency-version: 0.2.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/codeql.yml dependency-version: 0.2.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/contributors.yml dependency-version: 0.2.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/go-test.yml dependency-version: 0.2.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/scanner.yml dependency-version: 0.2.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/release.yml dependency-version: 0.2.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 99be9912..9b81e3a9 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index bafc2293..8d209a6d 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -36,7 +36,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 with: bump-patch: ${{ inputs.bump-patch }} bump-minor: ${{ inputs.bump-minor }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 73da0059..e503cb0a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 65d6f46f..c7fcf5b6 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 6dbce478..e1ba8d81 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index b20ede05..ed357e23 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # V0.2.5 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # V0.2.9 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 4441d7af..3c430127 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@ea0dfc9a8f78335f47355d842b76bcf95d29c846 # v0.2.5 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 with: tag: ${{ github.ref_name }} secrets: inherit From 0c2d5d470d5dca91f7d4ead24cdd0de5bb12d20f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 09:16:29 +0000 Subject: [PATCH 11/54] build(deps): bump github.com/go-openapi/testify/v2 Bumps the go-openapi-dependencies group with 1 update: [github.com/go-openapi/testify/v2](https://github.com/go-openapi/testify). Updates `github.com/go-openapi/testify/v2` from 2.3.0 to 2.4.0 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.3.0...v2.4.0) --- updated-dependencies: - dependency-name: github.com/go-openapi/testify/v2 dependency-version: 2.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1fe94426..d92cc780 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/go-openapi/swag/jsonutils v0.25.4 github.com/go-openapi/swag/loading v0.25.4 github.com/go-openapi/swag/stringutils v0.25.4 - github.com/go-openapi/testify/v2 v2.3.0 + github.com/go-openapi/testify/v2 v2.4.0 go.yaml.in/yaml/v3 v3.0.4 ) diff --git a/go.sum b/go.sum index 4088a948..f9e18b33 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtP github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= -github.com/go-openapi/testify/v2 v2.3.0 h1:cZFOKhatfyVejoFNd8jqnHFosegN5vJZiPOTnkyT9hA= -github.com/go-openapi/testify/v2 v2.3.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= +github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From d6177ef6dbe2c9f47a1e0c362403848dea6027b7 Mon Sep 17 00:00:00 2001 From: fredbi Date: Tue, 3 Mar 2026 01:30:19 +0100 Subject: [PATCH 12/54] chore: doc, tests, lint (#255) * documentation update to meet go-openapi standards * fixed discord link * relinted godoc and markdown * relinted the codebase (many nolint directives are set, the design can't be changed easily) * simplified test assertions for JSON & YAML (replaced ad'hoc helpers by testify/v2 features) * test: worked around windows-specific data race issue in tests (used embed fs to avoid windows FS issues) Signed-off-by: Frederic BIDON --- .cliff.toml | 181 ----------------------------- .github/CONTRIBUTING.md | 119 ++++++++++++------- .github/DCO.md | 2 +- .github/wordlist.txt | 44 +++++++ .github/workflows/bump-release.yml | 26 ++--- .gitignore | 5 + .golangci.yml | 1 + CODE_OF_CONDUCT.md | 6 +- CONTRIBUTORS.md | 76 ++++++------ README.md | 12 +- SECURITY.md | 28 ++++- auth_test.go | 121 +++++++++---------- cache.go | 18 +-- cache_test.go | 8 +- circular_test.go | 13 +-- contact_info.go | 6 +- contact_info_test.go | 14 +-- debug.go | 10 +- debug_test.go | 8 +- docs/MAINTAINERS.md | 123 ++++++++++++-------- docs/STYLE.md | 48 ++++++-- errors.go | 12 +- expander.go | 11 +- expander_test.go | 62 +++++----- external_docs_test.go | 13 ++- go.mod | 21 ++-- go.sum | 44 +++---- header.go | 42 +++---- header_test.go | 32 +++-- helpers_spec_test.go | 10 +- helpers_test.go | 26 ++++- info.go | 26 ++--- info_test.go | 19 ++- items.go | 44 +++---- items_test.go | 31 +++-- license.go | 6 +- license_test.go | 16 +-- normalizer.go | 2 +- normalizer_test.go | 18 +-- operation.go | 42 +++---- operation_test.go | 59 ++++------ parameter.go | 84 ++++++------- parameters_test.go | 59 +++++----- path_item.go | 8 +- path_item_test.go | 10 +- paths.go | 6 +- paths_test.go | 11 +- properties.go | 6 +- properties_test.go | 8 +- ref.go | 24 ++-- ref_test.go | 4 +- resolver.go | 18 +-- resolver_test.go | 72 +++++------- response.go | 22 ++-- response_test.go | 24 ++-- responses.go | 10 +- responses_test.go | 24 ++-- schema.go | 148 +++++++++++------------ schema_loader.go | 23 ++-- schema_test.go | 49 ++++---- schemas/v2/README.md | 2 +- security_scheme.go | 22 ++-- spec.go | 13 +-- spec_test.go | 20 ++-- structs_test.go | 109 +++++------------ swagger.go | 60 +++++----- swagger_test.go | 47 ++++---- tag.go | 10 +- validations.go | 16 +-- validations_test.go | 45 ++++--- xml_object.go | 14 +-- xml_object_test.go | 14 ++- 72 files changed, 1121 insertions(+), 1266 deletions(-) delete mode 100644 .cliff.toml create mode 100644 .github/wordlist.txt diff --git a/.cliff.toml b/.cliff.toml deleted file mode 100644 index 702629f5..00000000 --- a/.cliff.toml +++ /dev/null @@ -1,181 +0,0 @@ -# git-cliff ~ configuration file -# https://git-cliff.org/docs/configuration - -[changelog] -header = """ -""" - -footer = """ - ------ - -**[{{ remote.github.repo }}]({{ self::remote_url() }}) license terms** - -[![License][license-badge]][license-url] - -[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg -[license-url]: {{ self::remote_url() }}/?tab=Apache-2.0-1-ov-file#readme - -{%- macro remote_url() -%} - https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} -{%- endmacro -%} -""" - -body = """ -{%- if version %} -## [{{ version | trim_start_matches(pat="v") }}]({{ self::remote_url() }}/tree/{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }} -{%- else %} -## [unreleased] -{%- endif %} -{%- if message %} - {%- raw %}\n{% endraw %} -{{ message }} - {%- raw %}\n{% endraw %} -{%- endif %} -{%- if version %} - {%- if previous.version %} - -**Full Changelog**: <{{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }}> - {%- endif %} -{%- else %} - {%- raw %}\n{% endraw %} -{%- endif %} - -{%- if statistics %}{% if statistics.commit_count %} - {%- raw %}\n{% endraw %} -{{ statistics.commit_count }} commits in this release. - {%- raw %}\n{% endraw %} -{%- endif %}{% endif %} ------ - -{%- for group, commits in commits | group_by(attribute="group") %} - {%- raw %}\n{% endraw %} -### {{ group | upper_first }} - {%- raw %}\n{% endraw %} - {%- for commit in commits %} - {%- if commit.remote.pr_title %} - {%- set commit_message = commit.remote.pr_title %} - {%- else %} - {%- set commit_message = commit.message %} - {%- endif %} -* {{ commit_message | split(pat="\n") | first | trim }} - {%- if commit.remote.username %} -{%- raw %} {% endraw %}by [@{{ commit.remote.username }}](https://github.com/{{ commit.remote.username }}) - {%- endif %} - {%- if commit.remote.pr_number %} -{%- raw %} {% endraw %}in [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}) - {%- endif %} -{%- raw %} {% endraw %}[...]({{ self::remote_url() }}/commit/{{ commit.id }}) - {%- endfor %} -{%- endfor %} - -{%- if github %} -{%- raw %}\n{% endraw -%} - {%- set all_contributors = github.contributors | length %} - {%- if github.contributors | filter(attribute="username", value="dependabot[bot]") | length < all_contributors %} ------ - -### People who contributed to this release - {% endif %} - {%- for contributor in github.contributors | filter(attribute="username") | sort(attribute="username") %} - {%- if contributor.username != "dependabot[bot]" and contributor.username != "github-actions[bot]" %} -* [@{{ contributor.username }}](https://github.com/{{ contributor.username }}) - {%- endif %} - {%- endfor %} - - {% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %} ------ - {%- raw %}\n{% endraw %} - -### New Contributors - {%- endif %} - - {%- for contributor in github.contributors | filter(attribute="is_first_time", value=true) %} - {%- if contributor.username != "dependabot[bot]" and contributor.username != "github-actions[bot]" %} -* @{{ contributor.username }} made their first contribution - {%- if contributor.pr_number %} - in [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ - {%- endif %} - {%- endif %} - {%- endfor %} -{%- endif %} - -{%- raw %}\n{% endraw %} - -{%- macro remote_url() -%} - https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} -{%- endmacro -%} -""" -# Remove leading and trailing whitespaces from the changelog's body. -trim = true -# Render body even when there are no releases to process. -render_always = true -# An array of regex based postprocessors to modify the changelog. -postprocessors = [ - # Replace the placeholder with a URL. - #{ pattern = '', replace = "https://github.com/orhun/git-cliff" }, -] -# output file path -# output = "test.md" - -[git] -# Parse commits according to the conventional commits specification. -# See https://www.conventionalcommits.org -conventional_commits = false -# Exclude commits that do not match the conventional commits specification. -filter_unconventional = false -# Require all commits to be conventional. -# Takes precedence over filter_unconventional. -require_conventional = false -# Split commits on newlines, treating each line as an individual commit. -split_commits = false -# An array of regex based parsers to modify commit messages prior to further processing. -commit_preprocessors = [ - # Replace issue numbers with link templates to be updated in `changelog.postprocessors`. - #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))"}, - # Check spelling of the commit message using https://github.com/crate-ci/typos. - # If the spelling is incorrect, it will be fixed automatically. - #{ pattern = '.*', replace_command = 'typos --write-changes -' } -] -# Prevent commits that are breaking from being excluded by commit parsers. -protect_breaking_commits = false -# An array of regex based parsers for extracting data from the commit message. -# Assigns commits to groups. -# Optionally sets the commit's scope and can decide to exclude commits from further processing. -commit_parsers = [ - { message = "^[Cc]hore\\([Rr]elease\\): prepare for", skip = true }, - { message = "(^[Mm]erge)|([Mm]erge conflict)", skip = true }, - { field = "author.name", pattern = "dependabot*", group = "Updates" }, - { message = "([Ss]ecurity)|([Vv]uln)", group = "Security" }, - { body = "(.*[Ss]ecurity)|([Vv]uln)", group = "Security" }, - { message = "([Cc]hore\\(lint\\))|(style)|(lint)|(codeql)|(golangci)", group = "Code quality" }, - { message = "(^[Dd]oc)|((?i)readme)|(badge)|(typo)|(documentation)", group = "Documentation" }, - { message = "(^[Ff]eat)|(^[Ee]nhancement)", group = "Implemented enhancements" }, - { message = "(^ci)|(\\(ci\\))|(fixup\\s+ci)|(fix\\s+ci)|(license)|(example)", group = "Miscellaneous tasks" }, - { message = "^test", group = "Testing" }, - { message = "(^fix)|(panic)", group = "Fixed bugs" }, - { message = "(^refact)|(rework)", group = "Refactor" }, - { message = "(^[Pp]erf)|(performance)", group = "Performance" }, - { message = "(^[Cc]hore)", group = "Miscellaneous tasks" }, - { message = "^[Rr]evert", group = "Reverted changes" }, - { message = "(upgrade.*?go)|(go\\s+version)", group = "Updates" }, - { message = ".*", group = "Other" }, -] -# Exclude commits that are not matched by any commit parser. -filter_commits = false -# An array of link parsers for extracting external references, and turning them into URLs, using regex. -link_parsers = [] -# Include only the tags that belong to the current branch. -use_branch_tags = false -# Order releases topologically instead of chronologically. -topo_order = false -# Order releases topologically instead of chronologically. -topo_order_commits = true -# Order of commits in each group/release within the changelog. -# Allowed values: newest, oldest -sort_commits = "newest" -# Process submodules commits -recurse_submodules = false - -#[remote.github] -#owner = "go-openapi" diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 85707f7e..069bd7e5 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,48 +1,57 @@ -## Contribution Guidelines +You'll find here general guidelines to contribute to this project. +They mostly correspond to standard practices for open source repositories. -You'll find below general guidelines, which mostly correspond to standard practices for open sourced repositories. +We have tried to keep things as simple as possible. ->**TL;DR** -> -> If you're already an experienced go developer on github, then you should just feel at home with us +> [!NOTE] +> If you're an experienced go developer on github, then you should just feel at home with us > and you may well skip the rest of this document. > -> You'll essentially find the usual guideline for a go library project on github. +> You'll essentially apply the usual guidelines for a go library project on github. + +These guidelines are common to all libraries published on github by the `go-openapi` organization, +so you'll feel at home with any of our projects. -These guidelines are general to all libraries published on github by the `go-openapi` organization. +You'll find more detailed (or repo-specific) instructions in the [maintainer's docs][maintainers-doc]. -You'll find more detailed (or repo-specific) instructions in the [maintainer's docs](../docs). +[maintainers-doc]: ../docs/MAINTAINERS.md -## How can I contribute? +## How can I contribute -There are many ways in which you can contribute. Here are a few ideas: +There are many ways in which you can contribute, not just code. Here are a few ideas: - * Reporting Issues / Bugs - * Suggesting Improvements - * Code - * bug fixes and new features that are within the main project scope - * improving test coverage - * addressing code quality issues - * Documentation - * Art work that makes the project look great +- Reporting issues or bugs +- Suggesting improvements +- Documentation +- Art work that makes the project look great +- Code + - proposing bug fixes and new features that are within the main project scope + - improving test coverage + - addressing code quality issues ## Questions & issues -### Asking questions +### Asking a question + +You may inquire anything about this library by reporting a "Question" issue on github. -You may inquire about anything about this library by reporting a "Question" issue on github. +You may also join our discord server where you may discuss issues or requests. + +[![Discord Server][discord-badge]][discord-url] + +[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue +[discord-url]: https://discord.gg/twZ9BwT3 ### Reporting issues Reporting a problem with our libraries _is_ a valuable contribution. - You can do this on the github issues page of this repository. Please be as specific as possible when describing your issue. Whenever relevant, please provide information about your environment (go version, OS). -Adding a code snippet to reproduce the issue is great, and as a big time saver for maintainers. +Adding a code snippet to reproduce the issue is great, and a big time saver for maintainers. ### Triaging issues @@ -62,14 +71,16 @@ process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it. If your pull request is not accepted on the first try, don't be discouraged! -If there's a problem with the implementation, hopefully you received feedback on what to improve. +If there's a problem with the implementation, hopefully you've received feedback on what to improve. If you have a lot of ideas or a lot of issues to solve, try to refrain a bit and post focused pull requests. -Think that they must be reviewed by a maintainer and it is easy to lost track of things on big PRs. +Think that they must be reviewed by a maintainer and it is easy to lose track of things on big PRs. We're trying very hard to keep the go-openapi packages lean and focused. -These packages constitute a toolkit: it won't do everything for everybody out of the box, + +Together, these packages constitute a toolkit for go developers: +it won't do everything for everybody out of the box, but everybody can use it to do just about everything related to OpenAPI. This means that we might decide against incorporating a new feature. @@ -80,9 +91,11 @@ However, there might be a way to implement that feature *on top of* our librarie You just need a `go` compiler to be installed. No special tools are needed to work with our libraries. -The go compiler version required is always the old stable (latest minor go version - 1). +The minimal go compiler version required is always the old stable (latest minor go version - 1). + +Our libraries are designed and tested to work on `Linux`, `MacOS` and `Windows`. -If you're already used to work with `go` you should already have everything in place. +If you're used to work with `go` you should already have everything in place. Although not required, you'll be certainly more productive with a local installation of `golangci-lint`, the meta-linter our CI uses. @@ -104,12 +117,12 @@ github will propose to open a pull request on the original repository. Typically you'd follow some common naming conventions: -- if it's a bugfix branch, name it `fix/XXX-something`where XXX is the number of the +- if it's a bug fixing branch, name it `fix/XXX-something` where XXX is the number of the issue on github - if it's a feature branch, create an enhancement issue to announce your intentions, and name it `feature/XXX-something` where XXX is the number of the issue. -> NOTE: we don't enforce naming conventions on branches: it's your fork after all. +NOTE: we don't enforce naming conventions on branches: it's your fork after all. #### Tests @@ -121,10 +134,10 @@ Take a look at existing tests for inspiration, and run the full test suite on yo before submitting a pull request. Our CI measures test coverage and the test coverage of every patch. + Although not a blocking step - because there are so many special cases - this is an indicator that maintainers consider when approving a PR. - -Please try your best to cover about 80% of your patch. +Please try your best to cover at least 80% of your patch. #### Code style @@ -132,13 +145,13 @@ You may read our stance on code style [there](../docs/STYLE.md). #### Documentation -Don't forget to update the documentation when creating or modifying features. +Don't forget to update the documentation when creating or modifying a feature. Most documentation for this library is directly found in code as comments for godoc. -The documentation for the go-openapi packages is published on the public go docs site: +The documentation for this go-openapi package is published on [the public go docs site][go-doc]. - +--- Check your documentation changes for clarity, concision, and correctness. @@ -150,11 +163,14 @@ go install golang.org/x/pkgsite/cmd/pkgsite@latest ``` Then run on the repository folder: + ```sh pkgsite . ``` -This wil run a godoc server locally where you may see the documentation generated from your local repository. +This will run a godoc server locally where you may see the documentation generated from your local repository. + +[go-doc]: https://pkg.go.dev/github.com/go-openapi/spec #### Commit messages @@ -164,7 +180,7 @@ reference to all the issues that they address. Pull requests must not contain commits from other users or branches. Commit messages are not required to follow the "conventional commit" rule, but it's certainly a good -thing to follow this guidelinea (e.g. "fix: blah blah", "ci: did this", "feat: did that" ...). +thing to follow that convention (e.g. "fix: fixed panic in XYZ", "ci: did this", "feat: did that" ...). The title in your commit message is used directly to produce our release notes: try to keep them neat. @@ -186,7 +202,7 @@ Be sure to post a comment after pushing. The new commits will show up in the pul request automatically, but the reviewers will not be notified unless you comment. Before the pull request is merged, -**make sure that you squash your commits into logical units of work** +**make sure that you've squashed your commits into logical units of work** using `git rebase -i` and `git push -f`. After every commit the test suite should be passing. @@ -195,6 +211,8 @@ Include documentation changes in the same commit so that a revert would remove a #### Sign your work +Software is developed by real people. + The sign-off is a simple line at the end of your commit message, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch. @@ -204,11 +222,30 @@ PGP-signed commit are greatly appreciated but not required. The rules are pretty simple: -* read our [DCO](./DCO.md) (from [developercertificate.org](http://developercertificate.org/)) -* if you agree with these terms, then you just add a line to every git commit message +- read our [DCO][dco-doc] (from [developercertificate.org][dco-source]) +- if you agree with these terms, then you just add a line to every git commit message - Signed-off-by: Joe Smith +``` +Signed-off-by: Joe Smith +``` using your real name (sorry, no pseudonyms or anonymous contributions.) -You can add the sign off when creating the git commit via `git commit -s`. +You can add the sign-off when creating the git commit via `git commit -s`. + +[dco-doc]: ./DCO.md +[dco-source]: https://developercertificate.org + +## Code contributions by AI agents + +Our agentic friends are welcome to contribute! + +We only have a few demands to keep-up with human maintainers. + +1. Issues and PRs written or posted by agents should always mention the original (human) poster for reference +2. We don't accept PRs attributed to agents. We don't want commits signed like "author: @claude.code". + Agents or bots may coauthor commits, though. +3. Security vulnerability reports by agents should always be reported privately and mention the original (human) poster + (see also [Security Policy][security-doc]). + +[security-doc]: ../SECURITY.md diff --git a/.github/DCO.md b/.github/DCO.md index e168dc4c..78a2d64f 100644 --- a/.github/DCO.md +++ b/.github/DCO.md @@ -1,4 +1,4 @@ - # Developer's Certificate of Origin +# Developer's Certificate of Origin ``` Developer Certificate of Origin diff --git a/.github/wordlist.txt b/.github/wordlist.txt new file mode 100644 index 00000000..6dc83168 --- /dev/null +++ b/.github/wordlist.txt @@ -0,0 +1,44 @@ +CodeFactor +CodeQL +DCO +GoDoc +JSON +Maintainer's +PR's +PRs +Repo +SPDX +TODOs +Triaging +UI +XYZ +YAML +agentic +ci +codebase +codecov +config +dependabot +dev +developercertificate +fka +github +godoc +golang +golangci +jsonpointer +jsonschema +linter's +linters +maintainer's +md +metalinter +monorepo +openapi +prepended +repos +semver +sexualized +unmarshal +unmarshaling +vuln diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index 8d209a6d..0cf81156 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -6,21 +6,15 @@ permissions: on: workflow_dispatch: inputs: - bump-patch: - description: Bump a patch version release - type: boolean + bump-type: + description: Type of bump (patch, minor, major) + type: choice + options: + - patch + - minor + - major + default: patch required: false - default: true - bump-minor: - description: Bump a minor version release - type: boolean - required: false - default: false - bump-major: - description: Bump a major version release - type: boolean - required: false - default: false tag-message-title: description: Tag message title to prepend to the release notes required: false @@ -38,9 +32,7 @@ jobs: contents: write uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 with: - bump-patch: ${{ inputs.bump-patch }} - bump-minor: ${{ inputs.bump-minor }} - bump-major: ${{ inputs.bump-major }} + bump-type: ${{ inputs.bump-type }} tag-message-title: ${{ inputs.tag-message-title }} tag-message-body: ${{ inputs.tag-message-body }} secrets: inherit diff --git a/.gitignore b/.gitignore index f47cb204..885dc27a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,6 @@ *.out +*.cov +.idea +.env +.mcp.json +.claude/ diff --git a/.golangci.yml b/.golangci.yml index fdae591b..dc7c9605 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -12,6 +12,7 @@ linters: - paralleltest - recvcheck - testpackage + - thelper - tparallel - varnamelen - whitespace diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 9322b065..bac878f2 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -23,7 +23,9 @@ include: Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or + advances + * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic @@ -55,7 +57,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at ivan+abuse@flanders.co.nz. All +reported by contacting the project team at . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. @@ -68,7 +70,7 @@ members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] +available at [][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 26b16576..2967e3ce 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -8,43 +8,43 @@ | Username | All Time Contribution Count | All Commits | | --- | --- | --- | -| @casualjim | 191 | https://github.com/go-openapi/spec/commits?author=casualjim | -| @fredbi | 90 | https://github.com/go-openapi/spec/commits?author=fredbi | -| @pytlesk4 | 26 | https://github.com/go-openapi/spec/commits?author=pytlesk4 | -| @kul-amr | 10 | https://github.com/go-openapi/spec/commits?author=kul-amr | -| @keramix | 10 | https://github.com/go-openapi/spec/commits?author=keramix | -| @youyuanwu | 8 | https://github.com/go-openapi/spec/commits?author=youyuanwu | -| @pengsrc | 7 | https://github.com/go-openapi/spec/commits?author=pengsrc | -| @alphacentory | 5 | https://github.com/go-openapi/spec/commits?author=alphacentory | -| @mtfelian | 4 | https://github.com/go-openapi/spec/commits?author=mtfelian | -| @Capstan | 4 | https://github.com/go-openapi/spec/commits?author=Capstan | -| @sdghchj | 4 | https://github.com/go-openapi/spec/commits?author=sdghchj | -| @databus23 | 2 | https://github.com/go-openapi/spec/commits?author=databus23 | -| @vburenin | 2 | https://github.com/go-openapi/spec/commits?author=vburenin | -| @petrkotas | 2 | https://github.com/go-openapi/spec/commits?author=petrkotas | -| @nikhita | 2 | https://github.com/go-openapi/spec/commits?author=nikhita | -| @hypnoglow | 2 | https://github.com/go-openapi/spec/commits?author=hypnoglow | -| @carvind | 2 | https://github.com/go-openapi/spec/commits?author=carvind | -| @ujjwalsh | 1 | https://github.com/go-openapi/spec/commits?author=ujjwalsh | -| @mbohlool | 1 | https://github.com/go-openapi/spec/commits?author=mbohlool | -| @j2gg0s | 1 | https://github.com/go-openapi/spec/commits?author=j2gg0s | -| @ishveda | 1 | https://github.com/go-openapi/spec/commits?author=ishveda | -| @micln | 1 | https://github.com/go-openapi/spec/commits?author=micln | -| @GlenDC | 1 | https://github.com/go-openapi/spec/commits?author=GlenDC | -| @agmikhailov | 1 | https://github.com/go-openapi/spec/commits?author=agmikhailov | -| @tgraf | 1 | https://github.com/go-openapi/spec/commits?author=tgraf | -| @zhsj | 1 | https://github.com/go-openapi/spec/commits?author=zhsj | -| @sebastien-rosset | 1 | https://github.com/go-openapi/spec/commits?author=sebastien-rosset | -| @alexandear | 1 | https://github.com/go-openapi/spec/commits?author=alexandear | -| @morlay | 1 | https://github.com/go-openapi/spec/commits?author=morlay | -| @mikedanese | 1 | https://github.com/go-openapi/spec/commits?author=mikedanese | -| @koron | 1 | https://github.com/go-openapi/spec/commits?author=koron | -| @honza | 1 | https://github.com/go-openapi/spec/commits?author=honza | -| @gbjk | 1 | https://github.com/go-openapi/spec/commits?author=gbjk | -| @faguirre1 | 1 | https://github.com/go-openapi/spec/commits?author=faguirre1 | -| @ethantkoenig | 1 | https://github.com/go-openapi/spec/commits?author=ethantkoenig | -| @sttts | 1 | https://github.com/go-openapi/spec/commits?author=sttts | -| @ChandanChainani | 1 | https://github.com/go-openapi/spec/commits?author=ChandanChainani | -| @bvwells | 1 | https://github.com/go-openapi/spec/commits?author=bvwells | +| @casualjim | 191 | | +| @fredbi | 90 | | +| @pytlesk4 | 26 | | +| @kul-amr | 10 | | +| @keramix | 10 | | +| @youyuanwu | 8 | | +| @pengsrc | 7 | | +| @alphacentory | 5 | | +| @mtfelian | 4 | | +| @Capstan | 4 | | +| @sdghchj | 4 | | +| @databus23 | 2 | | +| @vburenin | 2 | | +| @petrkotas | 2 | | +| @nikhita | 2 | | +| @hypnoglow | 2 | | +| @carvind | 2 | | +| @ujjwalsh | 1 | | +| @mbohlool | 1 | | +| @j2gg0s | 1 | | +| @ishveda | 1 | | +| @micln | 1 | | +| @GlenDC | 1 | | +| @agmikhailov | 1 | | +| @tgraf | 1 | | +| @zhsj | 1 | | +| @sebastien-rosset | 1 | | +| @alexandear | 1 | | +| @morlay | 1 | | +| @mikedanese | 1 | | +| @koron | 1 | | +| @honza | 1 | | +| @gbjk | 1 | | +| @faguirre1 | 1 | | +| @ethantkoenig | 1 | | +| @sttts | 1 | | +| @ChandanChainani | 1 | | +| @bvwells | 1 | | _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_ diff --git a/README.md b/README.md index 13a2a17e..134809fd 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ go get github.com/go-openapi/spec > There is no plan to make it evolve toward supporting OpenAPI 3.x. > This [discussion thread](https://github.com/go-openapi/spec/issues/21) relates the full story. > -> An early attempt to support Swagger 3 may be found at: https://github.com/go-openapi/spec3 +> An early attempt to support Swagger 3 may be found at: * Does the unmarshaling support YAML? @@ -64,13 +64,13 @@ go get github.com/go-openapi/spec > In order to load a YAML document as a Swagger spec, you need to use the loaders provided by > github.com/go-openapi/loads > -> Take a look at the example there: https://pkg.go.dev/github.com/go-openapi/loads#example-Spec +> Take a look at the example there: > -> See also https://github.com/go-openapi/spec/issues/164 +> See also * How can I validate a spec? -> Validation is provided by [the validate package](http://github.com/go-openapi/validate) +Validation is provided by [the validate package](http://github.com/go-openapi/validate) * Why do we have an `ID` field for `Schema` which is not part of the swagger spec? @@ -78,7 +78,7 @@ go get github.com/go-openapi/spec > how `$ref` are resolved. > This `id` does not conflict with any property named `id`. > -> See also https://github.com/go-openapi/spec/issues/23 +> See also ## Change log @@ -136,7 +136,7 @@ Maintainers can cut a new release by either: [slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM [slack-url]: https://goswagger.slack.com/archives/C04R30YMU [discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue -[discord-url]: https://discord.gg/DrafRmZx +[discord-url]: https://discord.gg/twZ9BwT3 [license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg diff --git a/SECURITY.md b/SECURITY.md index 2a7b6f09..1fea2c57 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,14 +6,32 @@ This policy outlines the commitment and practices of the go-openapi maintainers | Version | Supported | | ------- | ------------------ | -| 0.22.x | :white_check_mark: | +| O.x | :white_check_mark: | + +## Vulnerability checks in place + +This repository uses automated vulnerability scans, at every merged commit and at least once a week. + +We use: + +* [`GitHub CodeQL`][codeql-url] +* [`trivy`][trivy-url] +* [`govulncheck`][govulncheck-url] + +Reports are centralized in github security reports and visible only to the maintainers. ## Reporting a vulnerability If you become aware of a security vulnerability that affects the current repository, -please report it privately to the maintainers. +**please report it privately to the maintainers** +rather than opening a publicly visible GitHub issue. + +Please follow the instructions provided by github to [Privately report a security vulnerability][github-guidance-url]. -Please follow the instructions provided by github to -[Privately report a security vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability). +> [!NOTE] +> On Github, navigate to the project's "Security" tab then click on "Report a vulnerability". -TL;DR: on Github, navigate to the project's "Security" tab then click on "Report a vulnerability". +[codeql-url]: https://github.com/github/codeql +[trivy-url]: https://trivy.dev/docs/latest/getting-started +[govulncheck-url]: https://go.dev/blog/govulncheck +[github-guidance-url]: https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability diff --git a/auth_test.go b/auth_test.go index df719f23..486d74de 100644 --- a/auth_test.go +++ b/auth_test.go @@ -5,120 +5,103 @@ package spec import ( "testing" + + "github.com/go-openapi/testify/v2/assert" ) func TestSerialization_AuthSerialization(t *testing.T) { - assertSerializeJSON(t, BasicAuth(), `{"type":"basic"}`) + assert.JSONMarshalAsT(t, `{"type":"basic"}`, BasicAuth()) - assertSerializeJSON(t, APIKeyAuth("api-key", "header"), `{"type":"apiKey","name":"api-key","in":"header"}`) + assert.JSONMarshalAsT(t, `{"type":"apiKey","name":"api-key","in":"header"}`, APIKeyAuth("api-key", "header")) - assertSerializeJSON( - t, - OAuth2Implicit("http://foo.com/authorization"), - `{"type":"oauth2","flow":"implicit","authorizationUrl":"http://foo.com/authorization"}`) + assert.JSONMarshalAsT(t, + `{"type":"oauth2","flow":"implicit","authorizationUrl":"http://foo.com/authorization"}`, + OAuth2Implicit("http://foo.com/authorization")) - assertSerializeJSON( - t, - OAuth2Password("http://foo.com/token"), - `{"type":"oauth2","flow":"password","tokenUrl":"http://foo.com/token"}`) + assert.JSONMarshalAsT(t, + `{"type":"oauth2","flow":"password","tokenUrl":"http://foo.com/token"}`, + OAuth2Password("http://foo.com/token")) - assertSerializeJSON(t, - OAuth2Application("http://foo.com/token"), - `{"type":"oauth2","flow":"application","tokenUrl":"http://foo.com/token"}`) + assert.JSONMarshalAsT(t, + `{"type":"oauth2","flow":"application","tokenUrl":"http://foo.com/token"}`, + OAuth2Application("http://foo.com/token")) - assertSerializeJSON( - t, - OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token"), + assert.JSONMarshalAsT(t, `{"type":"oauth2","flow":"accessCode","authorizationUrl":"http://foo.com/authorization",`+ - `"tokenUrl":"http://foo.com/token"}`) + `"tokenUrl":"http://foo.com/token"}`, + OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token")) auth1 := OAuth2Implicit("http://foo.com/authorization") auth1.AddScope("email", "read your email") - assertSerializeJSON( - t, - auth1, + assert.JSONMarshalAsT(t, `{"type":"oauth2","flow":"implicit","authorizationUrl":"http://foo.com/authorization",`+ - `"scopes":{"email":"read your email"}}`) + `"scopes":{"email":"read your email"}}`, + auth1) auth2 := OAuth2Password("http://foo.com/authorization") auth2.AddScope("email", "read your email") - assertSerializeJSON( - t, - auth2, + assert.JSONMarshalAsT(t, `{"type":"oauth2","flow":"password","tokenUrl":"http://foo.com/authorization",`+ - `"scopes":{"email":"read your email"}}`) + `"scopes":{"email":"read your email"}}`, + auth2) auth3 := OAuth2Application("http://foo.com/token") auth3.AddScope("email", "read your email") - assertSerializeJSON( - t, - auth3, - `{"type":"oauth2","flow":"application","tokenUrl":"http://foo.com/token","scopes":{"email":"read your email"}}`) + assert.JSONMarshalAsT(t, + `{"type":"oauth2","flow":"application","tokenUrl":"http://foo.com/token","scopes":{"email":"read your email"}}`, + auth3) auth4 := OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token") auth4.AddScope("email", "read your email") - assertSerializeJSON( - t, - auth4, + assert.JSONMarshalAsT(t, `{"type":"oauth2","flow":"accessCode","authorizationUrl":"http://foo.com/authorization",`+ - `"tokenUrl":"http://foo.com/token","scopes":{"email":"read your email"}}`) + `"tokenUrl":"http://foo.com/token","scopes":{"email":"read your email"}}`, + auth4) } func TestSerialization_AuthDeserialization(t *testing.T) { + assert.JSONUnmarshalAsT(t, BasicAuth(), `{"type":"basic"}`) - assertParsesJSON(t, `{"type":"basic"}`, BasicAuth()) - - assertParsesJSON( - t, - `{"in":"header","name":"api-key","type":"apiKey"}`, - APIKeyAuth("api-key", "header")) + assert.JSONUnmarshalAsT(t, + APIKeyAuth("api-key", "header"), + `{"in":"header","name":"api-key","type":"apiKey"}`) - assertParsesJSON( - t, - `{"authorizationUrl":"http://foo.com/authorization","flow":"implicit","type":"oauth2"}`, - OAuth2Implicit("http://foo.com/authorization")) + assert.JSONUnmarshalAsT(t, + OAuth2Implicit("http://foo.com/authorization"), + `{"authorizationUrl":"http://foo.com/authorization","flow":"implicit","type":"oauth2"}`) - assertParsesJSON( - t, - `{"flow":"password","tokenUrl":"http://foo.com/token","type":"oauth2"}`, - OAuth2Password("http://foo.com/token")) + assert.JSONUnmarshalAsT(t, + OAuth2Password("http://foo.com/token"), + `{"flow":"password","tokenUrl":"http://foo.com/token","type":"oauth2"}`) - assertParsesJSON( - t, - `{"flow":"application","tokenUrl":"http://foo.com/token","type":"oauth2"}`, - OAuth2Application("http://foo.com/token")) + assert.JSONUnmarshalAsT(t, + OAuth2Application("http://foo.com/token"), + `{"flow":"application","tokenUrl":"http://foo.com/token","type":"oauth2"}`) - assertParsesJSON( - t, + assert.JSONUnmarshalAsT(t, + OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token"), `{"authorizationUrl":"http://foo.com/authorization","flow":"accessCode","tokenUrl":"http://foo.com/token",`+ - `"type":"oauth2"}`, - OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token")) + `"type":"oauth2"}`) auth1 := OAuth2Implicit("http://foo.com/authorization") auth1.AddScope("email", "read your email") - assertParsesJSON(t, + assert.JSONUnmarshalAsT(t, auth1, `{"authorizationUrl":"http://foo.com/authorization","flow":"implicit","scopes":{"email":"read your email"},`+ - `"type":"oauth2"}`, - auth1) + `"type":"oauth2"}`) auth2 := OAuth2Password("http://foo.com/token") auth2.AddScope("email", "read your email") - assertParsesJSON(t, - `{"flow":"password","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`, - auth2) + assert.JSONUnmarshalAsT(t, auth2, + `{"flow":"password","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`) auth3 := OAuth2Application("http://foo.com/token") auth3.AddScope("email", "read your email") - assertParsesJSON(t, - `{"flow":"application","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`, - auth3) + assert.JSONUnmarshalAsT(t, auth3, + `{"flow":"application","scopes":{"email":"read your email"},"tokenUrl":"http://foo.com/token","type":"oauth2"}`) auth4 := OAuth2AccessToken("http://foo.com/authorization", "http://foo.com/token") auth4.AddScope("email", "read your email") - assertParsesJSON( - t, + assert.JSONUnmarshalAsT(t, auth4, `{"authorizationUrl":"http://foo.com/authorization","flow":"accessCode","scopes":{"email":"read your email"},`+ - `"tokenUrl":"http://foo.com/token","type":"oauth2"}`, - auth4) - + `"tokenUrl":"http://foo.com/token","type":"oauth2"}`) } diff --git a/cache.go b/cache.go index 10fba77a..06495d2c 100644 --- a/cache.go +++ b/cache.go @@ -8,10 +8,10 @@ import ( "sync" ) -// ResolutionCache a cache for resolving urls +// ResolutionCache a cache for resolving urls. type ResolutionCache interface { - Get(string) (any, bool) - Set(string, any) + Get(uri string) (any, bool) + Set(uri string, data any) } type simpleCache struct { @@ -19,7 +19,7 @@ type simpleCache struct { store map[string]any } -func (s *simpleCache) ShallowClone() ResolutionCache { +func (s *simpleCache) ShallowClone() ResolutionCache { //nolint:ireturn // returns the public interface type by design store := make(map[string]any, len(s.store)) s.lock.RLock() maps.Copy(store, s.store) @@ -30,7 +30,7 @@ func (s *simpleCache) ShallowClone() ResolutionCache { } } -// Get retrieves a cached URI +// Get retrieves a cached URI. func (s *simpleCache) Get(uri string) (any, bool) { s.lock.RLock() v, ok := s.store[uri] @@ -39,7 +39,7 @@ func (s *simpleCache) Get(uri string) (any, bool) { return v, ok } -// Set caches a URI +// Set caches a URI. func (s *simpleCache) Set(uri string, data any) { s.lock.Lock() s.store[uri] = data @@ -56,8 +56,8 @@ var ( // // All subsequent utilizations of this cache are produced from a shallow // clone of this initial version. - resCache *simpleCache - onceCache sync.Once + resCache *simpleCache //nolint:gochecknoglobals // package-level lazy cache for $ref resolution + onceCache sync.Once //nolint:gochecknoglobals // guards lazy init of resCache _ ResolutionCache = &simpleCache{} ) @@ -74,7 +74,7 @@ func defaultResolutionCache() *simpleCache { }} } -func cacheOrDefault(cache ResolutionCache) ResolutionCache { +func cacheOrDefault(cache ResolutionCache) ResolutionCache { //nolint:ireturn // returns the public interface type by design onceCache.Do(initResolutionCache) if cache != nil { diff --git a/cache_test.go b/cache_test.go index 1ef15db1..92f8a8f6 100644 --- a/cache_test.go +++ b/cache_test.go @@ -16,19 +16,19 @@ func TestDefaultResolutionCache(t *testing.T) { cache := defaultResolutionCache() sch, ok := cache.Get("not there") - assert.False(t, ok) + assert.FalseT(t, ok) assert.Nil(t, sch) sch, ok = cache.Get("http://swagger.io/v2/schema.json") - assert.True(t, ok) + assert.TrueT(t, ok) assert.Equal(t, swaggerSchema, sch) sch, ok = cache.Get("http://json-schema.org/draft-04/schema") - assert.True(t, ok) + assert.TrueT(t, ok) assert.Equal(t, jsonSchema, sch) cache.Set("something", "here") sch, ok = cache.Get("something") - assert.True(t, ok) + assert.TrueT(t, ok) assert.Equal(t, "here", sch) } diff --git a/circular_test.go b/circular_test.go index cc607c24..5a8535c7 100644 --- a/circular_test.go +++ b/circular_test.go @@ -6,7 +6,6 @@ package spec import ( "encoding/json" "net/http" - "net/http/httptest" "os" "path/filepath" "testing" @@ -73,7 +72,7 @@ func TestExpandCircular_Spec2Expansion(t *testing.T) { assertRefResolve(t, jazon, "", root) // assert stripped $ref in result - assert.NotContainsf(t, jazon, "circular-minimal.json#/", + assert.StringNotContainsTf(t, jazon, "circular-minimal.json#/", "expected %s to be expanded with stripped circular $ref", fixturePath) fixturePath = filepath.Join("fixtures", "expansion", "circularSpec2.json") @@ -89,7 +88,7 @@ func TestExpandCircular_Spec2Expansion(t *testing.T) { // circular $ref can always be further expanded against the root assertRefExpand(t, jazon, "", root) - assert.NotContainsf(t, jazon, "circularSpec.json#/", + assert.StringNotContainsTf(t, jazon, "circularSpec.json#/", "expected %s to be expanded with stripped circular $ref", fixturePath) /* @@ -152,7 +151,7 @@ func TestExpandCircular_Issue957(t *testing.T) { jazon, root := expandThisOrDieTrying(t, fixturePath) require.NotEmpty(t, jazon) - require.NotContainsf(t, jazon, "fixture-957.json#/", + require.StringNotContainsTf(t, jazon, "fixture-957.json#/", "expected %s to be expanded with stripped circular $ref", fixturePath) assertRefInJSON(t, jazon, "#/definitions/") @@ -253,9 +252,9 @@ func TestExpandCircular_RemoteCircularID(t *testing.T) { } func TestCircular_RemoteExpandAzure(t *testing.T) { - // local copy of : https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/network/resource-manager/Microsoft.Network/stable/2020-04-01/publicIpAddress.json - server := httptest.NewServer(http.FileServer(http.Dir("fixtures/azure"))) - defer server.Close() + // local copy of Azure publicIpAddress.json from azure-rest-api-specs + // (Microsoft.Network/stable/2020-04-01) + server := fixtureServer(t, "fixtures/azure") basePath := server.URL + "/publicIpAddress.json" jazon, sch := expandThisOrDieTrying(t, basePath) diff --git a/contact_info.go b/contact_info.go index fafe639b..46fada5d 100644 --- a/contact_info.go +++ b/contact_info.go @@ -17,14 +17,14 @@ type ContactInfo struct { VendorExtensible } -// ContactInfoProps hold the properties of a ContactInfo object +// ContactInfoProps hold the properties of a ContactInfo object. type ContactInfoProps struct { Name string `json:"name,omitempty"` URL string `json:"url,omitempty"` Email string `json:"email,omitempty"` } -// UnmarshalJSON hydrates ContactInfo from json +// UnmarshalJSON hydrates ContactInfo from json. func (c *ContactInfo) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &c.ContactInfoProps); err != nil { return err @@ -32,7 +32,7 @@ func (c *ContactInfo) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &c.VendorExtensible) } -// MarshalJSON produces ContactInfo as json +// MarshalJSON produces ContactInfo as json. func (c ContactInfo) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(c.ContactInfoProps) if err != nil { diff --git a/contact_info_test.go b/contact_info_test.go index 6159f75d..bcf177e2 100644 --- a/contact_info_test.go +++ b/contact_info_test.go @@ -4,11 +4,9 @@ package spec import ( - "encoding/json" "testing" "github.com/go-openapi/testify/v2/assert" - "github.com/go-openapi/testify/v2/require" ) const contactInfoJSON = `{ @@ -18,19 +16,13 @@ const contactInfoJSON = `{ "x-teams": "test team" }` -var contactInfo = ContactInfo{ContactInfoProps: ContactInfoProps{ +var contactInfo = ContactInfo{ContactInfoProps: ContactInfoProps{ //nolint:gochecknoglobals // test fixture Name: "wordnik api team", URL: "http://developer.wordnik.com", Email: "some@mailayada.dkdkd", }, VendorExtensible: VendorExtensible{Extensions: map[string]any{"x-teams": "test team"}}} func TestIntegrationContactInfo(t *testing.T) { - b, err := json.MarshalIndent(contactInfo, "", "\t") - require.NoError(t, err) - assert.JSONEq(t, contactInfoJSON, string(b)) - - actual := ContactInfo{} - err = json.Unmarshal([]byte(contactInfoJSON), &actual) - require.NoError(t, err) - assert.Equal(t, contactInfo, actual) + assert.JSONMarshalAsT(t, contactInfoJSON, contactInfo) + assert.JSONUnmarshalAsT(t, contactInfo, contactInfoJSON) } diff --git a/debug.go b/debug.go index f4316c26..fa52b0c7 100644 --- a/debug.go +++ b/debug.go @@ -14,14 +14,12 @@ import ( // Debug is true when the SWAGGER_DEBUG env var is not empty. // // It enables a more verbose logging of this package. -var Debug = os.Getenv("SWAGGER_DEBUG") != "" +var Debug = os.Getenv("SWAGGER_DEBUG") != "" //nolint:gochecknoglobals // public toggle for debug logging -var ( - // specLogger is a debug logger for this package - specLogger *log.Logger -) +// specLogger is a debug logger for this package. +var specLogger *log.Logger //nolint:gochecknoglobals // package-level debug logger -func init() { +func init() { //nolint:gochecknoinits // initializes debug logger at package load debugOptions() } diff --git a/debug_test.go b/debug_test.go index 0a8ba089..6f6547bf 100644 --- a/debug_test.go +++ b/debug_test.go @@ -11,9 +11,7 @@ import ( "github.com/go-openapi/testify/v2/assert" ) -var ( - logMutex = &sync.Mutex{} -) +var logMutex = &sync.Mutex{} //nolint:gochecknoglobals // test fixture func TestDebug(t *testing.T) { // usetesting linter disabled until https://github.com/golang/go/issues/71544 is fixed for windows @@ -40,9 +38,9 @@ func TestDebug(t *testing.T) { Debug = false _ = tmpFile.Close() - flushed, _ := os.Open(tmpName) + flushed, _ := os.Open(tmpName) //nolint:gosec // test file, path is from os.CreateTemp buf := make([]byte, 500) _, _ = flushed.Read(buf) specLogger.SetOutput(os.Stdout) - assert.Contains(t, string(buf), "A debug") + assert.StringContainsT(t, string(buf), "A debug") } diff --git a/docs/MAINTAINERS.md b/docs/MAINTAINERS.md index 6c15d12c..8fc6befb 100644 --- a/docs/MAINTAINERS.md +++ b/docs/MAINTAINERS.md @@ -1,37 +1,33 @@ -# Maintainer's guide +> [!NOTE] +> Comprehensive guide for maintainers covering repository structure, CI/CD workflows, release procedures, and development practices. +> Essential reading for anyone contributing to or maintaining this project. ## Repo structure -Single go module. - -> **NOTE** -> -> Some `go-openapi` repos are mono-repos with multiple modules, -> with adapted CI workflows. +This project is organized as a repo with a single go module. ## Repo configuration -* default branch: master -* protected branches: master -* branch protection rules: +* Default branch: master +* Protected branches: master +* Branch protection rules: * require pull requests and approval - * required status checks: - - DCO (simple email sign-off) - - Lint - - tests completed -* auto-merge enabled (used for dependabot updates) + * required status checks: + * DCO (simple email sign-off) + * Lint + * All tests completed +* Auto-merge enabled (used for dependabot updates and other auto-merged PR's, e.g. contributors update) ## Continuous Integration ### Code Quality checks -* meta-linter: golangci-lint -* linter config: [`.golangci.yml`](../.golangci.yml) (see our [posture](./STYLE.md) on linters) - -* Code quality assessment: [CodeFactor](https://www.codefactor.io/dashboard) +* meta-linter: [golangci-lint][golangci-url] +* linter config: [`.golangci.yml`][linter-config] (see our [posture][style-doc] on linters) +* Code quality assessment: [CodeFactor][codefactor-url] * Code quality badges - * go report card: - * CodeFactor: + * [go report card][gocard-url] + * [CodeFactor][codefactor-url] > **NOTES** > @@ -58,7 +54,7 @@ Coverage threshold status is informative and not blocking. This is because the thresholds are difficult to tune and codecov oftentimes reports false negatives or may fail to upload coverage. -All tests use our fork of `stretchr/testify`: `github.com/go-openapi/testify`. +All tests across `go-openapi` use our fork of `stretchr/spec` (this repo): `github.com/go-openapi/spec`. This allows for minimal test dependencies. > **NOTES** @@ -76,7 +72,7 @@ This allows for minimal test dependencies. ### Automated updates * dependabot - * configuration: [`dependabot.yaml`](../.github/dependabot.yaml) + * configuration: [`dependabot.yaml`][dependabot-config] Principle: @@ -84,7 +80,7 @@ This allows for minimal test dependencies. * all updates from "trusted" dependencies (github actions, golang.org packages, go-openapi packages are auto-merged if they successfully pass CI. -* go version udpates +* go version updates Principle: @@ -92,8 +88,14 @@ This allows for minimal test dependencies. * `go.mod` should be updated (manually) whenever there is a new go minor release (e.g. every 6 months). + > This means that our projects always have a 6 months lag to enforce new features from the go compiler. + > + > However, new features of go may be used with a "go:build" tag: this allows users of the newer + > version to benefit the new feature while users still running with `oldstable` use another version + > that still builds. + * contributors - * a [`CONTRIBUTORS.md`](../CONTRIBUTORS.md) file is updated weekly, with all-time contributors to the repository + * a [`CONTRIBUTORS.md`][contributors-doc] file is updated weekly, with all-time contributors to the repository * the `github-actions[bot]` posts a pull request to do that automatically * at this moment, this pull request is not auto-approved/auto-merged (bot cannot approve its own PRs) @@ -101,7 +103,7 @@ This allows for minimal test dependencies. There are 3 complementary scanners - obviously, there is some overlap, but each has a different focus. -* github `CodeQL` +* GitHub `CodeQL` * `trivy` * `govulnscan` @@ -115,45 +117,70 @@ Reports are centralized in github security reports for code scanning tools. ## Releases +**For single module repos:** + +A bump release workflow can be triggered from the github actions UI to cut a release with a few clicks. + The release process is minimalist: * push a semver tag (i.e v{major}.{minor}.{patch}) to the master branch. * the CI handles this to generate a github release with release notes * release notes generator: git-cliff -* configuration: [`cliff.toml`](../.cliff.toml) +* configuration: the `.cliff.toml` is defined as a share configuration on + remote repo [`ci-workflows/.cliff.toml`][remote-cliff-config] + +Commits from maintainers are preferably PGP-signed. Tags are preferably PGP-signed. +We want our releases to show as "verified" on github. + The tag message introduces the release notes (e.g. a summary of this release). The release notes generator does not assume that commits are necessarily "conventional commits". -## Other files +**For mono-repos with multiple modules:** -Standard documentation: +The release process is slightly different because we need to update cross-module dependencies +before pushing a tag. -* [`CONTRIBUTING.md`](../.github/CONTRIBUTING.md) guidelines -* [`DCO.md`](../.github/DCO.md) terms for first-time contributors to read -* [`CODE_OF_CONDUCT.md`](../CODE_OF_CONDUCT.md) -* [`SECURIY.md`](../SECURITY.md) policy: how to report vulnerabilities privately -* [`LICENSE`](../LICENSE) terms - +A bump release workflow (mono-repo) can be triggered from the github actions UI to cut a release with a few clicks. -Reference documentation (released): +It works with the same input as the one for single module repos, and first creates a PR (auto-merged) +that updates the different go.mod files _before_ pushing the desired git tag. + +Commits and tags pushed by the workflow bot are PGP-signed ("go-openapi[bot]"). + +## Other files + +Standard documentation: -* [godoc](https://pkg.go.dev/github.com/go-openapi/spec) +* [CONTRIBUTING.md][contributing-doc] guidelines +* [DCO.md][dco-doc] terms for first-time contributors to read +* [CODE_OF_CONDUCT.md][coc-doc] +* [SECURITY.md][security-doc] policy: how to report vulnerabilities privately +* [LICENSE][license-doc] terms -## TODOs & other ideas + -A few things remain ahead to ease a bit a maintainer's job: +Reference documentation (released): -* [x] reuse CI workflows (e.g. in `github.com/go-openapi/workflows`) -* [x] reusable actions with custom tools pinned (e.g. in `github.com/go-openapi/gh-actions`) -* open-source license checks -* [x] auto-merge for CONTRIBUTORS.md (requires a github app to produce tokens) -* [ ] more automated code renovation / relinting work (possibly built with CLAUDE) (ongoing) -* organization-level documentation web site -* ... +* [pkg.go.dev (fka godoc)][godoc-url] + + +[linter-config]: https://github.com/go-openapi/spec/blob/master/.golangci.yml +[remote-cliff-config]: https://github.com/go-openapi/ci-workflows/blob/master/.cliff.toml +[dependabot-config]: https://github.com/go-openapi/spec/blob/master/.github/dependabot.yaml +[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/spec +[codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/spec +[golangci-url]: https://golangci-lint.run/ +[godoc-url]: https://pkg.go.dev/github.com/go-openapi/spec +[contributors-doc]: ../CONTRIBUTORS.md +[contributing-doc]: ../.github/CONTRIBUTING.md +[dco-doc]: ../.github/DCO.md +[style-doc]: STYLE.md +[coc-doc]: ../CODE_OF_CONDUCT.md +[security-doc]: ../SECURITY.md +[license-doc]: ../LICENSE + diff --git a/docs/STYLE.md b/docs/STYLE.md index 056fdb51..46f46cef 100644 --- a/docs/STYLE.md +++ b/docs/STYLE.md @@ -2,14 +2,14 @@ > **TL;DR** > -> Let's be honest: at `go-openapi` and `go-swagger` we've never been super-strict on code style etc. +> Let's be honest: at `go-openapi` and `go-swagger` we've never been super-strict on code style and linting. > > But perhaps now (2025) is the time to adopt a different stance. Even though our repos have been early adopters of `golangci-lint` years ago (we used some other metalinter before), our decade-old codebase is only realigned to new rules from time to time. -Now go-openapi and go-swagger make up a really large codebase, which is taxing to maintain and keep afloat. +Now go-openapi and go-swagger together make up a really large codebase, which is taxing to maintain and keep afloat. Code quality and the harmonization of rules have thus become things that we need now. @@ -21,8 +21,13 @@ You should run `golangci-lint run` before committing your changes. Many editors have plugins that do that automatically. -> We use the `golangci-lint` meta-linter. The configuration lies in [`.golangci.yml`](../.golangci.yml). -> You may read for additional reference. +> We use the `golangci-lint` meta-linter. The configuration lies in +> [`.golangci.yml`][golangci-yml]. +> You may read [the linter's configuration reference][golangci-doc] for additional reference. + +This configuration is essentially the same across all `go-openapi` projects. + +Some projects may require slightly different settings. ## Linting rules posture @@ -30,9 +35,32 @@ Thanks to go's original design, we developers don't have to waste much time argu However, the number of available linters has been growing to the point that we need to pick a choice. +### Our approach: evaluate, don't consume blindly + +As early adopters of `golangci-lint` (and its predecessors), we've watched linting orthodoxy +shift back and forth over the years. Patterns that were idiomatic one year get flagged the next; +rules that seemed reasonable in isolation produce noise at scale. Conversations with maintainers +of other large Go projects confirmed what our own experience taught us: +**the default linter set is a starting point, not a prescription**. + +Our stance is deliberate: + +- **Start from `default: all`**, then consciously disable what doesn't earn its keep. + This forces us to evaluate every linter and articulate why we reject it — the disabled list + is a design rationale, not technical debt. +- **Tune thresholds rather than disable** when a linter's principle is sound but its defaults + are too aggressive for a mature codebase. +- **Require justification for every `//nolint`** directive. Each one must carry an inline comment + explaining why it's there. +- **Prefer disabling a linter over scattering `//nolint`** across the codebase. If a linter + produces systematic false positives on patterns we use intentionally, the linter goes — + not our code. +- **Keep the configuration consistent** across all `go-openapi` repositories. Per-repo + divergence is a maintenance tax we don't want to pay. + We enable all linters published by `golangci-lint` by default, then disable a few ones. -Here are the reasons why they are disabled (update: Nov. 2025, `golangci-lint v2.6.1`): +Here are the reasons why they are disabled (update: Feb. 2026, `golangci-lint v2.8.0`). ```yaml disable: @@ -46,6 +74,7 @@ Here are the reasons why they are disabled (update: Nov. 2025, `golangci-lint v2 - paralleltest # we like parallel tests. We just don't want them to be enforced everywhere - recvcheck # we like the idea of having pointer and non-pointer receivers - testpackage # we like test packages. We just don't want them to be enforced everywhere + - thelper # too many false positives on test case factories returning func(*testing.T). See note below - tparallel # see paralleltest - varnamelen # sometimes, we like short variables. The linter doesn't catch cases when a short name is good - whitespace # no added value @@ -55,9 +84,11 @@ Here are the reasons why they are disabled (update: Nov. 2025, `golangci-lint v2 ``` As you may see, we agree with the objective of most linters, at least the principle they are supposed to enforce. -But all linters do not support fine-grained tuning to tolerate some cases and not some others. +But all linters do not support fine-grained tuning to tolerate some cases and not some others. -When this is possible, we enable linters with relaxed constraints: +**Relaxed linter settings** + +When this is possible, we enable linters with relaxed constraints. ```yaml settings: @@ -81,3 +112,6 @@ When this is possible, we enable linters with relaxed constraints: Final note: since we have switched to a forked version of `stretchr/testify`, we no longer benefit from the great `testifylint` linter for tests. + +[golangci-yml]: https://github.com/go-openapi/spec/blob/master/.golangci.yml +[golangci-doc]: https://golangci-lint.run/docs/linters/configuration/ diff --git a/errors.go b/errors.go index e39ab8bf..eaca01cc 100644 --- a/errors.go +++ b/errors.go @@ -5,21 +5,21 @@ package spec import "errors" -// Error codes +// Error codes. var ( - // ErrUnknownTypeForReference indicates that a resolved reference was found in an unsupported container type + // ErrUnknownTypeForReference indicates that a resolved reference was found in an unsupported container type. ErrUnknownTypeForReference = errors.New("unknown type for the resolved reference") - // ErrResolveRefNeedsAPointer indicates that a $ref target must be a valid JSON pointer + // ErrResolveRefNeedsAPointer indicates that a $ref target must be a valid JSON pointer. ErrResolveRefNeedsAPointer = errors.New("resolve ref: target needs to be a pointer") // ErrDerefUnsupportedType indicates that a resolved reference was found in an unsupported container type. - // At the moment, $ref are supported only inside: schemas, parameters, responses, path items + // At the moment, $ref are supported only inside: schemas, parameters, responses, path items. ErrDerefUnsupportedType = errors.New("deref: unsupported type") - // ErrExpandUnsupportedType indicates that $ref expansion is attempted on some invalid type + // ErrExpandUnsupportedType indicates that $ref expansion is attempted on some invalid type. ErrExpandUnsupportedType = errors.New("expand: unsupported type. Input should be of type *Parameter or *Response") - // ErrSpec is an error raised by the spec package + // ErrSpec is an error raised by the spec package. ErrSpec = errors.New("spec error") ) diff --git a/expander.go b/expander.go index ff45350a..f9c2fa32 100644 --- a/expander.go +++ b/expander.go @@ -38,7 +38,7 @@ func optionsOrDefault(opts *ExpandOptions) *ExpandOptions { return &ExpandOptions{} } -// ExpandSpec expands the references in a swagger spec +// ExpandSpec expands the references in a swagger spec. func ExpandSpec(spec *Swagger, options *ExpandOptions) error { options = optionsOrDefault(options) resolver := defaultSchemaLoader(spec, options, nil, nil) @@ -92,7 +92,7 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error { const rootBase = ".root" // baseForRoot loads in the cache the root document and produces a fake ".root" base path entry -// for further $ref resolution +// for further $ref resolution. func baseForRoot(root any, cache ResolutionCache) string { // cache the root document to resolve $ref's normalizedBase := normalizeBase(rootBase) @@ -190,6 +190,7 @@ func expandItems(target Schema, parentRefs []string, resolver *schemaLoader, bas return &target, nil } +//nolint:gocognit,gocyclo,cyclop // complex but well-tested $ref expansion logic; refactoring deferred to dedicated PR func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) { if target.Ref.String() == "" && target.Ref.IsRoot() { newRef := normalizeRef(&target.Ref, basePath) @@ -464,7 +465,7 @@ func ExpandResponseWithRoot(response *Response, root any, cache ResolutionCache) // ExpandResponse expands a response based on a basepath // -// All refs inside response will be resolved relative to basePath +// All refs inside response will be resolved relative to basePath. func ExpandResponse(response *Response, basePath string) error { opts := optionsOrDefault(&ExpandOptions{ RelativeBase: basePath, @@ -491,7 +492,7 @@ func ExpandParameterWithRoot(parameter *Parameter, root any, cache ResolutionCac // ExpandParameter expands a parameter based on a basepath. // This is the exported version of expandParameter -// all refs inside parameter will be resolved relative to basePath +// all refs inside parameter will be resolved relative to basePath. func ExpandParameter(parameter *Parameter, basePath string) error { opts := optionsOrDefault(&ExpandOptions{ RelativeBase: basePath, @@ -565,7 +566,7 @@ func expandParameterOrResponse(input any, resolver *schemaLoader, basePath strin return nil } - if sch.Ref.String() != "" { + if sch.Ref.String() != "" { //nolint:nestif // intertwined ref rebasing and circularity check rebasedRef, ern := NewRef(normalizeURI(sch.Ref.String(), basePath)) if ern != nil { return ern diff --git a/expander_test.go b/expander_test.go index 1fc2e5b7..f7be753b 100644 --- a/expander_test.go +++ b/expander_test.go @@ -29,13 +29,13 @@ const ( //nolint:gochecknoglobals // it's okay to have embedded test fixtures as globals var ( - //go:embed fixtures/*/*.json fixtures/*/*.yaml fixtures/*/*.yml + //go:embed all:fixtures fixtureAssets embed.FS // PetStore20 json doc for swagger 2.0 pet store. PetStore20 []byte - // PetStoreJSONMessage json raw message for Petstore20 + // PetStoreJSONMessage json raw message for Petstore20. PetStoreJSONMessage json.RawMessage expectedExtraRef []byte expectedPathItem []byte @@ -73,17 +73,17 @@ func TestExpand_Issue148(t *testing.T) { return func(t *testing.T) { require.Len(t, sp.Definitions, 2) - require.Contains(t, sp.Definitions, "empty") + require.MapContainsT(t, sp.Definitions, "empty") empty := sp.Definitions["empty"] require.NotNil(t, empty.AdditionalProperties) require.NotNil(t, empty.AdditionalProperties.Schema) - require.True(t, empty.AdditionalProperties.Allows) + require.TrueT(t, empty.AdditionalProperties.Allows) - require.Contains(t, sp.Definitions, "false") + require.MapContainsT(t, sp.Definitions, "false") additionalIsFalse := sp.Definitions["false"] require.NotNil(t, additionalIsFalse.AdditionalProperties) require.Nil(t, additionalIsFalse.AdditionalProperties.Schema) - require.False(t, additionalIsFalse.AdditionalProperties.Allows) + require.FalseT(t, additionalIsFalse.AdditionalProperties.Allows) } } @@ -100,7 +100,7 @@ func TestExpand_KnownRef(t *testing.T) { schema := RefProperty("http://json-schema.org/draft-04/schema#") require.NoError(t, ExpandSchema(schema, nil, nil)) - assert.Equal(t, "Core schema meta-schema", schema.Description) + assert.EqualT(t, "Core schema meta-schema", schema.Description) // from the expanded schema, verify that all remaining $ref actually resolve jazon := asJSON(t, schema) @@ -126,7 +126,7 @@ func TestExpand_ResponseSchema(t *testing.T) { require.NotNil(t, sch) assert.Empty(t, sch.Ref.String()) - assert.Contains(t, sch.Type, "object") + assert.SliceContainsT(t, sch.Type, "object") assert.Len(t, sch.Properties, 2) } @@ -151,7 +151,6 @@ func TestExpand_EmptySpec(t *testing.T) { } func TestExpand_Spec(t *testing.T) { - // expansion of a rich spec specPath := filepath.Join("fixtures", "expansion", "all-the-things.json") specDoc, err := jsonDoc(specPath) @@ -214,7 +213,7 @@ func TestExpand_InternalResponse(t *testing.T) { jazon := asJSON(t, expectedPet) - assert.JSONEq(t, `{ + assert.JSONEqT(t, `{ "description": "pet response", "schema": { "required": [ @@ -253,7 +252,7 @@ func TestExpand_InternalResponse(t *testing.T) { jazon = asJSON(t, successResponse) - assert.JSONEq(t, `{ + assert.JSONEqT(t, `{ "$ref": "#/responses/anotherPet" }`, jazon) @@ -467,8 +466,8 @@ func TestExpand_InternalSchemas2(t *testing.T) { require.NotNil(t, s) schema = *s - assert.Empty(t, schema.Items.Schema.Ref.String()) // no more a $ref - assert.False(t, schema.Items.Schema.Ref.IsRoot()) // no more a $ref + assert.Empty(t, schema.Items.Schema.Ref.String()) // no more a $ref + assert.FalseT(t, schema.Items.Schema.Ref.IsRoot()) // no more a $ref assert.Equal(t, spec.Definitions["car"], *schema.Items.Schema) sch := new(Schema) @@ -750,8 +749,7 @@ func TestExpand_InternalSchemas1(t *testing.T) { } func TestExpand_RelativeBaseURI(t *testing.T) { - server := httptest.NewServer(http.FileServer(http.Dir("fixtures/remote"))) - defer server.Close() + server := fixtureServer(t, "fixtures/remote") spec := new(Swagger) @@ -802,7 +800,7 @@ func TestExpand_RelativeBaseURI(t *testing.T) { // backRef navigates back to the root document (relative $ref) backRef := spec.Responses["backRef"] require.NoError(t, ExpandResponse(&backRef, opts.RelativeBase)) - assert.Equal(t, "pet response", backRef.Description) + assert.EqualT(t, "pet response", backRef.Description) assert.NotEmpty(t, backRef.Schema) assert.Empty(t, backRef.Ref) @@ -918,7 +916,7 @@ func TestExpandRemoteRef_WithNestedResolutionContext(t *testing.T) { require.Empty(t, tgt.Ref) require.NotNil(t, tgt.Items) require.NotNil(t, tgt.Schema) - assert.Equal(t, "deeper/", tgt.ID) // schema id is preserved + assert.EqualT(t, "deeper/", tgt.ID) // schema id is preserved assert.Equal(t, StringOrArray([]string{"string"}), tgt.Items.Schema.Type) assert.Empty(t, tgt.Items.Schema.Ref) @@ -949,7 +947,7 @@ func TestExpand_RemoteRefWithNestedResolutionContextWithFragment(t *testing.T) { require.Empty(t, tgt.Ref) require.NotNil(t, tgt.Items) require.NotNil(t, tgt.Schema) - assert.Equal(t, "deeper/", tgt.ID) // schema id is preserved + assert.EqualT(t, "deeper/", tgt.ID) // schema id is preserved assert.Equal(t, StringOrArray([]string{"file"}), tgt.Items.Schema.Type) assert.Empty(t, tgt.Items.Schema.Ref) @@ -970,7 +968,7 @@ func TestExpand_TransitiveRefs(t *testing.T) { require.NoError(t, ExpandSpec(spec, opts)) - assert.Equal(t, "todos.stoplight.io", spec.Host) // i.e. not empty + assert.EqualT(t, "todos.stoplight.io", spec.Host) // i.e. not empty jazon := asJSON(t, spec) // verify that the spec has been fully expanded @@ -1030,12 +1028,12 @@ func expandRootWithID(t testing.TB, root *Swagger, testcase string) { func TestExpand_PathItem(t *testing.T) { jazon, _ := expandThisOrDieTrying(t, pathItemsFixture) - assert.JSONEq(t, string(expectedPathItem), jazon) + assert.JSONEqT(t, string(expectedPathItem), jazon) } func TestExpand_ExtraItems(t *testing.T) { jazon, _ := expandThisOrDieTrying(t, extraRefFixture) - assert.JSONEq(t, string(expectedExtraRef), jazon) + assert.JSONEqT(t, string(expectedExtraRef), jazon) } func TestExpand_Issue145(t *testing.T) { @@ -1046,39 +1044,39 @@ func TestExpand_Issue145(t *testing.T) { // assert the internal behavior of baseForRoot() t.Run("with nil root, empty cache", func(t *testing.T) { cache := defaultResolutionCache() - require.Equal(t, pseudoRoot, baseForRoot(nil, cache)) + require.EqualT(t, pseudoRoot, baseForRoot(nil, cache)) t.Run("empty root is cached", func(t *testing.T) { value, ok := cache.Get(pseudoRoot) - require.True(t, ok) // found in cache + require.TrueT(t, ok) // found in cache asMap, ok := value.(map[string]any) - require.True(t, ok) + require.TrueT(t, ok) require.Empty(t, asMap) }) }) t.Run("with non-nil root, empty cache", func(t *testing.T) { cache := defaultResolutionCache() - require.Equal(t, pseudoRoot, baseForRoot(map[string]any{"key": "arbitrary"}, cache)) + require.EqualT(t, pseudoRoot, baseForRoot(map[string]any{"key": "arbitrary"}, cache)) t.Run("non-empty root is cached", func(t *testing.T) { value, ok := cache.Get(pseudoRoot) - require.True(t, ok) // found in cache + require.TrueT(t, ok) // found in cache asMap, ok := value.(map[string]any) - require.True(t, ok) - require.Contains(t, asMap, "key") + require.TrueT(t, ok) + require.MapContainsT(t, asMap, "key") require.Equal(t, "arbitrary", asMap["key"]) }) t.Run("with nil root, non-empty cache", func(t *testing.T) { - require.Equal(t, pseudoRoot, baseForRoot(nil, cache)) + require.EqualT(t, pseudoRoot, baseForRoot(nil, cache)) t.Run("non-empty root is kept", func(t *testing.T) { value, ok := cache.Get(pseudoRoot) - require.True(t, ok) // found in cache + require.TrueT(t, ok) // found in cache asMap, ok := value.(map[string]any) - require.True(t, ok) - require.Contains(t, asMap, "key") + require.TrueT(t, ok) + require.MapContainsT(t, asMap, "key") require.Equal(t, "arbitrary", asMap["key"]) }) }) diff --git a/external_docs_test.go b/external_docs_test.go index 54b1e10c..3e8302f5 100644 --- a/external_docs_test.go +++ b/external_docs_test.go @@ -5,14 +5,17 @@ package spec import ( "testing" + + _ "github.com/go-openapi/testify/enable/yaml/v2" + "github.com/go-openapi/testify/v2/assert" ) func TestIntegrationExternalDocs(t *testing.T) { - var extDocs = ExternalDocumentation{Description: "the name", URL: "the url"} + extDocs := ExternalDocumentation{Description: "the name", URL: "the url"} const extDocsYAML = "description: the name\nurl: the url\n" const extDocsJSON = `{"description":"the name","url":"the url"}` - assertSerializeJSON(t, extDocs, extDocsJSON) - assertSerializeYAML(t, extDocs, extDocsYAML) - assertParsesJSON(t, extDocsJSON, extDocs) - assertParsesYAML(t, extDocsYAML, extDocs) + assert.JSONMarshalAsT(t, extDocsJSON, extDocs) + assert.YAMLMarshalAsT(t, extDocsYAML, extDocs) + assert.JSONUnmarshalAsT(t, extDocs, extDocsJSON) + assert.YAMLUnmarshalAsT(t, extDocs, extDocsYAML) } diff --git a/go.mod b/go.mod index d92cc780..b1ed3850 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,21 @@ module github.com/go-openapi/spec require ( - github.com/go-openapi/jsonpointer v0.22.4 - github.com/go-openapi/jsonreference v0.21.4 - github.com/go-openapi/swag/conv v0.25.4 - github.com/go-openapi/swag/jsonname v0.25.4 - github.com/go-openapi/swag/jsonutils v0.25.4 - github.com/go-openapi/swag/loading v0.25.4 - github.com/go-openapi/swag/stringutils v0.25.4 + github.com/go-openapi/jsonpointer v0.22.5 + github.com/go-openapi/jsonreference v0.21.5 + github.com/go-openapi/swag/conv v0.25.5 + github.com/go-openapi/swag/jsonname v0.25.5 + github.com/go-openapi/swag/jsonutils v0.25.5 + github.com/go-openapi/swag/loading v0.25.5 + github.com/go-openapi/swag/stringutils v0.25.5 + github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 github.com/go-openapi/testify/v2 v2.4.0 - go.yaml.in/yaml/v3 v3.0.4 ) require ( - github.com/go-openapi/swag/typeutils v0.25.4 // indirect - github.com/go-openapi/swag/yamlutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.5 // indirect + github.com/go-openapi/swag/yamlutils v0.25.5 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect ) go 1.24.0 diff --git a/go.sum b/go.sum index f9e18b33..39d1d0b3 100644 --- a/go.sum +++ b/go.sum @@ -1,25 +1,25 @@ -github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= -github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= -github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= -github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= -github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= -github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= -github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= -github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= -github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= -github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= -github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= -github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= -github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= -github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= -github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= -github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= -github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= -github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= -github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= -github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= +github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= +github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= +github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= +github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= +github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= +github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= +github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= +github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= +github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= +github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= +github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= +github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= +github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII= +github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E= +github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= +github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= +github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= diff --git a/header.go b/header.go index ab251ef7..599ba2c5 100644 --- a/header.go +++ b/header.go @@ -15,7 +15,7 @@ const ( jsonArray = "array" ) -// HeaderProps describes a response header +// HeaderProps describes a response header. type HeaderProps struct { Description string `json:"description,omitempty"` } @@ -30,25 +30,25 @@ type Header struct { HeaderProps } -// ResponseHeader creates a new header instance for use in a response +// ResponseHeader creates a new header instance for use in a response. func ResponseHeader() *Header { return new(Header) } -// WithDescription sets the description on this response, allows for chaining +// WithDescription sets the description on this response, allows for chaining. func (h *Header) WithDescription(description string) *Header { h.Description = description return h } -// Typed a fluent builder method for the type of parameter +// Typed a fluent builder method for the type of parameter. func (h *Header) Typed(tpe, format string) *Header { h.Type = tpe h.Format = format return h } -// CollectionOf a fluent builder method for an array item +// CollectionOf a fluent builder method for an array item. func (h *Header) CollectionOf(items *Items, format string) *Header { h.Type = jsonArray h.Items = items @@ -56,87 +56,87 @@ func (h *Header) CollectionOf(items *Items, format string) *Header { return h } -// WithDefault sets the default value on this item +// WithDefault sets the default value on this item. func (h *Header) WithDefault(defaultValue any) *Header { h.Default = defaultValue return h } -// WithMaxLength sets a max length value +// WithMaxLength sets a max length value. func (h *Header) WithMaxLength(maximum int64) *Header { h.MaxLength = &maximum return h } -// WithMinLength sets a min length value +// WithMinLength sets a min length value. func (h *Header) WithMinLength(minimum int64) *Header { h.MinLength = &minimum return h } -// WithPattern sets a pattern value +// WithPattern sets a pattern value. func (h *Header) WithPattern(pattern string) *Header { h.Pattern = pattern return h } -// WithMultipleOf sets a multiple of value +// WithMultipleOf sets a multiple of value. func (h *Header) WithMultipleOf(number float64) *Header { h.MultipleOf = &number return h } -// WithMaximum sets a maximum number value +// WithMaximum sets a maximum number value. func (h *Header) WithMaximum(maximum float64, exclusive bool) *Header { h.Maximum = &maximum h.ExclusiveMaximum = exclusive return h } -// WithMinimum sets a minimum number value +// WithMinimum sets a minimum number value. func (h *Header) WithMinimum(minimum float64, exclusive bool) *Header { h.Minimum = &minimum h.ExclusiveMinimum = exclusive return h } -// WithEnum sets a the enum values (replace) +// WithEnum sets a the enum values (replace). func (h *Header) WithEnum(values ...any) *Header { h.Enum = append([]any{}, values...) return h } -// WithMaxItems sets the max items +// WithMaxItems sets the max items. func (h *Header) WithMaxItems(size int64) *Header { h.MaxItems = &size return h } -// WithMinItems sets the min items +// WithMinItems sets the min items. func (h *Header) WithMinItems(size int64) *Header { h.MinItems = &size return h } -// UniqueValues dictates that this array can only have unique items +// UniqueValues dictates that this array can only have unique items. func (h *Header) UniqueValues() *Header { h.UniqueItems = true return h } -// AllowDuplicates this array can have duplicates +// AllowDuplicates this array can have duplicates. func (h *Header) AllowDuplicates() *Header { h.UniqueItems = false return h } -// WithValidations is a fluent method to set header validations +// WithValidations is a fluent method to set header validations. func (h *Header) WithValidations(val CommonValidations) *Header { h.SetValidations(SchemaValidations{CommonValidations: val}) return h } -// MarshalJSON marshal this to JSON +// MarshalJSON marshal this to JSON. func (h Header) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(h.CommonValidations) if err != nil { @@ -153,7 +153,7 @@ func (h Header) MarshalJSON() ([]byte, error) { return jsonutils.ConcatJSON(b1, b2, b3), nil } -// UnmarshalJSON unmarshals this header from JSON +// UnmarshalJSON unmarshals this header from JSON. func (h *Header) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &h.CommonValidations); err != nil { return err @@ -167,7 +167,7 @@ func (h *Header) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &h.HeaderProps) } -// JSONLookup look up a value by the json property name +// JSONLookup look up a value by the json property name. func (h Header) JSONLookup(token string) (any, error) { if ex, ok := h.Extensions[token]; ok { return &ex, nil diff --git a/header_test.go b/header_test.go index e4a27f70..ad34da3e 100644 --- a/header_test.go +++ b/header_test.go @@ -4,7 +4,6 @@ package spec import ( - "encoding/json" "testing" "github.com/go-openapi/swag/conv" @@ -17,11 +16,12 @@ const epsilon = 1e-9 func float64Ptr(f float64) *float64 { return &f } + func int64Ptr(f int64) *int64 { return &f } -var header = Header{ +var header = Header{ //nolint:gochecknoglobals // test fixture VendorExtensible: VendorExtensible{Extensions: map[string]any{ "x-framework": "swagger-go", }}, @@ -74,11 +74,7 @@ const headerJSON = `{ }` func TestIntegrationHeader(t *testing.T) { - var actual Header - require.NoError(t, json.Unmarshal([]byte(headerJSON), &actual)) - assert.Equal(t, actual, header) - - assertParsesJSON(t, headerJSON, header) + assert.JSONUnmarshalAsT(t, header, headerJSON) } func TestJSONLookupHeader(t *testing.T) { @@ -90,8 +86,8 @@ func TestJSONLookupHeader(t *testing.T) { var ok bool def, ok = res.(string) - require.True(t, ok) - assert.Equal(t, "8", def) + require.TrueT(t, ok) + assert.EqualT(t, "8", def) var x *any res, err = header.JSONLookup("x-framework") @@ -100,7 +96,7 @@ func TestJSONLookupHeader(t *testing.T) { require.IsType(t, x, res) x, ok = res.(*any) - require.True(t, ok) + require.TrueT(t, ok) assert.EqualValues(t, "swagger-go", *x) res, err = header.JSONLookup("unknown") @@ -114,8 +110,8 @@ func TestJSONLookupHeader(t *testing.T) { require.IsType(t, maximum, res) maximum, ok = res.(*float64) - require.True(t, ok) - assert.InDelta(t, float64(100), *maximum, epsilon) + require.TrueT(t, ok) + assert.InDeltaT(t, float64(100), *maximum, epsilon) } func TestResponseHeaueder(t *testing.T) { @@ -126,20 +122,20 @@ func TestResponseHeaueder(t *testing.T) { func TestWithHeader(t *testing.T) { h := new(Header).WithDescription("header description").Typed("integer", "int32") - assert.Equal(t, "header description", h.Description) - assert.Equal(t, "integer", h.Type) - assert.Equal(t, "int32", h.Format) + assert.EqualT(t, "header description", h.Description) + assert.EqualT(t, "integer", h.Type) + assert.EqualT(t, "int32", h.Format) i := new(Items).Typed("string", "date") h = new(Header).CollectionOf(i, "pipe") assert.Equal(t, *i, *h.Items) - assert.Equal(t, "pipe", h.CollectionFormat) + assert.EqualT(t, "pipe", h.CollectionFormat) h = new(Header).WithDefault([]string{"a", "b", "c"}).WithMaxLength(10).WithMinLength(3) - assert.Equal(t, int64(10), *h.MaxLength) - assert.Equal(t, int64(3), *h.MinLength) + assert.EqualT(t, int64(10), *h.MaxLength) + assert.EqualT(t, int64(3), *h.MinLength) assert.EqualValues(t, []string{"a", "b", "c"}, h.Default) h = new(Header).WithPattern("^abc$") diff --git a/helpers_spec_test.go b/helpers_spec_test.go index a2c542e6..7d5374f6 100644 --- a/helpers_spec_test.go +++ b/helpers_spec_test.go @@ -18,10 +18,10 @@ import ( var ( rex = regexp.MustCompile(`"\$ref":\s*"(.*?)"`) - testLoader func(string) (json.RawMessage, error) + testLoader func(string) (json.RawMessage, error) //nolint:gochecknoglobals // test fixture ) -func init() { +func init() { //nolint:gochecknoinits // sets up test loader for spec loading fixtures // mimics what the go-openapi/load does testLoader = func(path string) (json.RawMessage, error) { if loading.YAMLMatcher(path) { @@ -51,7 +51,7 @@ func assertRefInJSON(t testing.TB, jazon, prefix string) { for _, matched := range m { subMatch := matched[1] - assert.True(t, strings.HasPrefix(subMatch, prefix), + assert.TrueT(t, strings.HasPrefix(subMatch, prefix), "expected $ref to match %q, got: %s", prefix, matched[0]) } } @@ -66,7 +66,7 @@ func assertRefInJSONRegexp(t testing.TB, jazon, match string) { for _, matched := range m { subMatch := matched[1] - assert.True(t, refMatch.MatchString(subMatch), + assert.TrueT(t, refMatch.MatchString(subMatch), "expected $ref to match %q, got: %s", match, matched[0]) } } @@ -146,7 +146,7 @@ func asJSON(t testing.TB, sp any) string { return string(bbb) } -// assertNoRef ensures that no $ref is remaining in json doc +// assertNoRef ensures that no $ref is remaining in json doc. func assertNoRef(t testing.TB, jazon string) { m := rex.FindAllStringSubmatch(jazon, -1) require.Nil(t, m) diff --git a/helpers_test.go b/helpers_test.go index 6eab8ea5..06ab941d 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -6,6 +6,10 @@ package spec import ( "encoding/json" "fmt" + "io/fs" + "net/http" + "net/http/httptest" + "path/filepath" "regexp" "strings" "testing" @@ -17,6 +21,22 @@ import ( var rex = regexp.MustCompile(`"\$ref":\s*"(.*?)"`) +// fixtureServer returns an httptest.Server serving the given subdirectory +// from the embedded fixtureAssets FS. This avoids OS-level file serving +// (and the Windows TransmitFile/sendfile code path that has a data race +// in Go 1.26). +func fixtureServer(t testing.TB, dir string) *httptest.Server { + t.Helper() + + sub, err := fs.Sub(fixtureAssets, filepath.ToSlash(dir)) + require.NoError(t, err) + + server := httptest.NewServer(http.FileServerFS(sub)) + t.Cleanup(server.Close) + + return server +} + func jsonDoc(path string) (json.RawMessage, error) { data, err := loading.LoadFromFileOrHTTP(path) if err != nil { @@ -76,7 +96,7 @@ func assertRefInJSON(t testing.TB, jazon, prefix string) { for _, matched := range m { subMatch := matched[1] - assert.True(t, strings.HasPrefix(subMatch, prefix), + assert.TrueT(t, strings.HasPrefix(subMatch, prefix), "expected $ref to match %q, got: %s", prefix, matched[0]) } } @@ -94,12 +114,12 @@ func assertRefInJSONRegexp(t testing.TB, jazon, match string) { for _, matched := range m { subMatch := matched[1] - assert.True(t, refMatch.MatchString(subMatch), + assert.TrueT(t, refMatch.MatchString(subMatch), "expected $ref to match %q, got: %s", match, matched[0]) } } -// assertNoRef ensures that no $ref is remaining in json doc +// assertNoRef ensures that no $ref is remaining in json doc. func assertNoRef(t testing.TB, jazon string) { m := rex.FindAllStringSubmatch(jazon, -1) require.Nil(t, m) diff --git a/info.go b/info.go index 9401065b..0ccfdccc 100644 --- a/info.go +++ b/info.go @@ -12,16 +12,16 @@ import ( "github.com/go-openapi/swag/jsonutils" ) -// Extensions vendor specific extensions +// Extensions vendor specific extensions. type Extensions map[string]any -// Add adds a value to these extensions +// Add adds a value to these extensions. func (e Extensions) Add(key string, value any) { realKey := strings.ToLower(key) e[realKey] = value } -// GetString gets a string value from the extensions +// GetString gets a string value from the extensions. func (e Extensions) GetString(key string) (string, bool) { if v, ok := e[strings.ToLower(key)]; ok { str, ok := v.(string) @@ -30,7 +30,7 @@ func (e Extensions) GetString(key string) (string, bool) { return "", false } -// GetInt gets a int value from the extensions +// GetInt gets a int value from the extensions. func (e Extensions) GetInt(key string) (int, bool) { realKey := strings.ToLower(key) @@ -48,7 +48,7 @@ func (e Extensions) GetInt(key string) (int, bool) { return -1, false } -// GetBool gets a string value from the extensions +// GetBool gets a string value from the extensions. func (e Extensions) GetBool(key string) (bool, bool) { if v, ok := e[strings.ToLower(key)]; ok { str, ok := v.(bool) @@ -57,7 +57,7 @@ func (e Extensions) GetBool(key string) (bool, bool) { return false, false } -// GetStringSlice gets a string value from the extensions +// GetStringSlice gets a string value from the extensions. func (e Extensions) GetStringSlice(key string) ([]string, bool) { if v, ok := e[strings.ToLower(key)]; ok { arr, isSlice := v.([]any) @@ -82,7 +82,7 @@ type VendorExtensible struct { Extensions Extensions } -// AddExtension adds an extension to this extensible object +// AddExtension adds an extension to this extensible object. func (v *VendorExtensible) AddExtension(key string, value any) { if value == nil { return @@ -93,7 +93,7 @@ func (v *VendorExtensible) AddExtension(key string, value any) { v.Extensions.Add(key, value) } -// MarshalJSON marshals the extensions to json +// MarshalJSON marshals the extensions to json. func (v VendorExtensible) MarshalJSON() ([]byte, error) { toser := make(map[string]any) for k, v := range v.Extensions { @@ -105,7 +105,7 @@ func (v VendorExtensible) MarshalJSON() ([]byte, error) { return json.Marshal(toser) } -// UnmarshalJSON for this extensible object +// UnmarshalJSON for this extensible object. func (v *VendorExtensible) UnmarshalJSON(data []byte) error { var d map[string]any if err := json.Unmarshal(data, &d); err != nil { @@ -123,7 +123,7 @@ func (v *VendorExtensible) UnmarshalJSON(data []byte) error { return nil } -// InfoProps the properties for an info definition +// InfoProps the properties for an info definition. type InfoProps struct { Description string `json:"description,omitempty"` Title string `json:"title,omitempty"` @@ -142,7 +142,7 @@ type Info struct { InfoProps } -// JSONLookup look up a value by the json property name +// JSONLookup look up a value by the json property name. func (i Info) JSONLookup(token string) (any, error) { if ex, ok := i.Extensions[token]; ok { return &ex, nil @@ -151,7 +151,7 @@ func (i Info) JSONLookup(token string) (any, error) { return r, err } -// MarshalJSON marshal this to JSON +// MarshalJSON marshal this to JSON. func (i Info) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(i.InfoProps) if err != nil { @@ -164,7 +164,7 @@ func (i Info) MarshalJSON() ([]byte, error) { return jsonutils.ConcatJSON(b1, b2), nil } -// UnmarshalJSON marshal this from JSON +// UnmarshalJSON marshal this from JSON. func (i *Info) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &i.InfoProps); err != nil { return err diff --git a/info_test.go b/info_test.go index 6185d641..8ebace52 100644 --- a/info_test.go +++ b/info_test.go @@ -28,7 +28,7 @@ const infoJSON = `{ "x-framework": "go-swagger" }` -var testInfo = Info{ +var testInfo = Info{ //nolint:gochecknoglobals // test fixture InfoProps: InfoProps{ Version: "1.0.9-abcd", Title: "Swagger Sample API", @@ -36,10 +36,11 @@ var testInfo = Info{ "the swagger-2.0 specification", TermsOfService: "http://helloreverb.com/terms/", Contact: &ContactInfo{ContactInfoProps: ContactInfoProps{Name: "wordnik api team", URL: "http://developer.wordnik.com"}}, - License: &License{LicenseProps: LicenseProps{ - Name: "Creative Commons 4.0 International", - URL: "http://creativecommons.org/licenses/by/4.0/", - }, + License: &License{ + LicenseProps: LicenseProps{ + Name: "Creative Commons 4.0 International", + URL: "http://creativecommons.org/licenses/by/4.0/", + }, }, }, VendorExtensible: VendorExtensible{Extensions: map[string]any{"x-framework": "go-swagger"}}, @@ -47,15 +48,11 @@ var testInfo = Info{ func TestInfo(t *testing.T) { t.Run("should marshal Info", func(t *testing.T) { - b, err := json.MarshalIndent(testInfo, "", "\t") - require.NoError(t, err) - assert.JSONEq(t, infoJSON, string(b)) + assert.JSONMarshalAsT(t, infoJSON, testInfo) }) t.Run("should unmarshal Info", func(t *testing.T) { - actual := Info{} - require.NoError(t, json.Unmarshal([]byte(infoJSON), &actual)) - assert.Equal(t, testInfo, actual) + assert.JSONUnmarshalAsT(t, testInfo, infoJSON) }) t.Run("should GobEncode Info", func(t *testing.T) { diff --git a/items.go b/items.go index d30ca356..daf5a4fd 100644 --- a/items.go +++ b/items.go @@ -15,7 +15,7 @@ const ( jsonRef = "$ref" ) -// SimpleSchema describe swagger simple schemas for parameters and headers +// SimpleSchema describe swagger simple schemas for parameters and headers. type SimpleSchema struct { Type string `json:"type,omitempty"` Nullable bool `json:"nullable,omitempty"` @@ -26,7 +26,7 @@ type SimpleSchema struct { Example any `json:"example,omitempty"` } -// TypeName return the type (or format) of a simple schema +// TypeName return the type (or format) of a simple schema. func (s *SimpleSchema) TypeName() string { if s.Format != "" { return s.Format @@ -34,7 +34,7 @@ func (s *SimpleSchema) TypeName() string { return s.Type } -// ItemsTypeName yields the type of items in a simple schema array +// ItemsTypeName yields the type of items in a simple schema array. func (s *SimpleSchema) ItemsTypeName() string { if s.Items == nil { return "" @@ -53,12 +53,12 @@ type Items struct { VendorExtensible } -// NewItems creates a new instance of items +// NewItems creates a new instance of items. func NewItems() *Items { return &Items{} } -// Typed a fluent builder method for the type of item +// Typed a fluent builder method for the type of item. func (i *Items) Typed(tpe, format string) *Items { i.Type = tpe i.Format = format @@ -71,7 +71,7 @@ func (i *Items) AsNullable() *Items { return i } -// CollectionOf a fluent builder method for an array item +// CollectionOf a fluent builder method for an array item. func (i *Items) CollectionOf(items *Items, format string) *Items { i.Type = jsonArray i.Items = items @@ -79,87 +79,87 @@ func (i *Items) CollectionOf(items *Items, format string) *Items { return i } -// WithDefault sets the default value on this item +// WithDefault sets the default value on this item. func (i *Items) WithDefault(defaultValue any) *Items { i.Default = defaultValue return i } -// WithMaxLength sets a max length value +// WithMaxLength sets a max length value. func (i *Items) WithMaxLength(maximum int64) *Items { i.MaxLength = &maximum return i } -// WithMinLength sets a min length value +// WithMinLength sets a min length value. func (i *Items) WithMinLength(minimum int64) *Items { i.MinLength = &minimum return i } -// WithPattern sets a pattern value +// WithPattern sets a pattern value. func (i *Items) WithPattern(pattern string) *Items { i.Pattern = pattern return i } -// WithMultipleOf sets a multiple of value +// WithMultipleOf sets a multiple of value. func (i *Items) WithMultipleOf(number float64) *Items { i.MultipleOf = &number return i } -// WithMaximum sets a maximum number value +// WithMaximum sets a maximum number value. func (i *Items) WithMaximum(maximum float64, exclusive bool) *Items { i.Maximum = &maximum i.ExclusiveMaximum = exclusive return i } -// WithMinimum sets a minimum number value +// WithMinimum sets a minimum number value. func (i *Items) WithMinimum(minimum float64, exclusive bool) *Items { i.Minimum = &minimum i.ExclusiveMinimum = exclusive return i } -// WithEnum sets a the enum values (replace) +// WithEnum sets a the enum values (replace). func (i *Items) WithEnum(values ...any) *Items { i.Enum = append([]any{}, values...) return i } -// WithMaxItems sets the max items +// WithMaxItems sets the max items. func (i *Items) WithMaxItems(size int64) *Items { i.MaxItems = &size return i } -// WithMinItems sets the min items +// WithMinItems sets the min items. func (i *Items) WithMinItems(size int64) *Items { i.MinItems = &size return i } -// UniqueValues dictates that this array can only have unique items +// UniqueValues dictates that this array can only have unique items. func (i *Items) UniqueValues() *Items { i.UniqueItems = true return i } -// AllowDuplicates this array can have duplicates +// AllowDuplicates this array can have duplicates. func (i *Items) AllowDuplicates() *Items { i.UniqueItems = false return i } -// WithValidations is a fluent method to set Items validations +// WithValidations is a fluent method to set Items validations. func (i *Items) WithValidations(val CommonValidations) *Items { i.SetValidations(SchemaValidations{CommonValidations: val}) return i } -// UnmarshalJSON hydrates this items instance with the data from JSON +// UnmarshalJSON hydrates this items instance with the data from JSON. func (i *Items) UnmarshalJSON(data []byte) error { var validations CommonValidations if err := json.Unmarshal(data, &validations); err != nil { @@ -184,7 +184,7 @@ func (i *Items) UnmarshalJSON(data []byte) error { return nil } -// MarshalJSON converts this items object to JSON +// MarshalJSON converts this items object to JSON. func (i Items) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(i.CommonValidations) if err != nil { @@ -205,7 +205,7 @@ func (i Items) MarshalJSON() ([]byte, error) { return jsonutils.ConcatJSON(b4, b3, b1, b2), nil } -// JSONLookup look up a value by the json property name +// JSONLookup look up a value by the json property name. func (i Items) JSONLookup(token string) (any, error) { if token == jsonRef { return &i.Ref, nil diff --git a/items_test.go b/items_test.go index c5c585cd..e59d033b 100644 --- a/items_test.go +++ b/items_test.go @@ -4,7 +4,6 @@ package spec import ( - "encoding/json" "testing" "github.com/go-openapi/swag/conv" @@ -12,7 +11,7 @@ import ( "github.com/go-openapi/testify/v2/require" ) -var testItems = Items{ +var testItems = Items{ //nolint:gochecknoglobals // test fixture Refable: Refable{Ref: MustCreateRef("Dog")}, CommonValidations: CommonValidations{ Maximum: float64Ptr(100), @@ -63,18 +62,14 @@ const itemsJSON = `{ }` func TestIntegrationItems(t *testing.T) { - var actual Items - require.NoError(t, json.Unmarshal([]byte(itemsJSON), &actual)) - assert.Equal(t, actual, testItems) - - assertParsesJSON(t, itemsJSON, testItems) + assert.JSONUnmarshalAsT(t, testItems, itemsJSON) } func TestTypeNameItems(t *testing.T) { var nilItems Items assert.Empty(t, nilItems.TypeName()) - assert.Equal(t, "date", testItems.TypeName()) + assert.EqualT(t, "date", testItems.TypeName()) assert.Empty(t, testItems.ItemsTypeName()) nested := Items{ @@ -90,23 +85,23 @@ func TestTypeNameItems(t *testing.T) { }, } - assert.Equal(t, "array", nested.TypeName()) - assert.Equal(t, "int32", nested.ItemsTypeName()) + assert.EqualT(t, "array", nested.TypeName()) + assert.EqualT(t, "int32", nested.ItemsTypeName()) simple := SimpleSchema{ Type: "string", Items: nil, } - assert.Equal(t, "string", simple.TypeName()) + assert.EqualT(t, "string", simple.TypeName()) assert.Empty(t, simple.ItemsTypeName()) simple.Items = NewItems() simple.Type = "array" simple.Items.Type = "string" - assert.Equal(t, "array", simple.TypeName()) - assert.Equal(t, "string", simple.ItemsTypeName()) + assert.EqualT(t, "array", simple.TypeName()) + assert.EqualT(t, "string", simple.ItemsTypeName()) } func TestItemsBuilder(t *testing.T) { @@ -147,7 +142,7 @@ func TestJSONLookupItems(t *testing.T) { require.IsType(t, &Ref{}, res) ref, ok := res.(*Ref) - require.True(t, ok) + require.TrueT(t, ok) assert.Equal(t, MustCreateRef("Dog"), *ref) }) @@ -160,8 +155,8 @@ func TestJSONLookupItems(t *testing.T) { var ok bool maximum, ok = res.(*float64) - require.True(t, ok) - assert.InDelta(t, float64(100), *maximum, epsilon) + require.TrueT(t, ok) + assert.InDeltaT(t, float64(100), *maximum, epsilon) }) t.Run(`lookup should find "collectionFormat"`, func(t *testing.T) { @@ -172,8 +167,8 @@ func TestJSONLookupItems(t *testing.T) { require.IsType(t, f, res) f, ok := res.(string) - require.True(t, ok) - assert.Equal(t, "csv", f) + require.TrueT(t, ok) + assert.EqualT(t, "csv", f) }) t.Run(`lookup should fail on "unknown"`, func(t *testing.T) { diff --git a/license.go b/license.go index 286b237e..8209f218 100644 --- a/license.go +++ b/license.go @@ -17,13 +17,13 @@ type License struct { VendorExtensible } -// LicenseProps holds the properties of a License object +// LicenseProps holds the properties of a License object. type LicenseProps struct { Name string `json:"name,omitempty"` URL string `json:"url,omitempty"` } -// UnmarshalJSON hydrates License from json +// UnmarshalJSON hydrates License from json. func (l *License) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &l.LicenseProps); err != nil { return err @@ -31,7 +31,7 @@ func (l *License) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &l.VendorExtensible) } -// MarshalJSON produces License as json +// MarshalJSON produces License as json. func (l License) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(l.LicenseProps) if err != nil { diff --git a/license_test.go b/license_test.go index 1a197cb8..56f75b65 100644 --- a/license_test.go +++ b/license_test.go @@ -4,11 +4,9 @@ package spec import ( - "encoding/json" "testing" "github.com/go-openapi/testify/v2/assert" - "github.com/go-openapi/testify/v2/require" ) func TestIntegrationLicense(t *testing.T) { @@ -18,22 +16,18 @@ func TestIntegrationLicense(t *testing.T) { "x-license": "custom term" }` - var testLicense = License{ + testLicense := License{ LicenseProps: LicenseProps{Name: "the name", URL: "the url"}, - VendorExtensible: VendorExtensible{Extensions: map[string]any{"x-license": "custom term"}}} + VendorExtensible: VendorExtensible{Extensions: map[string]any{"x-license": "custom term"}}, + } // const licenseYAML = "name: the name\nurl: the url\n" t.Run("should marshal license", func(t *testing.T) { - b, err := json.MarshalIndent(testLicense, "", "\t") - require.NoError(t, err) - assert.JSONEq(t, licenseJSON, string(b)) + assert.JSONMarshalAsT(t, licenseJSON, testLicense) }) t.Run("should unmarshal empty license", func(t *testing.T) { - actual := License{} - err := json.Unmarshal([]byte(licenseJSON), &actual) - require.NoError(t, err) - assert.Equal(t, testLicense, actual) + assert.JSONUnmarshalAsT(t, testLicense, licenseJSON) }) } diff --git a/normalizer.go b/normalizer.go index e1d7c58d..68252dc3 100644 --- a/normalizer.go +++ b/normalizer.go @@ -138,7 +138,7 @@ func rebase(ref *Ref, v *url.URL, notEqual bool) (Ref, bool) { return MustCreateRef(newBase.String()), true } -// normalizeRef canonicalize a Ref, using a canonical relativeBase as its absolute anchor +// normalizeRef canonicalize a Ref, using a canonical relativeBase as its absolute anchor. func normalizeRef(ref *Ref, relativeBase string) *Ref { r := MustCreateRef(normalizeURI(ref.String(), relativeBase)) return &r diff --git a/normalizer_test.go b/normalizer_test.go index 48ab6bce..a7ab306c 100644 --- a/normalizer_test.go +++ b/normalizer_test.go @@ -17,10 +17,10 @@ import ( const windowsOS = "windows" -// only used for windows -var currentDriveLetter = getCurrentDrive() +// only used for windows. +var currentDriveLetter = getCurrentDrive() //nolint:gochecknoglobals // test fixture -// get the current drive letter in lowercase on windows that the test is running +// get the current drive letter in lowercase on windows that the test is running. func getCurrentDrive() string { if runtime.GOOS != windowsOS { return "" @@ -260,7 +260,7 @@ func TestNormalizer_NormalizeURI(t *testing.T) { t.Run(testCase.refPath, func(t *testing.T) { t.Parallel() out := normalizeURI(testCase.refPath, testCase.base) - assert.Equalf(t, testCase.expOutput, out, + assert.EqualTf(t, testCase.expOutput, out, "unexpected normalized URL with $ref %q and base %q", testCase.refPath, testCase.base) }) } @@ -295,7 +295,7 @@ func TestNormalizer_NormalizeBase(t *testing.T) { Base: ".", Expected: "file://$cwd", // edge case: this won't work because a document is a file }, - { + { //nolint:gosec // test data, not real credentials Base: "https://user:password@www.example.com:123/base/sub/file.json", Expected: "https://user:password@www.example.com:123/base/sub/file.json", }, @@ -466,10 +466,10 @@ func TestNormalizer_NormalizeBase(t *testing.T) { t.Run(testCase.Base, func(t *testing.T) { t.Parallel() expected := strings.ReplaceAll(strings.ReplaceAll(testCase.Expected, "$cwd", cwd), "$dir", path.Dir(cwd)) - require.Equalf(t, expected, normalizeBase(testCase.Base), "for base %q", testCase.Base) + require.EqualTf(t, expected, normalizeBase(testCase.Base), "for base %q", testCase.Base) // check for idempotence - require.Equalf(t, expected, normalizeBase(normalizeBase(testCase.Base)), + require.EqualTf(t, expected, normalizeBase(normalizeBase(testCase.Base)), "expected idempotent behavior on base %q", testCase.Base) }) } @@ -494,7 +494,7 @@ func TestNormalizer_Denormalize(t *testing.T) { Ref: "#/definitions/X", Expected: "#/definitions/X", }, - { + { //nolint:gosec // test data, not real credentials OriginalBase: "https://user:password@example.com/a/b/c/file.json", Ref: "https://user:password@example.com/a/b/c/other.json#/definitions/X", Expected: "other.json#/definitions/X", @@ -609,7 +609,7 @@ func TestNormalizer_Denormalize(t *testing.T) { ref := MustCreateRef(testCase.Ref) newRef := denormalizeRef(&ref, testCase.OriginalBase, testCase.ID) require.NotNil(t, newRef) - require.Equalf(t, expected, newRef.String(), + require.EqualTf(t, expected, newRef.String(), "expected %s, but got %s", testCase.Expected, newRef.String()) }) } diff --git a/operation.go b/operation.go index 29d9c4f4..cd70d254 100644 --- a/operation.go +++ b/operation.go @@ -13,7 +13,7 @@ import ( "github.com/go-openapi/swag/jsonutils" ) -func init() { +func init() { //nolint:gochecknoinits // registers gob types for Operation serialization gob.Register(map[string]any{}) gob.Register([]any{}) } @@ -22,7 +22,7 @@ func init() { // // NOTES: // - schemes, when present must be from [http, https, ws, wss]: see validate -// - Security is handled as a special case: see MarshalJSON function +// - Security is handled as a special case: see MarshalJSON function. type OperationProps struct { Description string `json:"description,omitempty"` Consumes []string `json:"consumes,omitempty"` @@ -82,7 +82,7 @@ func NewOperation(id string) *Operation { return op } -// SuccessResponse gets a success response model +// SuccessResponse gets a success response model. func (o *Operation) SuccessResponse() (*Response, int, bool) { if o.Responses == nil { return nil, 0, false @@ -103,7 +103,7 @@ func (o *Operation) SuccessResponse() (*Response, int, bool) { return o.Responses.Default, 0, false } -// JSONLookup look up a value by the json property name +// JSONLookup look up a value by the json property name. func (o Operation) JSONLookup(token string) (any, error) { if ex, ok := o.Extensions[token]; ok { return &ex, nil @@ -112,7 +112,7 @@ func (o Operation) JSONLookup(token string) (any, error) { return r, err } -// UnmarshalJSON hydrates this items instance with the data from JSON +// UnmarshalJSON hydrates this items instance with the data from JSON. func (o *Operation) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &o.OperationProps); err != nil { return err @@ -120,7 +120,7 @@ func (o *Operation) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &o.VendorExtensible) } -// MarshalJSON converts this items object to JSON +// MarshalJSON converts this items object to JSON. func (o Operation) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(o.OperationProps) if err != nil { @@ -140,13 +140,13 @@ func (o *Operation) WithID(id string) *Operation { return o } -// WithDescription sets the description on this operation, allows for chaining +// WithDescription sets the description on this operation, allows for chaining. func (o *Operation) WithDescription(description string) *Operation { o.Description = description return o } -// WithSummary sets the summary on this operation, allows for chaining +// WithSummary sets the summary on this operation, allows for chaining. func (o *Operation) WithSummary(summary string) *Operation { o.Summary = summary return o @@ -170,38 +170,38 @@ func (o *Operation) WithExternalDocs(description, url string) *Operation { return o } -// Deprecate marks the operation as deprecated +// Deprecate marks the operation as deprecated. func (o *Operation) Deprecate() *Operation { o.Deprecated = true return o } -// Undeprecate marks the operation as not deprecated +// Undeprecate marks the operation as not deprecated. func (o *Operation) Undeprecate() *Operation { o.Deprecated = false return o } -// WithConsumes adds media types for incoming body values +// WithConsumes adds media types for incoming body values. func (o *Operation) WithConsumes(mediaTypes ...string) *Operation { o.Consumes = append(o.Consumes, mediaTypes...) return o } -// WithProduces adds media types for outgoing body values +// WithProduces adds media types for outgoing body values. func (o *Operation) WithProduces(mediaTypes ...string) *Operation { o.Produces = append(o.Produces, mediaTypes...) return o } -// WithTags adds tags for this operation +// WithTags adds tags for this operation. func (o *Operation) WithTags(tags ...string) *Operation { o.Tags = append(o.Tags, tags...) return o } // AddParam adds a parameter to this operation, when a parameter for that location -// and with that name already exists it will be replaced +// and with that name already exists it will be replaced. func (o *Operation) AddParam(param *Parameter) *Operation { if param == nil { return o @@ -223,7 +223,7 @@ func (o *Operation) AddParam(param *Parameter) *Operation { return o } -// RemoveParam removes a parameter from the operation +// RemoveParam removes a parameter from the operation. func (o *Operation) RemoveParam(name, in string) *Operation { for i, p := range o.Parameters { if p.Name == name && p.In == in { @@ -241,14 +241,14 @@ func (o *Operation) SecuredWith(name string, scopes ...string) *Operation { } // WithDefaultResponse adds a default response to the operation. -// Passing a nil value will remove the response +// Passing a nil value will remove the response. func (o *Operation) WithDefaultResponse(response *Response) *Operation { return o.RespondsWith(0, response) } // RespondsWith adds a status code response to the operation. // When the code is 0 the value of the response will be used as default response value. -// When the value of the response is nil it will be removed from the operation +// When the value of the response is nil it will be removed from the operation. func (o *Operation) RespondsWith(code int, response *Response) *Operation { if o.Responses == nil { o.Responses = new(Responses) @@ -279,7 +279,7 @@ type gobAlias struct { SecurityIsEmpty bool } -// GobEncode provides a safe gob encoder for Operation, including empty security requirements +// GobEncode provides a safe gob encoder for Operation, including empty security requirements. func (o Operation) GobEncode() ([]byte, error) { raw := struct { Ext VendorExtensible @@ -293,7 +293,7 @@ func (o Operation) GobEncode() ([]byte, error) { return b.Bytes(), err } -// GobDecode provides a safe gob decoder for Operation, including empty security requirements +// GobDecode provides a safe gob decoder for Operation, including empty security requirements. func (o *Operation) GobDecode(b []byte) error { var raw struct { Ext VendorExtensible @@ -310,7 +310,7 @@ func (o *Operation) GobDecode(b []byte) error { return nil } -// GobEncode provides a safe gob encoder for Operation, including empty security requirements +// GobEncode provides a safe gob encoder for Operation, including empty security requirements. func (op OperationProps) GobEncode() ([]byte, error) { raw := gobAlias{ Alias: (*opsAlias)(&op), @@ -355,7 +355,7 @@ func (op OperationProps) GobEncode() ([]byte, error) { return b.Bytes(), err } -// GobDecode provides a safe gob decoder for Operation, including empty security requirements +// GobDecode provides a safe gob decoder for Operation, including empty security requirements. func (op *OperationProps) GobDecode(b []byte) error { var raw gobAlias diff --git a/operation_test.go b/operation_test.go index bd1d2b54..965b50e4 100644 --- a/operation_test.go +++ b/operation_test.go @@ -13,7 +13,7 @@ import ( "github.com/go-openapi/testify/v2/require" ) -var operation = Operation{ +var operation = Operation{ //nolint:gochecknoglobals // test fixture VendorExtensible: VendorExtensible{ Extensions: map[string]any{ "x-framework": "go-swagger", @@ -71,15 +71,15 @@ func TestSuccessResponse(t *testing.T) { ope := &Operation{} resp, n, f := ope.SuccessResponse() assert.Nil(t, resp) - assert.Equal(t, 0, n) - assert.False(t, f) + assert.EqualT(t, 0, n) + assert.FalseT(t, f) resp, n, f = operation.SuccessResponse() require.NotNil(t, resp) - assert.Equal(t, "void response", resp.Description) + assert.EqualT(t, "void response", resp.Description) - assert.Equal(t, 0, n) - assert.False(t, f) + assert.EqualT(t, 0, n) + assert.FalseT(t, f) require.NoError(t, json.Unmarshal([]byte(operationJSON), ope)) @@ -90,10 +90,10 @@ func TestSuccessResponse(t *testing.T) { }) resp, n, f = ope.SuccessResponse() require.NotNil(t, resp) - assert.Equal(t, "void response", resp.Description) + assert.EqualT(t, "void response", resp.Description) - assert.Equal(t, 0, n) - assert.False(t, f) + assert.EqualT(t, 0, n) + assert.FalseT(t, f) ope = ope.RespondsWith(200, &Response{ ResponseProps: ResponseProps{ @@ -103,10 +103,10 @@ func TestSuccessResponse(t *testing.T) { resp, n, f = ope.SuccessResponse() require.NotNil(t, resp) - assert.Equal(t, "success", resp.Description) + assert.EqualT(t, "success", resp.Description) - assert.Equal(t, 200, n) - assert.True(t, f) + assert.EqualT(t, 200, n) + assert.TrueT(t, f) } func TestOperationBuilder(t *testing.T) { @@ -134,10 +134,7 @@ func TestOperationBuilder(t *testing.T) { WithSummary("my summary"). WithExternalDocs("some doc", "https://www.example.com") - jazon, err := json.MarshalIndent(ope, "", " ") - require.NoError(t, err) - - assert.JSONEq(t, `{ + assert.JSONMarshalAsT(t, `{ "operationId": "operationID", "description": "test operation", "summary": "my summary", @@ -187,23 +184,20 @@ func TestOperationBuilder(t *testing.T) { "description": "default" } } - }`, string(jazon)) + }`, ope) // check token lookup token, err := ope.JSONLookup("responses") require.NoError(t, err) - jazon, err = json.MarshalIndent(token, "", " ") - require.NoError(t, err) - - assert.JSONEq(t, `{ + assert.JSONMarshalAsT(t, `{ "200": { "description": "success" }, "default": { "description": "default" } - }`, string(jazon)) + }`, token) // check delete methods ope = ope.RespondsWith(200, nil). @@ -212,10 +206,8 @@ func TestOperationBuilder(t *testing.T) { RemoveParam("fakeParam", "query"). Undeprecate(). WithExternalDocs("", "") - jazon, err = json.MarshalIndent(ope, "", " ") - require.NoError(t, err) - assert.JSONEq(t, `{ + assert.JSONMarshalAsT(t, `{ "security": [ { "scheme-name": [ @@ -242,15 +234,11 @@ func TestOperationBuilder(t *testing.T) { "description": "default" } } - }`, string(jazon)) + }`, ope) } func TestIntegrationOperation(t *testing.T) { - var actual Operation - require.NoError(t, json.Unmarshal([]byte(operationJSON), &actual)) - assert.Equal(t, actual, operation) - - assertParsesJSON(t, operationJSON, operation) + assert.JSONUnmarshalAsT(t, operation, operationJSON) } func TestSecurityProperty(t *testing.T) { @@ -258,7 +246,7 @@ func TestSecurityProperty(t *testing.T) { securityNotSet := OperationProps{} jsonResult, err := json.Marshal(securityNotSet) require.NoError(t, err) - assert.NotContains(t, string(jsonResult), "security", "security key should be omitted when unset") + assert.StringNotContainsT(t, string(jsonResult), "security", "security key should be omitted when unset") // Ensure we preserve the security key when it contains an empty (zero length) slice securityContainsEmptyArray := OperationProps{ @@ -344,10 +332,11 @@ func doTestOperationGobEncoding(t *testing.T, fixture string) { } func doTestAnyGobEncoding(t *testing.T, src, dst any) { - expectedJSON, _ := json.MarshalIndent(src, "", " ") + expectedJSON, err := json.MarshalIndent(src, "", " ") + require.NoError(t, err) var b bytes.Buffer - err := gob.NewEncoder(&b).Encode(src) + err = gob.NewEncoder(&b).Encode(src) require.NoError(t, err) err = gob.NewDecoder(&b).Decode(dst) @@ -355,5 +344,5 @@ func doTestAnyGobEncoding(t *testing.T, src, dst any) { jazon, err := json.MarshalIndent(dst, "", " ") require.NoError(t, err) - assert.JSONEq(t, string(expectedJSON), string(jazon)) + assert.JSONEqT(t, string(expectedJSON), string(jazon)) } diff --git a/parameter.go b/parameter.go index b94b7682..516f5d95 100644 --- a/parameter.go +++ b/parameter.go @@ -11,45 +11,51 @@ import ( "github.com/go-openapi/swag/jsonutils" ) -// QueryParam creates a query parameter +// QueryParam creates a query parameter. func QueryParam(name string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "query"}} } -// HeaderParam creates a header parameter, this is always required by default +// HeaderParam creates a header parameter, this is always required by default. func HeaderParam(name string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "header", Required: true}} } -// PathParam creates a path parameter, this is always required +// PathParam creates a path parameter, this is always required. func PathParam(name string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "path", Required: true}} } -// BodyParam creates a body parameter +// BodyParam creates a body parameter. func BodyParam(name string, schema *Schema) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "body", Schema: schema}} } -// FormDataParam creates a body parameter +// FormDataParam creates a body parameter. func FormDataParam(name string) *Parameter { return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}} } -// FileParam creates a body parameter +// FileParam creates a body parameter. func FileParam(name string) *Parameter { - return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}, - SimpleSchema: SimpleSchema{Type: "file"}} + return &Parameter{ + ParamProps: ParamProps{Name: name, In: "formData"}, + SimpleSchema: SimpleSchema{Type: "file"}, + } } -// SimpleArrayParam creates a param for a simple array (string, int, date etc) +// SimpleArrayParam creates a param for a simple array (string, int, date etc). func SimpleArrayParam(name, tpe, fmt string) *Parameter { - return &Parameter{ParamProps: ParamProps{Name: name}, - SimpleSchema: SimpleSchema{Type: jsonArray, CollectionFormat: "csv", - Items: &Items{SimpleSchema: SimpleSchema{Type: tpe, Format: fmt}}}} + return &Parameter{ + ParamProps: ParamProps{Name: name}, + SimpleSchema: SimpleSchema{ + Type: jsonArray, CollectionFormat: "csv", + Items: &Items{SimpleSchema: SimpleSchema{Type: tpe, Format: fmt}}, + }, + } } -// ParamRef creates a parameter that's a json reference +// ParamRef creates a parameter that's a json reference. func ParamRef(uri string) *Parameter { p := new(Parameter) p.Ref = MustCreateRef(uri) @@ -60,7 +66,7 @@ func ParamRef(uri string) *Parameter { // // NOTE: // - Schema is defined when "in" == "body": see validate -// - AllowEmptyValue is allowed where "in" == "query" || "formData" +// - AllowEmptyValue is allowed where "in" == "query" || "formData". type ParamProps struct { Description string `json:"description,omitempty"` Name string `json:"name,omitempty"` @@ -104,7 +110,7 @@ type Parameter struct { ParamProps } -// JSONLookup look up a value by the json property name +// JSONLookup look up a value by the json property name. func (p Parameter) JSONLookup(token string) (any, error) { if ex, ok := p.Extensions[token]; ok { return &ex, nil @@ -131,32 +137,32 @@ func (p Parameter) JSONLookup(token string) (any, error) { return r, err } -// WithDescription a fluent builder method for the description of the parameter +// WithDescription a fluent builder method for the description of the parameter. func (p *Parameter) WithDescription(description string) *Parameter { p.Description = description return p } -// Named a fluent builder method to override the name of the parameter +// Named a fluent builder method to override the name of the parameter. func (p *Parameter) Named(name string) *Parameter { p.Name = name return p } -// WithLocation a fluent builder method to override the location of the parameter +// WithLocation a fluent builder method to override the location of the parameter. func (p *Parameter) WithLocation(in string) *Parameter { p.In = in return p } -// Typed a fluent builder method for the type of the parameter value +// Typed a fluent builder method for the type of the parameter value. func (p *Parameter) Typed(tpe, format string) *Parameter { p.Type = tpe p.Format = format return p } -// CollectionOf a fluent builder method for an array parameter +// CollectionOf a fluent builder method for an array parameter. func (p *Parameter) CollectionOf(items *Items, format string) *Parameter { p.Type = jsonArray p.Items = items @@ -164,32 +170,32 @@ func (p *Parameter) CollectionOf(items *Items, format string) *Parameter { return p } -// WithDefault sets the default value on this parameter +// WithDefault sets the default value on this parameter. func (p *Parameter) WithDefault(defaultValue any) *Parameter { p.AsOptional() // with default implies optional p.Default = defaultValue return p } -// AllowsEmptyValues flags this parameter as being ok with empty values +// AllowsEmptyValues flags this parameter as being ok with empty values. func (p *Parameter) AllowsEmptyValues() *Parameter { p.AllowEmptyValue = true return p } -// NoEmptyValues flags this parameter as not liking empty values +// NoEmptyValues flags this parameter as not liking empty values. func (p *Parameter) NoEmptyValues() *Parameter { p.AllowEmptyValue = false return p } -// AsOptional flags this parameter as optional +// AsOptional flags this parameter as optional. func (p *Parameter) AsOptional() *Parameter { p.Required = false return p } -// AsRequired flags this parameter as required +// AsRequired flags this parameter as required. func (p *Parameter) AsRequired() *Parameter { if p.Default != nil { // with a default required makes no sense return p @@ -198,81 +204,81 @@ func (p *Parameter) AsRequired() *Parameter { return p } -// WithMaxLength sets a max length value +// WithMaxLength sets a max length value. func (p *Parameter) WithMaxLength(maximum int64) *Parameter { p.MaxLength = &maximum return p } -// WithMinLength sets a min length value +// WithMinLength sets a min length value. func (p *Parameter) WithMinLength(minimum int64) *Parameter { p.MinLength = &minimum return p } -// WithPattern sets a pattern value +// WithPattern sets a pattern value. func (p *Parameter) WithPattern(pattern string) *Parameter { p.Pattern = pattern return p } -// WithMultipleOf sets a multiple of value +// WithMultipleOf sets a multiple of value. func (p *Parameter) WithMultipleOf(number float64) *Parameter { p.MultipleOf = &number return p } -// WithMaximum sets a maximum number value +// WithMaximum sets a maximum number value. func (p *Parameter) WithMaximum(maximum float64, exclusive bool) *Parameter { p.Maximum = &maximum p.ExclusiveMaximum = exclusive return p } -// WithMinimum sets a minimum number value +// WithMinimum sets a minimum number value. func (p *Parameter) WithMinimum(minimum float64, exclusive bool) *Parameter { p.Minimum = &minimum p.ExclusiveMinimum = exclusive return p } -// WithEnum sets a the enum values (replace) +// WithEnum sets a the enum values (replace). func (p *Parameter) WithEnum(values ...any) *Parameter { p.Enum = append([]any{}, values...) return p } -// WithMaxItems sets the max items +// WithMaxItems sets the max items. func (p *Parameter) WithMaxItems(size int64) *Parameter { p.MaxItems = &size return p } -// WithMinItems sets the min items +// WithMinItems sets the min items. func (p *Parameter) WithMinItems(size int64) *Parameter { p.MinItems = &size return p } -// UniqueValues dictates that this array can only have unique items +// UniqueValues dictates that this array can only have unique items. func (p *Parameter) UniqueValues() *Parameter { p.UniqueItems = true return p } -// AllowDuplicates this array can have duplicates +// AllowDuplicates this array can have duplicates. func (p *Parameter) AllowDuplicates() *Parameter { p.UniqueItems = false return p } -// WithValidations is a fluent method to set parameter validations +// WithValidations is a fluent method to set parameter validations. func (p *Parameter) WithValidations(val CommonValidations) *Parameter { p.SetValidations(SchemaValidations{CommonValidations: val}) return p } -// UnmarshalJSON hydrates this items instance with the data from JSON +// UnmarshalJSON hydrates this items instance with the data from JSON. func (p *Parameter) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &p.CommonValidations); err != nil { return err @@ -289,7 +295,7 @@ func (p *Parameter) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &p.ParamProps) } -// MarshalJSON converts this items object to JSON +// MarshalJSON converts this items object to JSON. func (p Parameter) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(p.CommonValidations) if err != nil { diff --git a/parameters_test.go b/parameters_test.go index 6f2f0f2d..9d8a7623 100644 --- a/parameters_test.go +++ b/parameters_test.go @@ -12,7 +12,7 @@ import ( "github.com/go-openapi/testify/v2/require" ) -var parameter = Parameter{ +var parameter = Parameter{ //nolint:gochecknoglobals // test fixture VendorExtensible: VendorExtensible{Extensions: map[string]any{ "x-framework": "swagger-go", }}, @@ -49,6 +49,7 @@ var parameter = Parameter{ }, } +//nolint:gochecknoglobals // test fixture var parameterJSON = `{ "items": { "$ref": "Cat" @@ -81,11 +82,7 @@ var parameterJSON = `{ }` func TestIntegrationParameter(t *testing.T) { - var actual Parameter - require.NoError(t, json.Unmarshal([]byte(parameterJSON), &actual)) - assert.Equal(t, actual, parameter) - - assertParsesJSON(t, parameterJSON, parameter) + assert.JSONUnmarshalAsT(t, parameter, parameterJSON) } func TestParameterSerialization(t *testing.T) { @@ -97,27 +94,28 @@ func TestParameterSerialization(t *testing.T) { SimpleSchema: SimpleSchema{Type: "int", Format: "int32"}, } - assertSerializeJSON(t, QueryParam("").Typed("string", ""), `{"type":"string","in":"query"}`) + assert.JSONMarshalAsT(t, `{"type":"string","in":"query"}`, QueryParam("").Typed("string", "")) + + assert.JSONMarshalAsT(t, + `{"type":"array","items":{"type":"string"},"collectionFormat":"multi","in":"query"}`, + QueryParam("").CollectionOf(items, "multi")) - assertSerializeJSON(t, - QueryParam("").CollectionOf(items, "multi"), - `{"type":"array","items":{"type":"string"},"collectionFormat":"multi","in":"query"}`) + assert.JSONMarshalAsT(t, `{"type":"string","in":"path","required":true}`, PathParam("").Typed("string", "")) - assertSerializeJSON(t, PathParam("").Typed("string", ""), `{"type":"string","in":"path","required":true}`) + assert.JSONMarshalAsT(t, + `{"type":"array","items":{"type":"string"},"collectionFormat":"multi","in":"path","required":true}`, + PathParam("").CollectionOf(items, "multi")) - assertSerializeJSON(t, - PathParam("").CollectionOf(items, "multi"), - `{"type":"array","items":{"type":"string"},"collectionFormat":"multi","in":"path","required":true}`) + assert.JSONMarshalAsT(t, + `{"type":"array","items":{"type":"int","format":"int32"},"collectionFormat":"multi","in":"path","required":true}`, + PathParam("").CollectionOf(intItems, "multi")) - assertSerializeJSON(t, - PathParam("").CollectionOf(intItems, "multi"), - `{"type":"array","items":{"type":"int","format":"int32"},"collectionFormat":"multi","in":"path","required":true}`) + assert.JSONMarshalAsT(t, `{"type":"string","in":"header","required":true}`, HeaderParam("").Typed("string", "")) - assertSerializeJSON(t, HeaderParam("").Typed("string", ""), `{"type":"string","in":"header","required":true}`) + assert.JSONMarshalAsT(t, + `{"type":"array","items":{"type":"string"},"collectionFormat":"multi","in":"header","required":true}`, + HeaderParam("").CollectionOf(items, "multi")) - assertSerializeJSON(t, - HeaderParam("").CollectionOf(items, "multi"), - `{"type":"array","items":{"type":"string"},"collectionFormat":"multi","in":"header","required":true}`) schema := &Schema{SchemaProps: SchemaProps{ Properties: map[string]Schema{ "name": {SchemaProps: SchemaProps{ @@ -130,19 +128,18 @@ func TestParameterSerialization(t *testing.T) { SchemaProps: SchemaProps{Ref: MustCreateRef("Cat")}, } - assertSerializeJSON(t, - BodyParam("", schema), - `{"in":"body","schema":{"properties":{"name":{"type":"string"}}}}`) + assert.JSONMarshalAsT(t, + `{"in":"body","schema":{"properties":{"name":{"type":"string"}}}}`, + BodyParam("", schema)) - assertSerializeJSON(t, - BodyParam("", refSchema), - `{"in":"body","schema":{"$ref":"Cat"}}`) + assert.JSONMarshalAsT(t, + `{"in":"body","schema":{"$ref":"Cat"}}`, + BodyParam("", refSchema)) // array body param - assertSerializeJSON(t, - BodyParam("", ArrayProperty(RefProperty("Cat"))), - `{"in":"body","schema":{"type":"array","items":{"$ref":"Cat"}}}`) - + assert.JSONMarshalAsT(t, + `{"in":"body","schema":{"type":"array","items":{"$ref":"Cat"}}}`, + BodyParam("", ArrayProperty(RefProperty("Cat")))) } func TestParameterGobEncoding(t *testing.T) { diff --git a/path_item.go b/path_item.go index c692b89e..4408ece4 100644 --- a/path_item.go +++ b/path_item.go @@ -10,7 +10,7 @@ import ( "github.com/go-openapi/swag/jsonutils" ) -// PathItemProps the path item specific properties +// PathItemProps the path item specific properties. type PathItemProps struct { Get *Operation `json:"get,omitempty"` Put *Operation `json:"put,omitempty"` @@ -34,7 +34,7 @@ type PathItem struct { PathItemProps } -// JSONLookup look up a value by the json property name +// JSONLookup look up a value by the json property name. func (p PathItem) JSONLookup(token string) (any, error) { if ex, ok := p.Extensions[token]; ok { return &ex, nil @@ -46,7 +46,7 @@ func (p PathItem) JSONLookup(token string) (any, error) { return r, err } -// UnmarshalJSON hydrates this items instance with the data from JSON +// UnmarshalJSON hydrates this items instance with the data from JSON. func (p *PathItem) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &p.Refable); err != nil { return err @@ -57,7 +57,7 @@ func (p *PathItem) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &p.PathItemProps) } -// MarshalJSON converts this items object to JSON +// MarshalJSON converts this items object to JSON. func (p PathItem) MarshalJSON() ([]byte, error) { b3, err := json.Marshal(p.Refable) if err != nil { diff --git a/path_item_test.go b/path_item_test.go index ddb5e10d..8a08f6a8 100644 --- a/path_item_test.go +++ b/path_item_test.go @@ -4,14 +4,12 @@ package spec import ( - "encoding/json" "testing" "github.com/go-openapi/testify/v2/assert" - "github.com/go-openapi/testify/v2/require" ) -var pathItem = PathItem{ +var pathItem = PathItem{ //nolint:gochecknoglobals // test fixture Refable: Refable{Ref: MustCreateRef("Dog")}, VendorExtensible: VendorExtensible{ Extensions: map[string]any{ @@ -62,9 +60,5 @@ const pathItemJSON = `{ }` func TestIntegrationPathItem(t *testing.T) { - var actual PathItem - require.NoError(t, json.Unmarshal([]byte(pathItemJSON), &actual)) - assert.Equal(t, actual, pathItem) - - assertParsesJSON(t, pathItemJSON, pathItem) + assert.JSONUnmarshalAsT(t, pathItem, pathItemJSON) } diff --git a/paths.go b/paths.go index b9e42184..5daf5a67 100644 --- a/paths.go +++ b/paths.go @@ -23,7 +23,7 @@ type Paths struct { Paths map[string]PathItem `json:"-"` // custom serializer to flatten this, each entry must start with "/" } -// JSONLookup look up a value by the json property name +// JSONLookup look up a value by the json property name. func (p Paths) JSONLookup(token string) (any, error) { if pi, ok := p.Paths[token]; ok { return &pi, nil @@ -34,7 +34,7 @@ func (p Paths) JSONLookup(token string) (any, error) { return nil, fmt.Errorf("object has no field %q: %w", token, ErrSpec) } -// UnmarshalJSON hydrates this items instance with the data from JSON +// UnmarshalJSON hydrates this items instance with the data from JSON. func (p *Paths) UnmarshalJSON(data []byte) error { var res map[string]json.RawMessage if err := json.Unmarshal(data, &res); err != nil { @@ -65,7 +65,7 @@ func (p *Paths) UnmarshalJSON(data []byte) error { return nil } -// MarshalJSON converts this items object to JSON +// MarshalJSON converts this items object to JSON. func (p Paths) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(p.VendorExtensible) if err != nil { diff --git a/paths_test.go b/paths_test.go index 79dce173..3057a9da 100644 --- a/paths_test.go +++ b/paths_test.go @@ -4,14 +4,12 @@ package spec import ( - "encoding/json" "testing" "github.com/go-openapi/testify/v2/assert" - "github.com/go-openapi/testify/v2/require" ) -var paths = Paths{ +var paths = Paths{ //nolint:gochecknoglobals // test fixture VendorExtensible: VendorExtensible{Extensions: map[string]any{"x-framework": "go-swagger"}}, Paths: map[string]PathItem{ "/": { @@ -23,10 +21,5 @@ var paths = Paths{ const pathsJSON = `{"x-framework":"go-swagger","/":{"$ref":"cats"}}` func TestIntegrationPaths(t *testing.T) { - var actual Paths - require.NoError(t, json.Unmarshal([]byte(pathsJSON), &actual)) - assert.Equal(t, actual, paths) - - assertParsesJSON(t, pathsJSON, paths) - + assert.JSONUnmarshalAsT(t, paths, pathsJSON) } diff --git a/properties.go b/properties.go index c4988180..b8e97271 100644 --- a/properties.go +++ b/properties.go @@ -10,7 +10,7 @@ import ( "sort" ) -// OrderSchemaItem holds a named schema (e.g. from a property of an object) +// OrderSchemaItem holds a named schema (e.g. from a property of an object). type OrderSchemaItem struct { Schema @@ -53,7 +53,7 @@ func (items OrderSchemaItems) Swap(i, j int) { items[i], items[j] = items[j], it func (items OrderSchemaItems) Less(i, j int) (ret bool) { ii, oki := items[i].Extensions.GetInt("x-order") ij, okj := items[j].Extensions.GetInt("x-order") - if oki { + if oki { //nolint:nestif // nested recover logic for safe type comparison if okj { defer func() { if err := recover(); err != nil { @@ -94,7 +94,7 @@ func (items OrderSchemaItems) marshalJSONItem(item OrderSchemaItem, output *byte // It knows how to transform its keys into an ordered slice. type SchemaProperties map[string]Schema -// ToOrderedSchemaItems transforms the map of properties into a sortable slice +// ToOrderedSchemaItems transforms the map of properties into a sortable slice. func (properties SchemaProperties) ToOrderedSchemaItems() OrderSchemaItems { items := make(OrderSchemaItems, 0, len(properties)) for k, v := range properties { diff --git a/properties_test.go b/properties_test.go index 8475dfe2..1c59acab 100644 --- a/properties_test.go +++ b/properties_test.go @@ -6,6 +6,7 @@ package spec import ( "testing" + "github.com/go-openapi/testify/v2/assert" "github.com/go-openapi/testify/v2/require" ) @@ -20,7 +21,7 @@ func TestPropertySerialization(t *testing.T) { }}, }} - var propSerData = []struct { + propSerData := []struct { Schema *Schema JSON string }{ @@ -42,10 +43,9 @@ func TestPropertySerialization(t *testing.T) { for _, v := range propSerData { t.Log("roundtripping for", v.JSON) - assertSerializeJSON(t, v.Schema, v.JSON) - assertParsesJSON(t, v.JSON, v.Schema) + assert.JSONMarshalAsT(t, v.JSON, v.Schema) + assert.JSONUnmarshalAsT(t, v.Schema, v.JSON) } - } func TestOrderedSchemaItem_Issue216(t *testing.T) { diff --git a/ref.go b/ref.go index 1d1c7591..40b7d486 100644 --- a/ref.go +++ b/ref.go @@ -14,28 +14,28 @@ import ( "github.com/go-openapi/jsonreference" ) -// Refable is a struct for things that accept a $ref property +// Refable is a struct for things that accept a $ref property. type Refable struct { Ref Ref } -// MarshalJSON marshals the ref to json +// MarshalJSON marshals the ref to json. func (r Refable) MarshalJSON() ([]byte, error) { return r.Ref.MarshalJSON() } -// UnmarshalJSON unmarshals the ref from json +// UnmarshalJSON unmarshals the ref from json. func (r *Refable) UnmarshalJSON(d []byte) error { return json.Unmarshal(d, &r.Ref) } -// Ref represents a json reference that is potentially resolved +// Ref represents a json reference that is potentially resolved. type Ref struct { jsonreference.Ref } // NewRef creates a new instance of a ref object -// returns an error when the reference uri is an invalid uri +// returns an error when the reference uri is an invalid uri. func NewRef(refURI string) (Ref, error) { ref, err := jsonreference.New(refURI) if err != nil { @@ -51,7 +51,7 @@ func MustCreateRef(refURI string) Ref { return Ref{Ref: jsonreference.MustCreateRef(refURI)} } -// RemoteURI gets the remote uri part of the ref +// RemoteURI gets the remote uri part of the ref. func (r *Ref) RemoteURI() string { if r.String() == "" { return "" @@ -62,7 +62,7 @@ func (r *Ref) RemoteURI() string { return u.String() } -// IsValidURI returns true when the url the ref points to can be found +// IsValidURI returns true when the url the ref points to can be found. func (r *Ref) IsValidURI(basepaths ...string) bool { if r.String() == "" { return true @@ -112,7 +112,7 @@ func (r *Ref) IsValidURI(basepaths ...string) bool { } // Inherits creates a new reference from a parent and a child -// If the child cannot inherit from the parent, an error is returned +// If the child cannot inherit from the parent, an error is returned. func (r *Ref) Inherits(child Ref) (*Ref, error) { ref, err := r.Ref.Inherits(child.Ref) if err != nil { @@ -121,7 +121,7 @@ func (r *Ref) Inherits(child Ref) (*Ref, error) { return &Ref{Ref: *ref}, nil } -// MarshalJSON marshals this ref into a JSON object +// MarshalJSON marshals this ref into a JSON object. func (r Ref) MarshalJSON() ([]byte, error) { str := r.String() if str == "" { @@ -134,7 +134,7 @@ func (r Ref) MarshalJSON() ([]byte, error) { return json.Marshal(v) } -// UnmarshalJSON unmarshals this ref from a JSON object +// UnmarshalJSON unmarshals this ref from a JSON object. func (r *Ref) UnmarshalJSON(d []byte) error { var v map[string]any if err := json.Unmarshal(d, &v); err != nil { @@ -143,7 +143,7 @@ func (r *Ref) UnmarshalJSON(d []byte) error { return r.fromMap(v) } -// GobEncode provides a safe gob encoder for Ref +// GobEncode provides a safe gob encoder for Ref. func (r Ref) GobEncode() ([]byte, error) { var b bytes.Buffer raw, err := r.MarshalJSON() @@ -154,7 +154,7 @@ func (r Ref) GobEncode() ([]byte, error) { return b.Bytes(), err } -// GobDecode provides a safe gob decoder for Ref +// GobDecode provides a safe gob decoder for Ref. func (r *Ref) GobDecode(b []byte) error { var raw []byte buf := bytes.NewBuffer(b) diff --git a/ref_test.go b/ref_test.go index d9e238c9..8973af20 100644 --- a/ref_test.go +++ b/ref_test.go @@ -13,7 +13,7 @@ import ( "github.com/go-openapi/testify/v2/require" ) -// pin pointing go-swagger/go-swagger#1816 issue with cloning ref's +// pin pointing go-swagger/go-swagger#1816 issue with cloning ref's. func TestCloneRef(t *testing.T) { var b bytes.Buffer src := MustCreateRef("#/definitions/test") @@ -29,5 +29,5 @@ func TestCloneRef(t *testing.T) { jazon, err := json.Marshal(dst) require.NoError(t, err) - assert.JSONEq(t, `{"$ref":"#/definitions/test"}`, string(jazon)) + assert.JSONEqT(t, `{"$ref":"#/definitions/test"}`, string(jazon)) } diff --git a/resolver.go b/resolver.go index 600574e1..1bf90c86 100644 --- a/resolver.go +++ b/resolver.go @@ -20,7 +20,7 @@ func resolveAnyWithBase(root any, ref *Ref, result any, options *ExpandOptions) return nil } -// ResolveRefWithBase resolves a reference against a context root with preservation of base path +// ResolveRefWithBase resolves a reference against a context root with preservation of base path. func ResolveRefWithBase(root any, ref *Ref, options *ExpandOptions) (*Schema, error) { result := new(Schema) @@ -34,7 +34,7 @@ func ResolveRefWithBase(root any, ref *Ref, options *ExpandOptions) (*Schema, er // ResolveRef resolves a reference for a schema against a context root // ref is guaranteed to be in root (no need to go to external files) // -// ResolveRef is ONLY called from the code generation module +// ResolveRef is ONLY called from the code generation module. func ResolveRef(root any, ref *Ref) (*Schema, error) { res, _, err := ref.GetPointer().Get(root) if err != nil { @@ -57,7 +57,7 @@ func ResolveRef(root any, ref *Ref) (*Schema, error) { } } -// ResolveParameterWithBase resolves a parameter reference against a context root and base path +// ResolveParameterWithBase resolves a parameter reference against a context root and base path. func ResolveParameterWithBase(root any, ref Ref, options *ExpandOptions) (*Parameter, error) { result := new(Parameter) @@ -68,12 +68,12 @@ func ResolveParameterWithBase(root any, ref Ref, options *ExpandOptions) (*Param return result, nil } -// ResolveParameter resolves a parameter reference against a context root +// ResolveParameter resolves a parameter reference against a context root. func ResolveParameter(root any, ref Ref) (*Parameter, error) { return ResolveParameterWithBase(root, ref, nil) } -// ResolveResponseWithBase resolves response a reference against a context root and base path +// ResolveResponseWithBase resolves response a reference against a context root and base path. func ResolveResponseWithBase(root any, ref Ref, options *ExpandOptions) (*Response, error) { result := new(Response) @@ -85,12 +85,12 @@ func ResolveResponseWithBase(root any, ref Ref, options *ExpandOptions) (*Respon return result, nil } -// ResolveResponse resolves response a reference against a context root +// ResolveResponse resolves response a reference against a context root. func ResolveResponse(root any, ref Ref) (*Response, error) { return ResolveResponseWithBase(root, ref, nil) } -// ResolvePathItemWithBase resolves response a path item against a context root and base path +// ResolvePathItemWithBase resolves response a path item against a context root and base path. func ResolvePathItemWithBase(root any, ref Ref, options *ExpandOptions) (*PathItem, error) { result := new(PathItem) @@ -103,7 +103,7 @@ func ResolvePathItemWithBase(root any, ref Ref, options *ExpandOptions) (*PathIt // ResolvePathItem resolves response a path item against a context root and base path // -// Deprecated: use ResolvePathItemWithBase instead +// Deprecated: use ResolvePathItemWithBase instead. func ResolvePathItem(root any, ref Ref, options *ExpandOptions) (*PathItem, error) { return ResolvePathItemWithBase(root, ref, options) } @@ -124,7 +124,7 @@ func ResolveItemsWithBase(root any, ref Ref, options *ExpandOptions) (*Items, er // ResolveItems resolves parameter items reference against a context root and base path. // -// Deprecated: use ResolveItemsWithBase instead +// Deprecated: use ResolveItemsWithBase instead. func ResolveItems(root any, ref Ref, options *ExpandOptions) (*Items, error) { return ResolveItemsWithBase(root, ref, options) } diff --git a/resolver_test.go b/resolver_test.go index e8d6311e..c949eca0 100644 --- a/resolver_test.go +++ b/resolver_test.go @@ -5,8 +5,6 @@ package spec import ( "encoding/json" - "net/http" - "net/http/httptest" "os" "path/filepath" "testing" @@ -18,7 +16,7 @@ import ( func TestResolveRef(t *testing.T) { var root any - require.NoError(t, json.Unmarshal([]byte(PetStore20), &root)) + require.NoError(t, json.Unmarshal(PetStore20, &root)) ref, err := NewRef("#/definitions/Category") require.NoError(t, err) @@ -29,7 +27,7 @@ func TestResolveRef(t *testing.T) { b, err := sch.MarshalJSON() require.NoError(t, err) - assert.JSONEq(t, `{"id":"Category","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}`, string(b)) + assert.JSONEqT(t, `{"id":"Category","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}`, string(b)) // WithBase variant sch, err = ResolveRefWithBase(root, &ref, &ExpandOptions{ @@ -40,7 +38,7 @@ func TestResolveRef(t *testing.T) { b, err = sch.MarshalJSON() require.NoError(t, err) - assert.JSONEq(t, `{"id":"Category","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}`, string(b)) + assert.JSONEqT(t, `{"id":"Category","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}`, string(b)) } func TestResolveResponse(t *testing.T) { @@ -58,7 +56,7 @@ func TestResolveResponse(t *testing.T) { // resolve resolves the ref, but dos not expand jazon := asJSON(t, resp2) - assert.JSONEq(t, `{ + assert.JSONEqT(t, `{ "$ref": "#/responses/petResponse" }`, jazon) } @@ -78,7 +76,7 @@ func TestResolveResponseWithBase(t *testing.T) { // resolve resolves the ref, but dos not expand jazon := asJSON(t, resp2) - assert.JSONEq(t, `{ + assert.JSONEqT(t, `{ "$ref": "#/responses/petResponse" }`, jazon) } @@ -96,7 +94,7 @@ func TestResolveParam(t *testing.T) { jazon := asJSON(t, par) - assert.JSONEq(t, `{ + assert.JSONEqT(t, `{ "name": "id", "in": "path", "description": "ID of pet to fetch", @@ -119,7 +117,7 @@ func TestResolveParamWithBase(t *testing.T) { jazon := asJSON(t, par) - assert.JSONEq(t, `{ + assert.JSONEqT(t, `{ "description":"ID of pet to fetch", "format":"int64", "in":"path", @@ -130,9 +128,7 @@ func TestResolveParamWithBase(t *testing.T) { } func TestResolveRemoteRef_RootSame(t *testing.T) { - fileserver := http.FileServer(http.Dir(specs)) - server := httptest.NewServer(fileserver) - defer server.Close() + server := fixtureServer(t, specs) rootDoc := new(Swagger) b, err := os.ReadFile(filepath.Join(specs, "refed.json")) @@ -158,9 +154,7 @@ func TestResolveRemoteRef_RootSame(t *testing.T) { } func TestResolveRemoteRef_FromFragment(t *testing.T) { - fileserver := http.FileServer(http.Dir(specs)) - server := httptest.NewServer(fileserver) - defer server.Close() + server := fixtureServer(t, specs) rootDoc := new(Swagger) b, err := os.ReadFile(filepath.Join(specs, "refed.json")) @@ -178,9 +172,7 @@ func TestResolveRemoteRef_FromFragment(t *testing.T) { } func TestResolveRemoteRef_FromInvalidFragment(t *testing.T) { - fileserver := http.FileServer(http.Dir(specs)) - server := httptest.NewServer(fileserver) - defer server.Close() + server := fixtureServer(t, specs) rootDoc := new(Swagger) b, err := os.ReadFile(filepath.Join(specs, "refed.json")) @@ -215,9 +207,7 @@ func TestResolveRemoteRef_FromInvalidFragment(t *testing.T) { // } func TestResolveRemoteRef_ToParameter(t *testing.T) { - fileserver := http.FileServer(http.Dir(specs)) - server := httptest.NewServer(fileserver) - defer server.Close() + server := fixtureServer(t, specs) rootDoc := new(Swagger) b, err := os.ReadFile(filepath.Join(specs, "refed.json")) @@ -231,18 +221,16 @@ func TestResolveRemoteRef_ToParameter(t *testing.T) { resolver := defaultSchemaLoader(rootDoc, nil, nil, nil) require.NoError(t, resolver.Resolve(&ref, &tgt, "")) - assert.Equal(t, "id", tgt.Name) - assert.Equal(t, "path", tgt.In) - assert.Equal(t, "ID of pet to fetch", tgt.Description) - assert.True(t, tgt.Required) - assert.Equal(t, "integer", tgt.Type) - assert.Equal(t, "int64", tgt.Format) + assert.EqualT(t, "id", tgt.Name) + assert.EqualT(t, "path", tgt.In) + assert.EqualT(t, "ID of pet to fetch", tgt.Description) + assert.TrueT(t, tgt.Required) + assert.EqualT(t, "integer", tgt.Type) + assert.EqualT(t, "int64", tgt.Format) } func TestResolveRemoteRef_ToPathItem(t *testing.T) { - fileserver := http.FileServer(http.Dir(specs)) - server := httptest.NewServer(fileserver) - defer server.Close() + server := fixtureServer(t, specs) rootDoc := new(Swagger) b, err := os.ReadFile(filepath.Join(specs, "refed.json")) @@ -259,9 +247,7 @@ func TestResolveRemoteRef_ToPathItem(t *testing.T) { } func TestResolveRemoteRef_ToResponse(t *testing.T) { - fileserver := http.FileServer(http.Dir(specs)) - server := httptest.NewServer(fileserver) - defer server.Close() + server := fixtureServer(t, specs) rootDoc := new(Swagger) b, err := os.ReadFile(filepath.Join(specs, "refed.json")) @@ -298,7 +284,7 @@ func TestResolveLocalRef_FromFragment(t *testing.T) { resolver := defaultSchemaLoader(rootDoc, nil, nil, nil) require.NoError(t, resolver.Resolve(&ref, &tgt, "")) - assert.Equal(t, "Category", tgt.ID) + assert.EqualT(t, "Category", tgt.ID) } func TestResolveLocalRef_FromInvalidFragment(t *testing.T) { @@ -328,12 +314,12 @@ func TestResolveLocalRef_Parameter(t *testing.T) { resolver := defaultSchemaLoader(rootDoc, nil, nil, nil) require.NoError(t, resolver.Resolve(&ref, &tgt, basePath)) - assert.Equal(t, "id", tgt.Name) - assert.Equal(t, "path", tgt.In) - assert.Equal(t, "ID of pet to fetch", tgt.Description) - assert.True(t, tgt.Required) - assert.Equal(t, "integer", tgt.Type) - assert.Equal(t, "int64", tgt.Format) + assert.EqualT(t, "id", tgt.Name) + assert.EqualT(t, "path", tgt.In) + assert.EqualT(t, "ID of pet to fetch", tgt.Description) + assert.TrueT(t, tgt.Required) + assert.EqualT(t, "integer", tgt.Type) + assert.EqualT(t, "int64", tgt.Format) } func TestResolveLocalRef_PathItem(t *testing.T) { @@ -384,7 +370,7 @@ func TestResolvePathItem(t *testing.T) { jazon := asJSON(t, pathItem) - assert.JSONEq(t, `{ + assert.JSONEqT(t, `{ "get": { "responses": { "200": { @@ -419,7 +405,7 @@ func TestResolveExtraItem(t *testing.T) { jazon := asJSON(t, parmItem) - assert.JSONEq(t, `{ + assert.JSONEqT(t, `{ "type": "integer", "format": "int32" }`, jazon) @@ -431,7 +417,7 @@ func TestResolveExtraItem(t *testing.T) { jazon = asJSON(t, hdrItem) - assert.JSONEq(t, `{ + assert.JSONEqT(t, `{ "type": "string", "format": "uuid" }`, jazon) diff --git a/response.go b/response.go index e5a7e5c4..4bb6a2bc 100644 --- a/response.go +++ b/response.go @@ -10,7 +10,7 @@ import ( "github.com/go-openapi/swag/jsonutils" ) -// ResponseProps properties specific to a response +// ResponseProps properties specific to a response. type ResponseProps struct { Description string `json:"description"` Schema *Schema `json:"schema,omitempty"` @@ -27,19 +27,19 @@ type Response struct { VendorExtensible } -// NewResponse creates a new response instance +// NewResponse creates a new response instance. func NewResponse() *Response { return new(Response) } -// ResponseRef creates a response as a json reference +// ResponseRef creates a response as a json reference. func ResponseRef(url string) *Response { resp := NewResponse() resp.Ref = MustCreateRef(url) return resp } -// JSONLookup look up a value by the json property name +// JSONLookup look up a value by the json property name. func (r Response) JSONLookup(token string) (any, error) { if ex, ok := r.Extensions[token]; ok { return &ex, nil @@ -51,7 +51,7 @@ func (r Response) JSONLookup(token string) (any, error) { return ptr, err } -// UnmarshalJSON hydrates this items instance with the data from JSON +// UnmarshalJSON hydrates this items instance with the data from JSON. func (r *Response) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &r.ResponseProps); err != nil { return err @@ -62,7 +62,7 @@ func (r *Response) UnmarshalJSON(data []byte) error { return json.Unmarshal(data, &r.VendorExtensible) } -// MarshalJSON converts this items object to JSON +// MarshalJSON converts this items object to JSON. func (r Response) MarshalJSON() ([]byte, error) { var ( b1 []byte @@ -100,20 +100,20 @@ func (r Response) MarshalJSON() ([]byte, error) { return jsonutils.ConcatJSON(b1, b2, b3), nil } -// WithDescription sets the description on this response, allows for chaining +// WithDescription sets the description on this response, allows for chaining. func (r *Response) WithDescription(description string) *Response { r.Description = description return r } // WithSchema sets the schema on this response, allows for chaining. -// Passing a nil argument removes the schema from this response +// Passing a nil argument removes the schema from this response. func (r *Response) WithSchema(schema *Schema) *Response { r.Schema = schema return r } -// AddHeader adds a header to this response +// AddHeader adds a header to this response. func (r *Response) AddHeader(name string, header *Header) *Response { if header == nil { return r.RemoveHeader(name) @@ -125,13 +125,13 @@ func (r *Response) AddHeader(name string, header *Header) *Response { return r } -// RemoveHeader removes a header from this response +// RemoveHeader removes a header from this response. func (r *Response) RemoveHeader(name string) *Response { delete(r.Headers, name) return r } -// AddExample adds an example to this response +// AddExample adds an example to this response. func (r *Response) AddExample(mediaType string, example any) *Response { if r.Examples == nil { r.Examples = make(map[string]any) diff --git a/response_test.go b/response_test.go index cf62d576..dd9045e7 100644 --- a/response_test.go +++ b/response_test.go @@ -18,14 +18,13 @@ package spec import ( - "encoding/json" "testing" "github.com/go-openapi/testify/v2/assert" "github.com/go-openapi/testify/v2/require" ) -var response = Response{ +var response = Response{ //nolint:gochecknoglobals // test fixture Refable: Refable{Ref: MustCreateRef("Dog")}, VendorExtensible: VendorExtensible{ Extensions: map[string]any{ @@ -48,11 +47,7 @@ const responseJSON = `{ }` func TestIntegrationResponse(t *testing.T) { - var actual Response - require.NoError(t, json.Unmarshal([]byte(responseJSON), &actual)) - assert.Equal(t, actual, response) - - assertParsesJSON(t, responseJSON, response) + assert.JSONUnmarshalAsT(t, response, responseJSON) } func TestJSONLookupResponse(t *testing.T) { @@ -63,7 +58,7 @@ func TestJSONLookupResponse(t *testing.T) { var ok bool ref, ok := res.(*Ref) - require.True(t, ok) + require.TrueT(t, ok) assert.Equal(t, MustCreateRef("Dog"), *ref) var def string @@ -73,8 +68,8 @@ func TestJSONLookupResponse(t *testing.T) { require.IsType(t, def, res) def, ok = res.(string) - require.True(t, ok) - assert.Equal(t, "Dog exists", def) + require.TrueT(t, ok) + assert.EqualT(t, "Dog exists", def) var x *any res, err = response.JSONLookup("x-go-name") @@ -83,7 +78,7 @@ func TestJSONLookupResponse(t *testing.T) { require.IsType(t, x, res) x, ok = res.(*any) - require.True(t, ok) + require.TrueT(t, ok) assert.EqualValues(t, "PutDogExists", *x) res, err = response.JSONLookup("unknown") @@ -97,10 +92,7 @@ func TestResponseBuild(t *testing.T) { WithSchema(new(Schema).Typed("object", "")). AddHeader("x-header", ResponseHeader().Typed("string", "")). AddExample("application/json", `{"key":"value"}`) - jazon, err := json.MarshalIndent(resp, "", " ") - require.NoError(t, err) - - assert.JSONEq(t, `{ + assert.JSONMarshalAsT(t, `{ "description": "some response", "schema": { "type": "object" @@ -113,5 +105,5 @@ func TestResponseBuild(t *testing.T) { "examples": { "application/json": "{\"key\":\"value\"}" } - }`, string(jazon)) + }`, resp) } diff --git a/responses.go b/responses.go index 733a1315..fb369e4a 100644 --- a/responses.go +++ b/responses.go @@ -31,7 +31,7 @@ type Responses struct { ResponsesProps } -// JSONLookup implements an interface to customize json pointer lookup +// JSONLookup implements an interface to customize json pointer lookup. func (r Responses) JSONLookup(token string) (any, error) { if token == "default" { return r.Default, nil @@ -47,7 +47,7 @@ func (r Responses) JSONLookup(token string) (any, error) { return nil, fmt.Errorf("object has no field %q: %w", token, ErrSpec) } -// UnmarshalJSON hydrates this items instance with the data from JSON +// UnmarshalJSON hydrates this items instance with the data from JSON. func (r *Responses) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &r.ResponsesProps); err != nil { return err @@ -62,7 +62,7 @@ func (r *Responses) UnmarshalJSON(data []byte) error { return nil } -// MarshalJSON converts this items object to JSON +// MarshalJSON converts this items object to JSON. func (r Responses) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(r.ResponsesProps) if err != nil { @@ -84,7 +84,7 @@ type ResponsesProps struct { StatusCodeResponses map[int]Response } -// MarshalJSON marshals responses as JSON +// MarshalJSON marshals responses as JSON. func (r ResponsesProps) MarshalJSON() ([]byte, error) { toser := map[string]Response{} if r.Default != nil { @@ -96,7 +96,7 @@ func (r ResponsesProps) MarshalJSON() ([]byte, error) { return json.Marshal(toser) } -// UnmarshalJSON unmarshals responses from JSON +// UnmarshalJSON unmarshals responses from JSON. func (r *ResponsesProps) UnmarshalJSON(data []byte) error { var res map[string]json.RawMessage if err := json.Unmarshal(data, &res); err != nil { diff --git a/responses_test.go b/responses_test.go index f920ad21..c9810c1d 100644 --- a/responses_test.go +++ b/responses_test.go @@ -18,14 +18,13 @@ package spec import ( - "encoding/json" "testing" "github.com/go-openapi/testify/v2/assert" "github.com/go-openapi/testify/v2/require" ) -var responses = Responses{ +var responses = Responses{ //nolint:gochecknoglobals // test fixture VendorExtensible: VendorExtensible{ Extensions: map[string]any{ "x-go-name": "PutDogExists", @@ -62,16 +61,12 @@ const responsesJSON = `{ }` func TestIntegrationResponses(t *testing.T) { - var actual Responses - require.NoError(t, json.Unmarshal([]byte(responsesJSON), &actual)) - assert.Equal(t, actual, responses) - - assertParsesJSON(t, responsesJSON, responses) + assert.JSONUnmarshalAsT(t, responses, responsesJSON) } func TestJSONLookupResponses(t *testing.T) { resp200, ok := responses.StatusCodeResponses[200] - require.True(t, ok) + require.TrueT(t, ok) res, err := resp200.JSONLookup("$ref") require.NoError(t, err) @@ -79,7 +74,7 @@ func TestJSONLookupResponses(t *testing.T) { require.IsType(t, &Ref{}, res) ref, ok := res.(*Ref) - require.True(t, ok) + require.TrueT(t, ok) assert.Equal(t, MustCreateRef("Dog"), *ref) var def string @@ -89,8 +84,8 @@ func TestJSONLookupResponses(t *testing.T) { require.IsType(t, def, res) def, ok = res.(string) - require.True(t, ok) - assert.Equal(t, "Dog exists", def) + require.TrueT(t, ok) + assert.EqualT(t, "Dog exists", def) var x *any res, err = responses.JSONLookup("x-go-name") @@ -99,7 +94,7 @@ func TestJSONLookupResponses(t *testing.T) { require.IsType(t, x, res) x, ok = res.(*any) - require.True(t, ok) + require.TrueT(t, ok) assert.EqualValues(t, "PutDogExists", *x) res, err = responses.JSONLookup("unknown") @@ -113,8 +108,7 @@ func TestResponsesBuild(t *testing.T) { WithSchema(new(Schema).Typed("object", "")). AddHeader("x-header", ResponseHeader().Typed("string", "")). AddExample("application/json", `{"key":"value"}`) - jazon, _ := json.MarshalIndent(resp, "", " ") - assert.JSONEq(t, `{ + assert.JSONMarshalAsT(t, `{ "description": "some response", "schema": { "type": "object" @@ -127,5 +121,5 @@ func TestResponsesBuild(t *testing.T) { "examples": { "application/json": "{\"key\":\"value\"}" } - }`, string(jazon)) + }`, resp) } diff --git a/schema.go b/schema.go index 6623728a..d7a481bf 100644 --- a/schema.go +++ b/schema.go @@ -13,86 +13,88 @@ import ( "github.com/go-openapi/swag/jsonutils" ) -// BooleanProperty creates a boolean property +// BooleanProperty creates a boolean property. func BooleanProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}} } -// BoolProperty creates a boolean property +// BoolProperty creates a boolean property. func BoolProperty() *Schema { return BooleanProperty() } -// StringProperty creates a string property +// StringProperty creates a string property. func StringProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} } -// CharProperty creates a string property +// CharProperty creates a string property. func CharProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} } -// Float64Property creates a float64/double property +// Float64Property creates a float64/double property. func Float64Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}} } -// Float32Property creates a float32/float property +// Float32Property creates a float32/float property. func Float32Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}} } -// Int8Property creates an int8 property +// Int8Property creates an int8 property. func Int8Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}} } -// Int16Property creates an int16 property +// Int16Property creates an int16 property. func Int16Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}} } -// Int32Property creates an int32 property +// Int32Property creates an int32 property. func Int32Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}} } -// Int64Property creates an int64 property +// Int64Property creates an int64 property. func Int64Property() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}} } -// StrFmtProperty creates a property for the named string format +// StrFmtProperty creates a property for the named string format. func StrFmtProperty(format string) *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}} } -// DateProperty creates a date property +// DateProperty creates a date property. func DateProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}} } -// DateTimeProperty creates a date time property +// DateTimeProperty creates a date time property. func DateTimeProperty() *Schema { return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}} } -// MapProperty creates a map property +// MapProperty creates a map property. func MapProperty(property *Schema) *Schema { - return &Schema{SchemaProps: SchemaProps{Type: []string{"object"}, - AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}} + return &Schema{SchemaProps: SchemaProps{ + Type: []string{"object"}, + AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}, + }} } -// RefProperty creates a ref property +// RefProperty creates a ref property. func RefProperty(name string) *Schema { return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} } -// RefSchema creates a ref property +// RefSchema creates a ref property. func RefSchema(name string) *Schema { return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} } -// ArrayProperty creates an array property +// ArrayProperty creates an array property. func ArrayProperty(items *Schema) *Schema { if items == nil { return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}} @@ -100,17 +102,17 @@ func ArrayProperty(items *Schema) *Schema { return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}} } -// ComposedSchema creates a schema with allOf +// ComposedSchema creates a schema with allOf. func ComposedSchema(schemas ...Schema) *Schema { s := new(Schema) s.AllOf = schemas return s } -// SchemaURL represents a schema url +// SchemaURL represents a schema url. type SchemaURL string -// MarshalJSON marshal this to JSON +// MarshalJSON marshal this to JSON. func (r SchemaURL) MarshalJSON() ([]byte, error) { if r == "" { return []byte("{}"), nil @@ -119,7 +121,7 @@ func (r SchemaURL) MarshalJSON() ([]byte, error) { return json.Marshal(v) } -// UnmarshalJSON unmarshal this from JSON +// UnmarshalJSON unmarshal this from JSON. func (r *SchemaURL) UnmarshalJSON(data []byte) error { var v map[string]any if err := json.Unmarshal(data, &v); err != nil { @@ -145,7 +147,7 @@ func (r *SchemaURL) fromMap(v map[string]any) error { return nil } -// SchemaProps describes a JSON schema (draft 4) +// SchemaProps describes a JSON schema (draft 4). type SchemaProps struct { ID string `json:"id,omitempty"` Ref Ref `json:"-"` @@ -184,7 +186,7 @@ type SchemaProps struct { Definitions Definitions `json:"definitions,omitempty"` } -// SwaggerSchemaProps are additional properties supported by swagger schemas, but not JSON-schema (draft 4) +// SwaggerSchemaProps are additional properties supported by swagger schemas, but not JSON-schema (draft 4). type SwaggerSchemaProps struct { Discriminator string `json:"discriminator,omitempty"` ReadOnly bool `json:"readOnly,omitempty"` @@ -208,7 +210,7 @@ type Schema struct { ExtraProps map[string]any `json:"-"` } -// JSONLookup implements an interface to customize json pointer lookup +// JSONLookup implements an interface to customize json pointer lookup. func (s Schema) JSONLookup(token string) (any, error) { if ex, ok := s.Extensions[token]; ok { return &ex, nil @@ -226,31 +228,31 @@ func (s Schema) JSONLookup(token string) (any, error) { return r, err } -// WithID sets the id for this schema, allows for chaining +// WithID sets the id for this schema, allows for chaining. func (s *Schema) WithID(id string) *Schema { s.ID = id return s } -// WithTitle sets the title for this schema, allows for chaining +// WithTitle sets the title for this schema, allows for chaining. func (s *Schema) WithTitle(title string) *Schema { s.Title = title return s } -// WithDescription sets the description for this schema, allows for chaining +// WithDescription sets the description for this schema, allows for chaining. func (s *Schema) WithDescription(description string) *Schema { s.Description = description return s } -// WithProperties sets the properties for this schema +// WithProperties sets the properties for this schema. func (s *Schema) WithProperties(schemas map[string]Schema) *Schema { s.Properties = schemas return s } -// SetProperty sets a property on this schema +// SetProperty sets a property on this schema. func (s *Schema) SetProperty(name string, schema Schema) *Schema { if s.Properties == nil { s.Properties = make(map[string]Schema) @@ -259,32 +261,32 @@ func (s *Schema) SetProperty(name string, schema Schema) *Schema { return s } -// WithAllOf sets the all of property +// WithAllOf sets the all of property. func (s *Schema) WithAllOf(schemas ...Schema) *Schema { s.AllOf = schemas return s } -// WithMaxProperties sets the max number of properties an object can have +// WithMaxProperties sets the max number of properties an object can have. func (s *Schema) WithMaxProperties(maximum int64) *Schema { s.MaxProperties = &maximum return s } -// WithMinProperties sets the min number of properties an object must have +// WithMinProperties sets the min number of properties an object must have. func (s *Schema) WithMinProperties(minimum int64) *Schema { s.MinProperties = &minimum return s } -// Typed sets the type of this schema for a single value item +// Typed sets the type of this schema for a single value item. func (s *Schema) Typed(tpe, format string) *Schema { s.Type = []string{tpe} s.Format = format return s } -// AddType adds a type with potential format to the types for this schema +// AddType adds a type with potential format to the types for this schema. func (s *Schema) AddType(tpe, format string) *Schema { s.Type = append(s.Type, tpe) if format != "" { @@ -299,124 +301,124 @@ func (s *Schema) AsNullable() *Schema { return s } -// CollectionOf a fluent builder method for an array parameter +// CollectionOf a fluent builder method for an array parameter. func (s *Schema) CollectionOf(items Schema) *Schema { s.Type = []string{jsonArray} s.Items = &SchemaOrArray{Schema: &items} return s } -// WithDefault sets the default value on this parameter +// WithDefault sets the default value on this parameter. func (s *Schema) WithDefault(defaultValue any) *Schema { s.Default = defaultValue return s } -// WithRequired flags this parameter as required +// WithRequired flags this parameter as required. func (s *Schema) WithRequired(items ...string) *Schema { s.Required = items return s } -// AddRequired adds field names to the required properties array +// AddRequired adds field names to the required properties array. func (s *Schema) AddRequired(items ...string) *Schema { s.Required = append(s.Required, items...) return s } -// WithMaxLength sets a max length value +// WithMaxLength sets a max length value. func (s *Schema) WithMaxLength(maximum int64) *Schema { s.MaxLength = &maximum return s } -// WithMinLength sets a min length value +// WithMinLength sets a min length value. func (s *Schema) WithMinLength(minimum int64) *Schema { s.MinLength = &minimum return s } -// WithPattern sets a pattern value +// WithPattern sets a pattern value. func (s *Schema) WithPattern(pattern string) *Schema { s.Pattern = pattern return s } -// WithMultipleOf sets a multiple of value +// WithMultipleOf sets a multiple of value. func (s *Schema) WithMultipleOf(number float64) *Schema { s.MultipleOf = &number return s } -// WithMaximum sets a maximum number value +// WithMaximum sets a maximum number value. func (s *Schema) WithMaximum(maximum float64, exclusive bool) *Schema { s.Maximum = &maximum s.ExclusiveMaximum = exclusive return s } -// WithMinimum sets a minimum number value +// WithMinimum sets a minimum number value. func (s *Schema) WithMinimum(minimum float64, exclusive bool) *Schema { s.Minimum = &minimum s.ExclusiveMinimum = exclusive return s } -// WithEnum sets a the enum values (replace) +// WithEnum sets a the enum values (replace). func (s *Schema) WithEnum(values ...any) *Schema { s.Enum = append([]any{}, values...) return s } -// WithMaxItems sets the max items +// WithMaxItems sets the max items. func (s *Schema) WithMaxItems(size int64) *Schema { s.MaxItems = &size return s } -// WithMinItems sets the min items +// WithMinItems sets the min items. func (s *Schema) WithMinItems(size int64) *Schema { s.MinItems = &size return s } -// UniqueValues dictates that this array can only have unique items +// UniqueValues dictates that this array can only have unique items. func (s *Schema) UniqueValues() *Schema { s.UniqueItems = true return s } -// AllowDuplicates this array can have duplicates +// AllowDuplicates this array can have duplicates. func (s *Schema) AllowDuplicates() *Schema { s.UniqueItems = false return s } -// AddToAllOf adds a schema to the allOf property +// AddToAllOf adds a schema to the allOf property. func (s *Schema) AddToAllOf(schemas ...Schema) *Schema { s.AllOf = append(s.AllOf, schemas...) return s } -// WithDiscriminator sets the name of the discriminator field +// WithDiscriminator sets the name of the discriminator field. func (s *Schema) WithDiscriminator(discriminator string) *Schema { s.Discriminator = discriminator return s } -// AsReadOnly flags this schema as readonly +// AsReadOnly flags this schema as readonly. func (s *Schema) AsReadOnly() *Schema { s.ReadOnly = true return s } -// AsWritable flags this schema as writeable (not read-only) +// AsWritable flags this schema as writeable (not read-only). func (s *Schema) AsWritable() *Schema { s.ReadOnly = false return s } -// WithExample sets the example for this schema +// WithExample sets the example for this schema. func (s *Schema) WithExample(example any) *Schema { s.Example = example return s @@ -440,7 +442,7 @@ func (s *Schema) WithExternalDocs(description, url string) *Schema { return s } -// WithXMLName sets the xml name for the object +// WithXMLName sets the xml name for the object. func (s *Schema) WithXMLName(name string) *Schema { if s.XML == nil { s.XML = new(XMLObject) @@ -449,7 +451,7 @@ func (s *Schema) WithXMLName(name string) *Schema { return s } -// WithXMLNamespace sets the xml namespace for the object +// WithXMLNamespace sets the xml namespace for the object. func (s *Schema) WithXMLNamespace(namespace string) *Schema { if s.XML == nil { s.XML = new(XMLObject) @@ -458,7 +460,7 @@ func (s *Schema) WithXMLNamespace(namespace string) *Schema { return s } -// WithXMLPrefix sets the xml prefix for the object +// WithXMLPrefix sets the xml prefix for the object. func (s *Schema) WithXMLPrefix(prefix string) *Schema { if s.XML == nil { s.XML = new(XMLObject) @@ -467,7 +469,7 @@ func (s *Schema) WithXMLPrefix(prefix string) *Schema { return s } -// AsXMLAttribute flags this object as xml attribute +// AsXMLAttribute flags this object as xml attribute. func (s *Schema) AsXMLAttribute() *Schema { if s.XML == nil { s.XML = new(XMLObject) @@ -476,7 +478,7 @@ func (s *Schema) AsXMLAttribute() *Schema { return s } -// AsXMLElement flags this object as an xml node +// AsXMLElement flags this object as an xml node. func (s *Schema) AsXMLElement() *Schema { if s.XML == nil { s.XML = new(XMLObject) @@ -485,7 +487,7 @@ func (s *Schema) AsXMLElement() *Schema { return s } -// AsWrappedXML flags this object as wrapped, this is mostly useful for array types +// AsWrappedXML flags this object as wrapped, this is mostly useful for array types. func (s *Schema) AsWrappedXML() *Schema { if s.XML == nil { s.XML = new(XMLObject) @@ -494,7 +496,7 @@ func (s *Schema) AsWrappedXML() *Schema { return s } -// AsUnwrappedXML flags this object as an xml node +// AsUnwrappedXML flags this object as an xml node. func (s *Schema) AsUnwrappedXML() *Schema { if s.XML == nil { s.XML = new(XMLObject) @@ -524,13 +526,13 @@ func (s *Schema) SetValidations(val SchemaValidations) { s.PatternProperties = val.PatternProperties } -// WithValidations is a fluent method to set schema validations +// WithValidations is a fluent method to set schema validations. func (s *Schema) WithValidations(val SchemaValidations) *Schema { s.SetValidations(val) return s } -// Validations returns a clone of the validations for this schema +// Validations returns a clone of the validations for this schema. func (s Schema) Validations() SchemaValidations { return SchemaValidations{ CommonValidations: CommonValidations{ @@ -553,40 +555,40 @@ func (s Schema) Validations() SchemaValidations { } } -// MarshalJSON marshal this to JSON +// MarshalJSON marshal this to JSON. func (s Schema) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(s.SchemaProps) if err != nil { - return nil, fmt.Errorf("schema props %v: %w", err, ErrSpec) + return nil, fmt.Errorf("schema props %w: %w", err, ErrSpec) } b2, err := json.Marshal(s.VendorExtensible) if err != nil { - return nil, fmt.Errorf("vendor props %v: %w", err, ErrSpec) + return nil, fmt.Errorf("vendor props %w: %w", err, ErrSpec) } b3, err := s.Ref.MarshalJSON() if err != nil { - return nil, fmt.Errorf("ref prop %v: %w", err, ErrSpec) + return nil, fmt.Errorf("ref prop %w: %w", err, ErrSpec) } b4, err := s.Schema.MarshalJSON() if err != nil { - return nil, fmt.Errorf("schema prop %v: %w", err, ErrSpec) + return nil, fmt.Errorf("schema prop %w: %w", err, ErrSpec) } b5, err := json.Marshal(s.SwaggerSchemaProps) if err != nil { - return nil, fmt.Errorf("common validations %v: %w", err, ErrSpec) + return nil, fmt.Errorf("common validations %w: %w", err, ErrSpec) } var b6 []byte if s.ExtraProps != nil { jj, err := json.Marshal(s.ExtraProps) if err != nil { - return nil, fmt.Errorf("extra props %v: %w", err, ErrSpec) + return nil, fmt.Errorf("extra props %w: %w", err, ErrSpec) } b6 = jj } return jsonutils.ConcatJSON(b1, b2, b3, b4, b5, b6), nil } -// UnmarshalJSON marshal this from JSON +// UnmarshalJSON marshal this from JSON. func (s *Schema) UnmarshalJSON(data []byte) error { props := struct { SchemaProps diff --git a/schema_loader.go b/schema_loader.go index 8d4a9853..0894c932 100644 --- a/schema_loader.go +++ b/schema_loader.go @@ -24,7 +24,7 @@ import ( // NOTE: if you are using the go-openapi/loads package, it will override // this value with its own default (a loader to retrieve YAML documents as // well as JSON ones). -var PathLoader = func(pth string) (json.RawMessage, error) { +var PathLoader = func(pth string) (json.RawMessage, error) { //nolint:gochecknoglobals // package-level default loader, overridable by go-openapi/loads data, err := loading.LoadFromFileOrHTTP(pth) if err != nil { return nil, err @@ -76,7 +76,7 @@ type schemaLoader struct { // // If the schema the ref is referring to holds nested refs, Resolve doesn't resolve them. // -// If basePath is an empty string, ref is resolved against the root schema stored in the schemaLoader struct +// If basePath is an empty string, ref is resolved against the root schema stored in the schemaLoader struct. func (r *schemaLoader) Resolve(ref *Ref, target any, basePath string) error { return r.resolveRef(ref, target, basePath) } @@ -136,7 +136,7 @@ func (r *schemaLoader) resolveRef(ref *Ref, target any, basePath string) error { root := r.root if (ref.IsRoot() || ref.HasFragmentOnly) && root == nil && basePath != "" { if baseRef, erb := NewRef(basePath); erb == nil { - root, _, _, _ = r.load(baseRef.GetURL()) + root, _ = r.load(baseRef.GetURL()) } } @@ -144,7 +144,7 @@ func (r *schemaLoader) resolveRef(ref *Ref, target any, basePath string) error { data = root } else { baseRef := normalizeRef(ref, basePath) - data, _, _, err = r.load(baseRef.GetURL()) + data, err = r.load(baseRef.GetURL()) if err != nil { return err } @@ -160,33 +160,32 @@ func (r *schemaLoader) resolveRef(ref *Ref, target any, basePath string) error { return jsonutils.FromDynamicJSON(res, target) } -func (r *schemaLoader) load(refURL *url.URL) (any, url.URL, bool, error) { +func (r *schemaLoader) load(refURL *url.URL) (any, error) { debugLog("loading schema from url: %s", refURL) toFetch := *refURL toFetch.Fragment = "" - var err error pth := toFetch.String() normalized := normalizeBase(pth) debugLog("loading doc from: %s", normalized) data, fromCache := r.cache.Get(normalized) if fromCache { - return data, toFetch, fromCache, nil + return data, nil } b, err := r.context.loadDoc(normalized) if err != nil { - return nil, url.URL{}, false, err + return nil, err } var doc any if err := json.Unmarshal(b, &doc); err != nil { - return nil, url.URL{}, false, err + return nil, err } r.cache.Set(normalized, doc) - return doc, toFetch, fromCache, nil + return doc, nil } // isCircular detects cycles in sequences of $ref. @@ -293,8 +292,8 @@ func defaultSchemaLoader( root any, expandOptions *ExpandOptions, cache ResolutionCache, - context *resolverContext) *schemaLoader { - + context *resolverContext, +) *schemaLoader { if expandOptions == nil { expandOptions = &ExpandOptions{} } diff --git a/schema_test.go b/schema_test.go index 1009fbed..7d296a5b 100644 --- a/schema_test.go +++ b/schema_test.go @@ -12,7 +12,7 @@ import ( "github.com/go-openapi/testify/v2/require" ) -var schema = Schema{ +var schema = Schema{ //nolint:gochecknoglobals // test fixture VendorExtensible: VendorExtensible{Extensions: map[string]any{"x-framework": "go-swagger"}}, SchemaProps: SchemaProps{ Ref: MustCreateRef("Cat"), @@ -68,6 +68,7 @@ var schema = Schema{ }, } +//nolint:gochecknoglobals // test fixture var schemaJSON = `{ "x-framework": "go-swagger", "$ref": "Cat", @@ -139,55 +140,53 @@ var schemaJSON = `{ ` func TestSchema(t *testing.T) { - - expected := map[string]any{} - _ = json.Unmarshal([]byte(schemaJSON), &expected) - b, err := json.Marshal(schema) - require.NoError(t, err) - - var actual map[string]any - require.NoError(t, json.Unmarshal(b, &actual)) - assert.Equal(t, expected, actual) + assert.JSONMarshalAsT(t, schemaJSON, schema) actual2 := Schema{} require.NoError(t, json.Unmarshal([]byte(schemaJSON), &actual2)) assert.Equal(t, schema.Ref, actual2.Ref) - assert.Equal(t, schema.Description, actual2.Description) + assert.EqualT(t, schema.Description, actual2.Description) assert.Equal(t, schema.Maximum, actual2.Maximum) assert.Equal(t, schema.Minimum, actual2.Minimum) - assert.Equal(t, schema.ExclusiveMinimum, actual2.ExclusiveMinimum) - assert.Equal(t, schema.ExclusiveMaximum, actual2.ExclusiveMaximum) + assert.EqualT(t, schema.ExclusiveMinimum, actual2.ExclusiveMinimum) + assert.EqualT(t, schema.ExclusiveMaximum, actual2.ExclusiveMaximum) assert.Equal(t, schema.MaxLength, actual2.MaxLength) assert.Equal(t, schema.MinLength, actual2.MinLength) - assert.Equal(t, schema.Pattern, actual2.Pattern) + assert.EqualT(t, schema.Pattern, actual2.Pattern) assert.Equal(t, schema.MaxItems, actual2.MaxItems) assert.Equal(t, schema.MinItems, actual2.MinItems) - assert.True(t, actual2.UniqueItems) + assert.TrueT(t, actual2.UniqueItems) assert.Equal(t, schema.MultipleOf, actual2.MultipleOf) assert.Equal(t, schema.Enum, actual2.Enum) assert.Equal(t, schema.Type, actual2.Type) - assert.Equal(t, schema.Format, actual2.Format) - assert.Equal(t, schema.Title, actual2.Title) + assert.EqualT(t, schema.Format, actual2.Format) + assert.EqualT(t, schema.Title, actual2.Title) assert.Equal(t, schema.MaxProperties, actual2.MaxProperties) assert.Equal(t, schema.MinProperties, actual2.MinProperties) assert.Equal(t, schema.Required, actual2.Required) assert.Equal(t, schema.Items, actual2.Items) assert.Equal(t, schema.AllOf, actual2.AllOf) assert.Equal(t, schema.Properties, actual2.Properties) - assert.Equal(t, schema.Discriminator, actual2.Discriminator) - assert.Equal(t, schema.ReadOnly, actual2.ReadOnly) + assert.EqualT(t, schema.Discriminator, actual2.Discriminator) + assert.EqualT(t, schema.ReadOnly, actual2.ReadOnly) assert.Equal(t, schema.XML, actual2.XML) assert.Equal(t, schema.ExternalDocs, actual2.ExternalDocs) assert.Equal(t, schema.AdditionalProperties, actual2.AdditionalProperties) assert.Equal(t, schema.Extensions, actual2.Extensions) - examples := actual2.Example.([]any) - expEx := schema.Example.([]any) - ex1 := examples[0].(map[string]any) - ex2 := examples[1].(map[string]any) - exp1 := expEx[0].(map[string]any) - exp2 := expEx[1].(map[string]any) + examples, ok := actual2.Example.([]any) + require.TrueT(t, ok, "expected []any for actual2.Example") + expEx, ok := schema.Example.([]any) + require.TrueT(t, ok, "expected []any for schema.Example") + ex1, ok := examples[0].(map[string]any) + require.TrueT(t, ok, "expected map[string]any for examples[0]") + ex2, ok := examples[1].(map[string]any) + require.TrueT(t, ok, "expected map[string]any for examples[1]") + exp1, ok := expEx[0].(map[string]any) + require.TrueT(t, ok, "expected map[string]any for expEx[0]") + exp2, ok := expEx[1].(map[string]any) + require.TrueT(t, ok, "expected map[string]any for expEx[1]") assert.EqualValues(t, exp1["id"], ex1["id"]) assert.Equal(t, exp1["name"], ex1["name"]) diff --git a/schemas/v2/README.md b/schemas/v2/README.md index 32c1b929..af4656e7 100644 --- a/schemas/v2/README.md +++ b/schemas/v2/README.md @@ -2,4 +2,4 @@ This folder contains the Swagger 2.0 specification schema files maintained here: -https://github.com/reverb/swagger-spec/blob/master/schemas/v2.0 \ No newline at end of file + diff --git a/security_scheme.go b/security_scheme.go index 46a4a7e2..6d9019e7 100644 --- a/security_scheme.go +++ b/security_scheme.go @@ -20,17 +20,17 @@ const ( accessCode = "accessCode" ) -// BasicAuth creates a basic auth security scheme +// BasicAuth creates a basic auth security scheme. func BasicAuth() *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: basic}} } -// APIKeyAuth creates an api key auth security scheme +// APIKeyAuth creates an api key auth security scheme. func APIKeyAuth(fieldName, valueSource string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: apiKey, Name: fieldName, In: valueSource}} } -// OAuth2Implicit creates an implicit flow oauth2 security scheme +// OAuth2Implicit creates an implicit flow oauth2 security scheme. func OAuth2Implicit(authorizationURL string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ Type: oauth2, @@ -39,7 +39,7 @@ func OAuth2Implicit(authorizationURL string) *SecurityScheme { }} } -// OAuth2Password creates a password flow oauth2 security scheme +// OAuth2Password creates a password flow oauth2 security scheme. func OAuth2Password(tokenURL string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ Type: oauth2, @@ -48,7 +48,7 @@ func OAuth2Password(tokenURL string) *SecurityScheme { }} } -// OAuth2Application creates an application flow oauth2 security scheme +// OAuth2Application creates an application flow oauth2 security scheme. func OAuth2Application(tokenURL string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ Type: oauth2, @@ -57,7 +57,7 @@ func OAuth2Application(tokenURL string) *SecurityScheme { }} } -// OAuth2AccessToken creates an access token flow oauth2 security scheme +// OAuth2AccessToken creates an access token flow oauth2 security scheme. func OAuth2AccessToken(authorizationURL, tokenURL string) *SecurityScheme { return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{ Type: oauth2, @@ -67,7 +67,7 @@ func OAuth2AccessToken(authorizationURL, tokenURL string) *SecurityScheme { }} } -// SecuritySchemeProps describes a swagger security scheme in the securityDefinitions section +// SecuritySchemeProps describes a swagger security scheme in the securityDefinitions section. type SecuritySchemeProps struct { Description string `json:"description,omitempty"` Type string `json:"type"` @@ -79,7 +79,7 @@ type SecuritySchemeProps struct { Scopes map[string]string `json:"scopes,omitempty"` // oauth2 } -// AddScope adds a scope to this security scheme +// AddScope adds a scope to this security scheme. func (s *SecuritySchemeProps) AddScope(scope, description string) { if s.Scopes == nil { s.Scopes = make(map[string]string) @@ -97,7 +97,7 @@ type SecurityScheme struct { SecuritySchemeProps } -// JSONLookup implements an interface to customize json pointer lookup +// JSONLookup implements an interface to customize json pointer lookup. func (s SecurityScheme) JSONLookup(token string) (any, error) { if ex, ok := s.Extensions[token]; ok { return &ex, nil @@ -107,7 +107,7 @@ func (s SecurityScheme) JSONLookup(token string) (any, error) { return r, err } -// MarshalJSON marshal this to JSON +// MarshalJSON marshal this to JSON. func (s SecurityScheme) MarshalJSON() ([]byte, error) { var ( b1 []byte @@ -150,7 +150,7 @@ func (s SecurityScheme) MarshalJSON() ([]byte, error) { return jsonutils.ConcatJSON(b1, b2), nil } -// UnmarshalJSON marshal this from JSON +// UnmarshalJSON marshal this from JSON. func (s *SecurityScheme) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil { return err diff --git a/spec.go b/spec.go index 0d0aaabc..4eba04b2 100644 --- a/spec.go +++ b/spec.go @@ -13,13 +13,13 @@ import ( //go:generate perl -pi -e s,Json,JSON,g bindata.go const ( - // SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs + // SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs. SwaggerSchemaURL = "http://swagger.io/v2/schema.json#" - // JSONSchemaURL the url for the json schema + // JSONSchemaURL the url for the json schema. JSONSchemaURL = "http://json-schema.org/draft-04/schema#" ) -// MustLoadJSONSchemaDraft04 panics when Swagger20Schema returns an error +// MustLoadJSONSchemaDraft04 panics when Swagger20Schema returns an error. func MustLoadJSONSchemaDraft04() *Schema { d, e := JSONSchemaDraft04() if e != nil { @@ -28,7 +28,7 @@ func MustLoadJSONSchemaDraft04() *Schema { return d } -// JSONSchemaDraft04 loads the json schema document for json schema draft04 +// JSONSchemaDraft04 loads the json schema document for json schema draft04. func JSONSchemaDraft04() (*Schema, error) { b, err := jsonschemaDraft04JSONBytes() if err != nil { @@ -42,7 +42,7 @@ func JSONSchemaDraft04() (*Schema, error) { return schema, nil } -// MustLoadSwagger20Schema panics when Swagger20Schema returns an error +// MustLoadSwagger20Schema panics when Swagger20Schema returns an error. func MustLoadSwagger20Schema() *Schema { d, e := Swagger20Schema() if e != nil { @@ -51,9 +51,8 @@ func MustLoadSwagger20Schema() *Schema { return d } -// Swagger20Schema loads the swagger 2.0 schema from the embedded assets +// Swagger20Schema loads the swagger 2.0 schema from the embedded assets. func Swagger20Schema() (*Schema, error) { - b, err := v2SchemaJSONBytes() if err != nil { return nil, err diff --git a/spec_test.go b/spec_test.go index 998c7c76..05976478 100644 --- a/spec_test.go +++ b/spec_test.go @@ -41,7 +41,7 @@ func TestSpec_Issue2743(t *testing.T) { require.NoError(t, spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: false, PathLoader: testLoader}), ) - require.NotContainsf(t, asJSON(t, sp), "$ref", "all $ref's should have been expanded properly") + require.StringNotContainsTf(t, asJSON(t, sp), "$ref", "all $ref's should have been expanded properly") }) }) } @@ -55,7 +55,7 @@ func TestSpec_Issue1429(t *testing.T) { require.NoError(t, err) // assert well expanded - require.Truef(t, (sp.Paths != nil && sp.Paths.Paths != nil), "expected paths to be available in fixture") + require.TrueTf(t, (sp.Paths != nil && sp.Paths.Paths != nil), "expected paths to be available in fixture") assertPaths1429(t, sp) @@ -69,12 +69,12 @@ func TestSpec_Issue1429(t *testing.T) { require.NoError(t, err) // assert well resolved - require.Truef(t, (sp.Paths != nil && sp.Paths.Paths != nil), "expected paths to be available in fixture") + require.TrueTf(t, (sp.Paths != nil && sp.Paths.Paths != nil), "expected paths to be available in fixture") assertPaths1429SkipSchema(t, sp) for _, def := range sp.Definitions { - assert.Contains(t, def.Ref.String(), "responses.yaml#/definitions/") + assert.StringContainsT(t, def.Ref.String(), "responses.yaml#/definitions/") } } @@ -112,14 +112,14 @@ func assertPaths1429SkipSchema(t testing.TB, sp *spec.Swagger) { continue case "nestedBody": // this one is local - assert.Truef(t, strings.HasPrefix(param.Schema.Ref.String(), "#/definitions/"), + assert.TrueTf(t, strings.HasPrefix(param.Schema.Ref.String(), "#/definitions/"), "expected rooted definitions $ref, got: %s", param.Schema.Ref.String()) continue case "remoteRequest": - assert.Contains(t, param.Schema.Ref.String(), "remote/remote.yaml#/") + assert.StringContainsT(t, param.Schema.Ref.String(), "remote/remote.yaml#/") continue } - assert.Contains(t, param.Schema.Ref.String(), "responses.yaml#/") + assert.StringContainsT(t, param.Schema.Ref.String(), "responses.yaml#/") } @@ -130,13 +130,13 @@ func assertPaths1429SkipSchema(t testing.TB, sp *spec.Swagger) { assert.Nilf(t, response.Schema, "expected response schema to be nil") continue case 204: - assert.Contains(t, response.Schema.Ref.String(), "remote/remote.yaml#/") + assert.StringContainsT(t, response.Schema.Ref.String(), "remote/remote.yaml#/") continue case 404: assert.Empty(t, response.Schema.Ref.String()) continue } - assert.Containsf(t, response.Schema.Ref.String(), "responses.yaml#/", "expected remote ref at resp. %d", code) + assert.StringContainsTf(t, response.Schema.Ref.String(), "responses.yaml#/", "expected remote ref at resp. %d", code) } } } @@ -149,7 +149,7 @@ func TestSpec_MoreLocalExpansion(t *testing.T) { require.NoError(t, spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: false, PathLoader: testLoader})) // asserts all $ref are expanded - assert.NotContains(t, asJSON(t, sp), `"$ref"`) + assert.StringNotContainsT(t, asJSON(t, sp), `"$ref"`) } func TestSpec_Issue69(t *testing.T) { diff --git a/structs_test.go b/structs_test.go index 684c4428..f917ff16 100644 --- a/structs_test.go +++ b/structs_test.go @@ -4,106 +4,51 @@ package spec import ( - "encoding/json" - "reflect" "testing" "github.com/go-openapi/testify/v2/assert" - yaml "go.yaml.in/yaml/v3" ) -func assertSerializeJSON(t testing.TB, actual any, expected string) bool { - ser, err := json.Marshal(actual) - if err != nil { - return assert.Failf(t, "unable to marshal to json", "got: %v: %#v", err, actual) - } - - return assert.Equal(t, expected, string(ser)) -} - -func assertSerializeYAML(t testing.TB, actual any, expected string) bool { - ser, err := yaml.Marshal(actual) - if err != nil { - return assert.Failf(t, "unable to marshal to yaml", "got: %v: %#v", err, actual) - } - return assert.Equal(t, expected, string(ser)) -} - -func derefTypeOf(expected any) (tpe reflect.Type) { - tpe = reflect.TypeOf(expected) - if tpe.Kind() == reflect.Ptr { - tpe = tpe.Elem() - } - return -} - -func isPointed(expected any) (pointed bool) { - tpe := reflect.TypeOf(expected) - if tpe.Kind() == reflect.Ptr { - pointed = true - } - return -} - -func assertParsesJSON(t testing.TB, actual string, expected any) bool { - parsed := reflect.New(derefTypeOf(expected)) - err := json.Unmarshal([]byte(actual), parsed.Interface()) - if err != nil { - return assert.Failf(t, "unable to unmarshal from json", "got: %v: %s", err, actual) - } - act := parsed.Interface() - if !isPointed(expected) { - act = reflect.Indirect(parsed).Interface() - } - return assert.Equal(t, expected, act) -} - -func assertParsesYAML(t testing.TB, actual string, expected any) bool { - parsed := reflect.New(derefTypeOf(expected)) - err := yaml.Unmarshal([]byte(actual), parsed.Interface()) - if err != nil { - return assert.Failf(t, "unable to unmarshal from yaml", "got: %v: %s", err, actual) - } - act := parsed.Interface() - if !isPointed(expected) { - act = reflect.Indirect(parsed).Interface() - } - return assert.Equal(t, expected, act) -} - func TestSerialization_SerializeJSON(t *testing.T) { - assertSerializeJSON(t, []string{"hello"}, "[\"hello\"]") - assertSerializeJSON(t, []string{"hello", "world", "and", "stuff"}, "[\"hello\",\"world\",\"and\",\"stuff\"]") - assertSerializeJSON(t, StringOrArray(nil), "null") - assertSerializeJSON(t, SchemaOrArray{ + assert.JSONMarshalAsT(t, `["hello"]`, []string{"hello"}) + assert.JSONMarshalAsT(t, `["hello","world","and","stuff"]`, []string{"hello", "world", "and", "stuff"}) + assert.JSONMarshalAsT(t, `null`, StringOrArray(nil)) + assert.JSONMarshalAsT(t, `[{"type":"string"}]`, SchemaOrArray{ Schemas: []Schema{ - {SchemaProps: SchemaProps{Type: []string{"string"}}}}, - }, "[{\"type\":\"string\"}]") - assertSerializeJSON(t, SchemaOrArray{ + {SchemaProps: SchemaProps{Type: []string{"string"}}}, + }, + }) + assert.JSONMarshalAsT(t, `[{"type":"string"},{"type":"string"}]`, SchemaOrArray{ Schemas: []Schema{ {SchemaProps: SchemaProps{Type: []string{"string"}}}, {SchemaProps: SchemaProps{Type: []string{"string"}}}, - }}, "[{\"type\":\"string\"},{\"type\":\"string\"}]") - assertSerializeJSON(t, SchemaOrArray{}, "null") + }, + }) + assert.JSONMarshalAsT(t, `null`, SchemaOrArray{}) } func TestSerialization_DeserializeJSON(t *testing.T) { // String - assertParsesJSON(t, "\"hello\"", StringOrArray([]string{"hello"})) - assertParsesJSON(t, "[\"hello\",\"world\",\"and\",\"stuff\"]", - StringOrArray([]string{"hello", "world", "and", "stuff"})) - assertParsesJSON(t, "[\"hello\",\"world\",null,\"stuff\"]", StringOrArray([]string{"hello", "world", "", "stuff"})) - assertParsesJSON(t, "null", StringOrArray(nil)) + assert.JSONUnmarshalAsT(t, StringOrArray([]string{"hello"}), `"hello"`) + assert.JSONUnmarshalAsT(t, + StringOrArray([]string{"hello", "world", "and", "stuff"}), + `["hello","world","and","stuff"]`) + assert.JSONUnmarshalAsT(t, + StringOrArray([]string{"hello", "world", "", "stuff"}), + `["hello","world",null,"stuff"]`) + assert.JSONUnmarshalAsT(t, StringOrArray(nil), `null`) // Schema - assertParsesJSON(t, "{\"type\":\"string\"}", SchemaOrArray{Schema: &Schema{ - SchemaProps: SchemaProps{Type: []string{"string"}}}, - }) - assertParsesJSON(t, "[{\"type\":\"string\"},{\"type\":\"string\"}]", &SchemaOrArray{ + assert.JSONUnmarshalAsT(t, SchemaOrArray{ + Schema: &Schema{ + SchemaProps: SchemaProps{Type: []string{"string"}}, + }, + }, `{"type":"string"}`) + assert.JSONUnmarshalAsT(t, &SchemaOrArray{ Schemas: []Schema{ {SchemaProps: SchemaProps{Type: []string{"string"}}}, {SchemaProps: SchemaProps{Type: []string{"string"}}}, }, - }) - assertParsesJSON(t, "null", SchemaOrArray{}) + }, `[{"type":"string"},{"type":"string"}]`) + assert.JSONUnmarshalAsT(t, SchemaOrArray{}, `null`) } diff --git a/swagger.go b/swagger.go index f7cd0f60..dbe32db8 100644 --- a/swagger.go +++ b/swagger.go @@ -25,7 +25,7 @@ type Swagger struct { SwaggerProps } -// JSONLookup look up a value by the json property name +// JSONLookup look up a value by the json property name. func (s Swagger) JSONLookup(token string) (any, error) { if ex, ok := s.Extensions[token]; ok { return &ex, nil @@ -34,7 +34,7 @@ func (s Swagger) JSONLookup(token string) (any, error) { return r, err } -// MarshalJSON marshals this swagger structure to json +// MarshalJSON marshals this swagger structure to json. func (s Swagger) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(s.SwaggerProps) if err != nil { @@ -47,7 +47,7 @@ func (s Swagger) MarshalJSON() ([]byte, error) { return jsonutils.ConcatJSON(b1, b2), nil } -// UnmarshalJSON unmarshals a swagger spec from json +// UnmarshalJSON unmarshals a swagger spec from json. func (s *Swagger) UnmarshalJSON(data []byte) error { var sw Swagger if err := json.Unmarshal(data, &sw.SwaggerProps); err != nil { @@ -60,7 +60,7 @@ func (s *Swagger) UnmarshalJSON(data []byte) error { return nil } -// GobEncode provides a safe gob encoder for Swagger, including extensions +// GobEncode provides a safe gob encoder for Swagger, including extensions. func (s Swagger) GobEncode() ([]byte, error) { var b bytes.Buffer raw := struct { @@ -74,7 +74,7 @@ func (s Swagger) GobEncode() ([]byte, error) { return b.Bytes(), err } -// GobDecode provides a safe gob decoder for Swagger, including extensions +// GobDecode provides a safe gob decoder for Swagger, including extensions. func (s *Swagger) GobDecode(b []byte) error { var raw struct { Props SwaggerProps @@ -95,7 +95,7 @@ func (s *Swagger) GobDecode(b []byte) error { // NOTE: validation rules // - the scheme, when present must be from [http, https, ws, wss] // - BasePath must start with a leading "/" -// - Paths is required +// - Paths is required. type SwaggerProps struct { ID string `json:"id,omitempty"` Consumes []string `json:"consumes,omitempty"` @@ -126,7 +126,7 @@ type gobSwaggerPropsAlias struct { SecurityIsEmpty bool } -// GobEncode provides a safe gob encoder for SwaggerProps, including empty security requirements +// GobEncode provides a safe gob encoder for SwaggerProps, including empty security requirements. func (o SwaggerProps) GobEncode() ([]byte, error) { raw := gobSwaggerPropsAlias{ Alias: (*swaggerPropsAlias)(&o), @@ -171,7 +171,7 @@ func (o SwaggerProps) GobEncode() ([]byte, error) { return b.Bytes(), err } -// GobDecode provides a safe gob decoder for SwaggerProps, including empty security requirements +// GobDecode provides a safe gob decoder for SwaggerProps, including empty security requirements. func (o *SwaggerProps) GobDecode(b []byte) error { var raw gobSwaggerPropsAlias @@ -207,16 +207,16 @@ func (o *SwaggerProps) GobDecode(b []byte) error { return nil } -// Dependencies represent a dependencies property +// Dependencies represent a dependencies property. type Dependencies map[string]SchemaOrStringArray -// SchemaOrBool represents a schema or boolean value, is biased towards true for the boolean property +// SchemaOrBool represents a schema or boolean value, is biased towards true for the boolean property. type SchemaOrBool struct { Allows bool Schema *Schema } -// JSONLookup implements an interface to customize json pointer lookup +// JSONLookup implements an interface to customize json pointer lookup. func (s SchemaOrBool) JSONLookup(token string) (any, error) { if token == "allows" { return s.Allows, nil @@ -225,10 +225,12 @@ func (s SchemaOrBool) JSONLookup(token string) (any, error) { return r, err } -var jsTrue = []byte("true") -var jsFalse = []byte("false") +var ( + jsTrue = []byte("true") //nolint:gochecknoglobals // constant-like byte slices for JSON marshaling + jsFalse = []byte("false") //nolint:gochecknoglobals // constant-like byte slices for JSON marshaling +) -// MarshalJSON convert this object to JSON +// MarshalJSON convert this object to JSON. func (s SchemaOrBool) MarshalJSON() ([]byte, error) { if s.Schema != nil { return json.Marshal(s.Schema) @@ -240,7 +242,7 @@ func (s SchemaOrBool) MarshalJSON() ([]byte, error) { return jsTrue, nil } -// UnmarshalJSON converts this bool or schema object from a JSON structure +// UnmarshalJSON converts this bool or schema object from a JSON structure. func (s *SchemaOrBool) UnmarshalJSON(data []byte) error { var nw SchemaOrBool if len(data) > 0 { @@ -257,19 +259,19 @@ func (s *SchemaOrBool) UnmarshalJSON(data []byte) error { return nil } -// SchemaOrStringArray represents a schema or a string array +// SchemaOrStringArray represents a schema or a string array. type SchemaOrStringArray struct { Schema *Schema Property []string } -// JSONLookup implements an interface to customize json pointer lookup +// JSONLookup implements an interface to customize json pointer lookup. func (s SchemaOrStringArray) JSONLookup(token string) (any, error) { r, _, err := jsonpointer.GetForToken(s.Schema, token) return r, err } -// MarshalJSON converts this schema object or array into JSON structure +// MarshalJSON converts this schema object or array into JSON structure. func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) { if len(s.Property) > 0 { return json.Marshal(s.Property) @@ -280,7 +282,7 @@ func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) { return []byte("null"), nil } -// UnmarshalJSON converts this schema object or array from a JSON structure +// UnmarshalJSON converts this schema object or array from a JSON structure. func (s *SchemaOrStringArray) UnmarshalJSON(data []byte) error { var first byte if len(data) > 1 { @@ -318,15 +320,15 @@ type Definitions map[string]Schema type SecurityDefinitions map[string]*SecurityScheme // StringOrArray represents a value that can either be a string -// or an array of strings. Mainly here for serialization purposes +// or an array of strings. Mainly here for serialization purposes. type StringOrArray []string -// Contains returns true when the value is contained in the slice +// Contains returns true when the value is contained in the slice. func (s StringOrArray) Contains(value string) bool { return slices.Contains(s, value) } -// JSONLookup implements an interface to customize json pointer lookup +// JSONLookup implements an interface to customize json pointer lookup. func (s SchemaOrArray) JSONLookup(token string) (any, error) { if _, err := strconv.Atoi(token); err == nil { r, _, err := jsonpointer.GetForToken(s.Schemas, token) @@ -336,7 +338,7 @@ func (s SchemaOrArray) JSONLookup(token string) (any, error) { return r, err } -// UnmarshalJSON unmarshals this string or array object from a JSON array or JSON string +// UnmarshalJSON unmarshals this string or array object from a JSON array or JSON string. func (s *StringOrArray) UnmarshalJSON(data []byte) error { var first byte if len(data) > 1 { @@ -368,7 +370,7 @@ func (s *StringOrArray) UnmarshalJSON(data []byte) error { } } -// MarshalJSON converts this string or array to a JSON array or JSON string +// MarshalJSON converts this string or array to a JSON array or JSON string. func (s StringOrArray) MarshalJSON() ([]byte, error) { if len(s) == 1 { return json.Marshal([]string(s)[0]) @@ -377,13 +379,13 @@ func (s StringOrArray) MarshalJSON() ([]byte, error) { } // SchemaOrArray represents a value that can either be a Schema -// or an array of Schema. Mainly here for serialization purposes +// or an array of Schema. Mainly here for serialization purposes. type SchemaOrArray struct { Schema *Schema Schemas []Schema } -// Len returns the number of schemas in this property +// Len returns the number of schemas in this property. func (s SchemaOrArray) Len() int { if s.Schema != nil { return 1 @@ -391,7 +393,7 @@ func (s SchemaOrArray) Len() int { return len(s.Schemas) } -// ContainsType returns true when one of the schemas is of the specified type +// ContainsType returns true when one of the schemas is of the specified type. func (s *SchemaOrArray) ContainsType(name string) bool { if s.Schema != nil { return s.Schema.Type != nil && s.Schema.Type.Contains(name) @@ -399,7 +401,7 @@ func (s *SchemaOrArray) ContainsType(name string) bool { return false } -// MarshalJSON converts this schema object or array into JSON structure +// MarshalJSON converts this schema object or array into JSON structure. func (s SchemaOrArray) MarshalJSON() ([]byte, error) { if len(s.Schemas) > 0 { return json.Marshal(s.Schemas) @@ -407,7 +409,7 @@ func (s SchemaOrArray) MarshalJSON() ([]byte, error) { return json.Marshal(s.Schema) } -// UnmarshalJSON converts this schema object or array from a JSON structure +// UnmarshalJSON converts this schema object or array from a JSON structure. func (s *SchemaOrArray) UnmarshalJSON(data []byte) error { var nw SchemaOrArray var first byte diff --git a/swagger_test.go b/swagger_test.go index 5c167404..9ec0cad9 100644 --- a/swagger_test.go +++ b/swagger_test.go @@ -39,7 +39,7 @@ func init() { //nolint:gochecknoinits // it's okay to load embedded fixtures in } } -var spec = Swagger{ +var spec = Swagger{ //nolint:gochecknoglobals // test fixture SwaggerProps: SwaggerProps{ ID: "http://localhost:3849/api-docs", Swagger: "2.0", @@ -175,9 +175,10 @@ var spec = Swagger{ } */ -func assertSpecs(t testing.TB, actual, expected Swagger) bool { +func assertSpecs(t testing.TB, actual, expected Swagger) { + t.Helper() expected.Swagger = "2.0" - return assert.Equal(t, expected, actual) + assert.Equal(t, expected, actual) } /* @@ -225,25 +226,25 @@ func TestVendorExtensionStringSlice(t *testing.T) { var actual Swagger require.NoError(t, json.Unmarshal(specJSON, &actual)) schemes, ok := actual.Extensions.GetStringSlice("x-schemes") - require.True(t, ok) + require.TrueT(t, ok) assert.Equal(t, []string{"unix", "amqp"}, schemes) notSlice, ok := actual.Extensions.GetStringSlice("x-some-extension") assert.Nil(t, notSlice) - assert.False(t, ok) + assert.FalseT(t, ok) actual.AddExtension("x-another-ext", 100) notString, ok := actual.Extensions.GetStringSlice("x-another-ext") assert.Nil(t, notString) - assert.False(t, ok) + assert.FalseT(t, ok) actual.AddExtension("x-another-slice-ext", []any{100, 100}) notStringSlice, ok := actual.Extensions.GetStringSlice("x-another-slice-ext") assert.Nil(t, notStringSlice) - assert.False(t, ok) + assert.FalseT(t, ok) _, ok = actual.Extensions.GetStringSlice("x-notfound-ext") - assert.False(t, ok) + assert.FalseT(t, ok) } func TestOptionalSwaggerProps_Serialize(t *testing.T) { @@ -256,18 +257,18 @@ func TestOptionalSwaggerProps_Serialize(t *testing.T) { var ms map[string]any require.NoError(t, json.Unmarshal(bytes, &ms)) - assert.NotContains(t, ms, "consumes") - assert.NotContains(t, ms, "produces") - assert.NotContains(t, ms, "schemes") - assert.NotContains(t, ms, "host") - assert.NotContains(t, ms, "basePath") - assert.NotContains(t, ms, "definitions") - assert.NotContains(t, ms, "parameters") - assert.NotContains(t, ms, "responses") - assert.NotContains(t, ms, "securityDefinitions") - assert.NotContains(t, ms, "security") - assert.NotContains(t, ms, "tags") - assert.NotContains(t, ms, "externalDocs") + assert.MapNotContainsT(t, ms, "consumes") + assert.MapNotContainsT(t, ms, "produces") + assert.MapNotContainsT(t, ms, "schemes") + assert.MapNotContainsT(t, ms, "host") + assert.MapNotContainsT(t, ms, "basePath") + assert.MapNotContainsT(t, ms, "definitions") + assert.MapNotContainsT(t, ms, "parameters") + assert.MapNotContainsT(t, ms, "responses") + assert.MapNotContainsT(t, ms, "securityDefinitions") + assert.MapNotContainsT(t, ms, "security") + assert.MapNotContainsT(t, ms, "tags") + assert.MapNotContainsT(t, ms, "externalDocs") } func TestSecurityRequirements(t *testing.T) { @@ -276,11 +277,11 @@ func TestSecurityRequirements(t *testing.T) { sec := minimalSpec.Paths.Paths["/"].Get.Security require.Len(t, sec, 3) - assert.Contains(t, sec[0], "basic") - assert.Contains(t, sec[0], "apiKey") + assert.MapContainsT(t, sec[0], "basic") + assert.MapContainsT(t, sec[0], "apiKey") assert.NotNil(t, sec[1]) assert.Empty(t, sec[1]) - assert.Contains(t, sec[2], "queryKey") + assert.MapContainsT(t, sec[2], "queryKey") } func TestSwaggerGobEncoding(t *testing.T) { diff --git a/tag.go b/tag.go index ae98fd98..af3fb0a4 100644 --- a/tag.go +++ b/tag.go @@ -10,7 +10,7 @@ import ( "github.com/go-openapi/swag/jsonutils" ) -// TagProps describe a tag entry in the top level tags section of a swagger spec +// TagProps describe a tag entry in the top level tags section of a swagger spec. type TagProps struct { Description string `json:"description,omitempty"` Name string `json:"name,omitempty"` @@ -27,12 +27,12 @@ type Tag struct { TagProps } -// NewTag creates a new tag +// NewTag creates a new tag. func NewTag(name, description string, externalDocs *ExternalDocumentation) Tag { return Tag{TagProps: TagProps{Description: description, Name: name, ExternalDocs: externalDocs}} } -// JSONLookup implements an interface to customize json pointer lookup +// JSONLookup implements an interface to customize json pointer lookup. func (t Tag) JSONLookup(token string) (any, error) { if ex, ok := t.Extensions[token]; ok { return &ex, nil @@ -42,7 +42,7 @@ func (t Tag) JSONLookup(token string) (any, error) { return r, err } -// MarshalJSON marshal this to JSON +// MarshalJSON marshal this to JSON. func (t Tag) MarshalJSON() ([]byte, error) { b1, err := json.Marshal(t.TagProps) if err != nil { @@ -55,7 +55,7 @@ func (t Tag) MarshalJSON() ([]byte, error) { return jsonutils.ConcatJSON(b1, b2), nil } -// UnmarshalJSON marshal this from JSON +// UnmarshalJSON marshal this from JSON. func (t *Tag) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &t.TagProps); err != nil { return err diff --git a/validations.go b/validations.go index 2c0dc424..a82c2ffe 100644 --- a/validations.go +++ b/validations.go @@ -3,7 +3,7 @@ package spec -// CommonValidations describe common JSON-schema validations +// CommonValidations describe common JSON-schema validations. type CommonValidations struct { Maximum *float64 `json:"maximum,omitempty"` ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` @@ -143,22 +143,22 @@ func (v CommonValidations) Validations() SchemaValidations { } } -// HasNumberValidations indicates if the validations are for numbers or integers +// HasNumberValidations indicates if the validations are for numbers or integers. func (v CommonValidations) HasNumberValidations() bool { return v.Maximum != nil || v.Minimum != nil || v.MultipleOf != nil } -// HasStringValidations indicates if the validations are for strings +// HasStringValidations indicates if the validations are for strings. func (v CommonValidations) HasStringValidations() bool { return v.MaxLength != nil || v.MinLength != nil || v.Pattern != "" } -// HasArrayValidations indicates if the validations are for arrays +// HasArrayValidations indicates if the validations are for arrays. func (v CommonValidations) HasArrayValidations() bool { return v.MaxItems != nil || v.MinItems != nil || v.UniqueItems } -// HasEnum indicates if the validation includes some enum constraint +// HasEnum indicates if the validation includes some enum constraint. func (v CommonValidations) HasEnum() bool { return len(v.Enum) > 0 } @@ -175,12 +175,12 @@ type SchemaValidations struct { MinProperties *int64 `json:"minProperties,omitempty"` } -// HasObjectValidations indicates if the validations are for objects +// HasObjectValidations indicates if the validations are for objects. func (v SchemaValidations) HasObjectValidations() bool { return v.MaxProperties != nil || v.MinProperties != nil || v.PatternProperties != nil } -// SetValidations for schema validations +// SetValidations for schema validations. func (v *SchemaValidations) SetValidations(val SchemaValidations) { v.CommonValidations.SetValidations(val) v.PatternProperties = val.PatternProperties @@ -188,7 +188,7 @@ func (v *SchemaValidations) SetValidations(val SchemaValidations) { v.MinProperties = val.MinProperties } -// Validations for a schema +// Validations for a schema. func (v SchemaValidations) Validations() SchemaValidations { val := v.CommonValidations.Validations() val.PatternProperties = v.PatternProperties diff --git a/validations_test.go b/validations_test.go index 64422f41..21404cbb 100644 --- a/validations_test.go +++ b/validations_test.go @@ -36,7 +36,6 @@ func mkVal() SchemaValidations { } func TestValidations(t *testing.T) { - var cv CommonValidations val := mkVal() cv.SetValidations(val) @@ -44,34 +43,34 @@ func TestValidations(t *testing.T) { expectedCV := val.CommonValidations require.Equal(t, expectedCV, cv) - require.True(t, cv.HasArrayValidations()) - require.True(t, cv.HasNumberValidations()) - require.True(t, cv.HasStringValidations()) - require.True(t, cv.HasEnum()) + require.TrueT(t, cv.HasArrayValidations()) + require.TrueT(t, cv.HasNumberValidations()) + require.TrueT(t, cv.HasStringValidations()) + require.TrueT(t, cv.HasEnum()) cv.Enum = nil - require.False(t, cv.HasEnum()) + require.FalseT(t, cv.HasEnum()) cv.MaxLength = nil - require.True(t, cv.HasStringValidations()) + require.TrueT(t, cv.HasStringValidations()) cv.MinLength = nil - require.True(t, cv.HasStringValidations()) + require.TrueT(t, cv.HasStringValidations()) cv.Pattern = "" - require.False(t, cv.HasStringValidations()) + require.FalseT(t, cv.HasStringValidations()) cv.Minimum = nil - require.True(t, cv.HasNumberValidations()) + require.TrueT(t, cv.HasNumberValidations()) cv.Maximum = nil - require.True(t, cv.HasNumberValidations()) + require.TrueT(t, cv.HasNumberValidations()) cv.MultipleOf = nil - require.False(t, cv.HasNumberValidations()) + require.FalseT(t, cv.HasNumberValidations()) cv.MaxItems = nil - require.True(t, cv.HasArrayValidations()) + require.TrueT(t, cv.HasArrayValidations()) cv.MinItems = nil - require.True(t, cv.HasArrayValidations()) + require.TrueT(t, cv.HasArrayValidations()) cv.UniqueItems = false - require.False(t, cv.HasArrayValidations()) + require.FalseT(t, cv.HasArrayValidations()) val = mkVal() expectedSV := val @@ -92,24 +91,24 @@ func TestValidations(t *testing.T) { require.Equal(t, val, sv.Validations()) - require.True(t, sv.HasObjectValidations()) + require.TrueT(t, sv.HasObjectValidations()) sv.MinProperties = nil - require.True(t, sv.HasObjectValidations()) + require.TrueT(t, sv.HasObjectValidations()) sv.MaxProperties = nil - require.True(t, sv.HasObjectValidations()) + require.TrueT(t, sv.HasObjectValidations()) sv.PatternProperties = nil - require.False(t, sv.HasObjectValidations()) + require.FalseT(t, sv.HasObjectValidations()) val = mkVal() cv.SetValidations(val) cv.ClearStringValidations() - require.False(t, cv.HasStringValidations()) + require.FalseT(t, cv.HasStringValidations()) cv.ClearNumberValidations() - require.False(t, cv.HasNumberValidations()) + require.FalseT(t, cv.HasNumberValidations()) cv.ClearArrayValidations() - require.False(t, cv.HasArrayValidations()) + require.FalseT(t, cv.HasArrayValidations()) sv.SetValidations(val) sv.ClearObjectValidations(func(validation string, _ any) { @@ -121,5 +120,5 @@ func TestValidations(t *testing.T) { t.Fail() } }) - require.Falsef(t, sv.HasObjectValidations(), "%#v", sv) + require.FalseTf(t, sv.HasObjectValidations(), "%#v", sv) } diff --git a/xml_object.go b/xml_object.go index bf2f8f18..07f7ef8c 100644 --- a/xml_object.go +++ b/xml_object.go @@ -14,43 +14,43 @@ type XMLObject struct { Wrapped bool `json:"wrapped,omitempty"` } -// WithName sets the xml name for the object +// WithName sets the xml name for the object. func (x *XMLObject) WithName(name string) *XMLObject { x.Name = name return x } -// WithNamespace sets the xml namespace for the object +// WithNamespace sets the xml namespace for the object. func (x *XMLObject) WithNamespace(namespace string) *XMLObject { x.Namespace = namespace return x } -// WithPrefix sets the xml prefix for the object +// WithPrefix sets the xml prefix for the object. func (x *XMLObject) WithPrefix(prefix string) *XMLObject { x.Prefix = prefix return x } -// AsAttribute flags this object as xml attribute +// AsAttribute flags this object as xml attribute. func (x *XMLObject) AsAttribute() *XMLObject { x.Attribute = true return x } -// AsElement flags this object as an xml node +// AsElement flags this object as an xml node. func (x *XMLObject) AsElement() *XMLObject { x.Attribute = false return x } -// AsWrapped flags this object as wrapped, this is mostly useful for array types +// AsWrapped flags this object as wrapped, this is mostly useful for array types. func (x *XMLObject) AsWrapped() *XMLObject { x.Wrapped = true return x } -// AsUnwrapped flags this object as an xml node +// AsUnwrapped flags this object as an xml node. func (x *XMLObject) AsUnwrapped() *XMLObject { x.Wrapped = false return x diff --git a/xml_object_test.go b/xml_object_test.go index f0c46ba9..e1063eb0 100644 --- a/xml_object_test.go +++ b/xml_object_test.go @@ -15,7 +15,7 @@ func TestXmlObject_Serialize(t *testing.T) { obj1 := XMLObject{} actual, err := json.Marshal(obj1) require.NoError(t, err) - assert.Equal(t, "{}", string(actual)) + assert.EqualT(t, "{}", string(actual)) obj2 := XMLObject{ Name: "the name", @@ -33,15 +33,19 @@ func TestXmlObject_Serialize(t *testing.T) { assert.Equal(t, obj2.Name, ad["name"]) assert.Equal(t, obj2.Namespace, ad["namespace"]) assert.Equal(t, obj2.Prefix, ad["prefix"]) - assert.True(t, ad["attribute"].(bool)) - assert.True(t, ad["wrapped"].(bool)) + attrVal, ok := ad["attribute"].(bool) + require.TrueT(t, ok, "expected bool for attribute") + assert.TrueT(t, attrVal) + wrappedVal, ok := ad["wrapped"].(bool) + require.TrueT(t, ok, "expected bool for wrapped") + assert.TrueT(t, wrappedVal) } func TestXmlObject_Deserialize(t *testing.T) { expected := XMLObject{} actual := XMLObject{} require.NoError(t, json.Unmarshal([]byte("{}"), &actual)) - assert.Equal(t, expected, actual) + assert.EqualT(t, expected, actual) completed := `{"name":"the name","namespace":"the namespace","prefix":"the prefix","attribute":true,"wrapped":true}` expected = XMLObject{ @@ -54,5 +58,5 @@ func TestXmlObject_Deserialize(t *testing.T) { actual = XMLObject{} require.NoError(t, json.Unmarshal([]byte(completed), &actual)) - assert.Equal(t, expected, actual) + assert.EqualT(t, expected, actual) } From fb0c59ef05141ce91a44ef4b93bfcc3af1599f0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 09:18:41 +0000 Subject: [PATCH 13/54] build(deps): bump the development-dependencies group with 7 updates Bumps the development-dependencies group with 7 updates: | Package | From | To | | --- | --- | --- | | [go-openapi/ci-workflows/.github/workflows/auto-merge.yml](https://github.com/go-openapi/ci-workflows) | `0.2.9` | `0.2.11` | | [go-openapi/ci-workflows/.github/workflows/bump-release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.9` | `0.2.11` | | [go-openapi/ci-workflows/.github/workflows/codeql.yml](https://github.com/go-openapi/ci-workflows) | `0.2.9` | `0.2.11` | | [go-openapi/ci-workflows/.github/workflows/contributors.yml](https://github.com/go-openapi/ci-workflows) | `0.2.9` | `0.2.11` | | [go-openapi/ci-workflows/.github/workflows/go-test.yml](https://github.com/go-openapi/ci-workflows) | `0.2.9` | `0.2.11` | | [go-openapi/ci-workflows/.github/workflows/scanner.yml](https://github.com/go-openapi/ci-workflows) | `0.2.9` | `0.2.11` | | [go-openapi/ci-workflows/.github/workflows/release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.9` | `0.2.11` | Updates `go-openapi/ci-workflows/.github/workflows/auto-merge.yml` from 0.2.9 to 0.2.11 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff...435746a4b72b06b6b6989c309fd2ad8150dbae5a) Updates `go-openapi/ci-workflows/.github/workflows/bump-release.yml` from 0.2.9 to 0.2.11 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff...435746a4b72b06b6b6989c309fd2ad8150dbae5a) Updates `go-openapi/ci-workflows/.github/workflows/codeql.yml` from 0.2.9 to 0.2.11 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff...435746a4b72b06b6b6989c309fd2ad8150dbae5a) Updates `go-openapi/ci-workflows/.github/workflows/contributors.yml` from 0.2.9 to 0.2.11 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff...435746a4b72b06b6b6989c309fd2ad8150dbae5a) Updates `go-openapi/ci-workflows/.github/workflows/go-test.yml` from 0.2.9 to 0.2.11 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff...435746a4b72b06b6b6989c309fd2ad8150dbae5a) Updates `go-openapi/ci-workflows/.github/workflows/scanner.yml` from 0.2.9 to 0.2.11 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff...435746a4b72b06b6b6989c309fd2ad8150dbae5a) Updates `go-openapi/ci-workflows/.github/workflows/release.yml` from 0.2.9 to 0.2.11 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff...435746a4b72b06b6b6989c309fd2ad8150dbae5a) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/auto-merge.yml dependency-version: 0.2.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/bump-release.yml dependency-version: 0.2.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/codeql.yml dependency-version: 0.2.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/contributors.yml dependency-version: 0.2.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/go-test.yml dependency-version: 0.2.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/scanner.yml dependency-version: 0.2.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/release.yml dependency-version: 0.2.11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 9b81e3a9..48e5a578 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index 0cf81156..11411719 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -30,7 +30,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 with: bump-type: ${{ inputs.bump-type }} tag-message-title: ${{ inputs.tag-message-title }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e503cb0a..32fb5e3e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index c7fcf5b6..33a469f5 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index e1ba8d81..514d891d 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index ed357e23..b936bc10 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # V0.2.9 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # V0.2.11 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 3c430127..b8347438 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@84f8f9c0759d5d1d0c32b18a7abaa0cba65ebcff # v0.2.9 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 with: tag: ${{ github.ref_name }} secrets: inherit From cb33f35c7b11841301a60c582e06d81268d3ee3d Mon Sep 17 00:00:00 2001 From: "bot-go-openapi[bot]" <246880138+bot-go-openapi[bot]@users.noreply.github.com> Date: Sat, 7 Mar 2026 05:08:49 +0000 Subject: [PATCH 14/54] doc: updated contributors file Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CONTRIBUTORS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 2967e3ce..204a9858 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 38 | 392 | +| 38 | 393 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 191 | | -| @fredbi | 90 | | +| @fredbi | 91 | | | @pytlesk4 | 26 | | | @kul-amr | 10 | | | @keramix | 10 | | From 6bf199683e5a331e130e563c841eb0aba8fe0679 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 09:16:22 +0000 Subject: [PATCH 15/54] build(deps): bump the go-openapi-dependencies group with 2 updates Bumps the go-openapi-dependencies group with 2 updates: [github.com/go-openapi/testify/enable/yaml/v2](https://github.com/go-openapi/testify) and [github.com/go-openapi/testify/v2](https://github.com/go-openapi/testify). Updates `github.com/go-openapi/testify/enable/yaml/v2` from 2.4.0 to 2.4.1 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.4.0...v2.4.1) Updates `github.com/go-openapi/testify/v2` from 2.4.0 to 2.4.1 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.4.0...v2.4.1) --- updated-dependencies: - dependency-name: github.com/go-openapi/testify/enable/yaml/v2 dependency-version: 2.4.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/testify/v2 dependency-version: 2.4.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index b1ed3850..5db72de4 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/go-openapi/swag/jsonutils v0.25.5 github.com/go-openapi/swag/loading v0.25.5 github.com/go-openapi/swag/stringutils v0.25.5 - github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 - github.com/go-openapi/testify/v2 v2.4.0 + github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 + github.com/go-openapi/testify/v2 v2.4.1 ) require ( diff --git a/go.sum b/go.sum index 39d1d0b3..74aff222 100644 --- a/go.sum +++ b/go.sum @@ -18,10 +18,10 @@ github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzz github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= -github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= -github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 h1:NZOrZmIb6PTv5LTFxr5/mKV/FjbUzGE7E6gLz7vFoOQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.1/go.mod h1:r7dwsujEHawapMsxA69i+XMGZrQ5tRauhLAjV/sxg3Q= +github.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw= +github.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From b2867e8edaf21c4c7521a23310694990fdbf0caf Mon Sep 17 00:00:00 2001 From: fredbi Date: Sun, 15 Mar 2026 09:39:11 +0100 Subject: [PATCH 16/54] doc: update discord link (#260) --- .github/CONTRIBUTING.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 069bd7e5..8983754c 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -40,7 +40,7 @@ You may also join our discord server where you may discuss issues or requests. [![Discord Server][discord-badge]][discord-url] [discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue -[discord-url]: https://discord.gg/twZ9BwT3 +[discord-url]: https://discord.gg/FfnFYaC3k5 ### Reporting issues diff --git a/README.md b/README.md index 134809fd..405002b8 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ Maintainers can cut a new release by either: [slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM [slack-url]: https://goswagger.slack.com/archives/C04R30YMU [discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue -[discord-url]: https://discord.gg/twZ9BwT3 +[discord-url]: https://discord.gg/FfnFYaC3k5 [license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg From b7c0c1923c918a4ab01b66d3faa3c838feea3916 Mon Sep 17 00:00:00 2001 From: fredbi Date: Sun, 15 Mar 2026 23:11:07 +0100 Subject: [PATCH 17/54] doc: add portable agentic instructions (#261) * doc: add portable agentic instructions Add copilot-instructions.md, AGENTS.md (symlink), .github/copilot symlink to .claude/rules, contributions and workflows rules. Rewrite CLAUDE.md with accurate package documentation. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Frederic BIDON * doc: include previously ignored rule files Add linting.md and testing.md rules that were hidden by the old .gitignore pattern. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Frederic BIDON --------- Signed-off-by: Frederic BIDON Co-authored-by: Claude Opus 4.6 (1M context) --- .claude/.gitignore | 5 + .claude/CLAUDE.md | 85 +++++ .claude/rules/contributions.md | 52 +++ .claude/rules/github-workflows-conventions.md | 297 ++++++++++++++++++ .claude/rules/go-conventions.md | 11 + .claude/rules/linting.md | 17 + .claude/rules/testing.md | 47 +++ .github/copilot | 1 + .github/copilot-instructions.md | 61 ++++ .gitignore | 1 - AGENTS.md | 1 + 11 files changed, 577 insertions(+), 1 deletion(-) create mode 100644 .claude/.gitignore create mode 100644 .claude/CLAUDE.md create mode 100644 .claude/rules/contributions.md create mode 100644 .claude/rules/github-workflows-conventions.md create mode 100644 .claude/rules/go-conventions.md create mode 100644 .claude/rules/linting.md create mode 100644 .claude/rules/testing.md create mode 120000 .github/copilot create mode 100644 .github/copilot-instructions.md create mode 120000 AGENTS.md diff --git a/.claude/.gitignore b/.claude/.gitignore new file mode 100644 index 00000000..f830ad13 --- /dev/null +++ b/.claude/.gitignore @@ -0,0 +1,5 @@ +plans/ +skills/ +commands/ +agents/ +hooks/ diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 00000000..d580cb9e --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1,85 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Go types modeling the [Swagger 2.0 / OpenAPI 2.0](https://swagger.io/specification/v2/) +specification. Every object in the spec --- `Swagger`, `Info`, `PathItem`, `Operation`, +`Parameter`, `Schema`, `Response`, `Header`, `SecurityScheme`, etc. --- has a corresponding +Go struct with JSON serialization (`encoding/json`) that round-trips through the spec's +JSON representation. + +This package is the **foundational data model** for the +[go-swagger](https://github.com/go-swagger/go-swagger) ecosystem. Higher-level packages +(`analysis`, `loads`, `validate`, `runtime`) consume these types to load, analyze, validate, +and serve Swagger specifications. Because it sits at the bottom of the dependency graph, +changes here ripple through the entire ecosystem. + +Key capabilities beyond plain structs: + +- **`$ref` resolution** --- the `Ref` type wraps JSON Reference pointers; the `expander` + resolves `$ref` nodes (local, remote, circular) into fully expanded specs. +- **Schema composition** --- `Schema` supports `allOf`, `additionalProperties`, + `additionalItems`, and JSON Schema validations (`minimum`, `pattern`, `enum`, etc.). +- **URL normalization** --- cross-platform path/URL normalization for `$ref` targets. +- **Embedded spec** --- a copy of the Swagger 2.0 JSON Schema is embedded via `go:embed` + for offline use. + +See [docs/MAINTAINERS.md](../docs/MAINTAINERS.md) for CI/CD, release process, and repo structure details. + +### Package layout (single package) + +| File | Contents | +|------|----------| +| `swagger.go` | Root `Swagger` type (top-level spec object) | +| `info.go` | `Info`, `ContactInfo`, `LicenseInfo` | +| `paths.go` | `Paths` (map of path patterns to `PathItem`) | +| `path_item.go` | `PathItem` (GET/PUT/POST/DELETE/... operations per path) | +| `operation.go` | `Operation` (single API operation) | +| `parameter.go` | `Parameter` (query, header, path, body, formData) | +| `header.go` | `Header` | +| `response.go`, `responses.go` | `Response`, `Responses` | +| `schema.go` | `Schema` (JSON Schema subset used by Swagger) | +| `security_scheme.go` | `SecurityScheme` | +| `items.go` | `Items` (non-body parameter schema) | +| `ref.go` | `Ref` type, JSON Reference (`$ref`) handling | +| `expander.go` | `$ref` expansion / resolution engine | +| `normalizer.go` | URL/path normalization (platform-specific variants) | +| `cache.go` | Resolution cache for expanded specs | +| `validations.go` | Common validation properties shared across types | +| `properties.go` | `SchemaProperties` ordered map | +| `embed.go` | Embedded Swagger 2.0 JSON Schema (`go:embed`) | +| `spec.go` | `MustLoadSwagger20Schema()` loader | +| `external_docs.go` | `ExternalDocumentation` | +| `tag.go` | `Tag` | +| `xml_object.go` | `XMLObject` | +| `debug.go` | Debug logging helpers | + +### Key API + +- `Swagger` --- root specification object; deserialize with `json.Unmarshal` +- `Schema` --- JSON Schema with Swagger extensions; supports `allOf`, `$ref`, validations +- `Ref` / `MustCreateRef(uri)` --- JSON Reference wrapper +- `ExpandSpec(spec, opts)` --- resolve all `$ref` nodes in a specification +- `ExpandSchema(schema, root, cache)` --- resolve `$ref` nodes in a single schema +- `ResolveRef(root, ref)` / `ResolveParameter` / `ResolveResponse` --- targeted resolution + +### Dependencies + +- `github.com/go-openapi/jsonpointer` --- JSON Pointer (RFC 6901) navigation +- `github.com/go-openapi/jsonreference` --- JSON Reference parsing +- `github.com/go-openapi/swag` --- JSON/YAML utilities, name mangling +- `github.com/go-openapi/testify/v2` --- test-only assertions (zero-dep testify fork) + +### Notable historical design decisions + +- **Mixin of spec types and `$ref`** --- many types embed both their data fields and a `Ref` + field. When `$ref` is present, the data fields are ignored per the Swagger specification. + This is modeled by custom `MarshalJSON`/`UnmarshalJSON` on each type. +- **`VendorExtensible`** --- most types embed `VendorExtensible` to capture `x-` extension + fields as `map[string]any`. +- **`SchemaProperties` as ordered slice** --- schema properties are stored as a slice of + key-value pairs (not a map) to preserve declaration order during round-trip serialization. +- **Platform-specific normalization** --- Windows path handling differs from Unix; separate + `normalizer_windows.go` / `normalizer_nonwindows.go` files handle this. diff --git a/.claude/rules/contributions.md b/.claude/rules/contributions.md new file mode 100644 index 00000000..58027b9c --- /dev/null +++ b/.claude/rules/contributions.md @@ -0,0 +1,52 @@ +--- +paths: + - "**/*" +--- + +# Contribution rules (go-openapi) + +Read `.github/CONTRIBUTING.md` before opening a pull request. + +## Commit hygiene + +- Every commit **must** be DCO signed-off (`git commit -s`) with a real email address. + PGP-signed commits are appreciated but not required. +- Agents may be listed as co-authors (`Co-Authored-By:`) but the commit **author must be the human sponsor**. + We do not accept commits solely authored by bots or agents. +- Squash commits into logical units of work before requesting review (`git rebase -i`). + +## Linting + +Before pushing, verify your changes pass linting against the base branch: + +```sh +golangci-lint run --new-from-rev master +``` + +Install the latest version if you don't have it: + +```sh +go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest +``` + +## Problem statement + +- Clearly describe the problem the PR solves, or reference an existing issue. +- PR descriptions must not be vague ("fix bug", "improve code") — explain *what* was wrong and *why* the change is correct. + +## Tests are mandatory + +- Every bug fix or feature **must** include tests that demonstrate the problem and verify the fix. +- The only exceptions are documentation changes and typo fixes. +- Aim for at least 80% coverage of your patch. +- Run the full test suite before submitting: + +For mono-repos: +```sh +go test work ./... +``` + +For single module repos: +```sh +go test ./... +``` diff --git a/.claude/rules/github-workflows-conventions.md b/.claude/rules/github-workflows-conventions.md new file mode 100644 index 00000000..33800d0e --- /dev/null +++ b/.claude/rules/github-workflows-conventions.md @@ -0,0 +1,297 @@ +--- +paths: + - ".github/workflows/**.yml" + - ".github/workflows/**.yaml" +--- + +# GitHub Actions Workflows Formatting and Style Conventions + +This rule captures YAML and bash formatting rules to provide a consistent maintainer's experience across CI workflows. + +## File Structure + +**REQUIRED**: All github action workflows are organized as a flat structure beneath `.github/workflows/`. + +> GitHub does not support a hierarchical organization for workflows yet. + +**REQUIRED**: YAML files are conventionally named `{workflow}.yml`, with the `.yml` extension. + +## Code Style & Formatting + +### Expression Spacing + +**REQUIRED**: All GitHub Actions expressions must have spaces inside the braces: + +```yaml +# ✅ CORRECT +env: + PR_URL: ${{ github.event.pull_request.html_url }} + TOKEN: ${{ secrets.GITHUB_TOKEN }} + +# ❌ WRONG +env: + PR_URL: ${{github.event.pull_request.html_url}} + TOKEN: ${{secrets.GITHUB_TOKEN}} +``` + +> Provides a consistent formatting rule. + +### Conditional Syntax + +**REQUIRED**: Always use `${{ }}` in `if:` conditions: + +```yaml +# ✅ CORRECT +if: ${{ inputs.enable-signing == 'true' }} +if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }} + +# ❌ WRONG (works but inconsistent) +if: inputs.enable-signing == 'true' +``` + +> Provides a consistent formatting rule. + +### GitHub Workflow Commands + +**REQUIRED**: Use workflow commands for status messages that should appear as annotations, with **double colon separator**: + +```bash +# ✅ CORRECT - Double colon (::) separator after title +echo "::notice title=build::Build completed successfully" +echo "::warning title=race-condition::Merge already in progress" +echo "::error title=deployment::Failed to deploy" + +# ❌ WRONG - Single colon separator (won't render as annotation) +echo "::notice title=build:Build completed" # Missing second ':' +echo "::warning title=x:message" # Won't display correctly +``` + +**Syntax pattern:** `::LEVEL title=TITLE::MESSAGE` +- `LEVEL`: notice, warning, or error +- Double `::` separator is required between title and message + +> Wrong syntax may raise untidy warnings and produce botched output. + +### YAML arrays formatting + +For steps, YAML arrays are formatted with the following indentation: + +```yaml +# ✅ CORRECT - Clear spacing between steps + steps: + - + name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2.5.0 + - + name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + +# ❌ WRONG - Dense format, more difficult to read + steps: + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2.5.0 + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + +# ❌ WRONG - YAML comment or blank line could be avoided + steps: + # + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2.5.0 + + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 +``` + +## Security Best Practices + +### Version Pinning using SHAs + +**REQUIRED**: Always pin action versions to commit SHAs: + +> Runs must be repeatable with known pinned version. Automated updates are pushed frequently (e.g. daily or weekly) +> to keep pinned versions up-to-date. + +```yaml +# ✅ CORRECT - Pinned to commit SHA with version comment +uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 +uses: crazy-max/ghaction-import-gpg@e89d40939c28e39f97cf32126055eeae86ba74ec # v6.3.0 + +# ❌ WRONG - Mutable tag reference +uses: actions/checkout@v6 +``` + +### Permission settings + +**REQUIRED**: Always set minimal permissions at the workflow level. + +```yaml +# ✅ CORRECT - Workflow level permissions set to minimum +permissions: + contents: read + +# ❌ WRONG - Workflow level permissions with undue privilege escalation +permissions: + contents: write + pull-requests: write +``` + +**REQUIRED**: Whenever a job needs elevated privileges, always raise required permissions at the job level. + +```yaml +# ✅ CORRECT - Job level permissions set to the specific requirements for that job +jobs: + dependabot: + permissions: + contents: write + pull-requests: write + uses: ./.github/workflows/auto-merge.yml + secrets: inherit + +# ❌ WRONG - Same permissions but set at workflow level instead of job level +permissions: + contents: write + pull-requests: write +``` + +> (Security best practice detected by CodeQL analysis) + +### Undue secret exposure + +**NEVER** use `secrets[inputs.name]` — always use explicit secret parameters. + +> Using keyed access to secrets forces the runner to expose ALL secrets to the job, which causes a security risk +> (caught and reported by CodeQL security analysis). + +```yaml +# ❌ SECURITY VULNERABILITY +# This exposes ALL organization and repository secrets to the runner +on: + workflow_call: + inputs: + secret-name: + type: string +jobs: + my-job: + steps: + - uses: some-action@v1 + with: + token: ${{ secrets[inputs.secret-name] }} # ❌ DANGEROUS! +``` + +**SOLUTION**: Use explicit secret parameters with fallback for defaults: + +```yaml +# ✅ SECURE +on: + workflow_call: + secrets: + gpg-private-key: + required: false +jobs: + my-job: + steps: + - uses: go-openapi/gh-actions/ci-jobs/bot-credentials@master + with: + # Falls back to go-openapi default if not explicitly passed + gpg-private-key: ${{ secrets.gpg-private-key || secrets.CI_BOT_GPG_PRIVATE_KEY }} +``` + +## Common Gotchas + +### Description fields containing parsable expressions + +**REQUIRED**: **DO NOT** use `${{ }}` expressions in description fields: + +> They may be parsed by the runner, wrongly interpreted or causing failure (e.g. "not defined in this context"). + +```yaml +# ❌ WRONG - Can cause YAML parsing errors +description: | + Pass it as: gpg-private-key: ${{ secrets.MY_KEY }} + +# ✅ CORRECT +description: | + Pass it as: secrets.MY_KEY +``` + +### Boolean inputs + +**Boolean inputs are forbidden**: NEVER use `type: boolean` for workflow inputs due to unpredictable type coercion + +> gh-action expressions using boolean job inputs are hard to predict and come with many quirks. + + ```yaml + # ❌ FORBIDDEN - Boolean inputs have type coercion issues + on: + workflow_call: + inputs: + enable-feature: + type: boolean # ❌ NEVER USE THIS + default: true + + # The pattern `x == 'true' || x == true` seems safe but fails when: + # - x is not a boolean: `x == true` evaluates to true if x != null + # - Type coercion is unpredictable and error-prone + + # ✅ CORRECT - Always use string type for boolean-like inputs + on: + workflow_call: + inputs: + enable-feature: + type: string # ✅ Use string instead + default: 'true' # String value + + jobs: + my-job: + # Simple, reliable comparison + if: ${{ inputs.enable-feature == 'true' }} + + # ✅ In bash, this works perfectly (inputs are always strings in bash): + if [[ '${{ inputs.enable-feature }}' == 'true' ]]; then + echo "Feature enabled" + fi + ``` + + **Rule**: Use `type: string` with values `'true'` or `'false'` for all boolean-like workflow inputs. + + **Note**: Step outputs and bash variables are always strings, so `x == 'true'` works fine for those. + +### YAML fold scalars in action inputs + +**NEVER** use `>` or `>-` (fold scalars) for `with:` input values: + +> The YAML spec says fold scalars replace newlines with spaces, but the GitHub Actions runner +> does not reliably honor this for action inputs. The action receives the literal multi-line string +> instead of a single folded line, which breaks flag parsing. + +```yaml +# ❌ BROKEN - Fold scalar, args received with embedded newlines +- uses: goreleaser/goreleaser-action@... + with: + args: >- + release + --clean + --release-notes /tmp/notes.md + +# ✅ CORRECT - Single line +- uses: goreleaser/goreleaser-action@... + with: + args: release --clean --release-notes /tmp/notes.md + +# ✅ CORRECT - Literal block scalar (|) is fine for run: scripts +- run: | + echo "line 1" + echo "line 2" +``` + +**Rule**: Use single-line strings for `with:` inputs. Only use `|` (literal block scalar) for `run:` scripts where multi-line is intentional. diff --git a/.claude/rules/go-conventions.md b/.claude/rules/go-conventions.md new file mode 100644 index 00000000..9c2c9240 --- /dev/null +++ b/.claude/rules/go-conventions.md @@ -0,0 +1,11 @@ +--- +paths: + - "**/*.go" +--- + +# Code conventions (go-openapi) + +- All files must have SPDX license headers (Apache-2.0). +- Go version policy: support the 2 latest stable Go minor versions. +- Commits require DCO sign-off (`git commit -s`). +- use `golangci-lint fmt` to format code (not `gofmt` or `gofumpt`) diff --git a/.claude/rules/linting.md b/.claude/rules/linting.md new file mode 100644 index 00000000..a4456d42 --- /dev/null +++ b/.claude/rules/linting.md @@ -0,0 +1,17 @@ +--- +paths: + - "**/*.go" +--- + +# Linting conventions (go-openapi) + +```sh +golangci-lint run +``` + +Config: `.golangci.yml` — posture is `default: all` with explicit disables. +See `docs/STYLE.md` for the rationale behind each disabled linter. + +Key rules: +- Every `//nolint` directive **must** have an inline comment explaining why. +- Prefer disabling a linter over scattering `//nolint` across the codebase. diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md new file mode 100644 index 00000000..6974abaa --- /dev/null +++ b/.claude/rules/testing.md @@ -0,0 +1,47 @@ +--- +paths: + - "**/*_test.go" +--- + +# Testing conventions (go-openapi) + +## Running tests + +**Single module repos:** + +```sh +go test ./... +``` + +**Mono-repos (with `go.work`):** + +```sh +# All modules +go test work ./... + +# Single module +go test ./conv/... +``` + +Note: in mono-repos, plain `go test ./...` only tests the root module. +The `work` pattern expands to all modules listed in `go.work`. + +CI runs tests on `{ubuntu, macos, windows} x {stable, oldstable}` with `-race` via `gotestsum`. + +## Fuzz tests + +```sh +# List all fuzz targets +go test -list Fuzz ./... + +# Run a specific target (go test -fuzz cannot span multiple packages) +go test -fuzz=Fuzz -run='FuzzTargetName$' -fuzztime=1m30s ./package +``` + +Fuzz corpus lives in `testdata/fuzz/` within each package. CI runs each fuzz target for 1m30s +with a 5m minimize timeout. + +## Test framework + +`github.com/go-openapi/testify/v2` — a zero-dep fork of `stretchr/testify`. +Because it's a fork, `testifylint` does not work. diff --git a/.github/copilot b/.github/copilot new file mode 120000 index 00000000..52694831 --- /dev/null +++ b/.github/copilot @@ -0,0 +1 @@ +../.claude/rules \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..9131b7ed --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,61 @@ +# Copilot Instructions — spec + +## Project Overview + +Go types modeling the Swagger 2.0 / OpenAPI 2.0 specification. This package is the +foundational data model for the go-swagger ecosystem — every specification object +(`Swagger`, `Schema`, `Operation`, `Parameter`, etc.) is a Go struct with JSON +round-trip serialization. It also includes a `$ref` expansion engine for resolving +JSON References across local and remote documents. + +Single module: `github.com/go-openapi/spec`. + +### Package layout (single package) + +| File | Contents | +|------|----------| +| `swagger.go` | Root `Swagger` type (top-level spec object) | +| `schema.go` | `Schema` (JSON Schema subset used by Swagger) | +| `operation.go` | `Operation` (single API operation) | +| `parameter.go` | `Parameter` (query, header, path, body, formData) | +| `response.go`, `responses.go` | `Response`, `Responses` | +| `ref.go` | `Ref` type, JSON Reference (`$ref`) handling | +| `expander.go` | `$ref` expansion / resolution engine | +| `normalizer.go` | URL/path normalization (platform-specific variants) | + +### Key API + +- `Swagger` — root specification object; deserialize with `json.Unmarshal` +- `Schema` — JSON Schema with Swagger extensions; supports `allOf`, `$ref`, validations +- `Ref` / `MustCreateRef(uri)` — JSON Reference wrapper +- `ExpandSpec(spec, opts)` — resolve all `$ref` nodes in a specification +- `ExpandSchema(schema, root, cache)` — resolve `$ref` nodes in a single schema +- `ResolveRef(root, ref)` / `ResolveParameter` / `ResolveResponse` — targeted resolution + +### Dependencies + +- `github.com/go-openapi/jsonpointer` — JSON Pointer (RFC 6901) navigation +- `github.com/go-openapi/jsonreference` — JSON Reference parsing +- `github.com/go-openapi/swag` — JSON/YAML utilities, name mangling +- `github.com/go-openapi/testify/v2` — test-only assertions (zero-dep testify fork) + +## Building & testing + +```sh +go test ./... +``` + +## Conventions + +Coding conventions are found beneath `.github/copilot` + +### Summary + +- All `.go` files must have SPDX license headers (Apache-2.0). +- Commits require DCO sign-off (`git commit -s`). +- Linting: `golangci-lint run` — config in `.golangci.yml` (posture: `default: all` with explicit disables). +- Every `//nolint` directive **must** have an inline comment explaining why. +- Tests: `go test ./...`. CI runs on `{ubuntu, macos, windows} x {stable, oldstable}` with `-race`. +- Test framework: `github.com/go-openapi/testify/v2` (not `stretchr/testify`; `testifylint` does not work). + +See `.github/copilot/` (symlinked to `.claude/rules/`) for detailed rules on Go conventions, linting, testing, and contributions. diff --git a/.gitignore b/.gitignore index 885dc27a..d8f4186f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ .idea .env .mcp.json -.claude/ diff --git a/AGENTS.md b/AGENTS.md new file mode 120000 index 00000000..02dd1341 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +.github/copilot-instructions.md \ No newline at end of file From 1505803bad02e000a03bdc60a19329191d4aa95b Mon Sep 17 00:00:00 2001 From: fredbi Date: Mon, 16 Mar 2026 00:03:50 +0100 Subject: [PATCH 18/54] chore: bump go directive to 1.25.0 (#262) Update all go.mod (and go.work where applicable) to require go 1.25.0. Signed-off-by: Frederic BIDON Co-authored-by: Claude Opus 4.6 (1M context) --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 5db72de4..32ed725a 100644 --- a/go.mod +++ b/go.mod @@ -18,4 +18,4 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // indirect ) -go 1.24.0 +go 1.25.0 From 2e5142b8e1435aa5d94a767129caad9950c1562c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 15 Mar 2026 23:05:03 +0000 Subject: [PATCH 19/54] build(deps): bump the development-dependencies group with 7 updates Bumps the development-dependencies group with 7 updates: | Package | From | To | | --- | --- | --- | | [go-openapi/ci-workflows/.github/workflows/auto-merge.yml](https://github.com/go-openapi/ci-workflows) | `0.2.11` | `0.2.15` | | [go-openapi/ci-workflows/.github/workflows/bump-release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.11` | `0.2.15` | | [go-openapi/ci-workflows/.github/workflows/codeql.yml](https://github.com/go-openapi/ci-workflows) | `0.2.11` | `0.2.15` | | [go-openapi/ci-workflows/.github/workflows/contributors.yml](https://github.com/go-openapi/ci-workflows) | `0.2.11` | `0.2.15` | | [go-openapi/ci-workflows/.github/workflows/go-test.yml](https://github.com/go-openapi/ci-workflows) | `0.2.11` | `0.2.15` | | [go-openapi/ci-workflows/.github/workflows/scanner.yml](https://github.com/go-openapi/ci-workflows) | `0.2.11` | `0.2.15` | | [go-openapi/ci-workflows/.github/workflows/release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.11` | `0.2.15` | Updates `go-openapi/ci-workflows/.github/workflows/auto-merge.yml` from 0.2.11 to 0.2.15 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/435746a4b72b06b6b6989c309fd2ad8150dbae5a...e8e6599fe480362cb0d5cbdac5b245cc833742f5) Updates `go-openapi/ci-workflows/.github/workflows/bump-release.yml` from 0.2.11 to 0.2.15 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/435746a4b72b06b6b6989c309fd2ad8150dbae5a...e8e6599fe480362cb0d5cbdac5b245cc833742f5) Updates `go-openapi/ci-workflows/.github/workflows/codeql.yml` from 0.2.11 to 0.2.15 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/435746a4b72b06b6b6989c309fd2ad8150dbae5a...e8e6599fe480362cb0d5cbdac5b245cc833742f5) Updates `go-openapi/ci-workflows/.github/workflows/contributors.yml` from 0.2.11 to 0.2.15 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/435746a4b72b06b6b6989c309fd2ad8150dbae5a...e8e6599fe480362cb0d5cbdac5b245cc833742f5) Updates `go-openapi/ci-workflows/.github/workflows/go-test.yml` from 0.2.11 to 0.2.15 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/435746a4b72b06b6b6989c309fd2ad8150dbae5a...e8e6599fe480362cb0d5cbdac5b245cc833742f5) Updates `go-openapi/ci-workflows/.github/workflows/scanner.yml` from 0.2.11 to 0.2.15 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/435746a4b72b06b6b6989c309fd2ad8150dbae5a...e8e6599fe480362cb0d5cbdac5b245cc833742f5) Updates `go-openapi/ci-workflows/.github/workflows/release.yml` from 0.2.11 to 0.2.15 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/435746a4b72b06b6b6989c309fd2ad8150dbae5a...e8e6599fe480362cb0d5cbdac5b245cc833742f5) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/auto-merge.yml dependency-version: 0.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/bump-release.yml dependency-version: 0.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/codeql.yml dependency-version: 0.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/contributors.yml dependency-version: 0.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/go-test.yml dependency-version: 0.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/scanner.yml dependency-version: 0.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/release.yml dependency-version: 0.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 48e5a578..faeaecf9 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index 11411719..3e1688e5 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -30,7 +30,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 with: bump-type: ${{ inputs.bump-type }} tag-message-title: ${{ inputs.tag-message-title }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 32fb5e3e..4cbe535d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 33a469f5..89944c35 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 514d891d..16cb4664 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index b936bc10..ed85aeab 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # V0.2.11 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # V0.2.15 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index b8347438..097ab07c 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 with: tag: ${{ github.ref_name }} secrets: inherit From 2b4929034d93a1ebdc98613354416a267cc18673 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 09:14:08 +0000 Subject: [PATCH 20/54] build(deps): bump the go-openapi-dependencies group with 2 updates Bumps the go-openapi-dependencies group with 2 updates: [github.com/go-openapi/testify/enable/yaml/v2](https://github.com/go-openapi/testify) and [github.com/go-openapi/testify/v2](https://github.com/go-openapi/testify). Updates `github.com/go-openapi/testify/enable/yaml/v2` from 2.4.1 to 2.4.2 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.4.1...v2.4.2) Updates `github.com/go-openapi/testify/v2` from 2.4.1 to 2.4.2 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.4.1...v2.4.2) --- updated-dependencies: - dependency-name: github.com/go-openapi/testify/enable/yaml/v2 dependency-version: 2.4.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/testify/v2 dependency-version: 2.4.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 32ed725a..6911ff7f 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/go-openapi/swag/jsonutils v0.25.5 github.com/go-openapi/swag/loading v0.25.5 github.com/go-openapi/swag/stringutils v0.25.5 - github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 - github.com/go-openapi/testify/v2 v2.4.1 + github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 + github.com/go-openapi/testify/v2 v2.4.2 ) require ( diff --git a/go.sum b/go.sum index 74aff222..2611ec52 100644 --- a/go.sum +++ b/go.sum @@ -18,10 +18,10 @@ github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzz github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 h1:NZOrZmIb6PTv5LTFxr5/mKV/FjbUzGE7E6gLz7vFoOQ= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.1/go.mod h1:r7dwsujEHawapMsxA69i+XMGZrQ5tRauhLAjV/sxg3Q= -github.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw= -github.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE= +github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4= +github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From c5c71037019e90ce6f6b391d136e590098f834de Mon Sep 17 00:00:00 2001 From: "bot-go-openapi[bot]" <246880138+bot-go-openapi[bot]@users.noreply.github.com> Date: Sat, 21 Mar 2026 05:13:11 +0000 Subject: [PATCH 21/54] doc: updated contributors file Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CONTRIBUTORS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 204a9858..0f533c01 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 38 | 393 | +| 38 | 396 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 191 | | -| @fredbi | 91 | | +| @fredbi | 94 | | | @pytlesk4 | 26 | | | @kul-amr | 10 | | | @keramix | 10 | | @@ -47,4 +47,4 @@ | @ChandanChainani | 1 | | | @bvwells | 1 | | - _this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_ + _this file was generated by the [Contributors GitHub Action](https://github.com/github-community-projects/contributors)_ From 1d7d6519c1c50b930eacc3d0b5df880325195ad7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 09:18:42 +0000 Subject: [PATCH 22/54] build(deps): bump the go-openapi-dependencies group with 6 updates Bumps the go-openapi-dependencies group with 6 updates: | Package | From | To | | --- | --- | --- | | [github.com/go-openapi/jsonpointer](https://github.com/go-openapi/jsonpointer) | `0.22.5` | `0.23.0` | | [github.com/go-openapi/swag/conv](https://github.com/go-openapi/swag) | `0.25.5` | `0.26.0` | | [github.com/go-openapi/swag/jsonname](https://github.com/go-openapi/swag) | `0.25.5` | `0.26.0` | | [github.com/go-openapi/swag/jsonutils](https://github.com/go-openapi/swag) | `0.25.5` | `0.26.0` | | [github.com/go-openapi/swag/loading](https://github.com/go-openapi/swag) | `0.25.5` | `0.26.0` | | [github.com/go-openapi/swag/stringutils](https://github.com/go-openapi/swag) | `0.25.5` | `0.26.0` | Updates `github.com/go-openapi/jsonpointer` from 0.22.5 to 0.23.0 - [Release notes](https://github.com/go-openapi/jsonpointer/releases) - [Commits](https://github.com/go-openapi/jsonpointer/compare/v0.22.5...v0.23.0) Updates `github.com/go-openapi/swag/conv` from 0.25.5 to 0.26.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.25.5...v0.26.0) Updates `github.com/go-openapi/swag/jsonname` from 0.25.5 to 0.26.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.25.5...v0.26.0) Updates `github.com/go-openapi/swag/jsonutils` from 0.25.5 to 0.26.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.25.5...v0.26.0) Updates `github.com/go-openapi/swag/loading` from 0.25.5 to 0.26.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.25.5...v0.26.0) Updates `github.com/go-openapi/swag/stringutils` from 0.25.5 to 0.26.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.25.5...v0.26.0) --- updated-dependencies: - dependency-name: github.com/go-openapi/jsonpointer dependency-version: 0.23.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/conv dependency-version: 0.26.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/jsonname dependency-version: 0.26.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/jsonutils dependency-version: 0.26.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/loading dependency-version: 0.26.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/stringutils dependency-version: 0.26.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 16 ++++++++-------- go.sum | 36 ++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index 6911ff7f..b2aeffb9 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,20 @@ module github.com/go-openapi/spec require ( - github.com/go-openapi/jsonpointer v0.22.5 + github.com/go-openapi/jsonpointer v0.23.0 github.com/go-openapi/jsonreference v0.21.5 - github.com/go-openapi/swag/conv v0.25.5 - github.com/go-openapi/swag/jsonname v0.25.5 - github.com/go-openapi/swag/jsonutils v0.25.5 - github.com/go-openapi/swag/loading v0.25.5 - github.com/go-openapi/swag/stringutils v0.25.5 + github.com/go-openapi/swag/conv v0.26.0 + github.com/go-openapi/swag/jsonname v0.26.0 + github.com/go-openapi/swag/jsonutils v0.26.0 + github.com/go-openapi/swag/loading v0.26.0 + github.com/go-openapi/swag/stringutils v0.26.0 github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 github.com/go-openapi/testify/v2 v2.4.2 ) require ( - github.com/go-openapi/swag/typeutils v0.25.5 // indirect - github.com/go-openapi/swag/yamlutils v0.25.5 // indirect + github.com/go-openapi/swag/typeutils v0.26.0 // indirect + github.com/go-openapi/swag/yamlutils v0.26.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect ) diff --git a/go.sum b/go.sum index 2611ec52..fa7264e6 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,23 @@ -github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= -github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= +github.com/go-openapi/jsonpointer v0.23.0 h1:c25HFTJ6uWGmoe5BQI6p72p4o7KnlWYsy1MeFlAumsw= +github.com/go-openapi/jsonpointer v0.23.0/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= -github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= -github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= -github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= -github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= -github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= -github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= -github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= -github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= -github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= -github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII= -github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E= -github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= -github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= -github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= +github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I= +github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE= +github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w= +github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M= +github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA= +github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y= +github.com/go-openapi/swag/loading v0.26.0 h1:Apg6zaKhCJurpJer0DCxq99qwmhFddBhaMX7kilDcko= +github.com/go-openapi/swag/loading v0.26.0/go.mod h1:dBxQ/6V2uBaAQdevN18VELE6xSpJWZxLX4txe12JwDg= +github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg= +github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE= +github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4= +github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE= +github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ= +github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU= github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0= github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE= github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4= From a2d9c417cd978aee4ba42a451273221d1fb60d75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 09:20:57 +0000 Subject: [PATCH 23/54] build(deps): bump github.com/go-openapi/jsonpointer Bumps the go-openapi-dependencies group with 1 update: [github.com/go-openapi/jsonpointer](https://github.com/go-openapi/jsonpointer). Updates `github.com/go-openapi/jsonpointer` from 0.23.0 to 0.23.1 - [Release notes](https://github.com/go-openapi/jsonpointer/releases) - [Commits](https://github.com/go-openapi/jsonpointer/compare/v0.23.0...v0.23.1) --- updated-dependencies: - dependency-name: github.com/go-openapi/jsonpointer dependency-version: 0.23.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b2aeffb9..70567374 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/go-openapi/spec require ( - github.com/go-openapi/jsonpointer v0.23.0 + github.com/go-openapi/jsonpointer v0.23.1 github.com/go-openapi/jsonreference v0.21.5 github.com/go-openapi/swag/conv v0.26.0 github.com/go-openapi/swag/jsonname v0.26.0 diff --git a/go.sum b/go.sum index fa7264e6..80ad17d3 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/go-openapi/jsonpointer v0.23.0 h1:c25HFTJ6uWGmoe5BQI6p72p4o7KnlWYsy1MeFlAumsw= -github.com/go-openapi/jsonpointer v0.23.0/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= +github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= +github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I= From a5d0895d290c47a62efa8d1b37ecc8d98b967989 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 10:35:38 +0000 Subject: [PATCH 24/54] build(deps): bump the go-openapi-dependencies group with 2 updates Bumps the go-openapi-dependencies group with 2 updates: [github.com/go-openapi/testify/enable/yaml/v2](https://github.com/go-openapi/testify) and [github.com/go-openapi/testify/v2](https://github.com/go-openapi/testify). Updates `github.com/go-openapi/testify/enable/yaml/v2` from 2.4.2 to 2.5.0 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.4.2...v2.5.0) Updates `github.com/go-openapi/testify/v2` from 2.4.2 to 2.5.0 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.4.2...v2.5.0) --- updated-dependencies: - dependency-name: github.com/go-openapi/testify/enable/yaml/v2 dependency-version: 2.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/testify/v2 dependency-version: 2.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 70567374..de93d2c9 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/go-openapi/swag/jsonutils v0.26.0 github.com/go-openapi/swag/loading v0.26.0 github.com/go-openapi/swag/stringutils v0.26.0 - github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 - github.com/go-openapi/testify/v2 v2.4.2 + github.com/go-openapi/testify/enable/yaml/v2 v2.5.0 + github.com/go-openapi/testify/v2 v2.5.0 ) require ( diff --git a/go.sum b/go.sum index 80ad17d3..b0d18eed 100644 --- a/go.sum +++ b/go.sum @@ -18,10 +18,10 @@ github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFu github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE= github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ= github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0= -github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE= -github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4= -github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/go-openapi/testify/enable/yaml/v2 v2.5.0 h1:3hZD1fwydvCx/cc1R2uYNQirHqf2s6lqpKV3FcNTURA= +github.com/go-openapi/testify/enable/yaml/v2 v2.5.0/go.mod h1:TvDZKBH7ZbMaF3EqH2AwTvNQCmzyZq8K1agRjf1B+Nk= +github.com/go-openapi/testify/v2 v2.5.0 h1:UOCr63aAsMIDydZbZGqo5Ev01D4eydItRbekDuZMJLw= +github.com/go-openapi/testify/v2 v2.5.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From 596087b12d7949970ee0f0144d4108c6eaef2864 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 09:26:15 +0000 Subject: [PATCH 25/54] build(deps): bump the development-dependencies group across 1 directory with 7 updates Bumps the development-dependencies group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [go-openapi/ci-workflows/.github/workflows/auto-merge.yml](https://github.com/go-openapi/ci-workflows) | `0.2.15` | `0.2.16` | | [go-openapi/ci-workflows/.github/workflows/bump-release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.15` | `0.2.16` | | [go-openapi/ci-workflows/.github/workflows/codeql.yml](https://github.com/go-openapi/ci-workflows) | `0.2.15` | `0.2.16` | | [go-openapi/ci-workflows/.github/workflows/contributors.yml](https://github.com/go-openapi/ci-workflows) | `0.2.15` | `0.2.16` | | [go-openapi/ci-workflows/.github/workflows/go-test.yml](https://github.com/go-openapi/ci-workflows) | `0.2.15` | `0.2.16` | | [go-openapi/ci-workflows/.github/workflows/scanner.yml](https://github.com/go-openapi/ci-workflows) | `0.2.15` | `0.2.16` | | [go-openapi/ci-workflows/.github/workflows/release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.15` | `0.2.16` | Updates `go-openapi/ci-workflows/.github/workflows/auto-merge.yml` from 0.2.15 to 0.2.16 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/e8e6599fe480362cb0d5cbdac5b245cc833742f5...6ed4490472a56b1d952231565aac80f13c2d143c) Updates `go-openapi/ci-workflows/.github/workflows/bump-release.yml` from 0.2.15 to 0.2.16 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/e8e6599fe480362cb0d5cbdac5b245cc833742f5...6ed4490472a56b1d952231565aac80f13c2d143c) Updates `go-openapi/ci-workflows/.github/workflows/codeql.yml` from 0.2.15 to 0.2.16 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/e8e6599fe480362cb0d5cbdac5b245cc833742f5...6ed4490472a56b1d952231565aac80f13c2d143c) Updates `go-openapi/ci-workflows/.github/workflows/contributors.yml` from 0.2.15 to 0.2.16 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/e8e6599fe480362cb0d5cbdac5b245cc833742f5...6ed4490472a56b1d952231565aac80f13c2d143c) Updates `go-openapi/ci-workflows/.github/workflows/go-test.yml` from 0.2.15 to 0.2.16 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/e8e6599fe480362cb0d5cbdac5b245cc833742f5...6ed4490472a56b1d952231565aac80f13c2d143c) Updates `go-openapi/ci-workflows/.github/workflows/scanner.yml` from 0.2.15 to 0.2.16 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/e8e6599fe480362cb0d5cbdac5b245cc833742f5...6ed4490472a56b1d952231565aac80f13c2d143c) Updates `go-openapi/ci-workflows/.github/workflows/release.yml` from 0.2.15 to 0.2.16 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/e8e6599fe480362cb0d5cbdac5b245cc833742f5...6ed4490472a56b1d952231565aac80f13c2d143c) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/auto-merge.yml dependency-version: 0.2.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/bump-release.yml dependency-version: 0.2.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/codeql.yml dependency-version: 0.2.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/contributors.yml dependency-version: 0.2.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/go-test.yml dependency-version: 0.2.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/release.yml dependency-version: 0.2.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/scanner.yml dependency-version: 0.2.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index faeaecf9..2df77066 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index 3e1688e5..c0762006 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -30,7 +30,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 with: bump-type: ${{ inputs.bump-type }} tag-message-title: ${{ inputs.tag-message-title }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4cbe535d..f762fde1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 89944c35..f07e32b7 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 16cb4664..3e1e78f8 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index ed85aeab..ddac09d3 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # V0.2.15 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@6ed4490472a56b1d952231565aac80f13c2d143c # V0.2.16 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 097ab07c..719dd9ad 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@e8e6599fe480362cb0d5cbdac5b245cc833742f5 # v0.2.15 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 with: tag: ${{ github.ref_name }} secrets: inherit From 5c73b50fb446846dfdc9fbcfe3de4e46004c19be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 09:30:26 +0000 Subject: [PATCH 26/54] build(deps): bump the go-openapi-dependencies group with 2 updates Bumps the go-openapi-dependencies group with 2 updates: [github.com/go-openapi/testify/enable/yaml/v2](https://github.com/go-openapi/testify) and [github.com/go-openapi/testify/v2](https://github.com/go-openapi/testify). Updates `github.com/go-openapi/testify/enable/yaml/v2` from 2.5.0 to 2.5.1 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.5.0...v2.5.1) Updates `github.com/go-openapi/testify/v2` from 2.5.0 to 2.5.1 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.5.0...v2.5.1) --- updated-dependencies: - dependency-name: github.com/go-openapi/testify/enable/yaml/v2 dependency-version: 2.5.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/testify/v2 dependency-version: 2.5.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index de93d2c9..db14463e 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/go-openapi/swag/jsonutils v0.26.0 github.com/go-openapi/swag/loading v0.26.0 github.com/go-openapi/swag/stringutils v0.26.0 - github.com/go-openapi/testify/enable/yaml/v2 v2.5.0 - github.com/go-openapi/testify/v2 v2.5.0 + github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 + github.com/go-openapi/testify/v2 v2.5.1 ) require ( diff --git a/go.sum b/go.sum index b0d18eed..ecebf796 100644 --- a/go.sum +++ b/go.sum @@ -18,10 +18,10 @@ github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFu github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE= github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ= github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU= -github.com/go-openapi/testify/enable/yaml/v2 v2.5.0 h1:3hZD1fwydvCx/cc1R2uYNQirHqf2s6lqpKV3FcNTURA= -github.com/go-openapi/testify/enable/yaml/v2 v2.5.0/go.mod h1:TvDZKBH7ZbMaF3EqH2AwTvNQCmzyZq8K1agRjf1B+Nk= -github.com/go-openapi/testify/v2 v2.5.0 h1:UOCr63aAsMIDydZbZGqo5Ev01D4eydItRbekDuZMJLw= -github.com/go-openapi/testify/v2 v2.5.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 h1:q9NtHwK4qHF7yZziBPvZyv7zWAIk8ok88Gh2mR6Jpc8= +github.com/go-openapi/testify/enable/yaml/v2 v2.5.1/go.mod h1:JW0MXIotCYps/XsgJnG3a8Q7rE5xAiBwoOD5OfaIQBk= +github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo= +github.com/go-openapi/testify/v2 v2.5.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From 971500643e423f082055c9ec9b4a9274189ed849 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 09:58:55 +0000 Subject: [PATCH 27/54] build(deps): bump the development-dependencies group across 1 directory with 7 updates Bumps the development-dependencies group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [go-openapi/ci-workflows/.github/workflows/auto-merge.yml](https://github.com/go-openapi/ci-workflows) | `0.2.16` | `0.2.17` | | [go-openapi/ci-workflows/.github/workflows/bump-release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.16` | `0.2.17` | | [go-openapi/ci-workflows/.github/workflows/codeql.yml](https://github.com/go-openapi/ci-workflows) | `0.2.16` | `0.2.17` | | [go-openapi/ci-workflows/.github/workflows/contributors.yml](https://github.com/go-openapi/ci-workflows) | `0.2.16` | `0.2.17` | | [go-openapi/ci-workflows/.github/workflows/go-test.yml](https://github.com/go-openapi/ci-workflows) | `0.2.16` | `0.2.17` | | [go-openapi/ci-workflows/.github/workflows/scanner.yml](https://github.com/go-openapi/ci-workflows) | `0.2.16` | `0.2.17` | | [go-openapi/ci-workflows/.github/workflows/release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.16` | `0.2.17` | Updates `go-openapi/ci-workflows/.github/workflows/auto-merge.yml` from 0.2.16 to 0.2.17 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/6ed4490472a56b1d952231565aac80f13c2d143c...7982843ba86a9b47f456a44ed94e82f882b50a8d) Updates `go-openapi/ci-workflows/.github/workflows/bump-release.yml` from 0.2.16 to 0.2.17 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/6ed4490472a56b1d952231565aac80f13c2d143c...7982843ba86a9b47f456a44ed94e82f882b50a8d) Updates `go-openapi/ci-workflows/.github/workflows/codeql.yml` from 0.2.16 to 0.2.17 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/6ed4490472a56b1d952231565aac80f13c2d143c...7982843ba86a9b47f456a44ed94e82f882b50a8d) Updates `go-openapi/ci-workflows/.github/workflows/contributors.yml` from 0.2.16 to 0.2.17 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/6ed4490472a56b1d952231565aac80f13c2d143c...7982843ba86a9b47f456a44ed94e82f882b50a8d) Updates `go-openapi/ci-workflows/.github/workflows/go-test.yml` from 0.2.16 to 0.2.17 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/6ed4490472a56b1d952231565aac80f13c2d143c...7982843ba86a9b47f456a44ed94e82f882b50a8d) Updates `go-openapi/ci-workflows/.github/workflows/scanner.yml` from 0.2.16 to 0.2.17 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/6ed4490472a56b1d952231565aac80f13c2d143c...7982843ba86a9b47f456a44ed94e82f882b50a8d) Updates `go-openapi/ci-workflows/.github/workflows/release.yml` from 0.2.16 to 0.2.17 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/6ed4490472a56b1d952231565aac80f13c2d143c...7982843ba86a9b47f456a44ed94e82f882b50a8d) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/auto-merge.yml dependency-version: 0.2.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/bump-release.yml dependency-version: 0.2.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/codeql.yml dependency-version: 0.2.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/contributors.yml dependency-version: 0.2.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/go-test.yml dependency-version: 0.2.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/release.yml dependency-version: 0.2.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/scanner.yml dependency-version: 0.2.17 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 2df77066..65793ea6 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index c0762006..0df6a096 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -30,7 +30,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 with: bump-type: ${{ inputs.bump-type }} tag-message-title: ${{ inputs.tag-message-title }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f762fde1..bbb62355 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index f07e32b7..3ff83b64 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 3e1e78f8..a90517e9 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index ddac09d3..06dcf592 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@6ed4490472a56b1d952231565aac80f13c2d143c # V0.2.16 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # V0.2.17 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 719dd9ad..c974f7e9 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@6ed4490472a56b1d952231565aac80f13c2d143c # v0.2.16 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 with: tag: ${{ github.ref_name }} secrets: inherit From 45b7fe19b6dc5e29517d8f7e97b6a7806379dd49 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Sun, 31 May 2026 10:15:16 +0200 Subject: [PATCH 28/54] feat(ci): added shared workflow for bot-pr monitoring Signed-off-by: Frederic BIDON --- .github/workflows/monitor-bot-pr.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/monitor-bot-pr.yml diff --git a/.github/workflows/monitor-bot-pr.yml b/.github/workflows/monitor-bot-pr.yml new file mode 100644 index 00000000..2acc887d --- /dev/null +++ b/.github/workflows/monitor-bot-pr.yml @@ -0,0 +1,18 @@ +name: Monitor bot PRs + +on: + workflow_dispatch: + schedule: + - cron: '18 6 * * *' + +permissions: + contents: read + +jobs: + monitor-pr: + permissions: + contents: write + pull-requests: write + statuses: read + uses: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml@980b99d60c7d219dbc51f63a7e401c651586b680 # v0.3.3 + secrets: inherit From 0741160a14ab8312ecf8471eaccff07ccd3b0f15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jun 2026 09:12:49 +0000 Subject: [PATCH 29/54] build(deps): bump the development-dependencies group with 8 updates Bumps the development-dependencies group with 8 updates: | Package | From | To | | --- | --- | --- | | [go-openapi/ci-workflows/.github/workflows/auto-merge.yml](https://github.com/go-openapi/ci-workflows) | `0.2.17` | `0.3.4` | | [go-openapi/ci-workflows/.github/workflows/bump-release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.17` | `0.3.4` | | [go-openapi/ci-workflows/.github/workflows/codeql.yml](https://github.com/go-openapi/ci-workflows) | `0.2.17` | `0.3.4` | | [go-openapi/ci-workflows/.github/workflows/contributors.yml](https://github.com/go-openapi/ci-workflows) | `0.2.17` | `0.3.4` | | [go-openapi/ci-workflows/.github/workflows/go-test.yml](https://github.com/go-openapi/ci-workflows) | `0.2.17` | `0.3.4` | | [go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml](https://github.com/go-openapi/ci-workflows) | `980b99d60c7d219dbc51f63a7e401c651586b680` | `cd9849915b4f8b6ceeeaf24e02e8f8e24202c8f6` | | [go-openapi/ci-workflows/.github/workflows/scanner.yml](https://github.com/go-openapi/ci-workflows) | `0.2.17` | `0.3.4` | | [go-openapi/ci-workflows/.github/workflows/release.yml](https://github.com/go-openapi/ci-workflows) | `0.2.17` | `0.3.4` | Updates `go-openapi/ci-workflows/.github/workflows/auto-merge.yml` from 0.2.17 to 0.3.4 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7982843ba86a9b47f456a44ed94e82f882b50a8d...7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a) Updates `go-openapi/ci-workflows/.github/workflows/bump-release.yml` from 0.2.17 to 0.3.4 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7982843ba86a9b47f456a44ed94e82f882b50a8d...7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a) Updates `go-openapi/ci-workflows/.github/workflows/codeql.yml` from 0.2.17 to 0.3.4 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7982843ba86a9b47f456a44ed94e82f882b50a8d...7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a) Updates `go-openapi/ci-workflows/.github/workflows/contributors.yml` from 0.2.17 to 0.3.4 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7982843ba86a9b47f456a44ed94e82f882b50a8d...7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a) Updates `go-openapi/ci-workflows/.github/workflows/go-test.yml` from 0.2.17 to 0.3.4 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7982843ba86a9b47f456a44ed94e82f882b50a8d...7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a) Updates `go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml` from 980b99d60c7d219dbc51f63a7e401c651586b680 to cd9849915b4f8b6ceeeaf24e02e8f8e24202c8f6 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/980b99d60c7d219dbc51f63a7e401c651586b680...cd9849915b4f8b6ceeeaf24e02e8f8e24202c8f6) Updates `go-openapi/ci-workflows/.github/workflows/scanner.yml` from 0.2.17 to 0.3.4 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7982843ba86a9b47f456a44ed94e82f882b50a8d...7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a) Updates `go-openapi/ci-workflows/.github/workflows/release.yml` from 0.2.17 to 0.3.4 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7982843ba86a9b47f456a44ed94e82f882b50a8d...7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/auto-merge.yml dependency-version: 0.3.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/bump-release.yml dependency-version: 0.3.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/codeql.yml dependency-version: 0.3.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/contributors.yml dependency-version: 0.3.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/go-test.yml dependency-version: 0.3.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml dependency-version: cd9849915b4f8b6ceeeaf24e02e8f8e24202c8f6 dependency-type: direct:production dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/scanner.yml dependency-version: 0.3.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/release.yml dependency-version: 0.3.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/monitor-bot-pr.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 65793ea6..b2537754 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index 0df6a096..fecebe4f 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -30,7 +30,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 with: bump-type: ${{ inputs.bump-type }} tag-message-title: ${{ inputs.tag-message-title }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index bbb62355..78fee343 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 3ff83b64..19a62820 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index a90517e9..e2b3b47a 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 secrets: inherit diff --git a/.github/workflows/monitor-bot-pr.yml b/.github/workflows/monitor-bot-pr.yml index 2acc887d..a3a11e52 100644 --- a/.github/workflows/monitor-bot-pr.yml +++ b/.github/workflows/monitor-bot-pr.yml @@ -14,5 +14,5 @@ jobs: contents: write pull-requests: write statuses: read - uses: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml@980b99d60c7d219dbc51f63a7e401c651586b680 # v0.3.3 + uses: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml@cd9849915b4f8b6ceeeaf24e02e8f8e24202c8f6 # v0.3.3 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index 06dcf592..23be5941 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # V0.2.17 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # V0.3.4 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index c974f7e9..d76b7915 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@7982843ba86a9b47f456a44ed94e82f882b50a8d # v0.2.17 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 with: tag: ${{ github.ref_name }} secrets: inherit From 9a2db11ae704939ab52708fd04552da8ef8d16ce Mon Sep 17 00:00:00 2001 From: fredbi Date: Fri, 5 Jun 2026 20:59:05 +0200 Subject: [PATCH 30/54] doc: aligned with org docs (#273) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frédéric BIDON --- .github/CONTRIBUTING.md | 251 ---------------------------------------- .github/DCO.md | 40 ------- README.md | 16 ++- docs/.gitkeep | 0 docs/MAINTAINERS.md | 186 ----------------------------- docs/STYLE.md | 117 ------------------- 6 files changed, 7 insertions(+), 603 deletions(-) delete mode 100644 .github/CONTRIBUTING.md delete mode 100644 .github/DCO.md create mode 100644 docs/.gitkeep delete mode 100644 docs/MAINTAINERS.md delete mode 100644 docs/STYLE.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 8983754c..00000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,251 +0,0 @@ -You'll find here general guidelines to contribute to this project. -They mostly correspond to standard practices for open source repositories. - -We have tried to keep things as simple as possible. - -> [!NOTE] -> If you're an experienced go developer on github, then you should just feel at home with us -> and you may well skip the rest of this document. -> -> You'll essentially apply the usual guidelines for a go library project on github. - -These guidelines are common to all libraries published on github by the `go-openapi` organization, -so you'll feel at home with any of our projects. - -You'll find more detailed (or repo-specific) instructions in the [maintainer's docs][maintainers-doc]. - -[maintainers-doc]: ../docs/MAINTAINERS.md - -## How can I contribute - -There are many ways in which you can contribute, not just code. Here are a few ideas: - -- Reporting issues or bugs -- Suggesting improvements -- Documentation -- Art work that makes the project look great -- Code - - proposing bug fixes and new features that are within the main project scope - - improving test coverage - - addressing code quality issues - -## Questions & issues - -### Asking a question - -You may inquire anything about this library by reporting a "Question" issue on github. - -You may also join our discord server where you may discuss issues or requests. - -[![Discord Server][discord-badge]][discord-url] - -[discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue -[discord-url]: https://discord.gg/FfnFYaC3k5 - -### Reporting issues - -Reporting a problem with our libraries _is_ a valuable contribution. -You can do this on the github issues page of this repository. - -Please be as specific as possible when describing your issue. - -Whenever relevant, please provide information about your environment (go version, OS). - -Adding a code snippet to reproduce the issue is great, and a big time saver for maintainers. - -### Triaging issues - -You can help triage issues which may include: - -* reproducing bug reports -* asking for important information, such as version numbers or reproduction instructions -* answering questions and sharing your insight in issue comments - -## Code contributions - -### Pull requests are always welcome - -We are always thrilled to receive pull requests, and we do our best to -process them as fast as possible. - -Not sure if that typo is worth a pull request? Do it! We will appreciate it. - -If your pull request is not accepted on the first try, don't be discouraged! -If there's a problem with the implementation, hopefully you've received feedback on what to improve. - -If you have a lot of ideas or a lot of issues to solve, try to refrain a bit and post focused -pull requests. -Think that they must be reviewed by a maintainer and it is easy to lose track of things on big PRs. - -We're trying very hard to keep the go-openapi packages lean and focused. - -Together, these packages constitute a toolkit for go developers: -it won't do everything for everybody out of the box, -but everybody can use it to do just about everything related to OpenAPI. - -This means that we might decide against incorporating a new feature. - -However, there might be a way to implement that feature *on top of* our libraries. - -### Environment - -You just need a `go` compiler to be installed. No special tools are needed to work with our libraries. - -The minimal go compiler version required is always the old stable (latest minor go version - 1). - -Our libraries are designed and tested to work on `Linux`, `MacOS` and `Windows`. - -If you're used to work with `go` you should already have everything in place. - -Although not required, you'll be certainly more productive with a local installation of `golangci-lint`, -the meta-linter our CI uses. - -If you don't have it, you may install it like so: - -```sh -go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest -``` - -### Conventions - -#### Git flow - -Fork the repo and make changes to your fork in a feature branch. - -To submit a pull request, push your branch to your fork (e.g. `upstream` remote): -github will propose to open a pull request on the original repository. - -Typically you'd follow some common naming conventions: - -- if it's a bug fixing branch, name it `fix/XXX-something` where XXX is the number of the - issue on github -- if it's a feature branch, create an enhancement issue to announce your - intentions, and name it `feature/XXX-something` where XXX is the number of the issue. - -NOTE: we don't enforce naming conventions on branches: it's your fork after all. - -#### Tests - -Submit unit tests for your changes. - -Go has a great built-in test framework ; use it! - -Take a look at existing tests for inspiration, and run the full test suite on your branch -before submitting a pull request. - -Our CI measures test coverage and the test coverage of every patch. - -Although not a blocking step - because there are so many special cases - -this is an indicator that maintainers consider when approving a PR. -Please try your best to cover at least 80% of your patch. - -#### Code style - -You may read our stance on code style [there](../docs/STYLE.md). - -#### Documentation - -Don't forget to update the documentation when creating or modifying a feature. - -Most documentation for this library is directly found in code as comments for godoc. - -The documentation for this go-openapi package is published on [the public go docs site][go-doc]. - ---- - -Check your documentation changes for clarity, concision, and correctness. - -If you want to assess the rendering of your changes when published to `pkg.go.dev`, you may -want to install the `pkgsite` tool proposed by `golang.org`. - -```sh -go install golang.org/x/pkgsite/cmd/pkgsite@latest -``` - -Then run on the repository folder: - -```sh -pkgsite . -``` - -This will run a godoc server locally where you may see the documentation generated from your local repository. - -[go-doc]: https://pkg.go.dev/github.com/go-openapi/spec - -#### Commit messages - -Pull requests descriptions should be as clear as possible and include a -reference to all the issues that they address. - -Pull requests must not contain commits from other users or branches. - -Commit messages are not required to follow the "conventional commit" rule, but it's certainly a good -thing to follow that convention (e.g. "fix: fixed panic in XYZ", "ci: did this", "feat: did that" ...). - -The title in your commit message is used directly to produce our release notes: try to keep them neat. - -The commit message body should detail your changes. - -If an issue should be closed by a commit, please add this reference in the commit body: - -``` -* fixes #{issue number} -``` - -#### Code review - -Code review comments may be added to your pull request. - -Discuss, then make the suggested modifications and push additional commits to your feature branch. - -Be sure to post a comment after pushing. The new commits will show up in the pull -request automatically, but the reviewers will not be notified unless you comment. - -Before the pull request is merged, -**make sure that you've squashed your commits into logical units of work** -using `git rebase -i` and `git push -f`. - -After every commit the test suite should be passing. - -Include documentation changes in the same commit so that a revert would remove all traces of the feature or fix. - -#### Sign your work - -Software is developed by real people. - -The sign-off is a simple line at the end of your commit message, -which certifies that you wrote it or otherwise have the right to -pass it on as an open-source patch. - -We require the simple DCO below with an email signing your commit. -PGP-signed commit are greatly appreciated but not required. - -The rules are pretty simple: - -- read our [DCO][dco-doc] (from [developercertificate.org][dco-source]) -- if you agree with these terms, then you just add a line to every git commit message - -``` -Signed-off-by: Joe Smith -``` - -using your real name (sorry, no pseudonyms or anonymous contributions.) - -You can add the sign-off when creating the git commit via `git commit -s`. - -[dco-doc]: ./DCO.md -[dco-source]: https://developercertificate.org - -## Code contributions by AI agents - -Our agentic friends are welcome to contribute! - -We only have a few demands to keep-up with human maintainers. - -1. Issues and PRs written or posted by agents should always mention the original (human) poster for reference -2. We don't accept PRs attributed to agents. We don't want commits signed like "author: @claude.code". - Agents or bots may coauthor commits, though. -3. Security vulnerability reports by agents should always be reported privately and mention the original (human) poster - (see also [Security Policy][security-doc]). - -[security-doc]: ../SECURITY.md diff --git a/.github/DCO.md b/.github/DCO.md deleted file mode 100644 index 78a2d64f..00000000 --- a/.github/DCO.md +++ /dev/null @@ -1,40 +0,0 @@ -# Developer's Certificate of Origin - -``` -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. -660 York Street, Suite 102, -San Francisco, CA 94110 USA - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. -``` diff --git a/README.md b/README.md index 405002b8..7c96eb9a 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,9 @@ The object model for OpenAPI v2 specification documents. * **2025-12-19** : new community chat on discord * a new discord community channel is available to be notified of changes and support users - * our venerable Slack channel remains open, and will be eventually discontinued on **2026-03-31** You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url] -Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url] - ## Status API is stable. @@ -95,9 +92,9 @@ This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE). ## Other documentation * [All-time contributors](./CONTRIBUTORS.md) -* [Contributing guidelines](.github/CONTRIBUTING.md) -* [Maintainers documentation](docs/MAINTAINERS.md) -* [Code style](docs/STYLE.md) +* [Contributing guidelines][contributing-doc-site] +* [Maintainers documentation][maintainers-doc-site] +* [Code style][style-doc-site] ## Cutting a new release @@ -132,9 +129,6 @@ Maintainers can cut a new release by either: [doc-url]: https://goswagger.io/go-openapi [godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/spec [godoc-url]: http://pkg.go.dev/github.com/go-openapi/spec -[slack-logo]: https://a.slack-edge.com/e6a93c1/img/icons/favicon-32.png -[slack-badge]: https://img.shields.io/badge/slack-blue?link=https%3A%2F%2Fgoswagger.slack.com%2Farchives%2FC04R30YM -[slack-url]: https://goswagger.slack.com/archives/C04R30YMU [discord-badge]: https://img.shields.io/discord/1446918742398341256?logo=discord&label=discord&color=blue [discord-url]: https://discord.gg/FfnFYaC3k5 @@ -146,3 +140,7 @@ Maintainers can cut a new release by either: [goversion-url]: https://github.com/go-openapi/spec/blob/master/go.mod [top-badge]: https://img.shields.io/github/languages/top/go-openapi/spec [commits-badge]: https://img.shields.io/github/commits-since/go-openapi/spec/latest + +[contributing-doc-site]: https://go-openapi.github.io/doc-site/contributing/contributing/index.html +[maintainers-doc-site]: https://go-openapi.github.io/doc-site/maintainers/index.html +[style-doc-site]: https://go-openapi.github.io/doc-site/contributing/style/index.html diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/MAINTAINERS.md b/docs/MAINTAINERS.md deleted file mode 100644 index 8fc6befb..00000000 --- a/docs/MAINTAINERS.md +++ /dev/null @@ -1,186 +0,0 @@ -> [!NOTE] -> Comprehensive guide for maintainers covering repository structure, CI/CD workflows, release procedures, and development practices. -> Essential reading for anyone contributing to or maintaining this project. - -## Repo structure - -This project is organized as a repo with a single go module. - -## Repo configuration - -* Default branch: master -* Protected branches: master -* Branch protection rules: - * require pull requests and approval - * required status checks: - * DCO (simple email sign-off) - * Lint - * All tests completed -* Auto-merge enabled (used for dependabot updates and other auto-merged PR's, e.g. contributors update) - -## Continuous Integration - -### Code Quality checks - -* meta-linter: [golangci-lint][golangci-url] -* linter config: [`.golangci.yml`][linter-config] (see our [posture][style-doc] on linters) -* Code quality assessment: [CodeFactor][codefactor-url] -* Code quality badges - * [go report card][gocard-url] - * [CodeFactor][codefactor-url] - -> **NOTES** -> -> codefactor inherits roles from github. There is no need to create a dedicated account. -> -> The codefactor app is installed at the organization level (`github.com/go-openapi`). -> -> There is no special token to setup in github for CI usage. - -### Testing - -* Test reports - * Uploaded to codecov: -* Test coverage reports - * Uploaded to codecov: - -* Fuzz testing - * Fuzz tests are handled separately by CI and may reuse a cached version of the fuzzing corpus. - At this moment, cache may not be shared between feature branches or feature branch and master. - The minimized corpus produced on failure is uploaded as an artifact and should be added manually - to `testdata/fuzz/...`. - -Coverage threshold status is informative and not blocking. -This is because the thresholds are difficult to tune and codecov oftentimes reports false negatives -or may fail to upload coverage. - -All tests across `go-openapi` use our fork of `stretchr/spec` (this repo): `github.com/go-openapi/spec`. -This allows for minimal test dependencies. - -> **NOTES** -> -> codecov inherits roles from github. There is no need to create a dedicated account. -> However, there is only 1 maintainer allowed to be the admin of the organization on codecov -> with their free plan. -> -> The codecov app is installed at the organization level (`github.com/go-openapi`). -> -> There is no special token to setup in github for CI usage. -> A organization-level token used to upload coverage and test reports is managed at codecov: -> no setup is required on github. - -### Automated updates - -* dependabot - * configuration: [`dependabot.yaml`][dependabot-config] - - Principle: - - * codecov applies updates and security patches to the github-actions and golang ecosystems. - * all updates from "trusted" dependencies (github actions, golang.org packages, go-openapi packages - are auto-merged if they successfully pass CI. - -* go version updates - - Principle: - - * we support the 2 latest minor versions of the go compiler (`stable`, `oldstable`) - * `go.mod` should be updated (manually) whenever there is a new go minor release - (e.g. every 6 months). - - > This means that our projects always have a 6 months lag to enforce new features from the go compiler. - > - > However, new features of go may be used with a "go:build" tag: this allows users of the newer - > version to benefit the new feature while users still running with `oldstable` use another version - > that still builds. - -* contributors - * a [`CONTRIBUTORS.md`][contributors-doc] file is updated weekly, with all-time contributors to the repository - * the `github-actions[bot]` posts a pull request to do that automatically - * at this moment, this pull request is not auto-approved/auto-merged (bot cannot approve its own PRs) - -### Vulnerability scanners - -There are 3 complementary scanners - obviously, there is some overlap, but each has a different focus. - -* GitHub `CodeQL` -* `trivy` -* `govulnscan` - -None of these tools require an additional account or token. - -Github CodeQL configuration is set to "Advanced", so we may collect a CI status for this check (e.g. for badges). - -Scanners run on every commit to master and at least once a week. - -Reports are centralized in github security reports for code scanning tools. - -## Releases - -**For single module repos:** - -A bump release workflow can be triggered from the github actions UI to cut a release with a few clicks. - -The release process is minimalist: - -* push a semver tag (i.e v{major}.{minor}.{patch}) to the master branch. -* the CI handles this to generate a github release with release notes - -* release notes generator: git-cliff -* configuration: the `.cliff.toml` is defined as a share configuration on - remote repo [`ci-workflows/.cliff.toml`][remote-cliff-config] - -Commits from maintainers are preferably PGP-signed. - -Tags are preferably PGP-signed. - -We want our releases to show as "verified" on github. - -The tag message introduces the release notes (e.g. a summary of this release). - -The release notes generator does not assume that commits are necessarily "conventional commits". - -**For mono-repos with multiple modules:** - -The release process is slightly different because we need to update cross-module dependencies -before pushing a tag. - -A bump release workflow (mono-repo) can be triggered from the github actions UI to cut a release with a few clicks. - -It works with the same input as the one for single module repos, and first creates a PR (auto-merged) -that updates the different go.mod files _before_ pushing the desired git tag. - -Commits and tags pushed by the workflow bot are PGP-signed ("go-openapi[bot]"). - -## Other files - -Standard documentation: - -* [CONTRIBUTING.md][contributing-doc] guidelines -* [DCO.md][dco-doc] terms for first-time contributors to read -* [CODE_OF_CONDUCT.md][coc-doc] -* [SECURITY.md][security-doc] policy: how to report vulnerabilities privately -* [LICENSE][license-doc] terms - - - -Reference documentation (released): - -* [pkg.go.dev (fka godoc)][godoc-url] - - -[linter-config]: https://github.com/go-openapi/spec/blob/master/.golangci.yml -[remote-cliff-config]: https://github.com/go-openapi/ci-workflows/blob/master/.cliff.toml -[dependabot-config]: https://github.com/go-openapi/spec/blob/master/.github/dependabot.yaml -[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/spec -[codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/spec -[golangci-url]: https://golangci-lint.run/ -[godoc-url]: https://pkg.go.dev/github.com/go-openapi/spec -[contributors-doc]: ../CONTRIBUTORS.md -[contributing-doc]: ../.github/CONTRIBUTING.md -[dco-doc]: ../.github/DCO.md -[style-doc]: STYLE.md -[coc-doc]: ../CODE_OF_CONDUCT.md -[security-doc]: ../SECURITY.md -[license-doc]: ../LICENSE - diff --git a/docs/STYLE.md b/docs/STYLE.md deleted file mode 100644 index 46f46cef..00000000 --- a/docs/STYLE.md +++ /dev/null @@ -1,117 +0,0 @@ -# Coding style at `go-openapi` - -> **TL;DR** -> -> Let's be honest: at `go-openapi` and `go-swagger` we've never been super-strict on code style and linting. -> -> But perhaps now (2025) is the time to adopt a different stance. - -Even though our repos have been early adopters of `golangci-lint` years ago -(we used some other metalinter before), our decade-old codebase is only realigned to new rules from time to time. - -Now go-openapi and go-swagger together make up a really large codebase, which is taxing to maintain and keep afloat. - -Code quality and the harmonization of rules have thus become things that we need now. - -## Meta-linter - -Universally formatted go code promotes ease of writing, reading, and maintenance. - -You should run `golangci-lint run` before committing your changes. - -Many editors have plugins that do that automatically. - -> We use the `golangci-lint` meta-linter. The configuration lies in -> [`.golangci.yml`][golangci-yml]. -> You may read [the linter's configuration reference][golangci-doc] for additional reference. - -This configuration is essentially the same across all `go-openapi` projects. - -Some projects may require slightly different settings. - -## Linting rules posture - -Thanks to go's original design, we developers don't have to waste much time arguing about code figures of style. - -However, the number of available linters has been growing to the point that we need to pick a choice. - -### Our approach: evaluate, don't consume blindly - -As early adopters of `golangci-lint` (and its predecessors), we've watched linting orthodoxy -shift back and forth over the years. Patterns that were idiomatic one year get flagged the next; -rules that seemed reasonable in isolation produce noise at scale. Conversations with maintainers -of other large Go projects confirmed what our own experience taught us: -**the default linter set is a starting point, not a prescription**. - -Our stance is deliberate: - -- **Start from `default: all`**, then consciously disable what doesn't earn its keep. - This forces us to evaluate every linter and articulate why we reject it — the disabled list - is a design rationale, not technical debt. -- **Tune thresholds rather than disable** when a linter's principle is sound but its defaults - are too aggressive for a mature codebase. -- **Require justification for every `//nolint`** directive. Each one must carry an inline comment - explaining why it's there. -- **Prefer disabling a linter over scattering `//nolint`** across the codebase. If a linter - produces systematic false positives on patterns we use intentionally, the linter goes — - not our code. -- **Keep the configuration consistent** across all `go-openapi` repositories. Per-repo - divergence is a maintenance tax we don't want to pay. - -We enable all linters published by `golangci-lint` by default, then disable a few ones. - -Here are the reasons why they are disabled (update: Feb. 2026, `golangci-lint v2.8.0`). - -```yaml - disable: - - depguard # we don't want to configure rules to constrain import. That's the reviewer's job - - exhaustruct # we don't want to configure regexp's to check type name. That's the reviewer's job - - funlen # we accept cognitive complexity as a meaningful metric, but function length is relevant - - godox # we don't see any value in forbidding TODO's etc in code - - nlreturn # we usually apply this "blank line" rule to make code less compact. We just don't want to enforce it - - nonamedreturns # we don't see any valid reason why we couldn't used named returns - - noinlineerr # there is no value added forbidding inlined err - - paralleltest # we like parallel tests. We just don't want them to be enforced everywhere - - recvcheck # we like the idea of having pointer and non-pointer receivers - - testpackage # we like test packages. We just don't want them to be enforced everywhere - - thelper # too many false positives on test case factories returning func(*testing.T). See note below - - tparallel # see paralleltest - - varnamelen # sometimes, we like short variables. The linter doesn't catch cases when a short name is good - - whitespace # no added value - - wrapcheck # although there is some sense with this linter's general idea, it produces too much noise - - wsl # no added value. Noise - - wsl_v5 # no added value. Noise -``` - -As you may see, we agree with the objective of most linters, at least the principle they are supposed to enforce. -But all linters do not support fine-grained tuning to tolerate some cases and not some others. - -**Relaxed linter settings** - -When this is possible, we enable linters with relaxed constraints. - -```yaml - settings: - dupl: - threshold: 200 # in a older code base such as ours, we have to be tolerant with a little redundancy - # Hopefully, we'll be able to gradually get rid of those. - goconst: - min-len: 2 - min-occurrences: 3 - cyclop: - max-complexity: 20 # the default is too low for most of our functions. 20 is a nicer trade-off - gocyclo: - min-complexity: 20 - exhaustive: # when using default in switch, this should be good enough - default-signifies-exhaustive: true - default-case-required: true - lll: - line-length: 180 # we just want to avoid extremely long lines. - # It is no big deal if a line or two don't fit on your terminal. -``` - -Final note: since we have switched to a forked version of `stretchr/testify`, -we no longer benefit from the great `testifylint` linter for tests. - -[golangci-yml]: https://github.com/go-openapi/spec/blob/master/.golangci.yml -[golangci-doc]: https://golangci-lint.run/docs/linters/configuration/ From 1ab4532d10968a0bd9af541fbe2582020bcc1f33 Mon Sep 17 00:00:00 2001 From: "bot-go-openapi[bot]" <246880138+bot-go-openapi[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 07:25:51 +0000 Subject: [PATCH 31/54] doc: updated contributors file Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CONTRIBUTORS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 0f533c01..2fd257bb 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 38 | 396 | +| 38 | 398 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 191 | | -| @fredbi | 94 | | +| @fredbi | 96 | | | @pytlesk4 | 26 | | | @kul-amr | 10 | | | @keramix | 10 | | From e935605cb20565f606488399d3b6a47b05c76119 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jun 2026 17:02:56 +0000 Subject: [PATCH 32/54] build(deps): bump the go-openapi-dependencies group across 1 directory with 6 updates Bumps the go-openapi-dependencies group with 6 updates in the / directory: | Package | From | To | | --- | --- | --- | | [github.com/go-openapi/jsonreference](https://github.com/go-openapi/jsonreference) | `0.21.5` | `0.21.6` | | [github.com/go-openapi/swag/conv](https://github.com/go-openapi/swag) | `0.26.0` | `0.26.1` | | [github.com/go-openapi/swag/jsonname](https://github.com/go-openapi/swag) | `0.26.0` | `0.26.1` | | [github.com/go-openapi/swag/jsonutils](https://github.com/go-openapi/swag) | `0.26.0` | `0.26.1` | | [github.com/go-openapi/swag/loading](https://github.com/go-openapi/swag) | `0.26.0` | `0.26.1` | | [github.com/go-openapi/swag/stringutils](https://github.com/go-openapi/swag) | `0.26.0` | `0.26.1` | Updates `github.com/go-openapi/jsonreference` from 0.21.5 to 0.21.6 - [Release notes](https://github.com/go-openapi/jsonreference/releases) - [Commits](https://github.com/go-openapi/jsonreference/compare/v0.21.5...v0.21.6) Updates `github.com/go-openapi/swag/conv` from 0.26.0 to 0.26.1 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.0...v0.26.1) Updates `github.com/go-openapi/swag/jsonname` from 0.26.0 to 0.26.1 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.0...v0.26.1) Updates `github.com/go-openapi/swag/jsonutils` from 0.26.0 to 0.26.1 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.0...v0.26.1) Updates `github.com/go-openapi/swag/loading` from 0.26.0 to 0.26.1 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.0...v0.26.1) Updates `github.com/go-openapi/swag/stringutils` from 0.26.0 to 0.26.1 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.0...v0.26.1) --- updated-dependencies: - dependency-name: github.com/go-openapi/jsonreference dependency-version: 0.21.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/conv dependency-version: 0.26.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/jsonname dependency-version: 0.26.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/jsonutils dependency-version: 0.26.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/loading dependency-version: 0.26.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/stringutils dependency-version: 0.26.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 16 ++++++++-------- go.sum | 36 ++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index db14463e..cac771a0 100644 --- a/go.mod +++ b/go.mod @@ -2,19 +2,19 @@ module github.com/go-openapi/spec require ( github.com/go-openapi/jsonpointer v0.23.1 - github.com/go-openapi/jsonreference v0.21.5 - github.com/go-openapi/swag/conv v0.26.0 - github.com/go-openapi/swag/jsonname v0.26.0 - github.com/go-openapi/swag/jsonutils v0.26.0 - github.com/go-openapi/swag/loading v0.26.0 - github.com/go-openapi/swag/stringutils v0.26.0 + github.com/go-openapi/jsonreference v0.21.6 + github.com/go-openapi/swag/conv v0.26.1 + github.com/go-openapi/swag/jsonname v0.26.1 + github.com/go-openapi/swag/jsonutils v0.26.1 + github.com/go-openapi/swag/loading v0.26.1 + github.com/go-openapi/swag/stringutils v0.26.1 github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 github.com/go-openapi/testify/v2 v2.5.1 ) require ( - github.com/go-openapi/swag/typeutils v0.26.0 // indirect - github.com/go-openapi/swag/yamlutils v0.26.0 // indirect + github.com/go-openapi/swag/typeutils v0.26.1 // indirect + github.com/go-openapi/swag/yamlutils v0.26.1 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect ) diff --git a/go.sum b/go.sum index ecebf796..a4b56b35 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,23 @@ github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= -github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= -github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= -github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I= -github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE= -github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w= -github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M= -github.com/go-openapi/swag/jsonutils v0.26.0 h1:FawFML2iAXsPqmERscuMPIHmFsoP1tOqWkxBaKNMsnA= -github.com/go-openapi/swag/jsonutils v0.26.0/go.mod h1:2VmA0CJlyFqgawOaPI9psnjFDqzyivIqLYN34t9p91E= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0 h1:apqeINu/ICHouqiRZbyFvuDge5jCmmLTqGQ9V95EaOM= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.0/go.mod h1:AyM6QT8uz5IdKxk5akv0y6u4QvcL9GWERt0Jx/F/R8Y= -github.com/go-openapi/swag/loading v0.26.0 h1:Apg6zaKhCJurpJer0DCxq99qwmhFddBhaMX7kilDcko= -github.com/go-openapi/swag/loading v0.26.0/go.mod h1:dBxQ/6V2uBaAQdevN18VELE6xSpJWZxLX4txe12JwDg= -github.com/go-openapi/swag/stringutils v0.26.0 h1:qZQngLxs5s7SLijc3N2ZO+fUq2o8LjuWAASSrJuh+xg= -github.com/go-openapi/swag/stringutils v0.26.0/go.mod h1:sWn5uY+QIIspwPhvgnqJsH8xqFT2ZbYcvbcFanRyhFE= -github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFuuyQIKYybfq4= -github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE= -github.com/go-openapi/swag/yamlutils v0.26.0 h1:H7O8l/8NJJQ/oiReEN+oMpnGMyt8G0hl460nRZxhLMQ= -github.com/go-openapi/swag/yamlutils v0.26.0/go.mod h1:1evKEGAtP37Pkwcc7EWMF0hedX0/x3Rkvei2wtG/TbU= +github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y= +github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY= +github.com/go-openapi/swag/conv v0.26.1 h1:slr5FVkg9Wc3Y5zcwenD8Sd/PQ94b2I/QJI7N7KTBpg= +github.com/go-openapi/swag/conv v0.26.1/go.mod h1:mvQXgPptZk9GTrFgGwWvT4q+dN+zQej9JfmGwnipz1A= +github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE= +github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc= +github.com/go-openapi/swag/jsonutils v0.26.1 h1:2hdBfFkHg+7Wrz2VsCbeyR6hzkRDs7AztnMR2u84yOY= +github.com/go-openapi/swag/jsonutils v0.26.1/go.mod h1:U+RMJH3wa+6BRiphuRtIyI8fW9HPFqFQ4sHk2oRx0UQ= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1 h1:1CD7NiLLb/TXl3tOnFYU4b+mNfb5rtgHkaA+q7RMYYQ= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1/go.mod h1:ZWafc8nMdYzTE3uYY6W86f0n46+IF0g4uUyRhJw/kXc= +github.com/go-openapi/swag/loading v0.26.1 h1:E9K4wqXeROlhjFQ13K9zMz6ojFGXIggGe+ad1odrK9w= +github.com/go-openapi/swag/loading v0.26.1/go.mod h1:3qvRIlWzWdq1HvmldwmuJ2ohpcAryN6xVt2OTKd0/7E= +github.com/go-openapi/swag/stringutils v0.26.1 h1:f88uYyTso7TnHrKM/bUBsQ5e2wKf37cpgo6pvbzd9yU= +github.com/go-openapi/swag/stringutils v0.26.1/go.mod h1:Sc6d3bU8fgk5AyZR8/8jEQ+Is/Ald+TD/IIggPN8UJk= +github.com/go-openapi/swag/typeutils v0.26.1 h1:yg42FgMzRR6PVQ3M3qHz1s+Y6/P4HoJ3cBarXa3OVnU= +github.com/go-openapi/swag/typeutils v0.26.1/go.mod h1:VfnV+oUtSP2vCSCn2aJgnr8OevUYemyIzzS1VOzS10o= +github.com/go-openapi/swag/yamlutils v0.26.1 h1:0TSLK+lXs9vfIhAWzBeI/lOzEnIoot6WTCO1aAeWFTk= +github.com/go-openapi/swag/yamlutils v0.26.1/go.mod h1:7W5b7PRX9MxwL7TjeG7H8HkyBGRsIDRObhyMWFgBI2M= github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 h1:q9NtHwK4qHF7yZziBPvZyv7zWAIk8ok88Gh2mR6Jpc8= github.com/go-openapi/testify/enable/yaml/v2 v2.5.1/go.mod h1:JW0MXIotCYps/XsgJnG3a8Q7rE5xAiBwoOD5OfaIQBk= github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo= From 536d37519c8af8e4e806d6d47f7432f0f7f04980 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jun 2026 09:12:45 +0000 Subject: [PATCH 33/54] build(deps): bump the development-dependencies group with 8 updates Bumps the development-dependencies group with 8 updates: | Package | From | To | | --- | --- | --- | | [go-openapi/ci-workflows/.github/workflows/auto-merge.yml](https://github.com/go-openapi/ci-workflows) | `0.3.4` | `0.3.5` | | [go-openapi/ci-workflows/.github/workflows/bump-release.yml](https://github.com/go-openapi/ci-workflows) | `0.3.4` | `0.3.5` | | [go-openapi/ci-workflows/.github/workflows/codeql.yml](https://github.com/go-openapi/ci-workflows) | `0.3.4` | `0.3.5` | | [go-openapi/ci-workflows/.github/workflows/contributors.yml](https://github.com/go-openapi/ci-workflows) | `0.3.4` | `0.3.5` | | [go-openapi/ci-workflows/.github/workflows/go-test.yml](https://github.com/go-openapi/ci-workflows) | `0.3.4` | `0.3.5` | | [go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml](https://github.com/go-openapi/ci-workflows) | `cd9849915b4f8b6ceeeaf24e02e8f8e24202c8f6` | `93b16765c4045dbd4dac2372803294298aa7592a` | | [go-openapi/ci-workflows/.github/workflows/scanner.yml](https://github.com/go-openapi/ci-workflows) | `0.3.4` | `0.3.5` | | [go-openapi/ci-workflows/.github/workflows/release.yml](https://github.com/go-openapi/ci-workflows) | `0.3.4` | `0.3.5` | Updates `go-openapi/ci-workflows/.github/workflows/auto-merge.yml` from 0.3.4 to 0.3.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a...f00f5763ddb0c59105de5f565da8cac323fce2bf) Updates `go-openapi/ci-workflows/.github/workflows/bump-release.yml` from 0.3.4 to 0.3.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a...f00f5763ddb0c59105de5f565da8cac323fce2bf) Updates `go-openapi/ci-workflows/.github/workflows/codeql.yml` from 0.3.4 to 0.3.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a...f00f5763ddb0c59105de5f565da8cac323fce2bf) Updates `go-openapi/ci-workflows/.github/workflows/contributors.yml` from 0.3.4 to 0.3.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a...f00f5763ddb0c59105de5f565da8cac323fce2bf) Updates `go-openapi/ci-workflows/.github/workflows/go-test.yml` from 0.3.4 to 0.3.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a...f00f5763ddb0c59105de5f565da8cac323fce2bf) Updates `go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml` from cd9849915b4f8b6ceeeaf24e02e8f8e24202c8f6 to 93b16765c4045dbd4dac2372803294298aa7592a - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/cd9849915b4f8b6ceeeaf24e02e8f8e24202c8f6...93b16765c4045dbd4dac2372803294298aa7592a) Updates `go-openapi/ci-workflows/.github/workflows/scanner.yml` from 0.3.4 to 0.3.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a...f00f5763ddb0c59105de5f565da8cac323fce2bf) Updates `go-openapi/ci-workflows/.github/workflows/release.yml` from 0.3.4 to 0.3.5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a...f00f5763ddb0c59105de5f565da8cac323fce2bf) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/auto-merge.yml dependency-version: 0.3.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/bump-release.yml dependency-version: 0.3.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/codeql.yml dependency-version: 0.3.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/contributors.yml dependency-version: 0.3.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/go-test.yml dependency-version: 0.3.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml dependency-version: 93b16765c4045dbd4dac2372803294298aa7592a dependency-type: direct:production dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/scanner.yml dependency-version: 0.3.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies - dependency-name: go-openapi/ci-workflows/.github/workflows/release.yml dependency-version: 0.3.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/monitor-bot-pr.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index b2537754..4aa5830d 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index fecebe4f..c421c76e 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -30,7 +30,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 with: bump-type: ${{ inputs.bump-type }} tag-message-title: ${{ inputs.tag-message-title }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 78fee343..f2f8f687 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 19a62820..a5feb361 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index e2b3b47a..7e01290e 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 secrets: inherit diff --git a/.github/workflows/monitor-bot-pr.yml b/.github/workflows/monitor-bot-pr.yml index a3a11e52..15197cf1 100644 --- a/.github/workflows/monitor-bot-pr.yml +++ b/.github/workflows/monitor-bot-pr.yml @@ -14,5 +14,5 @@ jobs: contents: write pull-requests: write statuses: read - uses: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml@cd9849915b4f8b6ceeeaf24e02e8f8e24202c8f6 # v0.3.3 + uses: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml@93b16765c4045dbd4dac2372803294298aa7592a # v0.3.3 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index 23be5941..c48b398a 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # V0.3.4 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # V0.3.5 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index d76b7915..c30794ab 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@7a1bb6c4f078ac1a3258db1ae91c37a9d29eee2a # v0.3.4 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 with: tag: ${{ github.ref_name }} secrets: inherit From e41b4fd1b2143d1294379e933ed6710163cd81bc Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Sun, 14 Jun 2026 14:22:08 +0200 Subject: [PATCH 34/54] fix(header): header extension should correctly marshal as JSON * fixes #277 Signed-off-by: Frederic BIDON --- header.go | 6 +++++- header_test.go | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/header.go b/header.go index 599ba2c5..f656e078 100644 --- a/header.go +++ b/header.go @@ -150,7 +150,11 @@ func (h Header) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } - return jsonutils.ConcatJSON(b1, b2, b3), nil + b4, err := json.Marshal(h.VendorExtensible) + if err != nil { + return nil, err + } + return jsonutils.ConcatJSON(b1, b2, b3, b4), nil } // UnmarshalJSON unmarshals this header from JSON. diff --git a/header_test.go b/header_test.go index ad34da3e..e6e0b1a9 100644 --- a/header_test.go +++ b/header_test.go @@ -75,6 +75,7 @@ const headerJSON = `{ func TestIntegrationHeader(t *testing.T) { assert.JSONUnmarshalAsT(t, header, headerJSON) + assert.JSONMarshalAsT(t, headerJSON, header) } func TestJSONLookupHeader(t *testing.T) { From 49846cbe73d1de80fdee6344b0d3e45e72ee31da Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Sun, 14 Jun 2026 14:24:16 +0200 Subject: [PATCH 35/54] chore: relint Signed-off-by: Frederic BIDON --- .golangci.yml | 3 +++ debug_test.go | 2 +- schema_loader.go | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index dc7c9605..9d273317 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -4,7 +4,10 @@ linters: disable: - depguard - funlen + - goconst - godox + - gomodguard + - gomodguard_v2 - exhaustruct - nlreturn - nonamedreturns diff --git a/debug_test.go b/debug_test.go index 6f6547bf..af99d1ed 100644 --- a/debug_test.go +++ b/debug_test.go @@ -38,7 +38,7 @@ func TestDebug(t *testing.T) { Debug = false _ = tmpFile.Close() - flushed, _ := os.Open(tmpName) //nolint:gosec // test file, path is from os.CreateTemp + flushed, _ := os.Open(tmpName) buf := make([]byte, 500) _, _ = flushed.Read(buf) specLogger.SetOutput(os.Stdout) diff --git a/schema_loader.go b/schema_loader.go index 0894c932..1e346069 100644 --- a/schema_loader.go +++ b/schema_loader.go @@ -117,7 +117,7 @@ func (r *schemaLoader) updateBasePath(transitive *schemaLoader, basePath string) func (r *schemaLoader) resolveRef(ref *Ref, target any, basePath string) error { tgt := reflect.ValueOf(target) - if tgt.Kind() != reflect.Ptr { + if tgt.Kind() != reflect.Pointer { return ErrResolveRefNeedsAPointer } From dc55c96f60257d121e61e54c02bbd7da37ce44e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 09:12:32 +0000 Subject: [PATCH 36/54] build(deps): bump go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml Bumps the development-dependencies group with 1 update: [go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml](https://github.com/go-openapi/ci-workflows). Updates `go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml` from 93b16765c4045dbd4dac2372803294298aa7592a to 2e57e83146e049b5dfb8116ba16a09b2da27b3c5 - [Release notes](https://github.com/go-openapi/ci-workflows/releases) - [Commits](https://github.com/go-openapi/ci-workflows/compare/93b16765c4045dbd4dac2372803294298aa7592a...2e57e83146e049b5dfb8116ba16a09b2da27b3c5) --- updated-dependencies: - dependency-name: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml dependency-version: 2e57e83146e049b5dfb8116ba16a09b2da27b3c5 dependency-type: direct:production dependency-group: development-dependencies ... Signed-off-by: dependabot[bot] --- .github/workflows/monitor-bot-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/monitor-bot-pr.yml b/.github/workflows/monitor-bot-pr.yml index 15197cf1..8e8190d7 100644 --- a/.github/workflows/monitor-bot-pr.yml +++ b/.github/workflows/monitor-bot-pr.yml @@ -14,5 +14,5 @@ jobs: contents: write pull-requests: write statuses: read - uses: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml@93b16765c4045dbd4dac2372803294298aa7592a # v0.3.3 + uses: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml@2e57e83146e049b5dfb8116ba16a09b2da27b3c5 # v0.3.3 secrets: inherit From eb04d4706c556c70980864b5eb3cda2705983d91 Mon Sep 17 00:00:00 2001 From: "bot-go-openapi[bot]" <246880138+bot-go-openapi[bot]@users.noreply.github.com> Date: Sat, 20 Jun 2026 07:58:11 +0000 Subject: [PATCH 37/54] doc: updated contributors file Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CONTRIBUTORS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 2fd257bb..d56d7ca0 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 38 | 398 | +| 38 | 401 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 191 | | -| @fredbi | 96 | | +| @fredbi | 99 | | | @pytlesk4 | 26 | | | @kul-amr | 10 | | | @keramix | 10 | | From 1754e05bf68f2fc66465763c5a32d1f64da79ce2 Mon Sep 17 00:00:00 2001 From: fredbi Date: Sun, 21 Jun 2026 18:44:00 +0200 Subject: [PATCH 38/54] chore(ci): run contributors workflow monthly instead of weekly (#281) The all-time contributors workflow no longer needs a weekly cadence: nowadays it mostly bumps maintainer activity. Run it on the 1st of each month at 04:49 UTC ('49 4 1 * *') instead of every Saturday. Signed-off-by: Frederic BIDON Co-authored-by: Claude Opus 4.8 (1M context) --- .github/workflows/contributors.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index a5feb361..50ac3930 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -2,7 +2,7 @@ name: Contributors on: schedule: - - cron: '18 4 * * 6' + - cron: '49 4 1 * *' workflow_dispatch: From da6a6cfe8f033f8a4ce7eacc731360d304dabf06 Mon Sep 17 00:00:00 2001 From: fredbi Date: Mon, 22 Jun 2026 20:11:52 +0200 Subject: [PATCH 39/54] ci: post README announcements to discord + bump ci-workflows to v0.4.0 (#282) Add the webhook-announcements workflow (mirrors go-openapi/testify): pushes to master that change README.md are scanned for new "## Announcements" entries and posted to the discord channel. Also bump all ci-workflows shared-workflow pins to v0.4.0 (af4c93f45481ea7d24ac2a9858272cc03daf424e). Signed-off-by: Frederic BIDON Co-authored-by: Claude Opus 4.8 (1M context) --- .github/workflows/auto-merge.yml | 2 +- .github/workflows/bump-release.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/contributors.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/monitor-bot-pr.yml | 2 +- .github/workflows/scanner.yml | 2 +- .github/workflows/tag-release.yml | 2 +- .github/workflows/webhook-announcements.yml | 60 +++++++++++++++++++++ 9 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/webhook-announcements.yml diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 4aa5830d..c3377a63 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -11,5 +11,5 @@ jobs: permissions: contents: write pull-requests: write - uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 + uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@af4c93f45481ea7d24ac2a9858272cc03daf424e # v0.4.0 secrets: inherit diff --git a/.github/workflows/bump-release.yml b/.github/workflows/bump-release.yml index c421c76e..fa44d33e 100644 --- a/.github/workflows/bump-release.yml +++ b/.github/workflows/bump-release.yml @@ -30,7 +30,7 @@ jobs: bump-release: permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 + uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@af4c93f45481ea7d24ac2a9858272cc03daf424e # v0.4.0 with: bump-type: ${{ inputs.bump-type }} tag-message-title: ${{ inputs.tag-message-title }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f2f8f687..b48a31f9 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -18,5 +18,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 + uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@af4c93f45481ea7d24ac2a9858272cc03daf424e # v0.4.0 secrets: inherit diff --git a/.github/workflows/contributors.yml b/.github/workflows/contributors.yml index 50ac3930..6be321f1 100644 --- a/.github/workflows/contributors.yml +++ b/.github/workflows/contributors.yml @@ -14,5 +14,5 @@ jobs: permissions: pull-requests: write contents: write - uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 + uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@af4c93f45481ea7d24ac2a9858272cc03daf424e # v0.4.0 secrets: inherit diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 7e01290e..bdc4608d 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,5 +13,5 @@ on: jobs: test: - uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 + uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@af4c93f45481ea7d24ac2a9858272cc03daf424e # v0.4.0 secrets: inherit diff --git a/.github/workflows/monitor-bot-pr.yml b/.github/workflows/monitor-bot-pr.yml index 8e8190d7..3e5e18ea 100644 --- a/.github/workflows/monitor-bot-pr.yml +++ b/.github/workflows/monitor-bot-pr.yml @@ -14,5 +14,5 @@ jobs: contents: write pull-requests: write statuses: read - uses: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml@2e57e83146e049b5dfb8116ba16a09b2da27b3c5 # v0.3.3 + uses: go-openapi/ci-workflows/.github/workflows/monitor-bot-pr.yml@af4c93f45481ea7d24ac2a9858272cc03daf424e # v0.4.0 secrets: inherit diff --git a/.github/workflows/scanner.yml b/.github/workflows/scanner.yml index c48b398a..15ad371c 100644 --- a/.github/workflows/scanner.yml +++ b/.github/workflows/scanner.yml @@ -15,5 +15,5 @@ jobs: permissions: contents: read security-events: write - uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # V0.3.5 + uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@af4c93f45481ea7d24ac2a9858272cc03daf424e # v0.4.0 secrets: inherit diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index c30794ab..11736a8e 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -13,7 +13,7 @@ jobs: name: Create release permissions: contents: write - uses: go-openapi/ci-workflows/.github/workflows/release.yml@f00f5763ddb0c59105de5f565da8cac323fce2bf # v0.3.5 + uses: go-openapi/ci-workflows/.github/workflows/release.yml@af4c93f45481ea7d24ac2a9858272cc03daf424e # v0.4.0 with: tag: ${{ github.ref_name }} secrets: inherit diff --git a/.github/workflows/webhook-announcements.yml b/.github/workflows/webhook-announcements.yml new file mode 100644 index 00000000..a21bb820 --- /dev/null +++ b/.github/workflows/webhook-announcements.yml @@ -0,0 +1,60 @@ +name: Webhook Announcements + +# invoke the common webhook-announcements workflow, scanning README. +# +# Two modes: +# +# * push: diff on "## Announcements" section exercises the +# real before..after detection and post to discord channel. +# +# * workflow_dispatch: a manual live run. Optionally provide an arbitrary webhook URL and +# it POSTs for real. By default it diffs against the git empty tree, so every +# announcement currently in the fixture is posted — no need to craft a diff. +# +# NOTE: the webhook URL you type is a workflow_dispatch input and is therefore +# visible in the run's UI/logs. Use a throwaway test webhook (and/or rotate it +# afterwards), not the production go-openapi webhook. + +permissions: + contents: read + +on: + push: + branches: + - master + paths: + - 'README.md' + + workflow_dispatch: + inputs: + webhook-url: + description: | + Webhook URL to POST to (e.g. a test Discord channel webhook). + Visible in run logs — use a throwaway webhook. + type: string + default: '' + compare-base: + description: | + Git ref to diff the fixture against. The default empty-tree SHA posts + every announcement currently in the fixture. + type: string + default: "" + dry-run: + description: | + Print payloads instead of posting. + type: choice + options: + - 'false' + - 'true' + default: 'false' + +jobs: + announce: + uses: go-openapi/ci-workflows/.github/workflows/webhook-announcements.yml@af4c93f45481ea7d24ac2a9858272cc03daf424e # v0.4.0 + with: + scanned-markdown: README.md + # On push: normal before..after diff (empty + # compare-base). On dispatch: honor the provided inputs. + dry-run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry-run || 'false' }} + compare-base: ${{ github.event_name == 'workflow_dispatch' && inputs.compare-base || '' }} + secrets: inherit From bac1beef0f54e07f4ed0c906899260bdb99016c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:12:29 +0000 Subject: [PATCH 40/54] build(deps): bump the go-openapi-dependencies group with 2 updates Bumps the go-openapi-dependencies group with 2 updates: [github.com/go-openapi/testify/enable/yaml/v2](https://github.com/go-openapi/testify) and [github.com/go-openapi/testify/v2](https://github.com/go-openapi/testify). Updates `github.com/go-openapi/testify/enable/yaml/v2` from 2.5.1 to 2.6.0 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.5.1...v2.6.0) Updates `github.com/go-openapi/testify/v2` from 2.5.1 to 2.6.0 - [Release notes](https://github.com/go-openapi/testify/releases) - [Commits](https://github.com/go-openapi/testify/compare/v2.5.1...v2.6.0) --- updated-dependencies: - dependency-name: github.com/go-openapi/testify/enable/yaml/v2 dependency-version: 2.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/testify/v2 dependency-version: 2.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index cac771a0..abd288a7 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/go-openapi/swag/jsonutils v0.26.1 github.com/go-openapi/swag/loading v0.26.1 github.com/go-openapi/swag/stringutils v0.26.1 - github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 - github.com/go-openapi/testify/v2 v2.5.1 + github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 + github.com/go-openapi/testify/v2 v2.6.0 ) require ( diff --git a/go.sum b/go.sum index a4b56b35..61d7bdd6 100644 --- a/go.sum +++ b/go.sum @@ -18,10 +18,10 @@ github.com/go-openapi/swag/typeutils v0.26.1 h1:yg42FgMzRR6PVQ3M3qHz1s+Y6/P4HoJ3 github.com/go-openapi/swag/typeutils v0.26.1/go.mod h1:VfnV+oUtSP2vCSCn2aJgnr8OevUYemyIzzS1VOzS10o= github.com/go-openapi/swag/yamlutils v0.26.1 h1:0TSLK+lXs9vfIhAWzBeI/lOzEnIoot6WTCO1aAeWFTk= github.com/go-openapi/swag/yamlutils v0.26.1/go.mod h1:7W5b7PRX9MxwL7TjeG7H8HkyBGRsIDRObhyMWFgBI2M= -github.com/go-openapi/testify/enable/yaml/v2 v2.5.1 h1:q9NtHwK4qHF7yZziBPvZyv7zWAIk8ok88Gh2mR6Jpc8= -github.com/go-openapi/testify/enable/yaml/v2 v2.5.1/go.mod h1:JW0MXIotCYps/XsgJnG3a8Q7rE5xAiBwoOD5OfaIQBk= -github.com/go-openapi/testify/v2 v2.5.1 h1:TMdhCaw8fUNraVSf3Omoob1dO/AzBfhtFAPW0an6sBo= -github.com/go-openapi/testify/v2 v2.5.1/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= +github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= +github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= +github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From 8e7a0e601399d7612019ecb9b08082c509867fe7 Mon Sep 17 00:00:00 2001 From: "bot-go-openapi[bot]" <246880138+bot-go-openapi[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 08:40:59 +0000 Subject: [PATCH 41/54] doc: updated contributors file Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- CONTRIBUTORS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index d56d7ca0..12fd069b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -4,12 +4,12 @@ | Total Contributors | Total Contributions | | --- | --- | -| 38 | 401 | +| 38 | 403 | | Username | All Time Contribution Count | All Commits | | --- | --- | --- | | @casualjim | 191 | | -| @fredbi | 99 | | +| @fredbi | 101 | | | @pytlesk4 | 26 | | | @kul-amr | 10 | | | @keramix | 10 | | From 9b21ccd1bf2b2b75857c6629e4cfbcd651b127ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:12:33 +0000 Subject: [PATCH 42/54] build(deps): bump the go-openapi-dependencies group with 6 updates Bumps the go-openapi-dependencies group with 6 updates: | Package | From | To | | --- | --- | --- | | [github.com/go-openapi/jsonpointer](https://github.com/go-openapi/jsonpointer) | `0.23.1` | `0.24.0` | | [github.com/go-openapi/swag/conv](https://github.com/go-openapi/swag) | `0.26.1` | `0.27.0` | | [github.com/go-openapi/swag/jsonname](https://github.com/go-openapi/swag) | `0.26.1` | `0.27.0` | | [github.com/go-openapi/swag/jsonutils](https://github.com/go-openapi/swag) | `0.26.1` | `0.27.0` | | [github.com/go-openapi/swag/loading](https://github.com/go-openapi/swag) | `0.26.1` | `0.27.0` | | [github.com/go-openapi/swag/stringutils](https://github.com/go-openapi/swag) | `0.26.1` | `0.27.0` | Updates `github.com/go-openapi/jsonpointer` from 0.23.1 to 0.24.0 - [Release notes](https://github.com/go-openapi/jsonpointer/releases) - [Commits](https://github.com/go-openapi/jsonpointer/compare/v0.23.1...v0.24.0) Updates `github.com/go-openapi/swag/conv` from 0.26.1 to 0.27.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.1...v0.27.0) Updates `github.com/go-openapi/swag/jsonname` from 0.26.1 to 0.27.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.1...v0.27.0) Updates `github.com/go-openapi/swag/jsonutils` from 0.26.1 to 0.27.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.1...v0.27.0) Updates `github.com/go-openapi/swag/loading` from 0.26.1 to 0.27.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.1...v0.27.0) Updates `github.com/go-openapi/swag/stringutils` from 0.26.1 to 0.27.0 - [Release notes](https://github.com/go-openapi/swag/releases) - [Commits](https://github.com/go-openapi/swag/compare/v0.26.1...v0.27.0) --- updated-dependencies: - dependency-name: github.com/go-openapi/jsonpointer dependency-version: 0.24.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/conv dependency-version: 0.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/jsonname dependency-version: 0.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/jsonutils dependency-version: 0.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/loading dependency-version: 0.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/swag/stringutils dependency-version: 0.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 16 ++++++++-------- go.sum | 36 ++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index abd288a7..7439a6d3 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,20 @@ module github.com/go-openapi/spec require ( - github.com/go-openapi/jsonpointer v0.23.1 + github.com/go-openapi/jsonpointer v0.24.0 github.com/go-openapi/jsonreference v0.21.6 - github.com/go-openapi/swag/conv v0.26.1 - github.com/go-openapi/swag/jsonname v0.26.1 - github.com/go-openapi/swag/jsonutils v0.26.1 - github.com/go-openapi/swag/loading v0.26.1 - github.com/go-openapi/swag/stringutils v0.26.1 + github.com/go-openapi/swag/conv v0.27.0 + github.com/go-openapi/swag/jsonname v0.27.0 + github.com/go-openapi/swag/jsonutils v0.27.0 + github.com/go-openapi/swag/loading v0.27.0 + github.com/go-openapi/swag/stringutils v0.27.0 github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 github.com/go-openapi/testify/v2 v2.6.0 ) require ( - github.com/go-openapi/swag/typeutils v0.26.1 // indirect - github.com/go-openapi/swag/yamlutils v0.26.1 // indirect + github.com/go-openapi/swag/typeutils v0.27.0 // indirect + github.com/go-openapi/swag/yamlutils v0.27.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect ) diff --git a/go.sum b/go.sum index 61d7bdd6..975d6931 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,23 @@ -github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4= -github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY= +github.com/go-openapi/jsonpointer v0.24.0 h1:AA6mCjHYHmZ+1RU2Js089EaOK/iwXXNwQsTgnsTha2M= +github.com/go-openapi/jsonpointer v0.24.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y= github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY= -github.com/go-openapi/swag/conv v0.26.1 h1:slr5FVkg9Wc3Y5zcwenD8Sd/PQ94b2I/QJI7N7KTBpg= -github.com/go-openapi/swag/conv v0.26.1/go.mod h1:mvQXgPptZk9GTrFgGwWvT4q+dN+zQej9JfmGwnipz1A= -github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE= -github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc= -github.com/go-openapi/swag/jsonutils v0.26.1 h1:2hdBfFkHg+7Wrz2VsCbeyR6hzkRDs7AztnMR2u84yOY= -github.com/go-openapi/swag/jsonutils v0.26.1/go.mod h1:U+RMJH3wa+6BRiphuRtIyI8fW9HPFqFQ4sHk2oRx0UQ= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1 h1:1CD7NiLLb/TXl3tOnFYU4b+mNfb5rtgHkaA+q7RMYYQ= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.26.1/go.mod h1:ZWafc8nMdYzTE3uYY6W86f0n46+IF0g4uUyRhJw/kXc= -github.com/go-openapi/swag/loading v0.26.1 h1:E9K4wqXeROlhjFQ13K9zMz6ojFGXIggGe+ad1odrK9w= -github.com/go-openapi/swag/loading v0.26.1/go.mod h1:3qvRIlWzWdq1HvmldwmuJ2ohpcAryN6xVt2OTKd0/7E= -github.com/go-openapi/swag/stringutils v0.26.1 h1:f88uYyTso7TnHrKM/bUBsQ5e2wKf37cpgo6pvbzd9yU= -github.com/go-openapi/swag/stringutils v0.26.1/go.mod h1:Sc6d3bU8fgk5AyZR8/8jEQ+Is/Ald+TD/IIggPN8UJk= -github.com/go-openapi/swag/typeutils v0.26.1 h1:yg42FgMzRR6PVQ3M3qHz1s+Y6/P4HoJ3cBarXa3OVnU= -github.com/go-openapi/swag/typeutils v0.26.1/go.mod h1:VfnV+oUtSP2vCSCn2aJgnr8OevUYemyIzzS1VOzS10o= -github.com/go-openapi/swag/yamlutils v0.26.1 h1:0TSLK+lXs9vfIhAWzBeI/lOzEnIoot6WTCO1aAeWFTk= -github.com/go-openapi/swag/yamlutils v0.26.1/go.mod h1:7W5b7PRX9MxwL7TjeG7H8HkyBGRsIDRObhyMWFgBI2M= +github.com/go-openapi/swag/conv v0.27.0 h1:EKOH4feXrvdo8DbSsXSAqRT8fz1epEnS5O2IfXUOzE8= +github.com/go-openapi/swag/conv v0.27.0/go.mod h1:pfiv0uKQTbaGApk8Zs/lZV3uSjmSpa2FO1y183YngN8= +github.com/go-openapi/swag/jsonname v0.27.0 h1:4QVB//CKOdE8IOiBg19JNY2wfDS48MhesIquYBy2rUE= +github.com/go-openapi/swag/jsonname v0.27.0/go.mod h1:I1YsyvvhBuZsFXSW6I7ODfdyq13p7hDil//1T9/pFFk= +github.com/go-openapi/swag/jsonutils v0.27.0 h1:VYtd9jEQYeU4j8q5vdn5KWotF4vKywhGdMBrALtAsfE= +github.com/go-openapi/swag/jsonutils v0.27.0/go.mod h1:U7pb8AGuwhok3RDicHeHwSG4L3PXSq6PAL98Aon632g= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0 h1:+d7C7Ur/SsGg/UZ9G0JEovnfRqtMNZCJQGKc2h/ojoE= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= +github.com/go-openapi/swag/loading v0.27.0 h1:s8DA9aPEdFH6OluHUYUn3DnIuoTdyWs9RwffXBUfyeI= +github.com/go-openapi/swag/loading v0.27.0/go.mod h1:VOz+Jg6UGGywcmRvYsI4fvtp+bd7NfioseGEPleYdA4= +github.com/go-openapi/swag/stringutils v0.27.0 h1:Of7w/HljWsNZvuxsUAnw3n+hCOyI6HLJOxW2kQRAxio= +github.com/go-openapi/swag/stringutils v0.27.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= +github.com/go-openapi/swag/typeutils v0.27.0 h1:aCf4MSGo8NLwZP8Q6t32DWLJSvl/WwNqgmEG+xJ6v2o= +github.com/go-openapi/swag/typeutils v0.27.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= +github.com/go-openapi/swag/yamlutils v0.27.0 h1:bQ6eAMil5X9tdcf7dMn4t15alzG6jddnrKPuKa/zxKM= +github.com/go-openapi/swag/yamlutils v0.27.0/go.mod h1:yRfIo7qqVkmJRQjX8exjA3AfcI8rH1KDNPsTparoCv4= github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= From 1688f14122e3ec67c743f124e25ccdbff862efcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 07:49:25 +0200 Subject: [PATCH 43/54] build(deps): bump the go-openapi-dependencies group with 2 updates (#286) Bumps the go-openapi-dependencies group with 2 updates: [github.com/go-openapi/jsonpointer](https://github.com/go-openapi/jsonpointer) and [github.com/go-openapi/jsonreference](https://github.com/go-openapi/jsonreference). Updates `github.com/go-openapi/jsonpointer` from 0.24.0 to 1.0.0 - [Release notes](https://github.com/go-openapi/jsonpointer/releases) - [Commits](https://github.com/go-openapi/jsonpointer/compare/v0.24.0...v1.0.0) Updates `github.com/go-openapi/jsonreference` from 0.21.6 to 1.0.0 - [Release notes](https://github.com/go-openapi/jsonreference/releases) - [Commits](https://github.com/go-openapi/jsonreference/compare/v0.21.6...v1.0.0) --- updated-dependencies: - dependency-name: github.com/go-openapi/jsonpointer dependency-version: 1.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: go-openapi-dependencies - dependency-name: github.com/go-openapi/jsonreference dependency-version: 1.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: go-openapi-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 7439a6d3..e825bbf1 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/go-openapi/spec require ( - github.com/go-openapi/jsonpointer v0.24.0 - github.com/go-openapi/jsonreference v0.21.6 + github.com/go-openapi/jsonpointer v1.0.0 + github.com/go-openapi/jsonreference v1.0.0 github.com/go-openapi/swag/conv v0.27.0 github.com/go-openapi/swag/jsonname v0.27.0 github.com/go-openapi/swag/jsonutils v0.27.0 diff --git a/go.sum b/go.sum index 975d6931..32ea138d 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -github.com/go-openapi/jsonpointer v0.24.0 h1:AA6mCjHYHmZ+1RU2Js089EaOK/iwXXNwQsTgnsTha2M= -github.com/go-openapi/jsonpointer v0.24.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= -github.com/go-openapi/jsonreference v0.21.6 h1:NZ5nGfnaM1n4I43Xjm1e5/M2GjOwQwndQz22uhxwD+Y= -github.com/go-openapi/jsonreference v0.21.6/go.mod h1:xzbgtQ3ZbWxvET3AxdzCJlJt6vkovbf+IfSPJjD0tUY= +github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s= +github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= +github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY= +github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= github.com/go-openapi/swag/conv v0.27.0 h1:EKOH4feXrvdo8DbSsXSAqRT8fz1epEnS5O2IfXUOzE8= github.com/go-openapi/swag/conv v0.27.0/go.mod h1:pfiv0uKQTbaGApk8Zs/lZV3uSjmSpa2FO1y183YngN8= github.com/go-openapi/swag/jsonname v0.27.0 h1:4QVB//CKOdE8IOiBg19JNY2wfDS48MhesIquYBy2rUE= From d76a1a497cec7e63c68e55fa7408442bb664202b Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 20 Jul 2026 11:58:14 +0200 Subject: [PATCH 44/54] fix(expander): cap $ref expansion node count to prevent amplification DoS ExpandSpec/ExpandSchema* inline every $ref with no memoization and no global budget. A self-contained spec where each of N definitions references the next one twice (via allOf/anyOf/oneOf/properties/items) drives 2^N schema expansions from O(N) bytes of input. A ~1.5 KB document expands into tens of GB of heap and >30 s of CPU, letting an unauthenticated caller exhaust resources in any service that expands untrusted specs. All refs can be fragment-only, so a restrictive PathLoader is not a mitigation. The expanded output itself is exponential (expansion inlines by value), so a memoization cache would bound CPU but not memory. The only guard that bounds memory is refusing to build the tree past a budget. Add ExpandOptions.MaxExpansionNodes, a per-call cap on the number of expanded schema nodes, enforced by a counter in the shared resolverContext incremented at the top of expandSchema: 0 (zero value): DefaultMaxExpansionNodes (500,000) -- every caller protected <0: unbounded (trusted specs only) >0: explicit cap 500,000 leaves ~10x headroom over the largest real spec we test (the full Kubernetes API expands to ~47,000 nodes) while stopping the attack well before it hurts. The metric is nodes, not $ref resolutions: measurement showed resolution counts do not grow with the attack (document-level caching collapses them), so a resolution cap would miss the blow-up entirely. Exceeding the budget returns ErrExpandTooManyNodes. This is a resource-exhaustion safeguard, so it is terminal even under ContinueOnError, rather than leaving the caller with a silently truncated spec. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Frederic BIDON --- errors.go | 7 +++ expander.go | 43 +++++++++++++ expander_budget_test.go | 136 ++++++++++++++++++++++++++++++++++++++++ schema_loader.go | 31 ++++++++- 4 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 expander_budget_test.go diff --git a/errors.go b/errors.go index eaca01cc..740b773c 100644 --- a/errors.go +++ b/errors.go @@ -20,6 +20,13 @@ var ( // ErrExpandUnsupportedType indicates that $ref expansion is attempted on some invalid type. ErrExpandUnsupportedType = errors.New("expand: unsupported type. Input should be of type *Parameter or *Response") + // ErrExpandTooManyNodes indicates that $ref expansion exceeded the maximum number of schema nodes + // allowed for a single expansion (see ExpandOptions.MaxExpansionNodes). + // + // This is a safeguard against maliciously crafted specifications that expand to an exponential + // number of nodes from a small input (a $ref amplification / "billion laughs" style attack). + ErrExpandTooManyNodes = errors.New("expand: too many schema nodes: expansion budget exceeded (see ExpandOptions.MaxExpansionNodes)") + // ErrSpec is an error raised by the spec package. ErrSpec = errors.New("spec error") ) diff --git a/expander.go b/expander.go index f9c2fa32..b12be4ed 100644 --- a/expander.go +++ b/expander.go @@ -10,6 +10,17 @@ import ( const smallPrealloc = 10 +// DefaultMaxExpansionNodes is the default upper bound on the number of schema nodes +// expanded during a single ExpandSpec / ExpandSchema* call. +// +// It guards against maliciously crafted specifications whose $ref graph expands to an +// exponential number of nodes from a few kilobytes of input. For reference, expanding the +// full Kubernetes API specification (the largest real-world spec we test against) visits +// roughly 47,000 nodes, so this default leaves ample headroom for legitimate documents. +// +// See ExpandOptions.MaxExpansionNodes to tune or disable this budget. +const DefaultMaxExpansionNodes = 500_000 + // ExpandOptions provides options for the spec expander. // // RelativeBase is the path to the root document. This can be a remote URL or a path to a local file. @@ -24,6 +35,34 @@ type ExpandOptions struct { ContinueOnError bool // continue expanding even after and error is found PathLoader func(string) (json.RawMessage, error) `json:"-"` // the document loading method that takes a path as input and yields a json document AbsoluteCircularRef bool // circular $ref remaining after expansion remain absolute URLs + + // MaxExpansionNodes caps the number of schema nodes expanded during a single expansion call, + // as a safeguard against $ref amplification attacks (see ErrExpandTooManyNodes). + // + // The value is interpreted as follows: + // + // 0 (the zero value): use DefaultMaxExpansionNodes. Every caller is protected by default. + // <0: no limit (unbounded expansion). Use only with fully trusted specifications. + // >0: cap the expansion at this number of nodes. + // + // When the budget is exceeded, expansion stops and ErrExpandTooManyNodes is returned. + // Because this is a resource-exhaustion safeguard, the error is always returned, even when + // ContinueOnError is set. + MaxExpansionNodes int +} + +// maxExpansionNodes resolves the tri-state MaxExpansionNodes option into an effective budget. +// +// A returned value of 0 means "unbounded". +func (o *ExpandOptions) maxExpansionNodes() int { + switch { + case o.MaxExpansionNodes == 0: + return DefaultMaxExpansionNodes + case o.MaxExpansionNodes < 0: + return 0 // unbounded + default: + return o.MaxExpansionNodes + } } func optionsOrDefault(opts *ExpandOptions) *ExpandOptions { @@ -192,6 +231,10 @@ func expandItems(target Schema, parentRefs []string, resolver *schemaLoader, bas //nolint:gocognit,gocyclo,cyclop // complex but well-tested $ref expansion logic; refactoring deferred to dedicated PR func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) { + if err := resolver.context.countNode(); err != nil { + return &target, err + } + if target.Ref.String() == "" && target.Ref.IsRoot() { newRef := normalizeRef(&target.Ref, basePath) target.Ref = *newRef diff --git a/expander_budget_test.go b/expander_budget_test.go new file mode 100644 index 00000000..2eb86765 --- /dev/null +++ b/expander_budget_test.go @@ -0,0 +1,136 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package spec + +import ( + "encoding/json" + "errors" + "fmt" + "testing" + + "github.com/go-openapi/testify/v2/assert" + "github.com/go-openapi/testify/v2/require" +) + +// errNoExternalLoads is returned by the deny-all PathLoader used to prove that refusing +// external loads is not, on its own, a mitigation for the amplification attack. +var errNoExternalLoads = errors.New("no external loads allowed") + +// buildAmplificationSpec builds a self-contained spec where each of n definitions references +// the next one twice via allOf. Without an expansion budget, expanding d0 inlines a tree with +// 2^(n-1) leaves from O(n) bytes of input (a $ref amplification / "billion laughs" attack). +func buildAmplificationSpec(t testing.TB, n int) []byte { + t.Helper() + + defs := make(map[string]any, n) + for i := range n { + var sch any + if i == n-1 { + sch = map[string]any{"type": "string"} + } else { + next := fmt.Sprintf("#/definitions/d%d", i+1) + sch = map[string]any{"allOf": []any{ + map[string]any{"$ref": next}, + map[string]any{"$ref": next}, + }} + } + defs[fmt.Sprintf("d%d", i)] = sch + } + + doc := map[string]any{ + "swagger": "2.0", + "info": map[string]any{"title": "x", "version": "1"}, + "paths": map[string]any{}, + "definitions": defs, + } + raw, err := json.Marshal(doc) + require.NoError(t, err) + + return raw +} + +func TestMaxExpansionNodesTriState(t *testing.T) { + // 0 (zero value): default budget, so every caller is protected out of the box. + assert.EqualT(t, DefaultMaxExpansionNodes, (&ExpandOptions{}).maxExpansionNodes()) + + // negative: unbounded. + assert.EqualT(t, 0, (&ExpandOptions{MaxExpansionNodes: -1}).maxExpansionNodes()) + + // positive: explicit budget. + assert.EqualT(t, 1234, (&ExpandOptions{MaxExpansionNodes: 1234}).maxExpansionNodes()) +} + +func TestExpand_AmplificationBudget(t *testing.T) { + // A deep amplification spec. Even a modest depth would explode without a budget. + const depth = 40 + raw := buildAmplificationSpec(t, depth) + + t.Run("explicit budget trips the guard", func(t *testing.T) { + var sw Swagger + require.NoError(t, json.Unmarshal(raw, &sw)) + + err := ExpandSpec(&sw, &ExpandOptions{MaxExpansionNodes: 2000}) + require.ErrorIs(t, err, ErrExpandTooManyNodes) + }) + + t.Run("deny-all PathLoader is not a mitigation on its own", func(t *testing.T) { + // All refs are fragment-only and resolve against the in-memory root, so refusing + // external loads does not prevent the blow-up: the budget is what stops it. + var sw Swagger + require.NoError(t, json.Unmarshal(raw, &sw)) + + loaderCalled := false + err := ExpandSpec(&sw, &ExpandOptions{ + MaxExpansionNodes: 2000, + PathLoader: func(p string) (json.RawMessage, error) { + loaderCalled = true + return nil, fmt.Errorf("%w: %s", errNoExternalLoads, p) + }, + }) + require.ErrorIs(t, err, ErrExpandTooManyNodes) + assert.FalseT(t, loaderCalled, "expected no external load attempts") + }) + + t.Run("ContinueOnError does not suppress a budget breach", func(t *testing.T) { + // The budget is a hard resource-exhaustion safeguard: unlike an unresolvable $ref, + // it must surface even when the caller tolerates errors. + var sw Swagger + require.NoError(t, json.Unmarshal(raw, &sw)) + + err := ExpandSpec(&sw, &ExpandOptions{MaxExpansionNodes: 2000, ContinueOnError: true}) + require.ErrorIs(t, err, ErrExpandTooManyNodes) + }) + + t.Run("negative budget disables the guard", func(t *testing.T) { + // A shallow spec that stays well under any real budget must expand fully when unbounded. + shallow := buildAmplificationSpec(t, 8) + var sw Swagger + require.NoError(t, json.Unmarshal(shallow, &sw)) + + require.NoError(t, ExpandSpec(&sw, &ExpandOptions{MaxExpansionNodes: -1})) + }) +} + +func TestExpand_BudgetAllowsLegitSpec(t *testing.T) { + // A shallow amplification spec (small node count) must expand cleanly under the default budget. + raw := buildAmplificationSpec(t, 8) + var sw Swagger + require.NoError(t, json.Unmarshal(raw, &sw)) + + require.NoError(t, ExpandSpec(&sw, nil)) // nil options => default budget + // d0 fully expanded: no $ref remains in the leaf chain. + out, err := json.Marshal(sw.Definitions["d0"]) + require.NoError(t, err) + assert.StringNotContainsT(t, string(out), `"$ref"`) +} + +func TestExpand_BudgetErrorIsSentinel(t *testing.T) { + raw := buildAmplificationSpec(t, 40) + var sw Swagger + require.NoError(t, json.Unmarshal(raw, &sw)) + + err := ExpandSpec(&sw, &ExpandOptions{MaxExpansionNodes: 100}) + require.Error(t, err) + assert.TrueT(t, errors.Is(err, ErrExpandTooManyNodes)) +} diff --git a/schema_loader.go b/schema_loader.go index 1e346069..65d34df4 100644 --- a/schema_loader.go +++ b/schema_loader.go @@ -5,6 +5,7 @@ package spec import ( "encoding/json" + "errors" "fmt" "log" "net/url" @@ -43,6 +44,11 @@ type resolverContext struct { basePath string loadDoc func(string) (json.RawMessage, error) rootID string + + // nodes counts the schema nodes expanded so far, capped by maxNodes to guard against + // $ref amplification. maxNodes == 0 means unbounded. Shared, single-threaded: no locking needed. + nodes int + maxNodes int } func newResolverContext(options *ExpandOptions) *resolverContext { @@ -60,9 +66,20 @@ func newResolverContext(options *ExpandOptions) *resolverContext { circulars: make(map[string]bool), basePath: expandOptions.RelativeBase, // keep the root base path in context loadDoc: loader, + maxNodes: expandOptions.maxExpansionNodes(), } } +// countNode accounts for one expanded schema node and reports whether the expansion budget +// has been exceeded. A maxNodes of 0 disables the budget (unbounded expansion). +func (c *resolverContext) countNode() error { + c.nodes++ + if c.maxNodes > 0 && c.nodes > c.maxNodes { + return ErrExpandTooManyNodes + } + return nil +} + type schemaLoader struct { root any options *ExpandOptions @@ -246,14 +263,22 @@ func (r *schemaLoader) deref(input any, parentRefs []string, basePath string) er } func (r *schemaLoader) shouldStopOnError(err error) bool { - if err != nil && !r.options.ContinueOnError { + if err == nil { + return false + } + + if errors.Is(err, ErrExpandTooManyNodes) { + // a blown expansion budget is a hard, document-level failure: it is a safeguard against + // resource exhaustion and is never suppressed by ContinueOnError. return true } - if err != nil { - log.Println(err) + if !r.options.ContinueOnError { + return true } + log.Println(err) + return false } From 5ae1e0d1e553a36e0aca5266288b61a59deb9a2f Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 20 Jul 2026 12:15:31 +0200 Subject: [PATCH 45/54] chore: upgrade dependencies ; fix deprecated jsonname Signed-off-by: Frederic BIDON --- go.mod | 15 ++++++++------- go.sum | 17 +++++++++++++++++ schema.go | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index e825bbf1..59fccf18 100644 --- a/go.mod +++ b/go.mod @@ -3,18 +3,19 @@ module github.com/go-openapi/spec require ( github.com/go-openapi/jsonpointer v1.0.0 github.com/go-openapi/jsonreference v1.0.0 - github.com/go-openapi/swag/conv v0.27.0 - github.com/go-openapi/swag/jsonname v0.27.0 - github.com/go-openapi/swag/jsonutils v0.27.0 - github.com/go-openapi/swag/loading v0.27.0 - github.com/go-openapi/swag/stringutils v0.27.0 + github.com/go-openapi/swag/conv v0.27.1 + github.com/go-openapi/swag/jsonname v0.27.1 + github.com/go-openapi/swag/jsonutils v0.27.1 + github.com/go-openapi/swag/loading v0.27.1 + github.com/go-openapi/swag/stringutils v0.27.1 github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 github.com/go-openapi/testify/v2 v2.6.0 ) require ( - github.com/go-openapi/swag/typeutils v0.27.0 // indirect - github.com/go-openapi/swag/yamlutils v0.27.0 // indirect + github.com/go-openapi/swag/pools v0.27.1 // indirect + github.com/go-openapi/swag/typeutils v0.27.1 // indirect + github.com/go-openapi/swag/yamlutils v0.27.1 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect ) diff --git a/go.sum b/go.sum index 32ea138d..034a6a85 100644 --- a/go.sum +++ b/go.sum @@ -4,20 +4,37 @@ github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkr github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= github.com/go-openapi/swag/conv v0.27.0 h1:EKOH4feXrvdo8DbSsXSAqRT8fz1epEnS5O2IfXUOzE8= github.com/go-openapi/swag/conv v0.27.0/go.mod h1:pfiv0uKQTbaGApk8Zs/lZV3uSjmSpa2FO1y183YngN8= +github.com/go-openapi/swag/conv v0.27.1 h1:8wi9ZG+olmY1wXphl93EWniPtbSPkXM/feH7FgjsvrU= +github.com/go-openapi/swag/conv v0.27.1/go.mod h1:QbqMivkpKhC3g1B1GGGOJ6ANewI3S62dbzYu3Duowqs= github.com/go-openapi/swag/jsonname v0.27.0 h1:4QVB//CKOdE8IOiBg19JNY2wfDS48MhesIquYBy2rUE= github.com/go-openapi/swag/jsonname v0.27.0/go.mod h1:I1YsyvvhBuZsFXSW6I7ODfdyq13p7hDil//1T9/pFFk= +github.com/go-openapi/swag/jsonname v0.27.1 h1:Rrba0m4IgkENyxnIOBZGl0zQEjt6pfGy4SRmZnwVeoA= +github.com/go-openapi/swag/jsonname v0.27.1/go.mod h1:rtHNjjwBhdavc6eybmd5Fj60cIgstqQHcToaK/+4WwQ= github.com/go-openapi/swag/jsonutils v0.27.0 h1:VYtd9jEQYeU4j8q5vdn5KWotF4vKywhGdMBrALtAsfE= github.com/go-openapi/swag/jsonutils v0.27.0/go.mod h1:U7pb8AGuwhok3RDicHeHwSG4L3PXSq6PAL98Aon632g= +github.com/go-openapi/swag/jsonutils v0.27.1 h1:SVgK3i4USzCU5mibOOS/l4ea2h9UQXy7J7RNLTjuXjU= +github.com/go-openapi/swag/jsonutils v0.27.1/go.mod h1:tdlEpZqdcQ17uj6J4YdK9vd8It5qWMwjWXOs0tjpRlk= github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0 h1:+d7C7Ur/SsGg/UZ9G0JEovnfRqtMNZCJQGKc2h/ojoE= github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1 h1:mJu3COL9WEaZVp/Kf2PRMi7tPszPEJfSr/OO75ynCs8= github.com/go-openapi/swag/loading v0.27.0 h1:s8DA9aPEdFH6OluHUYUn3DnIuoTdyWs9RwffXBUfyeI= github.com/go-openapi/swag/loading v0.27.0/go.mod h1:VOz+Jg6UGGywcmRvYsI4fvtp+bd7NfioseGEPleYdA4= +github.com/go-openapi/swag/loading v0.27.1 h1:/DxUgDXKbBX4bcn7r9uEXfJyzN5XpiJmZplzQTjrRCY= +github.com/go-openapi/swag/loading v0.27.1/go.mod h1:jvGh3iA2+zyUUycB5fgJWzeHnhrpvGnJJM0RVE9ZShE= +github.com/go-openapi/swag/pools v0.27.1 h1:9LeadcMyb2GJCbXX5hVQDbZ2Lq9TL4dCs/nx1j5DO0E= +github.com/go-openapi/swag/pools v0.27.1/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= github.com/go-openapi/swag/stringutils v0.27.0 h1:Of7w/HljWsNZvuxsUAnw3n+hCOyI6HLJOxW2kQRAxio= github.com/go-openapi/swag/stringutils v0.27.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= +github.com/go-openapi/swag/stringutils v0.27.1 h1:ZXePZ0r2p1qSjo8tD3Un4vFj8+FqlCkczxDrJIhYUp8= +github.com/go-openapi/swag/stringutils v0.27.1/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= github.com/go-openapi/swag/typeutils v0.27.0 h1:aCf4MSGo8NLwZP8Q6t32DWLJSvl/WwNqgmEG+xJ6v2o= github.com/go-openapi/swag/typeutils v0.27.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= +github.com/go-openapi/swag/typeutils v0.27.1 h1:KSTdFlfnse4r6dP9IrEnwMldjE+zs71UeEB3//PtVXc= +github.com/go-openapi/swag/typeutils v0.27.1/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= github.com/go-openapi/swag/yamlutils v0.27.0 h1:bQ6eAMil5X9tdcf7dMn4t15alzG6jddnrKPuKa/zxKM= github.com/go-openapi/swag/yamlutils v0.27.0/go.mod h1:yRfIo7qqVkmJRQjX8exjA3AfcI8rH1KDNPsTparoCv4= +github.com/go-openapi/swag/yamlutils v0.27.1 h1:ftxv6xvXb1E3zohUc+okZ9nSqNb9StQX/FXnKZ98sQA= +github.com/go-openapi/swag/yamlutils v0.27.1/go.mod h1:bnxFIB1qewGRiZHypXGZ3fNgf13/0HfRgnS/iZBDrOo= github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= diff --git a/schema.go b/schema.go index d7a481bf..c71a2e5c 100644 --- a/schema.go +++ b/schema.go @@ -9,7 +9,7 @@ import ( "strings" "github.com/go-openapi/jsonpointer" - "github.com/go-openapi/swag/jsonname" + "github.com/go-openapi/jsonpointer/jsonname" "github.com/go-openapi/swag/jsonutils" ) From 64655f31c8d63f8e5ad8841e341ba7396ad50d50 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 20 Jul 2026 13:45:03 +0200 Subject: [PATCH 46/54] feat(expander): accept an option-aware document loader Add ExpandOptions.PathLoaderWithOptions, a document loader matching the func(string, ...loading.Option) (json.RawMessage, error) signature now used by the go-openapi/swag/loading and go-openapi/loads loaders. When set, it takes precedence over PathLoader, which in turn precedes the package-level default. This lets a caller inject an options-aware loader -- for example one confined to a directory with loading.WithRoot to safely resolve $ref targets from an untrusted spec -- directly, without wrapping it in a func(string) adapter closure. The injected loader carries its own loading options; the expander invokes it without adding any, keeping the plumbing free of forwarding logic. The change is additive: existing callers using PathLoader (or the default) are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Frederic BIDON --- expander.go | 19 +++++++- expander_loader_test.go | 99 +++++++++++++++++++++++++++++++++++++++++ schema_loader.go | 16 +++++-- 3 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 expander_loader_test.go diff --git a/expander.go b/expander.go index b12be4ed..767623b9 100644 --- a/expander.go +++ b/expander.go @@ -6,6 +6,8 @@ package spec import ( "encoding/json" "fmt" + + "github.com/go-openapi/swag/loading" ) const smallPrealloc = 10 @@ -28,7 +30,11 @@ const DefaultMaxExpansionNodes = 500_000 // If left empty, the root document is assumed to be located in the current working directory: // all relative $ref's will be resolved from there. // -// PathLoader injects a document loading method. By default, this resolves to the function provided by the SpecLoader package variable. +// PathLoader injects a document loading method. By default, this resolves to the function provided by the PathLoader package variable. +// +// PathLoaderWithOptions is an alternative document loader that accepts [loading.Option] values, matching the +// signature used by the go-openapi/swag/loading and go-openapi/loads loaders. When set, it takes precedence over +// PathLoader. This lets a caller inject an options-aware (e.g. path-confined) loader without an adapter closure. type ExpandOptions struct { RelativeBase string // the path to the root document to expand. This is a file, not a directory SkipSchemas bool // do not expand schemas, just paths, parameters and responses @@ -36,6 +42,17 @@ type ExpandOptions struct { PathLoader func(string) (json.RawMessage, error) `json:"-"` // the document loading method that takes a path as input and yields a json document AbsoluteCircularRef bool // circular $ref remaining after expansion remain absolute URLs + // PathLoaderWithOptions injects a document loading method that accepts loading options. + // + // It has the same role as PathLoader but matches the option-aware loader signature exposed by + // github.com/go-openapi/swag/loading (and github.com/go-openapi/loads), so such a loader can be + // injected directly, without wrapping it in an adapter closure. + // + // When set, PathLoaderWithOptions takes precedence over PathLoader. The provided loader is expected + // to carry its own loading options (for example a path confinement built with loading.WithRoot); + // the expander itself invokes it without adding options. + PathLoaderWithOptions func(string, ...loading.Option) (json.RawMessage, error) `json:"-"` + // MaxExpansionNodes caps the number of schema nodes expanded during a single expansion call, // as a safeguard against $ref amplification attacks (see ErrExpandTooManyNodes). // diff --git a/expander_loader_test.go b/expander_loader_test.go new file mode 100644 index 00000000..9243186b --- /dev/null +++ b/expander_loader_test.go @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package spec + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + "testing" + + "github.com/go-openapi/swag/loading" + "github.com/go-openapi/testify/v2/assert" + "github.com/go-openapi/testify/v2/require" +) + +// errUnexpectedLoad is returned by a test loader asked to load a path it does not expect. +var errUnexpectedLoad = errors.New("unexpected load") + +func TestPathLoaderSelection(t *testing.T) { + t.Run("option-aware loader is used when set", func(t *testing.T) { + var called string + ctx := newResolverContext(&ExpandOptions{ + PathLoaderWithOptions: func(string, ...loading.Option) (json.RawMessage, error) { + called = "withOptions" + return json.RawMessage(`{}`), nil + }, + }) + + _, err := ctx.loadDoc("x") + require.NoError(t, err) + assert.EqualT(t, "withOptions", called) + }) + + t.Run("option-aware loader takes precedence over the plain loader", func(t *testing.T) { + var called string + ctx := newResolverContext(&ExpandOptions{ + PathLoader: func(string) (json.RawMessage, error) { + called = "plain" + return json.RawMessage(`{}`), nil + }, + PathLoaderWithOptions: func(string, ...loading.Option) (json.RawMessage, error) { + called = "withOptions" + return json.RawMessage(`{}`), nil + }, + }) + + _, err := ctx.loadDoc("x") + require.NoError(t, err) + assert.EqualT(t, "withOptions", called) + }) + + t.Run("plain loader is used when only it is set", func(t *testing.T) { + var called string + ctx := newResolverContext(&ExpandOptions{ + PathLoader: func(string) (json.RawMessage, error) { + called = "plain" + return json.RawMessage(`{}`), nil + }, + }) + + _, err := ctx.loadDoc("x") + require.NoError(t, err) + assert.EqualT(t, "plain", called) + }) +} + +func TestExpand_PathLoaderWithOptions(t *testing.T) { + // A cross-file $ref forces a document load: prove it is routed through the option-aware loader. + const other = `{"definitions":{"Thing":{"type":"string"}}}` + + raw := []byte(`{ + "swagger":"2.0","info":{"title":"x","version":"1"},"paths":{}, + "definitions":{"Ref":{"$ref":"other.json#/definitions/Thing"}} + }`) + var sw Swagger + require.NoError(t, json.Unmarshal(raw, &sw)) + + var loaderCalls int + err := ExpandSpec(&sw, &ExpandOptions{ + RelativeBase: "/base/root.json", + PathLoaderWithOptions: func(pth string, _ ...loading.Option) (json.RawMessage, error) { + if strings.Contains(pth, "other.json") { + loaderCalls++ + return json.RawMessage(other), nil + } + return nil, fmt.Errorf("%w: %s", errUnexpectedLoad, pth) + }, + }) + require.NoError(t, err) + assert.TrueT(t, loaderCalls > 0, "expected the option-aware loader to be invoked") + + // the cross-file $ref has been expanded in place + out, err := json.Marshal(sw.Definitions["Ref"]) + require.NoError(t, err) + assert.StringContainsT(t, string(out), `"type":"string"`) + assert.StringNotContainsT(t, string(out), `"$ref"`) +} diff --git a/schema_loader.go b/schema_loader.go index 65d34df4..491ed020 100644 --- a/schema_loader.go +++ b/schema_loader.go @@ -54,12 +54,20 @@ type resolverContext struct { func newResolverContext(options *ExpandOptions) *resolverContext { expandOptions := optionsOrDefault(options) - // path loader may be overridden by options + // path loader may be overridden by options. An option-aware loader takes precedence over a + // plain one, which in turn takes precedence over the package-level default. var loader func(string) (json.RawMessage, error) - if expandOptions.PathLoader == nil { - loader = PathLoader - } else { + switch { + case expandOptions.PathLoaderWithOptions != nil: + withOptions := expandOptions.PathLoaderWithOptions + loader = func(pth string) (json.RawMessage, error) { + // the injected loader carries its own loading options: none are added here. + return withOptions(pth) + } + case expandOptions.PathLoader != nil: loader = expandOptions.PathLoader + default: + loader = PathLoader } return &resolverContext{ From 4e073e103e1da409715da2625919ffa37b887c26 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 20 Jul 2026 14:09:30 +0200 Subject: [PATCH 47/54] fix(ref): stop performing a network request in IsValidURI IsValidURI resolved an absolute-URL $ref by issuing http.Get(v) on http.DefaultClient, which has no timeout and no cancellation. On an attacker-controlled URL whose server accepts the connection but never responds, the call blocks indefinitely, leaking goroutines, sockets, and file descriptors. Because go-openapi/validate calls IsValidURI on every $ref of a spec (in validateReferencesValid), an untrusted document full of stalling full-URL refs can exhaust resources during validation (CWE-400/CWE-770). The bare GET to an arbitrary, caller-supplied URL is also an SSRF vector against internal addresses. A method named IsValidURI should validate the reference, not probe remote reachability over the network: that made validation depend on network availability and non-deterministic. Resolving and fetching remote references is the expander's job, through its configurable (and now confinable) document loader. Treat a well-formed absolute URL as a valid URI without any network request. Local file references are still checked on disk. No spec or validate test depended on the probe (validate's fixtures use fragment-only refs). Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Frederic BIDON --- ref.go | 22 ++++++++++----------- ref_test.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/ref.go b/ref.go index 40b7d486..d1a7ab9b 100644 --- a/ref.go +++ b/ref.go @@ -7,7 +7,6 @@ import ( "bytes" "encoding/gob" "encoding/json" - "net/http" "os" "path/filepath" @@ -62,7 +61,15 @@ func (r *Ref) RemoteURI() string { return u.String() } -// IsValidURI returns true when the url the ref points to can be found. +// IsValidURI returns true when the ref points to a valid URI. +// +// For an absolute URL, it only checks that the reference is a well-formed URI. It deliberately +// does NOT perform a network request to verify that the remote target is reachable: doing so +// would make validation depend on network availability and expose callers to denial-of-service +// and SSRF when processing untrusted specifications. Resolving and fetching remote references is +// the responsibility of the expander, through its configurable (and confinable) document loader. +// +// For a local file reference, it checks that the file exists. func (r *Ref) IsValidURI(basepaths ...string) bool { if r.String() == "" { return true @@ -74,15 +81,8 @@ func (r *Ref) IsValidURI(basepaths ...string) bool { } if r.HasFullURL { - //nolint:noctx,gosec - rr, err := http.Get(v) - if err != nil { - return false - } - defer rr.Body.Close() - - // true if the response is >= 200 and < 300 - return rr.StatusCode/100 == 2 //nolint:mnd + // a well-formed absolute URL is a valid URI; remote reachability is not checked here (see above). + return true } if !r.HasFileScheme && !r.HasFullFilePath && !r.HasURLPathOnly { diff --git a/ref_test.go b/ref_test.go index 8973af20..0ed9b0ef 100644 --- a/ref_test.go +++ b/ref_test.go @@ -7,7 +7,10 @@ import ( "bytes" "encoding/gob" "encoding/json" + "os" + "path/filepath" "testing" + "time" "github.com/go-openapi/testify/v2/assert" "github.com/go-openapi/testify/v2/require" @@ -31,3 +34,57 @@ func TestCloneRef(t *testing.T) { assert.JSONEqT(t, `{"$ref":"#/definitions/test"}`, string(jazon)) } + +func TestRef_IsValidURI(t *testing.T) { + t.Run("empty and fragment-only refs are valid", func(t *testing.T) { + empty := MustCreateRef("") + assert.TrueT(t, empty.IsValidURI()) + + frag := MustCreateRef("#/definitions/Foo") + assert.TrueT(t, frag.IsValidURI()) + }) + + t.Run("absolute URLs are valid without any network request", func(t *testing.T) { + // A well-formed absolute URL is a valid URI. IsValidURI must NOT reach out to the network: + // no timeout to tune, no goroutine to leak, no SSRF against internal addresses. + // 192.0.2.0/24 is TEST-NET-1 (RFC 5737): guaranteed non-routable, so a real GET would + // stall on connect. We assert the call returns true promptly to guard against a + // reintroduced network probe. + for _, uri := range []string{ + "http://192.0.2.1/schema.json", // unreachable public address + "http://127.0.0.1:1/internal", // internal address (SSRF target) + "https://example.com/openapi.json", + } { + ref := MustCreateRef(uri) + require.TrueT(t, ref.HasFullURL) + + done := make(chan bool, 1) + go func() { done <- ref.IsValidURI() }() + + select { + case ok := <-done: + assert.TrueT(t, ok, "expected %q to be a valid URI", uri) + case <-time.After(5 * time.Second): + t.Fatalf("IsValidURI(%q) blocked: it must not perform a network request", uri) + } + } + }) + + t.Run("local file references are checked on disk", func(t *testing.T) { + dir := t.TempDir() + require.NoError(t, os.WriteFile(filepath.Join(dir, "schema.json"), []byte(`{}`), 0o600)) + basePath := filepath.Join(dir, "root.json") // mirrors validate's IsValidURI(specFilePath) + + exists := MustCreateRef("schema.json") + assert.TrueT(t, exists.IsValidURI(basePath), + "an existing local file should be a valid URI") + + missing := MustCreateRef("does-not-exist.json") + assert.FalseT(t, missing.IsValidURI(basePath), + "a missing local file should be an invalid URI") + + asDir := MustCreateRef(".") + assert.FalseT(t, asDir.IsValidURI(basePath), + "a directory should not be a valid file URI") + }) +} From 7229152b356c3cb6c7bf380b4be43412ff5c8d28 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 20 Jul 2026 14:36:21 +0200 Subject: [PATCH 48/54] docs(security): warn that the default $ref loader is not sandboxed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expanding or resolving a specification loads referenced documents through a pluggable loader that, by default, is unconfined. A "$ref" in an untrusted spec can therefore read local files ("file:///etc/passwd", "../../secret.json" — arbitrary file read / path traversal) or reach internal addresses via a remote "$ref" (SSRF). This is inherent to the default configuration; it is not fixed by a code change but by using a confined loader. The mitigation already exists: inject an option-aware loader via ExpandOptions.PathLoaderWithOptions built with go-openapi/swag/loading options (loading.WithRoot to confine local reads, loading.WithHTTPClient to restrict remote fetches), or — recommended — use the restricted loaders from go-openapi/loads (SpecRestricted / SetRestrictedLoaders), which confine local reads and reject loopback/private/link-local remote addresses, and whose confinement applies to every "$ref" resolved during expansion. Document this in a package-level "Security" section and add pointers to it from ExpandSpec, ExpandSchemaWithBasePath and ExpandOptions. Also cross-reference ExpandOptions.MaxExpansionNodes for the related $ref amplification vector. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Frederic BIDON --- doc.go | 29 +++++++++++++++++++++++++++++ expander.go | 11 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/doc.go b/doc.go index 04eea357..8b589781 100644 --- a/doc.go +++ b/doc.go @@ -4,4 +4,33 @@ // Package spec exposes an object model for OpenAPIv2 specifications (swagger). // // The exposed data structures know how to serialize to and deserialize from JSON. +// +// # Security +// +// Resolving and expanding "$ref" pointers loads documents through a pluggable loader (see +// [ExpandOptions.PathLoader] and [ExpandOptions.PathLoaderWithOptions]). By default, that +// loader is NOT sandboxed, so a specification obtained from an untrusted source can abuse it: +// +// - A local "$ref" such as "file:///etc/passwd" or a relative "../../secret.json" is read +// straight off disk. A malicious specification can therefore read any file the process can +// access (arbitrary file read / path traversal, CWE-22). +// - A remote "$ref" such as "http://169.254.169.254/..." is fetched with no restriction. A +// malicious specification can therefore probe or reach internal addresses (SSRF, CWE-918). +// +// Do NOT expand or resolve an untrusted specification with the default options. To process +// untrusted specifications safely, inject a confined loader: +// +// - Recommended: use the restricted loaders from github.com/go-openapi/loads, for example +// loads.SpecRestricted(path, root) or loads.SetRestrictedLoaders(root). They confine local +// reads to root and route remote fetches through a client that rejects loopback, private and +// link-local addresses, and the confinement applies to every "$ref" resolved during +// expansion. +// - Or directly: set [ExpandOptions.PathLoaderWithOptions] to a loader built with +// github.com/go-openapi/swag/loading options such as loading.WithRoot (to confine local +// reads to a directory) and loading.WithHTTPClient (to restrict remote fetches). A "$ref" +// that resolves outside root is then rejected, including one reached through a "file://" +// URI or a "../" traversal. +// +// Expanding an untrusted specification also has a resource-exhaustion vector ("$ref" +// amplification); see [ExpandOptions.MaxExpansionNodes], which is bounded by default. package spec diff --git a/expander.go b/expander.go index 767623b9..037c5a48 100644 --- a/expander.go +++ b/expander.go @@ -35,6 +35,9 @@ const DefaultMaxExpansionNodes = 500_000 // PathLoaderWithOptions is an alternative document loader that accepts [loading.Option] values, matching the // signature used by the go-openapi/swag/loading and go-openapi/loads loaders. When set, it takes precedence over // PathLoader. This lets a caller inject an options-aware (e.g. path-confined) loader without an adapter closure. +// +// Security: the default loader is not sandboxed. When expanding an untrusted specification, inject a confined +// loader (for example one built with loading.WithRoot) — see the package "Security" section. type ExpandOptions struct { RelativeBase string // the path to the root document to expand. This is a file, not a directory SkipSchemas bool // do not expand schemas, just paths, parameters and responses @@ -95,6 +98,10 @@ func optionsOrDefault(opts *ExpandOptions) *ExpandOptions { } // ExpandSpec expands the references in a swagger spec. +// +// Security: with default options the document loader is not sandboxed, so a "$ref" in an +// untrusted spec can read local files or reach internal addresses. See the package "Security" +// section before expanding untrusted input. func ExpandSpec(spec *Swagger, options *ExpandOptions) error { options = optionsOrDefault(options) resolver := defaultSchemaLoader(spec, options, nil, nil) @@ -196,6 +203,10 @@ func ExpandSchema(schema *Schema, root any, cache ResolutionCache) error { // ExpandSchemaWithBasePath expands the refs in the schema object, base path configured through expand options. // // Setting the cache is optional and this parameter may safely be left to nil. +// +// Security: with default options the document loader is not sandboxed, so a "$ref" in an +// untrusted schema can read local files or reach internal addresses. See the package "Security" +// section before expanding untrusted input. func ExpandSchemaWithBasePath(schema *Schema, cache ResolutionCache, opts *ExpandOptions) error { if schema == nil { return nil From 75e485906faa6538f86b99e673ec8d47f43a9d45 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 20 Jul 2026 16:02:43 +0200 Subject: [PATCH 49/54] build(deps): bump swag/loading to v0.27.2 for confined $ref loading swag/loading v0.27.2 makes loading.WithRoot resolve absolute in-root paths (rebasing them onto the root) instead of rejecting every absolute path. Because spec normalizes every $ref to an absolute path against the spec's base, this is what makes a WithRoot-confined loader usable to safely expand an untrusted spec: legitimate in-root references resolve, while file:// and ../ references that escape the root are rejected. Add a consumer-side test that expands an untrusted spec through a PathLoaderWithOptions loader bound to loading.WithRoot, with an absolute RelativeBase: it asserts the in-root reference expands, the escaping references stay unexpanded, and no byte of the out-of-root file leaks into the result. go mod tidy also drops the now-unused swag/jsonname dependency. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Frederic BIDON --- expander_confine_test.go | 87 ++++++++++++++++++++++++++++++++++++++++ go.mod | 13 +++--- go.sum | 45 +++++++-------------- 3 files changed, 107 insertions(+), 38 deletions(-) create mode 100644 expander_confine_test.go diff --git a/expander_confine_test.go b/expander_confine_test.go new file mode 100644 index 00000000..dc16d313 --- /dev/null +++ b/expander_confine_test.go @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package spec + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/go-openapi/swag/loading" + "github.com/go-openapi/testify/v2/assert" + "github.com/go-openapi/testify/v2/require" +) + +// TestExpand_ConfinedLoader validates end to end that a WithRoot-confined loader, injected +// through PathLoaderWithOptions, safely expands an untrusted spec: +// - a legitimate $ref that resolves within the root is expanded (this requires the loader to +// accept the absolute paths spec normalizes references to); +// - a "file://" $ref and a "../" traversal $ref that point outside the root are blocked, and +// no byte of the out-of-root file leaks into the result. +// +// It exercises the go-openapi/swag/loading WithRoot behavior from the consumer side, with an +// absolute RelativeBase (the realistic case). +func TestExpand_ConfinedLoader(t *testing.T) { + const secretMarker = "TOP_SECRET" + + root := t.TempDir() + outside := t.TempDir() + + require.NoError(t, os.WriteFile(filepath.Join(root, "child.json"), + []byte(`{"definitions":{"Thing":{"type":"string","title":"IN_ROOT"}}}`), 0o600)) + require.NoError(t, os.WriteFile(filepath.Join(outside, "secret.json"), + []byte(`{"leaked":"`+secretMarker+`"}`), 0o600)) + + secretAbs := filepath.Join(outside, "secret.json") + // a relative traversal, from the spec's base dir (root), that reaches the outside secret + traversal, err := filepath.Rel(root, secretAbs) + require.NoError(t, err) + require.True(t, strings.HasPrefix(traversal, ".."), "sanity: traversal must escape the root") + + raw := `{ + "swagger":"2.0","info":{"title":"x","version":"1"},"paths":{}, + "definitions":{ + "Local": {"$ref":"child.json#/definitions/Thing"}, + "SecretFile":{"$ref":"file://` + filepath.ToSlash(secretAbs) + `"}, + "Traversal": {"$ref":"` + filepath.ToSlash(traversal) + `"} + } + }` + var sw Swagger + require.NoError(t, json.Unmarshal([]byte(raw), &sw)) + + confined := func(pth string, _ ...loading.Option) (json.RawMessage, error) { + b, err := loading.LoadFromFileOrHTTP(pth, loading.WithRoot(root)) + return json.RawMessage(b), err + } + + // absolute base, as a real consumer would pass + err = ExpandSpec(&sw, &ExpandOptions{ + RelativeBase: filepath.Join(root, "api.json"), + PathLoaderWithOptions: confined, + ContinueOnError: true, // do not abort on the blocked refs; expand what is legitimate + }) + require.NoError(t, err) + + dump := func(name string) string { + out, err := json.Marshal(sw.Definitions[name]) + require.NoError(t, err) + return string(out) + } + + // 1) the legitimate in-root ref resolved (the WithRoot fix: absolute in-root paths are accepted) + local := dump("Local") + assert.StringContainsT(t, local, "IN_ROOT") + assert.StringNotContainsT(t, local, `"$ref"`) + + // 2) the escaping refs were blocked: they remain unexpanded and leak nothing + assert.StringContainsT(t, dump("SecretFile"), `"$ref"`) + assert.StringContainsT(t, dump("Traversal"), `"$ref"`) + + // 3) the secret never appears anywhere in the expanded document + whole, err := json.Marshal(&sw) + require.NoError(t, err) + assert.StringNotContainsT(t, string(whole), secretMarker) +} diff --git a/go.mod b/go.mod index 59fccf18..c88cbbba 100644 --- a/go.mod +++ b/go.mod @@ -3,19 +3,18 @@ module github.com/go-openapi/spec require ( github.com/go-openapi/jsonpointer v1.0.0 github.com/go-openapi/jsonreference v1.0.0 - github.com/go-openapi/swag/conv v0.27.1 - github.com/go-openapi/swag/jsonname v0.27.1 - github.com/go-openapi/swag/jsonutils v0.27.1 - github.com/go-openapi/swag/loading v0.27.1 + github.com/go-openapi/swag/conv v0.27.2 + github.com/go-openapi/swag/jsonutils v0.27.2 + github.com/go-openapi/swag/loading v0.27.2 github.com/go-openapi/swag/stringutils v0.27.1 github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 github.com/go-openapi/testify/v2 v2.6.0 ) require ( - github.com/go-openapi/swag/pools v0.27.1 // indirect - github.com/go-openapi/swag/typeutils v0.27.1 // indirect - github.com/go-openapi/swag/yamlutils v0.27.1 // indirect + github.com/go-openapi/swag/pools v0.27.2 // indirect + github.com/go-openapi/swag/typeutils v0.27.2 // indirect + github.com/go-openapi/swag/yamlutils v0.27.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect ) diff --git a/go.sum b/go.sum index 034a6a85..18dd9f96 100644 --- a/go.sum +++ b/go.sum @@ -2,39 +2,22 @@ github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxg github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY= github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= -github.com/go-openapi/swag/conv v0.27.0 h1:EKOH4feXrvdo8DbSsXSAqRT8fz1epEnS5O2IfXUOzE8= -github.com/go-openapi/swag/conv v0.27.0/go.mod h1:pfiv0uKQTbaGApk8Zs/lZV3uSjmSpa2FO1y183YngN8= -github.com/go-openapi/swag/conv v0.27.1 h1:8wi9ZG+olmY1wXphl93EWniPtbSPkXM/feH7FgjsvrU= -github.com/go-openapi/swag/conv v0.27.1/go.mod h1:QbqMivkpKhC3g1B1GGGOJ6ANewI3S62dbzYu3Duowqs= -github.com/go-openapi/swag/jsonname v0.27.0 h1:4QVB//CKOdE8IOiBg19JNY2wfDS48MhesIquYBy2rUE= -github.com/go-openapi/swag/jsonname v0.27.0/go.mod h1:I1YsyvvhBuZsFXSW6I7ODfdyq13p7hDil//1T9/pFFk= -github.com/go-openapi/swag/jsonname v0.27.1 h1:Rrba0m4IgkENyxnIOBZGl0zQEjt6pfGy4SRmZnwVeoA= -github.com/go-openapi/swag/jsonname v0.27.1/go.mod h1:rtHNjjwBhdavc6eybmd5Fj60cIgstqQHcToaK/+4WwQ= -github.com/go-openapi/swag/jsonutils v0.27.0 h1:VYtd9jEQYeU4j8q5vdn5KWotF4vKywhGdMBrALtAsfE= -github.com/go-openapi/swag/jsonutils v0.27.0/go.mod h1:U7pb8AGuwhok3RDicHeHwSG4L3PXSq6PAL98Aon632g= -github.com/go-openapi/swag/jsonutils v0.27.1 h1:SVgK3i4USzCU5mibOOS/l4ea2h9UQXy7J7RNLTjuXjU= -github.com/go-openapi/swag/jsonutils v0.27.1/go.mod h1:tdlEpZqdcQ17uj6J4YdK9vd8It5qWMwjWXOs0tjpRlk= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0 h1:+d7C7Ur/SsGg/UZ9G0JEovnfRqtMNZCJQGKc2h/ojoE= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.0/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1 h1:mJu3COL9WEaZVp/Kf2PRMi7tPszPEJfSr/OO75ynCs8= -github.com/go-openapi/swag/loading v0.27.0 h1:s8DA9aPEdFH6OluHUYUn3DnIuoTdyWs9RwffXBUfyeI= -github.com/go-openapi/swag/loading v0.27.0/go.mod h1:VOz+Jg6UGGywcmRvYsI4fvtp+bd7NfioseGEPleYdA4= -github.com/go-openapi/swag/loading v0.27.1 h1:/DxUgDXKbBX4bcn7r9uEXfJyzN5XpiJmZplzQTjrRCY= -github.com/go-openapi/swag/loading v0.27.1/go.mod h1:jvGh3iA2+zyUUycB5fgJWzeHnhrpvGnJJM0RVE9ZShE= -github.com/go-openapi/swag/pools v0.27.1 h1:9LeadcMyb2GJCbXX5hVQDbZ2Lq9TL4dCs/nx1j5DO0E= -github.com/go-openapi/swag/pools v0.27.1/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= -github.com/go-openapi/swag/stringutils v0.27.0 h1:Of7w/HljWsNZvuxsUAnw3n+hCOyI6HLJOxW2kQRAxio= -github.com/go-openapi/swag/stringutils v0.27.0/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= +github.com/go-openapi/swag/conv v0.27.2 h1:aQDEuHUiPS3s4AeC3piAmUEeki92VSm8Wpa7MvLSMfo= +github.com/go-openapi/swag/conv v0.27.2/go.mod h1:FRnnoRFF20lGKJN+4zQ3aO41RrmbamqQXEbSrx9A08E= +github.com/go-openapi/swag/jsonutils v0.27.2 h1:25EPxb6Rl8a9r0MwTS82Cf2g34WhG/liS/v3K5AiMrg= +github.com/go-openapi/swag/jsonutils v0.27.2/go.mod h1:spkGpzfeSNKFEfjDyeliEhGVzk/rj8dXsyDhwSr68no= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.2 h1:3sV+i46ZOOHcvInpRJdJmvQ2m0KuiJlRwKes4ogcyM8= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.2/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= +github.com/go-openapi/swag/loading v0.27.2 h1:mV6jOX263NkNcLlFetI0PXunOflB3egUsKwBqrDPD1A= +github.com/go-openapi/swag/loading v0.27.2/go.mod h1:iiIENIWQNC9RTaHnThz8FmxSLs9lLsXcWH5BzrnRqUU= +github.com/go-openapi/swag/pools v0.27.2 h1:AvoQizOICyuFXsfn5HOCelxZxZ2DQq/XwTlHKLj/EFo= +github.com/go-openapi/swag/pools v0.27.2/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= github.com/go-openapi/swag/stringutils v0.27.1 h1:ZXePZ0r2p1qSjo8tD3Un4vFj8+FqlCkczxDrJIhYUp8= github.com/go-openapi/swag/stringutils v0.27.1/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= -github.com/go-openapi/swag/typeutils v0.27.0 h1:aCf4MSGo8NLwZP8Q6t32DWLJSvl/WwNqgmEG+xJ6v2o= -github.com/go-openapi/swag/typeutils v0.27.0/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= -github.com/go-openapi/swag/typeutils v0.27.1 h1:KSTdFlfnse4r6dP9IrEnwMldjE+zs71UeEB3//PtVXc= -github.com/go-openapi/swag/typeutils v0.27.1/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= -github.com/go-openapi/swag/yamlutils v0.27.0 h1:bQ6eAMil5X9tdcf7dMn4t15alzG6jddnrKPuKa/zxKM= -github.com/go-openapi/swag/yamlutils v0.27.0/go.mod h1:yRfIo7qqVkmJRQjX8exjA3AfcI8rH1KDNPsTparoCv4= -github.com/go-openapi/swag/yamlutils v0.27.1 h1:ftxv6xvXb1E3zohUc+okZ9nSqNb9StQX/FXnKZ98sQA= -github.com/go-openapi/swag/yamlutils v0.27.1/go.mod h1:bnxFIB1qewGRiZHypXGZ3fNgf13/0HfRgnS/iZBDrOo= +github.com/go-openapi/swag/typeutils v0.27.2 h1:0KXmflQjTsPUxUzh8uZGrf8m9Kr/sX1F8tajc8Consg= +github.com/go-openapi/swag/typeutils v0.27.2/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= +github.com/go-openapi/swag/yamlutils v0.27.2 h1:iIF+8/igydokZzzw+SfSe0RWJSvSW666LJYxBUqrX08= +github.com/go-openapi/swag/yamlutils v0.27.2/go.mod h1:Qmxd+FGj63w9DRvDjNDKX/uCifxUfR5rYZs9iFu2SC4= github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= From fe9f8bd892dc1da5293a701d56717c324a0a2380 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 20 Jul 2026 16:16:08 +0200 Subject: [PATCH 50/54] test(expander): validate the SSRF posture of an injected loader Expanding a spec with the default loader fetches any remote "$ref" through http.DefaultClient with no address filtering, so a "$ref" to a cloud metadata endpoint (e.g. AWS IMDS at 169.254.169.254), a private address, or localhost is an SSRF vector. This is documented in the package "Security" section; the mitigation is to inject an option-aware loader bound to a restricted HTTP client via ExpandOptions.PathLoaderWithOptions (or use the restricted loaders from go-openapi/loads). Add a regression test proving that posture end to end: a loader bound to a client whose DialContext refuses loopback/private/link-local/unspecified addresses causes ExpandSpec to refuse the IMDS reference at dial time, before any connection is made. The loader selection is shared by every expansion and resolution entry point, so this covers ExpandSpec, ExpandSchemaWithBasePath, ExpandResponse, ExpandParameter and the Resolve* functions. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Frederic BIDON --- expander_ssrf_test.go | 79 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 expander_ssrf_test.go diff --git a/expander_ssrf_test.go b/expander_ssrf_test.go new file mode 100644 index 00000000..8d97af3b --- /dev/null +++ b/expander_ssrf_test.go @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers +// SPDX-License-Identifier: Apache-2.0 + +package spec + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net" + "net/http" + "net/netip" + "testing" + "time" + + "github.com/go-openapi/swag/loading" + "github.com/go-openapi/testify/v2/require" +) + +var errBlockedAddress = errors.New("blocked non-public address") + +// restrictedDialContext refuses to dial loopback, private, link-local or unspecified addresses. +// This mirrors the SSRF guard a caller injects via loading.WithHTTPClient (and that +// go-openapi/loads ships as RestrictedHTTPClient). +func restrictedDialContext(_ context.Context, _, addr string) (net.Conn, error) { + host, _, err := net.SplitHostPort(addr) + if err != nil { + host = addr + } + + ip, err := netip.ParseAddr(host) + if err != nil { + // a hostname would need resolution then a re-check; this test only uses IP literals. + return nil, fmt.Errorf("%w: %s", errBlockedAddress, addr) + } + + ip = ip.Unmap() + if ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() || ip.IsUnspecified() { + return nil, fmt.Errorf("%w: %s", errBlockedAddress, addr) + } + + return nil, fmt.Errorf("%w: %s (test performs no real dial)", errBlockedAddress, addr) +} + +// TestExpand_SSRFPosture validates that a caller can neutralize the SSRF vector by injecting an +// option-aware loader bound to a restricted HTTP client through PathLoaderWithOptions: a remote +// "$ref" to a cloud metadata endpoint is refused at dial time, before any connection is made. +// +// The loader selection is shared by every expansion/resolution entry point, so blocking it here +// blocks it for ExpandSpec, ExpandSchemaWithBasePath, ExpandResponse, ExpandParameter and the +// Resolve* functions alike. +func TestExpand_SSRFPosture(t *testing.T) { + client := &http.Client{ + Timeout: 5 * time.Second, + Transport: &http.Transport{DialContext: restrictedDialContext}, + } + loader := func(pth string, _ ...loading.Option) (json.RawMessage, error) { + b, err := loading.LoadFromFileOrHTTP(pth, loading.WithHTTPClient(client)) + return json.RawMessage(b), err + } + + // AWS IMDS endpoint, exactly as in the report's PoC + raw := `{ + "swagger":"2.0","info":{"title":"x","version":"1"},"paths":{}, + "definitions":{ + "Victim":{"$ref":"http://169.254.169.254/latest/meta-data/iam/security-credentials/role"} + } + }` + var sw Swagger + require.NoError(t, json.Unmarshal([]byte(raw), &sw)) + + err := ExpandSpec(&sw, &ExpandOptions{PathLoaderWithOptions: loader}) + + // the metadata endpoint was refused at dial time: the fetch never happened + require.Error(t, err) + require.ErrorIs(t, err, errBlockedAddress) + require.ErrorContains(t, err, "169.254.169.254") +} From 497d5838d347a678350223bc3201eb694428b98b Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 20 Jul 2026 17:03:58 +0200 Subject: [PATCH 51/54] build(deps): bump swag modules to v0.27.3 Supersedes the v0.27.2 bump. swag/loading v0.27.3 fixes WithRoot on Windows: spec normalizes references to a file-URL path form ("/C:/dir/file"), which v0.27.2 did not recognize as absolute, so os.Root rejected legitimate in-root targets and TestExpand_ConfinedLoader failed on Windows CI. v0.27.3 normalizes that form before confinement, so a WithRoot-confined loader resolves in-root references on Windows too, while still rejecting file:// and ../ escapes. All go-openapi/swag submodules are moved to v0.27.3 together (stringutils, which had no v0.27.2 tag, is included). No spec code change is required. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Frederic BIDON --- go.mod | 14 +++++++------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index c88cbbba..87e8f292 100644 --- a/go.mod +++ b/go.mod @@ -3,18 +3,18 @@ module github.com/go-openapi/spec require ( github.com/go-openapi/jsonpointer v1.0.0 github.com/go-openapi/jsonreference v1.0.0 - github.com/go-openapi/swag/conv v0.27.2 - github.com/go-openapi/swag/jsonutils v0.27.2 - github.com/go-openapi/swag/loading v0.27.2 - github.com/go-openapi/swag/stringutils v0.27.1 + github.com/go-openapi/swag/conv v0.27.3 + github.com/go-openapi/swag/jsonutils v0.27.3 + github.com/go-openapi/swag/loading v0.27.3 + github.com/go-openapi/swag/stringutils v0.27.3 github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 github.com/go-openapi/testify/v2 v2.6.0 ) require ( - github.com/go-openapi/swag/pools v0.27.2 // indirect - github.com/go-openapi/swag/typeutils v0.27.2 // indirect - github.com/go-openapi/swag/yamlutils v0.27.2 // indirect + github.com/go-openapi/swag/pools v0.27.3 // indirect + github.com/go-openapi/swag/typeutils v0.27.3 // indirect + github.com/go-openapi/swag/yamlutils v0.27.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect ) diff --git a/go.sum b/go.sum index 18dd9f96..3c17049d 100644 --- a/go.sum +++ b/go.sum @@ -2,22 +2,22 @@ github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxg github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y= github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY= github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0= -github.com/go-openapi/swag/conv v0.27.2 h1:aQDEuHUiPS3s4AeC3piAmUEeki92VSm8Wpa7MvLSMfo= -github.com/go-openapi/swag/conv v0.27.2/go.mod h1:FRnnoRFF20lGKJN+4zQ3aO41RrmbamqQXEbSrx9A08E= -github.com/go-openapi/swag/jsonutils v0.27.2 h1:25EPxb6Rl8a9r0MwTS82Cf2g34WhG/liS/v3K5AiMrg= -github.com/go-openapi/swag/jsonutils v0.27.2/go.mod h1:spkGpzfeSNKFEfjDyeliEhGVzk/rj8dXsyDhwSr68no= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.2 h1:3sV+i46ZOOHcvInpRJdJmvQ2m0KuiJlRwKes4ogcyM8= -github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.2/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= -github.com/go-openapi/swag/loading v0.27.2 h1:mV6jOX263NkNcLlFetI0PXunOflB3egUsKwBqrDPD1A= -github.com/go-openapi/swag/loading v0.27.2/go.mod h1:iiIENIWQNC9RTaHnThz8FmxSLs9lLsXcWH5BzrnRqUU= -github.com/go-openapi/swag/pools v0.27.2 h1:AvoQizOICyuFXsfn5HOCelxZxZ2DQq/XwTlHKLj/EFo= -github.com/go-openapi/swag/pools v0.27.2/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= -github.com/go-openapi/swag/stringutils v0.27.1 h1:ZXePZ0r2p1qSjo8tD3Un4vFj8+FqlCkczxDrJIhYUp8= -github.com/go-openapi/swag/stringutils v0.27.1/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= -github.com/go-openapi/swag/typeutils v0.27.2 h1:0KXmflQjTsPUxUzh8uZGrf8m9Kr/sX1F8tajc8Consg= -github.com/go-openapi/swag/typeutils v0.27.2/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= -github.com/go-openapi/swag/yamlutils v0.27.2 h1:iIF+8/igydokZzzw+SfSe0RWJSvSW666LJYxBUqrX08= -github.com/go-openapi/swag/yamlutils v0.27.2/go.mod h1:Qmxd+FGj63w9DRvDjNDKX/uCifxUfR5rYZs9iFu2SC4= +github.com/go-openapi/swag/conv v0.27.3 h1:iqJFmGEjmX3AY0lSszABFqRVqOSt99XS0LzNIMJYuhU= +github.com/go-openapi/swag/conv v0.27.3/go.mod h1:nPRmN6jgNme99hpf+nM0auDZGALWIqlwhisKPK/bQhQ= +github.com/go-openapi/swag/jsonutils v0.27.3 h1:1DEz+O82frtSMBcos/7XIn1GnpNTbsD4Bru4Dc/uhRc= +github.com/go-openapi/swag/jsonutils v0.27.3/go.mod h1:qiDCoQvzkMxrV3G8FLEdIU5L+EFYc0zcDOHWT3Yofvo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.3 h1:h/eT9kmGCDdFLJF29lOhzLtF0FmP1AX2MhLJWVebsb8= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.3/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY= +github.com/go-openapi/swag/loading v0.27.3 h1:L9nQkEgzU7QgFQL+pLEMfGUKxeM4pWwGwbET9Z3weW0= +github.com/go-openapi/swag/loading v0.27.3/go.mod h1:rJ0NeaKsF4CVPnMGjPQl7JlSHzvD0bc2DKXLss1hiuE= +github.com/go-openapi/swag/pools v0.27.3 h1:gXjImP3F6/56wRRcFgEPld084Y6u2gs21ikPBt8NKBk= +github.com/go-openapi/swag/pools v0.27.3/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE= +github.com/go-openapi/swag/stringutils v0.27.3 h1:Ru28hnbAvN5wycALQYy8IobHvASq+FUFMlp1QzLM0JI= +github.com/go-openapi/swag/stringutils v0.27.3/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM= +github.com/go-openapi/swag/typeutils v0.27.3 h1:l6SSrx5eR5/WVwrGNzN6bQ9WqL04mrxNBl9YgQ3rcJ4= +github.com/go-openapi/swag/typeutils v0.27.3/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ= +github.com/go-openapi/swag/yamlutils v0.27.3 h1:cRFCAoYtslYn9L9T0xWryHy1t7c1MACC+DMj3CLvwvs= +github.com/go-openapi/swag/yamlutils v0.27.3/go.mod h1:6JYBGj8sw/NawMllyZY+cTA8Mzk2etS3ZBASdcyPsiU= github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0= github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo= github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug= From 9bfe73252e15c63384a5924ca452f8c624ddc2eb Mon Sep 17 00:00:00 2001 From: fredbi Date: Mon, 20 Jul 2026 19:22:40 +0200 Subject: [PATCH 52/54] feat(expander): add ExpandSchemaWithOptions for confined schema expansion (#291) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ExpandSchema expands a schema against an in-memory root but takes no ExpandOptions, so it always uses the package default (unsandboxed) document loader. Downstream consumers that expand a schema whose $ref may come from an untrusted source — go-openapi/analysis (schema analysis, flatten) and go-openapi/validate — had no way to inject a confined loader on this path, and could not reassemble the equivalent themselves because the root-to-base priming (baseForRoot / normalizeBase) is unexported. Add ExpandSchemaWithOptions(schema, root, cache, opts): the option-aware form of ExpandSchema. It preserves the in-memory-root behavior (base derived from root, schemas always expanded) while honoring the caller's options — in particular PathLoaderWithOptions / PathLoader for a confined loader, plus ContinueOnError, AbsoluteCircularRef and MaxExpansionNodes. ExpandSchema is reimplemented as ExpandSchemaWithOptions(schema, root, cache, nil), so its behavior is unchanged. Signed-off-by: Frederic BIDON Co-authored-by: Claude Opus 4.8 (1M context) --- expander.go | 33 +++++++++++++++++++++++++++------ expander_loader_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/expander.go b/expander.go index 037c5a48..9edbe9a5 100644 --- a/expander.go +++ b/expander.go @@ -184,20 +184,41 @@ func baseForRoot(root any, cache ResolutionCache) string { // (use ExpandSchemaWithBasePath to resolve external references). // // Setting the cache is optional and this parameter may safely be left to nil. +// +// ExpandSchema uses the package default document loader, which is not sandboxed. To expand a +// schema whose $ref may derive from untrusted input, use [ExpandSchemaWithOptions] with a confined +// loader — see the package "Security" section. func ExpandSchema(schema *Schema, root any, cache ResolutionCache) error { + return ExpandSchemaWithOptions(schema, root, cache, nil) +} + +// ExpandSchemaWithOptions expands the refs in the schema object with reference to the root object, +// honoring the provided expand options. It is the option-aware form of [ExpandSchema]. +// +// In particular, set opts.PathLoaderWithOptions (or opts.PathLoader) to inject a confined document +// loader when expanding a schema whose $ref may derive from an untrusted source (see the package +// "Security" section). opts.ContinueOnError, opts.AbsoluteCircularRef and opts.MaxExpansionNodes +// are honored as well. +// +// The base path is always derived from root (as with [ExpandSchema]), so opts.RelativeBase and +// opts.SkipSchemas are ignored. Passing nil opts is equivalent to [ExpandSchema]. +// +// Setting the cache is optional and this parameter may safely be left to nil. +func ExpandSchemaWithOptions(schema *Schema, root any, cache ResolutionCache, opts *ExpandOptions) error { cache = cacheOrDefault(cache) if root == nil { root = schema } - opts := &ExpandOptions{ - // when a root is specified, cache the root as an in-memory document for $ref retrieval - RelativeBase: baseForRoot(root, cache), - SkipSchemas: false, - ContinueOnError: false, + effective := ExpandOptions{} + if opts != nil { + effective = *opts // preserve caller options (loader, ContinueOnError, budget, ...) } + // when a root is specified, cache the root as an in-memory document for $ref retrieval + effective.RelativeBase = baseForRoot(root, cache) + effective.SkipSchemas = false - return ExpandSchemaWithBasePath(schema, cache, opts) + return ExpandSchemaWithBasePath(schema, cache, &effective) } // ExpandSchemaWithBasePath expands the refs in the schema object, base path configured through expand options. diff --git a/expander_loader_test.go b/expander_loader_test.go index 9243186b..3d0fc6d0 100644 --- a/expander_loader_test.go +++ b/expander_loader_test.go @@ -18,6 +18,45 @@ import ( // errUnexpectedLoad is returned by a test loader asked to load a path it does not expect. var errUnexpectedLoad = errors.New("unexpected load") +func TestExpandSchemaWithOptions(t *testing.T) { + // A schema whose $ref points into an external document is expanded through the injected + // option-aware loader, exactly as flatten/analysis and validate need for confined expansion. + const external = `{"definitions":{"Thing":{"type":"string"}}}` + + root := map[string]any{"swagger": "2.0", "definitions": map[string]any{}} + schema := RefSchema("external.json#/definitions/Thing") + + var loaderCalls int + err := ExpandSchemaWithOptions(schema, root, nil, &ExpandOptions{ + PathLoaderWithOptions: func(pth string, _ ...loading.Option) (json.RawMessage, error) { + if strings.Contains(pth, "external.json") { + loaderCalls++ + return json.RawMessage(external), nil + } + return nil, fmt.Errorf("%w: %s", errUnexpectedLoad, pth) + }, + }) + require.NoError(t, err) + assert.TrueT(t, loaderCalls > 0, "expected the injected loader to resolve the external $ref") + + out, err := json.Marshal(schema) + require.NoError(t, err) + assert.StringContainsT(t, string(out), `"type":"string"`) + assert.StringNotContainsT(t, string(out), `"$ref"`) + + t.Run("nil options behaves like ExpandSchema (in-memory root, fragment ref)", func(t *testing.T) { + inMemRoot := map[string]any{ + "definitions": map[string]any{"Local": map[string]any{"type": "integer"}}, + } + sch := RefSchema("#/definitions/Local") + require.NoError(t, ExpandSchemaWithOptions(sch, inMemRoot, nil, nil)) + + out, err := json.Marshal(sch) + require.NoError(t, err) + assert.StringContainsT(t, string(out), `"type":"integer"`) + }) +} + func TestPathLoaderSelection(t *testing.T) { t.Run("option-aware loader is used when set", func(t *testing.T) { var called string From e682f665cd0b25eee1bcc3ec42d939d7b037a1f1 Mon Sep 17 00:00:00 2001 From: fredbi Date: Mon, 20 Jul 2026 21:48:20 +0200 Subject: [PATCH 53/54] feat(expander): add ExpandParameterWithOptions and ExpandResponseWithOptions (#292) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ExpandParameter/ExpandParameterWithRoot and ExpandResponse/ExpandResponseWithRoot expand a parameter or response but take no ExpandOptions, so they always use the package default (unsandboxed) document loader — the same gap that motivated ExpandSchemaWithOptions. go-openapi/validate expands every parameter and response $ref of a spec through these functions, so a $ref from an untrusted source could not be confined there. Add ExpandParameterWithOptions(parameter, root, cache, opts) and ExpandResponseWithOptions(response, root, cache, opts): the option-aware forms. When root is non-nil, refs resolve against the in-memory root (base derived from root); otherwise they resolve relative to opts.RelativeBase. In particular opts.PathLoaderWithOptions / PathLoader inject a confined loader. The four existing functions are reimplemented in terms of the new ones, so their behavior is unchanged. Signed-off-by: Frederic BIDON Co-authored-by: Claude Opus 4.8 (1M context) --- expander.go | 70 ++++++++++++++++++++++++++--------------- expander_loader_test.go | 37 ++++++++++++++++++++++ 2 files changed, 82 insertions(+), 25 deletions(-) diff --git a/expander.go b/expander.go index 9edbe9a5..00eb5b53 100644 --- a/expander.go +++ b/expander.go @@ -546,25 +546,28 @@ func expandOperation(op *Operation, resolver *schemaLoader, basePath string) err // // Setting the cache is optional and this parameter may safely be left to nil. func ExpandResponseWithRoot(response *Response, root any, cache ResolutionCache) error { - cache = cacheOrDefault(cache) - opts := &ExpandOptions{ - RelativeBase: baseForRoot(root, cache), - } - resolver := defaultSchemaLoader(root, opts, cache, nil) - - return expandParameterOrResponse(response, resolver, opts.RelativeBase) + return ExpandResponseWithOptions(response, root, cache, nil) } // ExpandResponse expands a response based on a basepath // // All refs inside response will be resolved relative to basePath. func ExpandResponse(response *Response, basePath string) error { - opts := optionsOrDefault(&ExpandOptions{ - RelativeBase: basePath, - }) - resolver := defaultSchemaLoader(nil, opts, nil, nil) + return ExpandResponseWithOptions(response, nil, nil, &ExpandOptions{RelativeBase: basePath}) +} - return expandParameterOrResponse(response, resolver, opts.RelativeBase) +// ExpandResponseWithOptions expands a response, honoring the provided expand options. +// +// It is the option-aware form of [ExpandResponse] and [ExpandResponseWithRoot]. When root is +// non-nil, refs resolve against the in-memory root document; otherwise they resolve relative to +// opts.RelativeBase. +// +// Set opts.PathLoaderWithOptions (or opts.PathLoader) to inject a confined document loader when +// the response's $ref may derive from an untrusted source — see the package "Security" section. +// +// Setting the cache is optional and this parameter may safely be left to nil. +func ExpandResponseWithOptions(response *Response, root any, cache ResolutionCache, opts *ExpandOptions) error { + return expandRefableWithOptions(response, root, cache, opts) } // ExpandParameterWithRoot expands a parameter based on a root document, not a fetchable document. @@ -572,26 +575,43 @@ func ExpandResponse(response *Response, basePath string) error { // Notice that it is impossible to reference a json schema in a different document other than root // (use ExpandParameter to resolve external references). func ExpandParameterWithRoot(parameter *Parameter, root any, cache ResolutionCache) error { - cache = cacheOrDefault(cache) - - opts := &ExpandOptions{ - RelativeBase: baseForRoot(root, cache), - } - resolver := defaultSchemaLoader(root, opts, cache, nil) - - return expandParameterOrResponse(parameter, resolver, opts.RelativeBase) + return ExpandParameterWithOptions(parameter, root, cache, nil) } // ExpandParameter expands a parameter based on a basepath. // This is the exported version of expandParameter // all refs inside parameter will be resolved relative to basePath. func ExpandParameter(parameter *Parameter, basePath string) error { - opts := optionsOrDefault(&ExpandOptions{ - RelativeBase: basePath, - }) - resolver := defaultSchemaLoader(nil, opts, nil, nil) + return ExpandParameterWithOptions(parameter, nil, nil, &ExpandOptions{RelativeBase: basePath}) +} + +// ExpandParameterWithOptions expands a parameter, honoring the provided expand options. +// +// It is the option-aware form of [ExpandParameter] and [ExpandParameterWithRoot]. When root is +// non-nil, refs resolve against the in-memory root document; otherwise they resolve relative to +// opts.RelativeBase. +// +// Set opts.PathLoaderWithOptions (or opts.PathLoader) to inject a confined document loader when +// the parameter's $ref may derive from an untrusted source — see the package "Security" section. +// +// Setting the cache is optional and this parameter may safely be left to nil. +func ExpandParameterWithOptions(parameter *Parameter, root any, cache ResolutionCache, opts *ExpandOptions) error { + return expandRefableWithOptions(parameter, root, cache, opts) +} + +// expandRefableWithOptions is the shared implementation for the option-aware parameter/response +// expanders. When root is non-nil, refs resolve against the in-memory root (base derived from +// root); otherwise they resolve relative to opts.RelativeBase. opts carries the loader and other +// expand options. +func expandRefableWithOptions(input any, root any, cache ResolutionCache, opts *ExpandOptions) error { + cache = cacheOrDefault(cache) + effective := optionsOrDefault(opts) // clones and normalizes RelativeBase; preserves the loader + if root != nil { + effective.RelativeBase = baseForRoot(root, cache) + } + resolver := defaultSchemaLoader(root, effective, cache, nil) - return expandParameterOrResponse(parameter, resolver, opts.RelativeBase) + return expandParameterOrResponse(input, resolver, effective.RelativeBase) } func getRefAndSchema(input any) (*Ref, *Schema, error) { diff --git a/expander_loader_test.go b/expander_loader_test.go index 3d0fc6d0..aaaf9ebd 100644 --- a/expander_loader_test.go +++ b/expander_loader_test.go @@ -57,6 +57,43 @@ func TestExpandSchemaWithOptions(t *testing.T) { }) } +func TestExpandParameterResponseWithOptions(t *testing.T) { + // Parameter and response $ref pointing into an external document are expanded through the + // injected option-aware loader — the path go-openapi/validate needs for confined validation. + const external = `{ + "parameters":{"Foo":{"name":"foo","in":"query","type":"string"}}, + "responses":{"Bar":{"description":"ok"}} + }` + + var loaderCalls int + loader := func(pth string, _ ...loading.Option) (json.RawMessage, error) { + if strings.Contains(pth, "external.json") { + loaderCalls++ + return json.RawMessage(external), nil + } + return nil, fmt.Errorf("%w: %s", errUnexpectedLoad, pth) + } + opts := &ExpandOptions{RelativeBase: "spec.json", PathLoaderWithOptions: loader} + + t.Run("parameter", func(t *testing.T) { + param := new(Parameter) + param.Ref = MustCreateRef("external.json#/parameters/Foo") + require.NoError(t, ExpandParameterWithOptions(param, nil, nil, opts)) + assert.EqualT(t, "foo", param.Name) + assert.EqualT(t, "", param.Ref.String()) + }) + + t.Run("response", func(t *testing.T) { + resp := new(Response) + resp.Ref = MustCreateRef("external.json#/responses/Bar") + require.NoError(t, ExpandResponseWithOptions(resp, nil, nil, opts)) + assert.EqualT(t, "ok", resp.Description) + assert.EqualT(t, "", resp.Ref.String()) + }) + + assert.TrueT(t, loaderCalls >= 2, "expected the injected loader to resolve both external $ref") +} + func TestPathLoaderSelection(t *testing.T) { t.Run("option-aware loader is used when set", func(t *testing.T) { var called string From 29d6c85eb49f01588da9c719bd5313ae13e4cb28 Mon Sep 17 00:00:00 2001 From: Alex Demidoff Date: Mon, 3 Aug 2026 10:14:19 +0300 Subject: [PATCH 54/54] Keep extensions data on expand schema Re-applies the Percona patch (extensions declared next to a $ref, such as x-order, are kept on the expanded schema) on top of upstream v0.22.9. The previous fork base predates spec.ExpandSchemaWithOptions and spec.ExpandOptions.PathLoaderWithOptions, which go-openapi/analysis v0.25.5 requires, so consumers of go-openapi/runtime v0.33.0 no longer compile against it. --- expander.go | 10 +++++++++- expander_test.go | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/expander.go b/expander.go index 00eb5b53..11b4ae6e 100644 --- a/expander.go +++ b/expander.go @@ -462,7 +462,15 @@ func expandSchemaRef(target Schema, parentRefs []string, resolver *schemaLoader, basePath = resolver.updateBasePath(transitiveResolver, normalizedBasePath) - return expandSchema(*t, parentRefs, transitiveResolver, basePath) + expanded, err := expandSchema(*t, parentRefs, transitiveResolver, basePath) + if expanded != nil { + // Percona: keep the extensions declared next to the $ref (e.g. x-order) on the expanded schema. + for k, v := range target.Extensions { + expanded.AddExtension(k, v) + } + } + + return expanded, err } func expandPathItem(pathItem *PathItem, resolver *schemaLoader, basePath string) error { diff --git a/expander_test.go b/expander_test.go index f7be753b..40ea3132 100644 --- a/expander_test.go +++ b/expander_test.go @@ -1082,3 +1082,26 @@ func TestExpand_Issue145(t *testing.T) { }) }) } + +// TestExpand_KeepsSiblingExtensions asserts the Percona-specific behavior of keeping the extensions +// declared next to a $ref (e.g. x-order) on the expanded schema. +func TestExpand_KeepsSiblingExtensions(t *testing.T) { + root := new(Swagger) + require.NoError(t, json.Unmarshal([]byte(`{ + "swagger": "2.0", + "definitions": { + "Bar": {"type": "object"}, + "Foo": { + "type": "object", + "properties": { + "bar": {"$ref": "#/definitions/Bar", "x-order": 1} + } + } + } + }`), root)) + + sch := RefSchema("#/definitions/Foo") + require.NoError(t, ExpandSchema(sch, root, nil)) + + assert.Equal(t, 1.0, sch.Properties["bar"].Extensions["x-order"]) +}