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
10 changes: 8 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ jobs:
timeout-minutes: 30
permissions:
contents: read
env:
GOVULNCHECK_VERSION: v1.6.0

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand All @@ -135,8 +137,10 @@ jobs:
with:
go-version-file: go.mod
cache: false
- name: Check reachable Go vulnerabilities
run: go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
- name: Check reachable Go vulnerabilities in the source
run: go run "golang.org/x/vuln/cmd/govulncheck@${GOVULNCHECK_VERSION}" ./...
- name: Test that the symbol-table guard rejects a stripped binary
run: scripts/assert-go-symbols-test.sh
- name: Build GoReleaser snapshot artifacts
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
with:
Expand All @@ -145,6 +149,8 @@ jobs:
args: release --snapshot --clean --skip=publish
- name: Verify and prepare all release artifacts
run: scripts/prepare-artifact-scan-rootfs.sh
- name: Check reachable Go vulnerabilities in each release binary
run: scripts/govulncheck-release-binaries.sh
- name: Import release artifacts for scanning
run: docker import artifact-scan/rootfs.tar stackstate-backup-cli:security-scan
- name: Scan release artifacts with Trivy, Grype, and VEX
Expand Down
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ builds:
- windows_amd64
main: .
ldflags:
- -s -w -X github.com/stackvista/stackstate-backup-cli/cmd/version.Version={{.Version}}
- -w -X github.com/stackvista/stackstate-backup-cli/cmd/version.Version={{.Version}}
-X github.com/stackvista/stackstate-backup-cli/cmd/version.Commit={{.Commit}}
-X github.com/stackvista/stackstate-backup-cli/cmd/version.Date={{.Date}}
binary: sts-backup
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ require (
go.opentelemetry.io/otel/trace v1.44.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.53.0 // indirect
golang.org/x/net v0.56.0 // indirect
golang.org/x/crypto v0.55.0 // indirect
golang.org/x/net v0.57.0 // indirect
golang.org/x/oauth2 v0.27.0 // indirect
golang.org/x/sys v0.46.0 // indirect
golang.org/x/term v0.44.0 // indirect
golang.org/x/text v0.39.0 // indirect
golang.org/x/sys v0.47.0 // indirect
golang.org/x/term v0.45.0 // indirect
golang.org/x/text v0.41.0 // indirect
golang.org/x/time v0.9.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
Expand Down
24 changes: 12 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -208,17 +208,17 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -231,25 +231,25 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus=
golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM=
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.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
52 changes: 52 additions & 0 deletions scripts/assert-go-symbols-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env bash

# Negative control for assert-go-symbols.sh: proves the guard rejects a stripped
# binary for the absence of symbols alone, on a fixture no advisory matches, so
# the result cannot come from the vulnerability database.
#
# Every target in .goreleaser.yml is covered because the two platform families
# fail differently: stripping leaves an ELF or PE file with no symbol section at
# all, while a stripped Mach-O still yields a readable table that `runtime.main`
# is missing from. A guard that only checked whether `go tool nm` succeeded would
# pass both darwin artifacts.

set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
guard="${script_dir}/assert-go-symbols.sh"
fixture_dir="${script_dir}/testdata/assessable-fixture"
targets=(darwin/amd64 darwin/arm64 linux/amd64 linux/arm64 windows/amd64)

work="$(mktemp -d)"
trap 'rm -rf "${work}"' EXIT

export CGO_ENABLED=0
failures=0

for target in "${targets[@]}"; do
goos="${target%/*}"
goarch="${target#*/}"
suffix=""
[[ "${goos}" == "windows" ]] && suffix=".exe"

kept="${work}/${goos}-${goarch}-kept${suffix}"
stripped="${work}/${goos}-${goarch}-stripped${suffix}"
(cd "${fixture_dir}" && GOOS="${goos}" GOARCH="${goarch}" go build -ldflags '-w' -o "${kept}" main.go)
(cd "${fixture_dir}" && GOOS="${goos}" GOARCH="${goarch}" go build -ldflags '-s -w' -o "${stripped}" main.go)

if "${guard}" "${kept}" >/dev/null; then
echo "PASS ${target}: built with -w only, accepted"
else
echo "FAIL ${target}: built with -w only, should have been accepted" >&2
failures=1
fi

if "${guard}" "${stripped}" >/dev/null 2>&1; then
echo "FAIL ${target}: built with -s -w, should have been rejected" >&2
failures=1
else
echo "PASS ${target}: built with -s -w, rejected"
fi
done

exit "${failures}"
38 changes: 38 additions & 0 deletions scripts/assert-go-symbols.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash

# Binary-mode govulncheck can only tell which packages a binary links while its
# Go symbol table is present; without one it conservatively assumes every package
# named in an advisory is linked. A stripped binary therefore still exits
# non-zero today only because an advisory happens to match one of its modules,
# which is a property of the current vulnerability database rather than of the
# artifact — so assessability is asserted here instead of inferred from
# govulncheck's exit status.

set -euo pipefail

# Linked into every Go binary regardless of platform or build tags, so its
# absence means the symbol table was stripped rather than that the program
# differs.
required_symbol='runtime.main'

if [[ "$#" -eq 0 ]]; then
echo "usage: $0 <binary>..." >&2
exit 2
fi

status=0
for binary in "$@"; do
if ! symbols="$(go tool nm "${binary}" 2>&1)"; then
echo "FAIL ${binary}: no readable Go symbol table -- ${symbols%%$'\n'*}" >&2
status=1
continue
fi
if ! grep -q "[[:space:]]${required_symbol}\$" <<<"${symbols}"; then
echo "FAIL ${binary}: symbol table has no ${required_symbol}" >&2
status=1
continue
fi
echo "OK ${binary}: Go symbol table is usable"
done

exit "${status}"
37 changes: 37 additions & 0 deletions scripts/govulncheck-release-binaries.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash

# Binary-mode govulncheck can only judge which packages are linked while the
# release binaries keep their symbol table, so stripping it again (`-s` in the
# GoReleaser ldflags) makes this fail instead of publishing artifacts whose
# reachability nobody can assess. The symbol table is asserted separately rather
# than inferred from govulncheck's exit status, which would only catch a stripped
# binary while some advisory still matched one of its modules.

set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
rootfs_dir="${1:-artifact-scan/rootfs}"
govulncheck_version="${GOVULNCHECK_VERSION:-v1.6.0}"
expected_binaries=5
binaries=()

while IFS= read -r binary; do
binaries+=("${binary}")
done < <(find "${rootfs_dir}" -type f \( -name sts-backup -o -name sts-backup.exe \) -print | sort)

if [[ "${#binaries[@]}" -ne "${expected_binaries}" ]]; then
echo "Expected ${expected_binaries} release binaries under '${rootfs_dir}', found ${#binaries[@]}" >&2
exit 1
fi

"${script_dir}/assert-go-symbols.sh" "${binaries[@]}"

status=0
for binary in "${binaries[@]}"; do
echo "== ${binary}"
if ! go run "golang.org/x/vuln/cmd/govulncheck@${govulncheck_version}" -mode=binary "${binary}"; then
Comment thread
ai-collaboration-app[bot] marked this conversation as resolved.
status=1
fi
done

exit "${status}"
5 changes: 5 additions & 0 deletions scripts/testdata/assessable-fixture/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Command assessable-fixture is the smallest Go binary the assessability guard
// can be tested against, so the test does not pay for a full CLI cross-build.
package main

func main() {}
Loading