Compare commits

...

6 Commits

Author SHA1 Message Date
dependabot[bot] d74943f87f chore(deps): bump react-router from 7.15.1 to 8.1.0 in /frontend
Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.15.1 to 8.1.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@8.1.0/packages/react-router)

---
updated-dependencies:
- dependency-name: react-router
  dependency-version: 8.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-03 08:20:07 +00:00
Stavros 440a3a3ef5 chore: cleanup codegen (#965) 2026-07-02 23:35:34 +03:00
Stavros a3c4d6ac83 chore: move tailscale to experimental config (#964) 2026-07-02 23:17:03 +03:00
Stavros c8b31c54a0 chore: remove prettier from frontend 2026-07-02 22:23:52 +03:00
Stavros 04b93fa107 fix: remove shutdown from serve error path 2026-07-02 15:07:04 +03:00
Stavros a6c716c4e2 fix: ensure data paths are set correctly in docker, fixes #958 (#959) 2026-07-01 16:12:46 +03:00
23 changed files with 155 additions and 94 deletions
+17 -17
View File
@@ -220,6 +220,23 @@ TINYAUTH_LDAP_AUTHCERT=
TINYAUTH_LDAP_AUTHKEY=
# Cache duration for LDAP group membership in seconds.
TINYAUTH_LDAP_GROUPCACHETTL=900
# experimental config
# Enable Tailscale integration.
TINYAUTH_EXPERIMENTAL_TAILSCALE_ENABLED=false
# Tailscale state directory.
TINYAUTH_EXPERIMENTAL_TAILSCALE_DIR="./tailscale_state"
# Tailscale hostname.
TINYAUTH_EXPERIMENTAL_TAILSCALE_HOSTNAME=
# Tailscale auth key.
TINYAUTH_EXPERIMENTAL_TAILSCALE_AUTHKEY=
# Use ephemeral Tailscale node.
TINYAUTH_EXPERIMENTAL_TAILSCALE_EPHEMERAL=false
# Enable Tailscale Funnel.
TINYAUTH_EXPERIMENTAL_TAILSCALE_FUNNEL=false
# Listen on the Tailscale address instead of standard address.
TINYAUTH_EXPERIMENTAL_TAILSCALE_LISTEN=false
# Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment.
TINYAUTH_LABELPROVIDER="auto"
@@ -241,20 +258,3 @@ TINYAUTH_LOG_STREAMS_APP_LEVEL=
TINYAUTH_LOG_STREAMS_AUDIT_ENABLED=false
# Log level for this stream. Use global if empty.
TINYAUTH_LOG_STREAMS_AUDIT_LEVEL=
# tailscale config
# Enable Tailscale integration.
TINYAUTH_TAILSCALE_ENABLED=false
# Tailscale state directory.
TINYAUTH_TAILSCALE_DIR="./tailscale_state"
# Tailscale hostname.
TINYAUTH_TAILSCALE_HOSTNAME=
# Tailscale auth key.
TINYAUTH_TAILSCALE_AUTHKEY=
# Use ephemeral Tailscale node.
TINYAUTH_TAILSCALE_EPHEMERAL=false
# Enable Tailscale Funnel.
TINYAUTH_TAILSCALE_FUNNEL=false
# Listen on the Tailscale address instead of standard address.
TINYAUTH_TAILSCALE_LISTEN=false
+3 -3
View File
@@ -36,9 +36,9 @@ jobs:
- name: Check codegen is up to date
run: |
sqlc generate
go generate ./internal/repository/...
git diff --exit-code -- internal/repository/
git status --porcelain -- internal/repository/ | grep -q . && echo "untracked files in internal/repository/" && exit 1 || true
go generate ./...
git diff --exit-code
git status --porcelain | grep -q . && echo "untracked files code gen files" && exit 1 || true
- name: Install frontend dependencies
working-directory: ./frontend
+3
View File
@@ -51,3 +51,6 @@ config.certify.yml
# deepsec
/.deepsec
# jetbrains
/.idea/
+7 -5
View File
@@ -52,15 +52,17 @@ WORKDIR /tinyauth
COPY --from=builder /tinyauth/tinyauth ./
RUN mkdir -p /data
EXPOSE 3000
# Make the data directory with a non-root user
RUN addgroup tinyauth && adduser -DH tinyauth -G tinyauth
RUN mkdir -p /data/resources /data/oidc /data/tailscale
RUN chown -R tinyauth:tinyauth /data
VOLUME ["/data"]
ENV TINYAUTH_DATABASE_PATH=/data/tinyauth.db
ENV TINYAUTH_RESOURCES_PATH=/data/resources
# Tell tinyauth that it's running in a container and where to find the data directory
ENV RUNTIME_ENV=docker
ENV PATH=$PATH:/tinyauth
+8 -6
View File
@@ -40,13 +40,16 @@ COPY ./cmd ./cmd
COPY ./internal ./internal
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
RUN mkdir -p data
RUN CGO_ENABLED=0 go build -ldflags "${LDFLAGS} \
-X github.com/tinyauthapp/tinyauth/internal/model.Version=${VERSION} \
-X github.com/tinyauthapp/tinyauth/internal/model.CommitHash=${COMMIT_HASH} \
-X github.com/tinyauthapp/tinyauth/internal/model.BuildTimestamp=${BUILD_TIMESTAMP}" ./cmd/tinyauth
# Make the data directory with a non-root user
RUN addgroup tinyauth && adduser -DH tinyauth -G tinyauth
RUN mkdir -p /data/resources /data/oidc /data/tailscale
RUN chown -R tinyauth:tinyauth /data
# Runner
FROM gcr.io/distroless/static-debian12:latest AS runner
@@ -55,15 +58,14 @@ WORKDIR /tinyauth
COPY --from=builder /tinyauth/tinyauth ./
# Since it's distroless, we need to copy the data directory from the builder stage
COPY --from=builder /tinyauth/data /data
COPY --from=builder /data /data
EXPOSE 3000
VOLUME ["/data"]
ENV TINYAUTH_DATABASE_PATH=/data/tinyauth.db
ENV TINYAUTH_RESOURCES_PATH=/data/resources
# Tell tinyauth that it's running in a container and where to find the data directory
ENV RUNTIME_ENV=docker
ENV PATH=$PATH:/tinyauth
+11 -5
View File
@@ -16,6 +16,8 @@ PROD_COMPOSE := $(shell test -f "docker-compose.test.prod.yml" && echo "docker-c
.DEFAULT_GOAL := binary
.PHONY: deps clean-data clean-webui webui binary binary-linux-amd64 binary-linux-arm64 test vet test-race dev dev-infisical prod prod-infisical sql generate docker docker-distroless
# Deps
deps:
cd frontend && pnpm ci
@@ -58,12 +60,10 @@ binary-linux-arm64:
$(MAKE) binary
# Go test
.PHONY: test
test:
go test -v ./...
# Go vet
.PHONY: vet
vet:
go vet ./...
@@ -88,11 +88,17 @@ prod-infisical:
infisical run --env=dev -- docker compose -f $(PROD_COMPOSE) up --force-recreate --pull=always --remove-orphans
# SQL
.PHONY: sql
sql:
sqlc generate
# Go gen
generate:
go run ./gen
go generate ./internal/repository/...
go generate ./...
# Docker image
docker:
docker buildx build -t tinyauthapp/tinyauth:dev --build-arg=VERSION=$(TAG_NAME) --build-arg=COMMIT_HASH=$(COMMIT_HASH) --build-arg=BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) -f Dockerfile .
# Docker image distroless
docker-distroless:
docker buildx build -t tinyauthapp/tinyauth:dev-distroless --build-arg=VERSION=$(TAG_NAME) --build-arg=COMMIT_HASH=$(COMMIT_HASH) --build-arg=BUILD_TIMESTAMP=$(BUILD_TIMESTAMP) -f Dockerfile.distroless .
+26
View File
@@ -0,0 +1,26 @@
package main
import (
"encoding/json"
"fmt"
"github.com/tinyauthapp/paerser/cli"
"github.com/tinyauthapp/tinyauth/internal/model"
)
func configCmd(tconfig *model.Config, loaders []cli.ResourceLoader) *cli.Command {
return &cli.Command{
Name: "config",
Description: "Print the configuration of Tinyauth",
Configuration: tconfig,
Resources: loaders,
Run: func(_ []string) error {
jsonBytes, err := json.MarshalIndent(tconfig, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal configuration: %w", err)
}
fmt.Println(string(jsonBytes))
return nil
},
}
}
+8 -1
View File
@@ -13,7 +13,8 @@ import (
)
func main() {
tConfig := model.NewDefaultConfiguration()
env := model.DetectRuntimeEnv()
tConfig := model.NewDefaultConfiguration(env)
loaders := []cli.ResourceLoader{
&loaders.FileLoader{},
@@ -52,6 +53,12 @@ func main() {
log.Fatal().Err(err).Msg("Failed to add version command")
}
err = cmdTinyauth.AddCommand(configCmd(tConfig, loaders))
if err != nil {
log.Fatal().Err(err).Msg("Failed to add config command")
}
err = cmdUser.AddCommand(verifyUserCmd())
if err != nil {
+1 -2
View File
@@ -34,7 +34,7 @@
"react-hook-form": "^7.72.1",
"react-i18next": "^17.0.2",
"react-markdown": "^10.1.0",
"react-router": "^7.14.0",
"react-router": "^8.1.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tailwindcss": "^4.2.2",
@@ -51,7 +51,6 @@
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.5.0",
"prettier": "3.8.2",
"rollup-plugin-visualizer": "^7.0.1",
"tw-animate-css": "^1.4.0",
"typescript": "~6.0.2",
+12 -29
View File
@@ -75,8 +75,8 @@ importers:
specifier: ^10.1.0
version: 10.1.0(@types/react@19.2.14)(react@19.2.6)
react-router:
specifier: ^7.14.0
version: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
specifier: ^8.1.0
version: 8.1.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
sonner:
specifier: ^2.0.7
version: 2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
@@ -120,9 +120,6 @@ importers:
globals:
specifier: ^17.5.0
version: 17.6.0
prettier:
specifier: 3.8.2
version: 3.8.2
rollup-plugin-visualizer:
specifier: ^7.0.1
version: 7.0.1(rolldown@1.0.1)
@@ -1500,9 +1497,8 @@ packages:
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
cookie@1.1.1:
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
engines: {node: '>=18'}
cookie-es@3.1.1:
resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
@@ -2148,11 +2144,6 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
prettier@3.8.2:
resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==}
engines: {node: '>=14'}
hasBin: true
property-information@7.1.0:
resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==}
@@ -2230,12 +2221,12 @@ packages:
'@types/react':
optional: true
react-router@7.15.1:
resolution: {integrity: sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A==}
engines: {node: '>=20.0.0'}
react-router@8.1.0:
resolution: {integrity: sha512-Mdfi61uObuvWNN9OhChOC0HV6YWOIfKRzEWOvCHRSuQg8IM+Nv10edaM/2HE8ZixBpUTdQbruyWqC3sDkkh9vw==}
engines: {node: '>=22.22.0'}
peerDependencies:
react: '>=18'
react-dom: '>=18'
react: '>=19.2.7'
react-dom: '>=19.2.7'
peerDependenciesMeta:
react-dom:
optional: true
@@ -2294,9 +2285,6 @@ packages:
engines: {node: '>=10'}
hasBin: true
set-cookie-parser@2.7.2:
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -3924,7 +3912,7 @@ snapshots:
convert-source-map@2.0.0: {}
cookie@1.1.1: {}
cookie-es@3.1.1: {}
cross-spawn@7.0.6:
dependencies:
@@ -4658,8 +4646,6 @@ snapshots:
prelude-ls@1.2.1: {}
prettier@3.8.2: {}
property-information@7.1.0: {}
proxy-from-env@2.1.0: {}
@@ -4786,11 +4772,10 @@ snapshots:
optionalDependencies:
'@types/react': 19.2.14
react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
react-router@8.1.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
dependencies:
cookie: 1.1.1
cookie-es: 3.1.1
react: 19.2.6
set-cookie-parser: 2.7.2
optionalDependencies:
react-dom: 19.2.6(react@19.2.6)
@@ -4859,8 +4844,6 @@ snapshots:
semver@7.8.0: {}
set-cookie-parser@2.7.2: {}
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
+1 -2
View File
@@ -1,4 +1,3 @@
dangerouslyAllowAllBuilds: false
blockExoticSubdeps: true
minimumReleaseAge: 1440 # 1 day
trustPolicy: no-downgrade
minimumReleaseAge: 1440 # 1 day
View File
+1 -1
View File
@@ -20,7 +20,7 @@ type EnvEntry struct {
}
func generateExampleEnv() {
cfg := model.NewDefaultConfiguration()
cfg := model.NewDefaultConfiguration(model.RuntimeEnvUnknown)
entries := make([]EnvEntry, 0)
root := reflect.TypeOf(cfg).Elem()
+1 -1
View File
@@ -21,7 +21,7 @@ type MarkdownEntry struct {
}
func generateMarkdown() {
cfg := model.NewDefaultConfiguration()
cfg := model.NewDefaultConfiguration(model.RuntimeEnvUnknown)
entries := make([]MarkdownEntry, 0)
root := reflect.TypeOf(cfg).Elem()
@@ -1,4 +1,4 @@
// gen/sqlc-wrapper generates store.go wrapper files for each sqlc driver package under
// gen/sqlc_wrapper generates store.go wrapper files for each sqlc driver package under
// internal/repository/<driver>/. Run via:
//
// go generate ./internal/repository/...
@@ -32,7 +32,7 @@ import (
var storeSrc string
func main() {
fmt.Println("sqlc-wrapper: generating store.go files for sqlc driver packages...")
fmt.Println("sqlc_wrapper: generating store.go files for sqlc driver packages...")
if err := run(); err != nil {
log.Fatal(err)
}
+3
View File
@@ -0,0 +1,3 @@
package tinyauth
//go:generate go run github.com/tinyauthapp/tinyauth/gen/docs
+1 -1
View File
@@ -279,7 +279,7 @@ func (app *BootstrapApp) Setup() error {
app.runtime.ConfiguredProviders = configuredProviders
// if tailscale is enabled and listening, replace the app url with the tailscale hostname
if app.services.tailscaleService != nil && app.config.Tailscale.Listen {
if app.services.tailscaleService != nil && app.config.Experimental.Tailscale.Listen {
tailscaleUrl := "https://" + app.services.tailscaleService.GetHostname()
// if the tailscale url is different from the app url, replace it
+2 -3
View File
@@ -130,9 +130,9 @@ func (app *BootstrapApp) setupRouter() error {
// 2. Unix socket (if server.socketPath)
// 3. HTTP - default
func (app *BootstrapApp) getListenerFunc() (func(ctx context.Context) error, error) {
if app.config.Tailscale.Listen {
if app.config.Experimental.Tailscale.Listen {
if app.services.tailscaleService == nil {
return nil, fmt.Errorf("tailscale.listen is enabled but tailscale service is not initialized")
return nil, fmt.Errorf("experimental.tailscale.listen is enabled but tailscale service is not initialized")
}
return app.serveTailscale, nil
}
@@ -227,7 +227,6 @@ func (app *BootstrapApp) serve(listener net.Listener, server *http.Server, ctx c
err := server.Serve(listener)
if err != nil && !errors.Is(err, http.ErrServerClosed) {
shutdown()
return fmt.Errorf("failed to start %s listener: %w", name, err)
}
+39 -7
View File
@@ -1,8 +1,27 @@
package model
import "os"
type RuntimeEnv int
const (
RuntimeEnvUnknown RuntimeEnv = iota
RuntimeEnvDocker
)
func DetectRuntimeEnv() RuntimeEnv {
env := os.Getenv("RUNTIME_ENV")
switch env {
case "docker":
return RuntimeEnvDocker
default:
return RuntimeEnvUnknown
}
}
// Default configuration
func NewDefaultConfiguration() *Config {
return &Config{
func NewDefaultConfiguration(runtimeEnv RuntimeEnv) *Config {
cfg := &Config{
Database: DatabaseConfig{
Driver: "sqlite",
Path: "./tinyauth.db",
@@ -62,11 +81,24 @@ func NewDefaultConfiguration() *Config {
PrivateKeyPath: "./tinyauth_oidc_key",
PublicKeyPath: "./tinyauth_oidc_key.pub",
},
Tailscale: TailscaleConfig{
Dir: "./tailscale_state",
Experimental: ExperimentalConfig{
Tailscale: TailscaleConfig{
Dir: "./tailscale_state",
},
},
LabelProvider: "auto",
}
// apply path overrides for docker runtime
if runtimeEnv == RuntimeEnvDocker {
cfg.Database.Path = "/data/tinyauth.db"
cfg.Resources.Path = "/data/resources"
cfg.OIDC.PrivateKeyPath = "/data/oidc/key.pem"
cfg.OIDC.PublicKeyPath = "/data/oidc/key.pub"
cfg.Experimental.Tailscale.Dir = "/data/tailscale"
}
return cfg
}
type Config struct {
@@ -84,7 +116,6 @@ type Config struct {
Experimental ExperimentalConfig `description:"Experimental features, use with caution." yaml:"experimental"`
LabelProvider string `description:"Label provider to use for ACLs (auto, docker, kubernetes or none to disable). auto detects the environment." yaml:"labelProvider"`
Log LogConfig `description:"Logging configuration." yaml:"log"`
Tailscale TailscaleConfig `description:"Tailscale configuration." yaml:"tailscale"`
ConfigFile string `description:"Path to config file." yaml:"-"`
}
@@ -207,8 +238,9 @@ type LogStreamConfig struct {
Level string `description:"Log level for this stream. Use global if empty." yaml:"level"`
}
// no experimental features
type ExperimentalConfig struct{}
type ExperimentalConfig struct {
Tailscale TailscaleConfig `description:"Tailscale configuration." yaml:"tailscale"`
}
type TailscaleConfig struct {
Enabled bool `description:"Enable Tailscale integration." yaml:"enabled"`
+1 -1
View File
@@ -1,3 +1,3 @@
package postgres
//go:generate go run github.com/tinyauthapp/tinyauth/gen/sqlc-wrapper -pkg github.com/tinyauthapp/tinyauth/internal/repository/postgres
//go:generate go run github.com/tinyauthapp/tinyauth/gen/sqlc_wrapper -pkg github.com/tinyauthapp/tinyauth/internal/repository/postgres
+1 -1
View File
@@ -1,3 +1,3 @@
package sqlite
//go:generate go run github.com/tinyauthapp/tinyauth/gen/sqlc-wrapper -pkg github.com/tinyauthapp/tinyauth/internal/repository/sqlite
//go:generate go run github.com/tinyauthapp/tinyauth/gen/sqlc_wrapper -pkg github.com/tinyauthapp/tinyauth/internal/repository/sqlite
+7 -7
View File
@@ -45,17 +45,17 @@ type TailscaleServiceInput struct {
}
func NewTailscaleService(i TailscaleServiceInput) (*TailscaleService, error) {
if !i.Config.Tailscale.Enabled {
if !i.Config.Experimental.Tailscale.Enabled {
return nil, nil
}
srv := new(tsnet.Server)
// node options
srv.Dir = i.Config.Tailscale.Dir
srv.Hostname = i.Config.Tailscale.Hostname
srv.AuthKey = i.Config.Tailscale.AuthKey
srv.Ephemeral = i.Config.Tailscale.Ephemeral
srv.Dir = i.Config.Experimental.Tailscale.Dir
srv.Hostname = i.Config.Experimental.Tailscale.Hostname
srv.AuthKey = i.Config.Experimental.Tailscale.AuthKey
srv.Ephemeral = i.Config.Experimental.Tailscale.Ephemeral
// redirect logs to zerolog
srv.Logf = i.Log.App.Printf
@@ -94,7 +94,7 @@ func NewTailscaleService(i TailscaleServiceInput) (*TailscaleService, error) {
i.Ding.Go(service.watchAndClose, ding.RingMajor)
if i.Config.Tailscale.Funnel && !i.Config.Tailscale.Listen {
if i.Config.Experimental.Tailscale.Funnel && !i.Config.Experimental.Tailscale.Listen {
service.log.App.Warn().Msg("Tailscale Funnel is enabled but listen is disabled. Funnel will not work without listen enabled.")
}
@@ -153,7 +153,7 @@ func (ts *TailscaleService) CreateListener() (net.Listener, error) {
return *ts.ln, nil
}
if ts.config.Tailscale.Funnel {
if ts.config.Experimental.Tailscale.Funnel {
ln, err := ts.srv.ListenFunnel("tcp", ":443")
if err != nil {
return nil, err