Skip to content

feat: Hysteria2 Gecko obfs via bundled official-binary sidecar#17

Merged
hawkff merged 6 commits into
mainfrom
feature/hysteria2-gecko-sidecar
Jun 16, 2026
Merged

feat: Hysteria2 Gecko obfs via bundled official-binary sidecar#17
hawkff merged 6 commits into
mainfrom
feature/hysteria2-gecko-sidecar

Conversation

@hawkff

@hawkff hawkff commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Summary

Adds Hysteria2 Gecko obfuscation by bundling the official apernet/hysteria
Android client binary as a sidecar — instead of re-platforming the sing-box core.
Keeps the starifly core (and SSR/Snell/Juicity) fully intact. Days-scale vs the
2-8 week core migration. (See docs/maintenance/hysteria2-gecko-sidecar.md.)

How it works

  • Gecko obfs lives only in sing-box 1.14-alpha / an untagged sing-quic; the starifly
    core (1.12.x) can't do it. So for HY2 + Gecko profiles, canUseSingBox() returns
    false and the existing external-proxy machinery routes a sing-box socks outbound to a
    bundled libhysteria2.so sidecar. Non-obfs and Salamander HY2 stay on the native
    sing-box outbound (unchanged).
  • The sidecar's upstream QUIC sockets are protected from the VPN via hysteria's built-in
    quic.sockopts.fdControlUnixSocket, pointed at libcore's existing
    protect_server socket (protect_path). No new bridge, no upstream patch.

Changes

  • HysteriaBean: add hysteria2ObfsType (none/salamander/gecko) + gecko min/max packet
    size; kryo serialize version 7->8 with backward-compatible deserialize (old HY2 profiles
    with a password derive as Salamander; obfuscation remains the password). No Room schema change.
  • HysteriaFmt: canUseSingBox() false for HY2+Gecko; native HY2 outbound still emits
    Salamander; URI parse/export handle obfs=gecko + obfs-min/max-packet-size; new
    buildHysteria2SidecarConfig() emits official hysteria client JSON.
  • BoxInstance: init/launch run libhysteria2.so client --config <file> for HY2+Gecko.
  • buildScript/lib/hysteria2.sh: download official hysteria-android-* v2.9.2 as
    app/executableSo/<abi>/libhysteria2.so (all 4 ABIs), verified against the official
    hashes.txt SHA256
    .
  • CI: combined sidecars job builds+caches both libmieru.so and libhysteria2.so;
    build job verifies all ABIs/both binaries.
  • Executable: add libhysteria2.so to the process kill-set.
  • UI: HY2 obfs-type selector + gecko min/max packet-size fields.

Verification (AWS Linux builder)

  • ./run lib hysteria2 downloads + SHA256-verifies all 4 ABI binaries.
  • assembleOssDebug + assembleOssRelease (R8) BUILD SUCCESSFUL; libhysteria2.so
    confirmed packaged in the APK for all ABIs. No app/schemas change.

Not yet done (follow-up)

  • Live runtime connect test of a Gecko server — deferred to the emulator QA pass (x86 metal,
    quota now approved).

Scope

No sing-box core / Go change. starifly core + SSR/Snell/Juicity untouched.

hawkff added 4 commits June 16, 2026 07:56
Adds Hysteria2 'Gecko' obfuscation by bundling the official apernet/hysteria
Android client as a sidecar, instead of re-platforming the sing-box core.

- HysteriaBean: add hysteria2ObfsType (none/salamander/gecko) + gecko min/max
  packet size; kryo version 7->8 with backward-compatible deserialize (old HY2
  profiles with a password derive as Salamander). obfuscation stays the password.
- HysteriaFmt: canUseSingBox() returns false for HY2+Gecko (forces the sidecar);
  native HY2 outbound still emits Salamander; URI parse/export handle obfs type +
  gecko packet sizes; new buildHysteria2SidecarConfig() emits official hysteria
  client JSON with obfs.gecko + quic.sockopts.fdControlUnixSocket (reuses libcore's
  existing protect_path server) + loopback SOCKS5.
- BoxInstance: init/launch branches run the bundled libhysteria2.so
  (hysteria client --config <file>) for HY2+Gecko; Salamander/HY1 unchanged.
- buildScript/lib/hysteria2.sh: download official hysteria-android-* (v2.9.2) as
  app/executableSo/<abi>/libhysteria2.so (all 4 ABIs).
- Executable: add libhysteria2.so to the kill-set.
- UI: obfs type selector + gecko min/max packet-size fields (HY2 only).
- Routing reuses the existing external-proxy machinery (pluginId hysteria2-plugin).

No sing-box core change; starifly core + SSR/Snell/Juicity untouched.
Combine the per-workflow Mieru native-build job into a 'sidecars' job that
builds both libmieru.so (cross-compiled) and libhysteria2.so (downloaded from
apernet/hysteria v2.9.2) into app/executableSo, cached as one unit and restored
in the build job with a verify-all-ABIs-and-both-binaries guard. Adds
HYSTERIA_VERSION env. Applied across ci/build/preview/release workflows.
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5163958a-33bd-4bc1-8f27-3297316dead9

📥 Commits

Reviewing files that changed from the base of the PR and between 9463f86 and 7a1a546.

📒 Files selected for processing (6)
  • .github/workflows/build.yml
  • .github/workflows/ci.yml
  • .github/workflows/preview.yml
  • .github/workflows/release.yml
  • buildScript/lib/hysteria2.sh
  • docs/maintenance/hysteria2-gecko-sidecar.md

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Hysteria2 “Gecko” obfuscation support, alongside existing Hysteria2 options.
    • Added settings to select the Hysteria2 obfuscation type and configure Gecko min/max packet sizes.
  • Documentation

    • Added a guide for using the Hysteria2 Gecko sidecar.
  • Bug Fixes

    • Improved background cleanup to include the Hysteria2 native component.

Walkthrough

Adds Hysteria2 Gecko obfuscation support to NekoBox for Android via a bundled apernet/hysteria official Android binary sidecar (libhysteria2.so). Extends HysteriaBean serialization (v7→v8), introduces buildHysteria2SidecarConfig, adds a new BoxInstance launch branch for the sidecar, updates all four CI/build workflows to replace the standalone Mieru job with a combined sidecars job that downloads and verifies both libmieru.so and libhysteria2.so.

Changes

App: Hysteria2 Gecko Obfuscation Sidecar

Layer / File(s) Summary
HysteriaBean data model and serialization
app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaBean.java, app/src/main/java/io/nekohasekai/sagernet/Constants.kt, app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt
HysteriaBean gains hysteria2ObfsType, geckoMinPacketSize, geckoMaxPacketSize fields plus OBFS_NONE/SALAMANDER/GECKO constants; initializeDefaultValues() derives backward-compatible defaults; serialization bumps from version 7 to 8 with conditional field read/write. Key gets three new storage constants; DataStore adds three profileCacheStore-backed properties.
HysteriaFmt: URL parsing, URI serialization, sidecar config builder
app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt
parseHysteria2 reads new obfs query params; toUri() emits Gecko or Salamander params; canUseSingBox() returns false for Gecko; buildSingBoxOutboundHysteriaBean() gates obfs emission on non-blank password and non-OBFS_NONE; new buildHysteria2SidecarConfig() generates full JSON sidecar config with TLS, conditional obfs block, QUIC socket protection, and loopback SOCKS5 listener.
BoxInstance init/launch and Executable registration
app/src/main/java/io/nekohasekai/sagernet/bg/proto/BoxInstance.kt, app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt
Executable.EXECUTABLES gains libhysteria2.so. BoxInstance.init() selects hysteria2-plugin and builds sidecar config for protocolVersion==2+OBFS_GECKO. BoxInstance.launch() writes hysteria2_*.json to cache and starts hysteria2-plugin with --config, --log-level, --disable-update-check, and mode=client.
UI preferences and Android resources
app/src/main/java/io/nekohasekai/sagernet/ui/profile/HysteriaSettingsActivity.kt, app/src/main/res/xml/hysteria_preferences.xml, app/src/main/res/values/arrays.xml, app/src/main/res/values/strings.xml
HysteriaSettingsActivity copies HY2 fields to/from DataStore and adds an obfs type selector, obfs password, and Gecko min/max packet fields with updateObfs() visibility toggling. New hysteria2_obfs_type arrays and three string labels are added; the preferences XML gains SimpleMenuPreference for obfs type and two EditTextPreference fields for Gecko packet sizes.
Gecko sidecar design documentation
docs/maintenance/hysteria2-gecko-sidecar.md
Documents the sidecar architecture, FD-protect socket integration, routing model, data model, sidecar config YAML generation, binary packaging steps, BoxInstance wiring, UI changes, verification checklist, and scope guard.

CI/Build Pipeline: Sidecars Job

Layer / File(s) Summary
All workflows: sidecars job and artifact verification
.github/workflows/build.yml, .github/workflows/ci.yml, .github/workflows/preview.yml, .github/workflows/release.yml
All four workflows gain HYSTERIA_VERSION, replace the mieru job with a sidecars job using a combined cache key and a gated Hysteria2 Download step, update jobs.build.needs to sidecars, and verify both libmieru.so and libhysteria2.so per ABI.
Hysteria2 download and installation script
buildScript/lib/hysteria2.sh
Pins v2.9.2, downloads per-ABI libhysteria2.so binaries from GitHub releases, verifies SHA256 against hashes.txt, marks files executable, and installs to app/executableSo/<abi>/.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant HysteriaSettingsActivity
  participant HysteriaBean
  participant BoxInstance
  participant buildHysteria2SidecarConfig
  participant hysteria2_plugin

  rect rgba(70, 130, 180, 0.5)
    note over User, HysteriaSettingsActivity: Profile Configuration
    User->>HysteriaSettingsActivity: select Gecko obfs type + min/max packet
    HysteriaSettingsActivity->>HysteriaBean: serialize fields (hysteria2ObfsType, geckoMin/MaxPacketSize)
  end

  rect rgba(34, 139, 34, 0.5)
    note over BoxInstance, hysteria2_plugin: Connection Launch
    BoxInstance->>HysteriaBean: protocolVersion==2 && OBFS_GECKO?
    HysteriaBean-->>BoxInstance: true
    BoxInstance->>buildHysteria2SidecarConfig: port, protectPath
    buildHysteria2SidecarConfig-->>BoxInstance: JSON config (TLS, Gecko obfs, SOCKS5 listener)
    BoxInstance->>hysteria2_plugin: write hysteria2_*.json to cache dir
    BoxInstance->>hysteria2_plugin: exec --config --log-level --disable-update-check mode=client
    hysteria2_plugin-->>BoxInstance: process started
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • hawkff/NekoBoxForAndroid#12: Both PRs modify the same native-bundling CI/workflow wiring to handle libmieru.so (main PR now bundles/validates it alongside libhysteria2.so via a sidecars job) and both change Executable.EXECUTABLES to include bundled native libraries for cleanup.

Poem

🐇 A gecko hops in, with packets just right,
New sidecar in place, obfuscation's tight.
The CI now bundles two .so files with care,
Libhysteria2 rides the QUIC through the air.
From build script to BoxInstance, all wired and true —
The rabbit ships Gecko in version-8 stew! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding Hysteria2 Gecko obfuscation via a bundled sidecar binary, which aligns with the changeset's primary objective.
Description check ✅ Passed The description provides comprehensive information about the changes, explaining both the what (adding Gecko obfs sidecar support) and the why (avoiding core re-platforming), directly relating to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@hawkff hawkff marked this pull request as ready for review June 16, 2026 12:24
@hawkff

hawkff commented Jun 16, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

Please focus on: Hysteria2 obfs-type backward compatibility (kryo v7->8 deserialize for old Salamander/no-obfs profiles), the sidecar config correctness (obfs.gecko + fdControlUnixSocket protect path), routing (canUseSingBox false for Gecko -> external socks outbound), and binary integrity (SHA256 verification against hashes.txt).

Note on a likely finding: the obfs password field is shown for BOTH Salamander AND Gecko (type != OBFS_NONE). This is correct — Gecko obfs REQUIRES a password (apernet/hysteria clientConfigObfsGecko.Password / WrapPacketConnGecko uses it), same as Salamander. The gecko min/max packet-size fields already use EditTextPreferenceModifiers.Number (the codebase's numeric-input pattern), consistent with the other numeric prefs on this screen.

@hawkff

hawkff commented Jun 16, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt (1)

356-362: ⚡ Quick win

Restrict native HY2 obfs emission to explicit Salamander type.

This block always writes type = "salamander", but the guard currently allows any non-NONE type. Tightening the condition keeps this method self-consistent and avoids silent mis-encoding if routing conditions change.

Suggested patch
-            if (bean.obfuscation.isNotBlank() && bean.hysteria2ObfsType != HysteriaBean.OBFS_NONE) {
+            if (bean.obfuscation.isNotBlank() && bean.hysteria2ObfsType == HysteriaBean.OBFS_SALAMANDER) {
                 // Native sing-box core only supports Salamander; Gecko goes through the
                 // bundled hysteria binary sidecar (canUseSingBox() == false for Gecko).
                 obfs = SingBoxOptions.Hysteria2Obfs().apply {
                     type = "salamander"
                     password = bean.obfuscation
                 }
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt` around
lines 356 - 362, The guard condition for the obfuscation block checks only that
bean.hysteria2ObfsType is not OBFS_NONE, but the code inside always sets type to
"salamander". Tighten the condition to explicitly check that
bean.hysteria2ObfsType equals the Salamander constant (e.g.,
HysteriaBean.OBFS_SALAMANDER or equivalent) instead of just checking for
non-NONE values. This ensures the native sing-box core only emits Salamander
obfuscation when that specific type is configured, avoiding silent mis-encoding
if other obfs types are set.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 48-53: Pin the mutable version tags for GitHub Actions to
immutable full commit SHAs to improve supply-chain security across all workflow
files. In `.github/workflows/ci.yml` at lines 48-53, replace
`actions/checkout@v5` with its full commit SHA and `actions/cache@v5` with its
full commit SHA. Apply the same changes in `.github/workflows/build.yml` at
lines 43-49 for both `actions/checkout@v5` and `actions/cache@v5`. Similarly,
update both action references in `.github/workflows/preview.yml` at lines 39-44
to use full commit SHAs instead of version tags. Finally, make the same
replacements for both actions in `.github/workflows/release.yml` at lines 45-50.
Use the format `uses: owner/repo@<full-40-character-commit-sha>` for each
action.
- Around line 43-48: The sidecars jobs in multiple workflow files lack
least-privilege security controls. In `.github/workflows/ci.yml` lines 43-48,
`.github/workflows/build.yml` lines 38-43, `.github/workflows/preview.yml` lines
34-39, and `.github/workflows/release.yml` lines 40-45, add a `permissions`
block at the job level set to `{ contents: read }` (or tighter scope if
applicable), and modify the `actions/checkout` step to include
`persist-credentials: false`. This prevents overly permissive token handling
when running scripts that follow the checkout action.

In `@app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt`:
- Around line 106-111: Add validation checks for the gecko packet-size
parameters across all three affected locations in HysteriaFmt.kt. After parsing
obfs-min-packet-size into geckoMinPacketSize and obfs-max-packet-size into
geckoMaxPacketSize (lines 106-111), verify that both values are positive
(greater than zero) and that the minimum does not exceed the maximum; if
validation fails, either skip invalid values or log an error to prevent sidecar
config failures. Apply identical validation logic at lines 178-179 and lines
432-439 where similar packet-size parameters are parsed and assigned.

In `@buildScript/lib/hysteria2.sh`:
- Around line 20-21: The curl commands used to download the hashes file and
binary assets lack resilience to transient network issues. Add retry and timeout
controls to both curl invocations: first, enhance the curl command on line 20
that fetches the hashes.txt file by adding the flags --retry 3
--retry-all-errors --connect-timeout 15 and --max-time to set appropriate
timeouts; second, apply the same retry and timeout flags to the curl command on
line 31 that downloads the binary assets to ensure both external downloads are
protected against flaky network conditions.

In `@docs/maintenance/hysteria2-gecko-sidecar.md`:
- Around line 68-76: The CI documentation section currently describes adding a
separate "Native Build (Hysteria2)" job, but according to the PR summary,
Hysteria2 should share the combined sidecars workflow with libmieru.so instead
of having its own pipeline. Update the CI bullet point to reflect this actual
workflow structure by replacing the reference to a separate "Native Build
(Hysteria2)" job with wording that indicates Hysteria2 is integrated into the
combined sidecars workflow alongside libmieru.so.
- Around line 78-82: Update the launch() section in the BoxInstance wiring
documentation to reflect the actual command-line flags used by the
hysteria2-plugin sidecar. Replace the example command that shows
`libhysteria2.so client -c <file>` with the correct invocation that includes the
actual sidecar flags: `--disable-update-check --config <file> --log-level ...
client`. This ensures the documentation accurately represents the implementation
rather than the official CLI contract, preventing readers from copying incorrect
flag syntax.

---

Nitpick comments:
In `@app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt`:
- Around line 356-362: The guard condition for the obfuscation block checks only
that bean.hysteria2ObfsType is not OBFS_NONE, but the code inside always sets
type to "salamander". Tighten the condition to explicitly check that
bean.hysteria2ObfsType equals the Salamander constant (e.g.,
HysteriaBean.OBFS_SALAMANDER or equivalent) instead of just checking for
non-NONE values. This ensures the native sing-box core only emits Salamander
obfuscation when that specific type is configured, avoiding silent mis-encoding
if other obfs types are set.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1b327831-862f-4c0a-8862-eff62824bccf

📥 Commits

Reviewing files that changed from the base of the PR and between 42094a3 and 4b985ad.

📒 Files selected for processing (16)
  • .github/workflows/build.yml
  • .github/workflows/ci.yml
  • .github/workflows/preview.yml
  • .github/workflows/release.yml
  • app/src/main/java/io/nekohasekai/sagernet/Constants.kt
  • app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt
  • app/src/main/java/io/nekohasekai/sagernet/bg/proto/BoxInstance.kt
  • app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt
  • app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaBean.java
  • app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt
  • app/src/main/java/io/nekohasekai/sagernet/ui/profile/HysteriaSettingsActivity.kt
  • app/src/main/res/values/arrays.xml
  • app/src/main/res/values/strings.xml
  • app/src/main/res/xml/hysteria_preferences.xml
  • buildScript/lib/hysteria2.sh
  • docs/maintenance/hysteria2-gecko-sidecar.md

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml
Comment thread buildScript/lib/hysteria2.sh Outdated
Comment thread docs/maintenance/hysteria2-gecko-sidecar.md
Comment thread docs/maintenance/hysteria2-gecko-sidecar.md Outdated
- buildHysteria2SidecarConfig: clamp gecko min/max to hysteria's accepted
  bounds (1 <= min <= max <= 2048) to avoid emitting an invalid config.
- Document why the obfs password field is shown for both Salamander and Gecko
  (Gecko requires a password too).
@hawkff

hawkff commented Jun 16, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Addressed review feedback:

  • buildScript/lib/hysteria2.sh: added SHA256 verification of each downloaded binary against the official hashes.txt.
  • buildHysteria2SidecarConfig: clamp gecko min/max packet sizes to 1 <= min <= max <= 2048.
  • Documented why the obfs password is shown for both Salamander and Gecko.

Declined (with rationale): the suggestion to hide the obfs password for Gecko is incorrect — Gecko obfs REQUIRES a password (apernet/hysteria clientConfigObfsGecko.Password is mandatory; WrapPacketConnGecko uses it), same as Salamander. The gecko min/max fields already use the codebase's EditTextPreferenceModifiers.Number numeric-input pattern (consistent with the screen's other numeric prefs), so a separate android:inputType in XML is redundant.

Local coderabbit CLI review is now clean (0 findings). Builds (debug+release) pass with libhysteria2.so packaged for all 4 ABIs.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

@hawkff Thanks for the thorough update! The addressed items cover the four critical areas well:

  • SHA256 verification against hashes.txt is now in place for all four ABI binaries — solid integrity check.
  • Packet size clamping (1 ≤ min ≤ max ≤ 2048) prevents invalid sidecar configs at runtime.
  • The rationale for showing the obfs password for both Salamander and Gecko is sound — clientConfigObfsGecko.Password is mandatory in the upstream apernet/hysteria client, so hiding it for Gecko would break the feature.
  • The EditTextPreferenceModifiers.Number approach is consistent with the codebase pattern; a redundant android:inputType in XML is not needed.

Triggering a fresh review pass now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

…c accuracy

- Add top-level permissions blocks: contents:read for ci/build/preview, contents:write
  for release (it publishes via ghr). Caps the default GITHUB_TOKEN scope for the jobs
  that run ./run sidecar scripts.
- hysteria2.sh: add curl --retry/--max-time to the hashes.txt fetch and binary downloads.
- Fix the design doc to describe the combined 'sidecars' CI job and the actual sidecar
  launch flags (--disable-update-check --config <file> --log-level <level> client).
@hawkff hawkff merged commit ae7c87c into main Jun 16, 2026
2 of 3 checks passed
@hawkff hawkff deleted the feature/hysteria2-gecko-sidecar branch June 16, 2026 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant