fix(#797): fail-closed Go test + workflow preflight for handlers-postgres-integration #2174

Merged
claude-ceo-assistant merged 2 commits from fix/2166-blocker2-integration-fail-open into main 2026-06-04 05:30:18 +00:00
5 changed files with 56 additions and 15 deletions
@@ -253,6 +253,19 @@ jobs:
echo "✓ $tbl table present"
done
- if: needs.detect-changes.outputs.handlers == 'true'
name: Preflight — INTEGRATION_DB_URL must be present
run: |
# Belt-and-suspenders: if the postgres-start step failed to
# export INTEGRATION_DB_URL, fail loud BEFORE go test can
# t.Skip its way to a green build. Closes the workflow-level
# fail-open gap identified in PR #2166 blocker #2.
if [ -z "${INTEGRATION_DB_URL:-}" ]; then
echo "::error::INTEGRATION_DB_URL is empty — postgres-start step did not export the connection string"
exit 1
fi
echo "INTEGRATION_DB_URL is set"
- if: needs.detect-changes.outputs.handlers == 'true'
name: Run integration tests
run: |
@@ -36,7 +36,6 @@ package handlers
import (
"context"
"database/sql"
"os"
"strings"
"testing"
"time"
@@ -57,10 +56,7 @@ import (
// directly rather than going through the package global.
func integrationDB(t *testing.T) *sql.DB {
t.Helper()
url := os.Getenv("INTEGRATION_DB_URL")
if url == "" {
t.Skip("INTEGRATION_DB_URL not set; skipping (local devs: see file header)")
}
url := requireIntegrationDBURL(t)
conn, err := sql.Open("postgres", url)
if err != nil {
t.Fatalf("open: %v", err)
@@ -0,0 +1,40 @@
//go:build integration
// +build integration
// integration_helper_test.go — shared preflight for handler Postgres
// integration tests. Extracted so the fail-open/skip logic is in ONE place
// and can be tightened without editing every integration test file.
//
// See delegation_ledger_integration_test.go for the docker-postgres setup
// incantation used by local devs.
package handlers
import (
"os"
"testing"
)
// requireIntegrationDBURL returns $INTEGRATION_DB_URL.
//
// In CI (CI, GITHUB_ACTIONS, or GITEA_ACTIONS env var is non-empty), an
// empty URL is a fatal error — it means the workflow failed to export the
// variable (postgres container did not start, bridge IP resolution failed,
// or a regression in the workflow YAML). t.Fatalf keeps the test red so the
// failure is visible; t.Skip would silently pass and mask the defect.
//
// Locally (none of the three CI markers set), an empty URL skips the test
// so devs can run `go test ./...` without booting a Postgres container.
func requireIntegrationDBURL(t *testing.T) string {
t.Helper()
url := os.Getenv("INTEGRATION_DB_URL")
if url == "" {
if os.Getenv("CI") != "" ||
os.Getenv("GITHUB_ACTIONS") != "" ||
os.Getenv("GITEA_ACTIONS") != "" {
t.Fatalf("INTEGRATION_DB_URL required in CI handler integration tests — check workflow env export")
}
t.Skip("INTEGRATION_DB_URL not set; skipping (local devs: see file header)")
}
return url
}
@@ -43,7 +43,6 @@ package handlers
import (
"context"
"database/sql"
"os"
"strings"
"testing"
"time"
@@ -63,10 +62,7 @@ import (
// but kept separate so each table's wipe step is local to its tests.
func integrationDB_PendingUploads(t *testing.T) *sql.DB {
t.Helper()
url := os.Getenv("INTEGRATION_DB_URL")
if url == "" {
t.Skip("INTEGRATION_DB_URL not set; skipping (local devs: see file header)")
}
url := requireIntegrationDBURL(t)
conn, err := sql.Open("postgres", url)
if err != nil {
t.Fatalf("open: %v", err)
@@ -41,7 +41,6 @@ import (
"context"
"database/sql"
"fmt"
"os"
"testing"
"github.com/google/uuid"
@@ -59,10 +58,7 @@ import (
// only those.
func integrationDB_WorkspaceCreateName(t *testing.T) *sql.DB {
t.Helper()
url := os.Getenv("INTEGRATION_DB_URL")
if url == "" {
t.Skip("INTEGRATION_DB_URL not set; skipping (see file header)")
}
url := requireIntegrationDBURL(t)
conn, err := sql.Open("postgres", url)
if err != nil {
t.Fatalf("open: %v", err)