From 7737ac48ff930afa926b592eace4b1c3d3a46360 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 01/14] Forward every caught signal, not just the first The forwarding goroutine did a single blocking channel read, forwarded one signal, and exited. signal.Notify stays registered for the life of the process, so every later SIGTERM/SIGINT was still intercepted by the runtime but never read: it neither reached the child nor terminated the wrapper. A second Ctrl-C, or a supervisor escalating its shutdown request, was silently swallowed until SIGKILL. Drain the channel in a loop instead, and grow the buffer from 1 to 32: signal.Notify sends without blocking and drops signals when the buffer is full, so bursts could otherwise be lost while a forward is in flight. Co-Authored-By: Claude Fable 5 --- runner.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/runner.go b/runner.go index c7bad56..0c1e95e 100644 --- a/runner.go +++ b/runner.go @@ -29,20 +29,21 @@ func RunCommand(command string, args []string, envVars []string) error { log.Infof("PID %v running %s %s", cmd.Process.Pid, cmd.Path, strings.Join(args, " ")) - sigc := make(chan os.Signal, 1) + sigc := make(chan os.Signal, 32) signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) go func() { - sigv := <-sigc - killErr := syscall.Kill(-os.Getpid(), sigv.(syscall.Signal)) - log.WithFields(log.Fields{ - "err": killErr, - "pid": -cmd.Process.Pid, - "signal": sigv, - }).Info("Caught signal, sent to child") + for sigv := range sigc { + killErr := syscall.Kill(-os.Getpid(), sigv.(syscall.Signal)) + log.WithFields(log.Fields{ + "err": killErr, + "pid": -cmd.Process.Pid, + "signal": sigv, + }).Info("Caught signal, sent to child") + } }() return cmd.Wait() From a27fd2466c6d9f70a8d353c4408d058124b7a09b Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 02/14] Signal the child directly instead of the parent's process group kill(-getpid()) targets the process group whose ID equals the wrapper's own PID. That group only exists when the wrapper happens to be a group leader, e.g. PID 1 in a container or a job started by an interactive shell. Launched from a shell script or a supervisor, the kill failed with ESRCH and the child never received the signal at all. Where the group did exist, terminal-generated signals arrived twice (once from the kernel to the foreground group, once from us), and each forward re-signalled the wrapper itself. The log reported -cmd.Process.Pid, a group that never existed, while the code signalled a different one. Use cmd.Process.Signal to address exactly the process we started; it behaves identically in every launch context and delivers exactly once. Propagating further down the tree is the child's responsibility, the same contract as tini's default behaviour. Co-Authored-By: Claude Fable 5 --- runner.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runner.go b/runner.go index 0c1e95e..ac61696 100644 --- a/runner.go +++ b/runner.go @@ -37,10 +37,10 @@ func RunCommand(command string, args []string, envVars []string) error { syscall.SIGQUIT) go func() { for sigv := range sigc { - killErr := syscall.Kill(-os.Getpid(), sigv.(syscall.Signal)) + sigErr := cmd.Process.Signal(sigv) log.WithFields(log.Fields{ - "err": killErr, - "pid": -cmd.Process.Pid, + "err": sigErr, + "pid": cmd.Process.Pid, "signal": sigv, }).Info("Caught signal, sent to child") } From d0e52b3696bb99074c7103ad9b8ec7a01955ed34 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 03/14] Install signal handler before starting the child signal.Notify ran after cmd.Start, so a signal arriving between the two killed the wrapper via default disposition and orphaned the just-started child. Supervisors that start and almost immediately stop a service (crash loops, instant rollbacks) can hit this window. Register interception before starting the child. Signals arriving before the forwarding goroutine is up queue in the buffered channel and are delivered once the child runs. Co-Authored-By: Claude Fable 5 --- runner.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/runner.go b/runner.go index ac61696..ce4f8ea 100644 --- a/runner.go +++ b/runner.go @@ -23,18 +23,21 @@ func RunCommand(command string, args []string, envVars []string) error { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - if err := cmd.Start(); err != nil { - return err - } - - log.Infof("PID %v running %s %s", cmd.Process.Pid, cmd.Path, strings.Join(args, " ")) - + // Signals arriving before Start queue up in the channel and are forwarded + // once the child is running. sigc := make(chan os.Signal, 32) signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + + if err := cmd.Start(); err != nil { + return err + } + + log.Infof("PID %v running %s %s", cmd.Process.Pid, cmd.Path, strings.Join(args, " ")) + go func() { for sigv := range sigc { sigErr := cmd.Process.Signal(sigv) From de20cba016d771131a7740c1008f3ccdfe3df2d8 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 04/14] Forward all catchable signals to the child Only SIGHUP, SIGINT, SIGTERM and SIGQUIT were forwarded. Any other signal, e.g. SIGUSR1 to rotate logs or SIGWINCH on resize, killed the wrapper through its default disposition and orphaned the child. An entrypoint wrapper should be transparent: whatever an operator sends to the visible PID must reach the application behind it. Subscribe to every catchable signal and forward, with two exceptions: SIGCHLD is addressed to the wrapper about its own child, and SIGURG is used continuously by the Go runtime for goroutine preemption. Demote the per-forward log line to debug; with SIGWINCH forwarded, a terminal resize would otherwise spam info-level logs. Co-Authored-By: Claude Fable 5 --- runner.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/runner.go b/runner.go index ce4f8ea..d66dfc7 100644 --- a/runner.go +++ b/runner.go @@ -26,11 +26,7 @@ func RunCommand(command string, args []string, envVars []string) error { // Signals arriving before Start queue up in the channel and are forwarded // once the child is running. sigc := make(chan os.Signal, 32) - signal.Notify(sigc, - syscall.SIGHUP, - syscall.SIGINT, - syscall.SIGTERM, - syscall.SIGQUIT) + signal.Notify(sigc) if err := cmd.Start(); err != nil { return err @@ -40,12 +36,16 @@ func RunCommand(command string, args []string, envVars []string) error { go func() { for sigv := range sigc { + // SIGCHLD is for the wrapper itself; SIGURG is used by the Go runtime. + if sigv == syscall.SIGCHLD || sigv == syscall.SIGURG { + continue + } sigErr := cmd.Process.Signal(sigv) log.WithFields(log.Fields{ "err": sigErr, "pid": cmd.Process.Pid, "signal": sigv, - }).Info("Caught signal, sent to child") + }).Debug("Forwarded signal to child") } }() From d9ec55bc1ca71a91be01eeda4ad916717085beb0 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 05/14] Exit with 128+N when the child is killed by a signal A signal-killed child has no exit code, so ExitCode() returns -1 and os.Exit truncated it to 255, collapsing SIGTERM, SIGKILL and SIGSEGV into one indistinguishable value. Translate to the shell convention of 128+N: 143 for SIGTERM, 137 for SIGKILL, the code supervisors and container tooling already interpret (137 is the well-known OOM-kill signature). Voluntary exits still pass through unchanged. Co-Authored-By: Claude Fable 5 --- main.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 37a0324..64fde2f 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "os" "os/exec" "strings" + "syscall" log "github.com/sirupsen/logrus" "github.com/urfave/cli/v3" @@ -76,7 +77,11 @@ func action(ctx context.Context, cmd *cli.Command) error { if err := RunCommand(args.First(), args.Tail(), envVars); err != nil { var exitErr *exec.ExitError if errors.As(err, &exitErr) { - return cli.Exit(errorPrefix(err), exitErr.ExitCode()) + code := exitErr.ExitCode() + if status, ok := exitErr.Sys().(syscall.WaitStatus); ok && status.Signaled() { + code = 128 + int(status.Signal()) + } + return cli.Exit(errorPrefix(err), code) } return cli.Exit(errorPrefix(err), 128) } From aa56e8019cd1973b9440f4ddcd7293a157e5b404 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 06/14] Stop flag parsing at the wrapped command urfave/cli v3 parses flags interspersed with positional arguments, so flags belonging to the wrapped command were claimed by the wrapper: "env-aws-params --prefix /x bash -c set" failed with "flag provided but not defined: -c" unless callers inserted "--" by hand. Set StopOnNthArg to 1: parsing stops at the first positional argument, and everything after the command passes through verbatim, matching how env(1), sudo and docker run treat their command tails. Wrapper flags must consequently appear before the command; trailing flags now belong to the child. Co-Authored-By: Claude Fable 5 --- main.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 64fde2f..5ce83a0 100644 --- a/main.go +++ b/main.go @@ -18,13 +18,17 @@ import ( var VersionString string func main() { + // Stop flag parsing at the wrapped command, so its own flags + // (e.g. sh -c) are passed through instead of rejected. + stopOnFirstArg := 1 cmd := &cli.Command{ - Name: "env-aws-params", - Usage: "Application entry-point that injects SSM Parameter Store values as Environment Variables", - UsageText: "env-aws-params [global options] -p prefix command [command arguments]", - Version: VersionString, - Flags: cliFlags(), - Action: action, + Name: "env-aws-params", + Usage: "Application entry-point that injects SSM Parameter Store values as Environment Variables", + UsageText: "env-aws-params [global options] -p prefix command [command arguments]", + Version: VersionString, + Flags: cliFlags(), + Action: action, + StopOnNthArg: &stopOnFirstArg, } if err := cmd.Run(context.Background(), os.Args); err != nil { log.Fatal(err) From d881cf364cca4fe710a937db07dcc641fa3a9601 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 07/14] Use distinct exit codes for tool errors and document them Wrapper-side failures exited with 1 or 2 (validation), 255 (Parameter Store errors, via -1) and 128 (spawn failures). All of these collide with codes real children use, or with the 128+N signal range, so callers could not tell "the app failed" from "the plumbing failed". Adopt the shell and Docker convention: 125 for wrapper-side errors, 126 for a command that was found but could not be started, 127 for a command that was not found. exec.ErrNotFound covers failed PATH lookups; os.ErrNotExist covers explicit paths. A child may still exit with these codes itself; that ambiguity is inherent to the convention. validateArgs now returns only an error since both validation failures map to 125. Document the whole contract in the README. Co-Authored-By: Claude Fable 5 --- README.md | 10 ++++++++++ main.go | 20 +++++++++++--------- main_test.go | 24 ++++-------------------- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 29c24bd..46317a5 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,16 @@ GLOBAL OPTIONS: --version, -v print the version ``` +## Exit codes + +The wrapped command's exit code is passed through unchanged. ``env-aws-params`` +itself uses: + +- ``125`` — invalid usage or a Parameter Store error +- ``126`` — the command was found but could not be started +- ``127`` — the command was not found +- ``128+N`` — the command was killed by signal ``N`` (e.g. ``143`` for ``SIGTERM``) + ## Building from source This project uses [Go modules](https://go.dev/blog/using-go-modules) and requires Go 1.26+. diff --git a/main.go b/main.go index 5ce83a0..d7b935e 100644 --- a/main.go +++ b/main.go @@ -43,16 +43,15 @@ func action(ctx context.Context, cmd *cli.Command) error { log.SetOutput(io.Discard) } - code, err := validateArgs(cmd.NArg(), cmd.Bool("sanitize"), cmd.Bool("strip")) - if code > 0 { - return cli.Exit(errorPrefix(err), code) + if err := validateArgs(cmd.NArg(), cmd.Bool("sanitize"), cmd.Bool("strip")); err != nil { + return cli.Exit(errorPrefix(err), 125) } var envVars []string if len(cmd.StringSlice("prefix")) > 0 { params, err := getParameters(ctx, cmd) if err != nil { - return cli.Exit(errorPrefix(err), -1) + return cli.Exit(errorPrefix(err), 125) } envVars = BuildEnvVars( @@ -87,7 +86,10 @@ func action(ctx context.Context, cmd *cli.Command) error { } return cli.Exit(errorPrefix(err), code) } - return cli.Exit(errorPrefix(err), 128) + if errors.Is(err, exec.ErrNotFound) || errors.Is(err, os.ErrNotExist) { + return cli.Exit(errorPrefix(err), 127) + } + return cli.Exit(errorPrefix(err), 126) } return nil } @@ -179,14 +181,14 @@ func getParameters(ctx context.Context, cmd *cli.Command) (map[string]string, er return values, nil } -func validateArgs(nargs int, sanitize, strip bool) (int, error) { +func validateArgs(nargs int, sanitize, strip bool) error { if nargs == 0 { - return 1, errors.New("command not specified") + return errors.New("command not specified") } if sanitize && strip { - return 2, errors.New("--sanitize and --strip are mutually exclusive behaviors") + return errors.New("--sanitize and --strip are mutually exclusive behaviors") } - return 0, nil + return nil } diff --git a/main_test.go b/main_test.go index 6a1ffe4..2efd3a1 100644 --- a/main_test.go +++ b/main_test.go @@ -6,41 +6,25 @@ import ( ) func TestValidateArgsNoPrefixIsValid(t *testing.T) { - code, err := validateArgs(1, false, false) - if code != 0 { - t.Fatalf("expected code to be 0, got %v", code) - } - if err != nil { + if err := validateArgs(1, false, false); err != nil { t.Fatalf("expected err to be nil, got %v", err) } } func TestValidateArgsMissingCommand(t *testing.T) { - code, err := validateArgs(0, false, false) - if code != 1 { - t.Fatalf("expected code to be 1, got %v", code) - } - if err == nil { + if err := validateArgs(0, false, false); err == nil { t.Fatalf("expected err to be set, got nil") } } func TestValidateArgsStripAndSanitize(t *testing.T) { - code, err := validateArgs(1, true, true) - if code != 2 { - t.Fatalf("expected code to be 2, got %v", code) - } - if err == nil { + if err := validateArgs(1, true, true); err == nil { t.Fatalf("expected err to be set, got nil") } } func TestValidateArgsValid(t *testing.T) { - code, err := validateArgs(1, false, true) - if code != 0 { - t.Fatalf("expected code to be 0, got %v", code) - } - if err != nil { + if err := validateArgs(1, false, true); err != nil { t.Fatalf("expected err to be nil, got %v", err) } } From 832888a26d9ea35fe4686b053a471f9940b77d35 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 08/14] Warn on env key collisions and dedupe deterministically The --sanitize, --strip and --upcase transforms are lossy: db-host and db_host both become DB_HOST. Both entries were emitted, and the effective winner was picked by os/exec's keep-last deduplication over a slice sorted as whole "KEY=value" strings, i.e. by lexical order of the values. Rotating a value could silently flip which parameter won. Iterate parameters in sorted-name order into a map keyed by the final env key: exactly one entry per key is emitted and the parameter whose name sorts last wins, independent of values. Collisions log a warning naming both parameters, the contested key and the winner. Co-Authored-By: Claude Fable 5 --- data.go | 33 +++++++++++++++++++++++---------- data_test.go | 10 ++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/data.go b/data.go index c4cd224..a42b0d5 100644 --- a/data.go +++ b/data.go @@ -1,10 +1,12 @@ package main import ( - "fmt" + "maps" "regexp" - "sort" + "slices" "strings" + + log "github.com/sirupsen/logrus" ) var InvalidPattern = regexp.MustCompile(`[^a-zA-Z0-9_]`) @@ -25,20 +27,31 @@ func MergeEnvVars(ssmVars []string, environ []string) []string { } func BuildEnvVars(parameters map[string]string, sanitize bool, strip bool, upcase bool) []string { - var vars []string - - for k, v := range parameters { + // Transform in sorted parameter order so collisions resolve deterministically. + values := make(map[string]string, len(parameters)) + sources := make(map[string]string, len(parameters)) + for _, name := range slices.Sorted(maps.Keys(parameters)) { + key := name if sanitize { - k = InvalidPattern.ReplaceAllString(k, "_") + key = InvalidPattern.ReplaceAllString(key, "_") } if strip { - k = InvalidPattern.ReplaceAllString(k, "") + key = InvalidPattern.ReplaceAllString(key, "") } if upcase { - k = strings.ToUpper(k) + key = strings.ToUpper(key) + } + if prev, ok := sources[key]; ok { + log.Warnf("Parameters %q and %q both map to %s; keeping the value of %q", prev, name, key, name) } - vars = append(vars, fmt.Sprintf("%s=%s", k, v)) + sources[key] = name + values[key] = parameters[name] + } + + vars := make([]string, 0, len(values)) + for key, value := range values { + vars = append(vars, key+"="+value) } - sort.Strings(vars) + slices.Sort(vars) return vars } diff --git a/data_test.go b/data_test.go index 7ab7bab..346d410 100644 --- a/data_test.go +++ b/data_test.go @@ -110,6 +110,16 @@ func TestBuildEnvVarsUpperSanitize(t *testing.T) { AssertEqual(t, envVars, expectation) } +func TestBuildEnvVarsCollisionKeepsLastSortedParameter(t *testing.T) { + params := map[string]string{ + "db-host": "from-dash", + "db_host": "from-underscore", + } + + envVars := BuildEnvVars(params, true, false, true) + AssertEqual(t, envVars, []string{"DB_HOST=from-underscore"}) +} + func TestBuildEnvVarsUpperStrip(t *testing.T) { var params map[string]string From a211bbbe6c1e2284ebbdcc62de514e6551fd93b3 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 09/14] Default the version to dev for unversioned builds Builds that skip the -X ldflag, e.g. a plain go build or go install, printed an empty string for --version. The linker flag overwrites the initial value, so stamped release builds are unaffected. Co-Authored-By: Claude Fable 5 --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index d7b935e..f9ef265 100644 --- a/main.go +++ b/main.go @@ -15,7 +15,7 @@ import ( "golang.org/x/sync/errgroup" ) -var VersionString string +var VersionString = "dev" func main() { // Stop flag parsing at the wrapped command, so its own flags From 1236eef9e8de185058505e0a8c29ec70e3e6b51a Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 10/14] Require Go 1.26.5 to pick up the crypto/tls fix (GO-2026-5856) govulncheck reports the Encrypted Client Hello privacy leak in crypto/tls (GO-2026-5856) as reachable from this binary through the SSM client's TLS calls. The fix ships with the toolchain rather than a module, so the floor is expressed as a toolchain directive: any Go since 1.21 fetches 1.26.5 automatically, and GOTOOLCHAIN=local fails loudly instead of silently producing a vulnerable binary. CI floats on 1.26.x and picks the patch up by itself. Co-Authored-By: Claude Fable 5 --- go.mod | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go.mod b/go.mod index 0628081..b5de66c 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module env-aws-params go 1.26 +toolchain go1.26.5 + require ( github.com/aws/aws-sdk-go-v2 v1.41.7 github.com/aws/aws-sdk-go-v2/config v1.32.17 From 04f61e208be498779b54ca8c98546838a44c99f1 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 11/14] Scope release permissions to the release job contents: write applied to the whole workflow, handing a repo-write token to the test and build jobs. Those run on every push and pull request and execute the most third-party code, yet only need to read the repository. Default the workflow token to contents: read and grant write solely to the release job, which creates GitHub Releases. A compromised action or dependency in the hot path can then no longer push commits, move tags or forge releases. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e118b6..81b677a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ on: branches: [master] permissions: - contents: write + contents: read jobs: test: @@ -62,6 +62,8 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') needs: build runs-on: ubuntu-latest + permissions: + contents: write steps: - uses: actions/download-artifact@v8 with: From beba104a1b8164aad8991963ee866b7d81b48233 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 12/14] Pin release action to a commit SHA A version tag is a mutable pointer: whoever controls, or compromises, softprops/action-gh-release can repoint v3, and every workflow using it executes the new code on its next run. This is exactly how the tj-actions/changed-files compromise spread (CVE-2025-30066). The action is third-party, runs in the only job holding contents: write, and uploads the release binaries users download directly, so a hijacked version could replace them. Pin to the commit v3.0.2 resolves to; the trailing comment keeps the version readable and lets Dependabot propose bumps. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81b677a..f0a0b3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: with: path: dist merge-multiple: true - - uses: softprops/action-gh-release@v3 + - uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: files: dist/* generate_release_notes: true From 7763eb271a3b38b362fd7b501cd5707c19398462 Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:16 +0200 Subject: [PATCH 13/14] Run tests with the race detector, matching CI CI runs go test -race ./... while make test ran a bare go test, so data races surfaced only in CI. Align the Makefile with CI. Co-Authored-By: Claude Fable 5 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index eb30071..fa46853 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ $(TARGETS): go.mod make $(platform) test: deps - $(GO) test + $(GO) test -race ./... fmt: $(GO) fmt From 2b3ea92cc8752acaea34371834578c2655c4a5cd Mon Sep 17 00:00:00 2001 From: Erik Booij Date: Mon, 10 Aug 2026 13:05:17 +0200 Subject: [PATCH 14/14] Remove Docker artifacts The image publishing workflow is already gone and nothing builds or distributes this image any more; binaries ship through GitHub Releases. Drop the Dockerfile and the README's local image build instructions accordingly. Co-Authored-By: Claude Fable 5 --- Dockerfile | 23 ----------------------- README.md | 6 ------ 2 files changed, 29 deletions(-) delete mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index f5391f0..0000000 --- a/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -ARG GO_VERSION=1.26 - -FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS builder - -ARG TARGETOS -ARG TARGETARCH -ARG VERSION=dev - -WORKDIR /src - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . - -RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ - go build -trimpath -ldflags "-w -s -X main.VersionString=${VERSION}" \ - -o /out/env-aws-params . - -FROM alpine:latest -RUN apk add --no-cache ca-certificates -COPY --from=builder /out/env-aws-params /usr/local/bin/env-aws-params -ENTRYPOINT ["/usr/local/bin/env-aws-params"] diff --git a/README.md b/README.md index 46317a5..341194a 100644 --- a/README.md +++ b/README.md @@ -109,9 +109,3 @@ This project uses [Go modules](https://go.dev/blog/using-go-modules) and require go mod download go build ``` - -Or build the Docker image locally: - -```bash -docker build -t env-aws-params . -```