Author SHA1 Message Date
George Berkshire e978a636d9 feat: 新增无 - 前缀的纯文本规则列表(router/direct-plain.txt + 生成器)
CI / check (pull_request) Successful in 3s
2026-08-19 21:03:24 +08:00
4 changed files with 6 additions and 316 deletions
+6 -9
View File
@@ -1,5 +1,7 @@
# Gitea Actions CI(统一离线 lite 门禁)
# Runner 无外网且无 pip;这里只运行标准库测试和本地合规检查。
# Gitea Actions CI 模板(统一极简合规门禁)
# 复制为 <repo>/.gitea/workflows/ci.yml 后即可用;无需调整。
# 说明:runner 容器无外网且无 pip(Gitea 实例限制),CI 只做本地可完成的合规检查;
# 依赖安装与测试一律在本地运行(开发机上完成)。
name: CI
on:
@@ -16,18 +18,13 @@ permissions:
contents: read
jobs:
lite:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@524e936cd9e579adf00e308bfdf971aebc7de09e
with:
persist-credentials: false
- uses: actions/checkout@v4
- name: Gitea 合规校验
run: |
if git ls-tree -r HEAD | awk '$1==160000' | grep -q .; then echo "HEAD 含 gitlink"; exit 1; fi
if git ls-files .DS_Store | grep -q .; then echo "跟踪 .DS_Store"; exit 1; fi
if git grep -n -I -E 'sk-[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|xox[baprs]-[A-Za-z0-9-]{10,}' HEAD | grep -q .; then echo "检出疑似凭证"; exit 1; fi
echo "Gitea 合规校验通过"
- name: 规则契约测试
run: python3 -m unittest discover -s tests -v
-120
View File
@@ -1,120 +0,0 @@
{
"schema_version": 1,
"module_id": "vpn-rules",
"authority": {
"scope": "module_metadata",
"subject": "vpn-rules",
"owner": "vpn-rules-owner",
"source": "MODULE_SPEC.yaml",
"revision": 1,
"effective_from": "2026-08-20T00:00:00+08:00"
},
"repository": {
"name": "vpn-rules",
"workspace_id": null,
"type": "infrastructure",
"maturity": "operational"
},
"bounded_context": {
"domain": "network-routing-policy",
"responsibility": "Own the single source of truth for direct-routing rules and deterministic projections for supported clients.",
"prohibited_responsibilities": [
"Applying rules to production clients, routers, VPN services, or proxy runtimes",
"Owning or exposing proxy subscription credentials, provider tokens, or device secrets",
"Claiming generated or checked-in artifacts are active production configuration"
]
},
"capabilities": [
{
"id": "direct-routing-rule-authoring",
"summary": "Maintain provider-neutral direct-routing entries in the authoritative mihomo rule-provider source.",
"status": "operational"
},
{
"id": "clash-verge-script-generation",
"summary": "Render source entries as idempotent DIRECT rules for Clash Verge Script.js.",
"status": "operational"
},
{
"id": "router-rule-projection",
"summary": "Generate policy-bearing YAML and policy-free plain-text projections for router consumers.",
"status": "operational"
}
],
"data": {
"owns": [
{
"asset_id": "direct-routing-rule-source",
"kind": "reference",
"classification": "restricted"
},
{
"asset_id": "generated-router-rule-projections",
"kind": "artifact",
"classification": "restricted"
}
]
},
"contracts": {
"provides": [
{
"contract_id": "mihomo-direct-rule-provider",
"kind": "artifact",
"version": "1.0.0",
"path": "direct.yaml",
"compatibility": "backward"
},
{
"contract_id": "router-direct-rules",
"kind": "artifact",
"version": "1.0.0",
"path": "router/direct-rules.yaml",
"compatibility": "exact"
},
{
"contract_id": "router-direct-plain-list",
"kind": "artifact",
"version": "1.0.0",
"path": "router/direct-plain.txt",
"compatibility": "exact"
}
],
"consumes": []
},
"dependencies": [],
"agent_context": {
"default_entrypoints": [
{
"path": "README.md",
"purpose": "Repository purpose, supported consumers, generation commands, and maintenance flow."
},
{
"path": "direct.yaml",
"purpose": "Authoritative direct-routing rule source and provider format."
}
],
"excluded_paths": [
"router"
],
"max_default_tokens": 6000
},
"verification": {
"commands": [
{
"id": "rule-contract-tests",
"argv": [
"python3",
"-m",
"unittest",
"discover",
"-s",
"tests",
"-v"
],
"cwd": ".",
"network": false,
"required": true
}
]
}
}
-41
View File
@@ -1,41 +0,0 @@
from __future__ import annotations
import re
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
class CiContractTests(unittest.TestCase):
def test_ci_publishes_one_offline_lite_gate(self) -> None:
workflow = (ROOT / ".gitea/workflows/ci.yml").read_text(encoding="utf-8")
job_block = workflow.split("jobs:", 1)[1]
self.assertEqual(
re.findall(r"(?m)^ ([a-z][a-z0-9_-]*):\s*$", job_block),
["lite"],
)
self.assertIn(
"actions/checkout@524e936cd9e579adf00e308bfdf971aebc7de09e",
workflow,
)
self.assertIn("persist-credentials: false", workflow)
self.assertIn(
"python3 -m unittest discover -s tests -v",
workflow,
)
for forbidden in (
"actions/checkout@v",
"apt ",
"pip ",
"curl ",
"wget ",
"docker pull",
):
self.assertNotIn(forbidden, workflow)
if __name__ == "__main__":
unittest.main()
-146
View File
@@ -1,146 +0,0 @@
from __future__ import annotations
import json
import sys
import unittest
from pathlib import Path, PurePosixPath
ROOT = Path(__file__).resolve().parents[1]
SPEC_PATH = ROOT / "MODULE_SPEC.yaml"
sys.path.insert(0, str(ROOT / "scripts"))
from gen_clash_verge_script import load_payload, to_rule # noqa: E402
class ModuleSpecTests(unittest.TestCase):
def test_module_spec_declares_rule_authority_and_safe_context(self) -> None:
spec = json.loads(SPEC_PATH.read_text(encoding="utf-8"))
self.assertEqual(
set(spec),
{
"schema_version",
"module_id",
"authority",
"repository",
"bounded_context",
"capabilities",
"data",
"contracts",
"dependencies",
"agent_context",
"verification",
},
)
self.assertEqual(spec["schema_version"], 1)
self.assertEqual(spec["module_id"], "vpn-rules")
self.assertEqual(
spec["authority"],
{
"scope": "module_metadata",
"subject": "vpn-rules",
"owner": "vpn-rules-owner",
"source": "MODULE_SPEC.yaml",
"revision": 1,
"effective_from": "2026-08-20T00:00:00+08:00",
},
)
self.assertEqual(
spec["repository"],
{
"name": "vpn-rules",
"workspace_id": None,
"type": "infrastructure",
"maturity": "operational",
},
)
boundary = spec["bounded_context"]
self.assertEqual(boundary["domain"], "network-routing-policy")
self.assertIn("single source of truth", boundary["responsibility"].lower())
prohibited = " ".join(boundary["prohibited_responsibilities"]).lower()
self.assertIn("production", prohibited)
self.assertIn("credential", prohibited)
self.assertIn("proxy subscription", prohibited)
self.assertEqual(
{capability["id"] for capability in spec["capabilities"]},
{
"direct-routing-rule-authoring",
"clash-verge-script-generation",
"router-rule-projection",
},
)
self.assertEqual(spec["contracts"]["consumes"], [])
self.assertEqual(spec["dependencies"], [])
provided = {
contract["contract_id"]: contract
for contract in spec["contracts"]["provides"]
}
self.assertEqual(
set(provided),
{
"mihomo-direct-rule-provider",
"router-direct-rules",
"router-direct-plain-list",
},
)
self.assertEqual(
{contract["version"] for contract in provided.values()}, {"1.0.0"}
)
for contract in provided.values():
self.assertTrue((ROOT / contract["path"]).is_file())
context = spec["agent_context"]
self.assertLessEqual(context["max_default_tokens"], 6000)
self.assertEqual(
{entry["path"] for entry in context["default_entrypoints"]},
{"README.md", "direct.yaml"},
)
for entry in context["default_entrypoints"]:
self.assertTrue((ROOT / entry["path"]).is_file())
self.assertIn("router", context["excluded_paths"])
for value in context["excluded_paths"]:
path = PurePosixPath(value)
self.assertFalse(path.is_absolute())
self.assertNotIn("..", path.parts)
self.assertEqual(
spec["verification"],
{
"commands": [
{
"id": "rule-contract-tests",
"argv": [
"python3",
"-m",
"unittest",
"discover",
"-s",
"tests",
"-v",
],
"cwd": ".",
"network": False,
"required": True,
}
]
},
)
def test_checked_in_router_projections_match_the_rule_source(self) -> None:
payload = load_payload(ROOT / "direct.yaml")
plain = (ROOT / "router/direct-plain.txt").read_text(encoding="utf-8")
router = (ROOT / "router/direct-rules.yaml").read_text(encoding="utf-8")
self.assertEqual(plain, "\n".join(payload) + "\n")
self.assertEqual(
router.split("rules:\n", 1)[1],
"\n".join(f" - {to_rule(entry)}" for entry in payload) + "\n",
)
self.assertTrue(all(",DIRECT" not in entry for entry in payload))
if __name__ == "__main__":
unittest.main()