Compare commits

..

1 Commits

Author SHA1 Message Date
Stavros 44c763c302 fix: narrow down action permissions to per-job ones 2026-04-29 16:41:24 +03:00
44 changed files with 173 additions and 172 deletions
+17 -2
View File
@@ -5,12 +5,13 @@ on:
- cron: "0 0 * * *"
permissions:
contents: write
packages: write
contents: read
jobs:
create-release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -145,6 +146,8 @@ jobs:
needs:
- create-release
- generate-metadata
permissions:
packages: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -203,6 +206,8 @@ jobs:
- create-release
- generate-metadata
- image-build
permissions:
packages: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -261,6 +266,8 @@ jobs:
needs:
- create-release
- generate-metadata
permissions:
packages: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -319,6 +326,8 @@ jobs:
- create-release
- generate-metadata
- image-build-arm
permissions:
packages: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -377,6 +386,8 @@ jobs:
needs:
- image-build
- image-build-arm
permissions:
packages: write
steps:
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
@@ -416,6 +427,8 @@ jobs:
needs:
- image-build-distroless
- image-build-arm-distroless
permissions:
packages: write
steps:
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
@@ -455,6 +468,8 @@ jobs:
needs:
- binary-build
- binary-build-arm
permissions:
contents: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
+15 -2
View File
@@ -6,8 +6,7 @@ on:
- "v*"
permissions:
contents: write
packages: write
contents: read
jobs:
generate-metadata:
@@ -117,6 +116,8 @@ jobs:
runs-on: ubuntu-latest
needs:
- generate-metadata
permissions:
packages: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -172,6 +173,8 @@ jobs:
needs:
- generate-metadata
- image-build
permissions:
packages: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -227,6 +230,8 @@ jobs:
runs-on: ubuntu-24.04-arm
needs:
- generate-metadata
permissions:
packages: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -282,6 +287,8 @@ jobs:
needs:
- generate-metadata
- image-build-arm
permissions:
packages: read
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -338,6 +345,8 @@ jobs:
needs:
- image-build
- image-build-arm
permissions:
packages: write
steps:
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
@@ -379,6 +388,8 @@ jobs:
needs:
- image-build-distroless
- image-build-arm-distroless
permissions:
packages: write
steps:
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
@@ -422,6 +433,8 @@ jobs:
needs:
- binary-build
- binary-build-arm
permissions:
contents: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
+4 -2
View File
@@ -3,12 +3,14 @@ on:
workflow_dispatch:
permissions:
contents: write
pull-requests: write
contents: read
jobs:
generate-sponsors:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+4 -2
View File
@@ -4,12 +4,14 @@ on:
- cron: 0 10 * * *
permissions:
issues: write
pull-requests: write
contents: read
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10
with:
+1 -1
View File
@@ -11,5 +11,5 @@ var FrontendAssets embed.FS
// Migrations
//
//go:embed migrations/sqlite/*.sql
//go:embed migrations/*.sql
var Migrations embed.FS
+7 -4
View File
@@ -130,14 +130,17 @@ func (app *BootstrapApp) Setup() error {
tlog.App.Trace().Str("redirectCookieName", app.context.redirectCookieName).Msg("Redirect cookie name")
// Database
store, err := app.SetupStore()
db, err := app.SetupDatabase(app.config.Database.Path)
if err != nil {
return fmt.Errorf("failed to setup database: %w", err)
}
// Queries
queries := repository.New(db)
// Services
services, err := app.initServices(store)
services, err := app.initServices(queries)
if err != nil {
return fmt.Errorf("failed to initialize services: %w", err)
@@ -193,7 +196,7 @@ func (app *BootstrapApp) Setup() error {
// Start db cleanup routine
tlog.App.Debug().Msg("Starting database cleanup routine")
go app.dbCleanupRoutine(store)
go app.dbCleanupRoutine(queries)
// If analytics are not disabled, start heartbeat
if app.config.Analytics.Enabled {
@@ -283,7 +286,7 @@ func (app *BootstrapApp) heartbeatRoutine() {
}
}
func (app *BootstrapApp) dbCleanupRoutine(queries repository.Store) {
func (app *BootstrapApp) dbCleanupRoutine(queries *repository.Queries) {
ticker := time.NewTicker(time.Duration(30) * time.Minute)
defer ticker.Stop()
ctx := context.Background()
+3 -16
View File
@@ -7,8 +7,6 @@ import (
"path/filepath"
"github.com/tinyauthapp/tinyauth/internal/assets"
"github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/tinyauthapp/tinyauth/internal/repository/sqlite"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/sqlite3"
@@ -16,18 +14,7 @@ import (
_ "modernc.org/sqlite"
)
func (app *BootstrapApp) SetupStore() (repository.Store, error) {
return app.setupSQLite(app.config.Database.Path)
}
// NewSQLiteStore opens a SQLite database at the given path, runs migrations, and returns a Store.
// Useful for testing or when constructing a store outside of a BootstrapApp.
func NewSQLiteStore(databasePath string) (repository.Store, error) {
app := &BootstrapApp{}
return app.setupSQLite(databasePath)
}
func (app *BootstrapApp) setupSQLite(databasePath string) (repository.Store, error) {
func (app *BootstrapApp) SetupDatabase(databasePath string) (*sql.DB, error) {
dir := filepath.Dir(databasePath)
if err := os.MkdirAll(dir, 0750); err != nil {
@@ -44,7 +31,7 @@ func (app *BootstrapApp) setupSQLite(databasePath string) (repository.Store, err
// if the sqlite connection starts being a bottleneck
db.SetMaxOpenConns(1)
migrations, err := iofs.New(assets.Migrations, "migrations/sqlite")
migrations, err := iofs.New(assets.Migrations, "migrations")
if err != nil {
return nil, fmt.Errorf("failed to create migrations: %w", err)
@@ -66,5 +53,5 @@ func (app *BootstrapApp) setupSQLite(databasePath string) (repository.Store, err
return nil, fmt.Errorf("failed to migrate database: %w", err)
}
return sqlite.New(db), nil
return db, nil
}
+1 -1
View File
@@ -18,7 +18,7 @@ type Services struct {
oidcService *service.OIDCService
}
func (app *BootstrapApp) initServices(queries repository.Store) (Services, error) {
func (app *BootstrapApp) initServices(queries *repository.Queries) (Services, error) {
services := Services{}
ldapService := service.NewLdapService(service.LdapServiceConfig{
+1 -1
View File
@@ -95,7 +95,7 @@ type Config struct {
}
type DatabaseConfig struct {
Path string `description:"The path to the SQLite database, including file name." yaml:"path"`
Path string `description:"The path to the database, including file name." yaml:"path"`
}
type AnalyticsConfig struct {
+11 -2
View File
@@ -15,6 +15,7 @@ import (
"github.com/tinyauthapp/tinyauth/internal/bootstrap"
"github.com/tinyauthapp/tinyauth/internal/config"
"github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/tinyauthapp/tinyauth/internal/service"
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
@@ -847,10 +848,13 @@ func TestOIDCController(t *testing.T) {
},
}
store, err := bootstrap.NewSQLiteStore(path.Join(tempDir, "tinyauth.db"))
app := bootstrap.NewBootstrapApp(config.Config{})
db, err := app.SetupDatabase(path.Join(tempDir, "tinyauth.db"))
require.NoError(t, err)
oidcService := service.NewOIDCService(oidcServiceCfg, store)
queries := repository.New(db)
oidcService := service.NewOIDCService(oidcServiceCfg, queries)
err = oidcService.Init()
require.NoError(t, err)
@@ -873,4 +877,9 @@ func TestOIDCController(t *testing.T) {
test.run(t, router, recorder)
})
}
t.Cleanup(func() {
err = db.Close()
require.NoError(t, err)
})
}
+12 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/tinyauthapp/tinyauth/internal/bootstrap"
"github.com/tinyauthapp/tinyauth/internal/config"
"github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/tinyauthapp/tinyauth/internal/service"
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
@@ -392,9 +393,13 @@ func TestProxyController(t *testing.T) {
oauthBrokerCfgs := make(map[string]config.OAuthServiceConfig)
store, err := bootstrap.NewSQLiteStore(path.Join(tempDir, "tinyauth.db"))
app := bootstrap.NewBootstrapApp(config.Config{})
db, err := app.SetupDatabase(path.Join(tempDir, "tinyauth.db"))
require.NoError(t, err)
queries := repository.New(db)
docker := service.NewDockerService()
err = docker.Init()
require.NoError(t, err)
@@ -407,7 +412,7 @@ func TestProxyController(t *testing.T) {
err = broker.Init()
require.NoError(t, err)
authService := service.NewAuthService(authServiceCfg, ldap, store, broker)
authService := service.NewAuthService(authServiceCfg, ldap, queries, broker)
err = authService.Init()
require.NoError(t, err)
@@ -432,4 +437,9 @@ func TestProxyController(t *testing.T) {
test.run(t, router, recorder)
})
}
t.Cleanup(func() {
err = db.Close()
require.NoError(t, err)
})
}
+12 -2
View File
@@ -13,6 +13,7 @@ import (
"github.com/tinyauthapp/tinyauth/internal/bootstrap"
"github.com/tinyauthapp/tinyauth/internal/config"
"github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/tinyauthapp/tinyauth/internal/service"
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
@@ -350,9 +351,13 @@ func TestUserController(t *testing.T) {
oauthBrokerCfgs := make(map[string]config.OAuthServiceConfig)
store, err := bootstrap.NewSQLiteStore(path.Join(tempDir, "tinyauth.db"))
app := bootstrap.NewBootstrapApp(config.Config{})
db, err := app.SetupDatabase(path.Join(tempDir, "tinyauth.db"))
require.NoError(t, err)
queries := repository.New(db)
docker := service.NewDockerService()
err = docker.Init()
require.NoError(t, err)
@@ -365,7 +370,7 @@ func TestUserController(t *testing.T) {
err = broker.Init()
require.NoError(t, err)
authService := service.NewAuthService(authServiceCfg, ldap, store, broker)
authService := service.NewAuthService(authServiceCfg, ldap, queries, broker)
err = authService.Init()
require.NoError(t, err)
@@ -430,4 +435,9 @@ func TestUserController(t *testing.T) {
test.run(t, router, recorder)
})
}
t.Cleanup(func() {
err = db.Close()
require.NoError(t, err)
})
}
@@ -11,6 +11,7 @@ import (
"github.com/tinyauthapp/tinyauth/internal/bootstrap"
"github.com/tinyauthapp/tinyauth/internal/config"
"github.com/tinyauthapp/tinyauth/internal/controller"
"github.com/tinyauthapp/tinyauth/internal/repository"
"github.com/tinyauthapp/tinyauth/internal/service"
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
"github.com/stretchr/testify/assert"
@@ -100,10 +101,14 @@ func TestWellKnownController(t *testing.T) {
},
}
store, err := bootstrap.NewSQLiteStore(path.Join(tempDir, "tinyauth.db"))
app := bootstrap.NewBootstrapApp(config.Config{})
db, err := app.SetupDatabase(path.Join(tempDir, "tinyauth.db"))
require.NoError(t, err)
oidcService := service.NewOIDCService(oidcServiceCfg, store)
queries := repository.New(db)
oidcService := service.NewOIDCService(oidcServiceCfg, queries)
err = oidcService.Init()
require.NoError(t, err)
@@ -120,4 +125,9 @@ func TestWellKnownController(t *testing.T) {
test.run(t, router, recorder)
})
}
t.Cleanup(func() {
err = db.Close()
require.NoError(t, err)
})
}
@@ -1,8 +1,8 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.0
// sqlc v1.30.0
package sqlite
package repository
import (
"context"
+59 -14
View File
@@ -1,19 +1,64 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
package repository
// This file is a stop-gap until more drivers are added. It re-exports the models from the sqlite package so that the rest
// of the codebase can import them from a single location without needing to know about the underlying database implementation.
type OidcCode struct {
Sub string
CodeHash string
Scope string
RedirectURI string
ClientID string
ExpiresAt int64
Nonce string
CodeChallenge string
}
import "github.com/tinyauthapp/tinyauth/internal/repository/sqlite"
type OidcToken struct {
Sub string
AccessTokenHash string
RefreshTokenHash string
CodeHash string
Scope string
ClientID string
TokenExpiresAt int64
RefreshTokenExpiresAt int64
Nonce string
}
type Session = sqlite.Session
type OidcCode = sqlite.OidcCode
type OidcToken = sqlite.OidcToken
type OidcUserinfo = sqlite.OidcUserinfo
type OidcUserinfo struct {
Sub string
Name string
PreferredUsername string
Email string
Groups string
UpdatedAt int64
GivenName string
FamilyName string
MiddleName string
Nickname string
Profile string
Picture string
Website string
Gender string
Birthdate string
Zoneinfo string
Locale string
PhoneNumber string
Address string
}
type CreateSessionParams = sqlite.CreateSessionParams
type UpdateSessionParams = sqlite.UpdateSessionParams
type CreateOidcCodeParams = sqlite.CreateOidcCodeParams
type CreateOidcTokenParams = sqlite.CreateOidcTokenParams
type UpdateOidcTokenByRefreshTokenParams = sqlite.UpdateOidcTokenByRefreshTokenParams
type DeleteExpiredOidcTokensParams = sqlite.DeleteExpiredOidcTokensParams
type CreateOidcUserInfoParams = sqlite.CreateOidcUserInfoParams
type Session struct {
UUID string
Username string
Email string
Name string
Provider string
TotpPending bool
OAuthGroups string
Expiry int64
CreatedAt int64
OAuthName string
OAuthSub string
}
@@ -1,9 +1,9 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.0
// sqlc v1.30.0
// source: oidc_queries.sql
package sqlite
package repository
import (
"context"
@@ -1,9 +1,9 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.0
// sqlc v1.30.0
// source: session_queries.sql
package sqlite
package repository
import (
"context"
-64
View File
@@ -1,64 +0,0 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.0
package sqlite
type OidcCode struct {
Sub string
CodeHash string
Scope string
RedirectURI string
ClientID string
ExpiresAt int64
Nonce string
CodeChallenge string
}
type OidcToken struct {
Sub string
AccessTokenHash string
RefreshTokenHash string
CodeHash string
Scope string
ClientID string
TokenExpiresAt int64
RefreshTokenExpiresAt int64
Nonce string
}
type OidcUserinfo struct {
Sub string
Name string
PreferredUsername string
Email string
Groups string
UpdatedAt int64
GivenName string
FamilyName string
MiddleName string
Nickname string
Profile string
Picture string
Website string
Gender string
Birthdate string
Zoneinfo string
Locale string
PhoneNumber string
Address string
}
type Session struct {
UUID string
Username string
Email string
Name string
Provider string
TotpPending bool
OAuthGroups string
Expiry int64
CreatedAt int64
OAuthName string
OAuthSub string
}
-41
View File
@@ -1,41 +0,0 @@
package repository
import "context"
// Store is the interface that all storage drivers must implement.
// The sqlc-generated *Queries struct satisfies this interface for SQLite.
// Future drivers (postgres, etc.) must return the shared types defined in this package.
type Store interface {
// Sessions
CreateSession(ctx context.Context, arg CreateSessionParams) (Session, error)
GetSession(ctx context.Context, uuid string) (Session, error)
UpdateSession(ctx context.Context, arg UpdateSessionParams) (Session, error)
DeleteSession(ctx context.Context, uuid string) error
DeleteExpiredSessions(ctx context.Context, expiry int64) error
// OIDC codes
CreateOidcCode(ctx context.Context, arg CreateOidcCodeParams) (OidcCode, error)
GetOidcCode(ctx context.Context, codeHash string) (OidcCode, error)
GetOidcCodeBySub(ctx context.Context, sub string) (OidcCode, error)
GetOidcCodeUnsafe(ctx context.Context, codeHash string) (OidcCode, error)
GetOidcCodeBySubUnsafe(ctx context.Context, sub string) (OidcCode, error)
DeleteOidcCode(ctx context.Context, codeHash string) error
DeleteOidcCodeBySub(ctx context.Context, sub string) error
DeleteExpiredOidcCodes(ctx context.Context, expiresAt int64) ([]OidcCode, error)
// OIDC tokens
CreateOidcToken(ctx context.Context, arg CreateOidcTokenParams) (OidcToken, error)
GetOidcToken(ctx context.Context, accessTokenHash string) (OidcToken, error)
GetOidcTokenByRefreshToken(ctx context.Context, refreshTokenHash string) (OidcToken, error)
GetOidcTokenBySub(ctx context.Context, sub string) (OidcToken, error)
UpdateOidcTokenByRefreshToken(ctx context.Context, arg UpdateOidcTokenByRefreshTokenParams) (OidcToken, error)
DeleteOidcToken(ctx context.Context, accessTokenHash string) error
DeleteOidcTokenBySub(ctx context.Context, sub string) error
DeleteOidcTokenByCodeHash(ctx context.Context, codeHash string) error
DeleteExpiredOidcTokens(ctx context.Context, arg DeleteExpiredOidcTokensParams) ([]OidcToken, error)
// OIDC userinfo
CreateOidcUserInfo(ctx context.Context, arg CreateOidcUserInfoParams) (OidcUserinfo, error)
GetOidcUserInfo(ctx context.Context, sub string) (OidcUserinfo, error)
DeleteOidcUserInfo(ctx context.Context, sub string) error
}
+2 -2
View File
@@ -90,14 +90,14 @@ type AuthService struct {
loginMutex sync.RWMutex
ldapGroupsMutex sync.RWMutex
ldap *LdapService
queries repository.Store
queries *repository.Queries
oauthBroker *OAuthBrokerService
lockdown *Lockdown
lockdownCtx context.Context
lockdownCancelFunc context.CancelFunc
}
func NewAuthService(config AuthServiceConfig, ldap *LdapService, queries repository.Store, oauthBroker *OAuthBrokerService) *AuthService {
func NewAuthService(config AuthServiceConfig, ldap *LdapService, queries *repository.Queries, oauthBroker *OAuthBrokerService) *AuthService {
return &AuthService{
config: config,
loginAttempts: make(map[string]*LoginAttempt),
+2 -2
View File
@@ -121,7 +121,7 @@ type OIDCServiceConfig struct {
type OIDCService struct {
config OIDCServiceConfig
queries repository.Store
queries *repository.Queries
clients map[string]config.OIDCClientConfig
privateKey *rsa.PrivateKey
publicKey crypto.PublicKey
@@ -129,7 +129,7 @@ type OIDCService struct {
isConfigured bool
}
func NewOIDCService(config OIDCServiceConfig, queries repository.Store) *OIDCService {
func NewOIDCService(config OIDCServiceConfig, queries *repository.Queries) *OIDCService {
return &OIDCService{
config: config,
queries: queries,
+4 -4
View File
@@ -1,12 +1,12 @@
version: "2"
sql:
- engine: "sqlite"
queries: "sql/sqlite/*_queries.sql"
schema: "sql/sqlite/*_schemas.sql"
queries: "sql/*_queries.sql"
schema: "sql/*_schemas.sql"
gen:
go:
package: "sqlite"
out: "internal/repository/sqlite"
package: "repository"
out: "internal/repository"
rename:
uuid: "UUID"
oauth_groups: "OAuthGroups"