Skip to content

Commit 7a70d7c

Browse files
committed
cmd/gorelease: report a diagnostic error for retracted dependencies
Fixes golang/go#37781 Change-Id: I109ce5da26c757e7e1bdd6bdcee0ff14be35230b Reviewed-on: https://go-review.googlesource.com/c/exp/+/310370 Trust: Jean de Klerk <[email protected]> Run-TryBot: Jean de Klerk <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Jay Conrod <[email protected]>
1 parent 725118b commit 7a70d7c

13 files changed

+223
-0
lines changed

cmd/gorelease/gorelease.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
package main
8181

8282
import (
83+
"bytes"
8384
"context"
8485
"encoding/json"
8586
"errors"
@@ -95,6 +96,7 @@ import (
9596
"path/filepath"
9697
"sort"
9798
"strings"
99+
"unicode"
98100

99101
"golang.org/x/exp/apidiff"
100102
"golang.org/x/mod/modfile"
@@ -426,6 +428,12 @@ func loadLocalModule(ctx context.Context, modRoot, repoRoot, version string) (m
426428
m.highestTransitiveVersion = highestVersion
427429
}
428430

431+
retracted, err := loadRetractions(ctx, tmpLoadDir)
432+
if err != nil {
433+
return moduleInfo{}, err
434+
}
435+
m.diagnostics = append(m.diagnostics, retracted...)
436+
429437
return m, nil
430438
}
431439

@@ -1375,3 +1383,76 @@ func copyEnv(ctx context.Context, current []string) []string {
13751383
copy(clone, env)
13761384
return clone
13771385
}
1386+
1387+
// loadRetractions lists all retracted deps found at the modRoot.
1388+
func loadRetractions(ctx context.Context, modRoot string) ([]string, error) {
1389+
cmd := exec.CommandContext(ctx, "go", "list", "-json", "-m", "-u", "all")
1390+
if env, ok := ctx.Value("env").([]string); ok {
1391+
cmd.Env = env
1392+
}
1393+
cmd.Dir = modRoot
1394+
out, err := cmd.Output()
1395+
if err != nil {
1396+
return nil, cleanCmdError(err)
1397+
}
1398+
1399+
var retracted []string
1400+
type message struct {
1401+
Path string
1402+
Version string
1403+
Retracted []string
1404+
}
1405+
1406+
dec := json.NewDecoder(bytes.NewBuffer(out))
1407+
for {
1408+
var m message
1409+
if err := dec.Decode(&m); err == io.EOF {
1410+
break
1411+
} else if err != nil {
1412+
return nil, err
1413+
}
1414+
if len(m.Retracted) == 0 {
1415+
continue
1416+
}
1417+
rationale, ok := shortRetractionRationale(m.Retracted)
1418+
if ok {
1419+
retracted = append(retracted, fmt.Sprintf("required module %s@%s retracted by module author: %s", m.Path, m.Version, rationale))
1420+
} else {
1421+
retracted = append(retracted, fmt.Sprintf("required module %s@%s retracted by module author", m.Path, m.Version))
1422+
}
1423+
}
1424+
1425+
return retracted, nil
1426+
}
1427+
1428+
// ShortRetractionRationale returns a retraction rationale string that is safe
1429+
// to print in a terminal. It returns hard-coded strings if the rationale
1430+
// is empty, too long, or contains non-printable characters.
1431+
//
1432+
// It returns true if the rationale was printable, and false if it was not (too
1433+
// long, contains graphics, etc).
1434+
func shortRetractionRationale(rationales []string) (string, bool) {
1435+
if len(rationales) == 0 {
1436+
return "", false
1437+
}
1438+
rationale := rationales[0]
1439+
1440+
const maxRationaleBytes = 500
1441+
if i := strings.Index(rationale, "\n"); i >= 0 {
1442+
rationale = rationale[:i]
1443+
}
1444+
rationale = strings.TrimSpace(rationale)
1445+
if rationale == "" || rationale == "retracted by module author" {
1446+
return "", false
1447+
}
1448+
if len(rationale) > maxRationaleBytes {
1449+
return "", false
1450+
}
1451+
for _, r := range rationale {
1452+
if !unicode.IsGraphic(r) && !unicode.IsSpace(r) {
1453+
return "", false
1454+
}
1455+
}
1456+
// NOTE: the go.mod parser rejects invalid UTF-8, so we don't check that here.
1457+
return rationale, true
1458+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- go.mod --
2+
module example.com/retract
3+
4+
go 1.12
5+
6+
require example.com/retractdep v1.0.0
7+
-- go.sum --
8+
example.com/retractdep v1.0.0 h1:SOVn6jA2ygQY+v8/5aAwxVUJ9teuLrdH/UmbUtp2C44=
9+
example.com/retractdep v1.0.0/go.mod h1:UjjWSH/ulfbAGgQQwm7pAZ988MFRngUSkJnzcuPsYDI=
10+
-- a.go --
11+
package a
12+
13+
import _ "example.com/retractdep"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- go.mod --
2+
module example.com/retractdep
3+
4+
go 1.12
5+
-- a.go --
6+
package a
7+
8+
const A = "a"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- go.mod --
2+
module example.com/retractdep
3+
4+
go 1.12
5+
6+
// Remote-triggered crash in package foo. See CVE-2021-01234.
7+
retract v1.0.0
8+
-- a.go --
9+
package a
10+
11+
const A = "a"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Identical to v1.0.0: just need a new version so that we can test different
2+
# error messages based on the vX.0.1 retraction comments. We can't test them in
3+
# the same major version because go mod will always use the latest version's
4+
# error message.
5+
-- go.mod --
6+
module example.com/retractdep/v2
7+
8+
go 1.12
9+
-- a.go --
10+
package a
11+
12+
const A = "a"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-- go.mod --
2+
module example.com/retractdep/v2
3+
4+
go 1.12
5+
6+
retract v2.0.0
7+
-- a.go --
8+
package a
9+
10+
const A = "a"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Identical to v1.0.0: just need a new version so that we can test different
2+
# error messages based on the vX.0.1 retraction comments. We can't test them in
3+
# the same major version because go mod will always use the latest version's
4+
# error message.
5+
-- go.mod --
6+
module example.com/retractdep/v3
7+
8+
go 1.12
9+
-- a.go --
10+
package a
11+
12+
const A = "a"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- go.mod --
2+
module example.com/retractdep/v3
3+
4+
go 1.12
5+
6+
// This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message. This is a very long message.
7+
retract v3.0.0
8+
-- a.go --
9+
package a
10+
11+
const A = "a"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- go.mod --
2+
module example.com/retracttransitive
3+
4+
go 1.12
5+
6+
require example.com/retract v0.0.1
7+
-- go.sum --
8+
example.com/retract v0.0.1 h1:Afj8efoHilltHZNLlEARzpc1Vkc5d6ugWKIE/YDmXuQ=
9+
example.com/retract v0.0.1/go.mod h1:DUqXjcGF3aJhkjxsUjQ0DG65b51DDBvFrEbcr9kkyto=
10+
example.com/retractdep v1.0.0 h1:SOVn6jA2ygQY+v8/5aAwxVUJ9teuLrdH/UmbUtp2C44=
11+
example.com/retractdep v1.0.0/go.mod h1:UjjWSH/ulfbAGgQQwm7pAZ988MFRngUSkJnzcuPsYDI=
12+
-- a.go --
13+
package a
14+
15+
import _ "example.com/retract"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
mod=example.com/retract
2+
version=v0.0.1
3+
success=false
4+
-- want --
5+
Inferred base version: v0.0.1
6+
required module example.com/[email protected] retracted by module author: Remote-triggered crash in package foo. See CVE-2021-01234.

0 commit comments

Comments
 (0)