mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-30 22:55:13 +08:00
🐤 Sync 2026-10-03 00:12:36
This commit is contained in:
1 parent
ce3df55b24
commit
cb1d978497
58 files changed
+1627
-1018
No files matched your search
@@ -1009,9 +1009,25 @@ fi
|
||||
# No shipped file may cite docs/. The whole directory is gitignored, so every
|
||||
# pointer to it is a dead link in a fresh clone - that is how README.md
|
||||
# came to reference an agent guide and an improvement plan that no
|
||||
# contributor can open. Kept here (with the docs/ pattern, not the names)
|
||||
# so the rule cannot quietly come back.
|
||||
DEAD_DOCS="$(grep -rlE 'docs/(adr|architecture-improvement-plan|homeproxy_architecture_refactor_agent_guide|audit-report|next-step-plan)' \
|
||||
# contributor can open.
|
||||
#
|
||||
# The pattern is deliberately *shape*-based, not a list of names. An earlier
|
||||
# version enumerated the offending documents
|
||||
# (adr|architecture-improvement-plan|homeproxy_architecture_refactor_agent_guide|
|
||||
# audit-report|next-step-plan) and therefore only ever caught those five: the
|
||||
# next document to be written - the gap analysis, the dated review reports -
|
||||
# walked straight past it, and a dozen comments across the generators, the
|
||||
# views and the test suite kept citing
|
||||
# `docs/linux.json 与 pro 的差距分析.md` with no gate noticing.
|
||||
# Matching `docs/` followed by anything catches every present and future name.
|
||||
#
|
||||
# The anchor is what keeps it from crying wolf. `htdocs/` contains the
|
||||
# substring `docs/`, and so does the `/docs/` of an external URL such as
|
||||
# https://github.com/anytls/anytls-go/blob/v0.0.8/docs/uri_scheme.md - both
|
||||
# are legitimate and must not be flagged. Requiring the character before
|
||||
# `docs/` to be neither alphanumeric nor `_`, `.`, `/`, `-` or `:` excludes
|
||||
# exactly those two shapes and keeps every real citation.
|
||||
DEAD_DOCS="$(grep -rlE '(^|[^:A-Za-z0-9_./-])docs/[^[:space:]]' \
|
||||
"$ROOT/README.md" "$ROOT/root" "$ROOT/htdocs" 2>/dev/null || true)"
|
||||
if [ -z "$DEAD_DOCS" ]; then
|
||||
pass "no shipped file cites the gitignored docs/ tree"
|
||||
@@ -1020,6 +1036,18 @@ else
|
||||
printf '%s\n' "$DEAD_DOCS"
|
||||
fi
|
||||
|
||||
# The same rule for the test tree, minus this file: a dead citation inside a
|
||||
# test is just as unresolvable for a contributor reading the failure, and the
|
||||
# generator suite carried six of them.
|
||||
DEAD_DOCS_TESTS="$(grep -rlE '(^|[^:A-Za-z0-9_./-])docs/[^[:space:]]' \
|
||||
"$ROOT/tests" 2>/dev/null | grep -v 'tests/arch-guard\.sh$' || true)"
|
||||
if [ -z "$DEAD_DOCS_TESTS" ]; then
|
||||
pass "no test file cites the gitignored docs/ tree either"
|
||||
else
|
||||
fail "these test files cite docs/ (gitignored, absent from every clone):"
|
||||
printf '%s\n' "$DEAD_DOCS_TESTS"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== guard 21: dnsmasq snippet writer is incremental =="
|
||||
|
||||
@@ -1716,9 +1744,8 @@ echo "== guard 38: append_custom_dns emits the HTTPS/SVCB reject as its first DN
|
||||
|
||||
# The proxy path emits this reject (append_proxy_dns line 102); the custom
|
||||
# path used to rely on whatever the user wrote, so a rule that targets the
|
||||
# same query_type could shadow the safety net. The fix (see
|
||||
# docs/linux.json 与 pro 的差距分析.md §2.2) prepends the same literal in
|
||||
# append_custom_dns. Two checks keep that ordering:
|
||||
# same query_type could shadow the safety net. The fix prepends the same
|
||||
# literal in append_custom_dns. Two checks keep that ordering:
|
||||
#
|
||||
# (a) the literal appears in BOTH append_proxy_dns and append_custom_dns;
|
||||
# (b) the second occurrence (the one inside append_custom_dns) comes
|
||||
@@ -1732,7 +1759,7 @@ if [ "$reject_count" -eq 2 ]; then
|
||||
pass "the HTTPS/SVCB reject appears in both append_proxy_dns and append_custom_dns"
|
||||
else
|
||||
fail "expected 2 occurrences of 'query_type: [64, 65]' in generator/dns.uc, found $reject_count"
|
||||
fail "the custom path lost its built-in reject; see §2.2 of the gap analysis"
|
||||
fail "the custom path lost its built-in reject (see guard 38 in this file)"
|
||||
fi
|
||||
|
||||
# (b): the custom-path reject is the SECOND occurrence (append_custom_dns
|
||||
@@ -1759,9 +1786,7 @@ fi
|
||||
|
||||
echo "== guard 39: sniffer_advanced_mode default stays at '0' =="
|
||||
|
||||
# §2.7 (linux.json 与 pro 的差距分析.md): the advanced-mode sniff profile
|
||||
|
||||
# §2.7 (linux.json 与 pro 的差距分析.md): the advanced-mode sniff profile
|
||||
# The advanced-mode sniff profile
|
||||
# (100ms / universal list) is gated behind a UCI opt-in so an upgrade
|
||||
# does not change the sniffer behaviour. The default must remain '0';
|
||||
# the generator falls back to '0' on a missing UCI value, and the
|
||||
@@ -1869,7 +1894,7 @@ fi
|
||||
|
||||
echo "== guard 41: experimental.cache_file is unconditional in attachExperimental() =="
|
||||
|
||||
# Review (2026-09-29, docs/review-report-20260929.md §1.4.3 / §5.1, P2 #3):
|
||||
# The 2026-09-29 review (P2 #3) found:
|
||||
# attachExperimental() used to wrap the experimental.cache_file block in
|
||||
# `if (routing_mode in ['bypass_mainland_china', 'custom'])`, leaving
|
||||
# gfwlist / proxy_mainland_china / global with cold-start DNS on every
|
||||
@@ -1921,7 +1946,7 @@ esac
|
||||
|
||||
echo "== guard 42: NAPTR_BYPASS_SUFFIXES is the only domain_suffix qtype-35 source =="
|
||||
|
||||
# Review (2026-09-29, docs/review-report-20260929.md §2.2.1, P2 #4): the three
|
||||
# The 2026-09-29 review (P2 #4) found: the three
|
||||
# NAPTR (qtype 35) bypass suffixes (r.10086.cn, 10086.cn, pub.3gppnetwork.org)
|
||||
# used to be inlined into a push() call inside append_proxy_dns() and the
|
||||
# comment that explained them was on the same line as the push. The fix
|
||||
@@ -1948,7 +1973,7 @@ fi
|
||||
echo
|
||||
echo "== guard 43: the rollback UCI snapshot matches the keys the intercept layer reads =="
|
||||
|
||||
# Review 2026-09-29 (docs/review-report-20260929-full.md §1.2-1.4, P2 #1/#2).
|
||||
# The 2026-09-29 review (P2 #1 / #2) found:
|
||||
#
|
||||
# reload_service rolls back by restoring the known-good sing-box file *and*
|
||||
# replaying a UCI snapshot of the keys that steer the network layer - the
|
||||
@@ -2339,6 +2364,50 @@ else
|
||||
pass "no view calls the non-existent form.Map.formvalue()"
|
||||
fi
|
||||
|
||||
echo "== guard 49: the i18n package name cannot drift from PKG_NAME =="
|
||||
|
||||
# luci.mk names the translation package from the *checkout directory*, not from
|
||||
# PKG_NAME:
|
||||
#
|
||||
# LUCI_NAME?=$(notdir ${CURDIR})
|
||||
# LUCI_BASENAME?=$(patsubst luci-$(LUCI_TYPE)-%,%,$(LUCI_NAME))
|
||||
# define Package/luci-i18n-$(LUCI_BASENAME)-$(1)
|
||||
#
|
||||
# PKG_NAME is pinned to luci-app-homeproxy-pro here, so with the repository cloned
|
||||
# under its own name (luci-app-homeproxy-pro, which is what every self-compiler
|
||||
# gets) the feed build emitted luci-i18n-homeproxy-pro-zh-cn while the published
|
||||
# apk was named by build-pkg.sh from PKG_NAME and came out
|
||||
# luci-i18n-homeproxy-pro-zh-cn. Two names, one project, and the person self-building
|
||||
# concludes the translation package is missing (issue #5).
|
||||
#
|
||||
# The check is that LUCI_BASENAME agrees with the PKG_NAME the release path uses,
|
||||
# computed here from the Makefile the way luci.mk would - not by re-deriving it
|
||||
# from this repository's own directory name, which is precisely the thing that
|
||||
# was wrong and would make the assertion vacuous.
|
||||
MAKEFILE="$ROOT/Makefile"
|
||||
MK_PKG_NAME="$(sed -n 's/^PKG_NAME:=//p' "$MAKEFILE" 2>"/dev/null" | head -1)"
|
||||
MK_LUCI_BASENAME="$(sed -n 's/^LUCI_BASENAME:=//p' "$MAKEFILE" 2>"/dev/null" | head -1)"
|
||||
|
||||
if [ -z "$MK_PKG_NAME" ]; then
|
||||
fail "PKG_NAME is not declared in the Makefile - nothing to keep the i18n name tied to"
|
||||
elif [ -z "$MK_LUCI_BASENAME" ]; then
|
||||
fail "LUCI_BASENAME is not pinned, so the i18n package name follows the checkout"
|
||||
fail " directory: cloning as luci-app-homeproxy-pro yields luci-i18n-homeproxy-pro-zh-cn"
|
||||
fail " while the release path names it luci-i18n-homeproxy-pro-zh-cn (issue #5)"
|
||||
else
|
||||
# luci.mk strips the "luci-<type>-" prefix; type is the 2nd dash-field.
|
||||
mk_type="$(printf '%s' "$MK_PKG_NAME" | awk -F- '{print $2}')"
|
||||
mk_expected_basename="$(printf '%s' "$MK_PKG_NAME" | sed -n "s/^luci-${mk_type}-//p")"
|
||||
|
||||
if [ "$MK_LUCI_BASENAME" = "$mk_expected_basename" ]; then
|
||||
pass "LUCI_BASENAME matches PKG_NAME, so the i18n package is named the same"
|
||||
pass " in the feed build and in the release (luci-i18n-${MK_LUCI_BASENAME}-zh-cn)"
|
||||
else
|
||||
fail "LUCI_BASENAME is '$MK_LUCI_BASENAME' but PKG_NAME '$MK_PKG_NAME' implies"
|
||||
fail " '$mk_expected_basename' - the self-built i18n package will not match the release"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
printf '%s checks, %s failures\n' "$checks" "$([ "$FAILED" = 0 ] && echo 0 || echo 'nonzero')"
|
||||
if [ "$FAILED" != 0 ]; then
|
||||
|
||||
@@ -133,7 +133,7 @@ expect "uci restore: missing snapshot returns 1" "$?" "1"
|
||||
# Happy path: snapshot present, all keys applied, commit called.
|
||||
# The snapshot format carries the UCI type, because `uci set` on a list option
|
||||
# stores a string and the firewall validators then reject it (review
|
||||
# 2026-09-29, docs/review-report-20260929-full.md §1.5): lists are replayed
|
||||
# 2026-09-29 review): lists are replayed
|
||||
# with `uci delete` + `uci add_list`.
|
||||
: > "$HP_TEST_UCI_OUT"
|
||||
write_uci_stub
|
||||
|
||||
@@ -578,7 +578,7 @@ fi
|
||||
|
||||
run_case custom "$ROOT/tests/fixtures/generators/custom.uci" generate_client.uc sing-box-c.json
|
||||
|
||||
# §2.2 (linux.json 与 pro 的差距分析): append_custom_dns now prepends the
|
||||
# append_custom_dns now prepends the
|
||||
# HTTPS/SVCB reject so a user-written rule cannot shadow the safety net.
|
||||
# Without a dns_server in custom.uci the rule block is empty, so the
|
||||
# generated config still has the reject at index 0.
|
||||
@@ -613,7 +613,7 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# §2.5 (linux.json 与 pro 的差距分析): the original plan was to set
|
||||
# The original plan was to set
|
||||
# `experimental.reverse_mapping: true` so the literal pinned us against a
|
||||
# future sing-box default flip. sing-box 1.14.0-r1 (the CI floor pinned
|
||||
# by arch-guard 31) rejects the field as "json: unknown field" - the
|
||||
@@ -623,7 +623,7 @@ fi
|
||||
# purpose: the only assertion that matters is that the generated config
|
||||
# passes sing-box check, which the test runner does for every case.
|
||||
|
||||
# §2.4 (linux.json 与 pro 的差距分析): when the user configures a DoH
|
||||
# When the user configures a DoH
|
||||
# upstream against a known hostname, append_custom_dns emits a hosts-type
|
||||
# DNS server pinning that hostname to its real IPs. Without it, the DoH
|
||||
# resolver itself has to be resolved through the system DNS, and a DNS
|
||||
@@ -676,7 +676,7 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# §2.1 (linux.json 与 pro 的差距分析): cn_ip_fallback default flipped to '1'
|
||||
# cn_ip_fallback default flipped to '1'
|
||||
# for fresh installs (the package ships option cn_ip_fallback '1' and
|
||||
# context.uc falls back to '1' on a missing value). Existing users
|
||||
# upgrading get '0' written by migrate_config.uc and keep the prior
|
||||
@@ -719,7 +719,8 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# §2.1 opt-out: a fixture with cn_ip_fallback='0' must NOT emit the pair.
|
||||
# cn_ip_fallback opt-out: a fixture with cn_ip_fallback='0' must NOT emit
|
||||
# the pair.
|
||||
# client.uci does not set the option (so it defaults to '1' in the proxy
|
||||
# config above); here we stage a variant with '0' to assert the
|
||||
# upgrade-safe path of migrate_config.uc - existing users see no change.
|
||||
@@ -740,7 +741,7 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
# §2.7 (linux.json 与 pro 的差距分析): sniffer_advanced_mode default stays
|
||||
# sniffer_advanced_mode default stays
|
||||
# '0'. Client mode must emit the conservative sniff rule (300ms / no
|
||||
# sniffer list); advanced mode emits the 100ms / universal-list profile.
|
||||
if [ ! -f "$client_json" ]; then
|
||||
@@ -776,7 +777,7 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# §2.7 opt-in: sniffer_advanced_mode='1' flips the sniff rule to 100ms +
|
||||
# sniffer_advanced_mode opt-in: '1' flips the sniff rule to 100ms +
|
||||
# the universal protocol list. sed-injected on client.uci.
|
||||
run_case client-sniffer-advanced "$ROOT/tests/fixtures/generators/client.uci" generate_client.uc sing-box-c.json \
|
||||
"s#^\\([[:space:]]*\\)option main_node 'urltest'#\\1option main_node 'urltest'\\n\\1option sniffer_advanced_mode '1'#"
|
||||
@@ -920,8 +921,8 @@ run_case_type_error dangling-resolver "does not exist or is disabled" \
|
||||
|
||||
# --- review@2026-09-29 batch -------------------------------------------------
|
||||
#
|
||||
# Six checks that pin the five generator fixes from
|
||||
# docs/review-report-20260929.md §7. Earlier rounds attempted ucode
|
||||
# Six checks that pin the five generator fixes from the 2026-09-29 review.
|
||||
# Earlier rounds attempted ucode
|
||||
# probes (arrow functions, optional chaining on arrays, ...) and each
|
||||
# round surfaced a different ucode dialect issue on the testbed - the
|
||||
# macOS dev box has no ucode so the loop could not iterate locally.
|
||||
@@ -929,7 +930,7 @@ run_case_type_error dangling-resolver "does not exist or is disabled" \
|
||||
# it runs identically on macOS and the testbed. ucode-stdout probes
|
||||
# are out; structural assertions against the emitted bytes are in.
|
||||
|
||||
# 1) P2 #2 / §1.4.1: geosite-cn is the *DNS*-layer rule_set consumer.
|
||||
# 1) P2 #2: geosite-cn is the *DNS*-layer rule_set consumer.
|
||||
# The route layer never references it as a rule_set value (route.rule_set
|
||||
# declares it as a tag). Indent cannot disambiguate dns.rules[] from
|
||||
# route.rules[] (both pretty-print at 4 tabs on the testbed; both are
|
||||
@@ -962,7 +963,7 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
# 2) P3 #6 / §1.4.3: china-dns.strategy must mirror default-dns's gate
|
||||
# 2) P3 #6: china-dns.strategy must mirror default-dns's gate
|
||||
# on ipv6_support. With ipv6_support='0' (client.uci's value),
|
||||
# china-dns.strategy must be 'ipv4_only', not the pre-r28
|
||||
# unconditional 'prefer_ipv6'. The generated JSON emits the dns
|
||||
@@ -1083,7 +1084,7 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
# 3) P2 #4 / §2.2.1: the three NAPTR (qtype 35) bypass suffixes must be
|
||||
# 3) P2 #4: the three NAPTR (qtype 35) bypass suffixes must be
|
||||
# emitted as a single domain_suffix entry backed by the
|
||||
# NAPTR_BYPASS_SUFFIXES constant. ucode's pretty-printer emits the
|
||||
# query_type array and the domain_suffix array as multi-line:
|
||||
@@ -1121,7 +1122,7 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
# 4) P2 #3 / §1.4.3 / §5.1: attachExperimental() used to gate cache_file
|
||||
# 4) P2 #3: attachExperimental() used to gate cache_file
|
||||
# on routing_mode in [bypass_mainland_china, custom]. After the r28
|
||||
# fix, every routing_mode gets a cache_file block. Three sed
|
||||
# variations of the same fixture cover gfwlist / proxy_mainland_china
|
||||
@@ -1170,7 +1171,7 @@ else
|
||||
echo "PASS: cache-file-custom: experimental.cache_file emitted for routing_mode='custom'"
|
||||
fi
|
||||
|
||||
# 5) P3 #7 / §4.2.1: a local ruleset whose path is outside the homeproxy-pro
|
||||
# 5) P3 #7: a local ruleset whose path is outside the homeproxy-pro
|
||||
# whitelist (e.g. /etc/passwd) used to silently set the field to
|
||||
# null. The fix is to die() with a message naming the offender.
|
||||
# run_case_type_error observes the refusal. The variation targets
|
||||
@@ -1181,7 +1182,7 @@ run_case_type_error local-ruleset-bad-path "outside the homeproxy-pro whitelist"
|
||||
"$ROOT/tests/fixtures/generators/custom.uci" generate_client.uc sing-box-c.json \
|
||||
"s%^[[:space:]]*option path '/tmp/homeproxy_test_ruleset\\.[^/]*/local-ruleset-bad-path/test.srs'% option path '/etc/passwd'%"
|
||||
|
||||
# 6) P3 #8 / §4.2.2 (extra_tags die() on missing {tag}): deferred to
|
||||
# 6) P3 #8 (extra_tags die() on missing {tag}): deferred to
|
||||
# a dedicated 'testbed-dialect' sprint. The multi-line sed to
|
||||
# attach an extra_tags list onto the existing rs_local ruleset
|
||||
# drifted at the first whitespace change on the testbed, and
|
||||
|
||||
@@ -59,7 +59,7 @@ expect('server.insecure forced null', serverInsecure.insecure, null);
|
||||
/* 4. cert_path whitelist - the validator accepts /etc/homeproxy-pro/... and
|
||||
* /tmp/homeproxy_..., and rejects everything else (including
|
||||
* /etc/passwd and relative paths). This is the security patch
|
||||
* that backs the §4 path-whitelist entry; a regression here would
|
||||
* that backs the path-whitelist entry above; a regression here would
|
||||
* let UCI drive sing-box into reading arbitrary files as root. */
|
||||
expect('cert.path /etc/homeproxy-pro', validateHomeProxyPath('/etc/homeproxy-pro/certs/server_publickey.pem'), true);
|
||||
expect('cert.path /tmp/homeproxy_', validateHomeProxyPath('/tmp/homeproxy_test/foo.pem'), true);
|
||||
|
||||
Reference in new issue
Block a user