Skip to content
Merged
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
23 changes: 19 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,12 @@ jobs:
run: |
set -euo pipefail
bash scripts/release/check-image.sh "$LOCAL_IMAGE@$DIGEST" "$TAG"
docker buildx imagetools inspect "$LOCAL_IMAGE@$DIGEST" --format '{{ json .SBOM }}' | grep -q '"SPDX"'
docker buildx imagetools inspect "$LOCAL_IMAGE@$DIGEST" --format '{{ json .Provenance }}' | grep -q '"SLSA"'
# Captured first: grep -q stops reading at the first match, and
# under pipefail docker's broken pipe would fail the step.
sbom="$(docker buildx imagetools inspect "$LOCAL_IMAGE@$DIGEST" --format '{{ json .SBOM }}')"
grep -q '"SPDX"' <<<"$sbom"
provenance="$(docker buildx imagetools inspect "$LOCAL_IMAGE@$DIGEST" --format '{{ json .Provenance }}')"
grep -q '"SLSA"' <<<"$provenance"
# The Dockerfile's own build from source, which docs and
# contributors use, passes the same checks.
docker buildx build --load -t touchmark:source --build-arg VERSION="$TAG" .
Expand Down Expand Up @@ -465,15 +469,26 @@ jobs:
go-version: '1.26.x'
cache: true

# Every Fuzz* target in every package runs for 30 seconds.
# Every Fuzz* target in every package runs for 30 seconds. Go's fuzzer
# sometimes ends a timed run with "context deadline exceeded" although
# no input failed: that is a warning; a failing input is an error.
- name: go test -fuzz
run: |
set -euo pipefail
for pkg in $(go list ./...); do
listed="$(go test -list '^Fuzz' "$pkg")"
for target in $(printf '%s\n' "$listed" | grep '^Fuzz' || true); do
echo "::group::$pkg $target"
go test -run '^$' -fuzz "^${target}\$" -fuzztime 30s "$pkg"
if ! go test -run '^$' -fuzz "^${target}\$" -fuzztime 30s "$pkg" > fuzz.log 2>&1; then
cat fuzz.log
if grep -q 'context deadline exceeded' fuzz.log && ! grep -q 'Failing input written to' fuzz.log; then
echo "::warning::$pkg $target: the fuzzer stopped at its deadline with no failing input"
else
exit 1
fi
else
cat fuzz.log
fi
echo "::endgroup::"
done
done
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,12 @@ jobs:
test "$got" = "$DIGEST" || { echo "::error::$IMAGE:$t names $got, not $DIGEST"; exit 1; }
done
bash scripts/release/check-image.sh "$IMAGE:$VERSION" "$TAG"
docker buildx imagetools inspect "$IMAGE@$DIGEST" --format '{{ json .SBOM }}' | grep -q '"SPDX"'
docker buildx imagetools inspect "$IMAGE@$DIGEST" --format '{{ json .Provenance }}' | grep -q '"SLSA"'
# Captured first: grep -q stops reading at the first match, and
# under pipefail docker's broken pipe would fail the step.
sbom="$(docker buildx imagetools inspect "$IMAGE@$DIGEST" --format '{{ json .SBOM }}')"
grep -q '"SPDX"' <<<"$sbom"
provenance="$(docker buildx imagetools inspect "$IMAGE@$DIGEST" --format '{{ json .Provenance }}')"
grep -q '"SLSA"' <<<"$provenance"

- name: The release's files against the signed checksums.txt
if: runner.arch == 'X64'
Expand Down
9 changes: 6 additions & 3 deletions internal/gitx/target_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,14 @@ func newServed(t *testing.T, root, name string) *served {
if _, err := g.Run(t.Context(), nil, "init", "-q", "--bare", "-b", "main", dir); err != nil {
t.Fatal(err)
}
// Appended rather than set with git config: three git runs fewer per
// repository, which counts on Windows.
// Appended rather than set with git config: fewer git runs per
// repository, which counts on Windows. No garbage collection runs behind
// a test's back (receive-pack starts one after a push, and on macOS it
// was still writing when the test removed its directory), and Git for
// Windows takes paths NTFS cannot hold, since nothing is checked out.
f, err := os.OpenFile(filepath.Join(dir, "config"), os.O_APPEND|os.O_WRONLY, 0)
if err == nil {
_, err = f.WriteString("[uploadpack]\n\tallowFilter = true\n\tallowAnySHA1InWant = true\n[http]\n\treceivepack = true\n")
_, err = f.WriteString("[core]\n\tprotectNTFS = false\n[uploadpack]\n\tallowFilter = true\n\tallowAnySHA1InWant = true\n[http]\n\treceivepack = true\n[receive]\n\tautogc = false\n[gc]\n\tauto = 0\n")
err = errors.Join(err, f.Close())
}
if err != nil {
Expand Down
9 changes: 6 additions & 3 deletions internal/platform/fake/gitrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,12 @@ var (
const gitTimeout = 2 * time.Minute

// repoConfig is appended to the config of every bare repository: partial
// clones and fetches by id are served, pushes are accepted over HTTP, and
// no garbage collection runs behind a test's back.
const repoConfig = `[uploadpack]
// clones and fetches by id are served, pushes are accepted over HTTP, no
// garbage collection runs behind a test's back, and Git for Windows takes
// paths NTFS cannot hold (a tab, a quote), since nothing is checked out.
const repoConfig = `[core]
protectNTFS = false
[uploadpack]
allowFilter = true
allowAnySHA1InWant = true
[http]
Expand Down
7 changes: 5 additions & 2 deletions internal/platform/github/ghfake/gitrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ const (
// repoConfig is appended to the config of every bare repository: partial
// clones and fetches by id are served, pushes are accepted over HTTP,
// refs/pull/* are hidden from pushes as on GitHub ("deny updating a hidden
// ref"), and no garbage collection runs behind a test's back.
const repoConfig = `[uploadpack]
// ref"), no garbage collection runs behind a test's back, and Git for
// Windows takes paths NTFS cannot hold, since nothing is checked out.
const repoConfig = `[core]
protectNTFS = false
[uploadpack]
allowFilter = true
allowAnySHA1InWant = true
[http]
Expand Down
14 changes: 10 additions & 4 deletions internal/prbody/comments.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,20 +175,26 @@ func DeclinedComment(pr int64, paths []string, optInFile string) string {
if len(ps) == 0 {
return b.String()
}
b.WriteString("\n\nTo keep your own versions of these files for good, add them to `ignore` in " + optIn + ":\n\n```yaml\nignore:\n")
var y strings.Builder
y.WriteString("ignore:\n")
listed, size := 0, 0
for _, p := range ps {
entry := " - " + yamlQuote(ignorePattern(p)) + "\n"
if listed == maxRows || (listed > 0 && size+len(entry) > maxYAML) {
break
}
b.WriteString(entry)
y.WriteString(entry)
listed, size = listed+1, size+len(entry)
}
if more := len(ps) - listed; more > 0 {
b.WriteString(" # …and " + strconv.Itoa(more) + " more\n")
y.WriteString(" # …and " + strconv.Itoa(more) + " more\n")
}
b.WriteString("```")
// A path may hold backticks: the fence is longer than any run of them
// inside, so a path can never close the block early.
fence := strings.Repeat("`", max(3, longestRun(y.String(), '`')+1))
b.WriteString("\n\nTo keep your own versions of these files for good, add them to `ignore` in " + optIn + ":\n\n" + fence + "yaml\n")
b.WriteString(y.String())
b.WriteString(fence)
return b.String()
}

Expand Down
24 changes: 17 additions & 7 deletions internal/prbody/comments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,15 +317,25 @@ func checkComment(t *testing.T, s string) {
// yamlBlock returns the YAML inside the fenced block of a comment.
func yamlBlock(t *testing.T, s string) string {
t.Helper()
_, rest, ok := strings.Cut(s, "```yaml\n")
if !ok {
t.Fatalf("no YAML block in\n%s", s)
}
block, _, ok := strings.Cut(rest, "```")
if !ok {
// The opening line is a fence of three or more backticks and "yaml";
// the block ends at a line holding that fence alone.
lines := strings.SplitAfter(s, "\n")
for i, line := range lines {
fence, ok := strings.CutSuffix(strings.TrimSuffix(line, "\n"), "yaml")
if !ok || len(fence) < 3 || strings.Trim(fence, "`") != "" {
continue
}
var b strings.Builder
for _, line := range lines[i+1:] {
if strings.TrimSuffix(line, "\n") == fence {
return b.String()
}
b.WriteString(line)
}
t.Fatalf("an open YAML block in\n%s", s)
}
return block
t.Fatalf("no YAML block in\n%s", s)
return ""
}

// yamlIgnore parses the YAML block of a comment.
Expand Down
1 change: 1 addition & 0 deletions internal/prbody/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ func FuzzDeclinedComment(f *testing.F) {
f.Add(int64(12), "AGENTS.md\x00docs/[draft].md\x00@x/y.md", optInName)
f.Add(int64(0), hostileSeed, "@opt`in")
f.Add(int64(-3), " \x00/\x00./a\x00a*b?c\x00\t tab", "")
f.Add(int64(12), "```\x00a````b.md", "0") // backticks in a path once closed the YAML block early
f.Fuzz(func(t *testing.T, pr int64, paths, optIn string) {
ps := splitN(paths, 300)
got := DeclinedComment(pr, ps, optIn)
Expand Down
4 changes: 3 additions & 1 deletion scripts/e2e/template-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ tpl_source=${tpl_source:-}
# TEXT; it fails when the container stops or the time is up.
tpl_wait_log() {
local c=$1 text=$2 deadline=$((SECONDS + $3)) state
until docker logs "$c" 2>&1 | grep -qF -- "$text"; do
# The log is captured first: with pipefail, grep -q's early exit would
# fail docker logs on a broken pipe, and the wait would never end.
until grep -qF -- "$text" <<<"$(docker logs "$c" 2>&1)"; do
if state=$(docker inspect -f '{{.State.Running}}' "$c" 2>/dev/null) && [ "$state" != true ]; then
docker logs --tail 50 "$c" >&2 || true
die "$c stopped before it printed \"$text\""
Expand Down
Loading