fix: 加固运行时证据凭据脱敏
This commit is contained in:
parent
e480c0edcb
commit
269289a859
@ -4,6 +4,8 @@
|
||||
|
||||
**Goal:** Implement Phase 1 of the approved API runtime foundation: typed runtime config, classified runtime errors, structured runtime evidence, and a lightweight `GET /health/runtime` endpoint that can be used by Jenkins/K8s/ktWorkflow in the next plan.
|
||||
|
||||
**Post-review amendment:** The final public `GET /health/runtime` contract intentionally returns only `service`, `checkedAt`, `status`, and `checks`. Earlier code snippets in this plan that included `config` or described the endpoint as a safe config view were superseded during code review to avoid exposing runtime topology on an unauthenticated health endpoint. The internal `RuntimeConfigService` still owns the safe snapshot used to derive checks.
|
||||
|
||||
**Architecture:** Add a focused `src/runtime` Nest module. It depends on `ConfigModule` and `CommonModule`, exports typed runtime primitives, and keeps business modules unchanged during this phase. The endpoint returns plain machine-readable JSON, not a Vben response wrapper, so deployment tooling can consume it directly.
|
||||
|
||||
**Tech Stack:** NestJS 11, TypeScript 5.9, Jest 29 with `ts-jest`, existing `@nestjs/config`, existing `ToolsService`, existing Swagger/Knife4j setup.
|
||||
@ -1245,11 +1247,12 @@ git commit -m "feat: 添加API运行时健康检查"
|
||||
### Runtime health
|
||||
|
||||
The API exposes `GET /health/runtime` for deployment and local smoke checks.
|
||||
|
||||
Post-review note: the public response no longer returns `config`; it exposes status and config check results only.
|
||||
It returns plain JSON with:
|
||||
|
||||
- `status`: `live`, `ready`, `degraded`, or `blocked`.
|
||||
- `checks`: process and runtime config checks.
|
||||
- `config`: a safe runtime config snapshot with secrets masked.
|
||||
|
||||
The endpoint is machine-readable and intentionally does not use the Vben
|
||||
response wrapper.
|
||||
|
||||
@ -7,9 +7,9 @@ import {
|
||||
const REDACTED_VALUE = '<redacted>';
|
||||
const REDACTED_BASE64_VALUE = '<redacted-base64>';
|
||||
const SENSITIVE_KEY_PATTERN =
|
||||
/password|secret|token|authorization|cookie|privatekey|sshkey|ticket|randstr|replytext|base64/i;
|
||||
/password|secret|token|authorization|cookie|privatekey|sshkey|accesskey|apikey|ticket|randstr|replytext|base64/i;
|
||||
const SENSITIVE_TEXT_KEY_PATTERN =
|
||||
'(?:[A-Za-z0-9_-]*(?:password|secret|token|authorization|cookie|private[_-]?key|ssh[_-]?key|ticket|randstr|replyText|base64)[A-Za-z0-9_-]*|sid)';
|
||||
'(?:[A-Za-z0-9_-]*(?:password|secret|token|authorization|cookie|private[_-]?key|ssh[_-]?key|access[_-]?key|api[_-]?key|ticket|randstr|replyText|base64)[A-Za-z0-9_-]*|sid)';
|
||||
const SENSITIVE_TEXT_REPLACEMENTS: Array<[RegExp, string]> = [
|
||||
[
|
||||
/data:[a-z0-9.+-]+\/[a-z0-9.+-]+;base64,[a-z0-9+/=\r\n]+/gi,
|
||||
@ -18,6 +18,21 @@ const SENSITIVE_TEXT_REPLACEMENTS: Array<[RegExp, string]> = [
|
||||
[/\b[A-Za-z0-9+/]{120,}={0,2}\b/g, REDACTED_BASE64_VALUE],
|
||||
[/\b(Authorization)\s*[:=]\s*[^\r\n]+/gi, '$1=<redacted>'],
|
||||
[/\b(Cookie)\s*[:=]\s*[^\r\n]+/gi, '$1=<redacted>'],
|
||||
[
|
||||
/\b((?:private|ssh)[_-]?key)(\s*[:=]\s*)-----BEGIN[\s\S]*?-----END [^-]+-----/gi,
|
||||
'$1$2<redacted>',
|
||||
],
|
||||
[
|
||||
/\b((?:private|ssh)[_-]?key)(\s*[:=]\s*)-----BEGIN[\s\S]*?(?=\s+[A-Za-z0-9_-]+\s*[:=]|\s*$)/gi,
|
||||
'$1$2<redacted>',
|
||||
],
|
||||
[
|
||||
new RegExp(
|
||||
`\\b(${SENSITIVE_TEXT_KEY_PATTERN})(\\s*[:=]\\s*)Bearer\\s+[^\\s,;&]+`,
|
||||
'gi',
|
||||
),
|
||||
'$1$2<redacted>',
|
||||
],
|
||||
[
|
||||
new RegExp(
|
||||
`(["'])(${SENSITIVE_TEXT_KEY_PATTERN})\\1\\s*:\\s*(?:(["'])[^"']*\\3|[-+]?\\d+(?:\\.\\d+)?|true|false|null)`,
|
||||
|
||||
@ -279,4 +279,36 @@ describe('RuntimeEvidenceService', () => {
|
||||
expect(serialized).not.toContain('67890');
|
||||
expect(serialized).toContain('KT_SCAN_SAFE');
|
||||
});
|
||||
|
||||
it('redacts access key and api key text plus unquoted multi-word secret values', () => {
|
||||
const service = new RuntimeEvidenceService();
|
||||
|
||||
const record = service.createRecord({
|
||||
title: 'access key evidence',
|
||||
taskType: 'backend',
|
||||
project: 'kt-template-online-api',
|
||||
environment: 'local',
|
||||
operation: 'runtime-evidence',
|
||||
status: 'failed',
|
||||
details: {
|
||||
text:
|
||||
'accessKey=raw-access-key access_key=raw-snake-access-key apiKey=raw-api-key api_key=raw-snake-api-key private_key=-----BEGIN PRIVATE KEY----- raw unquoted pem token=Bearer raw-bearer-token safe=value',
|
||||
jsonText:
|
||||
'{"accessKey":"raw-json-access-key","api_key":"raw-json-api-key","safe":"kept"}',
|
||||
},
|
||||
});
|
||||
|
||||
const serialized = JSON.stringify(record);
|
||||
|
||||
expect(serialized).not.toContain('raw-access-key');
|
||||
expect(serialized).not.toContain('raw-snake-access-key');
|
||||
expect(serialized).not.toContain('raw-api-key');
|
||||
expect(serialized).not.toContain('raw-snake-api-key');
|
||||
expect(serialized).not.toContain('raw unquoted pem');
|
||||
expect(serialized).not.toContain('raw-bearer-token');
|
||||
expect(serialized).not.toContain('raw-json-access-key');
|
||||
expect(serialized).not.toContain('raw-json-api-key');
|
||||
expect(serialized).toContain('safe=value');
|
||||
expect(serialized).toContain('kept');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user