Some checks failed
RKNnoVPN Linux and Android CI / policy-and-go (push) Successful in 14s
RKNnoVPN Linux and Android CI / android-debug (push) Successful in 2m5s
Full build and Forgejo release / Privacy Lint (push) Successful in 3s
Full build and Forgejo release / Local-first Runtime Guardrail (push) Successful in 2s
Full build and Forgejo release / Go Tests (push) Successful in 13s
Full build and Forgejo release / Resolve sing-box release (push) Successful in 1s
Full build and Forgejo release / Resolve Xray-core release (push) Successful in 1s
Full build and Forgejo release / Android Guardrails & Tests (push) Failing after 16s
Full build and Forgejo release / Build APK (push) Has been skipped
Full build and Forgejo release / Build Runtime CLI (arm64) (push) Successful in 11s
Full build and Forgejo release / Build Runtime CLI (armv7) (push) Successful in 11s
Full build and Forgejo release / Build sing-box (arm64) (push) Failing after 2s
Full build and Forgejo release / Build sing-box (armv7) (push) Failing after 2s
Full build and Forgejo release / Build Xray-core (arm64) (push) Failing after 3s
Full build and Forgejo release / Build Xray-core (armv7) (push) Failing after 2s
Full build and Forgejo release / Build Magisk Module (push) Has been skipped
Full build and Forgejo release / Create Release (push) Has been skipped
245 lines
13 KiB
Shell
245 lines
13 KiB
Shell
#!/usr/bin/env bash
|
|
# Repository-independent Forgejo/local policy check.
|
|
set -euo pipefail
|
|
|
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
removed_update_installer="app/app/src/main/kotlin/com/rknnovpn/panel/update/Update""Installer.kt"
|
|
|
|
obsolete_paths=(
|
|
"daemon"
|
|
"app/app/src/main/kotlin/com/rknnovpn/panel/ipc"
|
|
"app/app/src/main/kotlin/com/rknnovpn/panel/advisor"
|
|
"app/app/src/main/kotlin/com/rknnovpn/panel/boot"
|
|
"app/app/src/main/kotlin/com/rknnovpn/panel/model"
|
|
"app/app/src/main/kotlin/com/rknnovpn/panel/profile/AppProfileV1.kt"
|
|
"app/app/src/main/kotlin/com/rknnovpn/panel/repository/StatusRepository.kt"
|
|
"app/app/src/main/kotlin/com/rknnovpn/panel/runtime/RuntimeConfigRenderer.kt"
|
|
"${removed_update_installer}"
|
|
"app/app/src/main/kotlin/com/rknnovpn/panel/ui/audit"
|
|
"app/app/src/test/kotlin/com/rknnovpn/panel/ipc"
|
|
"scripts/ci/check_ipc_contract_codegen.py"
|
|
"tools/device_lab/check_diagnostics_report.py"
|
|
)
|
|
|
|
for obsolete_path in "${obsolete_paths[@]}"; do
|
|
if [ -e "${repo_root}/${obsolete_path}" ]; then
|
|
echo "::error file=${repo_root}/${obsolete_path},title=Local-first runtime::Obsolete daemon/IPC path must not exist" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
alternate_type_name='type''alias'
|
|
removed_model_package='com[.]rknnovpn[.]panel[.]mo''del[.]|package[[:space:]]+com[.]rknnovpn[.]panel[.]mo''del'
|
|
kotlin_import_alias='^import .* as '
|
|
if find "${repo_root}/app/app/src/main/kotlin" -type f -name '*.kt' -print0 |
|
|
xargs -0 -r grep -En -- "${alternate_type_name}|${removed_model_package}|${kotlin_import_alias}"; then
|
|
echo "::error title=Local-first runtime::APK production Kotlin must use direct domain types, not removed model package aliases or import aliases" >&2
|
|
exit 1
|
|
fi
|
|
|
|
compat_method='compat[.]check'
|
|
contract_method='ipc[.]contract'
|
|
generated_contract='Generated''Dae''monContract'
|
|
require_gate='require''Compatible'
|
|
compat_cache='compat''ibility''Cache'
|
|
cooldown_text='Repair ''cooldown'
|
|
stable_invalid='stable''InvalidResponse'
|
|
module_fix='module''Rep''air'
|
|
allow_module_fix='allow''Module''Rep''air'
|
|
old_socket_owner='Dae''mon'
|
|
old_client="${old_socket_owner}Client"
|
|
old_runtime_bridge="${old_socket_owner}RuntimeBridge"
|
|
oldctl='dae''mon''ctl'
|
|
old_socket='dae''mon[.]sock'
|
|
diagnostics_report='diagnostics[.-]report'
|
|
self_check='self''-check'
|
|
backend_method='backend[.](status|start|stop|reset)'
|
|
profile_method='profile[.](get|apply)'
|
|
subscription_method='subscription[.](preview|refresh)'
|
|
update_state='update''Install|update''Check|Cached''UpdateCheckState|Update''InstallState'
|
|
root_profile_state='RKNNOVPN_STATE_DIR|PROFILE_FILE|PROFILES_DIR'
|
|
old_status_shape='Backend''StatusV2|Runtime''V2|Applied''StateV2|Runtime''Readiness''Status|Node''Probe''ResultV2|backend''Status|to''Runtime''Status|applied''State|runtime_v2|backend_kind|tun''Active'
|
|
pattern="${compat_method}|${contract_method}|${generated_contract}|${require_gate}|${compat_cache}|${cooldown_text}|${stable_invalid}|${module_fix}|${allow_module_fix}|${old_client}|${old_runtime_bridge}|${oldctl}|${old_socket}|${diagnostics_report}|${self_check}|${backend_method}|${profile_method}|${subscription_method}|${update_state}|${root_profile_state}|${old_status_shape}"
|
|
if find "${repo_root}/app" "${repo_root}/runtime" "${repo_root}/module" "${repo_root}/tools" "${repo_root}/.forgejo" -type f \
|
|
! -path '*/.gradle/*' \
|
|
! -path '*/build/*' \
|
|
! -path '*/out/*' \
|
|
! -path '*/__pycache__/*' \
|
|
! -path '*/.git/*' \
|
|
! -path "${repo_root}/module/binaries/*" \
|
|
! -path "${repo_root}/scripts/ci/check_local_first_runtime.sh" -print0 |
|
|
xargs -0 -r grep -En -- "${pattern}"; then
|
|
echo "::error title=Local-first runtime::Forbidden removed runtime path detected" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/runtime" -type f -name '*.kt' -print0 |
|
|
xargs -0 -r grep -En -- 'put[(]"subscriptions"|AppSubscription|profile[.]subscriptions'; then
|
|
echo "::error title=Local-first runtime::APK-owned subscriptions must not be rendered into runtime config" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/runtime" -type f -name '*.go' ! -name '*_test.go' -print0 |
|
|
xargs -0 -r grep -En -- 'ProfileSubscriptionConfig|Subscriptions[[:space:]]+\[\]json[.]RawMessage|profile[.]subscriptions'; then
|
|
echo "::error title=Local-first runtime::Runtime config must not own APK subscription registry" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/runtime" -type f -name '*.kt' -print0 |
|
|
xargs -0 -r grep -En -- 'val link|link = link|\"link\"'; then
|
|
echo "::error title=Local-first runtime::Runtime projection must not carry share-link recovery data" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! grep -q 'runtime response is not an envelope' \
|
|
"${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/runtime/RuntimeController.kt"; then
|
|
echo "::error title=Local-first runtime::Runtime protocol must reject non-envelope responses instead of accepting removed bare JSON" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! grep -q 'runtime response is missing ok' \
|
|
"${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/runtime/RuntimeController.kt"; then
|
|
echo "::error title=Local-first runtime::Runtime protocol must require strict ok/result envelopes" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if grep -En 'stageModule|stage-module|ModuleStageResult' \
|
|
"${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/runtime/RuntimeController.kt" \
|
|
"${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/repository/RuntimeSessionRepository.kt"; then
|
|
echo "::error title=Local-first runtime::Module staging must stay out of exact-match runtime session paths" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if grep -En 'pending-module[.]zip|filepath[.]Join[(]moduleDir,[[:space:]]*"releases"' \
|
|
"${repo_root}/runtime/cmd/rknnovpn-runtime/main.go"; then
|
|
echo "::error title=Local-first runtime::Module staging must use root-manager modules_update layout, not legacy pending zip storage" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! grep -q 'modules_update.*rknnovpn' \
|
|
"${repo_root}/runtime/cmd/rknnovpn-runtime/main.go"; then
|
|
echo "::error title=Local-first runtime::Module staging must target a root-manager modules_update/rknnovpn directory" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! grep -q 'writeStagedReleaseCatalog' \
|
|
"${repo_root}/runtime/cmd/rknnovpn-runtime/main.go"; then
|
|
echo "::error title=Local-first runtime::Module staging must materialize the installed release catalog for root-manager activation" >&2
|
|
exit 1
|
|
fi
|
|
|
|
for required_staged_file in \
|
|
scripts/dns.sh \
|
|
scripts/iptables.sh \
|
|
scripts/privacy_guard.sh \
|
|
scripts/routing.sh \
|
|
scripts/lib/rknnovpn_netstack.sh \
|
|
scripts/lib/rknnovpn_iptables_rules.sh; do
|
|
if ! grep -q "\"${required_staged_file}\"" \
|
|
"${repo_root}/runtime/cmd/rknnovpn-runtime/main.go"; then
|
|
echo "::error title=Local-first runtime::Module staging must require ${required_staged_file}" >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
if grep -En 'suspend fun (start|restart)[(][)]: RuntimeCommandResult|override suspend fun (start|restart)[(][)]: RuntimeCommandResult|runtime[.](start|restart)[(][)]' \
|
|
"${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/runtime/RuntimeController.kt" \
|
|
"${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/repository/RuntimeSessionRepository.kt"; then
|
|
echo "::error title=Local-first runtime::Runtime start/restart must take the current AppProfile and apply it before mutation" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/runtime/internal/config" -type f -name '*.go' ! -name '*_test.go' -print0 |
|
|
xargs -0 -r grep -En -- 'applyProfileLinkFallback|streamSettingsFromLinkQuery|parseShadowsocksLink|parseUserInfoProxyLink|Link[[:space:]]+string[[:space:]]+`json:"link"`'; then
|
|
echo "::error title=Local-first runtime::Runtime must not repair profile nodes from share links" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/runtime/internal/config" -type f -name '*.go' ! -name '*_test.go' -print0 |
|
|
xargs -0 -r grep -En -- 'normalizeProfileProjectionConfig|normalizeProfileNodes|delete[(]node,[[:space:]]*"(source|createdAt|latencyMs|responseMs|throughputBps|testStatus)"[)]'; then
|
|
echo "::error title=Local-first runtime::Runtime must reject stale APK node metadata instead of normalizing it" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if grep -En 'ignoreUnknownKeys|isLenient|coerceInputValues|profile-v1[.]json[.]bak|profile[.]corrupt|quarantineLocked' \
|
|
"${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/storage/FileAppProfileStore.kt"; then
|
|
echo "::error title=Local-first runtime::APK profile store must replace unsupported files cleanly instead of using removed repair paths" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if grep -En '"(node|transport)"' \
|
|
"${repo_root}/module/defaults/config.json" \
|
|
"${repo_root}/app/app/src/main/kotlin/com/rknnovpn/panel/runtime/RuntimeProfileRenderer.kt"; then
|
|
echo "::error title=Local-first runtime::Runtime config must be APK profile projection, not removed node/transport state" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/runtime/cmd" "${repo_root}/runtime/internal/core" "${repo_root}/runtime/internal/config" \
|
|
-type f \( -name '*.go' ! -name '*_test.go' \) -print0 |
|
|
xargs -0 -r grep -En -- 'SyncFromProfileProjection|cfg[.]ResolveProfile[(][)]'; then
|
|
echo "::error title=Local-first runtime::Runtime actions must use APK-rendered active profile projection" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/runtime/internal/core" "${repo_root}/runtime/internal/netstack" \
|
|
-type f \( -name '*.go' ! -name '*_test.go' \) -print0 |
|
|
xargs -0 -r grep -En -- 'HotSwap|hot-swap|hotswap|singbox[.]hotswap|restorePreviousRuntimeAfterHotSwapFailure|RuntimePreserved|runtimePreservedError'; then
|
|
echo "::error title=Local-first runtime::Runtime must not keep removed hot-swap/rollback paths" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/runtime/cmd" -type f \( -name '*.go' ! -name '*_test.go' \) -print0 |
|
|
xargs -0 -r grep -En -- 'HotSwap|hot-swap|hotswap|singbox[.]hotswap'; then
|
|
echo "::error title=Local-first runtime::Runtime CLI must not keep removed hot-swap config paths" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/runtime/internal/core" -type f \( -name '*.go' ! -name '*_test.go' \) -print0 |
|
|
xargs -0 -r grep -En -- 'StatusInfo|func [(]m [*]CoreManager[)] Status[(]|SetState[(]|StateDegraded'; then
|
|
echo "::error title=Local-first runtime::Runtime CLI owns minimal status; core must not keep removed status snapshots" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/runtime/internal/config" -type f \( -name '*.go' ! -name '*_test.go' \) -print0 |
|
|
xargs -0 -r grep -En -- 'type[[:space:]]+(NodeConfig|TransportConfig)|ResolveProfile[(]'; then
|
|
echo "::error title=Local-first runtime::Runtime config must not keep removed node/transport recovery APIs" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/module" "${repo_root}/runtime/internal/modulecontract" -type f -print0 |
|
|
xargs -0 -r grep -En -- 'BACKUP_DIR|BackupDir(Name)?|current[.]pre-|bin config config/rendered scripts run logs backup|bin config config/rendered scripts run logs backup profiles|/profiles| profiles( |$)'; then
|
|
echo "::error title=Local-first runtime::Module layout must not recreate removed profile/backup carry-forward paths" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/module" -type f \
|
|
! -path "${repo_root}/module/binaries/*" -print0 |
|
|
xargs -0 -r grep -En -- 'restore_missing_binaries|Restoring missing or non-executable binary|binary restore|chmod[[:space:]]+0?750[[:space:]]+["$][^[:space:]]*bin_path'; then
|
|
echo "::error title=Local-first runtime::Module boot must fail clearly instead of running binary repair loops" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/module" -type f \
|
|
! -path "${repo_root}/module/binaries/*" -print0 |
|
|
xargs -0 -r grep -En -- 'rknnovpn-rollback|rollback-guard|rknnovpn-uninstall-cleanup|stage_deferred_cleanup|trigger_rollback_guard|ROLLBACK_(DIR|SERVICE_SCRIPT|SYSCTL)|DEFERRED_(DIR|SERVICE_SCRIPT)|sysctl-snapshot|restore_kernel_params|rknnovpn_restore_sysctl_snapshots'; then
|
|
echo "::error title=Local-first runtime::Module must not keep removed rollback/deferred cleanup hooks" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if grep -En '/proc/sys/net/(ipv4/ip_forward|ipv6/conf/all/forwarding|ipv4/conf/.*/rp_filter)|rknnovpn_set_sysctl|set_sysctl_value' \
|
|
"${repo_root}/module/post-fs-data.sh" "${repo_root}/module/scripts/lib/rknnovpn_env.sh"; then
|
|
echo "::error title=Local-first runtime::Module boot must not change kernel networking before an explicit runtime action" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/module" "${repo_root}/runtime/internal/modulecontract" -type f -print0 |
|
|
xargs -0 -r grep -En -- 'boot-clean|--boot-clean|BootCleanupMarkers|has_boot_cleanup_markers|rknnovpn_has_boot_cleanup_markers|has_orphan_runtime_processes|Boot rescue cleanup|service boot cleanup|Running boot rescue cleanup'; then
|
|
echo "::error title=Local-first runtime::Module must not run boot-time root cleanup or stale-state repair" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if find "${repo_root}/app/app/src/main/kotlin" -type f -name '*.kt' -print0 |
|
|
xargs -0 -r grep -En -- 'RuntimeStatusPoller|pollNow|lastPollError|RuntimeConnectionState[.]POLLING|^[[:space:]]*suspend fun probe[(][)]'; then
|
|
echo "::error title=Local-first runtime::APK must not poll optional runtime/root without an explicit user action" >&2
|
|
exit 1
|
|
fi
|