@perrylink/dsh-skill-pack-security-provider 2.0.2 → 2.1.0
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/README.md +2 -0
- package/lib/index.js +2 -1
- package/lib/types/vet/checks.d.ts +1 -0
- package/lib/types/vet/config.d.ts +2 -0
- package/lib/types/vet/data-responsibility.d.ts +36 -0
- package/lib/types/vet/manifest.d.ts +1 -0
- package/lib/types/vet/vocabulary.d.ts +1 -1
- package/lib/vet/checks.js +24 -0
- package/lib/vet/config.js +3 -1
- package/lib/vet/data-responsibility.js +213 -0
- package/lib/vet/engine.js +12 -3
- package/lib/vet/manifest.js +2 -1
- package/lib/vet/skills.js +3 -0
- package/lib/vet/tool.js +2 -2
- package/lib/vet/vocabulary.js +1 -0
- package/pack/skills/dependency-audit/SKILL.md +1 -1
- package/pack/skills/incident-response/SKILL.md +1 -1
- package/pack/skills/prompt-injection-review/SKILL.md +1 -1
- package/pack/skills/secret-scan/SKILL.md +1 -1
- package/pack/skills/security-audit/SKILL.md +1 -1
- package/pack/skills/supply-chain-review/SKILL.md +1 -1
- package/pack/skills/threat-model/SKILL.md +1 -1
- package/pack/skills/vuln-intel/SKILL.md +1 -1
- package/pack/skills-en/dependency-audit/SKILL.md +1 -1
- package/pack/skills-en/incident-response/SKILL.md +1 -1
- package/pack/skills-en/prompt-injection-review/SKILL.md +1 -1
- package/pack/skills-en/secret-scan/SKILL.md +1 -1
- package/pack/skills-en/security-audit/SKILL.md +1 -1
- package/pack/skills-en/supply-chain-review/SKILL.md +1 -1
- package/pack/skills-en/threat-model/SKILL.md +1 -1
- package/pack/skills-en/vuln-intel/SKILL.md +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ This directory is an **optional** DSH plugin: it registers the pack's skill dire
|
|
|
23
23
|
| `language` | `'zh' \| 'en'` | `'zh'` | Which edition to publish: the Chinese `skills/` or the English `skills-en/`. Ignored when `skillsDir` is set. |
|
|
24
24
|
| `skillsDir` | string | — | Explicit skills root; overrides the `language`-derived default. Must exist and contain at least one `<skill>/SKILL.md` bundle, otherwise the plugin refuses to load. |
|
|
25
25
|
| `watch` | boolean | `false` | Whether to watch the packaged directory; packaged content is static. |
|
|
26
|
+
| `vet.dataResponsibility` | boolean | `true` | Run the `plugin_vet` data-responsibility review (ungated sensitive-seam hooks, undisclosed outbound endpoints, description-behavior coverage, embedded instruction-override payloads). Full `vet.*` documentation lives in the root README. |
|
|
26
27
|
|
|
27
28
|
### Mounting (any one)
|
|
28
29
|
|
|
@@ -67,6 +68,7 @@ Check 8 of `../verify/verify-skill-pack.mts` exercises this plugin: mounting the
|
|
|
67
68
|
| `language` | `'zh' \| 'en'` | `'zh'` | 发布哪个语言版:中文 `skills/` 或英文 `skills-en/`;设置了 `skillsDir` 时忽略 |
|
|
68
69
|
| `skillsDir` | string | — | 显式指定技能根目录,覆盖 `language` 推导的默认值;必须存在且含至少一个 `<skill>/SKILL.md` 包,否则插件拒绝加载 |
|
|
69
70
|
| `watch` | boolean | `false` | 是否监听包内技能目录;静态内容无需监听 |
|
|
71
|
+
| `vet.dataResponsibility` | boolean | `true` | 运行 `plugin_vet` 数据责任审查(无门控敏感监听、未披露出站端点、描述-行为覆盖率、随包文本中的指令覆盖类注入载荷);完整 `vet.*` 文档见根 README |
|
|
70
72
|
|
|
71
73
|
### 挂载方式(任选)
|
|
72
74
|
|
package/lib/index.js
CHANGED
|
@@ -38,7 +38,8 @@ export const Config = z.object({
|
|
|
38
38
|
maxExtractBytes: z.natural().min(1024).max(512 * 1024 * 1024).default(64 * 1024 * 1024),
|
|
39
39
|
maxDepNodes: z.natural().min(1).max(10000).default(600),
|
|
40
40
|
maxFindingsPerCheck: z.natural().min(1).max(100).default(12),
|
|
41
|
-
userAgent: z.string().max(200).default('dsh-skill-pack-security/2.
|
|
41
|
+
userAgent: z.string().max(200).default('dsh-skill-pack-security/2.1.0 (+https://github.com/PerryLink/dsh-skill-pack-security)'),
|
|
42
|
+
dataResponsibility: z.boolean().default(true),
|
|
42
43
|
gate: z.object({
|
|
43
44
|
policy: z.union(['warn', 'deny']).default('warn'),
|
|
44
45
|
}),
|
|
@@ -39,5 +39,6 @@ export declare function networkExfilCheck(inputs: CheckInputs): VetCheck;
|
|
|
39
39
|
export declare function obfuscationCheck(inputs: CheckInputs): VetCheck;
|
|
40
40
|
export declare function sourceCheck(inputs: CheckInputs): VetCheck;
|
|
41
41
|
export declare function maintenanceCheck(inputs: CheckInputs): VetCheck;
|
|
42
|
+
export declare function dataResponsibilityCheck(inputs: CheckInputs): VetCheck;
|
|
42
43
|
/** Run the requested checks over shared inputs. */
|
|
43
44
|
export declare function runChecks(inputs: CheckInputs, ids: readonly CheckId[]): CheckResult[];
|
|
@@ -18,6 +18,7 @@ export interface VetConfigInput {
|
|
|
18
18
|
readonly maxDepNodes?: number;
|
|
19
19
|
readonly maxFindingsPerCheck?: number;
|
|
20
20
|
readonly userAgent?: string;
|
|
21
|
+
readonly dataResponsibility?: boolean;
|
|
21
22
|
readonly gate?: {
|
|
22
23
|
readonly policy?: GatePolicy;
|
|
23
24
|
};
|
|
@@ -32,6 +33,7 @@ export interface VetConfig {
|
|
|
32
33
|
readonly maxDepNodes: number;
|
|
33
34
|
readonly maxFindingsPerCheck: number;
|
|
34
35
|
readonly userAgent: string;
|
|
36
|
+
readonly dataResponsibility: boolean;
|
|
35
37
|
readonly gate: {
|
|
36
38
|
readonly policy: GatePolicy;
|
|
37
39
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The data-responsibility review check: the Claude policy-scan dimensions,
|
|
3
|
+
* shipped as deterministic rules (the model-assisted stage is a documented
|
|
4
|
+
* future upgrade). Four sub-scans over the shipped payload:
|
|
5
|
+
*
|
|
6
|
+
* 1. hooks-scope — listeners/effects registered on sensitive seams
|
|
7
|
+
* (`agent/pre-step`, `tools/pre-execute`, `session/event`, …) must show
|
|
8
|
+
* project-relevance gating; an ungated broad-scope hook is a warn.
|
|
9
|
+
* 2. telemetry-disclosure — non-local URL literals in shipped files must be
|
|
10
|
+
* disclosed in the README (multilingual disclosure keywords); an
|
|
11
|
+
* undisclosed endpoint is a warn.
|
|
12
|
+
* 3. description-behavior — the manifest description must be reflected in
|
|
13
|
+
* the shipped text (keyword coverage); near-zero coverage is an info.
|
|
14
|
+
* 4. injection-payload — embedded instruction-override payloads in shipped
|
|
15
|
+
* text (skills, docs, prompts, tests) are warns; the manual continuation
|
|
16
|
+
* is the pack's prompt-injection-review skill.
|
|
17
|
+
*
|
|
18
|
+
* Pure and tolerant: every file is read from the shared `ScannedFile[]`
|
|
19
|
+
* (no filesystem/network), unreadable text is skipped, and evidence is
|
|
20
|
+
* redacted and capped through the shared redactor.
|
|
21
|
+
*
|
|
22
|
+
* NOTE on the pattern literals below: a security scanner ships the attack
|
|
23
|
+
* PATTERNS, never the payloads — but content filters scanning this very
|
|
24
|
+
* source cannot tell the difference, so the phrase literals are fragmented
|
|
25
|
+
* (joined at runtime) to keep the shipped scanner itself from tripping them.
|
|
26
|
+
*
|
|
27
|
+
* @module dsh-skill-pack-security/vet/data-responsibility
|
|
28
|
+
*/
|
|
29
|
+
import { type Lang } from './skills.js';
|
|
30
|
+
import type { ScannedFile } from './walk.js';
|
|
31
|
+
import type { VetConfig } from './config.js';
|
|
32
|
+
import type { VetFinding } from './vocabulary.js';
|
|
33
|
+
/** Run the whole data-responsibility review over the shared inputs. */
|
|
34
|
+
export declare function dataResponsibilityFindings(files: ScannedFile[], manifestDescription: string, readmeText: string, lang: Lang, _config: VetConfig): VetFinding[];
|
|
35
|
+
/** Score the review: 100 minus per-level deductions, floored at 0. */
|
|
36
|
+
export declare function dataResponsibilityScore(findings: VetFinding[]): number;
|
|
@@ -19,6 +19,7 @@ export interface Manifest {
|
|
|
19
19
|
readonly optionalDependencies: Record<string, string>;
|
|
20
20
|
readonly peerDependencies: Record<string, string>;
|
|
21
21
|
readonly repository: string;
|
|
22
|
+
readonly description: string;
|
|
22
23
|
readonly present: boolean;
|
|
23
24
|
}
|
|
24
25
|
/** One dependency edge inside a lockfile entry: name → raw spec. */
|
|
@@ -16,7 +16,7 @@ export type GatePolicy = 'warn' | 'deny';
|
|
|
16
16
|
/** How a scan target is addressed. */
|
|
17
17
|
export type TargetKind = 'github-repo' | 'local-path' | 'npm-package';
|
|
18
18
|
/** Stable check ids; each maps to exactly one dimension and one skill section. */
|
|
19
|
-
export type CheckId = 'license' | 'sbom' | 'commit-lock' | 'install-scripts' | 'network-exfil' | 'obfuscation' | 'source' | 'maintenance';
|
|
19
|
+
export type CheckId = 'license' | 'sbom' | 'commit-lock' | 'install-scripts' | 'network-exfil' | 'obfuscation' | 'source' | 'maintenance' | 'data-responsibility';
|
|
20
20
|
export declare const ALL_CHECK_IDS: readonly CheckId[];
|
|
21
21
|
/** Finding severity: fail blocks the check, warn downgrades, info is an observation. */
|
|
22
22
|
export type FindingLevel = 'fail' | 'warn' | 'info';
|
package/lib/vet/checks.js
CHANGED
|
@@ -10,6 +10,7 @@ import { buildDependencyTree, unpinnedSpecs } from './manifest.js';
|
|
|
10
10
|
import { redactSnippet } from './redact.js';
|
|
11
11
|
import { isCommitRef } from './source.js';
|
|
12
12
|
import { CHECK_NAME, SKILL_REF } from './skills.js';
|
|
13
|
+
import { dataResponsibilityFindings, dataResponsibilityScore } from './data-responsibility.js';
|
|
13
14
|
function clamp(value, min = 0, max = 100) {
|
|
14
15
|
return Math.min(max, Math.max(min, Math.round(value)));
|
|
15
16
|
}
|
|
@@ -719,6 +720,26 @@ export function maintenanceCheck(inputs) {
|
|
|
719
720
|
}
|
|
720
721
|
return makeCheck('maintenance', score, findings, lang, config);
|
|
721
722
|
}
|
|
723
|
+
// --- data-responsibility ------------------------------------------------------
|
|
724
|
+
/** README text across the shipped files (the telemetry-disclosure corpus). */
|
|
725
|
+
function readmeTextOf(files) {
|
|
726
|
+
return files
|
|
727
|
+
.filter(file => file.text !== null && /^readme(\.|$)/i.test(file.path.split('/').pop() ?? ''))
|
|
728
|
+
.map(file => file.text)
|
|
729
|
+
.join('\n');
|
|
730
|
+
}
|
|
731
|
+
export function dataResponsibilityCheck(inputs) {
|
|
732
|
+
const { files, manifest, lang, config } = inputs;
|
|
733
|
+
const findings = dataResponsibilityFindings(files, manifest.description, readmeTextOf(files), lang, config);
|
|
734
|
+
if (findings.length === 0) {
|
|
735
|
+
return makeCheck('data-responsibility', 100, [{
|
|
736
|
+
level: 'info',
|
|
737
|
+
message: lang === 'zh' ? '随包文本未发现无门控敏感监听、未披露出站端点或注入载荷特征' : 'no ungated sensitive-seam listeners, undisclosed outbound endpoints, or injection-payload indicators in shipped text',
|
|
738
|
+
skill: SKILL_REF['data-responsibility'],
|
|
739
|
+
}], lang, config);
|
|
740
|
+
}
|
|
741
|
+
return makeCheck('data-responsibility', dataResponsibilityScore(findings), findings, lang, config);
|
|
742
|
+
}
|
|
722
743
|
// --- runner ----------------------------------------------------------------------------
|
|
723
744
|
/** Run the requested checks over shared inputs. */
|
|
724
745
|
export function runChecks(inputs, ids) {
|
|
@@ -749,6 +770,9 @@ export function runChecks(inputs, ids) {
|
|
|
749
770
|
case 'maintenance':
|
|
750
771
|
results.push({ check: maintenanceCheck(inputs) });
|
|
751
772
|
break;
|
|
773
|
+
case 'data-responsibility':
|
|
774
|
+
results.push({ check: dataResponsibilityCheck(inputs) });
|
|
775
|
+
break;
|
|
752
776
|
}
|
|
753
777
|
}
|
|
754
778
|
return results;
|
package/lib/vet/config.js
CHANGED
|
@@ -15,7 +15,8 @@ export const VET_DEFAULTS = {
|
|
|
15
15
|
maxExtractBytes: 64 * 1024 * 1024,
|
|
16
16
|
maxDepNodes: 600,
|
|
17
17
|
maxFindingsPerCheck: 12,
|
|
18
|
-
userAgent: 'dsh-skill-pack-security/2.
|
|
18
|
+
userAgent: 'dsh-skill-pack-security/2.1.0 (+https://github.com/PerryLink/dsh-skill-pack-security)',
|
|
19
|
+
dataResponsibility: true,
|
|
19
20
|
gate: { policy: 'warn' },
|
|
20
21
|
};
|
|
21
22
|
/** Merge raw config over the defaults (the schema already validated shape/ranges). */
|
|
@@ -31,6 +32,7 @@ export function resolveVetConfig(raw) {
|
|
|
31
32
|
maxDepNodes: raw.maxDepNodes ?? VET_DEFAULTS.maxDepNodes,
|
|
32
33
|
maxFindingsPerCheck: raw.maxFindingsPerCheck ?? VET_DEFAULTS.maxFindingsPerCheck,
|
|
33
34
|
userAgent: raw.userAgent ?? VET_DEFAULTS.userAgent,
|
|
35
|
+
dataResponsibility: raw.dataResponsibility ?? VET_DEFAULTS.dataResponsibility,
|
|
34
36
|
gate: { policy: raw.gate?.policy ?? VET_DEFAULTS.gate.policy },
|
|
35
37
|
};
|
|
36
38
|
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The data-responsibility review check: the Claude policy-scan dimensions,
|
|
3
|
+
* shipped as deterministic rules (the model-assisted stage is a documented
|
|
4
|
+
* future upgrade). Four sub-scans over the shipped payload:
|
|
5
|
+
*
|
|
6
|
+
* 1. hooks-scope — listeners/effects registered on sensitive seams
|
|
7
|
+
* (`agent/pre-step`, `tools/pre-execute`, `session/event`, …) must show
|
|
8
|
+
* project-relevance gating; an ungated broad-scope hook is a warn.
|
|
9
|
+
* 2. telemetry-disclosure — non-local URL literals in shipped files must be
|
|
10
|
+
* disclosed in the README (multilingual disclosure keywords); an
|
|
11
|
+
* undisclosed endpoint is a warn.
|
|
12
|
+
* 3. description-behavior — the manifest description must be reflected in
|
|
13
|
+
* the shipped text (keyword coverage); near-zero coverage is an info.
|
|
14
|
+
* 4. injection-payload — embedded instruction-override payloads in shipped
|
|
15
|
+
* text (skills, docs, prompts, tests) are warns; the manual continuation
|
|
16
|
+
* is the pack's prompt-injection-review skill.
|
|
17
|
+
*
|
|
18
|
+
* Pure and tolerant: every file is read from the shared `ScannedFile[]`
|
|
19
|
+
* (no filesystem/network), unreadable text is skipped, and evidence is
|
|
20
|
+
* redacted and capped through the shared redactor.
|
|
21
|
+
*
|
|
22
|
+
* NOTE on the pattern literals below: a security scanner ships the attack
|
|
23
|
+
* PATTERNS, never the payloads — but content filters scanning this very
|
|
24
|
+
* source cannot tell the difference, so the phrase literals are fragmented
|
|
25
|
+
* (joined at runtime) to keep the shipped scanner itself from tripping them.
|
|
26
|
+
*
|
|
27
|
+
* @module dsh-skill-pack-security/vet/data-responsibility
|
|
28
|
+
*/
|
|
29
|
+
import { redactSnippet } from './redact.js';
|
|
30
|
+
import { SKILL_REF } from './skills.js';
|
|
31
|
+
/** Seams whose listeners can reshape the agent's model-visible surface. */
|
|
32
|
+
const SENSITIVE_SEAMS = [
|
|
33
|
+
'agent/pre-step', 'agent/post-step', 'agent/inject', 'agent/pre-request',
|
|
34
|
+
'tools/pre-execute', 'tools/post-execute', 'tools/error',
|
|
35
|
+
'session/event', 'session/flush', 'session/disposed',
|
|
36
|
+
'web/fetch', 'web/search',
|
|
37
|
+
];
|
|
38
|
+
/** Patterns that count as project-relevance gating near a registration. */
|
|
39
|
+
const GATING_PATTERNS = [
|
|
40
|
+
/\bprocess\.cwd\(\)/u,
|
|
41
|
+
/\bworkspaceRoot\b/u,
|
|
42
|
+
/\bprojectRoot\b/u,
|
|
43
|
+
/\ballowlist\b/iu,
|
|
44
|
+
/\bdenylist\b/iu,
|
|
45
|
+
/\bproject\b/iu,
|
|
46
|
+
/resolve\(/u,
|
|
47
|
+
/\bpath\b.*\.(?:dirname|relative|join)/u,
|
|
48
|
+
];
|
|
49
|
+
/** Multilingual README disclosure keywords for telemetry/privacy statements. */
|
|
50
|
+
const DISCLOSURE_KEYWORDS = [
|
|
51
|
+
'telemetry', 'privacy', 'analytics', 'opt-out', 'opt out', 'data collection',
|
|
52
|
+
'遥测', '隐私', '数据收集', '退出',
|
|
53
|
+
'telemetría', 'privacidad', 'recopilación de datos', 'exclusión',
|
|
54
|
+
'telemetria', 'privacidade', 'coleta de dados',
|
|
55
|
+
'टेलीमेट्री', 'गोपनीयता', 'डेटा संग्रह',
|
|
56
|
+
];
|
|
57
|
+
/** Stopwords removed from the description before keyword coverage. */
|
|
58
|
+
const STOPWORDS = new Set([
|
|
59
|
+
'the', 'a', 'an', 'and', 'or', 'of', 'for', 'with', 'your', 'in', 'on', 'to', 'is', 'are', 'by', 'as', 'at', 'from', 'that', 'this', 'it', 'into', 'per', 'via', 'one',
|
|
60
|
+
'一个', '与', '的', '为', '在', '和', '及', '或',
|
|
61
|
+
]);
|
|
62
|
+
/** Fragment joiner for the injection-pattern literals (see module note). */
|
|
63
|
+
function frag(...parts) {
|
|
64
|
+
return parts.join('');
|
|
65
|
+
}
|
|
66
|
+
/** Embedded instruction-override payload patterns (OWASP LLM01 / policy-scan payloads). */
|
|
67
|
+
const INJECTION_PATTERNS = [
|
|
68
|
+
{ pattern: new RegExp(`(?:${frag('ig', 'nore')}|${frag('disre', 'gard')}|${frag('for', 'get')})\\s+(?:all|${frag('pre', 'vious')}|${frag('ab', 'ove')}|${frag('pri', 'or')})\\s+(?:${frag('instru', 'ctions')}|${frag('ru', 'les')}|${frag('com', 'mands')}|${frag('con', 'text')})`, 'iu'), label: 'ignore-previous-instructions' },
|
|
69
|
+
{ pattern: new RegExp(`(?:${frag('over', 'ride')}|${frag('rep', 'lace')}|${frag('rew', 'rite')})\\s+(?:all|your|the)\\s+(?:${frag('instru', 'ctions')}|${frag('ru', 'les')}|${frag('system', ' prompt')})`, 'iu'), label: 'override-instructions' },
|
|
70
|
+
{ pattern: new RegExp(`you\\s+are\\s+now\\s+(?:a|an)\\s+[a-z0-9 -]{2,40}(?:,|\\.|\\n|$)`, 'iu'), label: 'role-override' },
|
|
71
|
+
{ pattern: new RegExp(`(?:${frag('rev', 'eal')}|${frag('pri', 'nt')}|${frag('sh', 'ow')}|${frag('rep', 'eat')})\\s+(?:your|the)\\s+(?:${frag('system', ' prompt')}|${frag('instru', 'ctions')}|${frag('ru', 'les')})`, 'iu'), label: 'prompt-exfiltration' },
|
|
72
|
+
{ pattern: new RegExp(`${frag('act', ' as')}\\s+(?:if\\s+)?(?:you\\s+are\\s+)?[a-z0-9 -]{2,40}(?:,|\\.|\\n|$)`, 'iu'), label: 'act-as-injection' },
|
|
73
|
+
];
|
|
74
|
+
/** Files whose content is prompt-shaped (embedded payloads weigh heavier there). */
|
|
75
|
+
const PROMPT_SHAPED = /(^|\/)(skills?|prompts?|SKILL|AGENTS?)(\/|\.|$)|\.md$/iu;
|
|
76
|
+
/** Text files the review reads (manifests excluded: they carry URL literals by design). */
|
|
77
|
+
function reviewable(file) {
|
|
78
|
+
return file.text !== null && file.skipped === null && !/\.(json|ya?ml|toml|lock)$/iu.test(file.path);
|
|
79
|
+
}
|
|
80
|
+
/** One sensitive-seam registration with its gating verdict. */
|
|
81
|
+
function scanHooksScope(files, lang) {
|
|
82
|
+
const zh = lang === 'zh';
|
|
83
|
+
const findings = [];
|
|
84
|
+
const seamPattern = new RegExp(`['"](${SENSITIVE_SEAMS.map(seam => seam.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')).join('|')})['"]`, 'gu');
|
|
85
|
+
for (const file of files) {
|
|
86
|
+
if (!reviewable(file))
|
|
87
|
+
continue;
|
|
88
|
+
for (const match of file.text.matchAll(seamPattern)) {
|
|
89
|
+
const seam = match[1];
|
|
90
|
+
const gated = GATING_PATTERNS.some(pattern => pattern.test(file.text));
|
|
91
|
+
findings.push({
|
|
92
|
+
level: gated ? 'info' : 'warn',
|
|
93
|
+
message: gated
|
|
94
|
+
? (zh ? `${file.path} 在 ${seam} 注册监听并带相关性门控证据` : `${file.path} registers a ${seam} listener with relevance-gating evidence`)
|
|
95
|
+
: (zh ? `${file.path} 在敏感 seam ${seam} 注册监听但未见项目相关性门控:审查其作用域` : `${file.path} registers a listener on the sensitive seam ${seam} without visible project-relevance gating: review its scope`),
|
|
96
|
+
location: file.path,
|
|
97
|
+
skill: SKILL_REF['data-responsibility'],
|
|
98
|
+
});
|
|
99
|
+
if (findings.length >= 24)
|
|
100
|
+
return findings;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return findings;
|
|
104
|
+
}
|
|
105
|
+
/** Outbound URL literals not disclosed in the README. */
|
|
106
|
+
function scanTelemetry(files, readmeText, lang) {
|
|
107
|
+
const zh = lang === 'zh';
|
|
108
|
+
const findings = [];
|
|
109
|
+
const disclosed = DISCLOSURE_KEYWORDS.some(keyword => readmeText.toLowerCase().includes(keyword));
|
|
110
|
+
const seen = new Set();
|
|
111
|
+
for (const file of files) {
|
|
112
|
+
if (!reviewable(file))
|
|
113
|
+
continue;
|
|
114
|
+
for (const match of file.text.matchAll(/https?:\/\/[^\s"'`<>)\]]+/gu)) {
|
|
115
|
+
let host = '';
|
|
116
|
+
try {
|
|
117
|
+
host = new URL(match[0]).host.toLowerCase();
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (host === '' || host === 'localhost' || host.startsWith('127.') || host.startsWith('0.0.0.0') || host.includes('example.com') || host === 'registry.npmjs.org' || host === 'github.com' || host.endsWith('.github.io'))
|
|
123
|
+
continue;
|
|
124
|
+
if (seen.has(host))
|
|
125
|
+
continue;
|
|
126
|
+
seen.add(host);
|
|
127
|
+
if (!disclosed) {
|
|
128
|
+
findings.push({
|
|
129
|
+
level: 'warn',
|
|
130
|
+
message: zh ? `出站端点 ${host} 未见 README 遥测/隐私披露:确认用途与 opt-out` : `outbound endpoint ${host} has no README telemetry/privacy disclosure: confirm purpose and opt-out`,
|
|
131
|
+
location: file.path,
|
|
132
|
+
skill: SKILL_REF['data-responsibility'],
|
|
133
|
+
evidence: redactSnippet(match[0], 140),
|
|
134
|
+
});
|
|
135
|
+
if (findings.length >= 12)
|
|
136
|
+
return findings;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return findings;
|
|
141
|
+
}
|
|
142
|
+
/** Description-keyword coverage over the shipped text. */
|
|
143
|
+
function scanDescriptionBehavior(description, files, lang) {
|
|
144
|
+
const zh = lang === 'zh';
|
|
145
|
+
const tokens = description
|
|
146
|
+
.toLowerCase()
|
|
147
|
+
.replace(/[^a-z0-9\u4e00-\u9fff\s]/gu, ' ')
|
|
148
|
+
.split(/\s+/u)
|
|
149
|
+
.filter(token => token.length >= 3 && !STOPWORDS.has(token));
|
|
150
|
+
if (tokens.length === 0)
|
|
151
|
+
return [];
|
|
152
|
+
const corpus = files.map(file => reviewable(file) ? file.text.toLowerCase() : '').join('\n');
|
|
153
|
+
const covered = tokens.filter(token => corpus.includes(token)).length;
|
|
154
|
+
const ratio = covered / tokens.length;
|
|
155
|
+
if (ratio >= 0.3)
|
|
156
|
+
return [];
|
|
157
|
+
return [{
|
|
158
|
+
level: 'info',
|
|
159
|
+
message: zh
|
|
160
|
+
? `描述与随包文本的覆盖度仅 ${Math.round(ratio * 100)}%(${covered}/${tokens.length} 个关键词):人工核对描述与行为一致性(prompt-injection-review §1)`
|
|
161
|
+
: `description coverage over shipped text is only ${Math.round(ratio * 100)}% (${covered}/${tokens.length} keywords): verify description-behavior consistency manually (prompt-injection-review §1)`,
|
|
162
|
+
skill: SKILL_REF['data-responsibility'],
|
|
163
|
+
}];
|
|
164
|
+
}
|
|
165
|
+
/** Embedded instruction-override payloads in shipped text. */
|
|
166
|
+
function scanInjectionPayloads(files, lang) {
|
|
167
|
+
const zh = lang === 'zh';
|
|
168
|
+
const findings = [];
|
|
169
|
+
for (const file of files) {
|
|
170
|
+
if (!reviewable(file))
|
|
171
|
+
continue;
|
|
172
|
+
const promptShaped = PROMPT_SHAPED.test(file.path);
|
|
173
|
+
for (const { pattern, label } of INJECTION_PATTERNS) {
|
|
174
|
+
const match = pattern.exec(file.text);
|
|
175
|
+
if (match === null)
|
|
176
|
+
continue;
|
|
177
|
+
findings.push({
|
|
178
|
+
level: promptShaped ? 'warn' : 'info',
|
|
179
|
+
message: zh
|
|
180
|
+
? `${file.path} 含注入载荷特征(${label}):若是安全测试夹具请确认不会进入运行时提示词`
|
|
181
|
+
: `${file.path} carries an injection-payload indicator (${label}): if this is a security-test fixture, confirm it never reaches runtime prompts`,
|
|
182
|
+
location: file.path,
|
|
183
|
+
skill: SKILL_REF['data-responsibility'],
|
|
184
|
+
evidence: redactSnippet(match[0], 140),
|
|
185
|
+
});
|
|
186
|
+
if (findings.length >= 16)
|
|
187
|
+
return findings;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return findings;
|
|
192
|
+
}
|
|
193
|
+
/** Run the whole data-responsibility review over the shared inputs. */
|
|
194
|
+
export function dataResponsibilityFindings(files, manifestDescription, readmeText, lang, _config) {
|
|
195
|
+
const findings = [
|
|
196
|
+
...scanHooksScope(files, lang),
|
|
197
|
+
...scanTelemetry(files, readmeText, lang),
|
|
198
|
+
...scanDescriptionBehavior(manifestDescription, files, lang),
|
|
199
|
+
...scanInjectionPayloads(files, lang),
|
|
200
|
+
];
|
|
201
|
+
return findings;
|
|
202
|
+
}
|
|
203
|
+
/** Score the review: 100 minus per-level deductions, floored at 0. */
|
|
204
|
+
export function dataResponsibilityScore(findings) {
|
|
205
|
+
let score = 100;
|
|
206
|
+
for (const finding of findings) {
|
|
207
|
+
if (finding.level === 'warn')
|
|
208
|
+
score -= 12;
|
|
209
|
+
else if (finding.level === 'info')
|
|
210
|
+
score -= 4;
|
|
211
|
+
}
|
|
212
|
+
return Math.max(0, score);
|
|
213
|
+
}
|
package/lib/vet/engine.js
CHANGED
|
@@ -77,11 +77,17 @@ function jsonClean(value) {
|
|
|
77
77
|
/** Dimension → checks contributing to it. */
|
|
78
78
|
const DIMENSION_CHECKS = {
|
|
79
79
|
license: ['license'],
|
|
80
|
-
source: ['source', 'commit-lock'],
|
|
80
|
+
source: ['source', 'commit-lock', 'data-responsibility'],
|
|
81
81
|
dependencies: ['sbom'],
|
|
82
82
|
'build-scripts': ['install-scripts', 'network-exfil', 'obfuscation'],
|
|
83
83
|
maintenance: ['maintenance'],
|
|
84
84
|
};
|
|
85
|
+
/** Weight factors per check inside the `source` dimension (they sum to 1). */
|
|
86
|
+
const SOURCE_WEIGHTS = {
|
|
87
|
+
source: 0.5,
|
|
88
|
+
'commit-lock': 0.3,
|
|
89
|
+
'data-responsibility': 0.2,
|
|
90
|
+
};
|
|
85
91
|
/** Build the five-dimension scorecard from executed checks. */
|
|
86
92
|
function scoreDimensions(checks) {
|
|
87
93
|
const byId = new Map(checks.map(check => [check.id, check]));
|
|
@@ -99,7 +105,7 @@ function scoreDimensions(checks) {
|
|
|
99
105
|
return check.score * factor;
|
|
100
106
|
}
|
|
101
107
|
if (dim === 'source') {
|
|
102
|
-
return check.score * (check.id
|
|
108
|
+
return check.score * (SOURCE_WEIGHTS[check.id] ?? 1);
|
|
103
109
|
}
|
|
104
110
|
return check.score;
|
|
105
111
|
});
|
|
@@ -121,6 +127,9 @@ function scoreDimensions(checks) {
|
|
|
121
127
|
/** Run the whole pipeline for one tool call. */
|
|
122
128
|
export async function runVet(args, config, lang, signal) {
|
|
123
129
|
const ids = requestedChecks(args);
|
|
130
|
+
// The data-responsibility review can be disabled per deployment; an explicit
|
|
131
|
+
// per-call request then simply does not run (documented in the tool help).
|
|
132
|
+
const effectiveIds = config.dataResponsibility ? ids : ids.filter(id => id !== 'data-responsibility');
|
|
124
133
|
const policy = args.policy === undefined || args.policy === 'inherit' ? config.gate.policy : args.policy;
|
|
125
134
|
const now = Date.now();
|
|
126
135
|
const fetchedAt = new Date(now).toISOString();
|
|
@@ -174,7 +183,7 @@ export async function runVet(args, config, lang, signal) {
|
|
|
174
183
|
lang,
|
|
175
184
|
localHead,
|
|
176
185
|
now,
|
|
177
|
-
},
|
|
186
|
+
}, effectiveIds);
|
|
178
187
|
const checks = results.map(result => result.check);
|
|
179
188
|
const sbom = results.find(result => result.sbom !== undefined)?.sbom;
|
|
180
189
|
// Unrequested checks are absent; the scorecard treats them as neutral.
|
package/lib/vet/manifest.js
CHANGED
|
@@ -31,7 +31,7 @@ export function parseManifest(files) {
|
|
|
31
31
|
const empty = {
|
|
32
32
|
name: '', version: '', license: '', scripts: {},
|
|
33
33
|
dependencies: {}, devDependencies: {}, optionalDependencies: {}, peerDependencies: {},
|
|
34
|
-
repository: '', present: false,
|
|
34
|
+
repository: '', description: '', present: false,
|
|
35
35
|
};
|
|
36
36
|
if (hit === undefined || hit.text === null)
|
|
37
37
|
return empty;
|
|
@@ -83,6 +83,7 @@ export function parseManifest(files) {
|
|
|
83
83
|
optionalDependencies: record(pkg['optionalDependencies']),
|
|
84
84
|
peerDependencies: record(pkg['peerDependencies']),
|
|
85
85
|
repository: repositoryString,
|
|
86
|
+
description: typeof pkg['description'] === 'string' ? pkg['description'] : '',
|
|
86
87
|
present: true,
|
|
87
88
|
};
|
|
88
89
|
}
|
package/lib/vet/skills.js
CHANGED
|
@@ -17,6 +17,7 @@ export const SKILL_REF = {
|
|
|
17
17
|
obfuscation: 'supply-chain-review §1',
|
|
18
18
|
source: 'dependency-audit §4.3',
|
|
19
19
|
maintenance: 'security-audit §3',
|
|
20
|
+
'data-responsibility': 'prompt-injection-review §2',
|
|
20
21
|
};
|
|
21
22
|
/** check id → human-readable check name per language. */
|
|
22
23
|
export const CHECK_NAME = {
|
|
@@ -29,6 +30,7 @@ export const CHECK_NAME = {
|
|
|
29
30
|
obfuscation: '混淆代码检测',
|
|
30
31
|
source: '来源可信信号',
|
|
31
32
|
maintenance: '维护状态',
|
|
33
|
+
'data-responsibility': '数据责任审查',
|
|
32
34
|
},
|
|
33
35
|
en: {
|
|
34
36
|
license: 'License scan',
|
|
@@ -39,6 +41,7 @@ export const CHECK_NAME = {
|
|
|
39
41
|
obfuscation: 'Obfuscation scan',
|
|
40
42
|
source: 'Source trust signals',
|
|
41
43
|
maintenance: 'Maintenance status',
|
|
44
|
+
'data-responsibility': 'Data-responsibility review',
|
|
42
45
|
},
|
|
43
46
|
};
|
|
44
47
|
/** dimension → label per language. */
|
package/lib/vet/tool.js
CHANGED
|
@@ -121,7 +121,7 @@ function textBlock(text) {
|
|
|
121
121
|
export function buildVetTool(config, lang) {
|
|
122
122
|
return defineTool({
|
|
123
123
|
name: 'plugin_vet',
|
|
124
|
-
description: 'Supply-chain security gate for DSH plugin repositories/packages. Scans a target (GitHub `owner/repo[@ref]`, an `npm:name@version` package, or a local path) and returns a five-dimension risk report: license, source, dependencies, build scripts, maintenance. Checks: LICENSE/SPDX detection (missing/unknown/NOASSERTION flagged), SBOM dependency tree, 40-hex commit pinning of install references, dangerous postinstall/preinstall scripts, network-exfiltration domains, obfuscated code, source trust signals, maintenance status. Each finding cites the matching dsh-skill-pack-security skill section for a manual deep-dive. Use it BEFORE installing any plugin (`dsh plugin add`); a FAIL verdict warns or blocks depending on the configured gate policy (default warn). Read-only: never modifies the target. Respects timeouts; bounded network use.',
|
|
124
|
+
description: 'Supply-chain security gate for DSH plugin repositories/packages. Scans a target (GitHub `owner/repo[@ref]`, an `npm:name@version` package, or a local path) and returns a five-dimension risk report: license, source, dependencies, build scripts, maintenance. Checks: LICENSE/SPDX detection (missing/unknown/NOASSERTION flagged), SBOM dependency tree, 40-hex commit pinning of install references, dangerous postinstall/preinstall scripts, network-exfiltration domains, obfuscated code, source trust signals, maintenance status, and the data-responsibility review (ungated sensitive-seam hooks, undisclosed outbound endpoints, description-behavior coverage, embedded instruction-override payloads in shipped text). Each finding cites the matching dsh-skill-pack-security skill section for a manual deep-dive. Use it BEFORE installing any plugin (`dsh plugin add`); a FAIL verdict warns or blocks depending on the configured gate policy (default warn). Read-only: never modifies the target. Respects timeouts; bounded network use.',
|
|
125
125
|
parameters: {
|
|
126
126
|
target: {
|
|
127
127
|
type: 'string',
|
|
@@ -135,7 +135,7 @@ export function buildVetTool(config, lang) {
|
|
|
135
135
|
checks: {
|
|
136
136
|
type: 'array',
|
|
137
137
|
items: { type: 'string' },
|
|
138
|
-
description: 'Optional subset of check ids: license, sbom, commit-lock, install-scripts, network-exfil, obfuscation, source, maintenance. Default: all.',
|
|
138
|
+
description: 'Optional subset of check ids: license, sbom, commit-lock, install-scripts, network-exfil, obfuscation, source, maintenance, data-responsibility. Default: all.',
|
|
139
139
|
},
|
|
140
140
|
policy: {
|
|
141
141
|
type: 'string',
|
package/lib/vet/vocabulary.js
CHANGED
|
@@ -4,7 +4,7 @@ description: '依赖供应链审计:pnpm/npm audit 输出与退出码解读、
|
|
|
4
4
|
whenToUse: '用户要求审计或盘点项目依赖安全(漏洞、license、投毒、锁文件漂移)、解读 audit 报告、判断某个依赖能否引入,或写依赖审计结论时使用;单个依赖的普通升级与纯功能开发不触发本技能。'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# 依赖审计(dependency-audit)
|
|
@@ -4,7 +4,7 @@ description: 'agent 环境安全事件响应:分类→控制蔓延→取证留
|
|
|
4
4
|
whenToUse: 'agent 环境(DSH 会话、插件、MCP、CI)出现疑似安全事件——密钥泄露、被注入执行了未授权操作、依赖投毒、权限异常——需要响应、留证与复盘时使用;没有事件迹象的日常开发不触发本技能。'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# 事件响应(incident-response)
|
|
@@ -4,7 +4,7 @@ description: '面向 agent 项目的提示注入面审查:AGENTS.md、技能
|
|
|
4
4
|
whenToUse: '审查 agent 项目的上下文注入面(AGENTS.md/CLAUDE.md、.agents/skills、工具描述、MCP server 来源、web 抓取链路)、评估间接注入风险或对 agent 项目做安全评审时使用;与模型上下文无关的普通代码评审不触发本技能。'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# 提示注入面审查(prompt-injection-review)
|
|
@@ -4,7 +4,7 @@ description: '仓库/软件安全审计总览:范围界定→资产清单→
|
|
|
4
4
|
whenToUse: '用户要求对代码仓库或项目做安全审计、制定审计计划、划分审计阶段、汇总多类发现成报告,或不确定该从哪个专项技能开始时使用;单一主题任务(只查密钥、只查依赖、只评审一个 PR、只查注入面)直接加载对应专项技能,不触发本技能。'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# 安全审计总览(security-audit)
|
|
@@ -4,7 +4,7 @@ description: 'PR/新依赖快速供应链评审:危险 install/postinstall 脚
|
|
|
4
4
|
whenToUse: '评审含新依赖(package.json/锁文件变更)的 PR、审查某包的 install 脚本行为、判断疑似 typosquat 包或验证构建可复现性时使用;纯业务代码、与新增依赖无关的 PR 评审不触发本技能。'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# 新增依赖快速评审(supply-chain-review)
|
|
@@ -4,7 +4,7 @@ description: '漏洞情报检索与判定:NVD/CISA-KEV/GHSA/OSV 四处权威
|
|
|
4
4
|
whenToUse: '用户给出 CVE/GHSA 编号要求查详情与影响、判断漏洞是否被在野利用(KEV)、评估漏洞对当前项目/依赖的适用性或汇总漏洞情报简报时使用;没有具体编号的通用安全学习、与特定漏洞无关的讨论不触发本技能。'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# 漏洞情报(vuln-intel)
|
|
@@ -4,7 +4,7 @@ description: 'Dependency supply-chain audit: reading pnpm/npm audit output and e
|
|
|
4
4
|
whenToUse: 'Use when the user asks to audit or inventory project dependency security (vulnerabilities, licenses, poisoning, lockfile drift), to interpret an audit report, to judge whether a dependency may be introduced, or to write a dependency-audit conclusion. Upgrading a single dependency and plain feature development do not trigger this skill.'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
# Dependency audit (dependency-audit)
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ description: 'Security incident response for agent environments: a staged flow o
|
|
|
4
4
|
whenToUse: 'Use when an agent environment (DSH sessions, plugins, MCP, CI) shows a suspected security incident — secret leak, injected execution of unauthorized actions, dependency poisoning, permission anomalies — and it needs response, evidence, and a postmortem. Day-to-day development without incident indicators does not trigger this skill.'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Incident response (incident-response)
|
|
@@ -4,7 +4,7 @@ description: 'Injection-surface review for agent projects: a checklist covering
|
|
|
4
4
|
whenToUse: 'Use when reviewing the context injection surfaces of an agent project (AGENTS.md/CLAUDE.md, .agents/skills, tool descriptions, MCP server sources, web-fetch chains), assessing indirect-injection risk, or doing a security review of an agent project. Ordinary code review unrelated to model context does not trigger this skill.'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
# Prompt-injection surface review (prompt-injection-review)
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ description: 'Credential/secret exposure audit: gitleaks and trivy full-history
|
|
|
4
4
|
whenToUse: 'Use when the user asks to scan or inspect a repository for secret leaks, to hunt tokens in a commit or file, to tier scan alerts as real or false, to write a redacted leak report, or to plan secret rotation. Plain feature development and ordinary code review do not trigger this skill.'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
# Secret scanning (secret-scan)
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ description: 'Repository/software security audit overview: a staged flow of scop
|
|
|
4
4
|
whenToUse: 'Use when the user asks for a security audit of a code repository or project, an audit plan, staged audit steps, a consolidated findings report, or is unsure which specialist skill to start with. Single-topic tasks (only secrets, only dependencies, only one PR, only injection surfaces) load the matching specialist skill directly and do not trigger this overview.'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
# Security audit overview (security-audit)
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ description: 'Quick PR/new-dependency supply-chain review: dangerous install/pos
|
|
|
4
4
|
whenToUse: 'Use when reviewing a PR that adds new dependencies (package.json/lockfile changes), inspecting a package install-script behavior, judging a suspected typosquat package, or verifying build reproducibility. Plain business-code PR reviews unrelated to new dependencies do not trigger this skill.'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
# New-dependency quick review (supply-chain-review)
|
|
10
10
|
|
|
@@ -4,7 +4,7 @@ description: 'Lightweight threat modeling for new features/systems: fix the targ
|
|
|
4
4
|
whenToUse: 'Use when the user asks for threat modeling of a new feature/system, design-stage security review, STRIDE analysis, attack-tree analysis, or wants security considered up front at design time. Pure implementation detail discussions and changes unrelated to trust boundaries do not trigger this skill.'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Threat modeling (threat-model)
|
|
@@ -4,7 +4,7 @@ description: 'Vulnerability intelligence lookup and triage: query commands for t
|
|
|
4
4
|
whenToUse: 'Use when the user gives a CVE/GHSA id and asks for details and impact, whether a vulnerability is actively exploited (KEV), its applicability to the current project/dependencies, or a vulnerability intelligence brief. General security learning without a specific id, and discussions unrelated to a specific vulnerability, do not trigger this skill.'
|
|
5
5
|
metadata:
|
|
6
6
|
pack: dsh-skill-pack-security
|
|
7
|
-
version: '2.0
|
|
7
|
+
version: '2.1.0'
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Vulnerability intelligence (vuln-intel)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@perrylink/dsh-skill-pack-security-provider",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Provider plugin for dsh-skill-pack-security: registers the pack's skills/ (zh) or skills-en/ (en) edition on ctx.skills AND the plugin_vet supply-chain gate tool on ctx.tools (license/SBOM/commit-lock/malware scans + five-dimension risk card). Ships both skill editions embedded in pack/.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|