Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ sec: | $(TOOL_BIN_DIR)/gosec # Check for security vulnerabilities
$(CHECK_FILES)

vulncheck: $(TOOL_BIN_DIR)/govulncheck # Check for known vulnerabilities
$(TOOL_BIN_DIR)/govulncheck -format json $(CHECK_FILES) | go run ./hack/vulncheck-filter
$(TOOL_BIN_DIR)/govulncheck $(CHECK_FILES) | go run ./hack/vulncheck-filter

unused: | $(TOOL_BIN_DIR)/staticcheck # Look for unused code
@echo "Unused code:"
Expand Down Expand Up @@ -181,6 +181,7 @@ format:
gofmt -s -w .

clean:
$(MAKE) -C tools clean
rm -rf \
$(addprefix release-,$(RELEASE_TARGETS)) \
$(addprefix auth-,$(RELEASE_TARGETS)) \
Expand Down
16 changes: 1 addition & 15 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -40,43 +40,30 @@ require (
github.com/consensys/gnark-crypto v0.18.1 // indirect
github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
github.com/getkin/kin-openapi v0.131.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/go-webauthn/x v0.2.3 // indirect
github.com/gobuffalo/nulls v0.4.2 // indirect
github.com/goccy/go-json v0.10.4 // indirect
github.com/google/go-tpm v0.9.8 // indirect
github.com/holiman/uint256 v1.3.2 // indirect
github.com/jackc/pgx/v4 v4.18.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.5 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/philhofer/fwd v1.2.0 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect
github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect
github.com/tinylib/msgp v1.6.4 // indirect
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
golang.org/x/mod v0.34.0 // indirect
golang.org/x/tools v0.43.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect
)
Expand Down Expand Up @@ -108,7 +95,6 @@ require (
github.com/gobuffalo/pop/v6 v6.1.1
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/lestrrat-go/jwx/v2 v2.1.0
github.com/oapi-codegen/oapi-codegen/v2 v2.4.2-0.20250102212541-8bbe226927c9
github.com/oapi-codegen/runtime v1.1.1
github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20240303152453-e0e82adf1721
github.com/supabase/hibp v0.0.0-20231124125943-d225752ae869
Expand Down Expand Up @@ -186,4 +172,4 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)

go 1.25.8
go 1.25.10
91 changes: 0 additions & 91 deletions go.sum

Large diffs are not rendered by default.

66 changes: 25 additions & 41 deletions hack/vulncheck-filter/main.go
Original file line number Diff line number Diff line change
@@ -1,61 +1,45 @@
package main

import (
"encoding/json"
"fmt"
"io"
"os"
"slices"
)

// Vulnerabilities with no upstream fix — remove entries once fixed.
var ignore = map[string]string{
"GO-2026-4518": "pgproto3/v2 DoS, no fix available (EOL). Transitive via pgconn v1 + pop/v6.",
}

type message struct {
Finding *struct {
OSV *struct {
ID string `json:"id"`
} `json:"osv"`
} `json:"finding"`
}

func main() {
dec := json.NewDecoder(os.Stdin)
if err := run(); err != nil {
fmt.Fprintf(os.Stderr, "vulncheck-filter: %v\n", err)
os.Exit(1)
}
}

var unignored []string
seen := make(map[string]bool)
for {
var m message
if err := dec.Decode(&m); err != nil {
if err == io.EOF {
break
}
// govulncheck JSON stream may contain objects we don't care about; skip decode errors
continue
}
if m.Finding == nil {
continue
}
if m.Finding.OSV == nil {
continue
}
id := m.Finding.OSV.ID
if seen[id] {
continue
}
seen[id] = true
func run() error {
res, err := Parse(os.Stdin)
if err != nil {
return err
}

if reason, ok := ignore[id]; ok {
fmt.Fprintf(os.Stderr, "ignoring %s: %s\n", id, reason)
} else {
fmt.Fprintf(os.Stderr, "ERROR: %s (not in ignore list)\n", id)
unignored = append(unignored, id)
vulns := res.Vulns
vulns = slices.DeleteFunc(vulns, func(v *Vulnerability) bool {
reason, ok := ignore[v.ID]
if ok {
fmt.Fprintf(os.Stderr, "ignoring %s: %s\n", v.ID, reason)
}
return ok
})
if len(vulns) == 0 {
return nil
}

if len(unignored) > 0 {
fmt.Fprintf(os.Stderr, "\n%d unignored vulnerability(ies) found\n", len(unignored))
os.Exit(1)
fmt.Fprintf(os.Stderr, "\n")
for idx, vuln := range vulns {
msg := "Vulnerability #%d: %v\n%v"
fmt.Fprintf(os.Stderr, msg, idx+1, vuln.ID, vuln.Text+"\n")
}
return fmt.Errorf("%d unignored vulnerability(ies) found", len(vulns))
}
154 changes: 154 additions & 0 deletions hack/vulncheck-filter/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package main

import (
"bufio"
"errors"
"fmt"
"io"
"strings"
)

type Result struct {
Msg string
Vulns []*Vulnerability
}

type Vulnerability struct {
ID string
Text string
}

var errParse = errors.New("parse error")

type parseState struct {
lines []string
pos int
res Result
}

func Parse(r io.Reader) (*Result, error) {
ps := &parseState{pos: -1}
sc := bufio.NewScanner(r)
for sc.Scan() {
ps.lines = append(ps.lines, sc.Text())
}
if err := sc.Err(); err != nil {
return nil, err
}
if err := ps.parse(); err != nil {
return nil, err
}
return &ps.res, nil
}

func (o *parseState) fail(format string, args ...any) error {
msg := fmt.Sprintf(format, args...)
return fmt.Errorf("%w; %v [line %v]", errParse, msg, o.pos+1)
}

func (o *parseState) scan() bool {
o.pos++
return o.pos < len(o.lines)
}

func (o *parseState) text() string {
if o.pos < 0 || o.pos >= len(o.lines) {
// panic("parse control flow error")
return ""
}
return o.lines[o.pos]
}

func (o *parseState) next() (string, bool) {
next := o.pos + 1
if next >= len(o.lines) {
return "", false
}
return o.lines[next], true
}

func (o *parseState) parse() error {
if !o.scan() {
return o.fail("empty output")
}
switch v := o.text(); v {
case "No vulnerabilities found.":
if o.scan() {
return o.fail(
"success followed by unexpected output: %q", o.text())
}
o.res.Msg = v + "\n"
return nil
case "=== Symbol Results ===":
return o.parseSection()
default:
return o.fail("unexpected line: %q", o.text())
}
}

func (o *parseState) parseSection() error {
if !o.scan() || o.text() != "" {
return o.fail("section was not followed by blank line")
}

var n int
for o.scan() {
if err := o.parseVuln(); err != nil {
return err
}
n++
}
if n == 0 || len(o.res.Vulns) == 0 {
return o.fail("section contains no vulns")
}
return nil
}

func (o *parseState) parseVuln() error {
if !startsVuln(o.text()) {
return o.parseSummary()
}

_, id, ok := strings.Cut(o.text(), ": ")
if !ok || id == "" {
return o.fail("vuln header invalid: %q", o.text())
}

cur := &Vulnerability{ID: id}
for o.scan() {
v := o.text()
switch {
case v == "" && strings.TrimSpace(cur.Text) == "":
return o.fail("vuln %q has empty details", cur.ID)
case v == "":
next, ok := o.next()
if !ok || startsVuln(next) || startsSummary(next) {
o.res.Vulns = append(o.res.Vulns, cur)
return nil
}
cur.Text += "\n"
case strings.HasPrefix(v, " "):
cur.Text += v + "\n"
default:
return o.fail("vuln %q has unexpected details: %q", cur.ID, v)
}
}
return o.fail("vuln %q is malformed", cur.ID)
}

func (o *parseState) parseSummary() error {
for {
o.res.Msg += o.text() + "\n"
if !o.scan() {
return nil
}
}
}

func startsVuln(s string) bool {
return strings.HasPrefix(s, "Vulnerability ")
}

func startsSummary(s string) bool {
return s != "" && !strings.HasPrefix(s, " ")
}
Loading
Loading