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
22 changes: 14 additions & 8 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,25 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
# codeql-action/init and /analyze are separate dependencies but must run the same version,
# so bump them in one PR - separate PRs each fail with a version mismatch
codeql-action:
patterns:
- "github/codeql-action*"
interval: "monthly"
cooldown:
default-days: 7
groups:
github-actions:
patterns:
- "*"

# dependabot auto-detects the vendor/ directory and runs `go mod tidy` + `go mod vendor` on updates
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
interval: "monthly"
cooldown:
default-days: 7
groups:
go-modules:
patterns:
- "*"

# dev tools (actionlint, golangci-lint, gofumpt) pinned in .tools/go.mod; tools move slowly,
# so only check quarterly
Expand All @@ -30,3 +32,7 @@ updates:
interval: "quarterly"
cooldown:
default-days: 7
groups:
go-tools:
patterns:
- "*"
3 changes: 3 additions & 0 deletions .github/trivyignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Advisories triaged out of main-binary-scan.yaml, one ID per line with the reason above it. Findings with
# no fixed version are already skipped by the workflow, so this is only for fixable findings in code the
# binary never calls. Remove an entry once the dependency moves past it.
85 changes: 85 additions & 0 deletions .github/workflows/main-binary-scan.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
# Scans the binaries for known vulnerabilities via the Go module and stdlib versions they embed. Three jobs so
# the red X on main says what to do: `release` scans the last published release (what users are running, so
# red means cut a release), `image` scans the published docker image (the go binary plus the alpine packages
# around it, so red means cut a release to rebuild on current alpine) and `main` scans a fresh build of this
# commit (what the next release would ship, so red means bump the dependency). govulncheck (pr-govulncheck.yaml) is the reachability check on PRs;
# this is the version-based artifact check, the same shape as hashicorp's release security scan.
name: binary vulnerability scan
on:
push:
branches: [ 'main' ]
schedule:
- cron: '23 5 * * 1' # weekly, so new advisories against unchanged binaries still turn main red
workflow_dispatch: # release.yaml reruns the failed jobs of the latest run on main once a release publishes

permissions:
contents: read

jobs:
release:
name: release binary
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Download the latest release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
gh release download --pattern '*linux_amd64.tar.gz' --dir release
tar -xzf release/*.tar.gz -C release
rm release/*.tar.gz
# rootfs, not fs: fs mode does not read go binaries. unfixed findings are skipped because nothing can
# clear them; anything else triaged out goes in .github/trivyignore with a reason
- uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: rootfs
scan-ref: release
scanners: vuln
severity: HIGH,CRITICAL
ignore-unfixed: true
trivyignores: .github/trivyignore
exit-code: 1

image:
name: release image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# :latest is the last release; the image is public so no registry login is needed. this also scans
# the alpine packages and the gh binary the image ships with, not just ghp-sync
- uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: image
image-ref: ghcr.io/${{ github.repository }}:latest
scanners: vuln
severity: HIGH,CRITICAL
ignore-unfixed: true
trivyignores: .github/trivyignore
exit-code: 1

main:
name: build of main
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: ./.go-version
- run: go build -o out/ghp-sync .
- uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: rootfs
scan-ref: out
scanners: vuln
severity: HIGH,CRITICAL
ignore-unfixed: true
trivyignores: .github/trivyignore
exit-code: 1
21 changes: 21 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,24 @@ jobs:
TAG: ${{ github.ref_name }}
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
run: ./scripts/update-homebrew-formula.sh

# the binary scan (main-binary-scan.yaml) goes red on main when the published release has a known
# vulnerability, and only a release can clear it. rerun the failed jobs of the scan runs on main's head so
# the red check runs are replaced in place; a fresh run from a new event would sit beside them and the
# commit would stay red
rescan:
needs: [goreleaser, docker] # the rerun scans both the release tarball and the :latest image
runs-on: ubuntu-latest
permissions:
actions: write # rerun workflow jobs
steps:
- name: rerun the failed binary scan jobs on main
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
head=$(gh api "repos/$GH_REPO/commits/main" --jq .sha)
runs=$(gh run list -w main-binary-scan.yaml -c "$head" --json databaseId,conclusion \
--jq '.[] | select(.conclusion == "failure") | .databaseId')
if [ -z "$runs" ]; then echo "no failed binary scan on main ($head), nothing to rerun"; exit 0; fi
for run in $runs; do echo "rerunning failed jobs of $run"; gh run rerun "$run" --failed; done
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## Unreleased

- ci: scan the release binary, the published docker image and a build of main with trivy for known vulnerabilities; a release reruns the failed scan in place
- docker: upgrade alpine packages when building the image, so a release picks up base image security fixes
- ci: dependabot runs monthly and groups updates into one PR per ecosystem
- bump golang.org/x/text to v0.42.0 for CVE-2026-56852, a hang on invalid UTF-8 input; ghp-sync never calls the affected code, but the binary now scans clean

## v0.3.2 (2026-09-15)

- publish the `v`-prefixed image tag too, so `:v0.3.2` works alongside `:0.3.2`, `:0.3` and `:latest`
Expand Down
5 changes: 3 additions & 2 deletions dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -mod=
-ldflags "-s -w -X github.com/katbyte/go-kt/version.Version=${VERSION} -X github.com/katbyte/go-kt/version.GitCommit=${GIT_COMMIT}" \
-o /out/ghp-sync .

# dcron runs the sync on a schedule, gh backs the graphql queries, tzdata makes TZ work
# dcron runs the sync on a schedule, gh backs the graphql queries, tzdata makes TZ work. upgrade first so a
# release rebuild picks up alpine security fixes the base image tag has not been rebuilt with yet
FROM alpine:3.24
RUN apk add --no-cache bash ca-certificates dcron github-cli tzdata
RUN apk upgrade --no-cache && apk add --no-cache bash ca-certificates dcron github-cli tzdata

WORKDIR /app
COPY --from=build /out/ghp-sync /usr/bin/ghp-sync
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ require (
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.28.0 // indirect
golang.org/x/text v0.42.0 // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,6 @@ golang.org/x/oauth2 v0.37.0 h1:JUlcxA8oAtauLfiH8FX2/FkAWHAdi0QtGCGc+hofE98=
golang.org/x/oauth2 v0.37.0/go.mod h1:IxwZNxUULJmpBFf9K/9NTMSIfZZuvuTy1gGxhigP/58=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
6 changes: 3 additions & 3 deletions vendor/golang.org/x/text/encoding/unicode/unicode.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 27 additions & 15 deletions vendor/golang.org/x/text/unicode/norm/composition.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading