Let a plain docker build pass and stamp the git version (closes #57)
check / check (push) Waiting to run
check / check (push) Waiting to run
The size tests skip a case whose secret needs more locked memory than RLIMIT_MEMLOCK allows: memguard panics otherwise, and a plain `docker build .` runs under an 8 MiB limit. script/cibuild still runs every case. The build stage stamps the VERSION build argument, else `git describe --tags --always`, and fails when .git is present but yields no version. `make build` stamps `git describe` too instead of the fixed 0.1.0. .dockerignore keeps .git/config out; script/docker is now the canonical copy. Model: opus-5-5
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
# .git is sent without its config. Without a VERSION build argument the
|
||||
# stage that compiles runs `git describe --tags --always` on .git, which
|
||||
# does not need .git/config; that file can hold a credential, such as a
|
||||
# password in a remote URL or the token the CI checkout step stores there.
|
||||
.git/config
|
||||
|
||||
# Build artifacts
|
||||
secret
|
||||
coverage.out
|
||||
|
||||
+14
-1
@@ -27,7 +27,20 @@ RUN go mod download
|
||||
COPY . .
|
||||
|
||||
RUN make test
|
||||
RUN make build
|
||||
|
||||
# The version stamped into the binary: the VERSION build argument when one
|
||||
# is given, otherwise `git describe --tags --always` of the .git the build
|
||||
# context carries: the tag on a tagged commit, tag-N-gHASH on a commit after
|
||||
# one, the short commit when no tag is reachable. A context that carries .git
|
||||
# and still yields no version fails the build.
|
||||
ARG VERSION
|
||||
RUN version="${VERSION:-$(git describe --tags --always)}"; \
|
||||
if [ -e .git ] && { [ -z "$version" ] || [ "$version" = dev ] || \
|
||||
[ "$version" = unknown ]; }; then \
|
||||
echo "no version could be derived although the build context carries .git" >&2; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
make build VERSION="${version:-dev}"
|
||||
|
||||
# Runtime stage
|
||||
# alpine 3.23 (2026-03-10)
|
||||
|
||||
@@ -2,7 +2,7 @@ export CGO_ENABLED=1
|
||||
export DOCKER_HOST := ssh://root@ber1app1.local
|
||||
|
||||
# Version information
|
||||
VERSION := 0.1.0
|
||||
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
||||
GIT_COMMIT := $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
|
||||
LDFLAGS := -X 'git.eeqj.de/sneak/secret/internal/cli.Version=$(VERSION)' \
|
||||
-X 'git.eeqj.de/sneak/secret/internal/cli.GitCommit=$(GIT_COMMIT)'
|
||||
|
||||
@@ -25,6 +25,14 @@ Bring the repo into policy compliance in one commit:
|
||||
|
||||
# Completed Steps
|
||||
|
||||
- 2026-10-02: A plain `docker build .` builds again: the size tests
|
||||
skip a case that needs more locked memory than the limit allows,
|
||||
and run every case under `script/cibuild`. The image stamps the
|
||||
`VERSION` build argument, else `git describe --tags --always`, into
|
||||
`Version`, and fails if `.git` is present but yields no version;
|
||||
`make build` stamps `git describe` too, not a fixed `0.1.0`.
|
||||
`.dockerignore` keeps `.git/config` out; `script/docker` is the
|
||||
canonical copy.
|
||||
- 2026-08-07: Updated golangci-lint to v2.12.2 with the canonical
|
||||
`.golangci.yml` (all linters enabled minus the standard disable
|
||||
list, `lll` 88, tests linted); bumped the `Dockerfile` lint-stage
|
||||
|
||||
@@ -16,6 +16,7 @@ require (
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/tyler-smith/go-bip39 v1.1.0
|
||||
golang.org/x/crypto v0.38.0
|
||||
golang.org/x/sys v0.33.0
|
||||
golang.org/x/term v0.32.0
|
||||
)
|
||||
|
||||
@@ -31,7 +32,6 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -17,11 +17,38 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// testVaultName is the vault name used by the size tests.
|
||||
const testVaultName = "test-vault"
|
||||
|
||||
// lockedBytesPerSecretByte bounds the locked memory that storing a secret
|
||||
// holds at once: the buffers it is read into reach up to 1.5 times its
|
||||
// size, and they are then copied into one more buffer of its size.
|
||||
const lockedBytesPerSecretByte = 3
|
||||
|
||||
// skipIfLockedMemoryTooLow skips the test when the locked-memory limit
|
||||
// (RLIMIT_MEMLOCK) cannot hold a secret of size bytes. memguard panics,
|
||||
// ending the whole test run, when it cannot lock a buffer, and a plain
|
||||
// `docker build .` runs the tests under an 8 MiB limit.
|
||||
func skipIfLockedMemoryTooLow(t *testing.T, size int) {
|
||||
t.Helper()
|
||||
|
||||
var limit unix.Rlimit
|
||||
|
||||
err := unix.Getrlimit(unix.RLIMIT_MEMLOCK, &limit)
|
||||
require.NoError(t, err)
|
||||
|
||||
//nolint:gosec // test sizes are never negative
|
||||
need := lockedBytesPerSecretByte * uint64(size)
|
||||
if limit.Cur < need {
|
||||
t.Skipf("a %d-byte secret needs up to %d bytes of locked memory, "+
|
||||
"more than the locked-memory limit (RLIMIT_MEMLOCK) of %d bytes",
|
||||
size, need, limit.Cur)
|
||||
}
|
||||
}
|
||||
|
||||
// newSizeTestVault creates an in-memory vault unlocked with the test
|
||||
// mnemonic and returns the filesystem and vault.
|
||||
//
|
||||
@@ -59,6 +86,7 @@ func newSizeTestVault(t *testing.T) (afero.Fs, *vault.Vault) {
|
||||
// verifies the outcome.
|
||||
func runAddSecretSizeCase(t *testing.T, size int, wantErr bool, errMsg string) {
|
||||
t.Helper()
|
||||
skipIfLockedMemoryTooLow(t, size)
|
||||
|
||||
fs, vlt := newSizeTestVault(t)
|
||||
|
||||
@@ -110,6 +138,7 @@ func runAddSecretSizeCase(t *testing.T, size int, wantErr bool, errMsg string) {
|
||||
// verifies the outcome.
|
||||
func runImportSecretSizeCase(t *testing.T, size int, wantErr bool, errMsg string) {
|
||||
t.Helper()
|
||||
skipIfLockedMemoryTooLow(t, size)
|
||||
|
||||
fs, vlt := newSizeTestVault(t)
|
||||
|
||||
@@ -300,6 +329,8 @@ func TestAddSecretBufferGrowth(t *testing.T) {
|
||||
|
||||
for _, size := range sizes {
|
||||
t.Run(fmt.Sprintf("size_%d", size), func(t *testing.T) {
|
||||
skipIfLockedMemoryTooLow(t, size)
|
||||
|
||||
fs, vlt := newSizeTestVault(t)
|
||||
|
||||
// Create test data of exactly the specified size
|
||||
|
||||
+3
-2
@@ -1,8 +1,9 @@
|
||||
#!/bin/sh
|
||||
# script/cibuild: run the CI build. The Dockerfile runs script/check
|
||||
# (via make check), so a successful build implies all checks pass.
|
||||
# The Gitea workflow runs this on push. The memlock ulimit is required
|
||||
# because the test suite uses memguard, which mlocks memory.
|
||||
# The Gitea workflow runs this on push. The memlock ulimit lets the tests
|
||||
# that lock large secrets in memory (memguard mlocks them) run; under the
|
||||
# lower limit of a plain `docker build .` they are skipped.
|
||||
set -eu
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
|
||||
+11
-2
@@ -1,7 +1,8 @@
|
||||
#!/bin/sh
|
||||
# script/docker: build the Docker image tagged with the project name.
|
||||
# Identical in all repos; the tag comes from script/projectname.
|
||||
# Generic: needs no adaptation.
|
||||
# --no-cache because the gate phases the final stage depends on are RUN
|
||||
# steps, and a cached one is a check that did not run.
|
||||
set -eu
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
||||
@@ -9,7 +10,15 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
|
||||
|
||||
main() {
|
||||
cd "$ROOT"
|
||||
docker build -t "$("$SCRIPT_DIR/projectname")" .
|
||||
# Own line: a failing command substitution inside an argument does
|
||||
# not trip `set -e`, so the inline form degrades silently to an
|
||||
# empty constant. The VERSION build argument takes precedence over
|
||||
# the version a build stage derives from the .git in the context.
|
||||
version="$(git describe --tags --always --dirty 2>/dev/null || true)"
|
||||
[ -n "$version" ] || version="unknown"
|
||||
docker build --no-cache \
|
||||
--build-arg VERSION="$version" \
|
||||
-t "$("$SCRIPT_DIR/projectname")" .
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user