[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,42 @@
# 零感域人类主控团队节点部署模板
这套模板用于把光湖人类主控团队成员的新服务器接入企业灯塔 `AW-GZ-001`
第一台真实样板是花尔广州节点 `HE-GZ-001`。成员节点不属于冰朔个人六节点,也不取得
京东主控或企业 CVM 的所有权。
## 基线
- Ubuntu Server 22.04 / 24.04 LTSx86_64
- 原生 Forgejo + SQLite仅监听 `127.0.0.1:3000`
- Nginx 在域名与证书确认前保持停止;
- 节点配置位于 `/etc/guanghu`,运行数据位于 `/var/lib/forgejo`
- 部署前快照和每日 Forgejo 备份位于 `/var/backups/guanghu`
- 工单收件人保存在服务器私有配置,不写入仓库、节点地图或回执;
- 企业灯塔登记状态与代码仓库运行状态分开验收。
## 安装
```bash
NODE_ID=HE-GZ-001 \
NODE_NAME='花尔 · 零感域人类主控团队节点' \
UPSTREAM_NODE=AW-GZ-001 \
bash server-tools/zero-sense-team-node/install.sh
```
安装完成后 Forgejo 仍只在回环地址提供服务。必须先完成健康检查,再单独配置企业备案
域名的子域、TLS 和企业灯塔登记。不要把 Forgejo 3000 端口直接开放公网。
## 邮件工单
邮箱授权由 `lake-lamp-authz` 的服务器私有 approver 注册表承载。只登记成员本人节点的
`server-login``server-ops``repo-push` scope请求方不能指定或覆盖收件人。
发送端 SMTP 凭据必须由企业私有邮件通道提供,不能使用成员 QQ 邮箱密码充当共享凭据。
## 验收与备份
```bash
guanghu-zero-sense-health
guanghu-forgejo-backup
```
备份脚本生成 SQLite 一致性备份、Forgejo 配置和仓库数据归档,默认保留 14 天。

View file

@ -0,0 +1,36 @@
APP_NAME = 光湖零感域代码仓库
RUN_USER = git
RUN_MODE = prod
[database]
DB_TYPE = sqlite3
PATH = /var/lib/forgejo/data/forgejo.db
[repository]
ROOT = /var/lib/forgejo/data/forgejo-repositories
ENABLE_PUSH_CREATE_USER = false
ENABLE_PUSH_CREATE_ORG = false
[server]
PROTOCOL = http
HTTP_ADDR = 127.0.0.1
HTTP_PORT = 3000
DOMAIN = localhost
ROOT_URL = http://127.0.0.1:3000/
DISABLE_SSH = true
OFFLINE_MODE = true
[service]
DISABLE_REGISTRATION = true
REQUIRE_SIGNIN_VIEW = true
ENABLE_NOTIFY_MAIL = false
[security]
INSTALL_LOCK = true
SECRET_KEY = __SECRET_KEY__
INTERNAL_TOKEN = __INTERNAL_TOKEN__
[log]
MODE = file
LEVEL = Info
ROOT_PATH = /var/lib/forgejo/log

View file

@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
BACKUP_ROOT=${BACKUP_ROOT:-/var/backups/guanghu/forgejo}
RETENTION_DAYS=${RETENTION_DAYS:-14}
stamp=$(date -u +%Y%m%dT%H%M%SZ)
target="$BACKUP_ROOT/$stamp"
install -d -m 0700 "$target"
if [[ -f /var/lib/forgejo/data/forgejo.db ]]; then
sqlite3 /var/lib/forgejo/data/forgejo.db ".backup '$target/forgejo.db'"
fi
tar -C / -czf "$target/forgejo-files.tgz" etc/forgejo var/lib/forgejo/data --exclude='var/lib/forgejo/data/forgejo.db'
sha256sum "$target"/* > "$target/SHA256SUMS"
find "$BACKUP_ROOT" -mindepth 1 -maxdepth 1 -type d -mtime "+$RETENTION_DAYS" -print -exec rm -rf -- {} +
printf 'FORGEJO_BACKUP_READY=%s\n' "$target"

View file

@ -0,0 +1,54 @@
#!/usr/bin/env bash
set -euo pipefail
NODE_ID=${NODE_ID:-HE-GZ-001}
CACHE=${FORGEJO_BINARY_CACHE:-/var/cache/guanghu/forgejo-16.0.0-linux-amd64}
EXPECTED_SHA256=${FORGEJO_SHA256:-c686f95df0b025d6075eaf4722f67179b945a1556acfc552408eeab624ed4f28}
TEMPLATE_DIR=${TEMPLATE_DIR:-/root/guanghu-bootstrap/zero-sense-team-node}
printf '%s %s\n' "$EXPECTED_SHA256" "$CACHE" | sha256sum -c -
install -m 0755 "$CACHE" /usr/local/bin/forgejo
getent group git >/dev/null || groupadd --system git
id -u git >/dev/null 2>&1 || useradd --system --shell /bin/bash --gid git --home-dir /home/git --create-home git
install -d -o git -g git -m 0750 /var/lib/forgejo /var/lib/forgejo/data /var/lib/forgejo/log /var/lib/forgejo/custom
install -d -o root -g git -m 0750 /etc/forgejo
install -d -m 0700 /var/backups/guanghu/forgejo
if [[ ! -f /etc/forgejo/app.ini ]]; then
install -o root -g git -m 0640 "$TEMPLATE_DIR/app.ini.template" /etc/forgejo/app.ini
secret_key=$(forgejo generate secret SECRET_KEY)
internal_token=$(forgejo generate secret INTERNAL_TOKEN)
sed -i "s|__SECRET_KEY__|$secret_key|; s|__INTERNAL_TOKEN__|$internal_token|" /etc/forgejo/app.ini
fi
install -m 0644 "$TEMPLATE_DIR/forgejo.service" /etc/systemd/system/forgejo.service
install -m 0755 "$TEMPLATE_DIR/backup.sh" /usr/local/sbin/guanghu-forgejo-backup
install -m 0755 "$TEMPLATE_DIR/health-check.sh" /usr/local/sbin/guanghu-zero-sense-health
cat > /etc/systemd/system/guanghu-forgejo-backup.service <<'EOF'
[Unit]
Description=Guanghu Forgejo consistent backup
After=forgejo.service
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/guanghu-forgejo-backup
EOF
cat > /etc/systemd/system/guanghu-forgejo-backup.timer <<'EOF'
[Unit]
Description=Daily Guanghu Forgejo backup
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=30m
[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable --now forgejo.service guanghu-forgejo-backup.timer
sleep 2
guanghu-zero-sense-health | tee "/var/lib/forgejo/health-${NODE_ID}-$(date -u +%Y%m%dT%H%M%SZ).json"
guanghu-forgejo-backup
touch /var/lib/forgejo/FORGEJO_DEPLOYED_AND_VERIFIED
printf 'ZERO_SENSE_FORGEJO_READY=%s\n' "$NODE_ID"

View file

@ -0,0 +1,21 @@
[Unit]
Description=Forgejo for Guanghu zero-sense member node
After=network.target
[Service]
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/forgejo
Environment=USER=git HOME=/home/git FORGEJO_WORK_DIR=/var/lib/forgejo
ExecStart=/usr/local/bin/forgejo web --config /etc/forgejo/app.ini
Restart=always
RestartSec=2s
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/forgejo
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
node_id=$(jq -r '.node_id' /etc/guanghu/node.json)
domain_id=$(jq -r '.domain_id' /etc/guanghu/node.json)
forgejo_state=$(systemctl is-active forgejo.service)
timer_state=$(systemctl is-active guanghu-forgejo-backup.timer)
version=$(forgejo --version | head -1)
http_code=$(curl -sS -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/api/healthz)
listeners=$(ss -lntH '( sport = :3000 )' | awk '{print $4}')
[[ $listeners == 127.0.0.1:3000 ]]
jq -n --arg node_id "$node_id" --arg domain_id "$domain_id" --arg forgejo "$forgejo_state" \
--arg backup_timer "$timer_state" --arg version "$version" --arg http_code "$http_code" --arg bind "$listeners" \
'{ok:true,node_id:$node_id,domain_id:$domain_id,forgejo:$forgejo,backup_timer:$backup_timer,version:$version,health_http:$http_code,bind:$bind,public_exposure:false}'

View file

@ -0,0 +1,89 @@
#!/usr/bin/env bash
set -euo pipefail
NODE_ID=${NODE_ID:?NODE_ID is required}
NODE_NAME=${NODE_NAME:?NODE_NAME is required}
UPSTREAM_NODE=${UPSTREAM_NODE:-AW-GZ-001}
FORGEJO_VERSION=${FORGEJO_VERSION:-16.0.0}
FORGEJO_SHA256=${FORGEJO_SHA256:-c686f95df0b025d6075eaf4722f67179b945a1556acfc552408eeab624ed4f28}
FORGEJO_MIRROR=${FORGEJO_MIRROR:-https://code.forgejo.org/forgejo/forgejo/releases/download}
FORGEJO_BINARY_CACHE=${FORGEJO_BINARY_CACHE:-/var/cache/guanghu/forgejo-${FORGEJO_VERSION}-linux-amd64}
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
BACKUP_DIR=/var/backups/guanghu/bootstrap/$(date -u +%Y%m%dT%H%M%SZ)
[[ $EUID -eq 0 ]] || { echo "Run as root" >&2; exit 1; }
[[ $NODE_ID =~ ^[A-Z0-9][A-Z0-9-]+$ ]] || { echo "Invalid NODE_ID" >&2; exit 1; }
. /etc/os-release
[[ ${ID:-} == ubuntu && ${VERSION_ID:-} =~ ^(22\.04|24\.04)$ ]] || { echo "Ubuntu 22.04 or 24.04 required" >&2; exit 1; }
[[ $(uname -m) == x86_64 ]] || { echo "x86_64 required" >&2; exit 1; }
install -d -m 0700 "$BACKUP_DIR"
for item in /etc/guanghu/node.json /etc/forgejo/app.ini /etc/systemd/system/forgejo.service; do
[[ -f $item ]] && cp -a "$item" "$BACKUP_DIR/"
done
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq ca-certificates curl git git-lfs jq nginx rsync sqlite3 unattended-upgrades
systemctl disable --now nginx.service || true
getent group git >/dev/null || groupadd --system git
id -u git >/dev/null 2>&1 || useradd --system --shell /bin/bash --gid git --home-dir /home/git --create-home git
install -d -o root -g root -m 0755 /etc/guanghu /etc/guanghu/navigation-maps /opt/guanghu
install -d -o root -g root -m 0700 /etc/guanghu/secrets /var/backups/guanghu/forgejo
install -d -o git -g git -m 0750 /var/lib/forgejo /var/lib/forgejo/data /var/lib/forgejo/log /var/lib/forgejo/custom
install -d -o root -g git -m 0750 /etc/forgejo
binary="forgejo-${FORGEJO_VERSION}-linux-amd64"
install -d -m 0755 "$(dirname "$FORGEJO_BINARY_CACHE")"
if ! printf '%s %s\n' "$FORGEJO_SHA256" "$FORGEJO_BINARY_CACHE" | sha256sum -c - 2>/dev/null; then
curl -fL --retry 20 --retry-all-errors --connect-timeout 15 --continue-at - \
"$FORGEJO_MIRROR/v${FORGEJO_VERSION}/$binary" -o "$FORGEJO_BINARY_CACHE"
fi
printf '%s %s\n' "$FORGEJO_SHA256" "$FORGEJO_BINARY_CACHE" | sha256sum -c -
install -m 0755 "$FORGEJO_BINARY_CACHE" /usr/local/bin/forgejo
install -m 0644 "$SCRIPT_DIR/forgejo.service" /etc/systemd/system/forgejo.service
install -m 0755 "$SCRIPT_DIR/backup.sh" /usr/local/sbin/guanghu-forgejo-backup
install -m 0755 "$SCRIPT_DIR/health-check.sh" /usr/local/sbin/guanghu-zero-sense-health
if [[ ! -f /etc/forgejo/app.ini ]]; then
install -o root -g git -m 0640 "$SCRIPT_DIR/app.ini.template" /etc/forgejo/app.ini
secret_key=$(forgejo generate secret SECRET_KEY)
internal_token=$(forgejo generate secret INTERNAL_TOKEN)
sed -i "s|__SECRET_KEY__|$secret_key|; s|__INTERNAL_TOKEN__|$internal_token|" /etc/forgejo/app.ini
fi
jq -n --arg node_id "$NODE_ID" --arg name "$NODE_NAME" --arg upstream "$UPSTREAM_NODE" \
'{schema:"guanghu.node/v1",node_id:$node_id,display_name:$name,domain_id:"DOMAIN-ZS",upstream:$upstream,role:"zero-sense-human-command-team-node",owner_boundary:"member-owned; enterprise lighthouse routing only",navigation_map:("/etc/guanghu/navigation-maps/"+$node_id+".json"),secret_policy:"private material stays in /etc/guanghu/secrets"}' \
> /etc/guanghu/node.json
chmod 0644 /etc/guanghu/node.json
jq -n --arg node_id "$NODE_ID" --arg upstream "$UPSTREAM_NODE" \
'{schema:"guanghu.navigation-map/v1",node_id:$node_id,domain_id:"DOMAIN-ZS",upstream:$upstream,modules:[{code:"ZS-FRG-01",name:"member Forgejo",bind:"loopback:3000",owner:"systemd"},{code:"ZS-BKP-01",name:"daily backup",bind:"local-timer",owner:"systemd"}],mandatory_order:["read-navigation-map","ack-current-map","execute-registered-action"],forbidden:["public-forgejo-before-tls","secret-in-repository","cross-node-authorization","arbitrary-shell-through-authorization-api"]}' \
> "/etc/guanghu/navigation-maps/${NODE_ID}.json"
chmod 0644 "/etc/guanghu/navigation-maps/${NODE_ID}.json"
cat > /etc/systemd/system/guanghu-forgejo-backup.service <<'EOF'
[Unit]
Description=Guanghu Forgejo consistent backup
After=forgejo.service
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/guanghu-forgejo-backup
EOF
cat > /etc/systemd/system/guanghu-forgejo-backup.timer <<'EOF'
[Unit]
Description=Daily Guanghu Forgejo backup
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=30m
[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable --now forgejo.service unattended-upgrades.service guanghu-forgejo-backup.timer
guanghu-zero-sense-health | tee "/var/lib/forgejo/health-${NODE_ID}-$(date -u +%Y%m%dT%H%M%SZ).json"
printf 'ZERO_SENSE_NODE_READY=%s\n' "$NODE_ID"

View file

@ -0,0 +1,34 @@
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const root = path.resolve(__dirname, "..");
test("supports the current Ubuntu LTS baselines", () => {
const source = fs.readFileSync(path.join(root, "install.sh"), "utf8");
assert.match(source, /22\\.04\\|24\\.04/);
});
test("official binary download resumes instead of restarting", () => {
const source = fs.readFileSync(path.join(root, "install.sh"), "utf8");
assert.match(source, /--continue-at -/);
assert.match(source, /sha256sum -c/);
});
test("Forgejo stays on loopback and registration is disabled", () => {
const ini = fs.readFileSync(path.join(root, "app.ini.template"), "utf8");
assert.match(ini, /HTTP_ADDR = 127\.0\.0\.1/);
assert.match(ini, /DISABLE_REGISTRATION = true/);
});
test("node belongs to zero-sense and enterprise upstream", () => {
const source = fs.readFileSync(path.join(root, "install.sh"), "utf8");
assert.match(source, /DOMAIN-ZS/);
assert.match(source, /AW-GZ-001/);
assert.doesNotMatch(source, /owner:"ICE-GL/);
});
test("secrets and recipient email are not embedded", () => {
const combined = fs.readdirSync(root).filter(name => fs.statSync(path.join(root, name)).isFile()).map(name => fs.readFileSync(path.join(root, name), "utf8")).join("\n");
assert.doesNotMatch(combined, /@qq\.com|BEGIN .*PRIVATE KEY|Bearer [A-Za-z0-9]/);
});