@oj-module/cli 0.2.42 → 0.2.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/shell-dist/assets/runtime.js +2 -2
- package/shell-dist/index.html +2 -2
- package/shell-dist/versions.json +3 -3
- package/src/market/__tests__/verify.test.ts +32 -1
- package/src/market/verify.ts +7 -3
- package/templates/config.yaml +43 -103
- package/vendor/host-versions.json +3 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oj-module/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.43",
|
|
5
5
|
"description": "React Antd 模块工程命令行工具(含预构建宿主 shell-dist)",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@faker-js/faker": "^10.4.0",
|
|
52
|
-
"@oj-module/runtime": "0.2.
|
|
52
|
+
"@oj-module/runtime": "0.2.43",
|
|
53
53
|
"@redocly/cli": "^2.51.0",
|
|
54
54
|
"@tailwindcss/vite": "^4.3.0",
|
|
55
55
|
"cac": "^6.7.14",
|
|
@@ -304,10 +304,10 @@ function getAppInfo() {
|
|
|
304
304
|
return {
|
|
305
305
|
"pkg": {
|
|
306
306
|
"name": "@oj-module/runtime",
|
|
307
|
-
"version": "0.2.
|
|
307
|
+
"version": "0.2.43",
|
|
308
308
|
"license": "MIT"
|
|
309
309
|
},
|
|
310
|
-
"lastBuildTime": "2026-10-26
|
|
310
|
+
"lastBuildTime": "2026-10-26 20:27:40"
|
|
311
311
|
};
|
|
312
312
|
}
|
|
313
313
|
var init_get_app_info = __esmMin((() => {}));
|
package/shell-dist/index.html
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" href="/favicon.ico" />
|
|
7
7
|
<title>React Antd Admin · Shell</title>
|
|
8
|
-
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' https://modules.cdn.example.com 'wasm-unsafe-eval' 'nonce-
|
|
8
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' https://modules.cdn.example.com 'wasm-unsafe-eval' 'nonce-1qa+1NwgUpqlsLbbr7v3iQ=='; script-src-attr 'none'; connect-src 'self' data: https://modules.cdn.example.com; style-src 'self' https://modules.cdn.example.com 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; frame-src https://ant.design https://react.dev https://condorheroblog.github.io; form-action 'none'; base-uri 'none'; object-src 'none'; upgrade-insecure-requests" />
|
|
9
9
|
|
|
10
|
-
<script type="importmap" nonce="
|
|
10
|
+
<script type="importmap" nonce="1qa+1NwgUpqlsLbbr7v3iQ==">{
|
|
11
11
|
"imports": {
|
|
12
12
|
"react": "/assets/react.js",
|
|
13
13
|
"react/jsx-runtime": "/assets/jsx-runtime.js",
|
package/shell-dist/versions.json
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
"react-router": "7.18.2",
|
|
8
8
|
"react-router/dom": "7.18.2",
|
|
9
9
|
"@tanstack/react-query": "5.102.8",
|
|
10
|
-
"@oj-module/runtime": "0.2.
|
|
11
|
-
"@oj-module/runtime/contract": "0.2.
|
|
12
|
-
"@oj-module/runtime/contract/errors": "0.2.
|
|
10
|
+
"@oj-module/runtime": "0.2.43",
|
|
11
|
+
"@oj-module/runtime/contract": "0.2.43",
|
|
12
|
+
"@oj-module/runtime/contract/errors": "0.2.43",
|
|
13
13
|
"@plane/kit": "0.1.20",
|
|
14
14
|
"@plane/editor": "0.1.20",
|
|
15
15
|
"antd": "6.6.1",
|
|
@@ -11,13 +11,16 @@ import { Buffer } from "node:buffer";
|
|
|
11
11
|
import { generateKeyPairSync } from "node:crypto";
|
|
12
12
|
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { tmpdir } from "node:os";
|
|
14
|
-
import { join } from "node:path";
|
|
14
|
+
import { dirname, join } from "node:path";
|
|
15
15
|
|
|
16
16
|
import { describe, expect, it } from "vitest";
|
|
17
17
|
import { parse, stringify } from "yaml";
|
|
18
|
+
import { createDeterministicTgz } from "../../deterministic-tar";
|
|
18
19
|
import { recomputeIndex, signIndex } from "../../publish";
|
|
20
|
+
import { signCommand } from "../../sign";
|
|
19
21
|
import { buildIndex } from "../build-index";
|
|
20
22
|
import { publishPackage } from "../publish";
|
|
23
|
+
import { readTgz } from "../scan";
|
|
21
24
|
import { verifyMarket } from "../verify";
|
|
22
25
|
|
|
23
26
|
const MOUNTS = " - prefix: /api\n api: src\n - prefix: /cdn\n web: ../cdn\n";
|
|
@@ -72,6 +75,34 @@ describe("given 一个正常落地的包 When 离线验包", () => {
|
|
|
72
75
|
});
|
|
73
76
|
});
|
|
74
77
|
|
|
78
|
+
describe("given 真实工程包(manifest 按 C2-29 整体省略 archive 占位)When 离线验包", () => {
|
|
79
|
+
it("then manifest 结构不因此打叉(REG-CS8 回归:ojm build --bundle 不落 archive ≠ 缺必填)", async () => {
|
|
80
|
+
const root = await seed();
|
|
81
|
+
const tgz = join(root, "cdn", "demo-solution-0.1.0.tgz");
|
|
82
|
+
// 解包 → 摘掉根 manifest 的 archive(fixture 有、真实方案无的字段差)→ 确定性重打包 → 重签 → 重建索引
|
|
83
|
+
const staging = mkdtempSync(join(tmpdir(), "ojm-verify-noarchive-"));
|
|
84
|
+
for (const e of readTgz(new Uint8Array(readFileSync(tgz)))) {
|
|
85
|
+
if (e.name.endsWith("/"))
|
|
86
|
+
continue;
|
|
87
|
+
const abs = join(staging, e.name);
|
|
88
|
+
mkdirSync(dirname(abs), { recursive: true });
|
|
89
|
+
writeFileSync(abs, e.content);
|
|
90
|
+
}
|
|
91
|
+
const rootManifestPath = join(staging, "manifest.yaml");
|
|
92
|
+
const manifest = parse(readFileSync(rootManifestPath, "utf-8")) as Record<string, unknown>;
|
|
93
|
+
delete manifest.archive;
|
|
94
|
+
writeFileSync(rootManifestPath, stringify(manifest));
|
|
95
|
+
await createDeterministicTgz(staging, tgz);
|
|
96
|
+
signCommand(tgz, { id: KEY_ID, privateKeyPem: testPem(), registryId: REGISTRY_ID });
|
|
97
|
+
await buildIndex({ projectRoot: root, id: KEY_ID, privateKeyPem: testPem() });
|
|
98
|
+
|
|
99
|
+
const result = await verifyMarket({ projectRoot: root });
|
|
100
|
+
|
|
101
|
+
expect(itemOf(result, "manifest 结构")?.ok).toBe(true);
|
|
102
|
+
rmSync(staging, { recursive: true, force: true });
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
75
106
|
describe("given 预发布版本(文件名含连字符)包体被篡改 When 离线验包", () => {
|
|
76
107
|
it("then 完整性仍能检出(不再因文件名解析错配而静默放过,REG-CS1 边界)", async () => {
|
|
77
108
|
const root = newProject();
|
package/src/market/verify.ts
CHANGED
|
@@ -295,7 +295,11 @@ export function expiryCheck(text: string | null): VerifyCheck {
|
|
|
295
295
|
};
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
-
/**
|
|
298
|
+
/**
|
|
299
|
+
* manifest 结构:必填字段 + 内嵌原生清单 desc 非空(等值要求已移除,见 §9.3)。
|
|
300
|
+
* 必填不含 archive:契约 C2-29 允许 Form A 整体省略,`ojm build --bundle` 对真实方案的
|
|
301
|
+
* 落盘形态即省略(fixture 会写 file 占位)——把它当必填会让一切真实工程包验包必红。
|
|
302
|
+
*/
|
|
299
303
|
function structureCheck(bytes: Uint8Array, file: string): VerifyCheck[] {
|
|
300
304
|
let entries: ReturnType<typeof readTgz>;
|
|
301
305
|
try {
|
|
@@ -308,12 +312,12 @@ function structureCheck(bytes: Uint8Array, file: string): VerifyCheck[] {
|
|
|
308
312
|
if (root === undefined)
|
|
309
313
|
return [{ item: "manifest 结构", ok: false, detail: `${file}:包内缺 manifest.yaml` }];
|
|
310
314
|
const manifest = (yamlParse(root.content.toString("utf-8")) ?? {}) as Record<string, unknown>;
|
|
311
|
-
const missing = ["name", "version", "summary", "peerRuntime"
|
|
315
|
+
const missing = ["name", "version", "summary", "peerRuntime"].filter(k => manifest[k] === undefined);
|
|
312
316
|
const out: VerifyCheck[] = [{
|
|
313
317
|
item: "manifest 结构",
|
|
314
318
|
ok: missing.length === 0,
|
|
315
319
|
detail: missing.length === 0
|
|
316
|
-
? `${file}:必填字段齐备(name/version/summary/peerRuntime
|
|
320
|
+
? `${file}:必填字段齐备(name/version/summary/peerRuntime)`
|
|
317
321
|
: `${file}:缺必填字段 ${missing.join(", ")}`,
|
|
318
322
|
}];
|
|
319
323
|
|
package/templates/config.yaml
CHANGED
|
@@ -1,117 +1,61 @@
|
|
|
1
|
-
# oj
|
|
2
|
-
# 本文件由 ojm init 生成;config 内相对路径相对本文件所在目录。
|
|
3
|
-
# 更多能力见手册 §10:vars / broker / tasks / oidc / ws / html_meta / secrets。
|
|
4
|
-
#
|
|
5
|
-
# ---- 证书与密钥的唯一落点:`./config/`(= 工程根/config/,本文件同级的子目录)----
|
|
6
|
-
# 三件套由 `ojm init` 现场签发(dev 缺证时 `ojm dev` 也会补签),逐把的作用与后果:
|
|
7
|
-
#
|
|
8
|
-
# ① private.pem —— 证书签发私钥(RSA 2048)。只用来给 ③ 签名,**oj 不读它**,
|
|
9
|
-
# 也绝不出部署机、不入仓。丢了不需要恢复:重新签发一套即可(旧的 ③ 作废)。
|
|
10
|
-
# ② public.pem —— 与 ① 成对的公钥,oj 启动时拿它验 ③ 的 RS256 签名。
|
|
11
|
-
# 配错路径或与 ③ 不是同一对 → oj 验签失败、启动即拒(读作「证书无效」)。
|
|
12
|
-
# 由 server.public_key_path 引用。
|
|
13
|
-
# ③ cert.jws —— JWS 证书(RS256 紧凑三段,payload 仅 nbf/exp),**oj 的启动闸门**:
|
|
14
|
-
# 缺失、过期、签名对不上 → fail-fast 拒启,devkit 手册明确**无任何 config/CLI 绕过开关**。
|
|
15
|
-
# 默认有效期 3650 天(短有效期等于定时炸弹);过期只能重新签发一套 ①②③。
|
|
16
|
-
# 由 server.certificate_path 引用。
|
|
17
|
-
#
|
|
18
|
-
# 另有一对与上面无关的密钥(jwt_secret 密封用,init 密封成功后追加到本文件末尾):
|
|
19
|
-
# secrets.private_key_path ./config/secrets-private.pem 解 jwt_secret 密文的私钥,只放部署机
|
|
20
|
-
# secrets.public_key_path ./config/secrets-public.pem 加密用的公钥,可随代码分发
|
|
21
|
-
# (密文形如 ENC 后跟方括号包裹的字串;未密封时 config 里是 32 字节十六进制明文)
|
|
22
|
-
#
|
|
23
|
-
# ojm 侧的解析入口是 `resolveCertDir()`,由本文件位置派生;改落点只需动那一处 + 本段注释。
|
|
1
|
+
# oj 服务配置(字段手册见 devkit oj-api-dev / oj --help)。由 ojm init 生成,相对路径相对本文件所在目录。
|
|
24
2
|
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
# 手写部署(不经 ojm)时才需要自己加回一条 `- prefix: /api` + `api: dist`。
|
|
3
|
+
# ---- 证书三件套在 ./config/(init 已现场签发)----
|
|
4
|
+
# private.pem 签发私钥:只用于给 cert.jws 签名,oj 不读它;泄露或丢失就重签一套,旧的作废
|
|
5
|
+
# public.pem oj 启动时验 cert.jws 签名用(server.public_key_path)
|
|
6
|
+
# cert.jws 启动闸门:缺失/过期/签名不符直接拒启,无 config/CLI 绕过(默认 10 年有效期)
|
|
7
|
+
# 另有一对 secrets-*.pem:init 密封 jwt_secret 后追加到本文件末尾,同样只放部署机。
|
|
8
|
+
|
|
9
|
+
# 站点挂载:一行 = 一个 URL 前缀 + 一个目录(api/web 二选一)。
|
|
10
|
+
# 这里不放 api 挂载是有意的:本工程是 src/<name>/{api,web} 布局,源码由 ojm dev
|
|
11
|
+
# 以 --module-root src 供给、产物由 ojm preview 以 --api-path dist/api 供给,都不走 mounts。
|
|
12
|
+
# 手写部署(不用 ojm)时才需要加回一条 `- prefix: /api` + `api: dist`。
|
|
36
13
|
mounts:
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# 不得给此挂载设 spa——缺文件必须返回 404,回落 index.html 会让市场解析崩。
|
|
14
|
+
# 本地市场 CDN:直出工程根 cdn/。seed 里 framework.market_cdn_url 缺省就是 /cdn,本站点自供免 setup。
|
|
15
|
+
# 生产删掉这条,并把该设置指向真 CDN(绝对地址)。不能设 spa:缺文件必须 404,
|
|
16
|
+
# 回落 index.html 会让市场解析崩。
|
|
41
17
|
- prefix: /cdn
|
|
42
18
|
web: ./cdn
|
|
43
|
-
#
|
|
44
|
-
# 60s stale-while-revalidate——yank 最坏 120s 生效(Q8)。ETag/If-None-Match→304 由 oj
|
|
45
|
-
# 静态层原生支持;本头只加在读面(静态挂载),写入面(ojm market build-index)不发 HTTP 头。
|
|
19
|
+
# 读面缓存 60s:yank 最坏 120s 生效。304 由 oj 静态层自带,这里只管新鲜窗口。
|
|
46
20
|
headers:
|
|
47
21
|
Cache-Control: 'max-age=60, stale-while-revalidate=60'
|
|
48
|
-
#
|
|
49
|
-
#
|
|
22
|
+
# 生产要 oj 直出前端(前后端同端口的 SPA,即 ojm preview 形态)就解开下面三行,先 ojm build。
|
|
23
|
+
# preview 自己会注入等价挂载,平时不用动。
|
|
50
24
|
# - prefix: "/"
|
|
51
|
-
# web: "./dist/web" #
|
|
25
|
+
# web: "./dist/web" # 相对本文件 → 工程根/dist/web
|
|
52
26
|
# spa: true
|
|
53
|
-
# 嵌套 handler 组(oj v0.1.64)无需配置开关,组织方式见 api.ts 顶部注释。
|
|
54
27
|
|
|
55
28
|
server:
|
|
56
|
-
host: 127.0.0.1 #
|
|
29
|
+
host: 127.0.0.1 # 钉死 127.0.0.1:oj 默认绑 [::1],localhost 在反代下解析有坑
|
|
57
30
|
port: 9778
|
|
58
31
|
public_key_path: ./config/public.pem
|
|
59
32
|
certificate_path: ./config/cert.jws
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
#
|
|
67
|
-
schema_validation: true
|
|
68
|
-
# ---- 单 isolate 堆限额(v0.1.40,默认 256MiB,下限 32MiB)----
|
|
69
|
-
js_heap_limit_bytes: 268435456
|
|
70
|
-
# ---- 路由级超时(v0.1.30):pattern 按声明序首个命中,且是含 base 的全路径 ----
|
|
71
|
-
route_timeouts: []
|
|
72
|
-
# ---- 统一响应头(v0.1.30)----
|
|
73
|
-
response_headers: {}
|
|
74
|
-
# ---- 热更端点(ojm install 的 reloading 段消费;显式关闭 = 安装器 reloading 段可读失败)----
|
|
75
|
-
# ojm:reload
|
|
76
|
-
reload_api: true
|
|
77
|
-
# ---- 直传路由 PUT {base}/blob/{key} 的体积上限(v0.1.30,默认 1GiB)----
|
|
78
|
-
# 与 max_upload_bytes(multipart,默认 10MB)是两套闸,别混。
|
|
79
|
-
blob_upload_max_bytes: 1073741824
|
|
80
|
-
# ---- CORS(v0.1.35):缺这一段 = 不挂 CORS 层;credentials 必须配显式 origins ----
|
|
33
|
+
migrate_on_start: auto # auto=启动即迁移;release 建议 verify(账本落后拒启,先 oj migrate)
|
|
34
|
+
schema_validation: true # 契约 .schema 违反即 400;仅当 .schema 与旧 handler 冲突时临时关
|
|
35
|
+
js_heap_limit_bytes: 268435456 # 单 isolate 堆限额(默认 256MiB,下限 32MiB)
|
|
36
|
+
route_timeouts: [] # 路由级超时;pattern 按声明序首个命中,写含 base 的全路径
|
|
37
|
+
response_headers: {} # 统一响应头
|
|
38
|
+
reload_api: true # 热更端点 /ojm:reload:安装器的 reloading 段要用,关掉安装会失败
|
|
39
|
+
blob_upload_max_bytes: 1073741824 # PUT blob 单文件上限(默认 1GiB;与 multipart 的 10MB 是两道闸)
|
|
81
40
|
cors:
|
|
82
|
-
origins: [] #
|
|
41
|
+
origins: [] # 空 = 放行任意源;要带凭据必须列具体源
|
|
83
42
|
credentials: false
|
|
84
43
|
db:
|
|
85
44
|
default: 'sqlite://db.sqlite' # 相对 config 目录;缺文件自动建空库
|
|
86
45
|
|
|
87
|
-
# ---- 安装序号(ojm install 每次安装自增一次,作为 reload 热更触发变更——unchanged 判定基于
|
|
88
|
-
# config 文档 sha,无落盘变更则热更恒失败。勿删行/勿手工回写旧值。)----
|
|
89
46
|
vars:
|
|
47
|
+
# ojm install 每次安装自增一次,用来触发 reload 热更。别删行、别手工回写旧值。
|
|
90
48
|
ojm_install_seq: 0
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
# 出站到攻击者指定源)。部署侧填真实对外地址(如 https://your-site.example.com);缺省留空 = fail-closed,
|
|
94
|
-
# 相对 URL 原样透传由下层 fetch 按站点自身地址解析,深检探针则跳过(info 项),绝不猜一个源。
|
|
49
|
+
# 站点对外地址。装方案时服务端拿它把 /cdn 这类相对地址补全成绝对 URL(深检探针也用它)。
|
|
50
|
+
# 故意不读请求头 Host(防伪造 Host 牵引出站):不配 = fail-closed,不会替你猜。
|
|
95
51
|
# canonical_origin: "https://your-site.example.com"
|
|
96
52
|
|
|
97
|
-
# ---- 平台 exec 白名单(ojm install 的解压/迁移两处消费;模板逐字对齐 lifecycle steps 命令构造,
|
|
98
|
-
# 不得增删——多一个 token 都会 NotCapable)----
|
|
99
53
|
platform:
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
-
root: src
|
|
106
|
-
# ---- U6 信任库加固(P3-1;P2-2 红线 spike 结论)----
|
|
107
|
-
# 威胁:devkit 0.1.75 语义下 fs: 段对全部模块生效(jail = fs.root),且 trusted_paths 只增不减——
|
|
108
|
-
# 信任库落在第三方方案模块可写的 fs.root 内即可被其伪造信任锚。加固须两端配合:
|
|
109
|
-
# ① 本模板已将信任库默认路径移出 modules/ 安装子树(见 _lifecycle 默认 `.solutions/trusted-keys.yaml`,
|
|
110
|
-
# 落在 fs.root 之外的部署根,第三方方案模块 jail 之外);
|
|
111
|
-
# ② **部署侧**须按 oj 语义补 `platform.trusted_paths`(指向运行时信任库目录,该目录须先存在——
|
|
112
|
-
# oj 对不存在的 trusted_paths 装配 fail-fast,故不可在模板里硬编码尚未创建的目录)显式授权给
|
|
113
|
-
# _platform 特权模块写信任库,并收窄第三方方案模块的 fs.root 至其安装子树,方可彻底隔离。
|
|
114
|
-
# 本仓负责①(代码路径);②属部署/上游配置,留作部署清单项(P3-1 备案,不硬编码以免 oj serve 装配失败)。
|
|
54
|
+
modules: [_platform] # 安装器热更 config 需要 _platform 特权;删了会在装到最后一步报 NotCapable
|
|
55
|
+
root: src # 后端模块源码根(src/<name>/api 的父目录);preview 派生 config 时改写成 dist
|
|
56
|
+
# 信任库默认落在安装子树之外(.solutions/trusted-keys.yaml),第三方方案模块碰不到。
|
|
57
|
+
# 部署侧还应补 platform.trusted_paths 授权 _platform 写库、并把第三方模块 fs.root 收窄到各自安装子树。
|
|
58
|
+
# 下面三条命令与安装器逐字对齐(含每个空格),一个 token 都不能动:
|
|
115
59
|
exec:
|
|
116
60
|
_platform:
|
|
117
61
|
allow:
|
|
@@ -119,18 +63,14 @@ platform:
|
|
|
119
63
|
- 'tar -xzf ${path:archive} -C ${path:dest}'
|
|
120
64
|
- 'oj migrate --format json -d ${path:dir} ${raw:module}'
|
|
121
65
|
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
# 缺本段 = fs.* 抛 NotCapable,且失败发生在任务文件落盘之前:表现为「POST 安装返回 200、
|
|
125
|
-
# 但 task 查询恒 404」,排查成本极高。生产收紧口径见上面 platform 段的 U6 说明
|
|
126
|
-
# (fs.root 收窄到安装子树 + third-party 模块 jail 隔离属部署清单项)。
|
|
66
|
+
# 安装器落盘面:解包到 modules/.staging、写 dist/modules、备份 db.sqlite,全在 config 目录内。
|
|
67
|
+
# 缺这段会 NotCapable,且症状很阴:安装提交返回 200,但 task 查询恒 404。
|
|
127
68
|
fs:
|
|
128
69
|
root: .
|
|
129
70
|
readonly: false
|
|
130
71
|
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
# ldap_uid_attr、ldap_email_attr,group=ldap,即时生效)。本段改动属 restart_pending,需重启。
|
|
72
|
+
# LDAP 连接段:解开注释填值即接通目录服务;字段映射在「系统设置 → LDAP」里配,改本段要重启。
|
|
73
|
+
# oj 严格解析这段,只写下面这些键,多一个键启动 fail-fast。
|
|
134
74
|
# ldap:
|
|
135
75
|
# url: "ldap://127.0.0.1:389"
|
|
136
76
|
# bind_dn: ""
|
|
@@ -138,14 +78,14 @@ fs:
|
|
|
138
78
|
# timeout_ms: 3000
|
|
139
79
|
# start_tls: false
|
|
140
80
|
# tls_skip_verify: false
|
|
81
|
+
|
|
141
82
|
auth:
|
|
142
83
|
jwt_secret: __JWT_SECRET__ # init 随机生成;生产必须更换
|
|
143
84
|
access_token_duration: 2h
|
|
144
85
|
refresh_token_duration: 720h
|
|
145
|
-
anonymous_paths: #
|
|
86
|
+
anonymous_paths: # 不带 token 也能访问的路径;漏列则未登录访问一律 401
|
|
146
87
|
- /auth/login
|
|
147
|
-
- /auth/ldap-login #
|
|
88
|
+
- /auth/ldap-login # LDAP 目录登录
|
|
148
89
|
- /auth/refresh
|
|
149
90
|
- /auth/logout
|
|
150
|
-
#
|
|
151
|
-
- /system/login-methods
|
|
91
|
+
- /system/login-methods # 登录页「登录方式」Tabs 的数据源,未登录就要能读
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"react-router": "7.18.2",
|
|
9
9
|
"react-router/dom": "7.18.2",
|
|
10
10
|
"@tanstack/react-query": "5.102.8",
|
|
11
|
-
"@oj-module/runtime": "0.2.
|
|
12
|
-
"@oj-module/runtime/contract": "0.2.
|
|
13
|
-
"@oj-module/runtime/contract/errors": "0.2.
|
|
11
|
+
"@oj-module/runtime": "0.2.43",
|
|
12
|
+
"@oj-module/runtime/contract": "0.2.43",
|
|
13
|
+
"@oj-module/runtime/contract/errors": "0.2.43",
|
|
14
14
|
"@plane/kit": "0.1.20",
|
|
15
15
|
"@plane/editor": "0.1.20",
|
|
16
16
|
"antd": "6.6.1",
|