feat(config): 涉密内容外置到配置目录(档案 140)
把散落在代码里的真实部署值统一收进 config/,代码改为引用配置, 使仓库副本/开源导出不再带出生产域名、IP、内网路径与凭据。 新增 config/:platform.env.example(模板)· load.sh(shell 加载器)· index.cjs(node 加载器)· README.md(键一览与优先级)。 真实值放 config/platform.env —— 已 .gitignore 排除,不入库、不进导出。 TS 侧新增 src/platform-paths.ts 作部署路径的唯一解析处(零副作用): platformDir/stateDir/backupDir/artifactDir/installDir/scriptPath。 config.ts 接入这些字段;内置中继种子由生产 URL 改为空(改由 DSHS_OVERLAY_BOOTSTRAP_SEEDS 提供)。修掉 5 处硬编码绝对路径, src/** 注释中性化 116 行/53 文件。 scripts/** 36 个内部运维脚本:真令牌/PG 口令/隧道目标/主机号/路径 一律改从配置取;web/wake.html 的注册域白名单改为运行时从 location.hostname 推导;test/** 夹具 119 行/13 文件改 RFC 2606/5737 保留值,并把「内置种子必须为空」固化为回归断言。 取证:tsc 0 错;npm test 373/375(唯一失败 lease 属既有); 全仓扫描(大小写不敏感)代码面涉密标识 = 0;已部署 47 并零回归 (/opt/dsh/* 未搬家,/var/lib/dshs/platform 未被误建)。
This commit is contained in:
1 parent
9c2e7975ac
commit
452924d89c
100 files changed
+1167
-453
No files matched your search
@@ -15,7 +15,7 @@
|
||||
* 越界即 `bad_path`)
|
||||
* ② 启停其 DSH 实例 —— 与用户自己点「启动 / 停止」同一条 `supervisor` 路径
|
||||
* 这与 `requireAdmin` 既有职能(审批 / 禁用 / 删除用户)同级;服务器层面 admin 本就能读
|
||||
* `/var/lib/dshs/users/**`。**不扩大普通用户的能力面** —— 这些前缀下没有任何 `requireAuth` 版本。
|
||||
* `<data-root>/users/**`。**不扩大普通用户的能力面** —— 这些前缀下没有任何 `requireAuth` 版本。
|
||||
* @module dshs/web/routes/admin-user-ops
|
||||
*/
|
||||
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
import type { FastifyPluginAsync } from 'fastify'
|
||||
import { execFileSync, spawn } from 'node:child_process'
|
||||
import { rm } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
import { requireAdmin } from '../middleware/authn.js'
|
||||
import { userRoot } from '../../fs/workspace.js'
|
||||
import { scriptPath, stateDir } from '../../platform-paths.js'
|
||||
|
||||
/** 档案 36:新用户审批通过后自动铺「功能插件」分区的脚本(幂等)。 */
|
||||
/** 档案 36:新用户审批通过后自动铺「功能插件」分区的脚本(幂等)。
|
||||
* 路径由**安装根**推导(`DSH_INSTALL_DIR` 可覆盖),⛔ 不写死绝对路径。 */
|
||||
const ENSURE_BIZ_PLUGINS =
|
||||
process.env.DSH_ENSURE_BIZ_PLUGINS ?? '/opt/dshs/scripts/ensure-biz-plugins.cjs'
|
||||
process.env.DSH_ENSURE_BIZ_PLUGINS ?? scriptPath('ensure-biz-plugins.cjs')
|
||||
|
||||
/** 档案 138:「平台共享模型」逐用户授权的入参(只有开关本身)。 */
|
||||
const sharedModelSchema = {
|
||||
@@ -149,7 +152,7 @@ export const adminRoutes: FastifyPluginAsync = async (app) => {
|
||||
/**
|
||||
* 档案 47:实例共享运行时/工具清单(admin 只读)。
|
||||
* 数据全部用 shell 取(避免为此新增 import):版本 = 直接执行二进制;
|
||||
* 基线 = cat /opt/dsh/state/runtime-baseline.json;清单 = cat SHARED-TOOLS.md。
|
||||
* 基线 = cat <platform-dir>/state/runtime-baseline.json;清单 = cat SHARED-TOOLS.md。
|
||||
* 升级/卸载不在此做 —— 走 `scripts/install-*.sh`(幂等、带 sha256 校验),
|
||||
* 升级后必须跑 `runtime-baseline.cjs --accept` 刷新基线(与档案 44 的版本冻结配套)。
|
||||
*/
|
||||
@@ -182,7 +185,7 @@ export const adminRoutes: FastifyPluginAsync = async (app) => {
|
||||
let baseline: unknown = null
|
||||
let drift: string[] = []
|
||||
try {
|
||||
baseline = JSON.parse(sh('cat', ['/opt/dsh/state/runtime-baseline.json'], '{}'))
|
||||
baseline = JSON.parse(sh('cat', [join(stateDir(), 'runtime-baseline.json')], '{}'))
|
||||
const v = (baseline as { versions?: Record<string, string> }).versions ?? {}
|
||||
const num = (s: string): string => (s.match(/\d+\.\d+(\.\d+)?/) ?? [''])[0]
|
||||
const pair: Array<[string, string]> = [
|
||||
|
||||
@@ -14,6 +14,8 @@ import { AlreadyRunningError, CrashBreakerOpenError } from '../../supervisor/orc
|
||||
import { renderPatch } from '../../supervisor/patch.js'
|
||||
import { subdomainForUser } from '../../supervisor/proxy.js'
|
||||
import { homeRoot, userRoot } from '../../fs/workspace.js'
|
||||
import { join } from 'node:path'
|
||||
import { stateDir } from '../../platform-paths.js'
|
||||
import { latestSessionPreset } from '../../supervisor/session-preset.js'
|
||||
|
||||
const launchSchema = {
|
||||
@@ -192,7 +194,7 @@ export const dshRoutes: FastifyPluginAsync = async (app) => {
|
||||
// 档案 56 ②:实例能力清单(由 scripts/gen-capabilities.cjs 生成,与实例内 skill 同源)。
|
||||
app.get('/api/capabilities', { preHandler: requireAuth }, async () => {
|
||||
const { readFileSync } = await import('node:fs')
|
||||
const file = process.env.DSH_CAPABILITIES_FILE ?? '/opt/dsh/state/capabilities.json'
|
||||
const file = process.env.DSH_CAPABILITIES_FILE ?? join(stateDir(), 'capabilities.json')
|
||||
try {
|
||||
return JSON.parse(readFileSync(file, 'utf8'))
|
||||
} catch {
|
||||
|
||||
@@ -35,6 +35,8 @@ import {
|
||||
} from '../../net/relay/direct/index.js'
|
||||
import { loadRegistry, summarizeNetworks, listNodes } from '../../net/relay/registry.js'
|
||||
import { requireAdmin } from '../middleware/authn.js'
|
||||
import { join } from 'node:path'
|
||||
import { dataRootDir } from '../../platform-paths.js'
|
||||
|
||||
/** 本机配置落点(`DSHS_OVERLAY_NODE_CONFIG` 可覆盖;缺省与 `join` 的 `--config` 一致)。 */
|
||||
function nodeConfigFile(): string {
|
||||
@@ -45,7 +47,7 @@ function nodeConfigFile(): string {
|
||||
/** 注册表落点(`DSHS_OVERLAY_NODES_FILE` 可覆盖;缺省 = 参数表 `NODES_REGISTRY_FILE`)。 */
|
||||
function registryFile(): string {
|
||||
const v = process.env.DSHS_OVERLAY_NODES_FILE
|
||||
return typeof v === 'string' && v.trim() !== '' ? v.trim() : '/var/lib/dshs/overlay/nodes.json'
|
||||
return typeof v === 'string' && v.trim() !== '' ? v.trim() : join(dataRootDir(), 'overlay', 'nodes.json')
|
||||
}
|
||||
|
||||
const fss = {
|
||||
|
||||
Reference in new issue
Block a user