2026-10-01 23:15:57 +02:00
|
|
|
SHELL := /bin/sh
|
|
|
|
|
|
|
|
|
|
GO_LOOSE_ADDR ?= :8081
|
2026-10-04 16:57:30 +02:00
|
|
|
GO_LOOSE_PORT ?= 8081
|
2026-10-01 23:15:57 +02:00
|
|
|
GO_LOOSE_BASE_URL ?= http://localhost:$(GO_LOOSE_PORT)
|
|
|
|
|
GO_LOOSE_DATABASE_URL ?= postgres://goloose:goloose@localhost:5433/goloose?sslmode=disable
|
|
|
|
|
GO_LOOSE_SESSION_SECRET ?= local-development-secret-change-me-now
|
|
|
|
|
GO_LOOSE_DEV_LOGIN ?= true
|
|
|
|
|
GO_LOOSE_DEV_USER ?= admin@local.test
|
|
|
|
|
GO_LOOSE_BOOTSTRAP_TENANT ?= nmbs
|
|
|
|
|
GO_LOOSE_BOOTSTRAP_APP ?= guess
|
|
|
|
|
GO_LOOSE_ALLOW_PRIVATE_CONTRACT_URLS ?= true
|
feat: account menu, database roles, and single logout
Bundles the console work from the current branch: the header account
control, database-backed roles and permissions, and signing out across
the applications that share this sign-in.
The account control replaces a separate identity chip and a separate
sign-out button, which meant the header carried two controls describing
one fact. web/account.js is mounted into every page by a placeholder and
owns the keyboard handling, the outside-click behaviour and the sign-out
form once. It also fills the trigger's name, which the previous markup
left empty.
Signing out revokes the hosted-login bearer sessions this installation
issued, then redirects to the provider's end_session_endpoint when the
discovery document advertises one. Applications that authenticate
against this installation therefore lose their session too; one pointed
straight at an identity provider is out of its reach and is unchanged.
Roles and permissions become rows rather than a closed enum, so a tenant
can extend the catalog without a migration, and a role can no longer be
granted a capability that is not in it. requireSameOrigin now compares
against the origin the request arrived on instead of the configured base
URL, which defaulted to http://localhost:8080 and so rejected every
write in a deployment that never set it.
Two bugs found while verifying in a browser:
- A profile picture never rendered. avatarURL built an absolute URL
from the configured base URL, and the page's own img-src 'self'
blocked it. The console's own pages now take a root-relative path;
only /connect/userinfo, read from another origin, needs an absolute
one, and it follows the request.
- absoluteURL preferred the configuration over the request while its
comment claimed the opposite, which also misdirected the logout
redirect.
Card layout: the footer was one two-column row shared between a label
and a forty-character identifier, so the identifier took the width and
crushed its label into three stacked words. Each pair is a line now, the
value truncates with the full text in the title, and cards align their
footers across a row.
2026-10-05 19:18:07 +02:00
|
|
|
GO_LOOSE_DEV_PORT ?= 8080
|
2026-10-01 23:15:57 +02:00
|
|
|
|
|
|
|
|
export
|
|
|
|
|
|
feat: account menu, database roles, and single logout
Bundles the console work from the current branch: the header account
control, database-backed roles and permissions, and signing out across
the applications that share this sign-in.
The account control replaces a separate identity chip and a separate
sign-out button, which meant the header carried two controls describing
one fact. web/account.js is mounted into every page by a placeholder and
owns the keyboard handling, the outside-click behaviour and the sign-out
form once. It also fills the trigger's name, which the previous markup
left empty.
Signing out revokes the hosted-login bearer sessions this installation
issued, then redirects to the provider's end_session_endpoint when the
discovery document advertises one. Applications that authenticate
against this installation therefore lose their session too; one pointed
straight at an identity provider is out of its reach and is unchanged.
Roles and permissions become rows rather than a closed enum, so a tenant
can extend the catalog without a migration, and a role can no longer be
granted a capability that is not in it. requireSameOrigin now compares
against the origin the request arrived on instead of the configured base
URL, which defaulted to http://localhost:8080 and so rejected every
write in a deployment that never set it.
Two bugs found while verifying in a browser:
- A profile picture never rendered. avatarURL built an absolute URL
from the configured base URL, and the page's own img-src 'self'
blocked it. The console's own pages now take a root-relative path;
only /connect/userinfo, read from another origin, needs an absolute
one, and it follows the request.
- absoluteURL preferred the configuration over the request while its
comment claimed the opposite, which also misdirected the logout
redirect.
Card layout: the footer was one two-column row shared between a label
and a forty-character identifier, so the identifier took the width and
crushed its label into three stacked words. Each pair is a line now, the
value truncates with the full text in the title, and cards align their
footers across a row.
2026-10-05 19:18:07 +02:00
|
|
|
.PHONY: build test integration-db integration-test run compose-up compose-down compose-dev-up compose-dev-down compose-dev-logs fmt vet
|
2026-10-01 23:15:57 +02:00
|
|
|
|
|
|
|
|
build:
|
|
|
|
|
go build ./...
|
|
|
|
|
|
|
|
|
|
test:
|
|
|
|
|
go test -race ./...
|
|
|
|
|
|
feat: account menu, database roles, and single logout
Bundles the console work from the current branch: the header account
control, database-backed roles and permissions, and signing out across
the applications that share this sign-in.
The account control replaces a separate identity chip and a separate
sign-out button, which meant the header carried two controls describing
one fact. web/account.js is mounted into every page by a placeholder and
owns the keyboard handling, the outside-click behaviour and the sign-out
form once. It also fills the trigger's name, which the previous markup
left empty.
Signing out revokes the hosted-login bearer sessions this installation
issued, then redirects to the provider's end_session_endpoint when the
discovery document advertises one. Applications that authenticate
against this installation therefore lose their session too; one pointed
straight at an identity provider is out of its reach and is unchanged.
Roles and permissions become rows rather than a closed enum, so a tenant
can extend the catalog without a migration, and a role can no longer be
granted a capability that is not in it. requireSameOrigin now compares
against the origin the request arrived on instead of the configured base
URL, which defaulted to http://localhost:8080 and so rejected every
write in a deployment that never set it.
Two bugs found while verifying in a browser:
- A profile picture never rendered. avatarURL built an absolute URL
from the configured base URL, and the page's own img-src 'self'
blocked it. The console's own pages now take a root-relative path;
only /connect/userinfo, read from another origin, needs an absolute
one, and it follows the request.
- absoluteURL preferred the configuration over the request while its
comment claimed the opposite, which also misdirected the logout
redirect.
Card layout: the footer was one two-column row shared between a label
and a forty-character identifier, so the identifier took the width and
crushed its label into three stacked words. Each pair is a line now, the
value truncates with the full text in the title, and cards align their
footers across a row.
2026-10-05 19:18:07 +02:00
|
|
|
# Integration tests drop every table they touch, so they only run against scratch
|
|
|
|
|
# databases. Both test helpers refuse any database whose name lacks "test", and
|
|
|
|
|
# `make integration-db` creates the two they expect. Override the check with
|
|
|
|
|
# GO_LOOSE_TEST_DATABASE_DESTRUCTIVE=1 only when you mean it.
|
|
|
|
|
#
|
|
|
|
|
# The store-backed tests in internal/server need a database of their own: Go runs
|
|
|
|
|
# package tests in parallel and both packages drop every table, so sharing one
|
|
|
|
|
# database makes them fight over the schema.
|
|
|
|
|
GO_LOOSE_TEST_DATABASE_URL ?= postgres://goloose:goloose@localhost:5433/goloose_test?sslmode=disable
|
|
|
|
|
GO_LOOSE_TEST_SERVER_DATABASE_URL ?= postgres://goloose:goloose@localhost:5433/goloose_server_test?sslmode=disable
|
|
|
|
|
|
|
|
|
|
# createdb is not idempotent, so ignore a database that is already there.
|
|
|
|
|
integration-db:
|
|
|
|
|
-docker compose exec -T postgres createdb -U goloose goloose_test
|
|
|
|
|
-docker compose exec -T postgres createdb -U goloose goloose_server_test
|
|
|
|
|
|
2026-10-04 12:24:13 +02:00
|
|
|
integration-test:
|
|
|
|
|
@test -n "$(GO_LOOSE_TEST_DATABASE_URL)" || { echo "set GO_LOOSE_TEST_DATABASE_URL to a scratch database"; exit 1; }
|
feat: account menu, database roles, and single logout
Bundles the console work from the current branch: the header account
control, database-backed roles and permissions, and signing out across
the applications that share this sign-in.
The account control replaces a separate identity chip and a separate
sign-out button, which meant the header carried two controls describing
one fact. web/account.js is mounted into every page by a placeholder and
owns the keyboard handling, the outside-click behaviour and the sign-out
form once. It also fills the trigger's name, which the previous markup
left empty.
Signing out revokes the hosted-login bearer sessions this installation
issued, then redirects to the provider's end_session_endpoint when the
discovery document advertises one. Applications that authenticate
against this installation therefore lose their session too; one pointed
straight at an identity provider is out of its reach and is unchanged.
Roles and permissions become rows rather than a closed enum, so a tenant
can extend the catalog without a migration, and a role can no longer be
granted a capability that is not in it. requireSameOrigin now compares
against the origin the request arrived on instead of the configured base
URL, which defaulted to http://localhost:8080 and so rejected every
write in a deployment that never set it.
Two bugs found while verifying in a browser:
- A profile picture never rendered. avatarURL built an absolute URL
from the configured base URL, and the page's own img-src 'self'
blocked it. The console's own pages now take a root-relative path;
only /connect/userinfo, read from another origin, needs an absolute
one, and it follows the request.
- absoluteURL preferred the configuration over the request while its
comment claimed the opposite, which also misdirected the logout
redirect.
Card layout: the footer was one two-column row shared between a label
and a forty-character identifier, so the identifier took the width and
crushed its label into three stacked words. Each pair is a line now, the
value truncates with the full text in the title, and cards align their
footers across a row.
2026-10-05 19:18:07 +02:00
|
|
|
go test -race ./internal/store/ ./internal/server/ -count=1
|
2026-10-04 12:24:13 +02:00
|
|
|
|
2026-10-01 23:15:57 +02:00
|
|
|
run:
|
|
|
|
|
go run ./cmd/go-loose
|
|
|
|
|
|
2026-10-04 16:57:30 +02:00
|
|
|
# The variables above are exported for `make run`, but compose reads
|
|
|
|
|
# GO_LOOSE_BASE_URL too and would inherit the local http://localhost:8081 value,
|
|
|
|
|
# which then overrides the https:// defaults in docker-compose.yaml. Clearing it
|
|
|
|
|
# for the compose targets lets compose apply its own defaults.
|
2026-10-01 23:15:57 +02:00
|
|
|
compose-up:
|
2026-10-04 16:57:30 +02:00
|
|
|
GO_LOOSE_BASE_URL= docker compose up --build
|
2026-10-01 23:15:57 +02:00
|
|
|
|
|
|
|
|
compose-down:
|
|
|
|
|
docker compose down
|
|
|
|
|
|
feat: account menu, database roles, and single logout
Bundles the console work from the current branch: the header account
control, database-backed roles and permissions, and signing out across
the applications that share this sign-in.
The account control replaces a separate identity chip and a separate
sign-out button, which meant the header carried two controls describing
one fact. web/account.js is mounted into every page by a placeholder and
owns the keyboard handling, the outside-click behaviour and the sign-out
form once. It also fills the trigger's name, which the previous markup
left empty.
Signing out revokes the hosted-login bearer sessions this installation
issued, then redirects to the provider's end_session_endpoint when the
discovery document advertises one. Applications that authenticate
against this installation therefore lose their session too; one pointed
straight at an identity provider is out of its reach and is unchanged.
Roles and permissions become rows rather than a closed enum, so a tenant
can extend the catalog without a migration, and a role can no longer be
granted a capability that is not in it. requireSameOrigin now compares
against the origin the request arrived on instead of the configured base
URL, which defaulted to http://localhost:8080 and so rejected every
write in a deployment that never set it.
Two bugs found while verifying in a browser:
- A profile picture never rendered. avatarURL built an absolute URL
from the configured base URL, and the page's own img-src 'self'
blocked it. The console's own pages now take a root-relative path;
only /connect/userinfo, read from another origin, needs an absolute
one, and it follows the request.
- absoluteURL preferred the configuration over the request while its
comment claimed the opposite, which also misdirected the logout
redirect.
Card layout: the footer was one two-column row shared between a label
and a forty-character identifier, so the identifier took the width and
crushed its label into three stacked words. Each pair is a line now, the
value truncates with the full text in the title, and cards align their
footers across a row.
2026-10-05 19:18:07 +02:00
|
|
|
# Air rebuilds into ./dist on every change.
|
|
|
|
|
compose-dev-up:
|
|
|
|
|
mkdir -p dist
|
|
|
|
|
docker compose -f docker-compose.dev.yaml up --build
|
|
|
|
|
|
|
|
|
|
compose-dev-down:
|
|
|
|
|
docker compose -f docker-compose.dev.yaml down --remove-orphans
|
|
|
|
|
# Air writes dist/go-loose as root inside the container, so the host user
|
|
|
|
|
# cannot delete it directly. Empty the directory through a container instead.
|
|
|
|
|
-docker run --rm -v "$(CURDIR)/dist:/dist" alpine sh -c 'rm -rf /dist/*' 2>/dev/null || true
|
|
|
|
|
|
|
|
|
|
compose-dev-logs:
|
|
|
|
|
docker compose -f docker-compose.dev.yaml logs -f go-loose
|
|
|
|
|
|
2026-10-01 23:15:57 +02:00
|
|
|
fmt:
|
feat: account menu, database roles, and single logout
Bundles the console work from the current branch: the header account
control, database-backed roles and permissions, and signing out across
the applications that share this sign-in.
The account control replaces a separate identity chip and a separate
sign-out button, which meant the header carried two controls describing
one fact. web/account.js is mounted into every page by a placeholder and
owns the keyboard handling, the outside-click behaviour and the sign-out
form once. It also fills the trigger's name, which the previous markup
left empty.
Signing out revokes the hosted-login bearer sessions this installation
issued, then redirects to the provider's end_session_endpoint when the
discovery document advertises one. Applications that authenticate
against this installation therefore lose their session too; one pointed
straight at an identity provider is out of its reach and is unchanged.
Roles and permissions become rows rather than a closed enum, so a tenant
can extend the catalog without a migration, and a role can no longer be
granted a capability that is not in it. requireSameOrigin now compares
against the origin the request arrived on instead of the configured base
URL, which defaulted to http://localhost:8080 and so rejected every
write in a deployment that never set it.
Two bugs found while verifying in a browser:
- A profile picture never rendered. avatarURL built an absolute URL
from the configured base URL, and the page's own img-src 'self'
blocked it. The console's own pages now take a root-relative path;
only /connect/userinfo, read from another origin, needs an absolute
one, and it follows the request.
- absoluteURL preferred the configuration over the request while its
comment claimed the opposite, which also misdirected the logout
redirect.
Card layout: the footer was one two-column row shared between a label
and a forty-character identifier, so the identifier took the width and
crushed its label into three stacked words. Each pair is a line now, the
value truncates with the full text in the title, and cards align their
footers across a row.
2026-10-05 19:18:07 +02:00
|
|
|
# Prune directories that are not source and may be unreadable: vendored
|
|
|
|
|
# code, build output, the PostgreSQL volume, and anything hidden or
|
|
|
|
|
# underscore prefixed, which is how Go itself skips package trees.
|
|
|
|
|
gofmt -w $$(find . -mindepth 1 -type d \( -name vendor -o -name dist -o -name '.*' -o -name '_*' \) -prune -o -name '*.go' -print)
|
2026-10-01 23:15:57 +02:00
|
|
|
|
|
|
|
|
vet:
|
|
|
|
|
go vet ./...
|