[HLCC-ICE-000001][ZY-CONTRIB-20260723-001] feat: 以来光者贡献链启用冰朔第五域个人子频道

This commit is contained in:
光湖代码频道 · 铸渊 2026-07-24 10:39:10 +08:00
commit 5615453e4e
660 changed files with 122355 additions and 0 deletions

View file

@ -0,0 +1,30 @@
# 京东云第五域国内主代码仓库
> **运行事实校正2026-07-23**:公网只读版本接口
> `https://guanghulab.com/fifth-domain/api/v1/version` 当前返回 `1.23.7`
> 页面元信息显示现役运行体为 Gitea。本目录描述的是目标 Forgejo 部署结构,
> 不能作为“线上已经运行 Forgejo”的证明。迁移与光湖自有化路线见
> `glw-architecture/GLW-OS-004-FORGEJO-UPSTREAM-PARTS-AND-GUANGHU-CODE-PLATFORM.hdlp`
产品身份必须独立验收,禁止再用服务名、目录名或相似 UI 代替真实版本证据:
```bash
node server-tools/jd-forgejo/product-identity.js \
https://guanghulab.com/fifth-domain FORGEJO
```
当前该命令应返回 `PRODUCT_IDENTITY_MISMATCH`,直到并行迁移完成并切换入口。
- 与广州/新加坡现役节点一致的原生 Forgejo 二进制 + SQLite
- Web 和 SSH 只绑定 JD 回环地址;
- 公网页面通过广州备案前门的专用 `permitopen` SSH 隧道发布在
`https://guanghulab.com/fifth-domain/`
- 数据位于 `/var/lib/guanghu/forgejo``SECRET_KEY``INTERNAL_TOKEN`
只写入服务器上的 `app.ini`
- 禁止公开注册和 push-create初始管理员由部署命令在容器内创建
- 服务器 `pre-receive` 必须串联导航记忆守门人、私密禁用标识扫描和
小湖灯一小时 repo-push 授权凭据。
不得再从广州/新加坡节点盲目复制“现役二进制”。任何候选二进制必须记录官方
来源、版本、SHA-256 和产品身份,再进入隔离实例。迁移必须另开批次、备份数据库
并人工验证。

View file

@ -0,0 +1,38 @@
APP_NAME = 第五域 · 国内主代码仓库
RUN_USER = git
WORK_PATH = /opt/forgejo
[server]
PROTOCOL = http
HTTP_ADDR = 127.0.0.1
HTTP_PORT = 3001
DOMAIN = guanghulab.com
ROOT_URL = https://guanghulab.com/fifth-domain/
DISABLE_SSH = true
LFS_START_SERVER = true
[database]
DB_TYPE = sqlite3
PATH = /var/lib/guanghu/forgejo/data/forgejo.db
LOG_SQL = false
[repository]
ROOT = /var/lib/guanghu/forgejo/repositories
DEFAULT_PRIVATE = private
ENABLE_PUSH_CREATE_USER = false
[service]
DISABLE_REGISTRATION = true
REQUIRE_SIGNIN_VIEW = false
[security]
INSTALL_LOCK = true
SECRET_KEY = PRIVATE_SERVER_VALUE
INTERNAL_TOKEN = PRIVATE_SERVER_VALUE
[session]
PROVIDER = file
[log]
MODE = console
LEVEL = Info

View file

@ -0,0 +1,12 @@
location /fifth-domain/ {
proxy_pass http://127.0.0.1:19301/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
client_max_body_size 256m;
}

View file

@ -0,0 +1,22 @@
[Unit]
Description=Guanghu Fifth Domain domestic Forgejo primary
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=git
Group=git
SupplementaryGroups=guanghu
WorkingDirectory=/opt/forgejo
ExecStart=/usr/local/bin/forgejo web -c /opt/forgejo/custom/conf/app.ini --work-path /opt/forgejo
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/forgejo /var/lib/guanghu/forgejo
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,19 @@
[Unit]
Description=Guanghu BS-GZ-006 to JD Forgejo web tunnel
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
ExecStart=/usr/bin/ssh -NT -F /etc/guanghu/jd-forgejo-tunnel-ssh-config jd-forgejo-target
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=read-only
ProtectSystem=strict
ReadOnlyPaths=/etc/guanghu/jd-forgejo-tunnel-ssh-config /etc/guanghu/secrets/ssh/bs_gz_006_to_jd_forgejo_proxy /root/.ssh/known_hosts
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
JD_HOST=${1:?JD host is required}
install -m 644 /tmp/guanghu-jd-forgejo-tunnel.service /etc/systemd/system/guanghu-jd-forgejo-tunnel.service
install -m 644 /tmp/guanghu-forgejo.nginx.conf /etc/nginx/snippets/guanghu-forgejo.conf
chmod 600 /etc/guanghu/secrets/ssh/bs_gz_006_to_jd_forgejo_proxy
install -m 600 /dev/null /etc/guanghu/jd-forgejo-tunnel-ssh-config
sed -e "s/JD_PUBLIC_ADDRESS/${JD_HOST}/" /tmp/jd-forgejo-tunnel-ssh-config.example > /etc/guanghu/jd-forgejo-tunnel-ssh-config
if ! grep -q "include /etc/nginx/snippets/guanghu-forgejo.conf;" /etc/nginx/sites-enabled/guanghulab; then
sed -i '0,/server_name guanghulab.com;/s##server_name guanghulab.com;\n include /etc/nginx/snippets/guanghu-forgejo.conf;#' /etc/nginx/sites-enabled/guanghulab
fi
systemctl daemon-reload
systemctl enable --now guanghu-jd-forgejo-tunnel.service
nginx -t
systemctl reload nginx
rm -f /tmp/guanghu-jd-forgejo-tunnel.service /tmp/guanghu-forgejo.nginx.conf /tmp/jd-forgejo-tunnel-ssh-config.example

View file

@ -0,0 +1,9 @@
Host jd-forgejo-target
HostName JD_PUBLIC_ADDRESS
User root
IdentityFile /etc/guanghu/secrets/ssh/bs_gz_006_to_jd_forgejo_proxy
IdentitiesOnly yes
LocalForward 127.0.0.1:19301 127.0.0.1:3001
ExitOnForwardFailure yes
ServerAliveInterval 30
ServerAliveCountMax 3

View file

@ -0,0 +1,41 @@
"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const { parseProductIdentity } = require("./product-identity");
const ini = fs.readFileSync(path.join(__dirname, "app.ini.template"), "utf8");
const unit = fs.readFileSync(path.join(__dirname, "guanghu-forgejo.service"), "utf8");
test("native Forgejo binds only to JD loopback", () => {
assert.match(ini, /HTTP_ADDR = 127\.0\.0\.1/);
assert.match(ini, /HTTP_PORT = 3001/);
});
test("registration and push-create are disabled", () => {
assert.match(ini, /DISABLE_REGISTRATION = true/);
assert.match(ini, /ENABLE_PUSH_CREATE_USER = false/);
});
test("secrets remain server-side placeholders", () => {
assert.equal((ini.match(/PRIVATE_SERVER_VALUE/g) || []).length, 2);
assert.doesNotMatch(ini, /[a-f0-9]{40,}/);
assert.match(unit, /User=git/);
});
test("product identity probe rejects Gitea being labeled as Forgejo", () => {
const identity = parseProductIdentity(
{ version: "1.23.7" },
'<meta name="author" content="Gitea - Git with a cup of tea">',
);
assert.deepEqual(identity, {
product: "GITEA",
version: "1.23.7",
author: "Gitea - Git with a cup of tea",
});
assert.notEqual(identity.product, "FORGEJO");
});
test("product identity probe recognizes Forgejo independently", () => {
const identity = parseProductIdentity(
{ version: "15.0.5" },
'<meta name="author" content="Forgejo Beyond coding. We forge.">',
);
assert.equal(identity.product, "FORGEJO");
assert.equal(identity.version, "15.0.5");
});

View file

@ -0,0 +1,57 @@
"use strict";
function parseProductIdentity(versionPayload, html) {
const version =
typeof versionPayload === "string"
? JSON.parse(versionPayload).version
: versionPayload.version;
const author =
html.match(
/<meta\s+name=["']author["']\s+content=["']([^"']+)["']/i,
)?.[1] ?? "";
const normalizedAuthor = author.toLowerCase();
let product = "UNKNOWN";
if (normalizedAuthor.includes("forgejo")) product = "FORGEJO";
if (normalizedAuthor.includes("gitea")) product = "GITEA";
return { product, version, author };
}
async function inspectProduct(baseUrl, fetchImpl = fetch) {
const normalizedBase = baseUrl.replace(/\/+$/, "");
const [versionResponse, homeResponse] = await Promise.all([
fetchImpl(`${normalizedBase}/api/v1/version`),
fetchImpl(`${normalizedBase}/`),
]);
if (!versionResponse.ok || !homeResponse.ok) {
throw new Error(
`repository identity probe failed: version=${versionResponse.status}, home=${homeResponse.status}`,
);
}
return parseProductIdentity(
await versionResponse.json(),
await homeResponse.text(),
);
}
async function main() {
const baseUrl =
process.argv[2] ?? "https://guanghulab.com/fifth-domain";
const expectedProduct = (process.argv[3] ?? "FORGEJO").toUpperCase();
const identity = await inspectProduct(baseUrl);
process.stdout.write(`${JSON.stringify(identity, null, 2)}\n`);
if (identity.product !== expectedProduct) {
process.stderr.write(
`PRODUCT_IDENTITY_MISMATCH: expected ${expectedProduct}, got ${identity.product} ${identity.version}\n`,
);
process.exitCode = 2;
}
}
if (require.main === module) {
main().catch((error) => {
process.stderr.write(`${error.message}\n`);
process.exitCode = 1;
});
}
module.exports = { inspectProduct, parseProductIdentity };