Hash passwords with 1 MiB in tests so make test fits in 4 GiB (closes #261)
Check / check (pull_request) Skipped

On a build machine with 4 GiB, docker build . failed: the auth test
binary was killed for lack of memory. upaasd hashes passwords with
argon2id at 64 MiB per hash; the auth and handlers tests run many such
hashes at once, and the race detector multiplies what each one takes,
so make test peaked at 2.7 GiB.

The memory per hash is now the auth service's ArgonMemory field. New
sets it to the same 64 MiB, which upaasd keeps; the test helpers lower
it to 1 MiB. A new test checks that New sets 64 MiB and hashes and
verifies a password with it. GOMAXPROCS=4 make test now peaks at about
1.4 GiB.

Model: opus-5-5
This commit is contained in:
2026-10-03 00:37:04 +00:00
parent d3b9c6fca9
commit 55795ddfc4
4 changed files with 42 additions and 6 deletions
+6
View File
@@ -20,6 +20,12 @@ regress.
# Completed Steps # Completed Steps
- 2026-10-03: `make test`, and so `docker build .`, fits a machine with 4 GiB of
memory: tests hash passwords with 1 MiB instead of upaasd's 64 MiB, so
`GOMAXPROCS=4 make test` peaks at about 1.4 GiB instead of 2.7 GiB. upaasd
still hashes with 64 MiB, and one test hashes and verifies a password at that
cost (#261).
- 2026-10-02: In a window too narrow for the top bar, such as 390 px, the New - 2026-10-02: In a window too narrow for the top bar, such as 390 px, the New
App and Logout buttons move to a second row instead of running into "by App and Logout buttons move to a second row instead of running into "by
@sneak"; the bar keeps a gap between its two sides at every width (#272). @sneak"; the bar keeps a gap between its two sides at every width (#272).
+3
View File
@@ -109,6 +109,9 @@ func createAppServices(
}) })
require.NoError(t, authErr) require.NoError(t, authErr)
// 1 MiB per password hash instead of 64 MiB; see auth.Service.ArgonMemory.
authSvc.ArgonMemory = 1024
appSvc, appErr := app.New(fx.Lifecycle(nil), app.ServiceParams{ appSvc, appErr := app.New(fx.Lifecycle(nil), app.ServiceParams{
Logger: logInstance, Logger: logInstance,
Database: dbInstance, Database: dbInstance,
+14 -6
View File
@@ -59,6 +59,13 @@ type ServiceParams struct {
// Service provides authentication functionality. // Service provides authentication functionality.
type Service struct { type Service struct {
// ArgonMemory is the memory each argon2id hash takes, in KiB. New sets
// argonMemory, 64 MiB, and upaasd never changes it. Tests lower it, since
// many 64 MiB hashes at once under the race detector need more memory
// than a 4 GiB build machine has. A hash verifies only with the value it
// was made with.
ArgonMemory uint32
log *slog.Logger log *slog.Logger
db *database.Database db *database.Database
store *sessions.CookieStore store *sessions.CookieStore
@@ -77,10 +84,11 @@ func New(_ fx.Lifecycle, params ServiceParams) (*Service, error) {
} }
return &Service{ return &Service{
log: params.Logger.Get(), ArgonMemory: argonMemory,
db: params.Database, log: params.Logger.Get(),
store: store, db: params.Database,
params: &params, store: store,
params: &params,
}, nil }, nil
} }
@@ -97,7 +105,7 @@ func (svc *Service) HashPassword(password string) (string, error) {
[]byte(password), []byte(password),
salt, salt,
argonTime, argonTime,
argonMemory, svc.ArgonMemory,
argonThreads, argonThreads,
argonKeyLen, argonKeyLen,
) )
@@ -132,7 +140,7 @@ func (svc *Service) VerifyPassword(hashedPassword, password string) bool {
[]byte(password), []byte(password),
salt, salt,
argonTime, argonTime,
argonMemory, svc.ArgonMemory,
argonThreads, argonThreads,
argonKeyLen, argonKeyLen,
) )
+19
View File
@@ -65,6 +65,10 @@ func setupTestService(t *testing.T) (*auth.Service, func()) {
}) })
require.NoError(t, err) require.NoError(t, err)
// 1 MiB per hash instead of 64 MiB; see Service.ArgonMemory. The tests
// that use setupAuthService keep 64 MiB.
svc.ArgonMemory = 1024
// t.TempDir() automatically cleans up after test // t.TempDir() automatically cleans up after test
cleanup := func() {} cleanup := func() {}
@@ -237,6 +241,21 @@ func TestVerifyPassword(testingT *testing.T) {
}) })
} }
// TestHashPasswordWithUpaasdMemory hashes and verifies a password with the
// memory New sets, which upaasd uses. setupTestService lowers it.
func TestHashPasswordWithUpaasdMemory(t *testing.T) {
t.Parallel()
svc := setupAuthService(t, false)
require.Equal(t, uint32(64*1024), svc.ArgonMemory)
hash, err := svc.HashPassword("correctpassword")
require.NoError(t, err)
assert.True(t, svc.VerifyPassword(hash, "correctpassword"))
assert.False(t, svc.VerifyPassword(hash, "wrongpassword"))
}
func TestIsSetupRequired(testingT *testing.T) { func TestIsSetupRequired(testingT *testing.T) {
testingT.Parallel() testingT.Parallel()