vendor: update buildkit to v0.30.0-rc2

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2026-05-11 13:15:00 -07:00
parent 5b40913913
commit cb6566122b
81 changed files with 1037 additions and 791 deletions
+4 -4
View File
@@ -1,5 +1,5 @@
secrets.yml
coverage.out
*.cov
*.out
playground
*.cov
.idea
.env
.mcp.json
+4 -2
View File
@@ -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 <ivan+abuse@flanders.co.nz>. 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 [<http://contributor-covenant.org/version/1/4>][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+45
View File
@@ -0,0 +1,45 @@
Copyright 2015-2025 go-swagger maintainers
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
This software library, github.com/go-openapi/jsonpointer, includes software developed
by the go-swagger and go-openapi maintainers ("go-swagger maintainers").
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this software except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
This software is copied from, derived from, and inspired by other original software products.
It ships with copies of other software which license terms are recalled below.
The original software was authored in 2014 by Naoya Inada <naoina@kuune.org>
https://github.com/naoina/denco
===========================
// SPDX-FileCopyrightText: Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
// SPDX-License-Identifier: MIT
Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+90 -20
View File
@@ -1,31 +1,46 @@
# runtime [![Build Status](https://github.com/go-openapi/runtime/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/runtime/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/runtime/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/runtime)
# runtime
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/runtime/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/runtime.svg)](https://pkg.go.dev/github.com/go-openapi/runtime)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/runtime)](https://goreportcard.com/report/github.com/go-openapi/runtime)
<!-- Badges: status -->
[![Tests][test-badge]][test-url] [![Coverage][cov-badge]][cov-url] [![CI vuln scan][vuln-scan-badge]][vuln-scan-url] [![CodeQL][codeql-badge]][codeql-url]
<!-- Badges: release & docker images -->
<!-- Badges: code quality -->
<!-- Badges: license & compliance -->
[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url]
<!-- Badges: documentation & support -->
<!-- Badges: others & stats -->
[![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]
# go OpenAPI toolkit runtime
---
A runtime for go OpenAPI toolkit.
The runtime component for use in code generation or as untyped usage.
## Release notes
## Announcements
### v0.29.0
* **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**
**New with this release**:
You may join the discord community by clicking the invite link on the discord badge (also above). [![Discord Channel][discord-badge]][discord-url]
* upgraded to `go1.24` and modernized the code base accordingly
* updated all dependencies, and removed an noticable indirect dependency (e.g. `mailru/easyjson`)
* **breaking change** no longer imports `opentracing-go` (#365).
* the `WithOpentracing()` method now returns an opentelemetry transport
* for users who can't transition to opentelemetry, the previous behavior
of `WithOpentracing` delivering an opentracing transport is provided by a separate
module `github.com/go-openapi/runtime/client-middleware/opentracing`.
* removed direct dependency to `gopkg.in/yaml.v3`, in favor of `go.yaml.in/yaml/v3` (an indirect
test dependency to the older package is still around)
* technically, the repo has evolved to a mono-repo, multiple modules structures (2 go modules
published), with CI adapted accordingly
Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]
## Status
API is stable.
## Import this library in your project
```cmd
go get github.com/go-openapi/runtime
```
## Change log
See <https://github.com/go-openapi/runtime/releases>
For pre-v0.30.0 releases see [release notes](docs/NOTES.md).
**What coming next?**
@@ -41,3 +56,58 @@ Moving forward, we want to :
## Licensing
This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
See the license [NOTICE](./NOTICE), which recalls the licensing terms of all the pieces of software
on top of which it has been built.
## Other documentation
* [FAQ](docs/FAQ.md)
* [All-time contributors](./CONTRIBUTORS.md)
* [Contributing guidelines](.github/CONTRIBUTING.md)
* [Maintainers documentation](docs/MAINTAINERS.md)
* [Code style](docs/STYLE.md)
## Cutting a new release
Maintainers can cut a new release by either:
* running [this workflow](https://github.com/go-openapi/runtime/actions/workflows/bump-release.yml)
* or pushing a semver tag
* signed tags are preferred
* The tag message is prepended to release notes
<!-- Badges: status -->
[test-badge]: https://github.com/go-openapi/runtime/actions/workflows/go-test.yml/badge.svg
[test-url]: https://github.com/go-openapi/runtime/actions/workflows/go-test.yml
[cov-badge]: https://codecov.io/gh/go-openapi/runtime/branch/master/graph/badge.svg
[cov-url]: https://codecov.io/gh/go-openapi/runtime
[vuln-scan-badge]: https://github.com/go-openapi/runtime/actions/workflows/scanner.yml/badge.svg
[vuln-scan-url]: https://github.com/go-openapi/runtime/actions/workflows/scanner.yml
[codeql-badge]: https://github.com/go-openapi/runtime/actions/workflows/codeql.yml/badge.svg
[codeql-url]: https://github.com/go-openapi/runtime/actions/workflows/codeql.yml
<!-- Badges: release & docker images -->
[release-badge]: https://badge.fury.io/gh/go-openapi%2Fruntime.svg
[release-url]: https://badge.fury.io/gh/go-openapi%2Fruntime
<!-- Badges: code quality -->
[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/runtime
[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/runtime
[codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/runtime
[codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/runtime
<!-- Badges: documentation & support -->
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/runtime
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/runtime
[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/twZ9BwT3
<!-- Badges: license & compliance -->
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
[license-url]: https://github.com/go-openapi/runtime/?tab=Apache-2.0-1-ov-file#readme
<!-- Badges: others & stats -->
[goversion-badge]: https://img.shields.io/github/go-mod/go-version/go-openapi/runtime
[goversion-url]: https://github.com/go-openapi/runtime/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/runtime
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/runtime/latest
+37
View File
@@ -0,0 +1,37 @@
# Security Policy
This policy outlines the commitment and practices of the go-openapi maintainers regarding security.
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 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**
rather than opening a publicly visible GitHub issue.
Please follow the instructions provided by github to [Privately report a security vulnerability][github-guidance-url].
> [!NOTE]
> 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
+12 -10
View File
@@ -18,7 +18,7 @@ func defaultCloser() error { return nil }
type byteStreamOpt func(opts *byteStreamOpts)
// ClosesStream when the bytestream consumer or producer is finished
// ClosesStream when the bytestream consumer or producer is finished.
func ClosesStream(opts *byteStreamOpts) {
opts.Close = true
}
@@ -32,11 +32,12 @@ type byteStreamOpts struct {
// The consumer consumes from a provided reader into the data passed by reference.
//
// Supported output underlying types and interfaces, prioritized in this order:
// - io.ReaderFrom (for maximum control)
// - io.Writer (performs io.Copy)
// - encoding.BinaryUnmarshaler
// - *string
// - *[]byte
//
// - [io.ReaderFrom] (for maximum control)
// - [io.Writer] (performs [io.Copy])
// - [encoding.BinaryUnmarshaler]
// - *string
// - *[]byte
func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
var vals byteStreamOpts
for _, opt := range opts {
@@ -124,13 +125,14 @@ func ByteStreamConsumer(opts ...byteStreamOpt) Consumer {
// The producer takes input data then writes to an output writer (essentially as a pipe).
//
// Supported input underlying types and interfaces, prioritized in this order:
// - io.WriterTo (for maximum control)
// - io.Reader (performs io.Copy). A ReadCloser is closed before exiting.
// - encoding.BinaryMarshaler
//
// - [io.WriterTo] (for maximum control)
// - [io.Reader] (performs [io.Copy]). A ReadCloser is closed before exiting.
// - [encoding.BinaryMarshaler]
// - error (writes as a string)
// - []byte
// - string
// - struct, other slices: writes as JSON
// - struct, other slices: writes as JSON.
func ByteStreamProducer(opts ...byteStreamOpt) Producer {
var vals byteStreamOpts
for _, opt := range opts {
+4 -4
View File
@@ -11,14 +11,14 @@ import (
"github.com/go-openapi/runtime"
)
// PassThroughAuth never manipulates the request
// PassThroughAuth never manipulates the request.
var PassThroughAuth runtime.ClientAuthInfoWriter
func init() {
PassThroughAuth = runtime.ClientAuthInfoWriterFunc(func(_ runtime.ClientRequest, _ strfmt.Registry) error { return nil })
}
// BasicAuth provides a basic auth info writer
// BasicAuth provides a basic auth info writer.
func BasicAuth(username, password string) runtime.ClientAuthInfoWriter {
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
encoded := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
@@ -26,7 +26,7 @@ func BasicAuth(username, password string) runtime.ClientAuthInfoWriter {
})
}
// APIKeyAuth provides an API key auth info writer
// APIKeyAuth provides an API key auth info writer.
func APIKeyAuth(name, in, value string) runtime.ClientAuthInfoWriter {
if in == "query" {
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
@@ -42,7 +42,7 @@ func APIKeyAuth(name, in, value string) runtime.ClientAuthInfoWriter {
return nil
}
// BearerToken provides a header based oauth2 bearer access token auth info writer
// BearerToken provides a header based oauth2 bearer access token auth info writer.
func BearerToken(token string) runtime.ClientAuthInfoWriter {
return runtime.ClientAuthInfoWriterFunc(func(r runtime.ClientRequest, _ strfmt.Registry) error {
return r.SetHeaderParam(runtime.HeaderAuthorization, "Bearer "+token)
+1 -1
View File
@@ -13,7 +13,7 @@ import (
// so that go will reuse the TCP connections.
// This is not enabled by default because there are servers where
// the response never gets closed and that would make the code hang forever.
// So instead it's provided as a http client middleware that can be used to override
// So instead it's provided as a [http] client [middleware] that can be used to override
// any request.
func KeepAliveTransport(rt http.RoundTripper) http.RoundTripper {
return &keepAliveTransport{wrapped: rt}
+4 -2
View File
@@ -98,12 +98,14 @@ func newOpenTelemetryTransport(transport runtime.ClientTransport, host string, o
host: host,
}
defaultOpts := []OpenTelemetryOpt{
const baseOptions = 4
defaultOpts := make([]OpenTelemetryOpt, 0, len(opts)+baseOptions)
defaultOpts = append(defaultOpts,
WithSpanOptions(trace.WithSpanKind(trace.SpanKindClient)),
WithSpanNameFormatter(defaultTransportFormatter),
WithPropagators(otel.GetTextMapPropagator()),
WithTracerProvider(otel.GetTracerProvider()),
}
)
c := newConfig(append(defaultOpts, opts...)...)
tr.config = c
+11 -12
View File
@@ -51,7 +51,7 @@ type request struct {
getBody func(r *request) []byte
}
// NewRequest creates a new swagger http client request
// NewRequest creates a new swagger http client request.
func newRequest(method, pathPattern string, writer runtime.ClientRequestWriter) *request {
return &request{
pathPattern: pathPattern,
@@ -64,7 +64,7 @@ func newRequest(method, pathPattern string, writer runtime.ClientRequestWriter)
}
}
// BuildHTTP creates a new http request based on the data from the params
// BuildHTTP creates a new http request based on the data from the params.
func (r *request) BuildHTTP(mediaType, basePath string, producers map[string]runtime.Producer, registry strfmt.Registry) (*http.Request, error) {
return r.buildHTTP(mediaType, basePath, producers, registry, nil)
}
@@ -87,7 +87,7 @@ func (r *request) GetBody() []byte {
// SetHeaderParam adds a header param to the request
// when there is only 1 value provided for the varargs, it will set it.
// when there are several values provided for the varargs it will add it (no overriding)
// when there are several values provided for the varargs it will add it (no overriding).
func (r *request) SetHeaderParam(name string, values ...string) error {
if r.header == nil {
r.header = make(http.Header)
@@ -96,14 +96,14 @@ func (r *request) SetHeaderParam(name string, values ...string) error {
return nil
}
// GetHeaderParams returns the all headers currently set for the request
// GetHeaderParams returns the all headers currently set for the request.
func (r *request) GetHeaderParams() http.Header {
return r.header
}
// SetQueryParam adds a query param to the request
// when there is only 1 value provided for the varargs, it will set it.
// when there are several values provided for the varargs it will add it (no overriding)
// when there are several values provided for the varargs it will add it (no overriding).
func (r *request) SetQueryParam(name string, values ...string) error {
if r.query == nil {
r.query = make(url.Values)
@@ -112,7 +112,7 @@ func (r *request) SetQueryParam(name string, values ...string) error {
return nil
}
// GetQueryParams returns a copy of all query params currently set for the request
// GetQueryParams returns a copy of all query params currently set for the request.
func (r *request) GetQueryParams() url.Values {
var result = make(url.Values)
for key, value := range r.query {
@@ -123,7 +123,7 @@ func (r *request) GetQueryParams() url.Values {
// SetFormParam adds a forn param to the request
// when there is only 1 value provided for the varargs, it will set it.
// when there are several values provided for the varargs it will add it (no overriding)
// when there are several values provided for the varargs it will add it (no overriding).
func (r *request) SetFormParam(name string, values ...string) error {
if r.formFields == nil {
r.formFields = make(url.Values)
@@ -132,7 +132,7 @@ func (r *request) SetFormParam(name string, values ...string) error {
return nil
}
// SetPathParam adds a path param to the request
// SetPathParam adds a path param to the request.
func (r *request) SetPathParam(name string, value string) error {
if r.pathParams == nil {
r.pathParams = make(map[string]string)
@@ -142,7 +142,7 @@ func (r *request) SetPathParam(name string, value string) error {
return nil
}
// SetFileParam adds a file param to the request
// SetFileParam adds a file param to the request.
func (r *request) SetFileParam(name string, files ...runtime.NamedReadCloser) error {
for _, file := range files {
if actualFile, ok := file.(*os.File); ok {
@@ -182,7 +182,7 @@ func (r *request) GetBodyParam() any {
return r.payload
}
// SetTimeout sets the timeout for a request
// SetTimeout sets the timeout for a request.
func (r *request) SetTimeout(timeout time.Duration) error {
r.timeout = timeout
return nil
@@ -298,8 +298,7 @@ func (r *request) buildHTTP(mediaType, basePath string, producers map[string]run
// if there is payload, use the producer to write the payload, and then
// set the header to the content-type appropriate for the payload produced
if r.payload != nil {
// TODO: infer most appropriate content type based on the producer used,
// and the `consumers` section of the spec/operation
// Enhancement proposal: https://github.com/go-openapi/runtime/issues/387
r.header.Set(runtime.HeaderContentType, mediaType)
if rdr, ok := r.payload.(io.ReadCloser); ok {
body = rdr
+28 -16
View File
@@ -33,10 +33,10 @@ const (
schemeHTTPS = "https"
)
// DefaultTimeout the default request timeout
// DefaultTimeout the default request timeout.
var DefaultTimeout = 30 * time.Second
// TLSClientOptions to configure client authentication with mutual TLS
// TLSClientOptions to configure client authentication with mutual TLS.
type TLSClientOptions struct {
// Certificate is the path to a PEM-encoded certificate to be used for
// client authentication. If set then Key must also be set.
@@ -92,6 +92,17 @@ type TLSClientOptions struct {
// the verifiedChains argument will always be nil.
VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
// VerifyConnection, if not nil, is called after normal certificate
// verification and after [TLSClientOptions.VerifyPeerCertificate] by either a TLS client or
// server. It receives the [tls.ConnectionState] which may be inspected.
//
// Unlike VerifyPeerCertificate, this callback is invoked on every
// connection, including resumed ones, making it suitable for checks
// that must always apply (e.g. certificate pinning).
//
// If it returns a non-nil error, the handshake is aborted and that error results.
VerifyConnection func(tls.ConnectionState) error
// SessionTicketsDisabled may be set to true to disable session ticket and
// PSK (resumption) support. Note that on clients, session ticket support is
// also disabled if ClientSessionCache is nil.
@@ -105,7 +116,7 @@ type TLSClientOptions struct {
_ struct{}
}
// TLSClientAuth creates a tls.Config for mutual auth
// TLSClientAuth creates a [tls.Config] for mutual auth.
func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
// create client tls config
cfg := &tls.Config{
@@ -150,6 +161,7 @@ func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
cfg.InsecureSkipVerify = opts.InsecureSkipVerify
cfg.VerifyPeerCertificate = opts.VerifyPeerCertificate
cfg.VerifyConnection = opts.VerifyConnection
cfg.SessionTicketsDisabled = opts.SessionTicketsDisabled
cfg.ClientSessionCache = opts.ClientSessionCache
@@ -183,7 +195,7 @@ func TLSClientAuth(opts TLSClientOptions) (*tls.Config, error) {
return cfg, nil
}
// TLSTransport creates a http client transport suitable for mutual tls auth
// TLSTransport creates a [http] client transport suitable for mutual [tls] auth.
func TLSTransport(opts TLSClientOptions) (http.RoundTripper, error) {
cfg, err := TLSClientAuth(opts)
if err != nil {
@@ -193,7 +205,7 @@ func TLSTransport(opts TLSClientOptions) (http.RoundTripper, error) {
return &http.Transport{TLSClientConfig: cfg}, nil
}
// TLSClient creates a http.Client for mutual auth
// TLSClient creates a [http.Client] for mutual auth.
func TLSClient(opts TLSClientOptions) (*http.Client, error) {
transport, err := TLSTransport(opts)
if err != nil {
@@ -203,7 +215,7 @@ func TLSClient(opts TLSClientOptions) (*http.Client, error) {
}
// Runtime represents an API client that uses the transport
// to make http requests based on a swagger specification.
// to make [http] requests based on a swagger specification.
type Runtime struct {
DefaultMediaType string
DefaultAuthentication runtime.ClientAuthInfoWriter
@@ -227,12 +239,12 @@ type Runtime struct {
response ClientResponseFunc
}
// New creates a new default runtime for a swagger api runtime.Client
// New creates a new default runtime for a swagger api runtime.Client.
func New(host, basePath string, schemes []string) *Runtime {
var rt Runtime
rt.DefaultMediaType = runtime.JSONMime
// TODO: actually infer this stuff from the spec
// Enhancement proposal: https://github.com/go-openapi/runtime/issues/385
rt.Consumers = map[string]runtime.Consumer{
runtime.YAMLMime: yamlpc.YAMLConsumer(),
runtime.JSONMime: runtime.JSONConsumer(),
@@ -271,7 +283,7 @@ func New(host, basePath string, schemes []string) *Runtime {
return &rt
}
// NewWithClient allows you to create a new transport with a configured http.Client
// NewWithClient allows you to create a new transport with a configured [http.Client].
func NewWithClient(host, basePath string, schemes []string, client *http.Client) *Runtime {
rt := New(host, basePath, schemes)
if client != nil {
@@ -297,8 +309,8 @@ func NewWithClient(host, basePath string, schemes []string, client *http.Client)
// an opentelemetry transport.
//
// If you have a strict requirement on using opentracing, you may still do so by importing
// module [github.com/go-openapi/runtime/client-middleware/opentracing] and using
// [github.com/go-openapi/runtime/client-middleware/opentracing.WithOpenTracing] with your
// module [github.com/go-openapi/runtime/client-[middleware]/opentracing] and using
// [github.com/go-openapi/runtime/client-[middleware]/opentracing.WithOpenTracing] with your
// usual opentracing options and opentracing-enabled transport.
//
// Passed options are ignored unless they are of type [OpenTelemetryOpt].
@@ -328,7 +340,7 @@ func (r *Runtime) WithOpenTelemetry(opts ...OpenTelemetryOpt) runtime.ClientTran
//
// This is not enabled by default because there are servers where
// the response never gets closed and that would make the code hang forever.
// So instead it's provided as a http client middleware that can be used to override
// So instead it's provided as a [http] client [middleware] that can be used to override
// any request.
func (r *Runtime) EnableConnectionReuse() {
if r.client == nil {
@@ -351,7 +363,7 @@ func (r *Runtime) CreateHttpRequest(operation *runtime.ClientOperation) (req *ht
}
// Submit a request and when there is a body on success it will turn that into the result
// all other things are turned into an api error for swagger which retains the status code
// all other things are turned into an api error for swagger which retains the status code.
func (r *Runtime) Submit(operation *runtime.ClientOperation) (any, error) {
_, readResponse, _ := operation.Params, operation.Reader, operation.AuthInfo
@@ -506,13 +518,13 @@ func transportOrDefault(left, right http.RoundTripper) http.RoundTripper {
return left
}
// takes a client operation and creates equivalent http.Request
// takes a client operation and creates equivalent http.Request.
func (r *Runtime) createHttpRequest(operation *runtime.ClientOperation) (*request, *http.Request, error) { //nolint:revive
params, _, auth := operation.Params, operation.Reader, operation.AuthInfo
request := newRequest(operation.Method, operation.PathPattern, params)
var accept []string
accept := make([]string, 0, len(operation.ProducesMediaTypes))
accept = append(accept, operation.ProducesMediaTypes...)
if err := request.SetHeaderParam(runtime.HeaderAccept, accept...); err != nil {
return nil, nil, err
@@ -532,7 +544,7 @@ func (r *Runtime) createHttpRequest(operation *runtime.ClientOperation) (*reques
// }
//}
// TODO: pick appropriate media type
// Enhancement proposal: https://github.com/go-openapi/runtime/issues/386
cmt := r.DefaultMediaType
for _, mediaType := range operation.ConsumesMediaTypes {
// Pick first non-empty media type
+3 -3
View File
@@ -5,15 +5,15 @@ package runtime
import "github.com/go-openapi/strfmt"
// A ClientAuthInfoWriterFunc converts a function to a request writer interface
// A ClientAuthInfoWriterFunc converts a function to a request writer interface.
type ClientAuthInfoWriterFunc func(ClientRequest, strfmt.Registry) error
// AuthenticateRequest adds authentication data to the request
// AuthenticateRequest adds authentication data to the request.
func (fn ClientAuthInfoWriterFunc) AuthenticateRequest(req ClientRequest, reg strfmt.Registry) error {
return fn(req, reg)
}
// A ClientAuthInfoWriter implementor knows how to write authentication info to a request
// A ClientAuthInfoWriter implementor knows how to write authentication info to a request.
type ClientAuthInfoWriter interface {
AuthenticateRequest(ClientRequest, strfmt.Registry) error
}
+2 -2
View File
@@ -8,7 +8,7 @@ import (
"net/http"
)
// ClientOperation represents the context for a swagger operation to be submitted to the transport
// ClientOperation represents the context for a swagger operation to be submitted to the transport.
type ClientOperation struct {
ID string
Method string
@@ -23,7 +23,7 @@ type ClientOperation struct {
Client *http.Client
}
// A ClientTransport implementor knows how to submit Request objects to some destination
// A ClientTransport implementor knows how to submit Request objects to some destination.
type ClientTransport interface {
// Submit(string, RequestWriter, ResponseReader, AuthInfoWriter) (interface{}, error)
Submit(*ClientOperation) (any, error)
+5 -5
View File
@@ -12,15 +12,15 @@ import (
"github.com/go-openapi/strfmt"
)
// ClientRequestWriterFunc converts a function to a request writer interface
// ClientRequestWriterFunc converts a function to a request writer interface.
type ClientRequestWriterFunc func(ClientRequest, strfmt.Registry) error
// WriteToRequest adds data to the request
// WriteToRequest adds data to the request.
func (fn ClientRequestWriterFunc) WriteToRequest(req ClientRequest, reg strfmt.Registry) error {
return fn(req, reg)
}
// ClientRequestWriter is an interface for things that know how to write to a request
// ClientRequestWriter is an interface for things that know how to write to a request.
type ClientRequestWriter interface {
WriteToRequest(ClientRequest, strfmt.Registry) error
}
@@ -57,13 +57,13 @@ type ClientRequest interface { //nolint:interfacebloat // a swagger-capable requ
GetFileParam() map[string][]NamedReadCloser
}
// NamedReadCloser represents a named ReadCloser interface
// NamedReadCloser represents a named ReadCloser interface.
type NamedReadCloser interface {
io.ReadCloser
Name() string
}
// NamedReader creates a NamedReadCloser for use as file upload
// NamedReader creates a [NamedReadCloser] for use as file upload.
func NamedReader(name string, rdr io.Reader) NamedReadCloser {
rc, ok := rdr.(io.ReadCloser)
if !ok {
+13 -13
View File
@@ -12,7 +12,7 @@ import (
// A ClientResponse represents a client response.
//
// This bridges between responses obtained from different transports
// This bridges between responses obtained from different transports.
type ClientResponse interface {
Code() int
Message() string
@@ -21,28 +21,28 @@ type ClientResponse interface {
Body() io.ReadCloser
}
// A ClientResponseReaderFunc turns a function into a ClientResponseReader interface implementation
// A ClientResponseReaderFunc turns a function into a [ClientResponseReader] interface implementation.
type ClientResponseReaderFunc func(ClientResponse, Consumer) (any, error)
// ReadResponse reads the response
// ReadResponse reads the response.
func (read ClientResponseReaderFunc) ReadResponse(resp ClientResponse, consumer Consumer) (any, error) {
return read(resp, consumer)
}
// A ClientResponseReader is an interface for things want to read a response.
// An application of this is to create structs from response values
// An application of this is to create structs from response values.
type ClientResponseReader interface {
ReadResponse(ClientResponse, Consumer) (any, error)
}
// APIError wraps an error model and captures the status code
// APIError wraps an error model and captures the status code.
type APIError struct {
OperationName string
Response any
Code int
}
// NewAPIError creates a new API error
// NewAPIError creates a new API error.
func NewAPIError(opName string, payload any, code int) *APIError {
return &APIError{
OperationName: opName,
@@ -51,7 +51,7 @@ func NewAPIError(opName string, payload any, code int) *APIError {
}
}
// sanitizer ensures that single quotes are escaped
// sanitizer ensures that single quotes are escaped.
var sanitizer = strings.NewReplacer(`\`, `\\`, `'`, `\'`)
func (o *APIError) Error() string {
@@ -69,37 +69,37 @@ func (o *APIError) String() string {
return o.Error()
}
// IsSuccess returns true when this API response returns a 2xx status code
// IsSuccess returns true when this API response returns a 2xx status code.
func (o *APIError) IsSuccess() bool {
const statusOK = 2
return o.Code/100 == statusOK
}
// IsRedirect returns true when this API response returns a 3xx status code
// IsRedirect returns true when this API response returns a 3xx status code.
func (o *APIError) IsRedirect() bool {
const statusRedirect = 3
return o.Code/100 == statusRedirect
}
// IsClientError returns true when this API response returns a 4xx status code
// IsClientError returns true when this API response returns a 4xx status code.
func (o *APIError) IsClientError() bool {
const statusClientError = 4
return o.Code/100 == statusClientError
}
// IsServerError returns true when this API response returns a 5xx status code
// IsServerError returns true when this API response returns a 5xx status code.
func (o *APIError) IsServerError() bool {
const statusServerError = 5
return o.Code/100 == statusServerError
}
// IsCode returns true when this API response returns a given status code
// IsCode returns true when this API response returns a given status code.
func (o *APIError) IsCode(code int) bool {
return o.Code == code
}
// A ClientResponseStatus is a common interface implemented by all responses on the generated code
// You can use this to treat any client response based on status code
// You can use this to treat any client response based on status code.
type ClientResponseStatus interface {
IsSuccess() bool
IsRedirect() bool
+13 -13
View File
@@ -4,35 +4,35 @@
package runtime
const (
// HeaderContentType represents a http content-type header, it's value is supposed to be a mime type
// HeaderContentType represents a [http] content-type header, it's value is supposed to be a mime type.
HeaderContentType = "Content-Type"
// HeaderTransferEncoding represents a http transfer-encoding header.
// HeaderTransferEncoding represents a [http] transfer-encoding header.
HeaderTransferEncoding = "Transfer-Encoding"
// HeaderAccept the Accept header
// HeaderAccept the Accept header.
HeaderAccept = "Accept"
// HeaderAuthorization the Authorization header
// HeaderAuthorization the Authorization header.
HeaderAuthorization = "Authorization"
charsetKey = "charset"
// DefaultMime the default fallback mime type
// DefaultMime the default fallback mime type.
DefaultMime = "application/octet-stream"
// JSONMime the json mime type
// JSONMime the json mime type.
JSONMime = "application/json"
// YAMLMime the yaml mime type
// YAMLMime the [yaml] mime type.
YAMLMime = "application/x-yaml"
// XMLMime the xml mime type
// XMLMime the [xml] mime type.
XMLMime = "application/xml"
// TextMime the text mime type
// TextMime the text mime type.
TextMime = "text/plain"
// HTMLMime the html mime type
// HTMLMime the html mime type.
HTMLMime = "text/html"
// CSVMime the csv mime type
// CSVMime the [csv] mime type.
CSVMime = "text/csv"
// MultipartFormMime the multipart form mime type
// MultipartFormMime the multipart form mime type.
MultipartFormMime = "multipart/form-data"
// URLencodedFormMime the url encoded form mime type
// URLencodedFormMime is the [url] encoded form mime type.
URLencodedFormMime = "application/x-www-form-urlencoded"
)
+17 -15
View File
@@ -21,17 +21,18 @@ import (
// The consumer consumes CSV records from a provided reader into the data passed by reference.
//
// CSVOpts options may be specified to alter the default CSV behavior on the reader and the writer side (e.g. separator, skip header, ...).
// The defaults are those of the standard library's csv.Reader and csv.Writer.
// The defaults are those of the standard library's [csv.Reader] and [csv.Writer].
//
// Supported output underlying types and interfaces, prioritized in this order:
// - *csv.Writer
// - CSVWriter (writer options are ignored)
// - io.Writer (as raw bytes)
// - io.ReaderFrom (as raw bytes)
// - encoding.BinaryUnmarshaler (as raw bytes)
// - *[][]string (as a collection of records)
// - *[]byte (as raw bytes)
// - *string (a raw bytes)
//
// - *[csv.Writer]
// - [CSVWriter] (writer options are ignored)
// - [io.Writer] (as raw bytes)
// - [io.ReaderFrom] (as raw bytes)
// - [encoding.BinaryUnmarshaler] (as raw bytes)
// - *[][]string (as a collection of records)
// - *[]byte (as raw bytes)
// - *string (a raw bytes)
//
// The consumer prioritizes situations where buffering the input is not required.
func CSVConsumer(opts ...CSVOpt) Consumer {
@@ -157,11 +158,12 @@ func CSVConsumer(opts ...CSVOpt) Consumer {
// The producer takes input data then writes as CSV to an output writer (essentially as a pipe).
//
// Supported input underlying types and interfaces, prioritized in this order:
// - *csv.Reader
// - CSVReader (reader options are ignored)
// - io.Reader
// - io.WriterTo
// - encoding.BinaryMarshaler
//
// - *[csv.Reader]
// - [CSVReader] (reader options are ignored)
// - [io.Reader]
// - [io.WriterTo]
// - [encoding.BinaryMarshaler]
// - [][]string
// - []byte
// - string
@@ -283,7 +285,7 @@ func CSVProducer(opts ...CSVOpt) Producer {
})
}
// pipeCSV copies CSV records from a CSV reader to a CSV writer
// pipeCSV copies CSV records from a CSV reader to a CSV writer.
func pipeCSV(csvWriter CSVWriter, csvReader CSVReader, opts csvOpts) error {
for ; opts.skippedLines > 0; opts.skippedLines-- {
_, err := csvReader.Read()
+3 -3
View File
@@ -18,7 +18,7 @@ type csvOpts struct {
closeStream bool
}
// WithCSVReaderOpts specifies the options to csv.Reader
// WithCSVReaderOpts specifies the options to [csv.Reader]
// when reading CSV.
func WithCSVReaderOpts(reader csv.Reader) CSVOpt {
return func(o *csvOpts) {
@@ -26,7 +26,7 @@ func WithCSVReaderOpts(reader csv.Reader) CSVOpt {
}
}
// WithCSVWriterOpts specifies the options to csv.Writer
// WithCSVWriterOpts specifies the options to [csv.Writer]
// when writing CSV.
func WithCSVWriterOpts(writer csv.Writer) CSVOpt {
return func(o *csvOpts) {
@@ -94,7 +94,7 @@ var (
_ CSVReader = &csvRecordsWriter{}
)
// csvRecordsWriter is an internal container to move CSV records back and forth
// csvRecordsWriter is an internal container to move CSV records back and forth.
type csvRecordsWriter struct {
i int
records [][]string
+6
View File
@@ -0,0 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
// Package runtime exposes runtime client and server components
// for go-openapi toolkit.
package runtime
+16
View File
@@ -14,6 +14,8 @@ github.com/go-openapi/swag/netutils v0.24.0/go.mod h1:WRgiHcYTnx+IqfMCtu0hy9oOaP
github.com/go-openapi/swag/stringutils v0.24.0/go.mod h1:5nUXB4xA0kw2df5PRipZDslPJgJut+NjL7D25zPZ/4w=
github.com/go-openapi/swag/typeutils v0.24.0/go.mod h1:q8C3Kmk/vh2VhpCLaoR2MVWOGP8y7Jc8l82qCTd1DYI=
github.com/go-openapi/swag/yamlutils v0.24.0/go.mod h1:DpKv5aYuaGm/sULePoeiG8uwMpZSfReo1HR3Ik0yaG8=
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/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -26,9 +28,13 @@ github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUt
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
@@ -37,6 +43,7 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
@@ -44,11 +51,15 @@ golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -69,11 +80,14 @@ golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw=
golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -88,6 +102,8 @@ golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"github.com/go-openapi/errors"
)
// ContentType parses a content type header
// ContentType parses a content type header.
func ContentType(headers http.Header) (string, string, error) {
ct := headers.Get(HeaderContentType)
orig := ct
+17 -17
View File
@@ -11,75 +11,75 @@ import (
"github.com/go-openapi/strfmt"
)
// OperationHandlerFunc an adapter for a function to the OperationHandler interface
// OperationHandlerFunc an adapter for a function to the [OperationHandler] interface.
type OperationHandlerFunc func(any) (any, error)
// Handle implements the operation handler interface
// Handle implements the operation handler interface.
func (s OperationHandlerFunc) Handle(data any) (any, error) {
return s(data)
}
// OperationHandler a handler for a swagger operation
// OperationHandler a handler for a swagger operation.
type OperationHandler interface {
Handle(any) (any, error)
}
// ConsumerFunc represents a function that can be used as a consumer
// ConsumerFunc represents a function that can be used as a consumer.
type ConsumerFunc func(io.Reader, any) error
// Consume consumes the reader into the data parameter
// Consume consumes the reader into the data parameter.
func (fn ConsumerFunc) Consume(reader io.Reader, data any) error {
return fn(reader, data)
}
// Consumer implementations know how to bind the values on the provided interface to
// data provided by the request body
// data provided by the request body.
type Consumer interface {
// Consume performs the binding of request values
Consume(io.Reader, any) error
}
// ProducerFunc represents a function that can be used as a producer
// ProducerFunc represents a function that can be used as a producer.
type ProducerFunc func(io.Writer, any) error
// Produce produces the response for the provided data
// Produce produces the response for the provided data.
func (f ProducerFunc) Produce(writer io.Writer, data any) error {
return f(writer, data)
}
// Producer implementations know how to turn the provided interface into a valid
// HTTP response
// HTTP response.
type Producer interface {
// Produce writes to the http response
Produce(io.Writer, any) error
}
// AuthenticatorFunc turns a function into an authenticator
// AuthenticatorFunc turns a function into an authenticator.
type AuthenticatorFunc func(any) (bool, any, error)
// Authenticate authenticates the request with the provided data
// Authenticate authenticates the request with the provided data.
func (f AuthenticatorFunc) Authenticate(params any) (bool, any, error) {
return f(params)
}
// Authenticator represents an authentication strategy
// implementations of Authenticator know how to authenticate the
// request data and translate that into a valid principal object or an error
// request data and translate that into a valid principal object or an error.
type Authenticator interface {
Authenticate(any) (bool, any, error)
}
// AuthorizerFunc turns a function into an authorizer
// AuthorizerFunc turns a function into an authorizer.
type AuthorizerFunc func(*http.Request, any) error
// Authorize authorizes the processing of the request for the principal
// Authorize authorizes the processing of the request for the principal.
func (f AuthorizerFunc) Authorize(r *http.Request, principal any) error {
return f(r, principal)
}
// Authorizer represents an authorization strategy
// implementations of Authorizer know how to authorize the principal object
// using the request data and returns error if unauthorized
// using the request data and returns error if unauthorized.
type Authorizer interface {
Authorize(*http.Request, any) error
}
@@ -87,7 +87,7 @@ type Authorizer interface {
// Validatable types implementing this interface allow customizing their validation
// this will be used instead of the reflective validation based on the spec document.
// the implementations are assumed to have been generated by the swagger tool so they should
// contain all the validations obtained from the spec
// contain all the validations obtained from the spec.
type Validatable interface {
Validate(strfmt.Registry) error
}
@@ -95,7 +95,7 @@ type Validatable interface {
// ContextValidatable types implementing this interface allow customizing their validation
// this will be used instead of the reflective validation based on the spec document.
// the implementations are assumed to have been generated by the swagger tool so they should
// contain all the context validations obtained from the spec
// contain all the context validations obtained from the spec.
type ContextValidatable interface {
ContextValidate(context.Context, strfmt.Registry) error
}
+2 -2
View File
@@ -8,7 +8,7 @@ import (
"io"
)
// JSONConsumer creates a new JSON consumer
// JSONConsumer creates a new JSON consumer.
func JSONConsumer() Consumer {
return ConsumerFunc(func(reader io.Reader, data any) error {
dec := json.NewDecoder(reader)
@@ -17,7 +17,7 @@ func JSONConsumer() Consumer {
})
}
// JSONProducer creates a new JSON producer
// JSONProducer creates a new JSON producer.
func JSONProducer() Producer {
return ProducerFunc(func(writer io.Writer, data any) error {
enc := json.NewEncoder(writer)
+40 -36
View File
@@ -24,10 +24,12 @@ import (
"github.com/go-openapi/runtime/security"
)
// Debug when true turns on verbose logging
// Debug when true turns on verbose logging.
var Debug = logger.DebugEnabled()
// Logger is the standard libray logger used for printing debug messages
// Logger is the standard library logger used for printing debug messages.
//
// (Note: The correct spelling is "library", not "libra". "Libra" is a zodiac sign/constellation and wouldn't make sense in this context.)
var Logger logger.Logger = logger.StandardLogger{}
func debugLogfFunc(lg logger.Logger) func(string, ...any) {
@@ -43,35 +45,35 @@ func debugLogfFunc(lg logger.Logger) func(string, ...any) {
return func(_ string, _ ...any) {}
}
// A Builder can create middlewares
// A Builder can create middlewares.
type Builder func(http.Handler) http.Handler
// PassthroughBuilder returns the handler, aka the builder identity function
// PassthroughBuilder returns the handler, aka the builder identity function.
func PassthroughBuilder(handler http.Handler) http.Handler { return handler }
// RequestBinder is an interface for types to implement
// when they want to be able to bind from a request
// when they want to be able to bind from a request.
type RequestBinder interface {
BindRequest(*http.Request, *MatchedRoute) error
}
// Responder is an interface for types to implement
// when they want to be considered for writing HTTP responses
// when they want to be considered for writing HTTP responses.
type Responder interface {
WriteResponse(http.ResponseWriter, runtime.Producer)
}
// ResponderFunc wraps a func as a Responder interface
// ResponderFunc wraps a func as a Responder interface.
type ResponderFunc func(http.ResponseWriter, runtime.Producer)
// WriteResponse writes to the response
// WriteResponse writes to the response.
func (fn ResponderFunc) WriteResponse(rw http.ResponseWriter, pr runtime.Producer) {
fn(rw, pr)
}
// Context is a type safe wrapper around an untyped request context
// Context is a type safe wrapper around an [untyped] request context
// used throughout to store request context with the standard context attached
// to the http.Request
// to the [http.Request].
type Context struct {
spec *loads.Document
analyzer *analysis.Spec
@@ -192,7 +194,7 @@ func (r *routableUntypedAPI) DefaultConsumes() string {
// NewRoutableContext creates a new context for a routable API.
//
// If a nil Router is provided, the DefaultRouter (denco-based) will be used.
// If a nil Router is provided, the [DefaultRouter] ([denco]-based) will be used.
func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Router) *Context {
var an *analysis.Spec
if spec != nil {
@@ -202,9 +204,9 @@ func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Ro
return NewRoutableContextWithAnalyzedSpec(spec, an, routableAPI, routes)
}
// NewRoutableContextWithAnalyzedSpec is like NewRoutableContext but takes as input an already analysed spec.
// NewRoutableContextWithAnalyzedSpec is like [NewRoutableContext] but takes as input an already analysed spec.
//
// If a nil Router is provided, the DefaultRouter (denco-based) will be used.
// If a nil Router is provided, the [DefaultRouter] ([denco]-based) will be used.
func NewRoutableContextWithAnalyzedSpec(spec *loads.Document, an *analysis.Spec, routableAPI RoutableAPI, routes Router) *Context {
// Either there are no spec doc and analysis, or both of them.
if (spec != nil || an != nil) && (spec == nil || an == nil) {
@@ -222,7 +224,7 @@ func NewRoutableContextWithAnalyzedSpec(spec *loads.Document, an *analysis.Spec,
// NewContext creates a new context wrapper.
//
// If a nil Router is provided, the DefaultRouter (denco-based) will be used.
// If a nil Router is provided, the [DefaultRouter] ([denco]-based) will be used.
func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context {
var an *analysis.Spec
if spec != nil {
@@ -239,13 +241,13 @@ func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context
return ctx
}
// Serve serves the specified spec with the specified api registrations as a http.Handler
// Serve serves the specified spec with the specified api registrations as a [http.Handler].
func Serve(spec *loads.Document, api *untyped.API) http.Handler {
return ServeWithBuilder(spec, api, PassthroughBuilder)
}
// ServeWithBuilder serves the specified spec with the specified api registrations as a http.Handler that is decorated
// by the Builder
// ServeWithBuilder serves the specified spec with the specified api registrations as a [http.Handler] that is decorated
// by the Builder.
func ServeWithBuilder(spec *loads.Document, api *untyped.API, builder Builder) http.Handler {
context := NewContext(spec, api, nil)
return context.APIHandler(builder)
@@ -294,7 +296,7 @@ type contentTypeValue struct {
Charset string
}
// BasePath returns the base path for this API
// BasePath returns the base path for this API.
func (c *Context) BasePath() string {
if c.spec == nil {
return ""
@@ -309,13 +311,13 @@ func (c *Context) SetLogger(lg logger.Logger) {
c.debugLogf = debugLogfFunc(lg)
}
// RequiredProduces returns the accepted content types for responses
// RequiredProduces returns the accepted content types for responses.
func (c *Context) RequiredProduces() []string {
return c.analyzer.RequiredProduces()
}
// BindValidRequest binds a params object to a request but only when the request is valid
// if the request is not valid an error will be returned
// if the request is not valid an error will be returned.
func (c *Context) BindValidRequest(request *http.Request, route *MatchedRoute, binder RequestBinder) error {
var res []error
var requestContentType string
@@ -374,7 +376,7 @@ func (c *Context) BindValidRequest(request *http.Request, route *MatchedRoute, b
// Returns the media type, its charset and a shallow copy of the request
// when its context doesn't contain the content type value, otherwise it returns
// the same request
// Returns the error that runtime.ContentType may retunrs.
// Returns the error that [runtime.ContentType] may returns.
func (c *Context) ContentType(request *http.Request) (string, string, *http.Request, error) {
var rCtx = request.Context()
@@ -390,7 +392,7 @@ func (c *Context) ContentType(request *http.Request) (string, string, *http.Requ
return mt, cs, request.WithContext(rCtx), nil
}
// LookupRoute looks a route up and returns true when it is found
// LookupRoute looks a route up and returns true when it is found.
func (c *Context) LookupRoute(request *http.Request) (*MatchedRoute, bool) {
if route, ok := c.router.Lookup(request.Method, request.URL.EscapedPath()); ok {
return route, ok
@@ -402,7 +404,7 @@ func (c *Context) LookupRoute(request *http.Request) (*MatchedRoute, bool) {
// Returns the matched route, a shallow copy of the request if its context
// contains the matched router, otherwise the same request, and a bool to
// indicate if it the request matches one of the routes, if it doesn't
// then it returns false and nil for the other two return values
// then it returns false and nil for the other two return values.
func (c *Context) RouteInfo(request *http.Request) (*MatchedRoute, *http.Request, bool) {
var rCtx = request.Context()
@@ -420,7 +422,7 @@ func (c *Context) RouteInfo(request *http.Request) (*MatchedRoute, *http.Request
// ResponseFormat negotiates the response content type
// Returns the response format and a shallow copy of the request if its context
// doesn't contain the response format, otherwise the same request
// doesn't contain the response format, otherwise the same request.
func (c *Context) ResponseFormat(r *http.Request, offers []string) (string, *http.Request) {
var rCtx = r.Context()
@@ -438,12 +440,12 @@ func (c *Context) ResponseFormat(r *http.Request, offers []string) (string, *htt
return format, r
}
// AllowedMethods gets the allowed methods for the path of this request
// AllowedMethods gets the allowed methods for the path of this request.
func (c *Context) AllowedMethods(request *http.Request) []string {
return c.router.OtherMethods(request.Method, request.URL.EscapedPath())
}
// ResetAuth removes the current principal from the request context
// ResetAuth removes the current principal from the request context.
func (c *Context) ResetAuth(request *http.Request) *http.Request {
rctx := request.Context()
rctx = stdContext.WithValue(rctx, ctxSecurityPrincipal, nil)
@@ -454,7 +456,7 @@ func (c *Context) ResetAuth(request *http.Request) *http.Request {
// Authorize authorizes the request
// Returns the principal object and a shallow copy of the request when its
// context doesn't contain the principal, otherwise the same request or an error
// (the last) if one of the authenticators returns one or an Unauthenticated error
// (the last) if one of the authenticators returns one or an Unauthenticated error.
func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (any, *http.Request, error) {
if route == nil || !route.HasAuth() {
return nil, nil, nil
@@ -492,7 +494,7 @@ func (c *Context) Authorize(request *http.Request, route *MatchedRoute) (any, *h
// BindAndValidate binds and validates the request
// Returns the validation map and a shallow copy of the request when its context
// doesn't contain the validation, otherwise it returns the same request or an
// CompositeValidationError error
// CompositeValidationError error.
func (c *Context) BindAndValidate(request *http.Request, matched *MatchedRoute) (any, *http.Request, error) {
var rCtx = request.Context()
@@ -513,12 +515,12 @@ func (c *Context) BindAndValidate(request *http.Request, matched *MatchedRoute)
return result.bound, request, nil
}
// NotFound the default not found responder for when no route has been matched yet
// NotFound the default not found responder for when no route has been matched yet.
func (c *Context) NotFound(rw http.ResponseWriter, r *http.Request) {
c.Respond(rw, r, []string{c.api.DefaultProduces()}, nil, errors.NotFound("not found"))
}
// Respond renders the response after doing some content negotiation
// Respond renders the response after doing some content negotiation.
func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []string, route *MatchedRoute, data any) {
c.debugLogf("responding to %s %s with produces: %v", r.Method, r.URL.Path, produces)
offers := []string{}
@@ -616,7 +618,7 @@ func (c *Context) Respond(rw http.ResponseWriter, r *http.Request, produces []st
//
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
//
// A spec UI (SwaggerUI) is served at {API base path}/docs and the spec document at /swagger.json
// A spec UI ([SwaggerUI]) is served at {API base path}/docs and the spec document at /swagger.json
// (these can be modified with uiOptions).
func (c *Context) APIHandlerSwaggerUI(builder Builder, opts ...UIOption) http.Handler {
b := builder
@@ -635,7 +637,7 @@ func (c *Context) APIHandlerSwaggerUI(builder Builder, opts ...UIOption) http.Ha
//
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
//
// A spec UI (RapiDoc) is served at {API base path}/docs and the spec document at /swagger.json
// A spec UI ([RapiDoc]) is served at {API base path}/docs and the spec document at /swagger.json
// (these can be modified with uiOptions).
func (c *Context) APIHandlerRapiDoc(builder Builder, opts ...UIOption) http.Handler {
b := builder
@@ -654,7 +656,7 @@ func (c *Context) APIHandlerRapiDoc(builder Builder, opts ...UIOption) http.Hand
//
// This handler includes a swagger spec, router and the contract defined in the swagger spec.
//
// A spec UI (Redoc) is served at {API base path}/docs and the spec document at /swagger.json
// A spec UI ([Redoc]) is served at {API base path}/docs and the spec document at /swagger.json
// (these can be modified with uiOptions).
func (c *Context) APIHandler(builder Builder, opts ...UIOption) http.Handler {
b := builder
@@ -669,7 +671,7 @@ func (c *Context) APIHandler(builder Builder, opts ...UIOption) http.Handler {
return Spec(specPath, c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(b)), specOpts...)
}
// RoutesHandler returns a handler to serve the API, just the routes and the contract defined in the swagger spec
// RoutesHandler returns a handler to serve the API, just the routes and the contract defined in the swagger spec.
func (c *Context) RoutesHandler(builder Builder) http.Handler {
b := builder
if b == nil {
@@ -686,10 +688,12 @@ func (c Context) uiOptionsForHandler(opts []UIOption) (string, uiOptions, []Spec
}
// default options (may be overridden)
optsForContext := []UIOption{
const baseOptions = 2
optsForContext := make([]UIOption, 0, len(opts)+baseOptions)
optsForContext = append(optsForContext,
WithUIBasePath(c.BasePath()),
WithUITitle(title),
}
)
optsForContext = append(optsForContext, opts...)
uiOpts := uiOptionsWithDefaults(optsForContext)
+1 -1
View File
@@ -8,7 +8,7 @@ However, Denco is optimized and some features added.
## Features
* Fast (See [go-http-routing-benchmark](https://github.com/naoina/go-http-routing-benchmark))
* [URL patterns](#url-patterns) (`/foo/:bar` and `/foo/*wildcard`)
*[URL patterns](#url-patterns) (`/foo/:bar` and `/foo/*wildcard`)
* Small (but enough) URL router API
* HTTP request multiplexer like `http.ServeMux`
+7 -5
View File
@@ -1,5 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
// SPDX-License-Identifier: MIT
// Package denco provides fast URL router.
package denco
@@ -24,7 +26,7 @@ const (
// SeparatorCharacter separates path segments.
SeparatorCharacter = '/'
// PathParamCharacter indicates a RESTCONF path param
// PathParamCharacter indicates a RESTCONF path param.
PathParamCharacter = '='
// MaxSize is max size of records and internal slice.
@@ -52,7 +54,7 @@ func New() *Router {
}
// Lookup returns data and path parameters that associated with path.
// params is a slice of the Param that arranged in the order in which parameters appeared.
// params is a slice of the [Param] that arranged in the order in which parameters appeared.
// e.g. when built routing path is "/path/to/:id/:name" and given path is "/path/to/1/alice". params order is [{"id": "1"}, {"name": "alice"}], not [{"name": "alice"}, {"id": "1"}].
func (rt *Router) Lookup(path string) (data any, params Params, found bool) {
if data, found = rt.static[path]; found {
@@ -138,7 +140,7 @@ func newDoubleArray() *doubleArray {
// BASE (22bit) | Extra flags (2bit) | CHECK (8bit)
//
// |----------------------|--|--------|
// 32 10 8 0
// 32 10 8 0.
type baseCheck uint32
const (
@@ -155,7 +157,7 @@ func (bc *baseCheck) SetBase(base int) {
}
func (bc baseCheck) Check() byte {
return byte(bc)
return byte(bc) //nolint:gosec // integer conversion is ok
}
func (bc *baseCheck) SetCheck(check byte) {
@@ -212,7 +214,7 @@ func (da *doubleArray) lookup(path string, params []Param, idx int) (*node, []Pa
BACKTRACKING:
for j := len(indices) - 1; j >= 0; j-- {
i, idx := int(indices[j]>>indexOffset), int(indices[j]&indexMask) //nolint:gosec // integer conversion is okay
i, idx := int(indices[j]>>indexOffset), int(indices[j]&indexMask)
if da.bc[idx].IsSingleParam() {
nextIdx := nextIndex(da.bc[idx].Base(), ParamCharacter)
if nextIdx >= len(da.bc) {
+9 -7
View File
@@ -1,5 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
// SPDX-License-Identifier: MIT
package denco
@@ -10,27 +12,27 @@ import (
// Mux represents a multiplexer for HTTP request.
type Mux struct{}
// NewMux returns a new Mux.
// NewMux returns a new [Mux].
func NewMux() *Mux {
return &Mux{}
}
// GET is shorthand of Mux.Handler("GET", path, handler).
// GET is shorthand of [Mux].Handler("GET", path, handler).
func (m *Mux) GET(path string, handler HandlerFunc) Handler {
return m.Handler("GET", path, handler)
}
// POST is shorthand of Mux.Handler("POST", path, handler).
// POST is shorthand of [Mux].Handler("POST", path, handler).
func (m *Mux) POST(path string, handler HandlerFunc) Handler {
return m.Handler("POST", path, handler)
}
// PUT is shorthand of Mux.Handler("PUT", path, handler).
// PUT is shorthand of [Mux].Handler("PUT", path, handler).
func (m *Mux) PUT(path string, handler HandlerFunc) Handler {
return m.Handler("PUT", path, handler)
}
// HEAD is shorthand of Mux.Handler("HEAD", path, handler).
// HEAD is shorthand of [Mux].Handler("HEAD", path, handler).
func (m *Mux) HEAD(path string, handler HandlerFunc) Handler {
return m.Handler("HEAD", path, handler)
}
@@ -44,7 +46,7 @@ func (m *Mux) Handler(method, path string, handler HandlerFunc) Handler {
}
}
// Build builds a http.Handler.
// Build builds a [http.Handler].
func (m *Mux) Build(handlers []Handler) (http.Handler, error) {
recordMap := make(map[string][]Record)
for _, h := range handlers {
@@ -73,7 +75,7 @@ type Handler struct {
Func HandlerFunc
}
// The HandlerFunc type is aliased to type of handler function.
// HandlerFunc is aliased to type of handler function.
type HandlerFunc func(w http.ResponseWriter, r *http.Request, params Params)
type serveMux struct {
+2
View File
@@ -1,5 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
// SPDX-License-Identifier: MIT
package denco
+46 -48
View File
@@ -1,52 +1,50 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
/*
Package middleware provides the library with helper functions for serving swagger APIs.
Pseudo middleware handler
import (
"net/http"
"github.com/go-openapi/errors"
)
func newCompleteMiddleware(ctx *Context) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
// use context to lookup routes
if matched, ok := ctx.RouteInfo(r); ok {
if matched.NeedsAuth() {
if _, err := ctx.Authorize(r, matched); err != nil {
ctx.Respond(rw, r, matched.Produces, matched, err)
return
}
}
bound, validation := ctx.BindAndValidate(r, matched)
if validation != nil {
ctx.Respond(rw, r, matched.Produces, matched, validation)
return
}
result, err := matched.Handler.Handle(bound)
if err != nil {
ctx.Respond(rw, r, matched.Produces, matched, err)
return
}
ctx.Respond(rw, r, matched.Produces, matched, result)
return
}
// Not found, check if it exists in the other methods first
if others := ctx.AllowedMethods(r); len(others) > 0 {
ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
return
}
ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.Path))
})
}
*/
// Package middleware provides the library with helper functions for serving swagger APIs.
//
// Pseudo middleware handler.
//
// import (
// "net/http"
//
// "github.com/go-openapi/errors"
// )
//
// func newCompleteMiddleware(ctx *Context) http.Handler {
// return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
// // use context to lookup routes
// if matched, ok := ctx.RouteInfo(r); ok {
//
// if matched.NeedsAuth() {
// if _, err := ctx.Authorize(r, matched); err != nil {
// ctx.Respond(rw, r, matched.Produces, matched, err)
// return
// }
// }
//
// bound, validation := ctx.BindAndValidate(r, matched)
// if validation != nil {
// ctx.Respond(rw, r, matched.Produces, matched, validation)
// return
// }
//
// result, err := matched.Handler.Handle(bound)
// if err != nil {
// ctx.Respond(rw, r, matched.Produces, matched, err)
// return
// }
//
// ctx.Respond(rw, r, matched.Produces, matched, result)
// return
// }
//
// // Not found, check if it exists in the other methods first
// if others := ctx.AllowedMethods(r); len(others) > 0 {
// ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
// return
// }
// ctx.Respond(rw, r, ctx.spec.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.Path))
// })
// }
package middleware
+2 -2
View File
@@ -31,13 +31,13 @@ func (e *errorResp) WriteResponse(rw http.ResponseWriter, producer runtime.Produ
}
}
// NotImplemented the error response when the response is not implemented
// NotImplemented the error response when the response is not implemented.
func NotImplemented(message string) Responder {
return Error(http.StatusNotImplemented, message)
}
// Error creates a generic responder for returning errors, the data will be serialized
// with the matching producer for the request
// with the matching producer for the request.
func Error(code int, data any, headers ...http.Header) Responder {
var hdr http.Header
for _, h := range headers {
+1 -1
View File
@@ -5,7 +5,7 @@ package middleware
import "net/http"
// NewOperationExecutor creates a context aware middleware that handles the operations after routing
// NewOperationExecutor creates a context aware [middleware] that handles the operations after routing.
func NewOperationExecutor(ctx *Context) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
// use context to lookup routes
+1 -1
View File
@@ -28,7 +28,7 @@ const (
typeArray = "array"
)
var textUnmarshalType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
var textUnmarshalType = reflect.TypeFor[encoding.TextUnmarshaler]()
func newUntypedParamBinder(param spec.Parameter, spec *spec.Swagger, formats strfmt.Registry) *untypedParamBinder {
binder := new(untypedParamBinder)
+3 -3
View File
@@ -11,7 +11,7 @@ import (
"path"
)
// RapiDocOpts configures the RapiDoc middlewares
// RapiDocOpts configures the [RapiDoc] middlewares.
type RapiDocOpts struct {
// BasePath for the UI, defaults to: /
BasePath string
@@ -50,9 +50,9 @@ func (r *RapiDocOpts) EnsureDefaults() {
}
}
// RapiDoc creates a middleware to serve a documentation site for a swagger spec.
// RapiDoc creates a [middleware] to serve a documentation site for a swagger spec.
//
// This allows for altering the spec before starting the http listener.
// This allows for altering the spec before starting the [http] listener.
func RapiDoc(opts RapiDocOpts, next http.Handler) http.Handler {
opts.EnsureDefaults()
+4 -4
View File
@@ -11,7 +11,7 @@ import (
"path"
)
// RedocOpts configures the Redoc middlewares
// RedocOpts configures the [Redoc] middlewares.
type RedocOpts struct {
// BasePath for the UI, defaults to: /
BasePath string
@@ -36,7 +36,7 @@ type RedocOpts struct {
RedocURL string
}
// EnsureDefaults in case some options are missing
// EnsureDefaults in case some options are missing.
func (r *RedocOpts) EnsureDefaults() {
common := toCommonUIOptions(r)
common.EnsureDefaults()
@@ -51,9 +51,9 @@ func (r *RedocOpts) EnsureDefaults() {
}
}
// Redoc creates a middleware to serve a documentation site for a swagger spec.
// Redoc creates a [middleware] to serve a documentation site for a swagger spec.
//
// This allows for altering the spec before starting the http listener.
// This allows for altering the spec before starting the [http] listener.
func Redoc(opts RedocOpts, next http.Handler) http.Handler {
opts.EnsureDefaults()
+2 -2
View File
@@ -14,7 +14,7 @@ import (
"github.com/go-openapi/strfmt"
)
// UntypedRequestBinder binds and validates the data from a http request
// UntypedRequestBinder binds and validates the data from a [http] request.
type UntypedRequestBinder struct {
Spec *spec.Swagger
Parameters map[string]spec.Parameter
@@ -38,7 +38,7 @@ func NewUntypedRequestBinder(parameters map[string]spec.Parameter, spec *spec.Sw
}
}
// Bind perform the databinding and validation
// Bind perform the databinding and validation.
func (o *UntypedRequestBinder) Bind(request *http.Request, routeParams RouteParams, consumer runtime.Consumer, data any) error {
val := reflect.Indirect(reflect.ValueOf(data))
isMap := val.Kind() == reflect.Map
+26 -22
View File
@@ -25,16 +25,16 @@ import (
// RouteParam is a object to capture route params in a framework agnostic way.
// implementations of the muxer should use these route params to communicate with the
// swagger framework
// swagger framework.
type RouteParam struct {
Name string
Value string
}
// RouteParams the collection of route params
// RouteParams the collection of route params.
type RouteParams []RouteParam
// Get gets the value for the route param for the specified key
// Get gets the value for the route param for the specified key.
func (r RouteParams) Get(name string) string {
vv, _, _ := r.GetOK(name)
if len(vv) > 0 {
@@ -44,9 +44,9 @@ func (r RouteParams) Get(name string) string {
}
// GetOK gets the value but also returns booleans to indicate if a key or value
// is present. This aids in validation and satisfies an interface in use there
// is present. This aids in validation and satisfies an interface in use there.
//
// The returned values are: data, has key, has value
// The returned values are: data, has key, has value.
func (r RouteParams) GetOK(name string) ([]string, bool, bool) {
for _, p := range r {
if p.Name == name {
@@ -56,7 +56,7 @@ func (r RouteParams) GetOK(name string) ([]string, bool, bool) {
return nil, false, false
}
// NewRouter creates a new context-aware router middleware
// NewRouter creates a new context-aware router [middleware].
func NewRouter(ctx *Context, next http.Handler) http.Handler {
if ctx.router == nil {
ctx.router = DefaultRouter(ctx.spec, ctx.api, WithDefaultRouterLoggerFunc(ctx.debugLogf))
@@ -68,18 +68,22 @@ func NewRouter(ctx *Context, next http.Handler) http.Handler {
return
}
// Always use the default producer Content-Type for Method not
// allowed and Not found responses
produces := []string{ctx.api.DefaultProduces()}
// Not found, check if it exists in the other methods first
if others := ctx.AllowedMethods(r); len(others) > 0 {
ctx.Respond(rw, r, ctx.analyzer.RequiredProduces(), nil, errors.MethodNotAllowed(r.Method, others))
ctx.Respond(rw, r, produces, nil, errors.MethodNotAllowed(r.Method, others))
return
}
ctx.Respond(rw, r, ctx.analyzer.RequiredProduces(), nil, errors.NotFound("path %s was not found", r.URL.EscapedPath()))
ctx.Respond(rw, r, produces, nil, errors.NotFound("path %s was not found", r.URL.EscapedPath()))
})
}
// RoutableAPI represents an interface for things that can serve
// as a provider of implementations for the swagger router
// as a provider of implementations for the swagger router.
type RoutableAPI interface {
HandlerFor(string, string) (http.Handler, bool)
ServeErrorFor(string) func(http.ResponseWriter, *http.Request, error)
@@ -92,7 +96,7 @@ type RoutableAPI interface {
DefaultConsumes() string
}
// Router represents a swagger-aware router
// Router represents a swagger-aware router.
type Router interface {
Lookup(method, path string) (*MatchedRoute, bool)
OtherMethods(method, path string) []string
@@ -153,7 +157,7 @@ func WithDefaultRouterLoggerFunc(fn func(string, ...any)) DefaultRouterOpt {
}
}
// DefaultRouter creates a default implementation of the router
// DefaultRouter creates a default implementation of the router.
func DefaultRouter(spec *loads.Document, api RoutableAPI, opts ...DefaultRouterOpt) Router {
builder := newDefaultRouteBuilder(spec, api, opts...)
if spec != nil {
@@ -170,7 +174,7 @@ func DefaultRouter(spec *loads.Document, api RoutableAPI, opts ...DefaultRouterO
// RouteAuthenticator is an authenticator that can compose several authenticators together.
// It also knows when it contains an authenticator that allows for anonymous pass through.
// Contains a group of 1 or more authenticators that have a logical AND relationship
// Contains a group of 1 or more authenticators that have a logical AND relationship.
type RouteAuthenticator struct {
Authenticator map[string]runtime.Authenticator
Schemes []string
@@ -185,18 +189,18 @@ func (ra *RouteAuthenticator) AllowsAnonymous() bool {
}
// AllScopes returns a list of unique scopes that is the combination
// of all the scopes in the requirements
// of all the scopes in the requirements.
func (ra *RouteAuthenticator) AllScopes() []string {
return ra.allScopes
}
// CommonScopes returns a list of unique scopes that are common in all the
// scopes in the requirements
// scopes in the requirements.
func (ra *RouteAuthenticator) CommonScopes() []string {
return ra.commonScopes
}
// Authenticate Authenticator interface implementation
// Authenticate Authenticator interface implementation.
func (ra *RouteAuthenticator) Authenticate(req *http.Request, route *MatchedRoute) (bool, any, error) {
if ra.allowAnonymous {
route.Authenticator = ra
@@ -262,10 +266,10 @@ func stringSliceIntersection(slices ...[]string) []string {
return intersection
}
// RouteAuthenticators represents a group of authenticators that represent a logical OR
// RouteAuthenticators represents a group of authenticators that represent a logical OR.
type RouteAuthenticators []RouteAuthenticator
// AllowsAnonymous returns true when there is an authenticator that means optional auth
// AllowsAnonymous returns true when there is an authenticator that means optional auth.
func (ras RouteAuthenticators) AllowsAnonymous() bool {
for _, ra := range ras {
if ra.AllowsAnonymous() {
@@ -275,7 +279,7 @@ func (ras RouteAuthenticators) AllowsAnonymous() bool {
return false
}
// Authenticate method implemention so this collection can be used as authenticator
// Authenticate method implementation so this collection can be used as authenticator.
func (ras RouteAuthenticators) Authenticate(req *http.Request, route *MatchedRoute) (bool, any, error) {
var lastError error
var allowsAnon bool
@@ -320,7 +324,7 @@ type routeEntry struct {
Authorizer runtime.Authorizer
}
// MatchedRoute represents the route that was matched in this request
// MatchedRoute represents the route that was matched in this request.
type MatchedRoute struct {
routeEntry
@@ -330,13 +334,13 @@ type MatchedRoute struct {
Authenticator *RouteAuthenticator
}
// HasAuth returns true when the route has a security requirement defined
// HasAuth returns true when the route has a security requirement defined.
func (m *MatchedRoute) HasAuth() bool {
return len(m.Authenticators) > 0
}
// NeedsAuth returns true when the request still
// needs to perform authentication
// needs to perform authentication.
func (m *MatchedRoute) NeedsAuth() bool {
return m.HasAuth() && m.Authenticator == nil
}
@@ -407,7 +411,7 @@ func (d *defaultRouter) SetLogger(lg logger.Logger) {
d.debugLogf = debugLogfFunc(lg)
}
// convert swagger parameters per path segment into a denco parameter as multiple parameters per segment are not supported in denco
// convert swagger parameters per path segment into a denco parameter as multiple parameters per segment are not supported in denco.
var pathConverter = regexp.MustCompile(`{(.+?)}([^/]*)`)
func decodeCompositParams(name string, value string, pattern string, names []string, values []string) ([]string, []string) {
+6 -6
View File
@@ -13,7 +13,7 @@ const (
applicationJSON = "application/json"
)
// SpecOption can be applied to the Spec serving middleware
// SpecOption can be applied to the Spec serving [middleware].
type SpecOption func(*specOptions)
var defaultSpecOptions = specOptions{
@@ -35,12 +35,12 @@ func specOptionsWithDefaults(opts []SpecOption) specOptions {
return o
}
// Spec creates a middleware to serve a swagger spec as a JSON document.
// Spec creates a [middleware] to serve a swagger spec as a JSON document.
//
// This allows for altering the spec before starting the http listener.
// This allows for altering the spec before starting the [http] listener.
//
// The basePath argument indicates the path of the spec document (defaults to "/").
// Additional SpecOption can be used to change the name of the document (defaults to "swagger.json").
// Additional [SpecOption] can be used to change the name of the document (defaults to "swagger.json").
func Spec(basePath string, b []byte, next http.Handler, opts ...SpecOption) http.Handler {
if basePath == "" {
basePath = "/"
@@ -68,7 +68,7 @@ func Spec(basePath string, b []byte, next http.Handler, opts ...SpecOption) http
})
}
// WithSpecPath sets the path to be joined to the base path of the Spec middleware.
// WithSpecPath sets the path to be joined to the base path of the Spec [middleware].
//
// This is empty by default.
func WithSpecPath(pth string) SpecOption {
@@ -79,7 +79,7 @@ func WithSpecPath(pth string) SpecOption {
// WithSpecDocument sets the name of the JSON document served as a spec.
//
// By default, this is "swagger.json"
// By default, this is "swagger.json".
func WithSpecDocument(doc string) SpecOption {
return func(o *specOptions) {
if doc == "" {
+4 -4
View File
@@ -11,7 +11,7 @@ import (
"path"
)
// SwaggerUIOpts configures the SwaggerUI middleware
// SwaggerUIOpts configures the [SwaggerUI] [middleware].
type SwaggerUIOpts struct {
// BasePath for the API, defaults to: /
BasePath string
@@ -47,7 +47,7 @@ type SwaggerUIOpts struct {
Favicon16 string
}
// EnsureDefaults in case some options are missing
// EnsureDefaults in case some options are missing.
func (r *SwaggerUIOpts) EnsureDefaults() {
r.ensureDefaults()
@@ -90,9 +90,9 @@ func (r *SwaggerUIOpts) ensureDefaults() {
}
}
// SwaggerUI creates a middleware to serve a documentation site for a swagger spec.
// SwaggerUI creates a [middleware] to serve a documentation site for a swagger spec.
//
// This allows for altering the spec before starting the http listener.
// This allows for altering the spec before starting the [http] listener.
func SwaggerUI(opts SwaggerUIOpts, next http.Handler) http.Handler {
opts.EnsureDefaults()
+8 -8
View File
@@ -13,7 +13,7 @@ import (
)
const (
// constants that are common to all UI-serving middlewares
// constants that are common to all UI-serving middlewares.
defaultDocsPath = "docs"
defaultDocsURL = "/swagger.json"
defaultDocsTitle = "API Documentation"
@@ -75,8 +75,8 @@ func fromCommonToAnyOptions[T any](source uiOptions, target *T) {
}
}
// UIOption can be applied to UI serving middleware, such as Context.APIHandler or
// Context.APIHandlerSwaggerUI to alter the defaut behavior.
// UIOption can be applied to UI serving [middleware], such as Context.[APIHandler] or
// Context.[APIHandlerSwaggerUI] to alter the default behavior.
type UIOption func(*uiOptions)
func uiOptionsWithDefaults(opts []UIOption) uiOptions {
@@ -90,7 +90,7 @@ func uiOptionsWithDefaults(opts []UIOption) uiOptions {
// WithUIBasePath sets the base path from where to serve the UI assets.
//
// By default, Context middleware sets this value to the API base path.
// By default, Context [middleware] sets this value to the API base path.
func WithUIBasePath(base string) UIOption {
return func(o *uiOptions) {
if !strings.HasPrefix(base, "/") {
@@ -111,7 +111,7 @@ func WithUIPath(pth string) UIOption {
//
// This may be specified as a full URL or a path.
//
// By default, this is "/swagger.json"
// By default, this is "/swagger.json".
func WithUISpecURL(specURL string) UIOption {
return func(o *uiOptions) {
o.SpecURL = specURL
@@ -120,7 +120,7 @@ func WithUISpecURL(specURL string) UIOption {
// WithUITitle sets the title of the UI.
//
// By default, Context middleware sets this value to the title found in the API spec.
// By default, Context [middleware] sets this value to the title found in the API spec.
func WithUITitle(title string) UIOption {
return func(o *uiOptions) {
o.Title = title
@@ -129,14 +129,14 @@ func WithUITitle(title string) UIOption {
// WithTemplate allows to set a custom template for the UI.
//
// UI middleware will panic if the template does not parse or execute properly.
// UI [middleware] will panic if the template does not parse or execute properly.
func WithTemplate(tpl string) UIOption {
return func(o *uiOptions) {
o.Template = tpl
}
}
// EnsureDefaults in case some options are missing
// EnsureDefaults in case some options are missing.
func (r *uiOptions) EnsureDefaults() {
if r.BasePath == "" {
r.BasePath = "/"
+17 -17
View File
@@ -23,7 +23,7 @@ const (
mediumPreallocatedSlots = 30
)
// API represents an untyped mux for a swagger spec
// API represents an untyped mux for a swagger spec.
type API struct {
spec *loads.Document
analyzer *analysis.Spec
@@ -39,7 +39,7 @@ type API struct {
formats strfmt.Registry
}
// NewAPI creates the default untyped API
// NewAPI creates the default untyped API.
func NewAPI(spec *loads.Document) *API {
var an *analysis.Spec
if spec != nil && spec.Spec() != nil {
@@ -60,7 +60,7 @@ func NewAPI(spec *loads.Document) *API {
return api.WithJSONDefaults()
}
// WithJSONDefaults loads the json defaults for this api
// WithJSONDefaults loads the json defaults for this api.
func (d *API) WithJSONDefaults() *API {
d.DefaultConsumes = runtime.JSONMime
d.DefaultProduces = runtime.JSONMime
@@ -69,7 +69,7 @@ func (d *API) WithJSONDefaults() *API {
return d
}
// WithoutJSONDefaults clears the json defaults for this api
// WithoutJSONDefaults clears the json defaults for this api.
func (d *API) WithoutJSONDefaults() *API {
d.DefaultConsumes = ""
d.DefaultProduces = ""
@@ -78,7 +78,7 @@ func (d *API) WithoutJSONDefaults() *API {
return d
}
// Formats returns the registered string formats
// Formats returns the registered string formats.
func (d *API) Formats() strfmt.Registry {
if d.formats == nil {
d.formats = strfmt.NewFormats()
@@ -86,7 +86,7 @@ func (d *API) Formats() strfmt.Registry {
return d.formats
}
// RegisterFormat registers a custom format validator
// RegisterFormat registers a custom format validator.
func (d *API) RegisterFormat(name string, format strfmt.Format, validator strfmt.Validator) {
if d.formats == nil {
d.formats = strfmt.NewFormats()
@@ -94,7 +94,7 @@ func (d *API) RegisterFormat(name string, format strfmt.Format, validator strfmt
d.formats.Add(name, format, validator)
}
// RegisterAuth registers an auth handler in this api
// RegisterAuth registers an auth handler in this api.
func (d *API) RegisterAuth(scheme string, handler runtime.Authenticator) {
if d.authenticators == nil {
d.authenticators = make(map[string]runtime.Authenticator)
@@ -102,7 +102,7 @@ func (d *API) RegisterAuth(scheme string, handler runtime.Authenticator) {
d.authenticators[scheme] = handler
}
// RegisterAuthorizer registers an authorizer handler in this api
// RegisterAuthorizer registers an authorizer handler in this api.
func (d *API) RegisterAuthorizer(handler runtime.Authorizer) {
d.authorizer = handler
}
@@ -115,7 +115,7 @@ func (d *API) RegisterConsumer(mediaType string, handler runtime.Consumer) {
d.consumers[strings.ToLower(mediaType)] = handler
}
// RegisterProducer registers a producer for a media type
// RegisterProducer registers a producer for a media type.
func (d *API) RegisterProducer(mediaType string, handler runtime.Producer) {
if d.producers == nil {
d.producers = make(map[string]runtime.Producer, smallPreallocatedSlots)
@@ -123,7 +123,7 @@ func (d *API) RegisterProducer(mediaType string, handler runtime.Producer) {
d.producers[strings.ToLower(mediaType)] = handler
}
// RegisterOperation registers an operation handler for an operation name
// RegisterOperation registers an operation handler for an operation name.
func (d *API) RegisterOperation(method, path string, handler runtime.OperationHandler) {
if d.operations == nil {
d.operations = make(map[string]map[string]runtime.OperationHandler, mediumPreallocatedSlots)
@@ -135,7 +135,7 @@ func (d *API) RegisterOperation(method, path string, handler runtime.OperationHa
d.operations[um][path] = handler
}
// OperationHandlerFor returns the operation handler for the specified id if it can be found
// OperationHandlerFor returns the operation handler for the specified id if it can be found.
func (d *API) OperationHandlerFor(method, path string) (runtime.OperationHandler, bool) {
if d.operations == nil {
return nil, false
@@ -147,7 +147,7 @@ func (d *API) OperationHandlerFor(method, path string) (runtime.OperationHandler
return nil, false
}
// ConsumersFor gets the consumers for the specified media types
// ConsumersFor gets the consumers for the specified media types.
func (d *API) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
result := make(map[string]runtime.Consumer)
for _, mt := range mediaTypes {
@@ -158,7 +158,7 @@ func (d *API) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer {
return result
}
// ProducersFor gets the producers for the specified media types
// ProducersFor gets the producers for the specified media types.
func (d *API) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
result := make(map[string]runtime.Producer)
for _, mt := range mediaTypes {
@@ -169,7 +169,7 @@ func (d *API) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
return result
}
// AuthenticatorsFor gets the authenticators for the specified security schemes
// AuthenticatorsFor gets the authenticators for the specified security schemes.
func (d *API) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator {
result := make(map[string]runtime.Authenticator)
for k := range schemes {
@@ -180,17 +180,17 @@ func (d *API) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[stri
return result
}
// Authorizer returns the registered authorizer
// Authorizer returns the registered authorizer.
func (d *API) Authorizer() runtime.Authorizer {
return d.authorizer
}
// Validate validates this API for any missing items
// Validate validates this API for any missing items.
func (d *API) Validate() error {
return d.validate()
}
// validateWith validates the registrations in this API against the provided spec analyzer
// validateWith validates the registrations in this API against the provided spec analyzer.
func (d *API) validate() error {
consumes := make([]string, 0, len(d.consumers))
for k := range d.consumers {
+1 -1
View File
@@ -21,7 +21,7 @@ type validation struct {
bound map[string]any
}
// ContentType validates the content type of a request
// ContentType validates the content type of a request.
func validateContentType(allowed []string, actual string) error {
if len(allowed) == 0 {
return nil
+9 -9
View File
@@ -14,25 +14,25 @@ import (
"github.com/go-openapi/swag/stringutils"
)
// CanHaveBody returns true if this method can have a body
// CanHaveBody returns true if this method can have a body.
func CanHaveBody(method string) bool {
mn := strings.ToUpper(method)
return mn == "POST" || mn == "PUT" || mn == "PATCH" || mn == "DELETE"
}
// IsSafe returns true if this is a request with a safe method
// IsSafe returns true if this is a request with a safe method.
func IsSafe(r *http.Request) bool {
mn := strings.ToUpper(r.Method)
return mn == "GET" || mn == "HEAD"
}
// AllowsBody returns true if the request allows for a body
// AllowsBody returns true if the request allows for a body.
func AllowsBody(r *http.Request) bool {
mn := strings.ToUpper(r.Method)
return mn != "HEAD"
}
// HasBody returns true if this method needs a content-type
// HasBody returns true if this method needs a content-type.
func HasBody(r *http.Request) bool {
// happy case: we have a content length set
if r.ContentLength > 0 {
@@ -104,9 +104,9 @@ func (p *peekingReader) Close() error {
return nil
}
// JSONRequest creates a new http request with json headers set.
// JSONRequest creates a new [http] request with json headers set.
//
// It uses context.Background.
// It uses [context.Background].
func JSONRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
req, err := http.NewRequestWithContext(context.Background(), method, urlStr, body)
if err != nil {
@@ -117,12 +117,12 @@ func JSONRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
return req, nil
}
// Gettable for things with a method GetOK(string) (data string, hasKey bool, hasValue bool)
// Gettable for things with a method [GetOK](string) (data string, hasKey bool, hasValue bool).
type Gettable interface {
GetOK(string) ([]string, bool, bool)
}
// ReadSingleValue reads a single value from the source
// ReadSingleValue reads a single value from the source.
func ReadSingleValue(values Gettable, name string) string {
vv, _, hv := values.GetOK(name)
if hv {
@@ -131,7 +131,7 @@ func ReadSingleValue(values Gettable, name string) string {
return ""
}
// ReadCollectionValue reads a collection value from a string data source
// ReadCollectionValue reads a collection value from a string data source.
func ReadCollectionValue(values Gettable, name, collectionFormat string) []string {
v := ReadSingleValue(values, name)
return stringutils.SplitByFormat(v, collectionFormat)
+18 -18
View File
@@ -19,7 +19,7 @@ const (
accessTokenParam = "access_token"
)
// HttpAuthenticator is a function that authenticates a HTTP request
// HttpAuthenticator is a function that authenticates a HTTP request.
func HttpAuthenticator(handler func(*http.Request) (bool, any, error)) runtime.Authenticator { //nolint:revive
return runtime.AuthenticatorFunc(func(params any) (bool, any, error) {
if request, ok := params.(*http.Request); ok {
@@ -32,7 +32,7 @@ func HttpAuthenticator(handler func(*http.Request) (bool, any, error)) runtime.A
})
}
// ScopedAuthenticator is a function that authenticates a HTTP request against a list of valid scopes
// ScopedAuthenticator is a function that authenticates a HTTP request against a list of valid scopes.
func ScopedAuthenticator(handler func(*ScopedAuthRequest) (bool, any, error)) runtime.Authenticator {
return runtime.AuthenticatorFunc(func(params any) (bool, any, error) {
if request, ok := params.(*ScopedAuthRequest); ok {
@@ -42,22 +42,22 @@ func ScopedAuthenticator(handler func(*ScopedAuthRequest) (bool, any, error)) ru
})
}
// UserPassAuthentication authentication function
// UserPassAuthentication authentication function.
type UserPassAuthentication func(string, string) (any, error)
// UserPassAuthenticationCtx authentication function with context.Context
// UserPassAuthenticationCtx authentication function with [context.Context].
type UserPassAuthenticationCtx func(context.Context, string, string) (context.Context, any, error)
// TokenAuthentication authentication function
// TokenAuthentication authentication function.
type TokenAuthentication func(string) (any, error)
// TokenAuthenticationCtx authentication function with context.Context
// TokenAuthenticationCtx authentication function with [context.Context].
type TokenAuthenticationCtx func(context.Context, string) (context.Context, any, error)
// ScopedTokenAuthentication authentication function
// ScopedTokenAuthentication authentication function.
type ScopedTokenAuthentication func(string, []string) (any, error)
// ScopedTokenAuthenticationCtx authentication function with context.Context
// ScopedTokenAuthenticationCtx authentication function with [context.Context].
type ScopedTokenAuthenticationCtx func(context.Context, string, []string) (context.Context, any, error)
var DefaultRealmName = "API"
@@ -93,12 +93,12 @@ func OAuth2SchemeNameCtx(ctx context.Context) string {
return v
}
// BasicAuth creates a basic auth authenticator with the provided authentication function
// BasicAuth creates a basic auth authenticator with the provided authentication function.
func BasicAuth(authenticate UserPassAuthentication) runtime.Authenticator {
return BasicAuthRealm(DefaultRealmName, authenticate)
}
// BasicAuthRealm creates a basic auth authenticator with the provided authentication function and realm name
// BasicAuthRealm creates a basic auth authenticator with the provided authentication function and realm name.
func BasicAuthRealm(realm string, authenticate UserPassAuthentication) runtime.Authenticator {
if realm == "" {
realm = DefaultRealmName
@@ -117,12 +117,12 @@ func BasicAuthRealm(realm string, authenticate UserPassAuthentication) runtime.A
})
}
// BasicAuthCtx creates a basic auth authenticator with the provided authentication function with support for context.Context
// BasicAuthCtx creates a basic auth authenticator with the provided authentication function with support for [context.Context].
func BasicAuthCtx(authenticate UserPassAuthenticationCtx) runtime.Authenticator {
return BasicAuthRealmCtx(DefaultRealmName, authenticate)
}
// BasicAuthRealmCtx creates a basic auth authenticator with the provided authentication function and realm name with support for context.Context
// BasicAuthRealmCtx creates a basic auth authenticator with the provided authentication function and realm name with support for [context.Context].
func BasicAuthRealmCtx(realm string, authenticate UserPassAuthenticationCtx) runtime.Authenticator {
if realm == "" {
realm = DefaultRealmName
@@ -143,7 +143,7 @@ func BasicAuthRealmCtx(realm string, authenticate UserPassAuthenticationCtx) run
}
// APIKeyAuth creates an authenticator that uses a token for authorization.
// This token can be obtained from either a header or a query string
// This token can be obtained from either a header or a query string.
func APIKeyAuth(name, in string, authenticate TokenAuthentication) runtime.Authenticator {
inl := strings.ToLower(in)
if inl != query && inl != header {
@@ -170,8 +170,8 @@ func APIKeyAuth(name, in string, authenticate TokenAuthentication) runtime.Authe
})
}
// APIKeyAuthCtx creates an authenticator that uses a token for authorization with support for context.Context.
// This token can be obtained from either a header or a query string
// APIKeyAuthCtx creates an authenticator that uses a token for authorization with support for [context.Context].
// This token can be obtained from either a header or a query string.
func APIKeyAuthCtx(name, in string, authenticate TokenAuthenticationCtx) runtime.Authenticator {
inl := strings.ToLower(in)
if inl != query && inl != header {
@@ -199,13 +199,13 @@ func APIKeyAuthCtx(name, in string, authenticate TokenAuthenticationCtx) runtime
})
}
// ScopedAuthRequest contains both a http request and the required scopes for a particular operation
// ScopedAuthRequest contains both a [http] request and the required scopes for a particular operation.
type ScopedAuthRequest struct {
Request *http.Request
RequiredScopes []string
}
// BearerAuth for use with oauth2 flows
// BearerAuth for use with oauth2 flows.
func BearerAuth(name string, authenticate ScopedTokenAuthentication) runtime.Authenticator {
const prefix = "Bearer "
return ScopedAuthenticator(func(r *ScopedAuthRequest) (bool, any, error) {
@@ -235,7 +235,7 @@ func BearerAuth(name string, authenticate ScopedTokenAuthentication) runtime.Aut
})
}
// BearerAuthCtx for use with oauth2 flows with support for context.Context.
// BearerAuthCtx for use with oauth2 flows with support for [context.Context].
func BearerAuthCtx(name string, authenticate ScopedTokenAuthenticationCtx) runtime.Authenticator {
const prefix = "Bearer "
return ScopedAuthenticator(func(r *ScopedAuthRequest) (bool, any, error) {
+2 -2
View File
@@ -9,8 +9,8 @@ import (
"github.com/go-openapi/runtime"
)
// Authorized provides a default implementation of the Authorizer interface where all
// requests are authorized (successful)
// Authorized provides a default implementation of the [Authorizer] interface where all
// requests are authorized (successful).
func Authorized() runtime.Authorizer {
return runtime.AuthorizerFunc(func(_ *http.Request, _ any) error { return nil })
}
+1 -1
View File
@@ -3,7 +3,7 @@
package runtime
// Statuses lists the most common HTTP status codes to default message
// Statuses lists the most common HTTP status codes to default message.
// taken from https://httpstatuses.com/
var Statuses = map[int]string{
100: "Continue",
+2 -2
View File
@@ -14,7 +14,7 @@ import (
"github.com/go-openapi/swag/jsonutils"
)
// TextConsumer creates a new text consumer
// TextConsumer creates a new text consumer.
func TextConsumer() Consumer {
return ConsumerFunc(func(reader io.Reader, data any) error {
if reader == nil {
@@ -56,7 +56,7 @@ func TextConsumer() Consumer {
})
}
// TextProducer creates a new text producer
// TextProducer creates a new text producer.
func TextProducer() Producer {
return ProducerFunc(func(writer io.Writer, data any) error {
if writer == nil {
+1 -1
View File
@@ -3,7 +3,7 @@
package runtime
// Values typically represent parameters on a http request.
// Values typically represent parameters on a [http] request.
type Values map[string][]string
// GetOK returns the values collection for the given key.
+2 -2
View File
@@ -8,7 +8,7 @@ import (
"io"
)
// XMLConsumer creates a new XML consumer
// XMLConsumer creates a new XML consumer.
func XMLConsumer() Consumer {
return ConsumerFunc(func(reader io.Reader, data any) error {
dec := xml.NewDecoder(reader)
@@ -16,7 +16,7 @@ func XMLConsumer() Consumer {
})
}
// XMLProducer creates a new XML producer
// XMLProducer creates a new XML producer.
func XMLProducer() Producer {
return ProducerFunc(func(writer io.Writer, data any) error {
enc := xml.NewEncoder(writer)
+2 -2
View File
@@ -10,7 +10,7 @@ import (
yaml "go.yaml.in/yaml/v3"
)
// YAMLConsumer creates a consumer for yaml data
// YAMLConsumer creates a consumer for [yaml] data.
func YAMLConsumer() runtime.Consumer {
return runtime.ConsumerFunc(func(r io.Reader, v any) error {
dec := yaml.NewDecoder(r)
@@ -18,7 +18,7 @@ func YAMLConsumer() runtime.Consumer {
})
}
// YAMLProducer creates a producer for yaml data
// YAMLProducer creates a producer for [yaml] data.
func YAMLProducer() runtime.Producer {
return runtime.ProducerFunc(func(w io.Writer, v any) error {
enc := yaml.NewEncoder(w)
+2
View File
@@ -3,3 +3,5 @@ vendor
Godeps
.idea
*.out
.mcp.json
.claude/
+4 -2
View File
@@ -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 <ivan+abuse@flanders.co.nz>. 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 [<http://contributor-covenant.org/version/1/4>][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+36
View File
@@ -0,0 +1,36 @@
# Contributors
- Repository: ['go-openapi/swag']
| Total Contributors | Total Contributions |
| --- | --- |
| 24 | 235 |
| Username | All Time Contribution Count | All Commits |
| --- | --- | --- |
| @fredbi | 105 | <https://github.com/go-openapi/swag/commits?author=fredbi> |
| @casualjim | 98 | <https://github.com/go-openapi/swag/commits?author=casualjim> |
| @alexandear | 4 | <https://github.com/go-openapi/swag/commits?author=alexandear> |
| @orisano | 3 | <https://github.com/go-openapi/swag/commits?author=orisano> |
| @reinerRubin | 2 | <https://github.com/go-openapi/swag/commits?author=reinerRubin> |
| @n-inja | 2 | <https://github.com/go-openapi/swag/commits?author=n-inja> |
| @nitinmohan87 | 2 | <https://github.com/go-openapi/swag/commits?author=nitinmohan87> |
| @Neo2308 | 2 | <https://github.com/go-openapi/swag/commits?author=Neo2308> |
| @michaelbowler-form3 | 2 | <https://github.com/go-openapi/swag/commits?author=michaelbowler-form3> |
| @ujjwalsh | 1 | <https://github.com/go-openapi/swag/commits?author=ujjwalsh> |
| @griffin-stewie | 1 | <https://github.com/go-openapi/swag/commits?author=griffin-stewie> |
| @POD666 | 1 | <https://github.com/go-openapi/swag/commits?author=POD666> |
| @pytlesk4 | 1 | <https://github.com/go-openapi/swag/commits?author=pytlesk4> |
| @shirou | 1 | <https://github.com/go-openapi/swag/commits?author=shirou> |
| @seanprince | 1 | <https://github.com/go-openapi/swag/commits?author=seanprince> |
| @petrkotas | 1 | <https://github.com/go-openapi/swag/commits?author=petrkotas> |
| @mszczygiel | 1 | <https://github.com/go-openapi/swag/commits?author=mszczygiel> |
| @sosiska | 1 | <https://github.com/go-openapi/swag/commits?author=sosiska> |
| @kzys | 1 | <https://github.com/go-openapi/swag/commits?author=kzys> |
| @faguirre1 | 1 | <https://github.com/go-openapi/swag/commits?author=faguirre1> |
| @posener | 1 | <https://github.com/go-openapi/swag/commits?author=posener> |
| @diego-fu-hs | 1 | <https://github.com/go-openapi/swag/commits?author=diego-fu-hs> |
| @davidalpert | 1 | <https://github.com/go-openapi/swag/commits?author=davidalpert> |
| @Xe | 1 | <https://github.com/go-openapi/swag/commits?author=Xe> |
_this file was generated by the [Contributors GitHub Action](https://github.com/github/contributors)_
+137 -152
View File
@@ -1,26 +1,60 @@
# Swag [![Build Status](https://github.com/go-openapi/swag/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/swag/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag)
# Swag
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](https://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE)
[![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/swag.svg)](https://pkg.go.dev/github.com/go-openapi/swag)
[![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/swag)](https://goreportcard.com/report/github.com/go-openapi/swag)
<!-- Badges: status -->
[![Tests][test-badge]][test-url] [![Coverage][cov-badge]][cov-url] [![CI vuln scan][vuln-scan-badge]][vuln-scan-url] [![CodeQL][codeql-badge]][codeql-url]
<!-- Badges: release & docker images -->
<!-- Badges: code quality -->
<!-- Badges: license & compliance -->
[![Release][release-badge]][release-url] [![Go Report Card][gocard-badge]][gocard-url] [![CodeFactor Grade][codefactor-badge]][codefactor-url] [![License][license-badge]][license-url]
<!-- Badges: documentation & support -->
<!-- Badges: others & stats -->
[![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]
Package `swag` contains a bunch of helper functions for go-openapi and go-swagger projects.
---
A bunch of helper functions for go-openapi and go-swagger projects.
You may also use it standalone for your projects.
> **NOTE**
> `swag` is one of the foundational building blocks of the go-openapi initiative.
>
> Most repositories in `github.com/go-openapi/...` depend on it in some way.
> And so does our CLI tool `github.com/go-swagger/go-swagger`,
> as well as the code generated by this tool.
* [Contents](#contents)
* [Dependencies](#dependencies)
* [Release Notes](#release-notes)
* [Change log](#change-log)
* [Licensing](#licensing)
* [Note to contributors](#note-to-contributors)
* [TODOs, suggestions and plans](#todos-suggestions-and-plans)
* [Roadmap](#roadmap)
## 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.
## Import this library in your project
```cmd
go get github.com/go-openapi/swag/{module}
```
Or for backward compatibility:
```cmd
go get github.com/go-openapi/swag
```
## Contents
@@ -36,7 +70,7 @@ Child modules will continue to evolve and some new ones may be added in the futu
| `cmdutils` | utilities to work with CLIs ||
| `conv` | type conversion utilities | convert between values and pointers for any types<br />convert from string to builtin types (wraps `strconv`)<br />require `./typeutils` (test dependency)<br /> |
| `fileutils` | file utilities | |
| `jsonname` | JSON utilities | infer JSON names from `go` properties<br /> |
| `jsonname` | JSON utilities | infer JSON names from `go` properties<br /> |
| `jsonutils` | JSON utilities | fast json concatenation<br />read and write JSON from and to dynamic `go` data structures<br />~require `github.com/mailru/easyjson`~<br /> |
| `loading` | file loading | load from file or http<br />require `./yamlutils`<br /> |
| `mangling` | safe name generation | name mangling for `go`<br /> |
@@ -49,84 +83,19 @@ Child modules will continue to evolve and some new ones may be added in the futu
## Dependencies
The root module `github.com/go-openapi/swag` at the repo level maintains a few
The root module `github.com/go-openapi/swag` at the repo level maintains a few
dependencies outside of the standard library.
* YAML utilities depend on `go.yaml.in/yaml/v3`
* JSON utilities depend on their registered adapter module:
* by default, only the standard library is used
* `github.com/mailru/easyjson` is now only a dependency for module
`github.com/go-openapi/swag/jsonutils/adapters/easyjson/json`,
for users willing to import that module.
* integration tests and benchmarks use all the dependencies are published as their own module
* by default, only the standard library is used
* `github.com/mailru/easyjson` is now only a dependency for module
`github.com/go-openapi/swag/jsonutils/adapters/easyjson/json`,
for users willing to import that module.
* integration tests and benchmarks use all the dependencies are published as their own module
* other dependencies are test dependencies drawn from `github.com/stretchr/testify`
## Release notes
### v0.25.4
** mangling**
Bug fix
* [x] mangler may panic with pluralized overlapping initialisms
Tests
* [x] introduced fuzz tests
### v0.25.3
** mangling**
Bug fix
* [x] mangler may panic with pluralized initialisms
### v0.25.2
Minor changes due to internal maintenance that don't affect the behavior of the library.
* [x] removed indirect test dependencies by switching all tests to `go-openapi/testify`,
a fork of `stretch/testify` with zero-dependencies.
* [x] improvements to CI to catch test reports.
* [x] modernized licensing annotations in source code, using the more compact SPDX annotations
rather than the full license terms.
* [x] simplified a bit JSON & YAML testing by using newly available assertions
* started the journey to an OpenSSF score card badge:
* [x] explicited permissions in CI workflows
* [x] published security policy
* pinned dependencies to github actions
* introduced fuzzing in tests
### v0.25.1
* fixes a data race that could occur when using the standard library implementation of a JSON ordered map
### v0.25.0
**New with this release**:
* requires `go1.24`, as iterators are being introduced
* removes the dependency to `mailru/easyjson` by default (#68)
* functionality remains the same, but performance may somewhat degrade for applications
that relied on `easyjson`
* users of the JSON or YAML utilities who want to use `easyjson` as their preferred JSON serializer library
will be able to do so by registering this the corresponding JSON adapter at runtime. See below.
* ordered keys in JSON and YAML objects: this feature used to rely solely on `easyjson`.
With this release, an implementation relying on the standard `encoding/json` is provided.
* an independent [benchmark](./jsonutils/adapters/testintegration/benchmarks/README.md) to compare the different adapters
* improves the "float is integer" check (`conv.IsFloat64AJSONInteger`) (#59)
* removes the _direct_ dependency to `gopkg.in/yaml.v3` (indirect dependency is still incurred through `stretchr/testify`) (#127)
* exposed `conv.IsNil()` (previously kept private): a safe nil check (accounting for the "non-nil interface with nil value" nonsensical go trick)
**What coming next?**
Moving forward, we want to :
* provide an implementation of the JSON adapter based on `encoding/json/v2`, for `go1.25` builds.
* provide similar implementations for `goccy/go-json` and `jsoniterator/go`, and perhaps some other
similar libraries may be interesting too.
## Usage
**How to explicitly register a dependency at runtime**?
@@ -150,90 +119,106 @@ or fallback to the standard library.
For more details, you may also look at our
[integration tests](jsonutils/adapters/testintegration/integration_suite_test.go#29).
### v0.24.0
With this release, we have largely modernized the API of `swag`:
* The traditional `swag` API is still supported: code that imports `swag` will still
compile and work the same.
* A deprecation notice is published to encourage consumers of this library to adopt
the newer API
* **Deprecation notice**
* configuration through global variables is now deprecated, in favor of options passed as parameters
* all helper functions are moved to more specialized packages, which are exposed as
go modules. Importing such a module would reduce the footprint of dependencies.
* _all_ functions, variables, constants exposed by the deprecated API have now moved, so
that consumers of the new API no longer need to import github.com/go-openapi/swag, but
should import the desired sub-module(s).
**New with this release**:
* [x] type converters and pointer to value helpers now support generic types
* [x] name mangling now support pluralized initialisms (issue #46)
Strings like "contact IDs" are now recognized as such a plural form and mangled as a linter would expect.
* [x] performance: small improvements to reduce the overhead of convert/format wrappers (see issues #110, or PR #108)
* [x] performance: name mangling utilities run ~ 10% faster (PR #115)
---
## Note to contributors
All kinds of contributions are welcome.
This repo is a go mono-repo. See [docs](docs/MAINTAINERS.md).
More general guidelines are available [here](.github/CONTRIBUTING.md).
## Roadmap
See the current [TODO list](docs/TODOS.md)
## Change log
See <https://github.com/go-openapi/swag/releases>
For pre-v0.26.0 releases, see [release notes](./docs/NOTES.md).
**What coming next?**
Moving forward, we want to :
* provide an implementation of the JSON adapter based on `encoding/json/v2`, for `go1.25` builds.
* provide similar implementations for `goccy/go-json` and `jsoniterator/go`, and perhaps some other
similar libraries may be interesting too.
<!--
## References
-->
## Licensing
This library ships under the [SPDX-License-Identifier: Apache-2.0](./LICENSE).
## Note to contributors
<!--
See the license [NOTICE](./NOTICE), which recalls the licensing terms of all the pieces of software
on top of which it has been built.
-->
A mono-repo structure comes with some unavoidable extra pains...
<!--
* Testing
## Limitations
> The usual `go test ./...` command, run from the root of this repo won't work any longer to test all submodules.
>
> Each module constitutes an independant unit of test. So you have to run `go test` inside each module.
> Or you may take a look at how this is achieved by CI
> [here] https://github.com/go-openapi/swag/blob/master/.github/workflows/go-test.yml).
>
> There are also some alternative tricks using `go work`, for local development, if you feel comfortable with
> go workspaces. Perhaps some day, we'll have a `go work test` to run all tests without any hack.
-->
* Releasing
## Other documentation
> Each module follows its own independant module versioning.
>
> So you have tags like `mangling/v0.24.0`, `fileutils/v0.24.0` etc that are used by `go mod` and `go get`
> to refer to the tagged version of each module specifically.
>
> This means we may release patches etc to each module independently.
>
> We'd like to adopt the rule that modules in this repo would only differ by a patch version
> (e.g. `v0.24.5` vs `v0.24.3`), and we'll level all modules whenever a minor version is introduced.
>
> A script in `./hack` is provided to tag all modules with the same version in one go.
* [All-time contributors](./CONTRIBUTORS.md)
* [Contributing guidelines](.github/CONTRIBUTING.md)
* [Maintainers documentation](docs/MAINTAINERS.md)
* [Code style](docs/STYLE.md)
* Continuous integration
## Cutting a new release
> At this moment, all tests in all modules are systematically run over the full test matrix (3 platform x 2 go releases).
> This generates quite a lot of jobs.
>
> We ought to reduce the number of jobs required to test a PR focused on only a few modules.
Maintainers can cut a new release by either:
## Todos, suggestions and plans
* running [this workflow](https://github.com/go-openapi/swag/actions/workflows/bump-release.yml)
* or pushing a semver tag
* signed tags are preferred
* The tag message is prepended to release notes
All kinds of contributions are welcome.
<!-- Badges: status -->
[test-badge]: https://github.com/go-openapi/swag/actions/workflows/go-test.yml/badge.svg
[test-url]: https://github.com/go-openapi/swag/actions/workflows/go-test.yml
[cov-badge]: https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg
[cov-url]: https://codecov.io/gh/go-openapi/swag
[vuln-scan-badge]: https://github.com/go-openapi/swag/actions/workflows/scanner.yml/badge.svg
[vuln-scan-url]: https://github.com/go-openapi/swag/actions/workflows/scanner.yml
[codeql-badge]: https://github.com/go-openapi/swag/actions/workflows/codeql.yml/badge.svg
[codeql-url]: https://github.com/go-openapi/swag/actions/workflows/codeql.yml
<!-- Badges: release & docker images -->
[release-badge]: https://badge.fury.io/gh/go-openapi%2Fswag.svg
[release-url]: https://badge.fury.io/gh/go-openapi%2Fswag
[gomod-badge]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fswag.svg
[gomod-url]: https://badge.fury.io/go/github.com%2Fgo-openapi%2Fswag
<!-- Badges: code quality -->
[gocard-badge]: https://goreportcard.com/badge/github.com/go-openapi/swag
[gocard-url]: https://goreportcard.com/report/github.com/go-openapi/swag
[codefactor-badge]: https://img.shields.io/codefactor/grade/github/go-openapi/swag
[codefactor-url]: https://www.codefactor.io/repository/github/go-openapi/swag
<!-- Badges: documentation & support -->
[doc-badge]: https://img.shields.io/badge/doc-site-blue?link=https%3A%2F%2Fgoswagger.io%2Fgo-openapi%2F
[doc-url]: https://goswagger.io/go-openapi
[godoc-badge]: https://pkg.go.dev/badge/github.com/go-openapi/swag
[godoc-url]: http://pkg.go.dev/github.com/go-openapi/swag
[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/twZ9BwT3
A few ideas:
* [x] Complete the split of dependencies to isolate easyjson from the rest
* [x] Improve CI to reduce needed tests
* [x] Replace dependency to `gopkg.in/yaml.v3` (`yamlutil`)
* [ ] Improve mangling utilities (improve readability, support for capitalized words,
better word substitution for non-letter symbols...)
* [ ] Move back to this common shared pot a few of the technical features introduced by go-swagger independently
(e.g. mangle go package names, search package with go modules support, ...)
* [ ] Apply a similar mono-repo approach to go-openapi/strfmt which suffer from similar woes: bloated API,
imposed dependency to some database driver.
* [ ] Adapt `go-swagger` (incl. generated code) to the new `swag` API.
* [ ] Factorize some tests, as there is a lot of redundant testing code in `jsonutils`
* [ ] Benchmark & profiling: publish independently the tool built to analyze and chart benchmarks (e.g. similar to `benchvisual`)
* [ ] more thorough testing for nil / null case
* [ ] ci pipeline to manage releases
* [ ] cleaner mockery generation (doesn't work out of the box for all sub-modules)
<!-- Badges: license & compliance -->
[license-badge]: http://img.shields.io/badge/license-Apache%20v2-orange.svg
[license-url]: https://github.com/go-openapi/swag/?tab=Apache-2.0-1-ov-file#readme
<!-- Badges: others & stats -->
[goversion-badge]: https://img.shields.io/github/go-mod/go-version/go-openapi/swag
[goversion-url]: https://github.com/go-openapi/swag/blob/master/go.mod
[top-badge]: https://img.shields.io/github/languages/top/go-openapi/swag
[commits-badge]: https://img.shields.io/github/commits-since/go-openapi/swag/latest
+17 -8
View File
@@ -192,12 +192,13 @@ func (x *GCPolicy) GetMinFreeSpace() int64 {
}
type BuildkitVersion struct {
state protoimpl.MessageState `protogen:"open.v1"`
Package string `protobuf:"bytes,1,opt,name=package,proto3" json:"package,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
state protoimpl.MessageState `protogen:"open.v1"`
Package string `protobuf:"bytes,1,opt,name=package,proto3" json:"package,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"`
DockerfileVersion string `protobuf:"bytes,4,opt,name=dockerfileVersion,proto3" json:"dockerfileVersion,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *BuildkitVersion) Reset() {
@@ -251,6 +252,13 @@ func (x *BuildkitVersion) GetRevision() string {
return ""
}
func (x *BuildkitVersion) GetDockerfileVersion() string {
if x != nil {
return x.DockerfileVersion
}
return ""
}
type CDIDevice struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
@@ -342,11 +350,12 @@ const file_github_com_moby_buildkit_api_types_worker_proto_rawDesc = "" +
"\afilters\x18\x04 \x03(\tR\afilters\x12$\n" +
"\rreservedSpace\x18\x03 \x01(\x03R\rreservedSpace\x12\"\n" +
"\fmaxUsedSpace\x18\x05 \x01(\x03R\fmaxUsedSpace\x12\"\n" +
"\fminFreeSpace\x18\x06 \x01(\x03R\fminFreeSpace\"a\n" +
"\fminFreeSpace\x18\x06 \x01(\x03R\fminFreeSpace\"\x8f\x01\n" +
"\x0fBuildkitVersion\x12\x18\n" +
"\apackage\x18\x01 \x01(\tR\apackage\x12\x18\n" +
"\aversion\x18\x02 \x01(\tR\aversion\x12\x1a\n" +
"\brevision\x18\x03 \x01(\tR\brevision\"\xef\x01\n" +
"\brevision\x18\x03 \x01(\tR\brevision\x12,\n" +
"\x11dockerfileVersion\x18\x04 \x01(\tR\x11dockerfileVersion\"\xef\x01\n" +
"\tCDIDevice\x12\x12\n" +
"\x04Name\x18\x01 \x01(\tR\x04Name\x12\x1c\n" +
"\tAutoAllow\x18\x02 \x01(\bR\tAutoAllow\x12T\n" +
+2 -1
View File
@@ -30,6 +30,7 @@ message BuildkitVersion {
string package = 1;
string version = 2;
string revision = 3;
string dockerfileVersion = 4;
}
message CDIDevice {
@@ -37,4 +38,4 @@ message CDIDevice {
bool AutoAllow = 2;
map<string, string> Annotations = 3;
bool OnDemand = 4;
}
}
+47
View File
@@ -100,6 +100,7 @@ func (m *BuildkitVersion) CloneVT() *BuildkitVersion {
r.Package = m.Package
r.Version = m.Version
r.Revision = m.Revision
r.DockerfileVersion = m.DockerfileVersion
if len(m.unknownFields) > 0 {
r.unknownFields = make([]byte, len(m.unknownFields))
copy(r.unknownFields, m.unknownFields)
@@ -277,6 +278,9 @@ func (this *BuildkitVersion) EqualVT(that *BuildkitVersion) bool {
if this.Revision != that.Revision {
return false
}
if this.DockerfileVersion != that.DockerfileVersion {
return false
}
return string(this.unknownFields) == string(that.unknownFields)
}
@@ -531,6 +535,13 @@ func (m *BuildkitVersion) MarshalToSizedBufferVT(dAtA []byte) (int, error) {
i -= len(m.unknownFields)
copy(dAtA[i:], m.unknownFields)
}
if len(m.DockerfileVersion) > 0 {
i -= len(m.DockerfileVersion)
copy(dAtA[i:], m.DockerfileVersion)
i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DockerfileVersion)))
i--
dAtA[i] = 0x22
}
if len(m.Revision) > 0 {
i -= len(m.Revision)
copy(dAtA[i:], m.Revision)
@@ -727,6 +738,10 @@ func (m *BuildkitVersion) SizeVT() (n int) {
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
l = len(m.DockerfileVersion)
if l > 0 {
n += 1 + l + protohelpers.SizeOfVarint(uint64(l))
}
n += len(m.unknownFields)
return n
}
@@ -1411,6 +1426,38 @@ func (m *BuildkitVersion) UnmarshalVT(dAtA []byte) error {
}
m.Revision = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field DockerfileVersion", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protohelpers.ErrIntOverflow
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protohelpers.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protohelpers.ErrInvalidLength
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.DockerfileVersion = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := protohelpers.Skip(dAtA[iNdEx:])
+8 -6
View File
@@ -13,9 +13,10 @@ type Info struct {
}
type BuildkitVersion struct {
Package string `json:"package"`
Version string `json:"version"`
Revision string `json:"revision"`
Package string `json:"package"`
Version string `json:"version"`
Revision string `json:"revision"`
DockerfileVersion string `json:"dockerfileVersion,omitempty"`
}
type CDIDevice struct {
@@ -40,9 +41,10 @@ func fromAPIBuildkitVersion(in *apitypes.BuildkitVersion) BuildkitVersion {
return BuildkitVersion{}
}
return BuildkitVersion{
Package: in.Package,
Version: in.Version,
Revision: in.Revision,
Package: in.Package,
Version: in.Version,
Revision: in.Revision,
DockerfileVersion: in.DockerfileVersion,
}
}
+1 -5
View File
@@ -7,10 +7,6 @@ import (
"github.com/pkg/errors"
)
// ErrNoActiveSessions is returned when a session group does not contain any
// active session IDs.
var ErrNoActiveSessions = errors.New("no active sessions")
type Group interface {
SessionIterator() Iterator
}
@@ -73,7 +69,7 @@ func (sm *Manager) Any(ctx context.Context, g Group, f func(context.Context, str
if lastErr != nil {
return lastErr
}
return ErrNoActiveSessions
return errors.Errorf("no active sessions")
}
timeoutCtx, cancel := context.WithCancelCause(ctx)
@@ -206,8 +206,9 @@ func (c ProvenanceConfigSourceSLSA1) Equal(other ProvenanceConfigSourceSLSA1) bo
}
type ProvenanceInternalParametersSLSA1 struct {
BuildConfig *BuildConfig `json:"buildConfig,omitempty"`
BuilderPlatform string `json:"builderPlatform"`
BuildConfig *BuildConfig `json:"buildConfig,omitempty"`
BuilderPlatform string `json:"builderPlatform"`
DockerfileVersion string `json:"dockerfileVersion,omitempty"`
ProvenanceCustomEnv
}
@@ -338,7 +339,8 @@ func (r *RequestProvenance) Equal(other *RequestProvenance) bool {
}
type Environment struct {
Platform string `json:"platform"`
Platform string `json:"platform"`
DockerfileVersion string `json:"dockerfileVersion,omitempty"`
ProvenanceCustomEnv
}
@@ -402,6 +404,7 @@ func (p *ProvenancePredicateSLSA1) ConvertToSLSA02() *ProvenancePredicateSLSA02
Parameters: p.BuildDefinition.ExternalParameters.Request,
Environment: Environment{
Platform: p.BuildDefinition.InternalParameters.BuilderPlatform,
DockerfileVersion: p.BuildDefinition.InternalParameters.DockerfileVersion,
ProvenanceCustomEnv: p.BuildDefinition.InternalParameters.ProvenanceCustomEnv,
},
},
@@ -436,6 +439,7 @@ func (p *ProvenancePredicateSLSA02) ConvertToSLSA1() *ProvenancePredicateSLSA1 {
InternalParameters: ProvenanceInternalParametersSLSA1{
BuildConfig: p.BuildConfig,
BuilderPlatform: p.Invocation.Environment.Platform,
DockerfileVersion: p.Invocation.Environment.DockerfileVersion,
ProvenanceCustomEnv: p.Invocation.Environment.ProvenanceCustomEnv,
},
}
+1 -1
View File
@@ -2,7 +2,7 @@ variable "ROOT_SIGNING_VERSION" {
type = string
# default = "8842feefbb65effea46ff4a0f2b6aad91e685fe9" # expired root
# default = "9d8b5c5e3bed603c80b57fcc316b7a1af688c57e" # expired timestamp
default = "975f28e3597a34098a7c0c07edc16f47420b9aa3"
default = "e88fa609ddf5a177bb46d0f7c9b43d178b9483a3"
description = "The git commit hash of sigstore/root-signing to use for embedded roots."
}
+4 -4
View File
@@ -2,15 +2,15 @@
"signatures": [
{
"keyid": "0c87432c3bf09fd99189fdc32fa5eaedf4e4a5fac7bab73fa04a2e0fc64af6f5",
"sig": "3046022100a42f44341870864aa7e4f94af642ed68e09890aa109d76947276e24f13c315f2022100c3efb5500a4b67cb03a0fe708db32d8f5f151aad4bbacfd6679437e8c5fa5f9f"
"sig": "30460221009aa4bf5821ae1b692da023df898b93d6f676062b4302d2041c5c262632e6bb72022100ea6d61eb8e9e776881a10ec3d5b036ee0def5f96ca1f1eb778083ed27122e57b"
}
],
"signed": {
"_type": "snapshot",
"expires": "2035-11-24T12:02:06Z",
"expires": "2036-05-04T09:04:05Z",
"meta": {
"registry.npmjs.org.json": {
"version": 7
"version": 8
},
"rekor.json": {
"hashes": {
@@ -49,6 +49,6 @@
}
},
"spec_version": "1.0",
"version": 163
"version": 164
}
}
+4 -4
View File
@@ -2,18 +2,18 @@
"signatures": [
{
"keyid": "0c87432c3bf09fd99189fdc32fa5eaedf4e4a5fac7bab73fa04a2e0fc64af6f5",
"sig": "3046022100a6e78ac794442ab5af6268bc68e66a6fbfc04944ae7feb184a35d28a3ed0a9d40221008f1201dc0924583d74321379a2a0ce709f7401ed69b1bd39ee8c0b8919a782b6"
"sig": "3046022100d90699c23313ac72c6afe8d7cae1b6ce887e59ccb8c2a8ba1206fcce81fe9924022100e7e2b9756673bba280acc90c1b6f30fe04d9a2668515efce004ce603c6b0b040"
}
],
"signed": {
"_type": "timestamp",
"expires": "2026-03-31T13:49:52Z",
"expires": "2026-05-14T09:04:06Z",
"meta": {
"snapshot.json": {
"version": 163
"version": 164
}
},
"spec_version": "1.0",
"version": 628
"version": 668
}
}
+2 -2
View File
@@ -62,7 +62,7 @@ type AlgorithmDetails struct {
// The underlying type of these parameters is dependent on the keyType.
// For example, ECDSA algorithms will store an elliptic curve here whereas, RSA keys will store the key size.
// Algorithms that don't require any extra parameters leave this set to nil.
extraKeyParams interface{}
extraKeyParams any
// flagValue is a string representation of the signature algorithm that follows the naming conventions of CLI
// arguments that are used for Sigstore services.
@@ -157,7 +157,7 @@ var supportedAlgorithms = []AlgorithmDetails{
{v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256, RSA, crypto.SHA256, v1.HashAlgorithm_SHA2_256, RSAKeySize(4096), "rsa-sign-pkcs1-4096-sha256"},
{v1.PublicKeyDetails_PKIX_RSA_PSS_2048_SHA256, RSA, crypto.SHA256, v1.HashAlgorithm_SHA2_256, RSAKeySize(2048), "rsa-sign-pss-2048-sha256"},
{v1.PublicKeyDetails_PKIX_RSA_PSS_3072_SHA256, RSA, crypto.SHA256, v1.HashAlgorithm_SHA2_256, RSAKeySize(3072), "rsa-sign-pss-3072-sha256"},
{v1.PublicKeyDetails_PKIX_RSA_PSS_4096_SHA256, RSA, crypto.SHA256, v1.HashAlgorithm_SHA2_256, RSAKeySize(4096), "rsa-sign-pss-4092-sha256"},
{v1.PublicKeyDetails_PKIX_RSA_PSS_4096_SHA256, RSA, crypto.SHA256, v1.HashAlgorithm_SHA2_256, RSAKeySize(4096), "rsa-sign-pss-4096-sha256"},
{v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256, ECDSA, crypto.SHA256, v1.HashAlgorithm_SHA2_256, elliptic.P256(), "ecdsa-sha2-256-nistp256"},
{v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384, ECDSA, crypto.SHA384, v1.HashAlgorithm_SHA2_384, elliptic.P384(), "ecdsa-sha2-384-nistp384"},
{v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_256, ECDSA, crypto.SHA256, v1.HashAlgorithm_SHA2_256, elliptic.P384(), "ecdsa-sha2-256-nistp384"}, //nolint:staticcheck
+2 -6
View File
@@ -21,18 +21,14 @@ import (
"errors"
"fmt"
"io"
"slices"
)
func isSupportedAlg(alg crypto.Hash, supportedAlgs []crypto.Hash) bool {
if supportedAlgs == nil {
return true
}
for _, supportedAlg := range supportedAlgs {
if alg == supportedAlg {
return true
}
}
return false
return slices.Contains(supportedAlgs, alg)
}
// ComputeDigestForSigning calculates the digest value for the specified message using a hash function selected by the following process:
+3 -3
View File
@@ -29,8 +29,8 @@ const CosignSignatureType = "cosign container image signature"
// SimpleContainerImage describes the structure of a basic container image signature payload, as defined at:
// https://github.com/containers/image/blob/main/docs/containers-signature.5.md#json-data-format
type SimpleContainerImage struct {
Critical Critical `json:"critical"` // Critical data critical to correctly evaluating the validity of the signature
Optional map[string]interface{} `json:"optional"` // Optional optional metadata about the image
Critical Critical `json:"critical"` // Critical data critical to correctly evaluating the validity of the signature
Optional map[string]any `json:"optional"` // Optional optional metadata about the image
}
// Critical data critical to correctly evaluating the validity of a signature
@@ -65,7 +65,7 @@ type Cosign struct {
// - Older versions of cosign generate signatures where ClaimedIdentity only contains a registry/…/repo ; signature consumers should allow users
// to determine whether such images should be accepted (and, long-term, the default SHOULD be to reject them)
ClaimedIdentity string
Annotations map[string]interface{}
Annotations map[string]any
}
// SimpleContainerImage returns information about a container image in the github.com/containers/image/signature format
+2 -2
View File
@@ -28,7 +28,7 @@ import (
)
// SignImage signs a container manifest using the specified signer object
func SignImage(signer SignerVerifier, image name.Digest, optionalAnnotations map[string]interface{}) (payload, signature []byte, err error) {
func SignImage(signer SignerVerifier, image name.Digest, optionalAnnotations map[string]any) (payload, signature []byte, err error) {
imgPayload := sigpayload.Cosign{
Image: image,
Annotations: optionalAnnotations,
@@ -45,7 +45,7 @@ func SignImage(signer SignerVerifier, image name.Digest, optionalAnnotations map
}
// VerifyImageSignature verifies a signature over a container manifest
func VerifyImageSignature(signer SignerVerifier, payload, signature []byte) (image name.Digest, annotations map[string]interface{}, err error) {
func VerifyImageSignature(signer SignerVerifier, payload, signature []byte) (image name.Digest, annotations map[string]any, err error) {
if err := signer.VerifySignature(bytes.NewReader(signature), bytes.NewReader(payload)); err != nil {
return name.Digest{}, nil, fmt.Errorf("signature verification failed: %w", err)
}
+31 -41
View File
@@ -81,14 +81,6 @@ func verifySubjectCommonName(cert *x509.Certificate, opts VerifyOpts) error {
return nil
}
// If embedded in the TSR, verify the TSR's leaf certificate matches a provided TSA certificate
func verifyEmbeddedLeafCert(tsaCert *x509.Certificate, opts VerifyOpts) error {
if opts.TSACertificate != nil && !opts.TSACertificate.Equal(tsaCert) {
return fmt.Errorf("certificate embedded in the TSR does not match the provided TSA certificate")
}
return nil
}
// Verify the leaf's EKU is set to critical, per RFC 3161 2.3
func verifyLeafCertCriticalEKU(cert *x509.Certificate) error {
var criticalEKU bool
@@ -104,33 +96,14 @@ func verifyLeafCertCriticalEKU(cert *x509.Certificate) error {
return nil
}
func verifyLeafCert(ts timestamp.Timestamp, opts VerifyOpts) error {
if len(ts.Certificates) == 0 && opts.TSACertificate == nil {
return fmt.Errorf("leaf certificate must be present the in TSR or as a verify option")
func verifyLeafCert(leafCert *x509.Certificate, opts VerifyOpts) error {
if leafCert == nil {
// should never happen
return fmt.Errorf("signer certificate is required")
}
errMsg := "failed to verify TSA certificate"
var leafCert *x509.Certificate
if len(ts.Certificates) != 0 {
for _, c := range ts.Certificates {
if !c.IsCA {
leafCert = c
break
}
}
if leafCert == nil {
return fmt.Errorf("no leaf certificate found in chain")
}
err := verifyEmbeddedLeafCert(leafCert, opts)
if err != nil {
return fmt.Errorf("%s: %w", errMsg, err)
}
} else {
leafCert = opts.TSACertificate
}
err := verifyLeafCertCriticalEKU(leafCert)
if err != nil {
return fmt.Errorf("%s: %w", errMsg, err)
@@ -237,7 +210,8 @@ func verifyNonce(requestNonce *big.Int, opts VerifyOpts) error {
return nil
}
// VerifyTimestampResponse the timestamp response using a timestamp certificate chain.
// VerifyTimestampResponse verifies the timestamp response using a timestamp certificate chain.
// Note: This function does not perform CRL/OCSP certificate revocation checks.
func VerifyTimestampResponse(tsrBytes []byte, artifact io.Reader, opts VerifyOpts) (*timestamp.Timestamp, error) {
// Verify the status of the TSR does not contain an error
// handled by the timestamp.ParseResponse function
@@ -251,7 +225,8 @@ func VerifyTimestampResponse(tsrBytes []byte, artifact io.Reader, opts VerifyOpt
}
// verify the timestamp response signature using the provided certificate pool
if err = verifyTSRWithChain(ts, opts); err != nil {
signerCert, err := verifyTSRWithChain(ts, opts)
if err != nil {
return nil, err
}
@@ -263,7 +238,7 @@ func VerifyTimestampResponse(tsrBytes []byte, artifact io.Reader, opts VerifyOpt
return nil, err
}
if err = verifyLeafCert(*ts, opts); err != nil {
if err = verifyLeafCert(signerCert, opts); err != nil {
return nil, err
}
@@ -276,15 +251,21 @@ func VerifyTimestampResponse(tsrBytes []byte, artifact io.Reader, opts VerifyOpt
return ts, nil
}
func verifyTSRWithChain(ts *timestamp.Timestamp, opts VerifyOpts) error {
// Returns the TSA signer certificate after verifying the certificate chain validity.
func verifyTSRWithChain(ts *timestamp.Timestamp, opts VerifyOpts) (*x509.Certificate, error) {
p7Message, err := pkcs7.Parse(ts.RawToken)
if err != nil {
return fmt.Errorf("error parsing hashed message: %w", err)
return nil, fmt.Errorf("error parsing hashed message: %w", err)
}
if len(opts.Roots) == 0 {
return fmt.Errorf("no root certificates provided for verifying the certificate chain")
return nil, fmt.Errorf("no root certificates provided for verifying the certificate chain")
}
if p7Message.Certificates == nil && opts.TSACertificate == nil {
return nil, fmt.Errorf("leaf certificate must be present in the TSR or as a verify option")
}
rootCertPool := x509.NewCertPool()
for _, cert := range opts.Roots {
if cert != nil {
@@ -292,7 +273,7 @@ func verifyTSRWithChain(ts *timestamp.Timestamp, opts VerifyOpts) error {
}
}
if rootCertPool.Equal(x509.NewCertPool()) {
return fmt.Errorf("no valid root certificates provided for verifying the certificate chain")
return nil, fmt.Errorf("no valid root certificates provided for verifying the certificate chain")
}
intermediateCertPool := x509.NewCertPool()
for _, cert := range opts.Intermediates {
@@ -312,16 +293,25 @@ func verifyTSRWithChain(ts *timestamp.Timestamp, opts VerifyOpts) error {
// leaf certificate issuer and serial number information is already part of
// the PKCS7 object, adding the leaf certificate to the Certificates field
// will allow verification to pass
if p7Message.Certificates == nil && opts.TSACertificate != nil {
if p7Message.Certificates == nil {
p7Message.Certificates = []*x509.Certificate{opts.TSACertificate}
}
err = p7Message.VerifyWithOpts(x509Opts)
if err != nil {
return fmt.Errorf("error while verifying with chain: %w", err)
return nil, fmt.Errorf("error while verifying with chain: %w", err)
}
return nil
signerCert := p7Message.GetOnlySigner()
if signerCert == nil {
return nil, fmt.Errorf("signer certificate was not found")
}
if opts.TSACertificate != nil && !opts.TSACertificate.Equal(signerCert) {
return nil, fmt.Errorf("certificate embedded in the TSR does not match the provided TSA certificate")
}
return signerCert, nil
}
// Verify that the TSR's hashed message matches the digest of the artifact to be timestamped
+1 -1
View File
@@ -586,7 +586,7 @@ func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader
// Length of encrypted portion of the packet (header, payload, padding).
// Enforce minimum padding and packet size.
encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPacketSize)
// Enforce block size.
encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
+7 -3
View File
@@ -274,10 +274,14 @@ func pickSignatureAlgorithm(signer Signer, extensions map[string][]byte) (MultiA
}
// Filter algorithms based on those supported by MultiAlgorithmSigner.
// Iterate over the signer's algorithms first to preserve its preference order.
supportedKeyAlgos := algorithmsForKeyFormat(keyFormat)
var keyAlgos []string
for _, algo := range algorithmsForKeyFormat(keyFormat) {
if slices.Contains(as.Algorithms(), underlyingAlgo(algo)) {
keyAlgos = append(keyAlgos, algo)
for _, signerAlgo := range as.Algorithms() {
if idx := slices.IndexFunc(supportedKeyAlgos, func(algo string) bool {
return underlyingAlgo(algo) == signerAlgo
}); idx >= 0 {
keyAlgos = append(keyAlgos, supportedKeyAlgos[idx])
}
}
+10 -3
View File
@@ -6,6 +6,7 @@ package hpack
import (
"fmt"
"strings"
)
// headerFieldTable implements a list of HeaderFields.
@@ -54,10 +55,16 @@ func (t *headerFieldTable) len() int {
// addEntry adds a new entry.
func (t *headerFieldTable) addEntry(f HeaderField) {
// Prevent f from escaping to the heap.
f2 := HeaderField{
Name: strings.Clone(f.Name),
Value: strings.Clone(f.Value),
Sensitive: f.Sensitive,
}
id := uint64(t.len()) + t.evictCount + 1
t.byName[f.Name] = id
t.byNameValue[pairNameValue{f.Name, f.Value}] = id
t.ents = append(t.ents, f)
t.byName[f2.Name] = id
t.byNameValue[pairNameValue{f2.Name, f2.Value}] = id
t.ents = append(t.ents, f2)
}
// evictOldest evicts the n oldest entries in the table.
+3 -6
View File
@@ -718,9 +718,6 @@ func canRetryError(err error) bool {
}
func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {
if t.transportTestHooks != nil {
return t.newClientConn(nil, singleUse, nil)
}
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
@@ -2861,6 +2858,9 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
var seenMaxConcurrentStreams bool
err := f.ForeachSetting(func(s Setting) error {
if err := s.Valid(); err != nil {
return err
}
switch s.ID {
case SettingMaxFrameSize:
cc.maxFrameSize = s.Val
@@ -2892,9 +2892,6 @@ func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error {
cc.henc.SetMaxDynamicTableSize(s.Val)
cc.peerMaxHeaderTableSize = s.Val
case SettingEnableConnectProtocol:
if err := s.Valid(); err != nil {
return err
}
// If the peer wants to send us SETTINGS_ENABLE_CONNECT_PROTOCOL,
// we require that it do so in the first SETTINGS frame.
//
+2
View File
@@ -6,6 +6,8 @@
package cpu
import "runtime"
func doinit() {
setMinimalFeatures()
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !darwin && !linux && !netbsd && !openbsd && !windows && arm64
//go:build !darwin && !linux && !netbsd && !openbsd && arm64
package cpu
-42
View File
@@ -1,42 +0,0 @@
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cpu
import (
"golang.org/x/sys/windows"
)
func doinit() {
// set HasASIMD and HasFP to true as per
// https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#base-requirements
//
// The ARM64 version of Windows always presupposes that it's running on an ARMv8 or later architecture.
// Both floating-point and NEON support are presumed to be present in hardware.
//
ARM64.HasASIMD = true
ARM64.HasFP = true
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) {
ARM64.HasAES = true
ARM64.HasPMULL = true
ARM64.HasSHA1 = true
ARM64.HasSHA2 = true
}
ARM64.HasSHA3 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)
ARM64.HasCRC32 = windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
ARM64.HasSHA512 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE)
ARM64.HasATOMICS = windows.IsProcessorFeaturePresent(windows.PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) {
ARM64.HasASIMDDP = true
ARM64.HasASIMDRDM = true
}
if windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE) {
ARM64.HasLRCPC = true
ARM64.HasSM3 = true
}
ARM64.HasSVE = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE_INSTRUCTIONS_AVAILABLE)
ARM64.HasSVE2 = windows.IsProcessorFeaturePresent(windows.PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE)
ARM64.HasJSCVT = windows.IsProcessorFeaturePresent(windows.PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
}
+1 -36
View File
@@ -163,42 +163,7 @@ func (p *Proc) Addr() uintptr {
// (according to the semantics of the specific function being called) before consulting
// the error. The error will be guaranteed to contain windows.Errno.
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
switch len(a) {
case 0:
return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
case 1:
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
case 2:
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
case 3:
return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
case 4:
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
case 5:
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
case 6:
return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
case 7:
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
case 8:
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
case 9:
return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
case 10:
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
case 11:
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
case 12:
return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
case 13:
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
case 14:
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
case 15:
return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
default:
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
}
return syscall.SyscallN(p.Addr(), a...)
}
// A LazyDLL implements access to a single DLL.
+5 -1
View File
@@ -1438,13 +1438,17 @@ func GetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformati
}
// GetNamedSecurityInfo queries the security information for a given named object and returns the self-relative security
// descriptor result on the Go heap.
// descriptor result on the Go heap. The security descriptor might be nil, even when err is nil, if the object exists
// but has no security descriptor.
func GetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION) (sd *SECURITY_DESCRIPTOR, err error) {
var winHeapSD *SECURITY_DESCRIPTOR
err = getNamedSecurityInfo(objectName, objectType, securityInformation, nil, nil, nil, nil, &winHeapSD)
if err != nil {
return
}
if winHeapSD == nil {
return nil, nil
}
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
}
+32 -1
View File
@@ -61,13 +61,42 @@ func (r *responseDeduper) addAll(dr *DriverResponse) {
}
func (r *responseDeduper) addPackage(p *Package) {
if r.seenPackages[p.ID] != nil {
if prev := r.seenPackages[p.ID]; prev != nil {
// Package already seen in a previous response. Merge the file lists,
// removing duplicates. This can happen when the same package appears
// in multiple driver responses that are being merged together.
prev.GoFiles = appendUniqueStrings(prev.GoFiles, p.GoFiles)
prev.CompiledGoFiles = appendUniqueStrings(prev.CompiledGoFiles, p.CompiledGoFiles)
prev.OtherFiles = appendUniqueStrings(prev.OtherFiles, p.OtherFiles)
prev.IgnoredFiles = appendUniqueStrings(prev.IgnoredFiles, p.IgnoredFiles)
prev.EmbedFiles = appendUniqueStrings(prev.EmbedFiles, p.EmbedFiles)
prev.EmbedPatterns = appendUniqueStrings(prev.EmbedPatterns, p.EmbedPatterns)
return
}
r.seenPackages[p.ID] = p
r.dr.Packages = append(r.dr.Packages, p)
}
// appendUniqueStrings appends elements from src to dst, skipping duplicates.
func appendUniqueStrings(dst, src []string) []string {
if len(src) == 0 {
return dst
}
seen := make(map[string]bool, len(dst))
for _, s := range dst {
seen[s] = true
}
for _, s := range src {
if !seen[s] {
dst = append(dst, s)
}
}
return dst
}
func (r *responseDeduper) addRoot(id string) {
if r.seenRoots[id] {
return
@@ -832,6 +861,8 @@ func golistargs(cfg *Config, words []string, goVersion int) []string {
// go list doesn't let you pass -test and -find together,
// probably because you'd just get the TestMain.
fmt.Sprintf("-find=%t", !cfg.Tests && cfg.Mode&findFlags == 0 && !usesExportData(cfg)),
// VCS information is not needed when not printing Stale or StaleReason fields
"-buildvcs=false",
}
// golang/go#60456: with go1.21 and later, go list serves pgo variants, which
+4
View File
@@ -403,6 +403,10 @@ func mergeResponses(responses ...*DriverResponse) *DriverResponse {
if len(responses) == 0 {
return nil
}
// No dedup needed
if len(responses) == 1 {
return responses[0]
}
response := newDeduper()
response.dr.NotHandled = false
response.dr.Compiler = responses[0].Compiler
+18 -18
View File
@@ -298,7 +298,7 @@ github.com/digitorus/timestamp
# github.com/distribution/reference v0.6.0
## explicit; go 1.20
github.com/distribution/reference
# github.com/docker/cli v29.4.2+incompatible
# github.com/docker/cli v29.4.3+incompatible
## explicit
github.com/docker/cli/cli
github.com/docker/cli/cli-plugins/metadata
@@ -390,7 +390,7 @@ github.com/go-openapi/jsonreference/internal
# github.com/go-openapi/loads v0.23.3
## explicit; go 1.24.0
github.com/go-openapi/loads
# github.com/go-openapi/runtime v0.29.2
# github.com/go-openapi/runtime v0.29.3
## explicit; go 1.24.0
github.com/go-openapi/runtime
github.com/go-openapi/runtime/client
@@ -408,10 +408,10 @@ github.com/go-openapi/spec
## explicit; go 1.24.0
github.com/go-openapi/strfmt
github.com/go-openapi/strfmt/internal/bsonlite
# github.com/go-openapi/swag v0.25.4
# github.com/go-openapi/swag v0.25.5
## explicit; go 1.24.0
github.com/go-openapi/swag
# github.com/go-openapi/swag/cmdutils v0.25.4
# github.com/go-openapi/swag/cmdutils v0.25.5
## explicit; go 1.24.0
github.com/go-openapi/swag/cmdutils
# github.com/go-openapi/swag/conv v0.25.5
@@ -435,7 +435,7 @@ github.com/go-openapi/swag/loading
# github.com/go-openapi/swag/mangling v0.25.5
## explicit; go 1.24.0
github.com/go-openapi/swag/mangling
# github.com/go-openapi/swag/netutils v0.25.4
# github.com/go-openapi/swag/netutils v0.25.5
## explicit; go 1.24.0
github.com/go-openapi/swag/netutils
# github.com/go-openapi/swag/stringutils v0.25.5
@@ -648,7 +648,7 @@ github.com/mitchellh/go-wordwrap
# github.com/mitchellh/hashstructure/v2 v2.0.2
## explicit; go 1.14
github.com/mitchellh/hashstructure/v2
# github.com/moby/buildkit v0.30.0-rc1
# github.com/moby/buildkit v0.30.0-rc2
## explicit; go 1.25.5
github.com/moby/buildkit/api/services/control
github.com/moby/buildkit/api/types
@@ -792,7 +792,7 @@ github.com/moby/moby/client/pkg/versions
## explicit; go 1.19
github.com/moby/patternmatcher
github.com/moby/patternmatcher/ignorefile
# github.com/moby/policy-helpers v0.0.0-20260324161837-b7c0b994300b
# github.com/moby/policy-helpers v0.0.0-20260507153417-a39d60132186
## explicit; go 1.25.5
github.com/moby/policy-helpers
github.com/moby/policy-helpers/image
@@ -1045,7 +1045,7 @@ github.com/sigstore/rekor-tiles/v2/pkg/generated/protobuf
github.com/sigstore/rekor-tiles/v2/pkg/note
github.com/sigstore/rekor-tiles/v2/pkg/types/verifier
github.com/sigstore/rekor-tiles/v2/pkg/verify
# github.com/sigstore/sigstore v1.10.4
# github.com/sigstore/sigstore v1.10.5
## explicit; go 1.25.0
github.com/sigstore/sigstore/pkg/cryptoutils
github.com/sigstore/sigstore/pkg/signature
@@ -1061,7 +1061,7 @@ github.com/sigstore/sigstore-go/pkg/tlog
github.com/sigstore/sigstore-go/pkg/tuf
github.com/sigstore/sigstore-go/pkg/util
github.com/sigstore/sigstore-go/pkg/verify
# github.com/sigstore/timestamp-authority/v2 v2.0.3
# github.com/sigstore/timestamp-authority/v2 v2.0.6
## explicit; go 1.25.0
github.com/sigstore/timestamp-authority/v2/pkg/verification
# github.com/sirupsen/logrus v1.9.4
@@ -1288,7 +1288,7 @@ go.yaml.in/yaml/v3
## explicit; go 1.18
go.yaml.in/yaml/v4
go.yaml.in/yaml/v4/internal/libyaml
# golang.org/x/crypto v0.49.0
# golang.org/x/crypto v0.50.0
## explicit; go 1.25.0
golang.org/x/crypto/argon2
golang.org/x/crypto/bcrypt
@@ -1318,7 +1318,7 @@ golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/module
golang.org/x/mod/semver
golang.org/x/mod/sumdb/note
# golang.org/x/net v0.52.0
# golang.org/x/net v0.53.0
## explicit; go 1.25.0
golang.org/x/net/html
golang.org/x/net/html/atom
@@ -1333,8 +1333,8 @@ golang.org/x/net/internal/timeseries
golang.org/x/net/proxy
golang.org/x/net/trace
golang.org/x/net/websocket
# golang.org/x/oauth2 v0.35.0
## explicit; go 1.24.0
# golang.org/x/oauth2 v0.36.0
## explicit; go 1.25.0
golang.org/x/oauth2
golang.org/x/oauth2/internal
# golang.org/x/sync v0.20.0
@@ -1342,17 +1342,17 @@ golang.org/x/oauth2/internal
golang.org/x/sync/errgroup
golang.org/x/sync/semaphore
golang.org/x/sync/singleflight
# golang.org/x/sys v0.42.0
# golang.org/x/sys v0.43.0
## explicit; go 1.25.0
golang.org/x/sys/cpu
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
golang.org/x/sys/windows/registry
# golang.org/x/term v0.41.0
# golang.org/x/term v0.42.0
## explicit; go 1.25.0
golang.org/x/term
# golang.org/x/text v0.35.0
# golang.org/x/text v0.36.0
## explicit; go 1.25.0
golang.org/x/text/cases
golang.org/x/text/feature/plural
@@ -1375,8 +1375,8 @@ golang.org/x/text/width
# golang.org/x/time v0.15.0
## explicit; go 1.25.0
golang.org/x/time/rate
# golang.org/x/tools v0.42.0
## explicit; go 1.24.0
# golang.org/x/tools v0.43.0
## explicit; go 1.25.0
golang.org/x/tools/cmd/stringer
golang.org/x/tools/go/ast/edge
golang.org/x/tools/go/ast/inspector