Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ KIND ?= kind
HELM ?= helm
GORELEASER ?= goreleaser
WAILS ?= wails
WAILS_VERSION ?= v2.12.0
WAILS_VERSION ?= v2.13.0
CODESIGN ?= codesign
PLISTBUDDY ?= /usr/libexec/PlistBuddy
LIPO ?= lipo
Expand Down Expand Up @@ -44,8 +44,7 @@ build: ## Build the sith binary into bin/
go build -trimpath -ldflags '$(LDFLAGS)' -o $(BIN_DIR)/$(BINARY) $(CMD)

desktop-build: ## Build the ad-hoc-signed macOS arm64 Sith.app development bundle
@command -v "$(WAILS)" >/dev/null || { echo "Wails $(WAILS_VERSION) is required" >&2; exit 1; }
@"$(WAILS)" version | grep -q '$(WAILS_VERSION)' || { echo "Wails $(WAILS_VERSION) is required" >&2; exit 1; }
@hack/verify-wails-version.sh "$(WAILS)" "$(WAILS_VERSION)"
cd cmd/sith-desktop && "$(WAILS)" build -clean -m -nosyncgomod -s -trimpath -platform darwin/arm64
@set -euo pipefail; \
app='cmd/sith-desktop/build/bin/Sith.app'; \
Expand All @@ -60,6 +59,7 @@ test: ## Run unit tests with the race detector and report coverage
go test -race -count=1 -coverprofile=coverage.out ./...

test-scripts: ## Run focused safety tests for operator-facing shell harnesses
bash tests/scripts/wails_tooling_policy_test.sh
bash tests/scripts/helm_tooling_policy_test.sh
bash tests/scripts/m0_ocm_falsification_safety_test.sh
bash tests/scripts/release_tag_identity_guide_test.sh
Expand Down
36 changes: 36 additions & 0 deletions hack/verify-wails-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0

set -Eeuo pipefail

if [[ "$#" -ne 2 ]]; then
printf 'usage: %s <wails-command> <expected-version>\n' "$0" >&2
exit 2
fi

readonly WAILS_COMMAND="$1"
readonly EXPECTED_VERSION="$2"

if [[ ! "${EXPECTED_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
printf 'invalid expected Wails version: %s\n' "${EXPECTED_VERSION}" >&2
exit 2
fi

if ! wails_path="$(command -v "${WAILS_COMMAND}")"; then
printf 'Wails %s is required\n' "${EXPECTED_VERSION}" >&2
exit 1
fi
readonly wails_path

if ! version_output="$("${wails_path}" version)"; then
printf 'failed to execute Wails version check\n' >&2
exit 1
fi
readonly version_output

actual_version="${version_output%%$'\n'*}"
readonly actual_version
if [[ "${actual_version}" != "${EXPECTED_VERSION}" ]]; then
printf 'Wails %s is required; got: %s\n' "${EXPECTED_VERSION}" "${actual_version:-<empty>}" >&2
exit 1
fi
40 changes: 40 additions & 0 deletions sessions/2026-07-21-wails-version-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Wails desktop version policy — 2026-07-21

## [S] Scope

The desktop module was already upgraded to Wails v2.13.0, but `make desktop-build` still required
v2.12.0. Its substring check also accepted lookalike version strings. This slice aligns the tool
gate with `go.mod` and makes exact-version enforcement independently testable on every CI runner.

## [D] Decision

Treat the `github.com/wailsapp/wails/v2` requirement in `go.mod` as the authoritative compatibility
version. A fail-closed verifier resolves the configured executable, requires a strict `vX.Y.Z`
expected value, executes the version command successfully, and compares its first output line
exactly. Additional informational lines remain compatible; prerelease, vendor, whitespace, empty,
and failed-command variants are rejected.

## [V] Verification

- Rebased without conflict onto the exact post-merge `dev` commit
`9e135de08cab047386b0a948311e7443e2741404`, whose CI and CodeQL runs completed successfully.
- The policy test derives both pins and passed 12 assertions covering valid, lookalike,
missing-command, command-failure, and malformed-expectation cases; both scripts pass ShellCheck.
- The checksummed Wails v2.13.0 CLI passes the verifier. The corresponding upstream release is
stable and was published on 2026-07-06:
<https://github.com/wailsapp/wails/releases/tag/v2.13.0>.
- `go mod verify`, `govulncheck ./...`, and `make ci` pass, including the race detector and all
operator-facing policy tests.
- `make e2e-isolation` passes against PostgreSQL plus 100,000 tenant-boundary fuzz executions.
- `make release-check` passes two independently rebuilt archive/SBOM distributions, Homebrew
formula validation, and the dual-architecture OCI layout contract.
- `make desktop-build` produces a strictly code-sign-valid `com.ardurai.sith` bundle containing a
Mach-O arm64 executable.
- `make e2e-kind KIND=/Volumes/EXTENDED/MacData/tools/bin/kind` passes the fleet fan-out, immutable
OCI image, and Argo application projection contracts in 241.937 seconds.

## [C] Security, operations, and cost

Exact matching prevents an unintended prerelease or vendor binary from satisfying the local build
gate. The change adds no runtime dependency, service, permission, network path, storage, or recurring
cloud cost.
79 changes: 79 additions & 0 deletions tests/scripts/wails_tooling_policy_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0
# shellcheck disable=SC2016

set -Eeuo pipefail

REPO_ROOT="$(git rev-parse --show-toplevel)"
readonly REPO_ROOT
readonly EXPECTED_VERSION="v2.13.0"
readonly VERIFIER="${REPO_ROOT}/hack/verify-wails-version.sh"

PASS_COUNT=0

pass() {
PASS_COUNT=$((PASS_COUNT + 1))
printf '[wails-policy] PASS: %s\n' "$1"
}

assert_equal() {
local actual=$1
local expected=$2
local description=$3

if [[ "${actual}" != "${expected}" ]]; then
printf '[wails-policy] FAIL: %s = %q, want %q\n' \
"${description}" "${actual}" "${expected}" >&2
return 1
fi
pass "${description}"
}

expect_failure() {
local description=$1
shift
if "$@" >/dev/null 2>&1; then
printf '[wails-policy] FAIL: %s\n' "${description}" >&2
exit 1
fi
pass "${description}"
}

makefile_version="$(awk '$1 == "WAILS_VERSION" && $2 == "?=" { print $3 }' "${REPO_ROOT}/Makefile")"
module_version="$(awk '$1 == "github.com/wailsapp/wails/v2" { print $2 }' "${REPO_ROOT}/go.mod")"

assert_equal "${module_version}" "${EXPECTED_VERSION}" "Wails module is current"
assert_equal "${makefile_version}" "${module_version}" "desktop tool pin matches go.mod"

scratch="$(mktemp -d)"
readonly scratch
trap 'rm -rf "${scratch}"' EXIT

fake_wails="${scratch}/wails"
readonly fake_wails
printf '%s\n' \
'#!/usr/bin/env bash' \
'if [[ "${WAILS_FAKE_EXIT:-0}" != "0" ]]; then exit "${WAILS_FAKE_EXIT}"; fi' \
'printf "%b" "${WAILS_FAKE_OUTPUT:-}"' >"${fake_wails}"
chmod 0700 "${fake_wails}"

WAILS_FAKE_OUTPUT=$'v2.13.0\nadditional upstream text\n' \
"${VERIFIER}" "${fake_wails}" "${EXPECTED_VERSION}"
pass "exact version accepts additional lines after the version"

for lookalike in 'v2.13.0-rc.1' 'v2.13.00' 'v2.13.0+vendor' ' v2.13.0' ''; do
expect_failure "rejects lookalike version ${lookalike:-<empty>}" \
env WAILS_FAKE_OUTPUT="${lookalike}" "${VERIFIER}" "${fake_wails}" "${EXPECTED_VERSION}"
done

expect_failure "rejects a failed version command" \
env WAILS_FAKE_EXIT=1 "${VERIFIER}" "${fake_wails}" "${EXPECTED_VERSION}"
expect_failure "rejects a missing Wails command" \
"${VERIFIER}" "${scratch}/missing-wails" "${EXPECTED_VERSION}"
expect_failure "rejects a malformed expected version" \
"${VERIFIER}" "${fake_wails}" 'v2.13'

grep -Fq 'hack/verify-wails-version.sh "$(WAILS)" "$(WAILS_VERSION)"' "${REPO_ROOT}/Makefile"
pass "desktop build invokes the tested exact-version verifier"

printf '[wails-policy] %d assertions passed\n' "${PASS_COUNT}"