Skip to content

feat: AmneziaWG outbound#25

Merged
hawkff merged 4 commits into
mainfrom
feature/amneziawg
Jun 18, 2026
Merged

feat: AmneziaWG outbound#25
hawkff merged 4 commits into
mainfrom
feature/amneziawg

Conversation

@hawkff

@hawkff hawkff commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Summary

Adds AmneziaWG as a native sing-box outbound — an obfuscated WireGuard variant that evades DPI via junk packets (Jc/Jmin/Jmax), randomized packet-size prefixes (S1-S4), magic-header obfuscation (H1-H4), and optional CPS signature packets (I1-I5). With all obfuscation params zero, it behaves like plain WireGuard.

Verified end-to-end on-device: handshake completes, egress IP is the AmneziaWG server, confirmed via ipleak.net.

App changes (mirror the WireGuard type; TYPE_AWG = 26)

  • AmneziaWGBean + AmneziaWGFmt (buildSingBoxOutboundAmneziaWGBean)
  • Outbound_AmneziaWGOptions in SingBoxOptions
  • ProxyEntity / TypeMap ("awg") / KryoConverters / ConfigBuilder
  • AmneziaWGSettingsActivity + amneziawg_preferences.xml + manifest entry
  • profile-create menu entry + strings
  • RawUpdater.parseAmneziaWG + .conf auto-detection (QR / clipboard / file import)
  • Room schema bump v8 → v9 (new awgBean column)
  • libcore/box_include.go registers the amneziawg outbound

Serializer fix

Also fixes an infinite-recursion StackOverflowError in SingBoxOptionSerializer (the delegate adapter re-entered the same type-hierarchy serializer), which surfaced as a stack size NNNNKB connection failure whenever a newly-added outbound type was serialized. Now serializes via a plain Gson tree and merges _hack_config_map/_hack_custom_config recursively.

Native dependency

Requires the matching sing-box fork branch hawkff/sing-box@feature/amneziawg: adds transport/amneziawg (drives upstream amnezia-vpn/amneziawg-go as a pristine dependency), protocol/amneziawg, and option.AmneziaWGOutboundOptions.

Note: libcore/go.mod currently uses replace ... => ../../sing-box (local sibling checkout), so CI's libcore build will not resolve sing-box until the replace is repointed at the fork. This PR is for code review of the app-side wiring; the native build wiring will be finalized separately.

Test plan

  • Import via QR scan (.conf with AmneziaWG params)
  • Import via clipboard/file
  • Connect → handshake + egress verified
  • DNS settings tuning (DoT over tunnel; tracked separately)

Greptile Summary

This PR adds AmneziaWG (an obfuscated WireGuard variant) as a native sing-box outbound (type = "amneziawg", TYPE_AWG = 26), and fixes an infinite-recursion StackOverflowError in SingBoxOptionSerializer that surfaced whenever a newly-added outbound type was serialized.

  • AmneziaWG outbound: New AmneziaWGBean + AmneziaWGFmt, Outbound_AmneziaWGOptions, settings activity, preferences XML, RawUpdater.parseAmneziaWG, .conf auto-detection (including all I1–I5 keys), TypeMap/KryoConverters registration, and amneziawg.RegisterOutbound in the Go layer; Room schema bumped to v9 with a new awgBean column.
  • Serializer fix: SingBoxOptionSerializer now calls gsonSingboxPlain.toJsonTree(src) (bypassing the hierarchy adapter) instead of delegating through the Gson context, which re-entered the same adapter for subtype instances and caused a stack overflow; applyHackConfig is then applied recursively to merge _hack_config_map / _hack_custom_config.
  • Native dependency: libcore/go.mod uses a local replace directive pointing to the hawkff/sing-box fork; buildScript/lib/core/get_source.sh clones that fork at a pinned commit so the CI build resolves correctly when the script runs first.

Confidence Score: 4/5

Safe to merge for new installs; existing v8 users will lose all saved proxies on upgrade due to a missing database migration that was flagged in a prior review pass.

The app-side wiring is thorough and self-consistent: every dispatch site (putByteArray, requireBean, displayType, ConfigBuilder, TypeMap, KryoConverters) handles TYPE_AWG, and the serializer fix correctly breaks the stack-overflow cycle. The unresolved issue is SagerDatabase.kt: the autoMigrations list stops at 7→8 with no AutoMigration(from=8, to=9) entry, so the Room framework falls back to destructive migration and silently wipes all proxy data for anyone upgrading from v8.

app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt — the missing AutoMigration(from=8, to=9) entry is the only blocking concern.

Important Files Changed

Filename Overview
app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt DB version bumped to 9 but autoMigrations stops at 7→8; no AutoMigration(from=8, to=9) is registered, so upgrades from v8 fall through to fallbackToDestructiveMigration(), erasing all saved proxies.
app/src/main/java/io/nekohasekai/sagernet/fmt/amneziawg/AmneziaWGBean.java New bean for AmneziaWG; Kryo serialization, default initialization, and clone() mirror the WireGuard pattern cleanly. All 17 obfuscation params (Jc/Jmin/Jmax, S1-S4, H1-H4, I1-I5) are covered.
app/src/main/java/io/nekohasekai/sagernet/fmt/amneziawg/AmneziaWGFmt.kt Outbound builder correctly omits zero/blank obfuscation fields; jmin/jmax are emitted independently with no guard against jmin > jmax, which can produce an invalid native config.
app/src/main/java/io/nekohasekai/sagernet/database/ProxyEntity.kt TYPE_AWG=26 added with a clear comment explaining why 25 is reserved; all switch arms (putByteArray, displayType, requireBean, haveStandardLink) include the new type consistently.
app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt isAmneziaWGConf now detects all AmneziaWG param families (J*, S*, H*, I*); parseAmneziaWG mirrors parseWireGuard structure correctly.
app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java SingBoxOptionSerializer infinite-recursion fix is correct (uses gsonSingboxPlain.toJsonTree instead of context delegation); Outbound_AmneziaWGOptions adds all obfuscation fields mirroring the bean.
libcore/box_include.go amneziawg.RegisterOutbound(registry) is correctly inserted alongside wireguard; no endpoint registration needed for amneziawg (consistent with WireGuard-as-outbound path).
libcore/go.mod Local replace directive points sing-box to ../../sing-box; get_source.sh clones the hawkff fork to that path, so CI builds that run the script first should resolve correctly. Acknowledged in the PR description.
app/src/main/java/io/nekohasekai/sagernet/ui/profile/AmneziaWGSettingsActivity.kt Settings activity cleanly mirrors WireGuardSettingsActivity; all 17 obfuscation params bound via PreferenceBindingManager with correct type converters.
app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt AmneziaWGBean dispatch inserted correctly; is AmneziaWGBean is checked after is WireGuardBean (no type-hierarchy conflict since they share only AbstractBean).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["User: import .conf / QR / clipboard"] --> B{"isAmneziaWGConf?\n(any of Jc/Jmin/Jmax,\nS1-S4, H1-H4, I1-I5 present)"}
    B -- Yes --> C["parseAmneziaWG(conf)\n→ List<AmneziaWGBean>"]
    B -- No --> D["parseWireGuard(conf)\n→ List<WireGuardBean>"]
    C --> E["ProxyEntity(TYPE_AWG=26,\nawgBean=AmneziaWGBean)"]
    E --> F["Room DB v9\n(awgBean BLOB column)"]
    E --> G["ConfigBuilder\nbuildSingBoxOutboundAmneziaWGBean"]
    G --> H["Outbound_AmneziaWGOptions\ntype='amneziawg'"]
    H --> I["SingBoxOptionSerializer\ngsonSingboxPlain.toJsonTree(src)\n+ applyHackConfig"]
    I --> J["sing-box JSON config"]
    J --> K["libcore: amneziawg.RegisterOutbound\n(hawkff/sing-box fork)"]
    K --> L["amnezia-vpn/amneziawg-go v1.0.4\nhandshake + DPI evasion"]
    M["AmneziaWGSettingsActivity\n(manual profile creation)"] --> E
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["User: import .conf / QR / clipboard"] --> B{"isAmneziaWGConf?\n(any of Jc/Jmin/Jmax,\nS1-S4, H1-H4, I1-I5 present)"}
    B -- Yes --> C["parseAmneziaWG(conf)\n→ List<AmneziaWGBean>"]
    B -- No --> D["parseWireGuard(conf)\n→ List<WireGuardBean>"]
    C --> E["ProxyEntity(TYPE_AWG=26,\nawgBean=AmneziaWGBean)"]
    E --> F["Room DB v9\n(awgBean BLOB column)"]
    E --> G["ConfigBuilder\nbuildSingBoxOutboundAmneziaWGBean"]
    G --> H["Outbound_AmneziaWGOptions\ntype='amneziawg'"]
    H --> I["SingBoxOptionSerializer\ngsonSingboxPlain.toJsonTree(src)\n+ applyHackConfig"]
    I --> J["sing-box JSON config"]
    J --> K["libcore: amneziawg.RegisterOutbound\n(hawkff/sing-box fork)"]
    K --> L["amnezia-vpn/amneziawg-go v1.0.4\nhandshake + DPI evasion"]
    M["AmneziaWGSettingsActivity\n(manual profile creation)"] --> E
Loading

Comments Outside Diff (1)

  1. app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt, line 17-27 (link)

    P1 Missing AutoMigration 8 → 9

    The database version was bumped to 9, but the autoMigrations list stops at from = 7, to = 8 with no AutoMigration(from = 8, to = 9) entry. Both 8.json and 9.json schema files are present, so Room could generate this migration automatically. As written, any user upgrading from v8 will hit fallbackToDestructiveMigration(), silently erasing all of their saved proxy configurations.

Reviews (4): Last reviewed commit: "ci: build libcore against hawkff/sing-bo..." | Re-trigger Greptile

Add AmneziaWG as a native sing-box outbound: an obfuscated WireGuard
variant that evades DPI via junk packets (Jc/Jmin/Jmax), randomized
packet-size prefixes (S1-S4), and magic-header obfuscation (H1-H4) plus
optional CPS signatures (I1-I5). With all params zero it behaves like
plain WireGuard.

App wiring (mirrors the existing WireGuard type, TYPE_AWG=26):
- AmneziaWGBean + AmneziaWGFmt (buildSingBoxOutboundAmneziaWGBean)
- Outbound_AmneziaWGOptions in SingBoxOptions
- ProxyEntity / TypeMap ("awg") / KryoConverters / ConfigBuilder
- AmneziaWGSettingsActivity + amneziawg_preferences.xml + manifest entry
- profile-create menu entry + strings
- RawUpdater: parseAmneziaWG + .conf auto-detection for QR/clipboard/file
- Room schema bump v8 -> v9 (new awgBean column)
- libcore box_include.go registers the amneziawg outbound

Also fixes an infinite-recursion StackOverflow in SingBoxOptionSerializer
(delegate adapter re-entered the same type-hierarchy serializer), which
surfaced as a 'stack size NNNNKB' connection failure on new outbound
types; serialize via a plain Gson tree and merge hacks recursively.

Verified end-to-end on-device from a censored test network: handshake
completes and egress IP is the AmneziaWG server.

Requires the matching sing-box fork branch (hawkff/sing-box
feature/amneziawg: transport/amneziawg + protocol/amneziawg + options).
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AmneziaWG (an obfuscated WireGuard variant) is added as proxy type 26 across the full stack: a new AmneziaWGBean data model with DPI-evasion parameters, Room database schema version bump to 9, SingBox Outbound_AmneziaWGOptions with a refactored serializer using reflection-based JSON tree mutation, INI config parser with obfuscation-key detection, Go libcore outbound registration, and a new Android settings UI activity with preference binding.

Changes

AmneziaWG Proxy Type

Layer / File(s) Summary
AmneziaWGBean data model and Kryo serialization
app/src/main/java/io/nekohasekai/sagernet/fmt/amneziawg/AmneziaWGBean.java, app/src/main/java/io/nekohasekai/sagernet/fmt/KryoConverters.java
AmneziaWGBean extends AbstractBean with WireGuard fields (local address, keys, MTU) plus AmneziaWG obfuscation parameters (jc/jmin/jmax, s1–s4, h1–h4, i1–i5), implements fixed-order Kryo serialize/deserialize, returns false from canTCPing(), provides clone() via KryoConverters, and introduces amneziaWGDeserialize TypeConverter for Room.
SingBox serializer refactor and Outbound_AmneziaWGOptions
app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java
Adds gsonSingboxPlain Gson instance and reflection-based imports. Rewrites SingBoxOptionSerializer.serialize to convert to plain JSON tree via gsonSingboxPlain, then recursively apply _hack_config_map and _hack_custom_config through public non-static fields. Introduces Outbound_AmneziaWGOptions as Outbound subclass with all AmneziaWG connection and obfuscation fields.
ProxyEntity wiring, TypeMap, and Room schema version 9
app/src/main/java/io/nekohasekai/sagernet/database/ProxyEntity.kt, app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt, app/src/main/java/io/nekohasekai/sagernet/fmt/TypeMap.kt, app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/9.json
Adds TYPE_AWG=26 constant and awgBean field to ProxyEntity, wires deserialization via amneziaWGDeserialize, extends displayType(), requireBean(), haveStandardLink(), putBean(), and settingIntent() for TYPE_AWG. Maps "awg" string to TYPE_AWG in TypeMap. Bumps SagerDatabase version to 9 and includes generated Room schema JSON.
AmneziaWG INI parsing and outbound building
app/src/main/java/io/nekohasekai/sagernet/fmt/amneziawg/AmneziaWGFmt.kt, app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt, app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt
buildSingBoxOutboundAmneziaWGBean converts AmneziaWGBean to Outbound_AmneziaWGOptions, conditionally including obfuscation parameters only when non-zero/non-blank. ConfigBuilder dispatches AmneziaWGBean to the builder. RawUpdater adds isAmneziaWGConf predicate to detect obfuscation keys in INI [Interface] sections and parseAmneziaWG function to parse per-peer AmneziaWGBean instances from interface and peer blocks.
AmneziaWGSettingsActivity, preferences UI, manifest, and menu
app/src/main/java/io/nekohasekai/sagernet/ui/profile/AmneziaWGSettingsActivity.kt, app/src/main/res/xml/amneziawg_preferences.xml, app/src/main/AndroidManifest.xml, app/src/main/res/menu/add_profile_menu.xml, app/src/main/res/values/strings.xml, app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt
AmneziaWGSettingsActivity wires all bean fields to PreferenceBindingManager, synchronizes cache during init() and serialize(), and defines preference fragment with EditTextPreferenceModifiers for numeric fields and PasswordSummaryProvider for private key. amneziawg_preferences.xml defines standard WireGuard settings and AmneziaWG obfuscation parameter preferences. Activity registered in manifest. Menu item action_new_awg and string action_amneziawg added. ConfigurationFragment launches the activity from menu selection.
Libcore outbound registration and Go dependencies
libcore/box_include.go, libcore/go.mod
Imports and registers amneziawg protocol in nekoboxAndroidOutboundRegistry. Adds github.com/amnezia-vpn/amneziawg-go v1.0.4 and transitive indirect dependencies (abool, atomic) to go.mod.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant ConfigurationFragment
  participant AmneziaWGSettingsActivity
  participant ProxyEntity
  participant RawUpdater
  participant ConfigBuilder
  participant SingBoxOutbound

  User->>ConfigurationFragment: select action_new_awg
  ConfigurationFragment->>AmneziaWGSettingsActivity: startActivity
  AmneziaWGSettingsActivity->>ProxyEntity: createEntity() → AmneziaWGBean
  User->>AmneziaWGSettingsActivity: configure obfuscation params
  AmneziaWGSettingsActivity->>ProxyEntity: serialize bean to awgBean
  ProxyEntity->>ProxyEntity: store in database (schema v9)

  Note over RawUpdater: On import from file
  RawUpdater->>RawUpdater: isAmneziaWGConf?
  RawUpdater->>RawUpdater: parseAmneziaWG → List<AmneziaWGBean>

  Note over ConfigBuilder: On VPN start
  ConfigBuilder->>ConfigBuilder: AmneziaWGBean dispatch
  ConfigBuilder->>SingBoxOutbound: buildSingBoxOutboundAmneziaWGBean
  SingBoxOutbound-->>ConfigBuilder: Outbound_AmneziaWGOptions{jc,jmin,jmax,s1–s4,h1–h4,i1–i5}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

🐰 A new tunnel hops through the noise,
With junk packets and magic as decoys,
jc, jmin, jmax set the beat,
AmneziaWG makes DPI obsolete,
The rabbit tunnels on, discreet! 🕳️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.57% 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 'feat: AmneziaWG outbound' directly and clearly describes the primary change: adding AmneziaWG as a new outbound proxy type.
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.
Description check ✅ Passed The PR description comprehensively documents the AmneziaWG implementation, serializer fix, test plan, and CI build requirements. All major changes are clearly explained with context about obfuscation parameters, type ID design decisions, and known limitations.

✏️ 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 changed the title feat: AmneziaWG outbound (obfuscated WireGuard) feat: AmneziaWG outbound Jun 18, 2026
Comment thread app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt Outdated
Comment thread app/src/main/java/io/nekohasekai/sagernet/database/ProxyEntity.kt
Comment thread app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
app/src/main/java/io/nekohasekai/sagernet/database/ProxyEntity.kt (1)

427-448: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear snellBean in the putBean reset block.

On Lines 428-448, all protocol beans are nulled before assignment except snellBean. That leaves stale Snell credentials persisted after type switches.

Suggested fix
     fun putBean(bean: AbstractBean): ProxyEntity {
         socksBean = null
         httpBean = null
         ssBean = null
         ssrBean = null
         vmessBean = null
         trojanBean = null
         trojanGoBean = null
         mieruBean = null
         naiveBean = null
         hysteriaBean = null
         sshBean = null
         wgBean = null
         awgBean = null
         tuicBean = null
         juicityBean = null
         shadowTLSBean = null
         anyTLSBean = null
         chainBean = null
+        snellBean = null
         configBean = null
         nekoBean = null
🤖 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/database/ProxyEntity.kt` around
lines 427 - 448, The putBean method in ProxyEntity is missing the reset for
snellBean when clearing all protocol beans before assignment. Add snellBean =
null to the list of bean nullifications in the putBean function along with the
other protocol beans (socksBean, httpBean, ssBean, ssrBean, vmessBean,
trojanBean, trojanGoBean, mieruBean, naiveBean, hysteriaBean, sshBean, wgBean,
awgBean, tuicBean, juicityBean, shadowTLSBean, anyTLSBean, chainBean,
configBean, nekoBean). This will ensure stale Snell credentials are not retained
when switching protocol types.
app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt (1)

19-26: ⚠️ Potential issue | 🟠 Major

Add a non-destructive Room migration path for v8 → v9.

Line 19 bumps to v9, but Lines 20-26 don't include AutoMigration(from = 8, to = 9). With Line 42 fallbackToDestructiveMigration(), upgrades from v8 will trigger destructive migration, wiping saved profiles.

Suggested fix
     autoMigrations = [
         AutoMigration(from = 3, to = 4),
         AutoMigration(from = 4, to = 5),
         AutoMigration(from = 5, to = 6),
         AutoMigration(from = 6, to = 7),
-        AutoMigration(from = 7, to = 8)
+        AutoMigration(from = 7, to = 8),
+        AutoMigration(from = 8, to = 9)
     ]
🤖 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/database/SagerDatabase.kt` around
lines 19 - 26, The database version is incremented to 9 but the autoMigrations
array is missing the migration path from version 8 to 9. This causes the
fallbackToDestructiveMigration() fallback to trigger during upgrades from v8,
destroying user data. Add AutoMigration(from = 8, to = 9) to the autoMigrations
array in the Database annotation to provide a non-destructive migration path for
this version bump.
🤖 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 `@app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt`:
- Around line 988-989: The AmneziaWG auto-detection logic in RawUpdater.kt at
the listOf statement is missing the CPS signature keys I1 through I5, which
causes profiles using only those fields to be incorrectly parsed as plain
WireGuard. Add the strings I1, I2, I3, I4, and I5 to the listOf collection that
currently contains Jc, Jmin, Jmax, S1, S2, S3, S4, H1, H2, H3, H4 so that the
.any check properly detects all AmneziaWG profile variations.

---

Outside diff comments:
In `@app/src/main/java/io/nekohasekai/sagernet/database/ProxyEntity.kt`:
- Around line 427-448: The putBean method in ProxyEntity is missing the reset
for snellBean when clearing all protocol beans before assignment. Add snellBean
= null to the list of bean nullifications in the putBean function along with the
other protocol beans (socksBean, httpBean, ssBean, ssrBean, vmessBean,
trojanBean, trojanGoBean, mieruBean, naiveBean, hysteriaBean, sshBean, wgBean,
awgBean, tuicBean, juicityBean, shadowTLSBean, anyTLSBean, chainBean,
configBean, nekoBean). This will ensure stale Snell credentials are not retained
when switching protocol types.

In `@app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt`:
- Around line 19-26: The database version is incremented to 9 but the
autoMigrations array is missing the migration path from version 8 to 9. This
causes the fallbackToDestructiveMigration() fallback to trigger during upgrades
from v8, destroying user data. Add AutoMigration(from = 8, to = 9) to the
autoMigrations array in the Database annotation to provide a non-destructive
migration path for this version bump.
🪄 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: 2beef3fa-5c8b-4693-9795-a9a3dd22500d

📥 Commits

Reviewing files that changed from the base of the PR and between fea1121 and f64c414.

⛔ Files ignored due to path filters (1)
  • libcore/go.sum is excluded by !**/*.sum
📒 Files selected for processing (18)
  • app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/9.json
  • app/src/main/AndroidManifest.xml
  • app/src/main/java/io/nekohasekai/sagernet/database/ProxyEntity.kt
  • app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt
  • app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt
  • app/src/main/java/io/nekohasekai/sagernet/fmt/KryoConverters.java
  • app/src/main/java/io/nekohasekai/sagernet/fmt/TypeMap.kt
  • app/src/main/java/io/nekohasekai/sagernet/fmt/amneziawg/AmneziaWGBean.java
  • app/src/main/java/io/nekohasekai/sagernet/fmt/amneziawg/AmneziaWGFmt.kt
  • app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt
  • app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt
  • app/src/main/java/io/nekohasekai/sagernet/ui/profile/AmneziaWGSettingsActivity.kt
  • app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java
  • app/src/main/res/menu/add_profile_menu.xml
  • app/src/main/res/values/strings.xml
  • app/src/main/res/xml/amneziawg_preferences.xml
  • libcore/box_include.go
  • libcore/go.mod

Comment thread app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt Outdated
- isAmneziaWGConf now also checks the CPS signature keys I1-I5, so a
  .conf carrying only those AmneziaWG fields is no longer misparsed as
  plain WireGuard (dropping the AWG params). (CodeRabbit, Greptile)
- parseAmneziaWG error messages: 'selection' -> 'section'. (Greptile)
@hawkff

hawkff commented Jun 18, 2026

Copy link
Copy Markdown
Owner Author

Thanks for the reviews — pushed 151c67a addressing the I1–I5 detection gap (CodeRabbit Major / Greptile P2) and the 'selection' → 'section' wording.

On TYPE_AWG = 26 skipping 25: this is intentional. TYPE = 25 is reserved for the MasterDnsVPN sidecar type that lives on a separate feature branch (feature/masterdnsvpn-sidecar, PR #18). Using 25 here would collide when both branches merge. Persisted type IDs must be stable, so I'm deliberately reserving 25 rather than reusing it. The unhandled-type case already falls through to error("Undefined type $type") in requireBean(), consistent with how every other gap is handled.

The device-stack files and the parseWireGuard-derived error strings in the existing WireGuard path are kept verbatim for parity; only the new AmneziaWG code was corrected.

Clarify that TYPE_AWG=26 deliberately skips 25, which is reserved for the
MasterDnsVPN sidecar type on PR #18, so persisted type IDs stay stable when
both branches merge. (Greptile)
@hawkff

hawkff commented Jun 18, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Pushed:

The WireGuard-derived device-stack files and the existing parseWireGuard error strings are intentionally kept verbatim for parity; only the new AmneziaWG code paths were changed.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

@hawkff, acknowledged — triggering a fresh review now. I've noted the following for future interactions:

  1. TYPE_AWG = 26 skipping 25 — intentional; TYPE = 25 is reserved for the MasterDnsVPN sidecar type on the feature/masterdnsvpn-sidecar branch (PR #18). Persisted type IDs must remain stable, so 25 is deliberately held back to avoid collision on merge.
  2. WireGuard-derived device-stack files and parseWireGuard error strings — kept verbatim in the existing WireGuard code path for parity; only newly-written AmneziaWG-specific code was corrected.

✏️ Learnings added
Learnt from: hawkff
URL: https://github.com/hawkff/NekoBoxForAndroid/pull/25

Timestamp: 2026-06-18T02:34:22.342Z
Learning: In the NekoBox for Android repository (hawkff/NekoBoxForAndroid), `ProxyEntity.TYPE_AWG = 26` intentionally skips type ID 25. Type 25 is reserved for the `MasterDnsVPN` sidecar type that lives on the separate `feature/masterdnsvpn-sidecar` branch (PR `#18`). Persisted type IDs must remain stable to avoid data corruption on upgrade, so 25 is deliberately held back to prevent collision when both branches eventually merge.

Learnt from: hawkff
URL: https://github.com/hawkff/NekoBoxForAndroid/pull/25

Timestamp: 2026-06-18T02:34:22.342Z
Learning: In the NekoBox for Android repository (hawkff/NekoBoxForAndroid), the WireGuard-derived device-stack files and error strings in the existing `parseWireGuard` code path are intentionally kept verbatim for parity with the original WireGuard implementation. Only newly-written AmneziaWG-specific code paths (e.g., `parseAmneziaWG`) are subject to corrections in this PR.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ 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.

CI cloned starifly/sing-box and checked out a commit without the new
protocol/amneziawg + transport/amneziawg packages, so the Native Build
(LibCore) job failed resolving github.com/sagernet/sing-box/protocol/amneziawg.
Point get_source.sh at the hawkff fork and pin COMMIT_SING_BOX to the
AmneziaWG commit (ed45ea9) so the native build resolves the new packages.

The libcore go.mod replace (=> ../../sing-box) consumes this sibling checkout.
@hawkff hawkff merged commit beb64f5 into main Jun 18, 2026
5 checks passed
@hawkff hawkff deleted the feature/amneziawg branch June 23, 2026 00:45
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