forked from bai/curriculum-project-hub
fix: clear dependency security advisories
This commit is contained in:
@@ -37,6 +37,12 @@ jobs:
|
||||
restore-keys: |
|
||||
cargo-${{ runner.os }}-
|
||||
|
||||
- name: Install cargo-audit 0.22.2
|
||||
run: cargo install cargo-audit --version 0.22.2 --locked
|
||||
|
||||
- name: Audit Rust vulnerabilities and unsoundness
|
||||
run: cargo audit --deny unsound
|
||||
|
||||
# Fonts for typst compilation (WU-4 onward): the engineering files are
|
||||
# CJK-heavy, so the compile-check / build tests need a CJK font present.
|
||||
# Harmless before those crates exist.
|
||||
|
||||
@@ -43,6 +43,9 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Audit production Node dependencies
|
||||
run: npm run audit:production
|
||||
|
||||
- name: Install Linux sandbox dependency
|
||||
run: sudo apt-get update && sudo apt-get install --yes bubblewrap socat
|
||||
|
||||
|
||||
+34
-1
@@ -1,7 +1,7 @@
|
||||
# Clear dependency advisories and gate releases
|
||||
|
||||
Type: task
|
||||
Status: open
|
||||
Status: resolved
|
||||
|
||||
## Question
|
||||
|
||||
@@ -9,3 +9,36 @@ Remove every current `npm audit --omit=dev` high finding and every `cargo audit`
|
||||
vulnerability/unsound finding through tested upgrades, compatible overrides or
|
||||
upstream fixes—not ignores—and add reproducible Node and Rust security-audit
|
||||
gates to CI and the production release evidence.
|
||||
|
||||
## Answer
|
||||
|
||||
All current production-high Node advisories and all Rust vulnerability/unsound
|
||||
advisories are removed without advisory ignores:
|
||||
|
||||
- `@larksuiteoapi/node-sdk` 1.70.0 declares Axios `~1.13.3`, which prevented npm
|
||||
from selecting a patched release. The Hub now has a targeted npm override to
|
||||
Axios 1.18.1. The direct SDK stays current; the override is locked and the
|
||||
full Hub type/build/test gate validates the resolved tree. A deterministic
|
||||
local-HTTP smoke also drives the real SDK/Axios stack through tenant-token,
|
||||
authenticated success and HTTP-error paths without external credentials.
|
||||
- `memmap2` is upgraded to 0.9.11 and `crossbeam-epoch` to 0.9.20.
|
||||
- `plist` is upgraded to 1.10.0, which moves its XML parser to `quick-xml`
|
||||
0.41.0.
|
||||
- crates.io `citationberg` 0.7.0 still pins vulnerable `quick-xml` 0.38.4.
|
||||
Cargo now patches it to the exact upstream citationberg commit that adopts
|
||||
`quick-xml` 0.41.0; the git revision is immutable in both manifest and lock.
|
||||
|
||||
`hub-check` runs the checked-in `npm run audit:production` command immediately
|
||||
after `npm ci`. `checker-check` installs the pinned cargo-audit 0.22.2 release
|
||||
with `--locked`, then runs `cargo audit --deny unsound`; vulnerabilities fail by
|
||||
default and unsound warnings are promoted to failures.
|
||||
|
||||
Current evidence:
|
||||
|
||||
- `npm audit --omit=dev --audit-level=high`: 0 vulnerabilities.
|
||||
- `cargo audit --deny unsound`: 0 vulnerabilities and 0 unsound warnings.
|
||||
- Four Rust `unmaintained` informational warnings remain visible and are not
|
||||
ignored; they are outside this issue's vulnerability/unsound acceptance
|
||||
criterion and will continue to appear in CI output.
|
||||
- Hub: type-check, build and 280 tests pass (10 environment-specific skips).
|
||||
- Rust: fmt, clippy with warnings denied, and all 53 workspace tests pass.
|
||||
|
||||
@@ -48,6 +48,7 @@ rollback and recovery, and no known critical security or data-integrity gaps.
|
||||
- [Confine the agent runtime and protect service credentials](issues/16-confine-agent-and-protect-credentials.md) — replace the Agent environment, deny host reads/writes from root, keep every writable SDK path inside the canonical project, require bubblewrap plus socat, emit bounded correlated diagnostics, and prove the boundary with the real Linux SDK under a capability-free non-root identity.
|
||||
- [Close MCP context and file-delivery escape paths](issues/17-close-mcp-data-egress-escapes.md) — use no-follow project-rooted file operations and delivery snapshots, remove Git-root delivery, and bind every Feishu MCP read to the run's project and chat.
|
||||
- [Enforce Organization status at the shared authorization seam](issues/22-enforce-organization-status.md) — deny non-ACTIVE tenants before principal resolution, serialize every customer mutation and run admission against Organization lifecycle updates, reauthorize queued work, and stage/publish attachments with crash recovery and explicit filesystem compensation.
|
||||
- [Clear dependency advisories and gate releases](issues/21-clear-dependency-security-advisories.md) — resolve Node production-high and Rust vulnerability/unsound advisories with locked compatible upgrades plus an exact upstream citationberg fix, and make both audits mandatory CI gates without ignores.
|
||||
|
||||
## Fog
|
||||
|
||||
|
||||
Generated
+11
-21
@@ -264,10 +264,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "citationberg"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "756ff1e3d43a9ecc8183932fb4d9fd3971236f3ce4acb62fe51d1cd43297547d"
|
||||
source = "git+https://github.com/typst/citationberg?rev=06a591e2f237d25e1dfdedac3f3d1494c496c52d#06a591e2f237d25e1dfdedac3f3d1494c496c52d"
|
||||
dependencies = [
|
||||
"quick-xml 0.38.4",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"serde_path_to_error",
|
||||
]
|
||||
@@ -481,9 +480,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
version = "0.9.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@@ -1403,9 +1402,9 @@ checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.10"
|
||||
version = "0.9.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
|
||||
checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -1642,13 +1641,13 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1"
|
||||
checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"indexmap",
|
||||
"quick-xml 0.39.4",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
@@ -1756,23 +1755,14 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.38.4"
|
||||
version = "0.41.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
|
||||
checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.39.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
|
||||
@@ -21,3 +21,8 @@ serde = { version = "1", features = ["derive"] }
|
||||
toml = "0.8"
|
||||
cph-diag = { path = "crates/cph-diag" }
|
||||
cph-model = { path = "crates/cph-model" }
|
||||
|
||||
# citationberg 0.7.0 on crates.io pins vulnerable quick-xml 0.38. Upstream has
|
||||
# adopted quick-xml 0.41 but has not published a replacement release yet.
|
||||
[patch.crates-io]
|
||||
citationberg = { git = "https://github.com/typst/citationberg", rev = "06a591e2f237d25e1dfdedac3f3d1494c496c52d" }
|
||||
|
||||
@@ -21,6 +21,11 @@ run the same command again. No systemd unit is installed until configuration,
|
||||
paths, Node, bubblewrap, `socat`, `cph --version`, PostgreSQL connectivity and directory
|
||||
ownership all pass preflight.
|
||||
|
||||
The deployment path also runs `npm run audit:production` from the locked clean
|
||||
install before building or restarting the service. A current high or critical
|
||||
production advisory therefore blocks deployment instead of becoming a warning
|
||||
buried in CI output.
|
||||
|
||||
An existing service account is accepted only when its primary group, home and
|
||||
non-login shell match the requested configuration and it has no supplementary
|
||||
groups. After provisioning, the installer executes path-access, built Hub,
|
||||
|
||||
@@ -36,8 +36,8 @@ rsync -az --delete \
|
||||
-e "ssh ${SSH_OPTS[*]}" \
|
||||
"$REPO_ROOT/hub/" "$DEPLOY_USER@$HOST:$HUB_DIR/"
|
||||
|
||||
# 2. Install deps + build on the host.
|
||||
ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" "cd '$HUB_DIR' && npm ci && npm run build"
|
||||
# 2. Install deps, prove the production dependency tree, then build on the host.
|
||||
ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" "cd '$HUB_DIR' && npm ci && npm run audit:production && npm run build"
|
||||
|
||||
# 3. Ensure the service is installed (idempotent), then restart.
|
||||
ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" "
|
||||
|
||||
Generated
+43
-16
@@ -10,7 +10,7 @@
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.3.202",
|
||||
"@fastify/cookie": "^11.0.2",
|
||||
"@larksuiteoapi/node-sdk": "^1.66.1",
|
||||
"@larksuiteoapi/node-sdk": "^1.70.0",
|
||||
"@prisma/client": "^6.19.3",
|
||||
"ai": "^7.0.16",
|
||||
"dotenv": "^17.4.2",
|
||||
@@ -874,9 +874,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@larksuiteoapi/node-sdk": {
|
||||
"version": "1.68.0",
|
||||
"resolved": "https://registry.npmjs.org/@larksuiteoapi/node-sdk/-/node-sdk-1.68.0.tgz",
|
||||
"integrity": "sha512-ip14+pWAv2La3bss4oDDtee2P5xBLDXuvmzhTvkxQMcPA5jCffFsler1TvNt4MyW6pexscj72AEWektyZwU9Yw==",
|
||||
"version": "1.70.0",
|
||||
"resolved": "https://registry.npmjs.org/@larksuiteoapi/node-sdk/-/node-sdk-1.70.0.tgz",
|
||||
"integrity": "sha512-CzVfMbh2MO+cVWQgQGeYN9KkFdX6mofYYTsIjImU0hQqlxaXKzHcUEwG6mrpsmU2LWqYYtIGwCSIZjYQRjD6kw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "~1.13.3",
|
||||
@@ -1621,6 +1621,18 @@
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ai": {
|
||||
"version": "7.0.16",
|
||||
"resolved": "https://registry.npmjs.org/ai/-/ai-7.0.16.tgz",
|
||||
@@ -1717,14 +1729,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.13.6",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
|
||||
"integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.18.1.tgz",
|
||||
"integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.11",
|
||||
"follow-redirects": "^1.16.0",
|
||||
"form-data": "^4.0.5",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"proxy-from-env": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
@@ -2004,7 +2017,6 @@
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
@@ -2823,6 +2835,19 @@
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "6",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
|
||||
@@ -3353,8 +3378,7 @@
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.15",
|
||||
@@ -3735,10 +3759,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/pure-rand": {
|
||||
"version": "6.1.0",
|
||||
|
||||
+7
-1
@@ -9,7 +9,7 @@
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.3.202",
|
||||
"@fastify/cookie": "^11.0.2",
|
||||
"@larksuiteoapi/node-sdk": "^1.66.1",
|
||||
"@larksuiteoapi/node-sdk": "^1.70.0",
|
||||
"@prisma/client": "^6.19.3",
|
||||
"ai": "^7.0.16",
|
||||
"dotenv": "^17.4.2",
|
||||
@@ -22,12 +22,18 @@
|
||||
"typescript": "^5.7.0",
|
||||
"vitest": "^4.1.10"
|
||||
},
|
||||
"overrides": {
|
||||
"@larksuiteoapi/node-sdk": {
|
||||
"axios": "1.18.1"
|
||||
}
|
||||
},
|
||||
"description": "Curriculum Project Hub — Feishu-group collaboration + Claude Code SDK agent runtime. Aligns to spec/System (ADR-0001..0004, 0017).",
|
||||
"scripts": {
|
||||
"dev": "npm run prisma:migrate && tsx watch src/server.ts",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"start": "npm run prisma:migrate && node dist/server.js",
|
||||
"check": "tsc -p tsconfig.json --noEmit",
|
||||
"audit:production": "npm audit --omit=dev --audit-level=high",
|
||||
"prisma:generate": "prisma generate --schema prisma/schema.prisma",
|
||||
"prisma:validate": "DATABASE_URL=${DATABASE_URL:-postgresql://stub:stub@127.0.0.1:5432/stub} prisma validate --schema prisma/schema.prisma",
|
||||
"prisma:migrate": "DATABASE_URL=${DATABASE_URL:-postgresql://paradigm:paradigm@127.0.0.1:5432/paradigm} prisma migrate deploy --schema prisma/schema.prisma",
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
|
||||
import * as lark from "@larksuiteoapi/node-sdk";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
|
||||
const openServers: ReturnType<typeof createServer>[] = [];
|
||||
|
||||
describe("real Lark SDK HTTP transport", () => {
|
||||
afterEach(async () => {
|
||||
await Promise.all(openServers.splice(0).map(async (server) => {
|
||||
server.closeAllConnections();
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.close((error) => error === undefined ? resolve() : reject(error));
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
it("uses overridden Axios for token, authenticated success, and HTTP error paths", async () => {
|
||||
const requests: Array<{
|
||||
readonly method: string | undefined;
|
||||
readonly url: string | undefined;
|
||||
readonly authorization: string | undefined;
|
||||
readonly body: string;
|
||||
}> = [];
|
||||
const server = createServer(async (request, response) => {
|
||||
const body = await readBody(request);
|
||||
requests.push({
|
||||
method: request.method,
|
||||
url: request.url,
|
||||
authorization: request.headers.authorization,
|
||||
body,
|
||||
});
|
||||
routeSmokeRequest(request, response, body);
|
||||
});
|
||||
openServers.push(server);
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.once("error", reject);
|
||||
server.listen(0, "127.0.0.1", resolve);
|
||||
});
|
||||
const address = server.address();
|
||||
if (address === null || typeof address === "string") throw new Error("local HTTP server has no TCP address");
|
||||
const domain = `http://127.0.0.1:${address.port}`;
|
||||
const client = new lark.Client({
|
||||
appId: "cli_transport_smoke",
|
||||
appSecret: "transport-smoke-secret",
|
||||
domain,
|
||||
loggerLevel: lark.LoggerLevel.error,
|
||||
});
|
||||
|
||||
await expect(client.request<{ readonly code: number; readonly data: { readonly ok: boolean } }>({
|
||||
method: "GET",
|
||||
url: "/open-apis/smoke/success",
|
||||
params: { probe: "axios-override" },
|
||||
})).resolves.toEqual({ code: 0, data: { ok: true } });
|
||||
|
||||
await expect(client.request({
|
||||
method: "GET",
|
||||
url: "/open-apis/smoke/failure",
|
||||
})).rejects.toMatchObject({
|
||||
response: {
|
||||
status: 429,
|
||||
data: { code: 999_429, msg: "forced smoke failure" },
|
||||
},
|
||||
});
|
||||
|
||||
expect(requests).toHaveLength(3);
|
||||
expect(requests[0]).toMatchObject({
|
||||
method: "POST",
|
||||
url: "/open-apis/auth/v3/tenant_access_token/internal",
|
||||
authorization: undefined,
|
||||
});
|
||||
expect(JSON.parse(requests[0]!.body)).toEqual({
|
||||
app_id: "cli_transport_smoke",
|
||||
app_secret: "transport-smoke-secret",
|
||||
});
|
||||
expect(requests[1]).toMatchObject({
|
||||
method: "GET",
|
||||
url: "/open-apis/smoke/success?probe=axios-override",
|
||||
authorization: "Bearer tenant-transport-smoke",
|
||||
});
|
||||
expect(requests[2]).toMatchObject({
|
||||
method: "GET",
|
||||
url: "/open-apis/smoke/failure",
|
||||
authorization: "Bearer tenant-transport-smoke",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function readBody(request: IncomingMessage): Promise<string> {
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of request) {
|
||||
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||
}
|
||||
return Buffer.concat(chunks).toString("utf8");
|
||||
}
|
||||
|
||||
function routeSmokeRequest(request: IncomingMessage, response: ServerResponse, body: string): void {
|
||||
if (request.method === "POST" && request.url === "/open-apis/auth/v3/tenant_access_token/internal") {
|
||||
const credential = JSON.parse(body) as { app_id?: unknown; app_secret?: unknown };
|
||||
if (credential.app_id !== "cli_transport_smoke" || credential.app_secret !== "transport-smoke-secret") {
|
||||
sendJson(response, 401, { code: 401, msg: "bad smoke credential" });
|
||||
return;
|
||||
}
|
||||
sendJson(response, 200, {
|
||||
code: 0,
|
||||
msg: "ok",
|
||||
tenant_access_token: "tenant-transport-smoke",
|
||||
expire: 3_600,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (request.method === "GET" && request.url === "/open-apis/smoke/success?probe=axios-override") {
|
||||
sendJson(response, 200, { code: 0, data: { ok: true } });
|
||||
return;
|
||||
}
|
||||
if (request.method === "GET" && request.url === "/open-apis/smoke/failure") {
|
||||
sendJson(response, 429, { code: 999_429, msg: "forced smoke failure" });
|
||||
return;
|
||||
}
|
||||
sendJson(response, 404, { code: 404, msg: "unknown smoke route" });
|
||||
}
|
||||
|
||||
function sendJson(response: ServerResponse, statusCode: number, body: unknown): void {
|
||||
response.writeHead(statusCode, { "content-type": "application/json" });
|
||||
response.end(JSON.stringify(body));
|
||||
}
|
||||
Reference in New Issue
Block a user