From 9d98538091bc4e9e9223ff3a24b7f0158046d4a4 Mon Sep 17 00:00:00 2001 From: Piyush Jena Date: Wed, 11 Mar 2026 21:15:50 +0000 Subject: [PATCH] skills: create skill to run govulncheck in source mode Signed-off-by: Piyush Jena --- skills/govulncheck-source/SKILL.md | 130 ++++++++++++++++++ .../scripts/extract-metadata.sh | 35 +++++ skills/govulncheck-source/scripts/pull-sdk.py | 51 +++++++ .../scripts/run-govulncheck.sh | 35 +++++ 4 files changed, 251 insertions(+) create mode 100644 skills/govulncheck-source/SKILL.md create mode 100755 skills/govulncheck-source/scripts/extract-metadata.sh create mode 100755 skills/govulncheck-source/scripts/pull-sdk.py create mode 100755 skills/govulncheck-source/scripts/run-govulncheck.sh diff --git a/skills/govulncheck-source/SKILL.md b/skills/govulncheck-source/SKILL.md new file mode 100644 index 00000000..61fd2c69 --- /dev/null +++ b/skills/govulncheck-source/SKILL.md @@ -0,0 +1,130 @@ +--- +name: govulncheck-source +description: Run govulncheck against Go packages in bottlerocket-core-kit using the bottlerocket-sdk container +--- + +# Skill: Govulncheck Source + +**Keywords:** govulncheck, go, vulnerability, security, scanning, core-kit, packages, sdk, docker + +## Purpose + +Scan Go packages in `bottlerocket-core-kit` for known vulnerabilities using `govulncheck` in source mode. +The scan runs inside the `bottlerocket-sdk` Docker container, using the correct Go version for each package. + +## When to Use + +- Auditing Go dependencies for known vulnerabilities before a release +- Checking if a package update introduces or resolves vulnerabilities +- Periodic security review of Go packages in core-kit + +## Prerequisites + +Before starting, verify: +- Docker is installed and running (`docker info`) +- Python 3.11+ is available (`python3 --version`) — needed for `tomllib` +- You are working from within a grove directory +- `kits/bottlerocket-core-kit` exists in the grove + +## Input + +The user provides: +- **Package name(s)** to scan (e.g., `runc`, `containerd-2.1`) +- **Kit name** — defaults to `bottlerocket-core-kit` + +## Procedure + +### 1. Pull the SDK image + +```bash +python3 skills/govulncheck-source/scripts/pull-sdk.py kits//Twoliter.toml +``` + +This outputs two lines to stdout: +1. The fully-qualified SDK image (e.g., `public.ecr.aws/bottlerocket/bottlerocket-sdk:v0.70.0`) +2. The default Go version in the SDK (e.g., `1.24`) + +Capture both values — they are needed by subsequent steps. + +### 2. Extract package metadata + +For each package, run: + +```bash +bash skills/govulncheck-source/scripts/extract-metadata.sh \ + kits//packages +``` + +This outputs a single tab-separated line: `version\turl\tgo_major\tgitrev` + +- `version` — upstream version (e.g., `1.2.8`) +- `url` — upstream repository URL (e.g., `https://github.com/opencontainers/runc`) +- `go_major` — Go toolchain version to use (e.g., `1.24`) +- `gitrev` — commit hash if the package is pinned to a specific commit (may be empty) + +### 3. Determine source type and obtain source + +Read `kits//packages//Cargo.toml` to determine the source type: + +**Upstream packages** (have `[[package.metadata.build-package.external-files]]`): +Clone the upstream repo at the correct ref. +Try tags in this order: +1. `v` (most common) +2. `` (bare) +3. For moby/docker-engine: `docker-v` +4. Fall back to `gitrev` commit hash if tags fail + +```bash +git clone --depth 1 --branch v /tmp/govulncheck- +``` + +**Internal packages** (have `source-groups = [""]`): +Source lives in `kits//sources//`. +No cloning needed — use the local path directly. + +### 4. Run govulncheck + +```bash +bash skills/govulncheck-source/scripts/run-govulncheck.sh \ + +``` + +Save the output to `govulncheck-results//govulncheck.txt`. + +Count vulnerabilities by looking for `Vulnerability #` lines in the output. + +### 5. Clean up and report + +Remove any cloned source directories. + +Present results as a summary table: + +| Package | Version | Go | Vulns | Status | +|---------|---------|-----|-------|--------| +| runc | 1.2.8 | 1.24 | 0 | clean | + +## Output Structure + +``` +govulncheck-results/ +├── / +│ └── govulncheck.txt +└── ... +``` + +## Common Issues + +**Docker not running:** +Start Docker with `sudo systemctl start docker` + +**SDK image pull fails (ECR auth):** +```bash +aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws +``` + +**govulncheck reports "no go.mod":** +Some upstream repos have `go.mod` in a subdirectory. +The `run-govulncheck.sh` script searches up to 3 levels deep automatically. + +**Tag not found during clone:** +Try the next tag variant, then fall back to full clone with `gitrev` checkout. diff --git a/skills/govulncheck-source/scripts/extract-metadata.sh b/skills/govulncheck-source/scripts/extract-metadata.sh new file mode 100755 index 00000000..5a056df8 --- /dev/null +++ b/skills/govulncheck-source/scripts/extract-metadata.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Extract package metadata (version, url, go_major, gitrev) via rpmspec in the SDK container. +# +# Usage: +# ./extract-metadata.sh +# +# Outputs a single line of tab-separated values: +# version\turl\tgo_major\tgitrev +set -euo pipefail + +SDK_IMAGE="$1" +DEFAULT_GO_MAJOR="$2" +PACKAGES_DIR="$3" +PKG="$4" + +docker run --rm \ + -v "$(cd "$PACKAGES_DIR" && pwd):/packages:ro" \ + "$SDK_IMAGE" bash -c " + cp /usr/lib/rpm/platform/x86_64-bottlerocket/macros ~/.rpmmacros + spec='/packages/${PKG}/${PKG}.spec' + + version=\$(rpmspec --query --queryformat='%{version}\n' \"\$spec\" 2>/dev/null | head -1) + url=\$(rpmspec --query --queryformat='%{url}\n' \"\$spec\" 2>/dev/null | head -1) + + expanded=\$(rpmspec -P \"\$spec\" 2>/dev/null) + go_major=\$(echo \"\$expanded\" | grep -oP 'GO_MAJOR=\"\K[^\"]+' | head -1) + go_major=\${go_major:-${DEFAULT_GO_MAJOR}} + + gitrev=\$(echo \"\$expanded\" | grep '^Source0:' | grep -oE '[0-9a-f]{40}' | head -1) + if [[ -z \"\$gitrev\" ]]; then + gitrev=\$(grep 'gitrev' \"\$spec\" | grep -oE '[0-9a-f]{40}' | head -1) + fi + + printf '%s\t%s\t%s\t%s\n' \"\$version\" \"\$url\" \"\$go_major\" \"\$gitrev\" + " diff --git a/skills/govulncheck-source/scripts/pull-sdk.py b/skills/govulncheck-source/scripts/pull-sdk.py new file mode 100755 index 00000000..a9596052 --- /dev/null +++ b/skills/govulncheck-source/scripts/pull-sdk.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +"""Parse Twoliter.toml for the SDK image and pull it via Docker. + +Usage: + python3 pull-sdk.py + +Outputs the fully-qualified SDK image reference on stdout, e.g.: + public.ecr.aws/bottlerocket/bottlerocket-sdk:v0.70.0 + +Also prints the lowest Go version available in the SDK on a second line, e.g.: + 1.24 +""" +import subprocess +import sys + +try: + import tomllib +except ModuleNotFoundError: + import tomli as tomllib # type: ignore[no-redef] + + +def main() -> None: + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} ", file=sys.stderr) + sys.exit(1) + + with open(sys.argv[1], "rb") as f: + data = tomllib.load(f) + + registry = data["vendor"]["bottlerocket"]["registry"] + name = data["sdk"]["name"] + version = data["sdk"]["version"] + image = f"{registry}/{name}:v{version}" + + subprocess.run(["docker", "pull", image], check=True, + stdout=sys.stderr, stderr=sys.stderr) + + result = subprocess.run( + ["docker", "run", "--rm", image, "bash", "-c", + r'ls -d /usr/libexec/go-* | sed "s|.*/go-||" | sort -V | head -1'], + capture_output=True, text=True, check=True, + ) + default_go = result.stdout.strip() + + # stdout: line 1 = image, line 2 = default go version + print(image) + print(default_go) + + +if __name__ == "__main__": + main() diff --git a/skills/govulncheck-source/scripts/run-govulncheck.sh b/skills/govulncheck-source/scripts/run-govulncheck.sh new file mode 100755 index 00000000..ec64b160 --- /dev/null +++ b/skills/govulncheck-source/scripts/run-govulncheck.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Run govulncheck inside the SDK container against a local source directory. +# +# Usage: +# ./run-govulncheck.sh +# +# Outputs govulncheck results to stdout. +# Exit code 3 = vulnerabilities found, 0 = clean, other = error. +set -euo pipefail + +SDK_IMAGE="$1" +GO_MAJOR="$2" +SRC_DIR="$3" + +docker run --rm \ + -v "$(cd "$SRC_DIR" && pwd):/src:ro" \ + "$SDK_IMAGE" bash -c " + export GOBIN=/tmp/bin + /usr/libexec/go-${GO_MAJOR}/bin/go install golang.org/x/vuln/cmd/govulncheck@latest 2>/dev/null + + export PATH=/usr/libexec/go-${GO_MAJOR}/bin:/tmp/bin:\$PATH + + gomod_dir=/src + if [[ ! -f /src/go.mod ]]; then + found=\$(find /src -maxdepth 3 -name go.mod -print -quit 2>/dev/null) + if [[ -n \"\$found\" ]]; then + gomod_dir=\$(dirname \"\$found\") + else + echo 'ERROR: no go.mod found' >&2 + exit 1 + fi + fi + + govulncheck -C \"\$gomod_dir\" -show verbose ./... 2>&1 + "