Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package semaphore for openSUSE:Factory checked in at 2026-11-06 19:46:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/semaphore (Old) and /work/SRC/openSUSE:Factory/.semaphore.new.3759290 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "semaphore" Fri Nov 6 19:46:55 2026 rev:60 rq:1395460 version:2.19.18 Changes: -------- --- /work/SRC/openSUSE:Factory/semaphore/semaphore.changes 2026-10-21 20:59:35.631281493 +0200 +++ /work/SRC/openSUSE:Factory/.semaphore.new.3759290/semaphore.changes 2026-11-06 19:52:50.853296577 +0100 @@ -1,0 +2,7 @@ +Wed Nov 04 10:14:40 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 2.19.18: + * SEMAPHORE_SESSION_INACTIVITY_HOURS — How long a login session + may stay unused, in hours, before it is rejected and expired. + +------------------------------------------------------------------- Old: ---- semaphore-2.19.17.obscpio web-2.19.17.tar.gz New: ---- semaphore-2.19.18.obscpio web-2.19.18.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ semaphore.spec ++++++ --- /var/tmp/diff_new_pack.jkEXex/_old 2026-11-06 19:53:13.733254579 +0100 +++ /var/tmp/diff_new_pack.jkEXex/_new 2026-11-06 19:53:13.737254746 +0100 @@ -17,7 +17,7 @@ Name: semaphore -Version: 2.19.17 +Version: 2.19.18 Release: 0 Summary: Modern UI for Ansible License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.jkEXex/_old 2026-11-06 19:53:13.833258766 +0100 +++ /var/tmp/diff_new_pack.jkEXex/_new 2026-11-06 19:53:13.841259101 +0100 @@ -4,8 +4,8 @@ <param name="scm">git</param> <param name="submodules">disable</param> <param name="exclude">.git</param> - <param name="revision">refs/tags/v2.19.17</param> - <param name="match-tag">v2.19.17</param> + <param name="revision">refs/tags/v2.19.18</param> + <param name="match-tag">v2.19.18</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.jkEXex/_old 2026-11-06 19:53:13.877260608 +0100 +++ /var/tmp/diff_new_pack.jkEXex/_new 2026-11-06 19:53:13.889261111 +0100 @@ -3,6 +3,6 @@ <param name="url">https://github.com/ansible-semaphore/semaphore</param> <param name="changesrevision">8a4dcf0868af718aaa5871368a3247dd622521f4</param></service><service name="tar_scm"> <param name="url">https://github.com/ansible-semaphore/semaphore.git</param> - <param name="changesrevision">f8cefe62da4d40e536323e3dd936eb2e04e82b1a</param></service></servicedata> + <param name="changesrevision">b621d1453a4eba54b5e162e2f572495d26944221</param></service></servicedata> (No newline at EOF) ++++++ semaphore-2.19.17.obscpio -> semaphore-2.19.18.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/semaphore-2.19.17/api/auth.go new/semaphore-2.19.18/api/auth.go --- old/semaphore-2.19.17/api/auth.go 2026-10-07 07:29:04.000000000 +0200 +++ new/semaphore-2.19.18/api/auth.go 2026-11-02 21:03:04.000000000 +0100 @@ -49,9 +49,9 @@ return nil, false } - if time.Since(session.LastActive).Hours() > 7*24 { - // more than week old unused session - // destroy. + if time.Since(session.LastActive) > util.Config.SessionInactivityTimeout() { + // The session was unused for longer than the configured inactivity + // timeout. Destroy it so it cannot be reused. if err = helpers.Store(r).ExpireSession(userID, sessionID); err != nil { // it is internal error, it doesn't concern the user log.Error(err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/semaphore-2.19.17/config.schema.yaml new/semaphore-2.19.18/config.schema.yaml --- old/semaphore-2.19.17/config.schema.yaml 2026-10-07 07:29:04.000000000 +0200 +++ new/semaphore-2.19.18/config.schema.yaml 2026-11-02 21:03:04.000000000 +0100 @@ -33,6 +33,7 @@ # ========================================================================== # Authentication # ========================================================================== + auth: { $ref: "#/$defs/AuthConfig" } mfa: { $ref: "#/$defs/MultifactorAuthConfig" } # ========================================================================== @@ -324,6 +325,19 @@ maximum: 65535 description: Port for the HTTP→HTTPS redirect listener. Mutually exclusive with http_redirect_addr. + AuthConfig: + type: object + description: Settings that apply to every login method. + properties: + session_inactivity_hours: + type: integer + minimum: 0 + default: 0 + description: >- + How long a login session may stay unused, in hours, before it is + expired. Every authenticated request resets the counter. 0 means the + built-in 168 hours (7 days); the timeout cannot be disabled. + MultifactorAuthConfig: type: object description: Multi-factor authentication settings. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/semaphore-2.19.17/services/session_svc.go new/semaphore-2.19.18/services/session_svc.go --- old/semaphore-2.19.17/services/session_svc.go 2026-10-07 07:29:04.000000000 +0200 +++ new/semaphore-2.19.18/services/session_svc.go 2026-11-02 21:03:04.000000000 +0100 @@ -50,9 +50,9 @@ return nil, false } - if time.Since(session.LastActive).Hours() > 7*24 { - // more than week old unused session - // destroy. + if time.Since(session.LastActive) > util.Config.SessionInactivityTimeout() { + // The session was unused for longer than the configured inactivity + // timeout. Destroy it so it cannot be reused. if err = s.sessionRepo.ExpireSession(userID, sessionID); err != nil { // it is internal error, it doesn't concern the user log.Error(err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/semaphore-2.19.17/util/config.go new/semaphore-2.19.18/util/config.go --- old/semaphore-2.19.17/util/config.go 2026-10-07 07:29:04.000000000 +0200 +++ new/semaphore-2.19.18/util/config.go 2026-11-02 21:03:04.000000000 +0100 @@ -483,7 +483,8 @@ Port string `json:"port,omitempty" default:":3000" rule:"^:?([0-9]{1,5})$" env:"SEMAPHORE_PORT"` TLS *TLSConfig `json:"tls,omitempty"` - Mfa *MultifactorAuthConfig `json:"mfa,omitempty"` + Auth *AuthConfig `json:"auth,omitempty"` + Mfa *MultifactorAuthConfig `json:"mfa,omitempty"` // Interface ip, put in front of the port. // defaults to empty @@ -1641,6 +1642,10 @@ panic(err) } + if err := validate(Config.Auth); err != nil { + panic(err) + } + if err := validateAccessKeyEncryption(Config.AccessKeyEncryption); err != nil { panic(err) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/semaphore-2.19.17/util/config_auth.go new/semaphore-2.19.18/util/config_auth.go --- old/semaphore-2.19.17/util/config_auth.go 2026-10-07 07:29:04.000000000 +0200 +++ new/semaphore-2.19.18/util/config_auth.go 2026-11-02 21:03:04.000000000 +0100 @@ -1,5 +1,31 @@ package util +import "time" + +// DefaultSessionInactivityTimeout is how long a session may stay unused before +// it is rejected when auth.session_inactivity_hours is not configured. +const DefaultSessionInactivityTimeout = 7 * 24 * time.Hour + +// AuthConfig holds settings that apply to every login method. +type AuthConfig struct { + // SessionInactivityHours is how long a login session may stay unused, in + // hours, before it is rejected and expired. Every authenticated request + // resets the counter. 0 (default) means the built-in 168 hours (7 days). + // The inactivity timeout cannot be disabled. + SessionInactivityHours int `json:"session_inactivity_hours,omitempty" rule:"^[0-9]*$" env:"SEMAPHORE_SESSION_INACTIVITY_HOURS"` +} + +// SessionInactivityTimeout returns how long a session may stay unused before +// it is rejected, as configured by auth.session_inactivity_hours, or +// DefaultSessionInactivityTimeout when the option is not set. It is safe to +// call when the auth section is not configured. +func (c *ConfigType) SessionInactivityTimeout() time.Duration { + if c == nil || c.Auth == nil || c.Auth.SessionInactivityHours <= 0 { + return DefaultSessionInactivityTimeout + } + return time.Duration(c.Auth.SessionInactivityHours) * time.Hour +} + type RecaptchaConfig struct { Enabled string `json:"enabled,omitempty" env:"SEMAPHORE_RECAPTCHA_ENABLED"` SiteKey string `json:"site_key,omitempty" env:"SEMAPHORE_RECAPTCHA_SITE_KEY"` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/semaphore-2.19.17/util/config_auth_test.go new/semaphore-2.19.18/util/config_auth_test.go --- old/semaphore-2.19.17/util/config_auth_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/semaphore-2.19.18/util/config_auth_test.go 2026-11-02 21:03:04.000000000 +0100 @@ -0,0 +1,47 @@ +package util + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestConfigType_SessionInactivityTimeout(t *testing.T) { + tests := []struct { + name string + config *ConfigType + expected time.Duration + }{ + {"nil config", nil, DefaultSessionInactivityTimeout}, + {"auth section not configured", &ConfigType{}, DefaultSessionInactivityTimeout}, + {"zero hours means built-in default", &ConfigType{Auth: &AuthConfig{SessionInactivityHours: 0}}, DefaultSessionInactivityTimeout}, + {"negative hours means built-in default", &ConfigType{Auth: &AuthConfig{SessionInactivityHours: -5}}, DefaultSessionInactivityTimeout}, + {"configured hours", &ConfigType{Auth: &AuthConfig{SessionInactivityHours: 8}}, 8 * time.Hour}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, tt.config.SessionInactivityTimeout()) + }) + } +} + +func TestAuthConfig_LoadFromEnvironment(t *testing.T) { + t.Setenv("SEMAPHORE_SESSION_INACTIVITY_HOURS", "8") + + cfg := &ConfigType{} + _, err := loadEnvironmentToObject(cfg) + require.NoError(t, err) + + require.NotNil(t, cfg.Auth) + assert.Equal(t, 8, cfg.Auth.SessionInactivityHours) + assert.Equal(t, 8*time.Hour, cfg.SessionInactivityTimeout()) +} + +func TestAuthConfig_ValidateRejectsNegative(t *testing.T) { + assert.Error(t, validate(&AuthConfig{SessionInactivityHours: -1})) + assert.NoError(t, validate(&AuthConfig{SessionInactivityHours: 0})) + assert.NoError(t, validate(&AuthConfig{SessionInactivityHours: 48})) +} ++++++ semaphore.obsinfo ++++++ --- /var/tmp/diff_new_pack.jkEXex/_old 2026-11-06 19:53:15.312320696 +0100 +++ /var/tmp/diff_new_pack.jkEXex/_new 2026-11-06 19:53:15.318320947 +0100 @@ -1,5 +1,5 @@ name: semaphore -version: 2.19.17 -mtime: 1791350944 -commit: f8cefe62da4d40e536323e3dd936eb2e04e82b1a +version: 2.19.18 +mtime: 1793649784 +commit: b621d1453a4eba54b5e162e2f572495d26944221 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/semaphore/vendor.tar.gz /work/SRC/openSUSE:Factory/.semaphore.new.3759290/vendor.tar.gz differ: char 151, line 1 ++++++ web-2.19.17.tar.gz -> web-2.19.18.tar.gz ++++++ /work/SRC/openSUSE:Factory/semaphore/web-2.19.17.tar.gz /work/SRC/openSUSE:Factory/.semaphore.new.3759290/web-2.19.18.tar.gz differ: char 15, line 1
