Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package conftest for openSUSE:Factory checked in at 2026-10-06 19:17:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/conftest (Old) and /work/SRC/openSUSE:Factory/.conftest.new.3698736 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "conftest" Tue Oct 6 19:17:43 2026 rev:42 rq:1382662 version:0.71.0 Changes: -------- --- /work/SRC/openSUSE:Factory/conftest/conftest.changes 2026-09-21 12:13:58.431101979 +0200 +++ /work/SRC/openSUSE:Factory/.conftest.new.3698736/conftest.changes 2026-10-06 19:17:46.662928630 +0200 @@ -1,0 +2,25 @@ +Thu Oct 01 05:00:11 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 0.71.0: + * New Features + - 636cfe3: feat: Add parser for CODEOWNER files (#1404) + (@apnsngr) + * Bug Fixes + - 96fc461: fix(docs): unbreak Netlify build on the Noble image + (#1433) (@boranx) + - 8345c40: fix: emit a single TAP plan across all files (#1435) + (@behappymia) + * OPA Changes + - b254dd7: build(deps): bump github.com/open-policy-agent/opa + from 1.20.2 to 1.21.0 (#1434) (@dependabot[bot]) + * Other Changes + - a766df6: build(deps): bump alpine from 3.24.1 to 3.24.2 + (#1430) (@dependabot[bot]) + - 6febea0: build(deps): bump github.com/magiconair/properties + (#1431) (@dependabot[bot]) + - e0275ea: chore: run goreleaser in parallel with docker builds + (#1427) (@jalseth) + - f1484a6: refactor(outputter): Standardize how totals are + accumulated (#1429) (@jalseth) + +------------------------------------------------------------------- Old: ---- conftest-0.70.1.obscpio New: ---- conftest-0.71.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ conftest.spec ++++++ --- /var/tmp/diff_new_pack.KWT4EC/_old 2026-10-06 19:17:48.568008408 +0200 +++ /var/tmp/diff_new_pack.KWT4EC/_new 2026-10-06 19:17:48.570008492 +0200 @@ -17,7 +17,7 @@ Name: conftest -Version: 0.70.1 +Version: 0.71.0 Release: 0 Summary: Tool to write tests against structured configuration data License: Apache-2.0 @@ -26,7 +26,7 @@ Source1: vendor.tar.gz BuildRequires: bash-completion BuildRequires: fish -BuildRequires: go1.26 >= 1.26.3 +BuildRequires: go1.27 >= 1.27.1 BuildRequires: zsh %description ++++++ _service ++++++ --- /var/tmp/diff_new_pack.KWT4EC/_old 2026-10-06 19:17:48.603009878 +0200 +++ /var/tmp/diff_new_pack.KWT4EC/_new 2026-10-06 19:17:48.607010046 +0200 @@ -4,7 +4,7 @@ <param name="scm">git</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> - <param name="revision">refs/tags/v0.70.1</param> + <param name="revision">refs/tags/v0.71.0</param> <param name="changesgenerate">enable</param> </service> <service name="set_version" mode="manual"> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.KWT4EC/_old 2026-10-06 19:17:48.628010927 +0200 +++ /var/tmp/diff_new_pack.KWT4EC/_new 2026-10-06 19:17:48.631011053 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/open-policy-agent/conftest.git</param> - <param name="changesrevision">0b42cb5cd1aa1dc1c9025a5e83c7e963166d08c0</param></service></servicedata> + <param name="changesrevision">8345c40e21f3e6ab1159f4e15585b5f7d6aa32a7</param></service></servicedata> (No newline at EOF) ++++++ conftest-0.70.1.obscpio -> conftest-0.71.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/.github/workflows/post_merge.yaml new/conftest-0.71.0/.github/workflows/post_merge.yaml --- old/conftest-0.70.1/.github/workflows/post_merge.yaml 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/.github/workflows/post_merge.yaml 2026-09-30 03:15:00.000000000 +0200 @@ -20,7 +20,7 @@ run: docker buildx create --name conftestbuild --use - name: Build Docker image - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # ratchet:docker/[email protected] + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # ratchet:docker/[email protected] with: context: '.' push: false @@ -44,7 +44,7 @@ run: docker buildx create --name conftestbuild --use - name: Build Docker image - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # ratchet:docker/[email protected] + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # ratchet:docker/[email protected] with: context: '.' target: examples diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/.github/workflows/release.yaml new/conftest-0.71.0/.github/workflows/release.yaml --- old/conftest-0.70.1/.github/workflows/release.yaml 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/.github/workflows/release.yaml 2026-09-30 03:15:00.000000000 +0200 @@ -26,9 +26,8 @@ with: persist-credentials: false - # It is important to check the GoReleaser config before pushing to - # Dockerhub to avoid having mismatches between what is in Dockerhub - # and GitHub releases. + # Validate the GoReleaser config before building anything so a bad + # config fails fast rather than after images have been pushed. - name: check releaser config uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # ratchet:goreleaser/[email protected] with: @@ -64,7 +63,7 @@ - name: Build and push Docker image id: build - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # ratchet:docker/[email protected] + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # ratchet:docker/[email protected] with: context: . push: true @@ -100,7 +99,7 @@ - name: Build and push examples image id: build - uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # ratchet:docker/[email protected] + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # ratchet:docker/[email protected] with: context: . push: true @@ -143,8 +142,7 @@ permissions: contents: write # GoReleaser creates the GitHub release. needs: - - docker-conftest - - docker-examples + - check steps: - name: checkout source uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # ratchet:actions/checkout@v5 @@ -158,6 +156,11 @@ go-version-file: 'go.mod' cache: false + - name: install syft + uses: anchore/sbom-action/download-syft@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # ratchet:anchore/sbom-action/[email protected] + with: + syft-version: v1.52.0 + - name: release uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # ratchet:goreleaser/[email protected] with: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/.goreleaser.yml new/conftest-0.71.0/.goreleaser.yml --- old/conftest-0.70.1/.goreleaser.yml 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/.goreleaser.yml 2026-09-30 03:15:00.000000000 +0200 @@ -47,6 +47,9 @@ checksum: name_template: 'checksums.txt' +sboms: +- artifacts: archive + # The release is published by the workflow once all attestations succeed. release: draft: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/Dockerfile new/conftest-0.71.0/Dockerfile --- old/conftest-0.70.1/Dockerfile 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/Dockerfile 2026-09-30 03:15:00.000000000 +0200 @@ -51,7 +51,7 @@ WORKDIR /examples ## RELEASE ## -FROM alpine:3.24.1 +FROM alpine:3.24.2 # Install git for protocols that depend on it when using conftest pull RUN apk add --no-cache git diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/acceptance.bats new/conftest-0.71.0/acceptance.bats --- old/conftest-0.70.1/acceptance.bats 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/acceptance.bats 2026-09-30 03:15:00.000000000 +0200 @@ -286,6 +286,12 @@ [ "$status" -eq 0 ] } +@test "Can parse CODEOWNERS files" { + run ./conftest test -p examples/codeowners/policy examples/codeowners/CODEOWNERS + [ "$status" -eq 0 ] + [[ "$output" =~ "4 tests, 4 passed" ]] +} + @test "Can parse stdin with parser flag" { run bash -c "cat examples/ini/grafana.ini | ./conftest test -p examples/ini/policy --parser ini -" [ "$status" -eq 1 ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/docs/examples.md new/conftest-0.71.0/docs/examples.md --- old/conftest-0.70.1/docs/examples.md 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/docs/examples.md 2026-09-30 03:15:00.000000000 +0200 @@ -6,6 +6,7 @@ - [AWS SAM Framework](https://github.com/open-policy-agent/conftest/tree/master/examples/awssam) - [Builtin-Errors](https://github.com/open-policy-agent/conftest/tree/master/examples/builtin-errors) - [Capabilities](https://github.com/open-policy-agent/conftest/tree/master/examples/capabilities) +- [CODEOWNERS](https://github.com/open-policy-agent/conftest/tree/master/examples/codeowners) - [Combine](https://github.com/open-policy-agent/conftest/tree/master/examples/combine) - [Configfile](https://github.com/open-policy-agent/conftest/tree/master/examples/configfile) - [CUE](https://github.com/open-policy-agent/conftest/tree/master/examples/cue) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/docs/index.md new/conftest-0.71.0/docs/index.md --- old/conftest-0.70.1/docs/index.md 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/docs/index.md 2026-09-30 03:15:00.000000000 +0200 @@ -84,6 +84,7 @@ As of today Conftest supports: +- CODEOWNERS - CUE - CycloneDX - Dockerfile diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/examples/codeowners/CODEOWNERS new/conftest-0.71.0/examples/codeowners/CODEOWNERS --- old/conftest-0.70.1/examples/codeowners/CODEOWNERS 1970-01-01 01:00:00.000000000 +0100 +++ new/conftest-0.71.0/examples/codeowners/CODEOWNERS 2026-09-30 03:15:00.000000000 +0200 @@ -0,0 +1,18 @@ +# This is a comment. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in +# the repo. +* @bob @carol + +# Order is important; the last matching pattern takes the most +# precedence. When someone opens a pull request that only +# modifies JS files, only @my-org/js-devs and not the global +# owner(s) will be requested for a review. +*.js @my-org/js-devs # This is an inline comment. + +*.go @my-org/go-devs + +docs/ @my-org/librarians + +very/important/file @bob diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/examples/codeowners/policy/policy.rego new/conftest-0.71.0/examples/codeowners/policy/policy.rego --- old/conftest-0.70.1/examples/codeowners/policy/policy.rego 1970-01-01 01:00:00.000000000 +0100 +++ new/conftest-0.71.0/examples/codeowners/policy/policy.rego 2026-09-30 03:15:00.000000000 +0200 @@ -0,0 +1,33 @@ +package main +import rego.v1 + +# Check that file starts with default owner +deny contains msg if { + input.rules[0].pattern != "*" + msg := "first rule must assign default owner" +} + +deny contains msg if { + some rule in input.rules + rule.pattern == "*.js" + rule.owners != [{ + "type": "team", + "value": "my-org/js-devs", + }] + msg := "JavaScript files must be owned by my-org/js-devs" +} + +deny contains msg if { + some rule in input.rules + rule.pattern == "*.go" + rule.owners != [{ + "type": "team", + "value": "my-org/go-devs", + }] + msg := "go files must be owned by my-org/go-devs" +} + +deny contains msg if { + input.rules[-1].pattern != "very/important/file" + msg := "last rule must assign dedicated owner for very/important/file" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/go.mod new/conftest-0.71.0/go.mod --- old/conftest-0.70.1/go.mod 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/go.mod 2026-09-30 03:15:00.000000000 +0200 @@ -18,13 +18,14 @@ github.com/google/go-jsonnet v0.22.0 github.com/hashicorp/go-getter v1.8.9 github.com/hashicorp/hcl v1.0.0 + github.com/hmarr/codeowners v1.2.1 github.com/jstemmer/go-junit-report v1.0.0 github.com/logrusorgru/aurora v2.0.3+incompatible - github.com/magiconair/properties v1.18.11 + github.com/magiconair/properties v1.18.12 github.com/moby/buildkit v0.33.0 github.com/muhammadmuzzammil1998/jsonc v1.0.0 - github.com/olekukonko/tablewriter v1.1.4 - github.com/open-policy-agent/opa v1.20.2 + github.com/olekukonko/tablewriter v1.1.5 + github.com/open-policy-agent/opa v1.21.0 github.com/opencontainers/image-spec v1.1.1 github.com/owenrumney/go-sarif/v2 v2.3.3 github.com/shteou/go-ignore v0.3.1 @@ -96,7 +97,7 @@ github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect - github.com/gobwas/glob v0.2.3 // indirect + github.com/gobwas/glob v1.0.0 // indirect github.com/goccy/go-json v0.10.6 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect @@ -107,13 +108,13 @@ github.com/hashicorp/go-version v1.9.0 // indirect github.com/hashicorp/hcl/v2 v2.23.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/klauspost/compress v1.19.2 // indirect + github.com/klauspost/compress v1.20.0 // indirect github.com/lestrrat-go/blackmagic v1.0.4 // indirect - github.com/lestrrat-go/dsig v1.3.0 // indirect + github.com/lestrrat-go/dsig v1.4.0 // indirect github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc/v3 v3.0.6 // indirect - github.com/lestrrat-go/jwx/v3 v3.2.0 // indirect + github.com/lestrrat-go/jwx/v3 v3.3.0 // indirect github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -142,7 +143,7 @@ github.com/tonistiigi/go-csvvalue v0.0.0-20240814133006-030d3b2625d0 // indirect github.com/ulikunitz/xz v0.5.16 // indirect github.com/valyala/fastjson v1.6.10 // indirect - github.com/vektah/gqlparser/v2 v2.5.36 // indirect + github.com/vektah/gqlparser/v2 v2.5.37 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect @@ -159,13 +160,13 @@ go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect golang.org/x/crypto v0.56.0 // indirect - golang.org/x/mod v0.40.0 // indirect + golang.org/x/mod v0.41.0 // indirect golang.org/x/net v0.58.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sync v0.22.0 // indirect - golang.org/x/sys v0.47.0 // indirect - golang.org/x/text v0.41.0 // indirect - golang.org/x/time v0.15.0 // indirect + golang.org/x/sync v0.23.0 // indirect + golang.org/x/sys v0.48.0 // indirect + golang.org/x/text v0.42.0 // indirect + golang.org/x/time v0.16.0 // indirect golang.org/x/tools v0.49.0 // indirect google.golang.org/api v0.294.0 // indirect google.golang.org/genproto v0.0.0-20260715232425-e75dac1f907d // indirect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/go.sum new/conftest-0.71.0/go.sum --- old/conftest-0.70.1/go.sum 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/go.sum 2026-09-30 03:15:00.000000000 +0200 @@ -176,8 +176,9 @@ github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/glob v1.0.0 h1:p+FKbLEIsK1yZ39/OINwFvqNb5oyPY4H8xcy6uYu8dg= +github.com/gobwas/glob v1.0.0/go.mod h1:oWCdo522i2P1n/hMXGNWs7yoV4wy/ciZuUIbvKj5rkc= github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godoctor/godoctor v0.0.0-20181123222458-69df17f3a6f6/go.mod h1:+tyhT8jBF8E0XvdlSXOSL7Iko7DlNiongHq3q+wcsPs= @@ -214,6 +215,8 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos= github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= +github.com/hmarr/codeowners v1.2.1 h1:+9yndrwG0UVP1GkLBEQMSbSUNeLpbrbL924SRthA/9k= +github.com/hmarr/codeowners v1.2.1/go.mod h1:KPlR1p/B4owPjwfNIBueWlOP4CmqlQFX9b6nANG6j40= github.com/imega/luaformatter v0.0.0-20211025140405-86b0a68d6bef h1:RC993DdTIHNItsyLj79fgZNLzrf9tBN0GR6W5ZPms6s= github.com/imega/luaformatter v0.0.0-20211025140405-86b0a68d6bef/go.mod h1:i2XCfvmO94HrEOQWllihhtPrkvNfuB2R2p/o6+OVnRU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -222,8 +225,8 @@ github.com/jstemmer/go-junit-report v1.0.0 h1:8X1gzZpR+nVQLAht+L/foqOeX2l9DTZoaIPbEQHxsds= github.com/jstemmer/go-junit-report v1.0.0/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= -github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= -github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.20.0 h1:a3C1ke2ohxFymNlb2HWAHjDeKCI90scRskErZkR0ezA= +github.com/klauspost/compress v1.20.0/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -235,16 +238,16 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= -github.com/lestrrat-go/dsig v1.3.0 h1:phjMOCXvYzhuIgn7Voe2rex8z166vGfxRxmqM25P9/Q= -github.com/lestrrat-go/dsig v1.3.0/go.mod h1:RD2eOaidyPvpc7IJQoO3Qq52RWdy8ZcJs8lrOnoa1Kc= +github.com/lestrrat-go/dsig v1.4.0 h1:g7LUjK8cT74A5DzBXJI5HzsJuLhoYN0Wzj4nuOMIrH8= +github.com/lestrrat-go/dsig v1.4.0/go.mod h1:I8Nddg/vN2cUl/h8N7SRRApLnNNeyZPIqLYpvpOtGGo= github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7gcrVVMFPOzY= github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/httprc/v3 v3.0.6 h1:4FpLQ18KK/ypPbVU3NLWJNRvH3kcYiqKqWfKGqNWxxI= github.com/lestrrat-go/httprc/v3 v3.0.6/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0= -github.com/lestrrat-go/jwx/v3 v3.2.0 h1:Jb3zBASTSZXz7gzzSAfYqxXF8KejvKC4xWoePLQqXCA= -github.com/lestrrat-go/jwx/v3 v3.2.0/go.mod h1:38vQ8iWKq3qRSbilbzvzdQPuywhowwuR03lhkYskyrw= +github.com/lestrrat-go/jwx/v3 v3.3.0 h1:OXcYvQOQ7cxWzeZ/Q9sYk8ABe/kCSI371WmuACiCT+4= +github.com/lestrrat-go/jwx/v3 v3.3.0/go.mod h1:eIJhDcKHBwcgxqv8RiIylV67TVl1wJp/265IAHY1Db8= github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= @@ -252,8 +255,8 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.18.11 h1:j5ozYZl0zCjG7ahMDH0GWIobOvvUzT0BdAguG0ViKy0= -github.com/magiconair/properties v1.18.11/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/magiconair/properties v1.18.12 h1:sT9zQpvTB3B4gzrX0tmZNTEaGyg8Zw55MFYRE32Mr9I= +github.com/magiconair/properties v1.18.12/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -283,10 +286,10 @@ github.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= github.com/olekukonko/ll v0.1.6 h1:lGVTHO+Qc4Qm+fce/2h2m5y9LvqaW+DCN7xW9hsU3uA= github.com/olekukonko/ll v0.1.6/go.mod h1:NVUmjBb/aCtUpjKk75BhWrOlARz3dqsM+OtszpY4o88= -github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= -github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= -github.com/open-policy-agent/opa v1.20.2 h1:dlX5VEGA5M62W8+X1nRPEaQIh/CMRn5FcD1mebpKWKg= -github.com/open-policy-agent/opa v1.20.2/go.mod h1:yYKTQAlkbefoXSYChT4ek8gc8WCtScL7L7OSZxFVe0s= +github.com/olekukonko/tablewriter v1.1.5 h1:4LoZSfMySpMQY3PT8RWJsJeuEuMIoo9xGRgvmqjg6IQ= +github.com/olekukonko/tablewriter v1.1.5/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= +github.com/open-policy-agent/opa v1.21.0 h1:k/N0fieTkBPM0H7mIOrMd/xZPaMsxW70jIzIPeOBst4= +github.com/open-policy-agent/opa v1.21.0/go.mod h1:eJL6KUOIaW5YLnhJEA6sm3FOYRDJaHZvYT6geATbpPk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -306,8 +309,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59uiuyR2bPlnU= github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE= -github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= -github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/client_model v0.6.3 h1:O0jaTVAYNxTHYInEPFJt5I3+sN8zqBtVMPTB1qyxiEo= +github.com/prometheus/client_model v0.6.3/go.mod h1:gpN5P9S7Rr6Yr92PiQ+Ixvhf6JZEkF1dnxsYL2aPBEM= github.com/prometheus/common v0.70.1 h1:1HvjP4D5oL3t8RsPlwxA9onvvStjtIHYE5XuuwOi/PY= github.com/prometheus/common v0.70.1/go.mod h1:VdFUQDMZK3VLkurFUVhia6uys/0suUp86TJz5qbJRhc= github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI= @@ -387,8 +390,8 @@ github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= github.com/vektah/gqlparser v1.2.0/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74= -github.com/vektah/gqlparser/v2 v2.5.36 h1:CN9mKVHgMkc+XftdOWIhb4HEL8wKSYkFAqhf8booa7s= -github.com/vektah/gqlparser/v2 v2.5.36/go.mod h1:cAJ9qwVgPaUkWv6Gn8vn0mqOE0Ui5Pn56wNy5396XWo= +github.com/vektah/gqlparser/v2 v2.5.37 h1:jbb1Ilv+xBklV6653tKb4oVUupPNTLb5LmrnBKVI12Y= +github.com/vektah/gqlparser/v2 v2.5.37/go.mod h1:9O4Ox6Ngd3Y12bMD3w6i3CRQXh8W1oC1q0m6olCymDM= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= @@ -439,8 +442,8 @@ golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= golang.org/x/exp v0.0.0-20260603202125-055de637280b h1:v1uXiEBHo8QA0LiGCo7UgHMzHT4Kdfpl2zmtH5vaP1Q= golang.org/x/exp v0.0.0-20260603202125-055de637280b/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw= -golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs= -golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE= +golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c= +golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -449,21 +452,21 @@ golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= -golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= +golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= -golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= +golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= -golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= -golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= -golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= +golang.org/x/time v0.16.0 h1:vMb6ptszcQMkcwiRTAuNNU50gom6++Q/6gY2hDM6VDE= +golang.org/x/time v0.16.0/go.mod h1:rVKOqvZeKvrDKTQiAHJ7wmwP0RzleSphoEA9RcdLA0s= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/output/azuredevops.go new/conftest-0.71.0/output/azuredevops.go --- old/conftest-0.70.1/output/azuredevops.go 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/output/azuredevops.go 2026-09-30 03:15:00.000000000 +0200 @@ -25,76 +25,35 @@ // Output outputs the results. func (t *AzureDevOps) Output(checkResults CheckResults) error { - var totalFailures int - var totalExceptions int - var totalWarnings int - var totalSuccesses int - var totalSkipped int - for _, result := range checkResults { - totalPolicies := result.Successes + len(result.Failures) + len(result.Warnings) + len(result.Exceptions) + len(result.Skipped) + totalPolicies := result.Totals().Tests() - fmt.Fprintf(t.writer, "##[section]Testing '%v' against %v policies in namespace '%v'\n", result.FileName, totalPolicies, result.Namespace) + fmt.Fprintf(t.writer, "##[section]Testing '%s' against %d policies in namespace '%s'\n", result.FileName, totalPolicies, result.Namespace) fmt.Fprintf(t.writer, "##[group]See conftest results\n") for _, failure := range result.Failures { - fmt.Fprintf(t.writer, "##vso[task.logissue type=error] file=%v --> %v\n", result.FileName, failure.Message) + fmt.Fprintf(t.writer, "##vso[task.logissue type=error] file=%s --> %s\n", result.FileName, failure.Message) } for _, warning := range result.Warnings { - fmt.Fprintf(t.writer, "##vso[task.logissue type=warning] file=%v --> %v\n", result.FileName, warning.Message) + fmt.Fprintf(t.writer, "##vso[task.logissue type=warning] file=%s --> %s\n", result.FileName, warning.Message) } for _, exception := range result.Exceptions { - fmt.Fprintf(t.writer, "##vso[task.logissue type=warning] file=%v --> %v\n", result.FileName, exception.Message) + fmt.Fprintf(t.writer, "##vso[task.logissue type=warning] file=%s --> %s\n", result.FileName, exception.Message) } for _, skipped := range result.Skipped { - fmt.Fprintf(t.writer, "skipped file=%v %v\n", result.FileName, skipped.Message) + fmt.Fprintf(t.writer, "skipped file=%s %s\n", result.FileName, skipped.Message) } if result.Successes > 0 { - fmt.Fprintf(t.writer, "success file=%v %v\n", result.FileName, result.Successes) + fmt.Fprintf(t.writer, "success file=%s %d\n", result.FileName, result.Successes) } - totalFailures += len(result.Failures) - totalExceptions += len(result.Exceptions) - totalWarnings += len(result.Warnings) - totalSkipped += len(result.Skipped) - totalSuccesses += result.Successes - fmt.Fprintf(t.writer, "##[endgroup]\n") } - totalTests := totalFailures + totalExceptions + totalWarnings + totalSuccesses + totalSkipped - - var pluralSuffixTests string - if totalTests != 1 { - pluralSuffixTests = "s" - } - - var pluralSuffixWarnings string - if totalWarnings != 1 { - pluralSuffixWarnings = "s" - } - - var pluralSuffixFailures string - if totalFailures != 1 { - pluralSuffixFailures = "s" - } - - var pluralSuffixExceptions string - if totalExceptions != 1 { - pluralSuffixExceptions = "s" - } - - outputText := fmt.Sprintf("%v test%s, %v passed, %v warning%s, %v failure%s, %v exception%s", - totalTests, pluralSuffixTests, - totalSuccesses, - totalWarnings, pluralSuffixWarnings, - totalFailures, pluralSuffixFailures, - totalExceptions, pluralSuffixExceptions, - ) - fmt.Fprintln(t.writer, outputText) + fmt.Fprintln(t.writer, checkResults.Totals()) return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/output/github.go new/conftest-0.71.0/output/github.go --- old/conftest-0.70.1/output/github.go 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/output/github.go 2026-09-30 03:15:00.000000000 +0200 @@ -42,25 +42,14 @@ // Output outputs the results. func (g *GitHub) Output(checkResults CheckResults) error { - var totalFailures int - var totalExceptions int - var totalWarnings int - var totalSuccesses int - var totalSkipped int for _, result := range checkResults { - totalFailures += len(result.Failures) - totalExceptions += len(result.Exceptions) - totalWarnings += len(result.Warnings) - totalSkipped += len(result.Skipped) - totalSuccesses += result.Successes - // When hidePassed is set, skip files that only have successful checks. - // Their tests still count toward the summary line tallied above. + // Their tests still count toward the summary line. if g.hidePassed && len(result.Failures) == 0 && len(result.Warnings) == 0 && len(result.Exceptions) == 0 && len(result.Skipped) == 0 { continue } - numPolicies := result.Successes + len(result.Failures) + len(result.Warnings) + len(result.Exceptions) + len(result.Skipped) + numPolicies := result.Totals().Tests() fileLoc := &Location{File: result.FileName, Line: json.Number("1")} @@ -81,15 +70,7 @@ g.writeLn("::endgroup::") } - totalTests := totalFailures + totalExceptions + totalWarnings + totalSuccesses + totalSkipped - - g.writeLn("%d %s, %d passed, %d %s, %d %s, %d %s", - totalTests, plural("test", totalTests), - totalSuccesses, - totalWarnings, plural("warning", totalWarnings), - totalFailures, plural("failure", totalFailures), - totalExceptions, plural("exception", totalExceptions), - ) + g.writeLn("%s", checkResults.Totals()) return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/output/result.go new/conftest-0.71.0/output/result.go --- old/conftest-0.70.1/output/result.go 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/output/result.go 2026-09-30 03:15:00.000000000 +0200 @@ -212,3 +212,60 @@ } return 0 } + +// Totals holds the number of results of each type. +type Totals struct { + Successes int + Failures int + Warnings int + Exceptions int + Skipped int +} + +// Totals returns the number of results of each type in the check. +func (cr CheckResult) Totals() Totals { + return Totals{ + Successes: cr.Successes, + Failures: len(cr.Failures), + Warnings: len(cr.Warnings), + Exceptions: len(cr.Exceptions), + Skipped: len(cr.Skipped), + } +} + +// Totals returns the number of results of each type across all of the checks. +func (cr CheckResults) Totals() Totals { + var totals Totals + for _, result := range cr { + totals = totals.Add(result.Totals()) + } + return totals +} + +// Add returns the sum of the two totals. +func (t Totals) Add(o Totals) Totals { + return Totals{ + Successes: t.Successes + o.Successes, + Failures: t.Failures + o.Failures, + Warnings: t.Warnings + o.Warnings, + Exceptions: t.Exceptions + o.Exceptions, + Skipped: t.Skipped + o.Skipped, + } +} + +// Tests returns the total number of tests. +func (t Totals) Tests() int { + return t.Successes + t.Failures + t.Warnings + t.Exceptions + t.Skipped +} + +// String returns the summary line for the totals. Skipped +// results are counted as tests, but are not listed. +func (t Totals) String() string { + return fmt.Sprintf("%d %s, %d passed, %d %s, %d %s, %d %s", + t.Tests(), plural("test", t.Tests()), + t.Successes, + t.Warnings, plural("warning", t.Warnings), + t.Failures, plural("failure", t.Failures), + t.Exceptions, plural("exception", t.Exceptions), + ) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/output/result_test.go new/conftest-0.71.0/output/result_test.go --- old/conftest-0.70.1/output/result_test.go 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/output/result_test.go 2026-09-30 03:15:00.000000000 +0200 @@ -234,3 +234,66 @@ }) } } + +func TestTotals(t *testing.T) { + t.Parallel() + + mixed := CheckResult{ + Successes: 3, + Failures: []Result{{}, {}}, + Warnings: []Result{{}}, + Exceptions: []Result{{}}, + Skipped: []Result{{}}, + } + + failure := CheckResult{ + Failures: []Result{{}}, + } + + testCases := []struct { + results CheckResults + expected Totals + expectedTests int + expectedText string + }{ + { + results: CheckResults{}, + expectedText: "0 tests, 0 passed, 0 warnings, 0 failures, 0 exceptions", + }, + { + results: CheckResults{failure}, + expected: Totals{Failures: 1}, + expectedTests: 1, + expectedText: "1 test, 0 passed, 0 warnings, 1 failure, 0 exceptions", + }, + { + results: CheckResults{mixed}, + expected: Totals{Successes: 3, Failures: 2, Warnings: 1, Exceptions: 1, Skipped: 1}, + expectedTests: 8, + expectedText: "8 tests, 3 passed, 1 warning, 2 failures, 1 exception", + }, + { + results: CheckResults{mixed, failure, mixed}, + expected: Totals{Successes: 6, Failures: 5, Warnings: 2, Exceptions: 2, Skipped: 2}, + expectedTests: 17, + expectedText: "17 tests, 6 passed, 2 warnings, 5 failures, 2 exceptions", + }, + } + + for i, testCase := range testCases { + t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Parallel() + + actual := testCase.results.Totals() + if actual != testCase.expected { + t.Errorf("Unexpected totals. expected %+v, actual %+v", testCase.expected, actual) + } + if actual.Tests() != testCase.expectedTests { + t.Errorf("Unexpected number of tests. expected %v, actual %v", testCase.expectedTests, actual.Tests()) + } + if actual.String() != testCase.expectedText { + t.Errorf("Unexpected summary. expected %q, actual %q", testCase.expectedText, actual.String()) + } + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/output/standard.go new/conftest-0.71.0/output/standard.go --- old/conftest-0.70.1/output/standard.go 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/output/standard.go 2026-09-30 03:15:00.000000000 +0200 @@ -58,11 +58,6 @@ s.outputPrints(results, colorizer) - var totalFailures int - var totalExceptions int - var totalWarnings int - var totalSuccesses int - var totalSkipped int for _, result := range results { var indicator string var namespace string @@ -91,54 +86,21 @@ fmt.Fprintln(s.Writer, colorizer.Colorize("EXCP", aurora.CyanFg), indicator, namespace, exception.Message) } } - - totalFailures += len(result.Failures) - totalExceptions += len(result.Exceptions) - totalWarnings += len(result.Warnings) - totalSkipped += len(result.Skipped) - totalSuccesses += result.Successes - } - - totalTests := totalFailures + totalExceptions + totalWarnings + totalSuccesses + totalSkipped - - var pluralSuffixTests string - if totalTests != 1 { - pluralSuffixTests = "s" - } - - var pluralSuffixWarnings string - if totalWarnings != 1 { - pluralSuffixWarnings = "s" - } - - var pluralSuffixFailures string - if totalFailures != 1 { - pluralSuffixFailures = "s" - } - - var pluralSuffixExceptions string - if totalExceptions != 1 { - pluralSuffixExceptions = "s" } - outputText := fmt.Sprintf("%v test%s, %v passed, %v warning%s, %v failure%s, %v exception%s", - totalTests, pluralSuffixTests, - totalSuccesses, - totalWarnings, pluralSuffixWarnings, - totalFailures, pluralSuffixFailures, - totalExceptions, pluralSuffixExceptions, - ) + totals := results.Totals() + outputText := totals.String() if s.ShowSkipped { - outputText += fmt.Sprintf(", %v skipped", totalSkipped) + outputText += fmt.Sprintf(", %d skipped", totals.Skipped) } var outputColor aurora.Color - if totalFailures > 0 { + if totals.Failures > 0 { outputColor = aurora.RedFg - } else if totalWarnings > 0 { + } else if totals.Warnings > 0 { outputColor = aurora.YellowFg - } else if totalExceptions > 0 { + } else if totals.Exceptions > 0 { outputColor = aurora.CyanFg } else { outputColor = aurora.GreenFg diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/output/tap.go new/conftest-0.71.0/output/tap.go --- old/conftest-0.70.1/output/tap.go 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/output/tap.go 2026-09-30 03:15:00.000000000 +0200 @@ -3,6 +3,7 @@ import ( "fmt" "io" + "slices" "github.com/open-policy-agent/opa/v1/tester" ) @@ -24,6 +25,16 @@ // Output outputs the results. func (t *TAP) Output(checkResults CheckResults) error { + // TAP expects a single plan for the whole stream, with test numbers + // continuing across all of the checks. + totalTests := checkResults.Totals().Tests() + if totalTests == 0 { + return nil + } + + fmt.Fprintf(t.Writer, "1..%d\n", totalTests) + + counter := 1 for _, result := range checkResults { var indicator string var namespace string @@ -39,47 +50,24 @@ namespace = fmt.Sprintf("- %s -", result.Namespace) } - totalTests := result.Successes + len(result.Failures) + len(result.Warnings) + len(result.Exceptions) + len(result.Skipped) - if totalTests == 0 { - return nil + sections := []struct { + header string + status string + results []Result + }{ + {status: "not ok", results: result.Failures}, + {header: "warnings", status: "not ok", results: result.Warnings}, + {header: "exceptions", status: "ok", results: result.Exceptions}, + {header: "skip", status: "ok", results: result.Skipped}, + {header: "successes", status: "ok", results: slices.Repeat([]Result{{Message: "SUCCESS"}}, result.Successes)}, } - counter := 1 - fmt.Fprintf(t.Writer, "1..%d\n", totalTests) - - for _, failure := range result.Failures { - fmt.Fprintf(t.Writer, "not ok %v %v %v %v\n", counter, indicator, namespace, failure.Message) - counter++ - } - - if len(result.Warnings) > 0 { - fmt.Fprintln(t.Writer, "# warnings") - for _, warning := range result.Warnings { - fmt.Fprintf(t.Writer, "not ok %v %v %v %v\n", counter, indicator, namespace, warning.Message) - counter++ + for _, section := range sections { + if section.header != "" && len(section.results) > 0 { + fmt.Fprintln(t.Writer, "#", section.header) } - } - - if len(result.Exceptions) > 0 { - fmt.Fprintln(t.Writer, "# exceptions") - for _, exception := range result.Exceptions { - fmt.Fprintf(t.Writer, "ok %v %v %v %v\n", counter, indicator, namespace, exception.Message) - counter++ - } - } - - if len(result.Skipped) > 0 { - fmt.Fprintln(t.Writer, "# skip") - for _, skipped := range result.Skipped { - fmt.Fprintf(t.Writer, "ok %v %v %v %v\n", counter, indicator, namespace, skipped.Message) - counter++ - } - } - - if result.Successes > 0 { - fmt.Fprintln(t.Writer, "# successes") - for i := 0; i < result.Successes; i++ { - fmt.Fprintf(t.Writer, "ok %v %v %v %v\n", counter, indicator, namespace, "SUCCESS") + for _, r := range section.results { + fmt.Fprintf(t.Writer, "%s %d %s %s %s\n", section.status, counter, indicator, namespace, r.Message) counter++ } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/output/tap_test.go new/conftest-0.71.0/output/tap_test.go --- old/conftest-0.70.1/output/tap_test.go 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/output/tap_test.go 2026-09-30 03:15:00.000000000 +0200 @@ -41,6 +41,50 @@ }, }, { + name: "multiple files use a single plan with continuous numbering", + input: CheckResults{ + { + FileName: "examples/kubernetes/service.yaml", + Namespace: "namespace", + Failures: []Result{{Message: "first failure"}}, + }, + { + FileName: "examples/kubernetes/deployment.yaml", + Namespace: "namespace", + Warnings: []Result{{Message: "second file warning"}}, + Successes: 1, + }, + }, + expected: []string{ + "1..3", + "not ok 1 - examples/kubernetes/service.yaml - namespace - first failure", + "# warnings", + "not ok 2 - examples/kubernetes/deployment.yaml - namespace - second file warning", + "# successes", + "ok 3 - examples/kubernetes/deployment.yaml - namespace - SUCCESS", + "", + }, + }, + { + name: "files without tests do not truncate later results", + input: CheckResults{ + { + FileName: "examples/kubernetes/service.yaml", + Namespace: "namespace", + }, + { + FileName: "examples/kubernetes/deployment.yaml", + Namespace: "namespace", + Failures: []Result{{Message: "first failure"}}, + }, + }, + expected: []string{ + "1..1", + "not ok 1 - examples/kubernetes/deployment.yaml - namespace - first failure", + "", + }, + }, + { name: "mixed failure, warnings and skipped", input: CheckResults{ { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/parser/codeowners/codeowners.go new/conftest-0.71.0/parser/codeowners/codeowners.go --- old/conftest-0.70.1/parser/codeowners/codeowners.go 1970-01-01 01:00:00.000000000 +0100 +++ new/conftest-0.71.0/parser/codeowners/codeowners.go 2026-09-30 03:15:00.000000000 +0200 @@ -0,0 +1,114 @@ +// Package codeowners provides a parser for CODEOWNERS files +// +// A [CODEOWNERS] file defines which reviewers are required for various +// files within a repository. The file format is similar to +// [gitignore]. +// +// GitHub searches for the CODEOWNERS file in the following priority +// order relative to the repository root: +// - .github/CODEOWNERS +// - CODEOWNERS +// - docs/CODEOWNERS +// +// [CODEOWNERS]: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +// [gitignore]: https://git-scm.com/docs/gitignore +package codeowners + +import ( + "bytes" + "encoding/json" + "fmt" + + "github.com/hmarr/codeowners" +) + +// codeowners contains required reviewers for zero or more file patterns. +type owners struct { + Rules []rule `json:"rules"` +} + +// rule contains the required reviewers for a file pattern. +type rule struct { + Pattern string `json:"pattern"` + Owners []owner `json:"owners"` + Comment string `json:"comment"` + LineNumber int `json:"lineNumber"` +} + +type ownerType string + +const ( + // EmailOwner is the owner type for email addresses. + emailOwner ownerType = "email" + // TeamOwner is the owner type for GitHub teams. + teamOwner ownerType = "team" + // UsernameOwner is the owner type for GitHub usernames. + usernameOwner ownerType = "username" +) + +// owner contains information about a codeowner +type owner struct { + Type ownerType `json:"type"` + Value string `json:"value"` +} + +func ownerFromEmail(email string) owner { + return owner{ + Type: emailOwner, + Value: email, + } +} + +func ownerFromTeam(team string) owner { + return owner{ + Type: teamOwner, + Value: team, + } +} + +func ownerFromUsername(username string) owner { + return owner{ + Type: usernameOwner, + Value: username, + } +} + +// Parser is a CODEOWNERS file parser. +type Parser struct{} + +// Unmarshal unmarshals a CODEOWNERS file. +func (p *Parser) Unmarshal(data []byte, v any) error { + f := bytes.NewBuffer(data) + ruleset, err := codeowners.ParseFile(f) + if err != nil { + return fmt.Errorf("failed to parse CODEOWNERS: %w", err) + } + + config := owners{} + for _, r := range ruleset { + os := make([]owner, len(r.Owners)) + for i, o := range r.Owners { + os[i] = owner{ + Type: ownerType(o.Type), + Value: o.Value, + } + } + config.Rules = append(config.Rules, rule{ + Pattern: r.RawPattern(), + Owners: os, + Comment: r.Comment, + LineNumber: r.LineNumber, + }) + } + + j, err := json.Marshal(config) + if err != nil { + return fmt.Errorf("marshal CODEOWNERS to json: %w", err) + } + + if err := json.Unmarshal(j, v); err != nil { + return fmt.Errorf("unmarshal CODEOWNERS json: %w", err) + } + + return nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/parser/codeowners/codeowners_test.go new/conftest-0.71.0/parser/codeowners/codeowners_test.go --- old/conftest-0.70.1/parser/codeowners/codeowners_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/conftest-0.71.0/parser/codeowners/codeowners_test.go 2026-09-30 03:15:00.000000000 +0200 @@ -0,0 +1,247 @@ +package codeowners + +import ( + "encoding/json" + "fmt" + "testing" +) + +const codePath = "/apps/code.go" + +var ( + bobEmail = ownerFromEmail("[email protected]") + bobUser = ownerFromUsername("bob") + carolUser = ownerFromUsername("carol") + developersTeam = ownerFromTeam("my-org/developers") + librariansTeam = ownerFromTeam("my-org/librarians") + goOwner = ownerFromUsername("go-owner") +) + +func TestParser(t *testing.T) { + tests := []struct { + name string + input []byte + want owners + wantErr bool + }{ + { + name: "anyone with write access", + // A lone pattern requires a review from anyone with write access + input: []byte(codePath), + want: owners{ + Rules: []rule{ + { + Pattern: codePath, + Owners: []owner{}, + }, + }, + }, + }, + { + name: "comment", + input: []byte(`# Just a comment`), + want: owners{ + Rules: []rule{}, + }, + }, + { + name: "user owner", + input: []byte(`* @bob`), + want: owners{ + Rules: []rule{ + { + Pattern: "*", + Owners: []owner{bobUser}, + }, + }, + }, + }, + { + name: "email owner", + input: []byte(`*.go [email protected]`), + want: owners{ + Rules: []rule{ + { + Pattern: "*.go", + Owners: []owner{bobEmail}, + }, + }, + }, + }, + { + name: "team owner", + input: []byte(`*.txt @my-org/developers`), + want: owners{ + Rules: []rule{ + { + Pattern: "*.txt", + Owners: []owner{developersTeam}, + }, + }, + }, + }, + { + name: "two owners", + input: []byte(`* @bob @carol`), + want: owners{ + Rules: []rule{ + { + Pattern: "*", + Owners: []owner{bobUser, carolUser}, + }, + }, + }, + }, + { + name: "inline comment", + input: []byte(`*.js @carol #This is an inline comment.`), + want: owners{ + Rules: []rule{ + { + Pattern: "*.js", + Owners: []owner{carolUser}, + }, + }, + }, + }, + { + name: "folder path", + input: []byte(`/build/logs/ @my-org/librarians`), + want: owners{ + Rules: []rule{ + { + Pattern: "/build/logs/", + Owners: []owner{librariansTeam}, + }, + }, + }, + }, + { + name: "multi-line example", + input: []byte(`# This is a comment. +# Default owner +* @my-org/developers + +# Special owner for go files +*.go @go-owner + +*.txt @bob + +docs/ @my-org/librarians + +/scripts/ @bob @carol +`), + want: owners{ + Rules: []rule{ + { + Pattern: "*", + Owners: []owner{developersTeam}, + }, + { + Pattern: "*.go", + Owners: []owner{goOwner}, + }, + { + Pattern: "*.txt", + Owners: []owner{bobUser}, + }, + { + Pattern: "docs/", + Owners: []owner{librariansTeam}, + }, + { + Pattern: "/scripts/", + Owners: []owner{bobUser, carolUser}, + }, + }, + }, + }, + { + name: "windows line endings", + input: []byte("# developers by default\r\n* @my-org/developers\r\n# librarians for docs\r\ndocs/\t@my-org/librarians\r\n"), + want: owners{ + Rules: []rule{ + { + Pattern: "*", + Owners: []owner{developersTeam}, + }, + { + Pattern: "docs/", + Owners: []owner{librariansTeam}, + }, + }, + }, + }, + } + + parser := &Parser{} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var parsedInput any + err := parser.Unmarshal(tt.input, &parsedInput) + if (err != nil) != tt.wantErr { + t.Errorf("Unmarshal() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr && parsedInput == nil { + t.Fatal("expected parsed content, got nil") + } + + got := roundTrip(t, parsedInput) + if err != nil { + t.Fatalf("round trip of CODEOWNERS failed: %v", err) + } + expectCodeowners(t, got, tt.want) + }) + } +} + +func roundTrip(t *testing.T, parsed any) owners { + t.Helper() + ownersJSON, err := json.Marshal(parsed) + if err != nil { + t.Fatalf("marshal CODEOWNERS to JSON: %v", err) + } + var output owners + if err := json.Unmarshal(ownersJSON, &output); err != nil { + t.Fatalf("unmarshal CODEOWNERS JSON: %v", err) + } + return output +} + +func expectCodeowners(t *testing.T, got, want owners) { + t.Helper() + if len(got.Rules) != len(want.Rules) { + t.Errorf("expected %d rules, got %d rules", len(want.Rules), len(got.Rules)) + return + } + for i, wantRule := range want.Rules { + gotRule := got.Rules[i] + expectRule(t, gotRule, wantRule) + } +} + +func expectRule(t *testing.T, got, want rule) { + t.Helper() + if got.Pattern != want.Pattern { + t.Errorf("line %d: expected '%s' pattern, got '%s'", got.LineNumber, want.Pattern, got.Pattern) + } + if len(got.Owners) != len(want.Owners) { + t.Errorf("line %d: expected %d owners, got %d owners", got.LineNumber, len(want.Owners), len(got.Owners)) + return + } + for i, wantOwner := range want.Owners { + gotOwner := got.Owners[i] + err := expectOwner(gotOwner, wantOwner) + if err != nil { + t.Errorf("line %d: owner %d: %v", got.LineNumber, i, err) + } + } +} + +func expectOwner(got, want owner) error { + if got.Type != want.Type || got.Value != want.Value { + return fmt.Errorf("expected: %s %s, got %s %s", want.Type, want.Value, got.Type, got.Value) + } + return nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/parser/parser.go new/conftest-0.71.0/parser/parser.go --- old/conftest-0.70.1/parser/parser.go 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/parser/parser.go 2026-09-30 03:15:00.000000000 +0200 @@ -13,6 +13,7 @@ "github.com/spf13/viper" "golang.org/x/exp/slices" + "github.com/open-policy-agent/conftest/parser/codeowners" "github.com/open-policy-agent/conftest/parser/cue" "github.com/open-policy-agent/conftest/parser/cyclonedx" "github.com/open-policy-agent/conftest/parser/docker" @@ -40,6 +41,7 @@ // The defined parsers are the parsers that are valid for // parsing files. const ( + CODEOWNERS = "codeowners" CUE = "cue" CYCLONEDX = "cyclonedx" Dockerfile = "dockerfile" @@ -135,6 +137,8 @@ } return parser, nil + case CODEOWNERS: + return &codeowners.Parser{}, nil default: return nil, fmt.Errorf("unknown parser: %v", parser) } @@ -221,6 +225,10 @@ return New(TEXTPROTO) } + if fileName == "codeowners" { + return New(CODEOWNERS) + } + parser, err := New(fileExtension) if err != nil { return nil, fmt.Errorf("new: %w", err) @@ -232,6 +240,7 @@ // Parsers returns a list of the supported Parsers. func Parsers() []string { parsers := []string{ + CODEOWNERS, CUE, CYCLONEDX, Dockerfile, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/requirements.txt new/conftest-0.71.0/requirements.txt --- old/conftest-0.70.1/requirements.txt 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/requirements.txt 2026-09-30 03:15:00.000000000 +0200 @@ -1,2 +1,2 @@ -mkdocs==1.3.0 -mkdocs-material==4.6.3 +mkdocs==1.6.1 +mkdocs-material==9.7.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/conftest-0.70.1/runtime.txt new/conftest-0.71.0/runtime.txt --- old/conftest-0.70.1/runtime.txt 2026-09-19 18:32:18.000000000 +0200 +++ new/conftest-0.71.0/runtime.txt 2026-09-30 03:15:00.000000000 +0200 @@ -1 +1 @@ -3.8 \ No newline at end of file +3.12 ++++++ conftest.obsinfo ++++++ --- /var/tmp/diff_new_pack.KWT4EC/_old 2026-10-06 19:17:48.874021256 +0200 +++ /var/tmp/diff_new_pack.KWT4EC/_new 2026-10-06 19:17:48.878021424 +0200 @@ -1,5 +1,5 @@ name: conftest -version: 0.70.1 -mtime: 1789835538 -commit: 0b42cb5cd1aa1dc1c9025a5e83c7e963166d08c0 +version: 0.71.0 +mtime: 1790730900 +commit: 8345c40e21f3e6ab1159f4e15585b5f7d6aa32a7 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/conftest/vendor.tar.gz /work/SRC/openSUSE:Factory/.conftest.new.3698736/vendor.tar.gz differ: char 13, line 1
