diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a87b28a..e09c65c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,16 +14,28 @@ jobs: with: { path: lattice } - name: checkout lattice-sdk uses: actions/checkout@v6 - with: { repository: LatticeNet/lattice-sdk, path: lattice-sdk } + with: + repository: LatticeNet/lattice-sdk + path: lattice-sdk + ref: 4a318f246d23875cdd6448d96a62bd87bd67215c - name: checkout lattice-server uses: actions/checkout@v6 - with: { repository: LatticeNet/lattice-server, path: lattice-server } + with: + repository: LatticeNet/lattice-server + path: lattice-server + ref: ef13509e74b7564d2c4a9847f11f6b86e3bd6cfd - name: checkout lattice-node-agent uses: actions/checkout@v6 - with: { repository: LatticeNet/lattice-node-agent, path: lattice-node-agent } + with: + repository: LatticeNet/lattice-node-agent + path: lattice-node-agent + ref: 03f730acb9653cc1a99c62c95510cafd58a4afad - name: checkout lattice-plugin-template uses: actions/checkout@v6 - with: { repository: LatticeNet/lattice-plugin-template, path: lattice-plugin-template } + with: + repository: LatticeNet/lattice-plugin-template + path: lattice-plugin-template + ref: 793b476f346d1a8584d34c89e6d8da3f4b115d3e - uses: actions/setup-go@v6 with: go-version: '1.26.x' @@ -45,7 +57,13 @@ jobs: - name: make build working-directory: lattice run: make build + - name: clean-tree gate regression + working-directory: lattice + run: make test-check-clean - name: gosec run: | go install github.com/securego/gosec/v2/cmd/gosec@latest gosec ./lattice-server/... ./lattice-node-agent/... + - name: workspace stays clean + working-directory: lattice + run: make check-clean diff --git a/Makefile b/Makefile index 3c8c9ba..d1fe495 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,10 @@ -.PHONY: test build run-server run-agent check-dashboard +.PHONY: test build check-clean test-check-clean run-server run-agent check-dashboard export GOCACHE := $(CURDIR)/.cache/go-build export GOWORK := $(CURDIR)/go.work +WORKSPACE_REPOS := . ../lattice-sdk ../lattice-server ../lattice-node-agent ../lattice-plugin-template + test: mkdir -p $(GOCACHE) cd ../lattice-sdk && go test ./... @@ -16,6 +18,24 @@ build: cd ../lattice-node-agent && go build -o ../lattice/bin/lattice-agent ./cmd/lattice-agent cd ../lattice-plugin-template/system-go && go build ./... +check-clean: + @dirty=0; \ + for repo in $(WORKSPACE_REPOS); do \ + if ! status="$$(git -C "$$repo" status --porcelain --untracked-files=all)"; then \ + printf 'workspace checkout cannot be inspected: %s\n' "$$repo" >&2; \ + dirty=1; \ + continue; \ + fi; \ + if [ -n "$$status" ]; then \ + printf 'workspace checkout is dirty: %s\n%s\n' "$$repo" "$$status" >&2; \ + dirty=1; \ + fi; \ + done; \ + test "$$dirty" -eq 0 + +test-check-clean: + @sh scripts/test-check-clean.sh + run-server: cd ../lattice-server && LATTICE_WEB_ROOT=../lattice-dashboard go run ./cmd/lattice-server diff --git a/README.md b/README.md index 4396c87..50bb835 100644 --- a/README.md +++ b/README.md @@ -170,3 +170,13 @@ Current published SDK baseline: latest `lattice-sdk` tag is `v0.2.17`; `v0.2.17`. The workspace `use` list includes the local SDK checkout, so cross-repo development exercises the current model sources without relying on a stale version-specific replace. + +Workspace CI pins each sibling checkout to an exact commit in +`.github/workflows/ci.yml`. Update those refs and `go.work.sum` together when +advancing the integration set, then run `make test`, `make build`, and +`make test-check-clean` followed by `make check-clean` in the five-repository +sibling layout. The regression covers clean, dirty, missing, and non-repository +checkouts both separately and in one aggregate scan. CI keeps the real +clean-tree gate as its final step, where it fails if any checkout cannot be +inspected or has changes: a successful Go command that rewrites a tracked sum +is not a reproducible green build. diff --git a/go.work.sum b/go.work.sum index a3c0f2e..041fe6e 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,2 +1,10 @@ -github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= -github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= diff --git a/scripts/test-check-clean.sh b/scripts/test-check-clean.sh new file mode 100644 index 0000000..298f54e --- /dev/null +++ b/scripts/test-check-clean.sh @@ -0,0 +1,72 @@ +#!/bin/sh +set -eu + +root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd) +tmp=$(mktemp -d "${TMPDIR:-/tmp}/lattice-check-clean.XXXXXX") + +cleanup() { + case "$tmp" in + "${TMPDIR:-/tmp}"/lattice-check-clean.*) rm -rf -- "$tmp" ;; + *) printf 'refusing to remove unexpected test path: %s\n' "$tmp" >&2 ;; + esac +} +trap cleanup EXIT HUP INT TERM + +clean="$tmp/clean" +dirty="$tmp/dirty" +not_repo="$tmp/not-repo" +missing="$tmp/missing" + +git init -q "$clean" +git init -q "$dirty" +mkdir -p "$not_repo" +printf 'dirty\n' >"$dirty/untracked.txt" + +expect_pass() { + name=$1 + repo=$2 + if ! output=$(make -s -C "$root" check-clean "WORKSPACE_REPOS=$repo" 2>&1); then + printf 'not ok - %s unexpectedly failed\n%s\n' "$name" "$output" >&2 + exit 1 + fi + printf 'ok - %s\n' "$name" +} + +expect_fail() { + name=$1 + repo=$2 + message=$3 + if output=$(make -s -C "$root" check-clean "WORKSPACE_REPOS=$repo" 2>&1); then + printf 'not ok - %s unexpectedly passed\n' "$name" >&2 + exit 1 + fi + case "$output" in + *"$message"*) ;; + *) printf 'not ok - %s failed without %s\n%s\n' "$name" "$message" "$output" >&2; exit 1 ;; + esac + printf 'ok - %s\n' "$name" +} + +expect_pass clean "$clean" +expect_fail dirty "$dirty" 'workspace checkout is dirty:' +expect_fail missing "$missing" 'workspace checkout cannot be inspected:' +expect_fail non-repository "$not_repo" 'workspace checkout cannot be inspected:' + +aggregate_repos="$clean $dirty $missing $not_repo" +if aggregate_output=$(make -s -C "$root" check-clean "WORKSPACE_REPOS=$aggregate_repos" 2>&1); then + printf 'not ok - aggregate failures unexpectedly passed\n' >&2 + exit 1 +fi +for expected in \ + "workspace checkout is dirty: $dirty" \ + "workspace checkout cannot be inspected: $missing" \ + "workspace checkout cannot be inspected: $not_repo" +do + case "$aggregate_output" in + *"$expected"*) ;; + *) printf 'not ok - aggregate output omitted %s\n%s\n' "$expected" "$aggregate_output" >&2; exit 1 ;; + esac +done +printf 'ok - aggregate reports every failure\n' + +printf 'check-clean regression: 5/5 passed\n'