From 3210cc1f3b25e92cdd0dd0038d555bf17470ea2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Mart=C3=ADn?= Date: Mon, 2 Mar 2026 13:32:26 +0100 Subject: [PATCH 1/4] build: update vendor licensing and upgrade oapi-codegen dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive license tracking for vendored Go dependencies and update RPM spec with complete license list (0BSD, Apache-2.0, BSD-3-Clause, MIT, Unlicense). Add Makefile target for automated RPM licensing updates. Upgrade oapi-codegen/runtime from v1.1.2 to v1.2.0, regenerating OpenAPI handlers with enhanced enum validation methods. Signed-off-by: Miguel Martín --- Makefile | 27 ++++--- build/package/rpm/go-fdo-server.spec | 2 +- build/package/rpm/go-vendor-tools.toml | 9 +++ go.mod | 4 +- go.sum | 12 +-- internal/handlers/components/models.gen.go | 72 ++++++++++++++++- internal/handlers/deviceca/handler.gen.go | 66 +++++++++++++--- internal/handlers/health/handler.gen.go | 2 +- internal/handlers/rvinfo/handler.gen.go | 2 +- internal/handlers/rvto2addr/handler.gen.go | 2 +- internal/handlers/voucher/handler.gen.go | 92 ++++++++++++++++++---- 11 files changed, 243 insertions(+), 47 deletions(-) diff --git a/Makefile b/Makefile index d9248c5b..ef3f5ea0 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ COMMIT_SHORT := $(shell git rev-parse --short HEAD) SOURCE_DIR := $(CURDIR)/build/package/rpm SPEC_FILE_NAME := $(PROJECT).spec SPEC_FILE := $(SOURCE_DIR)/$(SPEC_FILE_NAME) -VERSION := $(shell grep 'Version:' $(SPEC_FILE) | awk '{printf "%s", $$2}').git$(COMMIT_SHORT) +VERSION := $(shell grep 'Version:' $(SPEC_FILE) | awk '{printf "%s", $$2}') # Default target @@ -65,15 +65,23 @@ GO_VENDOR_TOOLS_FILE_NAME := go-vendor-tools.toml GO_VENDOR_TOOLS_FILE := $(SOURCE_DIR)/$(GO_VENDOR_TOOLS_FILE_NAME) VENDOR_TARBALL_FILENAME := go-fdo-server-$(VERSION)-vendor.tar.bz2 VENDOR_TARBALL := $(SOURCE_DIR)/$(VENDOR_TARBALL_FILENAME) -$(VENDOR_TARBALL): + +.PHONY: install-go-vendor-tools +install-go-vendor-tools: + command -v go_vendor_archive || sudo dnf install -y go-vendor-tools python3-tomlkit askalono-cli go-rpm-macros + +$(VENDOR_TARBALL): install-go-vendor-tools rm -rf vendor; \ - command -v go_vendor_archive || sudo dnf install -y go-vendor-tools python3-tomlkit askalono-cli; \ go_vendor_archive create --config $(GO_VENDOR_TOOLS_FILE) --write-config --output $(VENDOR_TARBALL) .; \ rm -rf vendor; .PHONY: vendor-tarball vendor-tarball: $(VENDOR_TARBALL) +.PHONY: update-rpm-licensing +update-rpm-licensing: install-go-vendor-tools $(SPEC_FILE) $(SOURCE_TARBALL) $(VENDOR_TARBALL) + go_vendor_license --config $(GO_VENDOR_TOOLS_FILE) --path $(SPEC_FILE) report --update-spec --autofill=auto + # # Building packages # @@ -98,6 +106,7 @@ RENDEZVOUS_USER_FILE := $(SOURCE_DIR)/$(RENDEZVOUS_USER_FILE_NA OWNER_USER_FILE_NAME := go-fdo-server-owner-user.conf OWNER_USER_FILE := $(SOURCE_DIR)/$(OWNER_USER_FILE_NAME) +RPMBUILD_VERSION := $(VERSION).git$(COMMIT_SHORT) RPMBUILD_TOP_DIR := $(CURDIR)/rpmbuild RPMBUILD_BUILD_DIR := $(RPMBUILD_TOP_DIR)/build RPMBUILD_RPMS_DIR := $(RPMBUILD_TOP_DIR)/rpms @@ -107,9 +116,9 @@ RPMBUILD_SRPMS_DIR := $(RPMBUILD_TOP_DIR)/srpms RPMBUILD_BUILD_DIR := $(RPMBUILD_TOP_DIR)/build RPMBUILD_BUILDROOT_DIR := $(RPMBUILD_TOP_DIR)/buildroot RPMBUILD_GOLANG_VENDOR_TOOLS_FILE := $(RPMBUILD_SOURCES_DIR)/$(GO_VENDOR_TOOLS_FILE_NAME) -RPMBUILD_SPECFILE := $(RPMBUILD_SPECS_DIR)/go-fdo-server-$(VERSION).spec -RPMBUILD_TARBALL := $(RPMBUILD_SOURCES_DIR)/$(SOURCE_TARBALL_FILENAME) -RPMBUILD_VENDOR_TARBALL := ${RPMBUILD_SOURCES_DIR}/$(VENDOR_TARBALL_FILENAME) +RPMBUILD_SPECFILE := $(RPMBUILD_SPECS_DIR)/go-fdo-server-$(RPMBUILD_VERSION).spec +RPMBUILD_TARBALL := $(RPMBUILD_SOURCES_DIR)/go-fdo-server-$(RPMBUILD_VERSION).tar.gz +RPMBUILD_VENDOR_TARBALL := ${RPMBUILD_SOURCES_DIR}/go-fdo-server-$(RPMBUILD_VERSION)-vendor.tar.bz2 RPMBUILD_GROUP_FILE := $(RPMBUILD_SOURCES_DIR)/$(GROUP_FILE_NAME) RPMBUILD_MANUFACTURER_USER_FILE := $(RPMBUILD_SOURCES_DIR)/$(MANUFACTURER_USER_FILE_NAME) RPMBUILD_RENDEZVOUS_USER_FILE := $(RPMBUILD_SOURCES_DIR)/$(RENDEZVOUS_USER_FILE_NAME) @@ -120,12 +129,12 @@ RPMBUILD_RPM_FILE := $(RPMBUILD_RPMS_DIR)/$(ARCH)/$(PROJECT) $(RPMBUILD_SPECFILE): mkdir -p $(RPMBUILD_SPECS_DIR) - sed -e "s/^Version:\(\s*\).*/Version:\1$(VERSION)/;" \ + sed -e "s/^Version:\(\s*\).*/Version:\1$(RPMBUILD_VERSION)/;" \ $(SPEC_FILE) > $(RPMBUILD_SPECFILE) -$(RPMBUILD_TARBALL): $(SOURCE_TARBALL) $(VENDOR_TARBALL) +$(RPMBUILD_TARBALL): $(VENDOR_TARBALL) mkdir -p $(RPMBUILD_SOURCES_DIR) - cp $(SOURCE_TARBALL) $(RPMBUILD_TARBALL) + git archive --prefix=go-fdo-server-$(RPMBUILD_VERSION)/ --format=tar.gz HEAD > $(RPMBUILD_TARBALL) cp $(VENDOR_TARBALL) $(RPMBUILD_VENDOR_TARBALL); $(RPMBUILD_GOLANG_VENDOR_TOOLS_FILE): diff --git a/build/package/rpm/go-fdo-server.spec b/build/package/rpm/go-fdo-server.spec index e4c6b1d5..c1fc13a9 100644 --- a/build/package/rpm/go-fdo-server.spec +++ b/build/package/rpm/go-fdo-server.spec @@ -22,7 +22,7 @@ Release: %autorelease Summary: A Go implementation of the FIDO Device Onboard Specification # Generated by go-vendor-tools -License: Apache-2.0 AND BSD-3-Clause AND MIT +License: 0BSD AND Apache-2.0 AND BSD-3-Clause AND MIT AND Unlicense URL: %{gourl} Source0: %{gosource} # Generated by go-vendor-tools diff --git a/build/package/rpm/go-vendor-tools.toml b/build/package/rpm/go-vendor-tools.toml index 0352ed07..bc8e9b22 100644 --- a/build/package/rpm/go-vendor-tools.toml +++ b/build/package/rpm/go-vendor-tools.toml @@ -10,3 +10,12 @@ path = "vendor/gopkg.in/yaml.v3/LICENSE" sha256sum = "d18f6323b71b0b768bb5e9616e36da390fbd39369a81807cca352de4e4e6aa0b" expression = "Apache-2.0 AND MIT" +[[licensing.licenses]] +path = "vendor/github.com/oasdiff/yaml/LICENSE" +sha256sum = "24653fd8a39354396da1a265d68316399edc39b1df48c5866d55f9f06484fa9a" +expression = "MIT AND BSD-3-Clause" + +[[licensing.licenses]] +path = "vendor/github.com/oasdiff/yaml3/LICENSE" +sha256sum = "d18f6323b71b0b768bb5e9616e36da390fbd39369a81807cca352de4e4e6aa0b" +expression = "Apache-2.0 AND MIT" diff --git a/go.mod b/go.mod index 0dc674d8..7282b8fb 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/jackc/pgx/v5 v5.7.6 github.com/mattn/go-sqlite3 v1.14.32 github.com/mitchellh/mapstructure v1.5.0 - github.com/oapi-codegen/runtime v1.1.2 + github.com/oapi-codegen/runtime v1.2.0 github.com/spf13/cobra v1.9.1 github.com/spf13/viper v1.20.1 golang.org/x/time v0.11.0 @@ -38,7 +38,7 @@ require ( github.com/mailru/easyjson v0.7.7 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/neilotoole/jsoncolor v0.7.1 // indirect - github.com/oapi-codegen/oapi-codegen/v2 v2.5.1 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.6.0 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect diff --git a/go.sum b/go.sum index a42511eb..846e9192 100644 --- a/go.sum +++ b/go.sum @@ -105,10 +105,10 @@ github.com/nwidger/jsoncolor v0.3.2/go.mod h1:Cs34umxLbJvgBMnVNVqhji9BhoT/N/KinH github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oapi-codegen/oapi-codegen/v2 v2.5.1 h1:5vHNY1uuPBRBWqB2Dp0G7YB03phxLQZupZTIZaeorjc= -github.com/oapi-codegen/oapi-codegen/v2 v2.5.1/go.mod h1:ro0npU1BWkcGpCgGD9QwPp44l5OIZ94tB3eabnT7DjQ= -github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI= -github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= +github.com/oapi-codegen/oapi-codegen/v2 v2.6.0 h1:4i+F2cvwBFZeplxCssNdLy3MhNzUD87mI3HnayHZkAU= +github.com/oapi-codegen/oapi-codegen/v2 v2.6.0/go.mod h1:eWHeJSohQJIINJZzzQriVynfGsnlQVh0UkN2UYYcw4Q= +github.com/oapi-codegen/runtime v1.2.0 h1:RvKc1CVS1QeKSNzO97FBQbSMZyQ8s6rZd+LpmzwHMP4= +github.com/oapi-codegen/runtime v1.2.0/go.mod h1:Y7ZhmmlE8ikZOmuHRRndiIm7nf3xcVv+YMweKgG1DT0= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= @@ -173,8 +173,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= diff --git a/internal/handlers/components/models.gen.go b/internal/handlers/components/models.gen.go index 01d0beaa..b46f3782 100644 --- a/internal/handlers/components/models.gen.go +++ b/internal/handlers/components/models.gen.go @@ -1,6 +1,6 @@ // Package components provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.6.0 DO NOT EDIT. package components import ( @@ -33,6 +33,54 @@ const ( WiredAll MediumMedium = "wired_all" ) +// Valid indicates whether the value is a known member of the MediumMedium enum. +func (e MediumMedium) Valid() bool { + switch e { + case Wifi1: + return true + case Wifi2: + return true + case Wifi3: + return true + case Wifi4: + return true + case Wifi5: + return true + case Wifi6: + return true + case Wifi7: + return true + case Wifi8: + return true + case Wifi9: + return true + case WifiAll: + return true + case Wired1: + return true + case Wired2: + return true + case Wired3: + return true + case Wired4: + return true + case Wired5: + return true + case Wired6: + return true + case Wired7: + return true + case Wired8: + return true + case Wired9: + return true + case WiredAll: + return true + default: + return false + } +} + // Defines values for ProtocolType. const ( Coap ProtocolType = "coap" @@ -44,6 +92,28 @@ const ( Tls ProtocolType = "tls" ) +// Valid indicates whether the value is a known member of the ProtocolType enum. +func (e ProtocolType) Valid() bool { + switch e { + case Coap: + return true + case CoapTcp: + return true + case Http: + return true + case Https: + return true + case Rest: + return true + case Tcp: + return true + case Tls: + return true + default: + return false + } +} + // ClCertHash Client certificate hash for validation (SHA-256 or SHA-384) type ClCertHash struct { ClCertHash *string `json:"cl_cert_hash,omitempty"` diff --git a/internal/handlers/deviceca/handler.gen.go b/internal/handlers/deviceca/handler.gen.go index a4e428f2..facb67bd 100644 --- a/internal/handlers/deviceca/handler.gen.go +++ b/internal/handlers/deviceca/handler.gen.go @@ -2,7 +2,7 @@ // Package deviceca provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.6.0 DO NOT EDIT. package deviceca import ( @@ -33,6 +33,20 @@ const ( Valid ListTrustedDeviceCACertsParamsValidityStatus = "valid" ) +// Valid indicates whether the value is a known member of the ListTrustedDeviceCACertsParamsValidityStatus enum. +func (e ListTrustedDeviceCACertsParamsValidityStatus) Valid() bool { + switch e { + case Expired: + return true + case NotYetValid: + return true + case Valid: + return true + default: + return false + } +} + // Defines values for ListTrustedDeviceCACertsParamsSortBy. const ( CreatedAt ListTrustedDeviceCACertsParamsSortBy = "createdAt" @@ -42,12 +56,42 @@ const ( Subject ListTrustedDeviceCACertsParamsSortBy = "subject" ) +// Valid indicates whether the value is a known member of the ListTrustedDeviceCACertsParamsSortBy enum. +func (e ListTrustedDeviceCACertsParamsSortBy) Valid() bool { + switch e { + case CreatedAt: + return true + case Issuer: + return true + case NotAfter: + return true + case NotBefore: + return true + case Subject: + return true + default: + return false + } +} + // Defines values for ListTrustedDeviceCACertsParamsSortOrder. const ( Asc ListTrustedDeviceCACertsParamsSortOrder = "asc" Desc ListTrustedDeviceCACertsParamsSortOrder = "desc" ) +// Valid indicates whether the value is a known member of the ListTrustedDeviceCACertsParamsSortOrder enum. +func (e ListTrustedDeviceCACertsParamsSortOrder) Valid() bool { + switch e { + case Asc: + return true + case Desc: + return true + default: + return false + } +} + // TrustedDeviceCACert defines model for TrustedDeviceCACert. type TrustedDeviceCACert struct { // CreatedAt The timestamp when the certificate was added. @@ -195,7 +239,7 @@ func (siw *ServerInterfaceWrapper) ListTrustedDeviceCACerts(w http.ResponseWrite // ------------- Optional query parameter "limit" ------------- - err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit) + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) return @@ -203,7 +247,7 @@ func (siw *ServerInterfaceWrapper) ListTrustedDeviceCACerts(w http.ResponseWrite // ------------- Optional query parameter "offset" ------------- - err = runtime.BindQueryParameter("form", true, false, "offset", r.URL.Query(), ¶ms.Offset) + err = runtime.BindQueryParameterWithOptions("form", true, false, "offset", r.URL.Query(), ¶ms.Offset, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "offset", Err: err}) return @@ -211,7 +255,7 @@ func (siw *ServerInterfaceWrapper) ListTrustedDeviceCACerts(w http.ResponseWrite // ------------- Optional query parameter "issuer" ------------- - err = runtime.BindQueryParameter("form", true, false, "issuer", r.URL.Query(), ¶ms.Issuer) + err = runtime.BindQueryParameterWithOptions("form", true, false, "issuer", r.URL.Query(), ¶ms.Issuer, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "issuer", Err: err}) return @@ -219,7 +263,7 @@ func (siw *ServerInterfaceWrapper) ListTrustedDeviceCACerts(w http.ResponseWrite // ------------- Optional query parameter "subject" ------------- - err = runtime.BindQueryParameter("form", true, false, "subject", r.URL.Query(), ¶ms.Subject) + err = runtime.BindQueryParameterWithOptions("form", true, false, "subject", r.URL.Query(), ¶ms.Subject, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "subject", Err: err}) return @@ -227,7 +271,7 @@ func (siw *ServerInterfaceWrapper) ListTrustedDeviceCACerts(w http.ResponseWrite // ------------- Optional query parameter "validityStatus" ------------- - err = runtime.BindQueryParameter("form", true, false, "validityStatus", r.URL.Query(), ¶ms.ValidityStatus) + err = runtime.BindQueryParameterWithOptions("form", true, false, "validityStatus", r.URL.Query(), ¶ms.ValidityStatus, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "validityStatus", Err: err}) return @@ -235,7 +279,7 @@ func (siw *ServerInterfaceWrapper) ListTrustedDeviceCACerts(w http.ResponseWrite // ------------- Optional query parameter "search" ------------- - err = runtime.BindQueryParameter("form", true, false, "search", r.URL.Query(), ¶ms.Search) + err = runtime.BindQueryParameterWithOptions("form", true, false, "search", r.URL.Query(), ¶ms.Search, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "search", Err: err}) return @@ -243,7 +287,7 @@ func (siw *ServerInterfaceWrapper) ListTrustedDeviceCACerts(w http.ResponseWrite // ------------- Optional query parameter "sortBy" ------------- - err = runtime.BindQueryParameter("form", true, false, "sortBy", r.URL.Query(), ¶ms.SortBy) + err = runtime.BindQueryParameterWithOptions("form", true, false, "sortBy", r.URL.Query(), ¶ms.SortBy, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "sortBy", Err: err}) return @@ -251,7 +295,7 @@ func (siw *ServerInterfaceWrapper) ListTrustedDeviceCACerts(w http.ResponseWrite // ------------- Optional query parameter "sortOrder" ------------- - err = runtime.BindQueryParameter("form", true, false, "sortOrder", r.URL.Query(), ¶ms.SortOrder) + err = runtime.BindQueryParameterWithOptions("form", true, false, "sortOrder", r.URL.Query(), ¶ms.SortOrder, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "sortOrder", Err: err}) return @@ -304,7 +348,7 @@ func (siw *ServerInterfaceWrapper) DeleteTrustedDeviceCACert(w http.ResponseWrit // ------------- Path parameter "fingerprint" ------------- var fingerprint string - err = runtime.BindStyledParameterWithOptions("simple", "fingerprint", r.PathValue("fingerprint"), &fingerprint, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "fingerprint", r.PathValue("fingerprint"), &fingerprint, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "fingerprint", Err: err}) return @@ -343,7 +387,7 @@ func (siw *ServerInterfaceWrapper) GetTrustedDeviceCACertByFingerprint(w http.Re // ------------- Path parameter "fingerprint" ------------- var fingerprint string - err = runtime.BindStyledParameterWithOptions("simple", "fingerprint", r.PathValue("fingerprint"), &fingerprint, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "fingerprint", r.PathValue("fingerprint"), &fingerprint, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "fingerprint", Err: err}) return diff --git a/internal/handlers/health/handler.gen.go b/internal/handlers/health/handler.gen.go index 9dd591b3..1b32afc0 100644 --- a/internal/handlers/health/handler.gen.go +++ b/internal/handlers/health/handler.gen.go @@ -2,7 +2,7 @@ // Package health provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.6.0 DO NOT EDIT. package health import ( diff --git a/internal/handlers/rvinfo/handler.gen.go b/internal/handlers/rvinfo/handler.gen.go index 9998822a..1e21c408 100644 --- a/internal/handlers/rvinfo/handler.gen.go +++ b/internal/handlers/rvinfo/handler.gen.go @@ -2,7 +2,7 @@ // Package rvinfo provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.6.0 DO NOT EDIT. package rvinfo import ( diff --git a/internal/handlers/rvto2addr/handler.gen.go b/internal/handlers/rvto2addr/handler.gen.go index aa13a06c..f5ed37a9 100644 --- a/internal/handlers/rvto2addr/handler.gen.go +++ b/internal/handlers/rvto2addr/handler.gen.go @@ -2,7 +2,7 @@ // Package rvto2addr provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.6.0 DO NOT EDIT. package rvto2addr import ( diff --git a/internal/handlers/voucher/handler.gen.go b/internal/handlers/voucher/handler.gen.go index 4eeeac56..f20d869e 100644 --- a/internal/handlers/voucher/handler.gen.go +++ b/internal/handlers/voucher/handler.gen.go @@ -2,7 +2,7 @@ // Package voucher provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.1 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.6.0 DO NOT EDIT. package voucher import ( @@ -36,6 +36,26 @@ const ( SHA512 HashAlgorithm = "SHA-512" ) +// Valid indicates whether the value is a known member of the HashAlgorithm enum. +func (e HashAlgorithm) Valid() bool { + switch e { + case HMACSHA256: + return true + case HMACSHA384: + return true + case HMACSHA512: + return true + case SHA256: + return true + case SHA384: + return true + case SHA512: + return true + default: + return false + } +} + // Defines values for PublicKeyType. const ( RSA2048RESTR PublicKeyType = "RSA2048RESTR" @@ -44,6 +64,22 @@ const ( SECP384R1 PublicKeyType = "SECP384R1" ) +// Valid indicates whether the value is a known member of the PublicKeyType enum. +func (e PublicKeyType) Valid() bool { + switch e { + case RSA2048RESTR: + return true + case RSAPKCS: + return true + case SECP256R1: + return true + case SECP384R1: + return true + default: + return false + } +} + // Defines values for ListOwnershipVouchersParamsSortBy. const ( CreatedAt ListOwnershipVouchersParamsSortBy = "createdAt" @@ -52,12 +88,40 @@ const ( UpdatedAt ListOwnershipVouchersParamsSortBy = "updatedAt" ) +// Valid indicates whether the value is a known member of the ListOwnershipVouchersParamsSortBy enum. +func (e ListOwnershipVouchersParamsSortBy) Valid() bool { + switch e { + case CreatedAt: + return true + case DeviceInfo: + return true + case Guid: + return true + case UpdatedAt: + return true + default: + return false + } +} + // Defines values for ListOwnershipVouchersParamsSortOrder. const ( Asc ListOwnershipVouchersParamsSortOrder = "asc" Desc ListOwnershipVouchersParamsSortOrder = "desc" ) +// Valid indicates whether the value is a known member of the ListOwnershipVouchersParamsSortOrder enum. +func (e ListOwnershipVouchersParamsSortOrder) Valid() bool { + switch e { + case Asc: + return true + case Desc: + return true + default: + return false + } +} + // Hash defines model for Hash. type Hash struct { // Algorithm Hash algorithm. @@ -76,7 +140,7 @@ type HashAlgorithm string // OwnershipVoucher defines model for OwnershipVoucher. type OwnershipVoucher struct { // CertChain X.509 certificate chain in PEM format (null for Intel EPID). - CertChain *[]string `json:"certChain"` + CertChain *[]string `json:"certChain,omitempty"` // DeviceInfo Device information string. DeviceInfo VoucherDeviceInfo `json:"deviceInfo"` @@ -168,7 +232,7 @@ type VoucherDeviceInfo = string // VoucherEntry defines model for VoucherEntry. type VoucherEntry struct { // Extra Additional optional data. - Extra *map[string]interface{} `json:"extra"` + Extra *map[string]interface{} `json:"extra,omitempty"` HeaderHash Hash `json:"headerHash"` PreviousHash Hash `json:"previousHash"` PublicKey PublicKey `json:"publicKey"` @@ -180,7 +244,7 @@ type VoucherGuid = string // VoucherHeader defines model for VoucherHeader. type VoucherHeader struct { // CertChainHash Hash of the certificate chain (required when certChain is present). - CertChainHash *Hash `json:"certChainHash"` + CertChainHash *Hash `json:"certChainHash,omitempty"` // DeviceInfo Device information string. DeviceInfo string `json:"deviceInfo"` @@ -296,7 +360,7 @@ func (siw *ServerInterfaceWrapper) ListOwnershipVouchers(w http.ResponseWriter, // ------------- Optional query parameter "limit" ------------- - err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit) + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) return @@ -304,7 +368,7 @@ func (siw *ServerInterfaceWrapper) ListOwnershipVouchers(w http.ResponseWriter, // ------------- Optional query parameter "offset" ------------- - err = runtime.BindQueryParameter("form", true, false, "offset", r.URL.Query(), ¶ms.Offset) + err = runtime.BindQueryParameterWithOptions("form", true, false, "offset", r.URL.Query(), ¶ms.Offset, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "offset", Err: err}) return @@ -312,7 +376,7 @@ func (siw *ServerInterfaceWrapper) ListOwnershipVouchers(w http.ResponseWriter, // ------------- Optional query parameter "guid" ------------- - err = runtime.BindQueryParameter("form", true, false, "guid", r.URL.Query(), ¶ms.Guid) + err = runtime.BindQueryParameterWithOptions("form", true, false, "guid", r.URL.Query(), ¶ms.Guid, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "guid", Err: err}) return @@ -320,7 +384,7 @@ func (siw *ServerInterfaceWrapper) ListOwnershipVouchers(w http.ResponseWriter, // ------------- Optional query parameter "deviceInfo" ------------- - err = runtime.BindQueryParameter("form", true, false, "deviceInfo", r.URL.Query(), ¶ms.DeviceInfo) + err = runtime.BindQueryParameterWithOptions("form", true, false, "deviceInfo", r.URL.Query(), ¶ms.DeviceInfo, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "deviceInfo", Err: err}) return @@ -328,7 +392,7 @@ func (siw *ServerInterfaceWrapper) ListOwnershipVouchers(w http.ResponseWriter, // ------------- Optional query parameter "search" ------------- - err = runtime.BindQueryParameter("form", true, false, "search", r.URL.Query(), ¶ms.Search) + err = runtime.BindQueryParameterWithOptions("form", true, false, "search", r.URL.Query(), ¶ms.Search, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "search", Err: err}) return @@ -336,7 +400,7 @@ func (siw *ServerInterfaceWrapper) ListOwnershipVouchers(w http.ResponseWriter, // ------------- Optional query parameter "sortBy" ------------- - err = runtime.BindQueryParameter("form", true, false, "sortBy", r.URL.Query(), ¶ms.SortBy) + err = runtime.BindQueryParameterWithOptions("form", true, false, "sortBy", r.URL.Query(), ¶ms.SortBy, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "sortBy", Err: err}) return @@ -344,7 +408,7 @@ func (siw *ServerInterfaceWrapper) ListOwnershipVouchers(w http.ResponseWriter, // ------------- Optional query parameter "sortOrder" ------------- - err = runtime.BindQueryParameter("form", true, false, "sortOrder", r.URL.Query(), ¶ms.SortOrder) + err = runtime.BindQueryParameterWithOptions("form", true, false, "sortOrder", r.URL.Query(), ¶ms.SortOrder, runtime.BindQueryParameterOptions{Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "sortOrder", Err: err}) return @@ -397,7 +461,7 @@ func (siw *ServerInterfaceWrapper) DeleteOwnershipVoucher(w http.ResponseWriter, // ------------- Path parameter "guid" ------------- var guid string - err = runtime.BindStyledParameterWithOptions("simple", "guid", r.PathValue("guid"), &guid, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "guid", r.PathValue("guid"), &guid, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "guid", Err: err}) return @@ -436,7 +500,7 @@ func (siw *ServerInterfaceWrapper) GetOwnershipVoucherByGuid(w http.ResponseWrit // ------------- Path parameter "guid" ------------- var guid string - err = runtime.BindStyledParameterWithOptions("simple", "guid", r.PathValue("guid"), &guid, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "guid", r.PathValue("guid"), &guid, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "guid", Err: err}) return @@ -475,7 +539,7 @@ func (siw *ServerInterfaceWrapper) ExtendOwnershipVoucher(w http.ResponseWriter, // ------------- Path parameter "guid" ------------- var guid string - err = runtime.BindStyledParameterWithOptions("simple", "guid", r.PathValue("guid"), &guid, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + err = runtime.BindStyledParameterWithOptions("simple", "guid", r.PathValue("guid"), &guid, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""}) if err != nil { siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "guid", Err: err}) return From 72a9eb636ff04817726f58d4618792b58e11f668 Mon Sep 17 00:00:00 2001 From: knecasov Date: Thu, 26 Feb 2026 08:28:23 +0100 Subject: [PATCH 2/4] ci: add Go test coverage workflow with baseline comparison ci: add Go test coverage workflow with baseline comparison - add GitHub Actions workflow combining unit and integration test coverage with HTML report artifact - add .testcoverage.yml with initial zero thresholds and generated file exclusion - update utils.sh to support coverage-instrumented server build when GOCOVERDIR is set - add coverage output files to .gitignore - enable coverage comparison against main branch baseline Signed-off-by: Klara Necasova --- .github/workflows/coverage.yml | 95 ++++++++++++++++++++++++++++++++++ .gitignore | 3 ++ .testcoverage.yml | 8 +++ test/ci/utils.sh | 11 +++- 4 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/coverage.yml create mode 100644 .testcoverage.yml diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 00000000..e1bcc59b --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,95 @@ +on: + push: + branches: + - main + pull_request: + +name: Go test coverage + +jobs: + coverage: + name: Measure test coverage (unit + integration tests) + runs-on: ubuntu-latest + steps: + - name: Install golang + uses: actions/setup-go@v5 + with: + go-version: "1.25" + + - name: Check out repository code + uses: actions/checkout@v4 + + # --- Phase 1: Unit tests --- + - name: Run unit tests with coverage + run: go test -coverpkg=./... -coverprofile=coverage-unit.out -covermode=atomic ./... + + # --- Phase 2: Integration tests with coverage --- + - name: Set up coverage directory + run: | + GOCOVERDIR="$(pwd)/coverage-integration" + echo "GOCOVERDIR=${GOCOVERDIR}" >> "$GITHUB_ENV" + rm -rf "$GOCOVERDIR" + mkdir -p "$GOCOVERDIR" + + - name: Run integration tests with coverage + run: | + source test/ci/utils.sh + install_server + + passed=0 + failed=0 + for t in test/ci/test-*.sh; do + echo "=== Running: $t ===" + source "$t" + if run_test; then + passed=$((passed + 1)) + else + failed=$((failed + 1)) + echo "WARN: $t failed, continuing" + fi + cleanup || true + done + echo "=== Integration tests: $passed passed, $failed failed ===" + + # --- Merge coverage profiles --- + - name: Merge coverage profiles + run: | + go tool covdata textfmt -i="$GOCOVERDIR" -o=coverage-integration.out + go install github.com/wadey/gocovmerge@latest + gocovmerge coverage-unit.out coverage-integration.out > coverage.out + + # --- Evaluate and report --- + - name: Download base coverage breakdown + id: download-main-breakdown + uses: dawidd6/action-download-artifact@v6 + with: + branch: main + workflow_conclusion: success + name: main.breakdown + if_no_artifact_found: warn + + - name: Check coverage thresholds + uses: vladopajic/go-test-coverage@v2 + with: + config: .testcoverage.yml + breakdown-file-name: ${{ github.ref_name == 'main' && 'main.breakdown' || '' }} + diff-base-breakdown-file-name: ${{ steps.download-main-breakdown.outputs.found_artifact == 'true' && 'main.breakdown' || '' }} + + - name: Upload coverage breakdown + uses: actions/upload-artifact@v4 + if: github.ref_name == 'main' + with: + name: main.breakdown + path: main.breakdown + if-no-files-found: error + + - name: Generate HTML report + if: always() + run: go tool cover -html=coverage.out -o coverage.html + + - name: Upload coverage report + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage.html diff --git a/.gitignore b/.gitignore index 90abaf59..af8ea38b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ go-fdo-server go-fdo-server-*.tar.* rpmbuild test/workdir +coverage*.out +coverage*.html +coverage-integration/ diff --git a/.testcoverage.yml b/.testcoverage.yml new file mode 100644 index 00000000..a33d3a76 --- /dev/null +++ b/.testcoverage.yml @@ -0,0 +1,8 @@ +profile: coverage.out +threshold: + file: 0 + package: 0 + total: 0 +exclude: + paths: + - \.gen\.go$ diff --git a/test/ci/utils.sh b/test/ci/utils.sh index 10d05eb0..acd6e979 100644 --- a/test/ci/utils.sh +++ b/test/ci/utils.sh @@ -319,7 +319,8 @@ run_go_fdo_server() { shift 5 mkdir -p "$(dirname "${log}")" mkdir -p "$(dirname "${pid_file}")" - nohup "${bin_dir}/go-fdo-server" "${role}" "${address_port}" --db-type sqlite --db-dsn "file:${base_dir}/${name}.db" --log-level=debug "${@}" &>"${log}" & + GOCOVERDIR="${GOCOVERDIR:-}" nohup "${bin_dir}/go-fdo-server" "${role}" "${address_port}" --db-type sqlite \ + --db-dsn "file:${base_dir}/${name}.db" --log-level=debug "${@}" &>"${log}" & echo -n $! >"${pid_file}" } @@ -407,7 +408,13 @@ uninstall_client() { install_server() { mkdir -p "${bin_dir}" - make build && install -m 755 go-fdo-server "${bin_dir}" && rm -f go-fdo-server + if [[ -n "${GOCOVERDIR:-}" ]]; then + # Build with coverage instrumentation for code coverage measurement + go build -cover -covermode=atomic -o go-fdo-server . && + install -m 755 go-fdo-server "${bin_dir}" && rm -f go-fdo-server + else + make build && install -m 755 go-fdo-server "${bin_dir}" && rm -f go-fdo-server + fi } uninstall_server() { From 975141d3a04eaeb2dfc398395b03285adf61e637 Mon Sep 17 00:00:00 2001 From: Klara Necasova Date: Thu, 26 Feb 2026 10:30:46 +0100 Subject: [PATCH 3/4] ci: add coverage report posting to pull requests - find PR number via GitHub API with event context fallback - post coverage report as PR comment - defer workflow failure until after PR comment and artifacts are posted Signed-off-by: Klara Necasova --- .github/workflows/coverage.yml | 36 ++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e1bcc59b..f2ce4c95 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -19,11 +19,9 @@ jobs: - name: Check out repository code uses: actions/checkout@v4 - # --- Phase 1: Unit tests --- - name: Run unit tests with coverage run: go test -coverpkg=./... -coverprofile=coverage-unit.out -covermode=atomic ./... - # --- Phase 2: Integration tests with coverage --- - name: Set up coverage directory run: | GOCOVERDIR="$(pwd)/coverage-integration" @@ -51,14 +49,12 @@ jobs: done echo "=== Integration tests: $passed passed, $failed failed ===" - # --- Merge coverage profiles --- - name: Merge coverage profiles run: | go tool covdata textfmt -i="$GOCOVERDIR" -o=coverage-integration.out go install github.com/wadey/gocovmerge@latest gocovmerge coverage-unit.out coverage-integration.out > coverage.out - # --- Evaluate and report --- - name: Download base coverage breakdown id: download-main-breakdown uses: dawidd6/action-download-artifact@v6 @@ -68,13 +64,39 @@ jobs: name: main.breakdown if_no_artifact_found: warn + # continue-on-error: allow workflow to proceed to post PR comment and upload artifacts - name: Check coverage thresholds + id: coverage uses: vladopajic/go-test-coverage@v2 + continue-on-error: true with: config: .testcoverage.yml breakdown-file-name: ${{ github.ref_name == 'main' && 'main.breakdown' || '' }} diff-base-breakdown-file-name: ${{ steps.download-main-breakdown.outputs.found_artifact == 'true' && 'main.breakdown' || '' }} + - name: Find pull request ID + run: | + PR_DATA=$(curl -s -H "Authorization: token ${{ github.token }}" \ + "https://api.github.com/repos/${{ github.repository }}/pulls?head=${{ github.repository_owner }}:${{ github.head_ref || github.ref_name }}&state=open") + PR_ID=$(echo "$PR_DATA" | jq -r '.[0].number') + if [ "$PR_ID" != "null" ]; then + echo "pull_request_id=$PR_ID" >> "$GITHUB_ENV" + else + echo "No open pull request found for branch ${{ github.head_ref || github.ref_name }}." + fi + + - name: Post coverage report to PR + if: env.pull_request_id + uses: thollander/actions-comment-pull-request@v3 + with: + github-token: ${{ github.token }} + comment-tag: coverage-report + pr-number: ${{ env.pull_request_id }} + message: | + `go-test-coverage` report + ``` + ${{ fromJSON(steps.coverage.outputs.report) }}``` + - name: Upload coverage breakdown uses: actions/upload-artifact@v4 if: github.ref_name == 'main' @@ -93,3 +115,9 @@ jobs: with: name: coverage-report path: coverage.html + + # fail the workflow if coverage thresholds are not met, after PR comment and artifacts are posted + - name: Fail if coverage thresholds not met + if: steps.coverage.outcome == 'failure' + shell: bash + run: echo "Coverage thresholds are not met." && exit 1 From 70e0e8efd0e20fdab3c43d0d57ed191e0225b5a0 Mon Sep 17 00:00:00 2001 From: Klara Necasova Date: Sat, 28 Feb 2026 12:10:55 +0100 Subject: [PATCH 4/4] refactor: move coverage logic to Makefile test-coverage target - add test-coverage target combining unit tests, integration tests, coverage merge, and HTML report generation - add GOFLAGS, COVERDIR, and GOCOVERDIR variables with configurable defaults - simplify coverage.yml workflow to call `make test-coverage` - remove GOCOVERDIR prefix from run_go_fdo_server() - simplify install_server() to always use `make build` - consolidate all coverage output under test/coverage/ Signed-off-by: Klara Necasova --- .github/workflows/coverage.yml | 43 +++------------------------------- .gitignore | 4 +--- .testcoverage.yml | 2 +- Makefile | 23 +++++++++++++++++- test/ci/utils.sh | 11 ++------- 5 files changed, 29 insertions(+), 54 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f2ce4c95..204c501a 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -19,41 +19,8 @@ jobs: - name: Check out repository code uses: actions/checkout@v4 - - name: Run unit tests with coverage - run: go test -coverpkg=./... -coverprofile=coverage-unit.out -covermode=atomic ./... - - - name: Set up coverage directory - run: | - GOCOVERDIR="$(pwd)/coverage-integration" - echo "GOCOVERDIR=${GOCOVERDIR}" >> "$GITHUB_ENV" - rm -rf "$GOCOVERDIR" - mkdir -p "$GOCOVERDIR" - - - name: Run integration tests with coverage - run: | - source test/ci/utils.sh - install_server - - passed=0 - failed=0 - for t in test/ci/test-*.sh; do - echo "=== Running: $t ===" - source "$t" - if run_test; then - passed=$((passed + 1)) - else - failed=$((failed + 1)) - echo "WARN: $t failed, continuing" - fi - cleanup || true - done - echo "=== Integration tests: $passed passed, $failed failed ===" - - - name: Merge coverage profiles - run: | - go tool covdata textfmt -i="$GOCOVERDIR" -o=coverage-integration.out - go install github.com/wadey/gocovmerge@latest - gocovmerge coverage-unit.out coverage-integration.out > coverage.out + - name: Run tests with coverage + run: make test-coverage - name: Download base coverage breakdown id: download-main-breakdown @@ -105,16 +72,12 @@ jobs: path: main.breakdown if-no-files-found: error - - name: Generate HTML report - if: always() - run: go tool cover -html=coverage.out -o coverage.html - - name: Upload coverage report if: always() uses: actions/upload-artifact@v4 with: name: coverage-report - path: coverage.html + path: test/coverage/coverage.html # fail the workflow if coverage thresholds are not met, after PR comment and artifacts are posted - name: Fail if coverage thresholds not met diff --git a/.gitignore b/.gitignore index af8ea38b..7b834463 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,4 @@ go-fdo-server go-fdo-server-*.tar.* rpmbuild test/workdir -coverage*.out -coverage*.html -coverage-integration/ +test/coverage diff --git a/.testcoverage.yml b/.testcoverage.yml index a33d3a76..11ab0a0a 100644 --- a/.testcoverage.yml +++ b/.testcoverage.yml @@ -1,4 +1,4 @@ -profile: coverage.out +profile: test/coverage/coverage.out threshold: file: 0 package: 0 diff --git a/Makefile b/Makefile index ef3f5ea0..5dca4ce6 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ SOURCE_DIR := $(CURDIR)/build/package/rpm SPEC_FILE_NAME := $(PROJECT).spec SPEC_FILE := $(SOURCE_DIR)/$(SPEC_FILE_NAME) VERSION := $(shell grep 'Version:' $(SPEC_FILE) | awk '{printf "%s", $$2}') +GOFLAGS ?= +COVERDIR ?= $(CURDIR)/test/coverage +GOCOVERDIR ?= $(COVERDIR)/integration # Default target @@ -15,7 +18,7 @@ all: build test # Build the Go project .PHONY: build build: generate tidy fmt vet - go build -ldflags="-X github.com/fido-device-onboard/go-fdo-server/internal/version.VERSION=${VERSION}" + go build $(GOFLAGS) -ldflags="-X github.com/fido-device-onboard/go-fdo-server/internal/version.VERSION=${VERSION}" .PHONY: oapi-codegen oapi-codegen: @@ -50,6 +53,24 @@ test: shfmt: shfmt -i 2 -ci -w . +.PHONY: test-coverage +test-coverage: SHELL := /usr/bin/env bash +test-coverage: + rm -rf "$(COVERDIR)" + mkdir -p "$(GOCOVERDIR)" + go test -coverpkg=./... -coverprofile="$(COVERDIR)/unit.out" -covermode=atomic ./... + export GOCOVERDIR="$(GOCOVERDIR)"; \ + export GOFLAGS="-cover -covermode=atomic"; \ + set -e; \ + for t in test/ci/test-*.sh; do \ + echo "=== RUNNING: $$t ==="; \ + ($$t); \ + done; \ + go tool covdata textfmt -i="$(GOCOVERDIR)" -o="$(COVERDIR)/integration.out" + go install github.com/wadey/gocovmerge@latest + gocovmerge "$(COVERDIR)/unit.out" "$(COVERDIR)/integration.out" > "$(COVERDIR)/coverage.out" + go tool cover -html="$(COVERDIR)/coverage.out" -o "$(COVERDIR)/coverage.html" + # # Generating sources and vendor tar files # diff --git a/test/ci/utils.sh b/test/ci/utils.sh index acd6e979..10d05eb0 100644 --- a/test/ci/utils.sh +++ b/test/ci/utils.sh @@ -319,8 +319,7 @@ run_go_fdo_server() { shift 5 mkdir -p "$(dirname "${log}")" mkdir -p "$(dirname "${pid_file}")" - GOCOVERDIR="${GOCOVERDIR:-}" nohup "${bin_dir}/go-fdo-server" "${role}" "${address_port}" --db-type sqlite \ - --db-dsn "file:${base_dir}/${name}.db" --log-level=debug "${@}" &>"${log}" & + nohup "${bin_dir}/go-fdo-server" "${role}" "${address_port}" --db-type sqlite --db-dsn "file:${base_dir}/${name}.db" --log-level=debug "${@}" &>"${log}" & echo -n $! >"${pid_file}" } @@ -408,13 +407,7 @@ uninstall_client() { install_server() { mkdir -p "${bin_dir}" - if [[ -n "${GOCOVERDIR:-}" ]]; then - # Build with coverage instrumentation for code coverage measurement - go build -cover -covermode=atomic -o go-fdo-server . && - install -m 755 go-fdo-server "${bin_dir}" && rm -f go-fdo-server - else - make build && install -m 755 go-fdo-server "${bin_dir}" && rm -f go-fdo-server - fi + make build && install -m 755 go-fdo-server "${bin_dir}" && rm -f go-fdo-server } uninstall_server() {