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
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ COPY internal/ internal/
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /github-scout .
COPY LICENSE NOTICE THIRD_PARTY_NOTICES.md ./
COPY scripts/collect-licenses.sh scripts/
RUN sh scripts/collect-licenses.sh --name github-scout .

FROM gcr.io/distroless/static-debian13:nonroot@sha256:e2e927ec666bae08560abb3c55d0659eceabb657f56b6782ab500a9fc7f555e3

COPY --chmod=755 --from=builder /github-scout /github-scout
COPY --from=builder /out/usr/share/licenses /usr/share/licenses
USER nonroot:nonroot
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=15s \
CMD ["/github-scout", "health"]
Expand Down
50 changes: 2 additions & 48 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -1,49 +1,3 @@
github-scout
Copyright (c) 2026 cplieger

This product is licensed under the GNU General Public License v3.0 or
later (see LICENSE).

------------------------------------------------------------------------
Third-party acknowledgements
------------------------------------------------------------------------

The GitHub REST API client design in internal/github (Bearer-token auth
header set, the X-GitHub-Api-Version pin, and page-count pagination)
follows patterns common to the following MIT-licensed projects. No source
code was copied verbatim; the approach was studied and reimplemented.

githubexporter/github-exporter
https://github.com/githubexporter/github-exporter
Copyright (c) 2016 Infinity Works Ltd
Licensed under the MIT License.

xrstf/github_exporter
https://github.com/xrstf/github_exporter
Copyright (c) 2020 Christoph Mewes
Licensed under the MIT License.

The MIT License permits this use. Their full license text is reproduced
below for attribution.

------------------------------------------------------------------------
MIT License

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
Copyright 2026 cplieger
https://github.com/cplieger/github-scout
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -490,4 +490,6 @@ This project was built with AI-assisted tooling using [Claude](https://claude.co

## License

GPL-3.0-or-later. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
GPL-3.0-or-later. See [LICENSE](LICENSE). The image carries the license text of every bundled component under `/usr/share/licenses/`.

Third-party attributions are in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
38 changes: 38 additions & 0 deletions THIRD_PARTY_NOTICES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Third-party notices

## Design followed, no code included

The GitHub REST API client in `internal/github` follows patterns common to two MIT-licensed community exporters. No source code was copied; the approach was studied and reimplemented. Each pattern is named at the line of ours that follows it:

- The request headers in `internal/github/client.go` (`setHeaders`: the `Authorization: Bearer` set and the `X-GitHub-Api-Version` pin) follow both exporters.
- The page-count pagination in `internal/github/client.go` (`ListRepos`, `ListRuns`, the `/search/issues` paths and `ListCodeScanningAlerts` each request `page` with `per_page` and stop on a short page) follows both exporters.

The upstreams:

- [githubexporter/github-exporter](https://github.com/githubexporter/github-exporter), copyright (c) 2016 Infinity Works Ltd, MIT.
- [xrstf/github_exporter](https://github.com/xrstf/github_exporter), copyright (c) 2020 Christoph Mewes, MIT.

The MIT License permits this use. Their full license text is reproduced below for attribution.

```text
MIT License

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
```
118 changes: 118 additions & 0 deletions scripts/collect-licenses.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/bin/sh
# Copy every linked Go module's license files into the /usr/share/licenses tree of
# attribution.md section 4. usage: collect-licenses.sh --name IMAGE [--out DIR] [PACKAGE ...]
# CANONICAL COPY in cplieger/ci (configs/collect-licenses.sh), synced to each
# root-Dockerfile repo's scripts/collect-licenses.sh: edit it there, never here.
# A module with no license file fails the build rather than being skipped, because a
# missing text is a section 4(a) breach and the fix is a human decision.
set -eu

OUT=/out/usr/share/licenses
NAME=""
while [ $# -gt 0 ]; do
case "$1" in
--out)
OUT="${2:?--out needs a directory}"
shift 2
;;
--name)
NAME="${2:?--name needs an image name}"
shift 2
;;
--)
shift
break
;;
-*)
printf 'collect-licenses: unknown option %s\n' "$1" >&2
exit 2
;;
*) break ;;
esac
done
case "$NAME" in
'')
printf 'collect-licenses: --name IMAGE is required\n' >&2
exit 2
;;
*[!A-Za-z0-9._-]*)
printf 'collect-licenses: --name must be a single path component, got "%s"\n' "$NAME" >&2
exit 2
;;
esac
[ $# -gt 0 ] || set -- ./...
export GOWORK=off

modules=0
files=0
missing=""

# copy_files SRC_DIR DEST_DIR all|licenses: copy the regular files at SRC_DIR's root
# (all of them, or the license-family names only) into DEST_DIR; sets $copied.
copy_files() {
copied=0
for f in "$1"/*; do
[ -f "$f" ] || continue
if [ "$3" = licenses ]; then
case "${f##*/}" in
LICENSE* | LICENCE* | COPYING* | NOTICE*) ;;
*) continue ;;
esac
fi
mkdir -p "$2"
cp -f "$f" "$2/"
copied=$((copied + 1))
done
}

main_path=$(go list -m -f '{{.Path}}')
main_dir=$(go list -m -f '{{.Dir}}')

roots=$(go list -f '{{if eq .Name "main"}}{{.ImportPath}}{{end}}' "$@" | sed '/^$/d')
if [ -z "$roots" ]; then
printf 'collect-licenses: no main package matches: %s\n' "$*" >&2
exit 1
fi
# shellcheck disable=SC2086 # import paths carry no whitespace
deps=$(go list -deps -f '{{if not .Standard}}{{with .Module}}{{.Path}}|{{.Dir}}{{end}}{{end}}' $roots \
| sed '/^$/d' | sort -u)

if [ ! -f "$main_dir/LICENSE" ]; then
printf 'collect-licenses: %s has no LICENSE (the main module, at %s)\n' "$main_path" "$main_dir" >&2
exit 1
fi
copy_files "$main_dir" "$OUT/$NAME" licenses
if [ -f "$main_dir/THIRD_PARTY_NOTICES.md" ]; then
cp -f "$main_dir/THIRD_PARTY_NOTICES.md" "$OUT/$NAME/"
copied=$((copied + 1))
fi
modules=$((modules + 1))
files=$((files + copied))

while IFS='|' read -r path dir; do
[ "$path" = "$main_path" ] && continue
if [ -z "$dir" ]; then
printf 'collect-licenses: %s has no source directory (vendor mode is not supported)\n' "$path" >&2
exit 1
fi
copy_files "$dir" "$OUT/$path" licenses
if [ "$copied" -eq 0 ]; then
copy_files "$main_dir/licenses/$path" "$OUT/$path" all
fi
if [ "$copied" -eq 0 ]; then
missing="$missing
$path (at $dir; add licenses/$path/ to the repo or drop the module)"
continue
fi
modules=$((modules + 1))
files=$((files + copied))
done <<EOF
$deps
EOF

if [ -n "$missing" ]; then
printf 'collect-licenses: no LICENSE*, LICENCE*, COPYING* or NOTICE* file at the module root of:\n' >&2
printf '%s\n' "$missing" | sed '/^$/d; s/^/ /' >&2
exit 1
fi
printf 'collect-licenses: %s modules, %s files under %s\n' "$modules" "$files" "$OUT"
2 changes: 2 additions & 0 deletions tests/image-smoke.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@
SMOKE_APP_NAME=github-scout
SMOKE_TIMEOUT=60
SMOKE_RUN_ARGS="-e GITHUB_OWNER=smoke-test -e GITHUB_TOKEN=smoke-dummy-token"

SMOKE_LICENSE_TREE=1
Loading