Weighs the soul of incoming HTTP requests to stop AI crawlers

Try using ko to build images

Signed-off-by: Xe Iaso <me@xeiaso.net>

Xe Iaso 1efcb882 1a13292c

Changed files
+166 -11
.github
workflows
cmd
containerbuild
+14 -10
.github/workflows/docker.yml
··· 8 8 pull_request: 9 9 branches: [ "main" ] 10 10 11 + env: 12 + DOCKER_METADATA_SET_OUTPUT_ENV: "true" 13 + 11 14 permissions: 12 15 contents: read 13 16 packages: write ··· 20 23 steps: 21 24 - name: Checkout code 22 25 uses: actions/checkout@v4 26 + with: 27 + fetch-tags: true 28 + fetch-depth: 0 23 29 24 30 - name: Set up QEMU 25 31 uses: docker/setup-qemu-action@v3 26 32 27 33 - name: Set up Docker Buildx 28 34 uses: docker/setup-buildx-action@v3 35 + 36 + - uses: actions/setup-go@v5 37 + with: 38 + go-version: '1.24.x' 39 + 40 + - uses: ko-build/setup-ko@v0.8 29 41 30 42 - name: Log into registry 31 43 uses: docker/login-action@v3 ··· 42 54 43 55 - name: Build and push 44 56 id: build 45 - uses: docker/build-push-action@v6 46 - with: 47 - context: . 48 - cache-to: type=gha 49 - cache-from: type=gha 50 - tags: ${{ steps.meta.outputs.tags }} 51 - labels: ${{ steps.meta.outputs.labels }} 52 - platforms: linux/arm64/v8,linux/amd64 53 - sbom: true 54 - push: true 57 + run: | 58 + go run ./cmd/containerbuild --docker-repo ghcr.io/techarohq/anubis --slog-level debug 55 59 56 60 - name: Generate artifact attestation 57 61 uses: actions/attest-build-provenance@v2
+13
.ko.yaml
··· 1 + defaultBaseImage: cgr.dev/chainguard/static 2 + defaultPlatforms: 3 + - linux/arm64 4 + - linux/amd64 5 + - linux/arm/v7 6 + 7 + builds: 8 + - id: anubis 9 + main: ./cmd/anubis 10 + ldflags: 11 + - -s -w 12 + - -extldflags "-static" 13 + - -X github.com/TecharoHQ/anubis.Version={{.Env.VERSION}}
+2 -1
Brewfile
··· 1 1 # programming languages 2 2 brew "go@1.24" 3 - brew "node" 3 + brew "node" 4 + brew "ko"
+3
CHANGELOG.md
··· 7 7 8 8 ## [Unreleased] 9 9 10 + - Images are built using ko instead of `docker buildx build` 11 + [#13](https://github.com/TecharoHQ/anubis/pull/13) 12 + 10 13 ## 1.12.1 11 14 12 15 - Phrasing in the `<noscript>` warning was replaced from its original placeholder text to
+1
cmd/containerbuild/.gitignore
··· 1 + images
+133
cmd/containerbuild/main.go
··· 1 + package main 2 + 3 + import ( 4 + "flag" 5 + "fmt" 6 + "log" 7 + "log/slog" 8 + "os" 9 + "os/exec" 10 + "path/filepath" 11 + "strings" 12 + 13 + "github.com/TecharoHQ/anubis/internal" 14 + "github.com/facebookgo/flagenv" 15 + ) 16 + 17 + var ( 18 + dockerAnnotations = flag.String("docker-annotations", os.Getenv("DOCKER_METADATA_OUTPUT_ANNOTATIONS"), "Docker image annotations") 19 + dockerLabels = flag.String("docker-labels", os.Getenv("DOCKER_METADATA_OUTPUT_LABELS"), "Docker image labels") 20 + dockerRepo = flag.String("docker-repo", "registry.int.xeserv.us/techaro/anubis", "Docker image repository for Anubis") 21 + dockerTags = flag.String("docker-tags", os.Getenv("DOCKER_METADATA_OUTPUT_TAGS"), "newline separated docker tags including the registry name") 22 + slogLevel = flag.String("slog-level", "INFO", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)") 23 + ) 24 + 25 + func main() { 26 + flagenv.Parse() 27 + flag.Parse() 28 + 29 + internal.InitSlog(*slogLevel) 30 + 31 + koDockerRepo := strings.TrimRight(*dockerRepo, "/"+filepath.Base(*dockerRepo)) 32 + version, err := run("git describe --tags --always --dirty") 33 + 34 + slog.Debug( 35 + "ko env", 36 + "KO_DOCKER_REPO", koDockerRepo, 37 + "VERSION", version, 38 + ) 39 + 40 + os.Setenv("KO_DOCKER_REPO", koDockerRepo) 41 + os.Setenv("VERSION", version) 42 + 43 + setOutput("version", version) 44 + 45 + if *dockerTags == "" { 46 + log.Fatal("Must set --docker-tags or DOCKER_METADATA_OUTPUT_TAGS") 47 + } 48 + 49 + images, err := parseImageList(*dockerTags) 50 + if err != nil { 51 + log.Fatalf("can't parse images: %v", err) 52 + } 53 + 54 + for _, img := range images { 55 + if img.repository != *dockerRepo { 56 + slog.Error( 57 + "Something weird is going on. Wanted docker repo differs from contents of --docker-tags. Did a flag get set incorrectly?", 58 + "wanted", *dockerRepo, 59 + "got", img.repository, 60 + "docker-tags", *dockerTags, 61 + ) 62 + os.Exit(2) 63 + } 64 + } 65 + 66 + var tags []string 67 + for _, img := range images { 68 + tags = append(tags, img.tag) 69 + } 70 + 71 + output, err := run(fmt.Sprintf("ko build --platform=all --base-import-paths --tags=%q --image-user=1000 --image-annotation=%q --image-label=%q ./cmd/anubis | tail -n1", strings.Join(tags, ","), *dockerAnnotations, *dockerLabels)) 72 + if err != nil { 73 + log.Fatalf("can't run ko build, check stderr: %v", err) 74 + } 75 + 76 + sp := strings.SplitN(output, "@", 2) 77 + 78 + setOutput("digest", sp[1]) 79 + } 80 + 81 + type image struct { 82 + repository string 83 + tag string 84 + } 85 + 86 + func newlineSep2Comma(inp string) string { 87 + lines := strings.Split(inp, "\n") 88 + return strings.Join(lines, ",") 89 + } 90 + 91 + func parseImageList(imageList string) ([]image, error) { 92 + images := strings.Split(imageList, "\n") 93 + var result []image 94 + for _, img := range images { 95 + if img == "" { 96 + continue 97 + } 98 + 99 + // reg.xeiaso.net/techaro/anubis:latest 100 + // repository: reg.xeiaso.net/techaro/anubis 101 + // tag: latest 102 + parts := strings.SplitN(img, ":", 2) 103 + result = append(result, image{ 104 + repository: parts[0], 105 + tag: parts[1], 106 + }) 107 + } 108 + 109 + if len(result) == 0 { 110 + return nil, fmt.Errorf("no images provided, bad flags??") 111 + } 112 + 113 + return result, nil 114 + } 115 + 116 + // run executes a command and returns the trimmed output. 117 + func run(command string) (string, error) { 118 + bin, err := exec.LookPath("sh") 119 + if err != nil { 120 + return "", err 121 + } 122 + cmd := exec.Command(bin, "-c", command) 123 + cmd.Stderr = os.Stderr 124 + out, err := cmd.Output() 125 + if err != nil { 126 + return "", err 127 + } 128 + return strings.TrimSpace(string(out)), nil 129 + } 130 + 131 + func setOutput(key, val string) { 132 + fmt.Printf("::set-output name=%s::%s\n", key, val) 133 + }