Scaffold build repo for pinned tailscale/go-cache-plugin
Upstream publishes no releases, so CI has nothing to curl. - pin cmd/go-cache-plugin at 3031b5d via the go.mod tool directive - build a static stripped binary with make build - test the built binary: static ELF, pinned provenance, and a real go build driven through it as a GOCACHEPROG against a stub S3 - add PR build/test/pre-commit workflows and a tag release workflow attaching linux/amd64 and linux/arm64 to a Gitea release
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
/go-cache-plugin
|
||||
/go-cache-plugin-*
|
||||
@@ -0,0 +1,15 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.6.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-merge-conflict
|
||||
- id: mixed-line-ending
|
||||
args: [--fix=lf]
|
||||
|
||||
- repo: https://github.com/dnephin/pre-commit-golang
|
||||
rev: v0.5.1
|
||||
hooks:
|
||||
- id: go-fmt
|
||||
@@ -0,0 +1,18 @@
|
||||
when:
|
||||
- event: pull_request
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: docker.io/golang:1.26
|
||||
commands:
|
||||
- make build
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 2Gi
|
||||
cpu: 2
|
||||
limits:
|
||||
memory: 6Gi
|
||||
cpu: 4
|
||||
@@ -0,0 +1,18 @@
|
||||
when:
|
||||
- event: pull_request
|
||||
|
||||
steps:
|
||||
- name: pre-commit
|
||||
image: git.unkin.net/unkin/almalinux9-gobuilder:20260606
|
||||
commands:
|
||||
- uvx pre-commit run --all-files
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 512Mi
|
||||
cpu: 1
|
||||
limits:
|
||||
memory: 2Gi
|
||||
cpu: 2
|
||||
@@ -0,0 +1,69 @@
|
||||
when:
|
||||
- event: tag
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: docker.io/golang:1.26
|
||||
commands:
|
||||
- make test
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 2Gi
|
||||
cpu: 2
|
||||
limits:
|
||||
memory: 6Gi
|
||||
cpu: 4
|
||||
|
||||
# Static binaries so CI images can curl one and run it regardless of libc.
|
||||
- name: build
|
||||
image: docker.io/golang:1.26
|
||||
commands:
|
||||
- |
|
||||
for arch in amd64 arm64; do
|
||||
make build OS=linux ARCH="$$arch"
|
||||
mv dist/go-cache-plugin "go-cache-plugin-linux-$$arch"
|
||||
done
|
||||
- make upstream > upstream-version.txt
|
||||
depends_on: [test]
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 2Gi
|
||||
cpu: 2
|
||||
limits:
|
||||
memory: 6Gi
|
||||
cpu: 4
|
||||
|
||||
- name: release
|
||||
image: git.unkin.net/unkin/almalinux9-base:20260606
|
||||
environment:
|
||||
RELEASER_TOKEN:
|
||||
from_secret: RELEASER_TOKEN
|
||||
commands:
|
||||
# $$ escapes shell vars so Woodpecker leaves them for the shell;
|
||||
# ${CI_COMMIT_TAG}/${CI_REPO} are real Woodpecker vars.
|
||||
- |
|
||||
curl -f -o /usr/local/bin/tea https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/gitea-dl/tea/0.12.0/tea-0.12.0-linux-amd64
|
||||
chmod +x /usr/local/bin/tea
|
||||
tea logins add --name gitea --url https://git.unkin.net --token "$${RELEASER_TOKEN}" --no-version-check
|
||||
ASSETS="go-cache-plugin-linux-amd64 go-cache-plugin-linux-arm64"
|
||||
sha256sum $$ASSETS > sha256sums.txt
|
||||
NOTES="Built from github.com/tailscale/go-cache-plugin $$(cat upstream-version.txt)"
|
||||
tea releases create --tag "${CI_COMMIT_TAG}" --title "${CI_COMMIT_TAG}" --note "$$NOTES" --login gitea --repo "${CI_REPO}"
|
||||
tea releases assets create "${CI_COMMIT_TAG}" $$ASSETS sha256sums.txt --login gitea --repo "${CI_REPO}"
|
||||
depends_on: [build]
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 128Mi
|
||||
cpu: 100m
|
||||
limits:
|
||||
memory: 512Mi
|
||||
cpu: 500m
|
||||
@@ -0,0 +1,37 @@
|
||||
when:
|
||||
- event: pull_request
|
||||
|
||||
steps:
|
||||
# go vet rather than golangci-lint: the repo has no source of its own beyond
|
||||
# the build test, and the lint image lags the Go version upstream requires.
|
||||
- name: vet
|
||||
image: docker.io/golang:1.26
|
||||
commands:
|
||||
- go vet ./...
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 2Gi
|
||||
cpu: 2
|
||||
limits:
|
||||
memory: 6Gi
|
||||
cpu: 4
|
||||
|
||||
# Builds the pinned binary and drives a real `go build` through it.
|
||||
- name: test
|
||||
image: docker.io/golang:1.26
|
||||
commands:
|
||||
- make test
|
||||
depends_on: [vet]
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 2Gi
|
||||
cpu: 2
|
||||
limits:
|
||||
memory: 6Gi
|
||||
cpu: 4
|
||||
@@ -0,0 +1,58 @@
|
||||
BINARY := go-cache-plugin
|
||||
# Upstream has no releases; the shipped binary is built from the module version
|
||||
# pinned by the tool directive in go.mod.
|
||||
PKG := github.com/tailscale/go-cache-plugin/cmd/go-cache-plugin
|
||||
DIST := dist
|
||||
UPSTREAM := $(shell go list -m -f '{{.Version}}' github.com/tailscale/go-cache-plugin)
|
||||
GOFLAGS := -ldflags="-s -w"
|
||||
OS ?= $(shell go env GOOS)
|
||||
ARCH ?= $(shell go env GOARCH)
|
||||
|
||||
.PHONY: all build test lint fmt pre-commit clean upstream patch minor major _tag
|
||||
|
||||
all: build
|
||||
|
||||
# Static so the released binary runs on any image in the estate, Alpine included.
|
||||
build:
|
||||
CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build $(GOFLAGS) -o $(DIST)/$(BINARY) $(PKG)
|
||||
|
||||
test:
|
||||
go test -v ./...
|
||||
|
||||
lint:
|
||||
golangci-lint run ./...
|
||||
|
||||
fmt:
|
||||
gofmt -w .
|
||||
|
||||
pre-commit:
|
||||
uvx pre-commit run --all-files
|
||||
|
||||
upstream:
|
||||
@echo $(UPSTREAM)
|
||||
|
||||
clean:
|
||||
rm -rf $(DIST)
|
||||
|
||||
# Bump helpers -- reads the latest semver tag and creates the next one.
|
||||
# If no tag exists yet, starts from v0.0.0.
|
||||
_LATEST := $(shell git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$$' | head -1)
|
||||
_BASE := $(if $(_LATEST),$(_LATEST),v0.0.0)
|
||||
_MAJ := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f1)
|
||||
_MIN := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f2)
|
||||
_PAT := $(shell echo $(_BASE) | sed 's/^v//' | cut -d. -f3)
|
||||
|
||||
patch:
|
||||
@NEW=v$(_MAJ).$(_MIN).$(shell expr $(_PAT) + 1); \
|
||||
git tag $$NEW && echo "Tagged $$NEW" && $(MAKE) _tag TAG=$$NEW
|
||||
|
||||
minor:
|
||||
@NEW=v$(_MAJ).$(shell expr $(_MIN) + 1).0; \
|
||||
git tag $$NEW && echo "Tagged $$NEW" && $(MAKE) _tag TAG=$$NEW
|
||||
|
||||
major:
|
||||
@NEW=v$(shell expr $(_MAJ) + 1).0.0; \
|
||||
git tag $$NEW && echo "Tagged $$NEW" && $(MAKE) _tag TAG=$$NEW
|
||||
|
||||
_tag:
|
||||
git push origin $(TAG)
|
||||
@@ -1,3 +1,58 @@
|
||||
# go-cache-plugin
|
||||
|
||||
Build repo that compiles the tailscale/go-cache-plugin GOCACHEPROG S3 Go build cache from a pinned upstream module version and publishes static binaries as Gitea releases.
|
||||
Build repo for [`tailscale/go-cache-plugin`](https://github.com/tailscale/go-cache-plugin),
|
||||
a `GOCACHEPROG` implementation that backs the Go build cache with S3. Upstream
|
||||
publishes no releases, so this repo pins a commit via the `tool` directive in
|
||||
`go.mod` and ships the static binary as a Gitea release.
|
||||
|
||||
No source of its own. To move to a newer upstream commit:
|
||||
|
||||
```sh
|
||||
go get -tool github.com/tailscale/go-cache-plugin/cmd/go-cache-plugin@<commit>
|
||||
make test
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
```sh
|
||||
make build # dist/go-cache-plugin, CGO_ENABLED=0, stripped
|
||||
make test # builds the binary, then drives a real `go build` through it
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
Point it at the estate's Ceph RGW, which needs both a custom endpoint and
|
||||
path-style addressing:
|
||||
|
||||
```sh
|
||||
export GOCACHEPROG="go-cache-plugin \
|
||||
--cache-dir=$HOME/.cache/go-cache-plugin \
|
||||
--bucket=go-build-cache \
|
||||
--region=default \
|
||||
--s3-endpoint-url=https://s3.ceph.unkin.net \
|
||||
--s3-path-style"
|
||||
go build ./...
|
||||
```
|
||||
|
||||
Credentials come from the usual `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY`
|
||||
environment. Every flag also has a `GOCACHE_*` environment equivalent — see
|
||||
`go-cache-plugin help environment`. Add `--metrics` to print cache hit rates at
|
||||
exit, and `--expiry` to age entries out.
|
||||
|
||||
For a shared cache daemon, run `go-cache-plugin serve --plugin <port>` once and
|
||||
have each build use `go-cache-plugin connect <port>` as its `GOCACHEPROG`.
|
||||
|
||||
## CI
|
||||
|
||||
Woodpecker steps fetch the released binary:
|
||||
|
||||
```yaml
|
||||
commands:
|
||||
- curl -fsSLo /usr/local/bin/go-cache-plugin https://git.unkin.net/unkin/go-cache-plugin/releases/download/v0.1.0/go-cache-plugin-linux-amd64
|
||||
- chmod +x /usr/local/bin/go-cache-plugin
|
||||
```
|
||||
|
||||
## Release
|
||||
|
||||
`make patch|minor|major` tags and pushes; the tag pipeline builds
|
||||
`linux/amd64` and `linux/arm64` and attaches them with `sha256sums.txt`.
|
||||
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
// Package gocacheplugin has no source of its own: this repo exists only to
|
||||
// build the pinned upstream go-cache-plugin and ship it as a release. The tests
|
||||
// therefore exercise the built binary rather than any local code.
|
||||
package gocacheplugin
|
||||
|
||||
import (
|
||||
"debug/buildinfo"
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
upstreamPkg = "github.com/tailscale/go-cache-plugin/cmd/go-cache-plugin"
|
||||
upstreamModule = "github.com/tailscale/go-cache-plugin"
|
||||
)
|
||||
|
||||
var pluginBin string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
dir, err := os.MkdirTemp("", "go-cache-plugin-test")
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
pluginBin = filepath.Join(dir, "go-cache-plugin")
|
||||
build := exec.Command("go", "build", "-ldflags=-s -w", "-o", pluginBin, upstreamPkg)
|
||||
build.Env = append(os.Environ(), "CGO_ENABLED=0")
|
||||
if out, err := build.CombinedOutput(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "building %s: %v\n%s", upstreamPkg, err, out)
|
||||
_ = os.RemoveAll(dir)
|
||||
os.Exit(1)
|
||||
}
|
||||
code := m.Run()
|
||||
_ = os.RemoveAll(dir)
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// A dynamically linked binary will not run on the estate's Alpine-based CI
|
||||
// images, so CGO_ENABLED=0 must actually take effect.
|
||||
func TestBinaryIsStatic(t *testing.T) {
|
||||
fi, err := os.Stat(pluginBin)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fi.Size() == 0 {
|
||||
t.Fatal("binary is empty")
|
||||
}
|
||||
f, err := elf.Open(pluginBin)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
if s := f.Section(".interp"); s != nil {
|
||||
t.Error("binary has a .interp section, so it needs a dynamic loader")
|
||||
}
|
||||
libs, err := f.ImportedLibraries()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(libs) != 0 {
|
||||
t.Errorf("binary links shared libraries: %v", libs)
|
||||
}
|
||||
}
|
||||
|
||||
// The binary must come from the version go.mod pins, not from whatever the
|
||||
// toolchain would resolve on its own.
|
||||
func TestBuiltFromPinnedVersion(t *testing.T) {
|
||||
out, err := exec.Command("go", "list", "-m", "-f", "{{.Version}}", upstreamModule).Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := strings.TrimSpace(string(out))
|
||||
if want == "" {
|
||||
t.Fatalf("%s is not in the module graph", upstreamModule)
|
||||
}
|
||||
|
||||
info, err := buildinfo.ReadFile(pluginBin)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := info.Main.Version
|
||||
for _, dep := range info.Deps {
|
||||
if dep.Path == upstreamModule {
|
||||
got = dep.Version
|
||||
}
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("binary built from %s %q, go.mod pins %q", upstreamModule, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check that the real entry point runs and parses flags: without a
|
||||
// bucket the cache server must refuse to start.
|
||||
func TestRequiresBucket(t *testing.T) {
|
||||
cmd := exec.Command(pluginBin, "--cache-dir="+t.TempDir())
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Fatalf("expected a non-zero exit, got success:\n%s", out)
|
||||
}
|
||||
if !strings.Contains(string(out), "--bucket") {
|
||||
t.Errorf("expected a usage error naming --bucket, got:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
// End to end: drive a real `go build` through the binary as a GOCACHEPROG
|
||||
// plugin, pointed at a stub S3 endpoint that misses every read. This is the
|
||||
// only thing the repo ships, so it has to actually speak the protocol.
|
||||
func TestServesGoCacheProg(t *testing.T) {
|
||||
var reqs atomic.Int64
|
||||
s3 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
reqs.Add(1)
|
||||
if r.Method == http.MethodPut || r.Method == http.MethodPost {
|
||||
_, _ = io.Copy(io.Discard, r.Body)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/xml")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
_, _ = io.WriteString(w, `<?xml version="1.0" encoding="UTF-8"?><Error><Code>NoSuchKey</Code><Message>no such key</Message></Error>`)
|
||||
}))
|
||||
defer s3.Close()
|
||||
|
||||
cacheDir := t.TempDir()
|
||||
src := t.TempDir()
|
||||
write(t, filepath.Join(src, "go.mod"), "module example.test\n\ngo 1.26.1\n")
|
||||
write(t, filepath.Join(src, "main.go"), "package main\n\nfunc main() { println(\"ok\") }\n")
|
||||
|
||||
prog := strings.Join([]string{
|
||||
pluginBin,
|
||||
"--cache-dir=" + cacheDir,
|
||||
"--bucket=go-cache-test",
|
||||
"--region=us-east-1",
|
||||
"--s3-endpoint-url=" + s3.URL,
|
||||
"--s3-path-style",
|
||||
}, " ")
|
||||
|
||||
build := exec.Command("go", "build", "-o", filepath.Join(src, "out"), ".")
|
||||
build.Dir = src
|
||||
build.Env = append(os.Environ(),
|
||||
"GOFLAGS=",
|
||||
"GOCACHEPROG="+prog,
|
||||
"AWS_ACCESS_KEY_ID=test",
|
||||
"AWS_SECRET_ACCESS_KEY=test",
|
||||
)
|
||||
if out, err := build.CombinedOutput(); err != nil {
|
||||
t.Fatalf("go build under GOCACHEPROG failed: %v\n%s", err, out)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(src, "out")); err != nil {
|
||||
t.Fatalf("build produced no binary: %v", err)
|
||||
}
|
||||
if n := countFiles(t, cacheDir); n == 0 {
|
||||
t.Error("plugin staged nothing in the local cache directory")
|
||||
}
|
||||
if reqs.Load() == 0 {
|
||||
t.Error("plugin made no S3 requests")
|
||||
}
|
||||
}
|
||||
|
||||
func write(t *testing.T, path, content string) {
|
||||
t.Helper()
|
||||
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func countFiles(t *testing.T, dir string) int {
|
||||
t.Helper()
|
||||
var n int
|
||||
err := filepath.WalkDir(dir, func(_ string, d os.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !d.IsDir() {
|
||||
n++
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
module git.unkin.net/unkin/go-cache-plugin
|
||||
|
||||
go 1.26.1
|
||||
|
||||
tool github.com/tailscale/go-cache-plugin/cmd/go-cache-plugin
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.99.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 // indirect
|
||||
github.com/aws/smithy-go v1.25.0 // indirect
|
||||
github.com/creachadair/atomicfile v0.4.2 // indirect
|
||||
github.com/creachadair/command v0.2.6 // indirect
|
||||
github.com/creachadair/flax v0.0.6 // indirect
|
||||
github.com/creachadair/gocache v0.0.0-20260710224145-042386578e2a // indirect
|
||||
github.com/creachadair/mds v0.29.2 // indirect
|
||||
github.com/creachadair/mhttp v0.0.0-20260407161248-6866af4c556b // indirect
|
||||
github.com/creachadair/msync v0.8.1 // indirect
|
||||
github.com/creachadair/scheddle v0.0.0-20260418161627-87a4a0c853c4 // indirect
|
||||
github.com/creachadair/taskgroup v0.14.4 // indirect
|
||||
github.com/creachadair/tlsutil v0.0.0-20260218173745-49b0059fedaf // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect
|
||||
github.com/goproxy/goproxy v0.21.0 // indirect
|
||||
github.com/tailscale/go-cache-plugin v0.1.2-0.20260723040932-3031b5d01c50 // indirect
|
||||
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||
golang.org/x/mod v0.31.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
tailscale.com v1.96.5 // indirect
|
||||
)
|
||||
@@ -0,0 +1,78 @@
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.6/go.mod h1:dy0UzBIfwSeot4grGvY1AqFWN5zgziMmWGzysDnHFcQ=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.9 h1:adBsCIIpLbLmYnkQU+nAChU5yhVTvu5PerROm+/Kq2A=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.9/go.mod h1:uOYhgfgThm/ZyAuJGNQ5YgNyOlYfqnGpTHXvk3cpykg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.16 h1:Q0iQ7quUgJP0F/SCRTieScnaMdXr9h/2+wze1u3cNeM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.16/go.mod h1:duCCnJEFqpt2RC6no1iK6q+8HpwOAkiUua0pY507dQc=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.15 h1:fyvgWTszojq8hEnMi8PPBTvZdTtEVmAVyo+NFLHBhH4=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.15/go.mod h1:gJiYyMOjNg8OEdRWOf3CrFQxM2a98qmrtjx1zuiQfB8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 h1:IOGsJ1xVWhsi+ZO7/NW8OuZZBtMJLZbk4P5HDjJO0jQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22/go.mod h1:b+hYdbU+jGKfXE8kKM6g1+h+L/Go3vMvzlxBsiuGsxg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 h1:GmLa5Kw1ESqtFpXsx5MmC84QWa/ZrLZvlJGa2y+4kcQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22/go.mod h1:6sW9iWm9DK9YRpRGga/qzrzNLgKpT2cIxb7Vo2eNOp0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 h1:dY4kWZiSaXIzxnKlj17nHnBcXXBfac6UlsAx2qL6XrU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22/go.mod h1:KIpEUx0JuRZLO7U6cbV204cWAEco2iC3l061IxlwLtI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 h1:FPXsW9+gMuIeKmz7j6ENWcWtBGTe1kH8r9thNt5Uxx4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23/go.mod h1:7J8iGMdRKk6lw2C+cMIphgAnT8uTwBwNOsGkyOCm80U=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 h1:HtOTYcbVcGABLOVuPYaIihj6IlkqubBwFj10K5fxRek=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8/go.mod h1:VsK9abqQeGlzPgUr+isNWzPlK2vKe9INMLWnY65f5Xs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.14 h1:xnvDEnw+pnj5mctWiYuFbigrEzSm35x7k4KS/ZkCANg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.14/go.mod h1:yS5rNogD8e0Wu9+l3MUwr6eENBzEeGejvINpN5PAYfY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 h1:PUmZeJU6Y1Lbvt9WFuJ0ugUK2xn6hIWUBBbKuOWF30s=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22/go.mod h1:nO6egFBoAaoXze24a2C0NjQCvdpk8OueRoYimvEB9jo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.22 h1:SE+aQ4DEqG53RRCAIHlCf//B2ycxGH7jFkpnAh/kKPM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.22/go.mod h1:ES3ynECd7fYeJIL6+oax+uIEljmfps0S70BaQzbMd/o=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.99.1 h1:kU/eBN5+MWNo/LcbNa4hWDdN76hdcd7hocU5kvu7IsU=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.99.1/go.mod h1:Fw9aqhJicIVee1VytBBjH+l+5ov6/PhbtIK/u3rt/ls=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 h1:a1Fq/KXn75wSzoJaPQTgZO0wHGqE9mjFnylnqEPTchA=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.10/go.mod h1:p6+MXNxW7IA6dMgHfTAzljuwSKD0NCm/4lbS4t6+7vI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 h1:x6bKbmDhsgSZwv6q19wY/u3rLk/3FGjJWyqKcIRufpE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.16/go.mod h1:CudnEVKRtLn0+3uMV0yEXZ+YZOKnAtUJ5DmDhilVnIw=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 h1:oK/njaL8GtyEihkWMD4k3VgHCT64RQKkZwh0DG5j8ak=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20/go.mod h1:JHs8/y1f3zY7U5WcuzoJ/yAYGYtNIVPKLIbp61euvmg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 h1:ks8KBcZPh3PYISr5dAiXCM5/Thcuxk8l+PG4+A0exds=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.42.0/go.mod h1:pFw33T0WLvXU3rw1WBkpMlkgIn54eCB5FYLhjDc9Foo=
|
||||
github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U=
|
||||
github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/creachadair/atomicfile v0.4.2 h1:pSSsKxmUefqCTg+QgyCG2bw1KmsB76apBL4lhJjichI=
|
||||
github.com/creachadair/atomicfile v0.4.2/go.mod h1:ts9VunJluQvSXtkrl0YlDn9ckZaS+eMkBW2g20gB5II=
|
||||
github.com/creachadair/command v0.2.6 h1:+d4xUSZza5nqRVVsVRf5jDbix/0uKxVqFrc30F4uyRI=
|
||||
github.com/creachadair/command v0.2.6/go.mod h1:HWvS3zEpVakKlNXxT/j1U8tNoDaY7By7ORYQ+m1ha2U=
|
||||
github.com/creachadair/flax v0.0.6 h1:IFUdRdfKynNTyR5SRlrHMUGnxxMZZen8RVpwcDq/ftk=
|
||||
github.com/creachadair/flax v0.0.6/go.mod h1:F1PML0JZLXSNDMNiRGK2yjm5f+L9QCHchyHBldFymj8=
|
||||
github.com/creachadair/gocache v0.0.0-20260710224145-042386578e2a h1:cYAmYaIvlHjbnpM2DmH+kNaOC3qYQcpg8iYXNaMrcMg=
|
||||
github.com/creachadair/gocache v0.0.0-20260710224145-042386578e2a/go.mod h1:f7A5Y4U3AWm53Dh6diUnOxDRBfuFNLqusf07sLd6cc4=
|
||||
github.com/creachadair/mds v0.29.2 h1:1IBhfyolZUCA53twI1hXembOdpIe4bJ4OGJELBbGrN4=
|
||||
github.com/creachadair/mds v0.29.2/go.mod h1:dMBTCSy3iS3dwh4Rb1zxeZz2d7K8+N24GCTsayWtQRI=
|
||||
github.com/creachadair/mhttp v0.0.0-20260407161248-6866af4c556b h1:bIvrALyE2ixkCvz9LADfOIuhkUMYWMBsvQ29xe70nI0=
|
||||
github.com/creachadair/mhttp v0.0.0-20260407161248-6866af4c556b/go.mod h1:eV+igunEfCBbgpM0gkDK/25/ukdeNYXH9PZuuEWZTDo=
|
||||
github.com/creachadair/msync v0.8.1 h1:QRd8si3qZ2Q4TaDL7tS/MG/lFE3YND7U7J9fy42eAFM=
|
||||
github.com/creachadair/msync v0.8.1/go.mod h1:dt0bscS09J8Ie3AdccK9JpCb7LfStaDGlAmDLukOlY4=
|
||||
github.com/creachadair/scheddle v0.0.0-20260418161627-87a4a0c853c4 h1:uYu6k39F6Sz4Y5Zb+R2ZnhE1S5ehCw4lknwrt4bm7NI=
|
||||
github.com/creachadair/scheddle v0.0.0-20260418161627-87a4a0c853c4/go.mod h1:PE4owEX+08lTR1VNomiSFFh6DzkmmzlBgysEOq8zwdI=
|
||||
github.com/creachadair/taskgroup v0.14.4 h1:ttR8StLWmYA1O6x96YlTpQLXjKyRpO4RBo+OcO6W6C0=
|
||||
github.com/creachadair/taskgroup v0.14.4/go.mod h1:uhCtIEsa7zpeMAFixddhCYjbJi7e4JMyU7OXUygkSsg=
|
||||
github.com/creachadair/tlsutil v0.0.0-20260218173745-49b0059fedaf h1:6ZqacBCoIdOSlwh03zr3TMqA5VyuFpzUS7E2yzfjq7w=
|
||||
github.com/creachadair/tlsutil v0.0.0-20260218173745-49b0059fedaf/go.mod h1:YUng4wUBh60nfswe0FwLeBOpoIsrW6ReXt9Zr9k55Sg=
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I=
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
|
||||
github.com/goproxy/goproxy v0.21.0 h1:S3JPCp/WLqLl7X40eo5FFiAbBZwD8S6TzGPBITwfHlo=
|
||||
github.com/goproxy/goproxy v0.21.0/go.mod h1:4j3iRV76B133PK4sOzVYWSBs/SsE5ovbZsdceoC5f+w=
|
||||
github.com/tailscale/go-cache-plugin v0.1.2-0.20260723040932-3031b5d01c50 h1:iF7+CaT5ro+WYnIZH6a9EbGPQ3KRWnF7VnyA+57sFKY=
|
||||
github.com/tailscale/go-cache-plugin v0.1.2-0.20260723040932-3031b5d01c50/go.mod h1:HiHE7c3OvFT6JfCq+UZCupZN1aohtpYaY6MdhOpBPys=
|
||||
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek=
|
||||
go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
|
||||
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
tailscale.com v1.96.5 h1:gNkfA/KSZAl6jCH9cj8urq00HRWItDDTtGsyATI89jA=
|
||||
tailscale.com v1.96.5/go.mod h1:/3lnZBYb2UEwnN0MNu2SDXUtT06AGd5k0s+OWx3WmcY=
|
||||
Reference in New Issue
Block a user