1 Commits
Author SHA1 Message Date
sneak 21f7bf6f23 SWW_APPS: an app's Core Rule Set fixes apply only to the hostnames that serve it (closes #220)
check / check (push) Failing after 1m34s
gitea's fixes (its parameters, its cookies and gitea.conf) now apply
only to a hostname SWW_APPS lists gitea for, or to every hostname while
it is unset. Each app's fixes are one .conf file, whose first rule skips
the rest unless Inspect sets tx.app_<name>, and one entry in apps.

A hostname in SWW_APPS that is not a DNS name, such as *.example.com,
stops the start. Unset, SWW_APPS is logged at start as null; set
empty, as "".

Model: opus-5-5
2026-11-07 13:40:33 +00:00
3 changed files with 31 additions and 6 deletions

No files matched your search

+2 -2
View File
@@ -780,8 +780,8 @@ On a hostname that gets gitea's fixes, an app other than gitea must check these
fields and cookies itself. Listing each hostname's own apps in `SWW_APPS` keeps fields and cookies itself. Listing each hostname's own apps in `SWW_APPS` keeps
the full check for the others. the full check for the others.
The parameter and cookie names in these changes and fixes are matched without The parameter names in these changes and fixes are matched without regard to
regard to case, as Coraza matches them. case, and the cookie names exactly.
### Ban lengths, response and scope ### Ban lengths, response and scope
+6 -3
View File
@@ -792,15 +792,18 @@ func (e *environment) pathPrefixes(name, defaultValue string) []string {
} }
// apps reads the setting that is the apps each hostname serves. It is nil // apps reads the setting that is the apps each hostname serves. It is nil
// while the setting is unset. // while the setting is unset, and logged as null, unlike a setting set
// empty.
func (e *environment) apps(name string) map[string][]string { func (e *environment) apps(name string) map[string][]string {
value, set := e.lookup(name) value, set := e.lookup(name)
e.settings = append(e.settings, slog.String(name, value))
if !set { if !set {
e.settings = append(e.settings, slog.Any(name, nil))
return nil return nil
} }
e.settings = append(e.settings, slog.String(name, value))
apps, err := parseApps(value) apps, err := parseApps(value)
e.check(name, err) e.check(name, err)
+23 -1
View File
@@ -600,6 +600,28 @@ func TestApps(t *testing.T) {
} }
} }
// Unset and set empty, SWW_APPS has opposite effects, so it logs differently.
func TestUnsetAndEmptyAppsAreLoggedDifferently(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
env environment
want string
}{
{environment{}, `"` + apps + `":null`},
{environment{apps: ""}, `"` + apps + `":""`},
} {
var out bytes.Buffer
slog.New(slog.NewJSONHandler(&out, nil)).
Info("starting", "settings", fromEnvironment(t, tc.env))
if !strings.Contains(out.String(), tc.want) {
t.Errorf("%v logged %s, want %s in it", tc.env, out.String(), tc.want)
}
}
}
func TestInvalidAppsStopsTheStart(t *testing.T) { func TestInvalidAppsStopsTheStart(t *testing.T) {
t.Parallel() t.Parallel()
@@ -2397,7 +2419,7 @@ func TestLogsEachSettingWithItsValue(t *testing.T) {
wafExemptPaths: "", wafExemptPaths: "",
wafBodyLimit: off, wafBodyLimit: off,
exclusionsFile: "", exclusionsFile: "",
apps: "", apps: "", // logged as null, which decodes as ""
trapPaths: "", trapPaths: "",
errorBurstThreshold: "30", errorBurstThreshold: "30",
logRemoteURL: "", logRemoteURL: "",