@neobiotechlabs/neobiotech-dev-agent 0.1.20 → 0.1.21
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/data/cyber_sec.png +0 -0
- package/data/hazard_panel.png +0 -0
- package/data/risk_score.png +0 -0
- package/dist/index.js +353 -145
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"source": "npm",
|
|
11
11
|
"package": "@neobiotechlabs/neobiotech-dev-agent",
|
|
12
12
|
"registry": "https://registry.npmjs.org",
|
|
13
|
-
"version": "0.1.
|
|
13
|
+
"version": "0.1.21"
|
|
14
14
|
},
|
|
15
15
|
"description": "의료기기 SW 규제 개발 자동화 (Jira·Confluence·Risk·CVSS·Xray·IEC 62304/62366·MDR·문서 렌더)",
|
|
16
16
|
"category": "medical-device",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -159642,6 +159642,7 @@ var RiskClient = class {
|
|
|
159642
159642
|
this.authHeader = `Basic ${Buffer.from(`${email2}:${token}`).toString("base64")}`;
|
|
159643
159643
|
this.riskAuthToken = riskAuthToken2;
|
|
159644
159644
|
}
|
|
159645
|
+
/** Jira issue property 활성화 (Jira 표준 REST + Basic auth) */
|
|
159645
159646
|
async activateRiskPanel(issueKey) {
|
|
159646
159647
|
const appId = "306e01a8-5530-427d-b93a-f91f4898ff16";
|
|
159647
159648
|
const configId = "2a1d023a-d4a5-42c7-91e2-51a05b9eb9be";
|
|
@@ -159660,11 +159661,23 @@ var RiskClient = class {
|
|
|
159660
159661
|
);
|
|
159661
159662
|
return resp.ok;
|
|
159662
159663
|
}
|
|
159663
|
-
|
|
159664
|
-
|
|
159665
|
-
|
|
159666
|
-
|
|
159667
|
-
|
|
159664
|
+
/**
|
|
159665
|
+
* Legacy 0.1.20 호환 — classifier/option name을 받아 lookup 후 setRawPayload 호출.
|
|
159666
|
+
* 0.1.21+ 핸들러는 planSetRisk 결과를 setRiskValueRaw로 직접 보내므로 이 메서드는
|
|
159667
|
+
* 그레이스존 유지용. 그러나 RISK_DEFAULTS 정의를 사용하지 않으므로 항상 undefined.
|
|
159668
|
+
*/
|
|
159669
|
+
async setRiskValue(_issueKey, _riskConfig, _classifierName, _optionName) {
|
|
159670
|
+
return {
|
|
159671
|
+
ok: false,
|
|
159672
|
+
status: 0,
|
|
159673
|
+
error: "risk_set_values\uC740 0.1.21\uC5D0\uC11C setRiskValueRaw\uB85C \uC774\uC804\uB418\uC5C8\uC2B5\uB2C8\uB2E4. planSetRisk() \uC0AC\uC6A9 \uAD8C\uC7A5."
|
|
159674
|
+
};
|
|
159675
|
+
}
|
|
159676
|
+
/**
|
|
159677
|
+
* 신규 0.1.21 메서드 — payload가 완전 set된 상태로 RMP webtrigger 호출.
|
|
159678
|
+
* endpoint+token은 환경변수에서 받음 (회사 사이트마다 다름).
|
|
159679
|
+
*/
|
|
159680
|
+
async setRiskValueRaw(issueKey, payload) {
|
|
159668
159681
|
if (!this.riskAuthToken) {
|
|
159669
159682
|
return {
|
|
159670
159683
|
ok: false,
|
|
@@ -159672,24 +159685,27 @@ var RiskClient = class {
|
|
|
159672
159685
|
error: "RISK_PLUGIN_AUTH_TOKEN not configured (x-trigger-authentication header would be empty)"
|
|
159673
159686
|
};
|
|
159674
159687
|
}
|
|
159675
|
-
const
|
|
159688
|
+
const endpoint = process.env.RISK_PLUGIN_ENDPOINT;
|
|
159689
|
+
if (!endpoint) {
|
|
159690
|
+
return {
|
|
159691
|
+
ok: false,
|
|
159692
|
+
status: 0,
|
|
159693
|
+
error: "RISK_PLUGIN_ENDPOINT not configured. \uD68C\uC0AC DYN \uC0AC\uC774\uD2B8\uC758 RMP webtrigger URL\uC744 environment \uBCC0\uC218\uB85C \uC785\uB825\uD558\uC138\uC694."
|
|
159694
|
+
};
|
|
159695
|
+
}
|
|
159696
|
+
const fullPayload = {
|
|
159697
|
+
...payload,
|
|
159676
159698
|
issueKey,
|
|
159677
|
-
author:
|
|
159678
|
-
riskModelKey: riskConfig.riskModelKey,
|
|
159679
|
-
riskSetId: riskConfig.riskSetId,
|
|
159680
|
-
classifierValuePayload: {
|
|
159681
|
-
classifierId: classifier.id,
|
|
159682
|
-
optionId
|
|
159683
|
-
}
|
|
159699
|
+
author: payload.author ?? ""
|
|
159684
159700
|
};
|
|
159685
159701
|
try {
|
|
159686
|
-
const resp = await fetch(
|
|
159702
|
+
const resp = await fetch(endpoint, {
|
|
159687
159703
|
method: "POST",
|
|
159688
159704
|
headers: {
|
|
159689
159705
|
"x-trigger-authentication": this.riskAuthToken,
|
|
159690
159706
|
"Content-Type": "application/json"
|
|
159691
159707
|
},
|
|
159692
|
-
body: JSON.stringify(
|
|
159708
|
+
body: JSON.stringify(fullPayload)
|
|
159693
159709
|
});
|
|
159694
159710
|
const body = await resp.text();
|
|
159695
159711
|
return {
|
|
@@ -160081,57 +160097,244 @@ var registerConfluenceTools = (ctx2) => {
|
|
|
160081
160097
|
});
|
|
160082
160098
|
};
|
|
160083
160099
|
|
|
160084
|
-
// src/config/
|
|
160085
|
-
var
|
|
160086
|
-
|
|
160087
|
-
|
|
160088
|
-
|
|
160089
|
-
|
|
160090
|
-
|
|
160091
|
-
|
|
160092
|
-
|
|
160093
|
-
|
|
160094
|
-
|
|
160095
|
-
|
|
160096
|
-
|
|
160097
|
-
|
|
160098
|
-
|
|
160099
|
-
|
|
160100
|
-
|
|
160101
|
-
|
|
160100
|
+
// src/config/risk-models.ts
|
|
160101
|
+
var RISK_MODELS = {
|
|
160102
|
+
p1_p2_iso14971: {
|
|
160103
|
+
label: "P1-P2 ISO14971 Hazard analysis",
|
|
160104
|
+
modelKey: "risk-model-9dc1c741-0858-4a96-65d6-5feaf052da71",
|
|
160105
|
+
riskSets: {
|
|
160106
|
+
initial: "2f43f135-d043-84bd-4222-46ba4a309738",
|
|
160107
|
+
current: "f957cae9-a34c-30d7-557b-f7f29a414ba5"
|
|
160108
|
+
},
|
|
160109
|
+
classifiers: {
|
|
160110
|
+
severity: {
|
|
160111
|
+
id: "120dbe93-8a5c-89d9-398c-6fdefc8fa072",
|
|
160112
|
+
options: {
|
|
160113
|
+
negligible: "0750b204-3be7-14b2-34c9-5100846e99db",
|
|
160114
|
+
minor: "70ccea9f-a585-d248-dbd0-e6eefcc683e8",
|
|
160115
|
+
serious: "a8b765c0-2e55-f6c4-25ff-1a4513c1cfd7",
|
|
160116
|
+
critical: "587d166e-890a-5123-e179-15bafbd617e1",
|
|
160117
|
+
catastrophic: "981fbfd5-604d-f9b9-6765-3405a165f401"
|
|
160118
|
+
}
|
|
160119
|
+
},
|
|
160120
|
+
p1: {
|
|
160121
|
+
id: "c2c0af5d-74de-e463-ad13-ba80da1b6afd",
|
|
160122
|
+
options: {
|
|
160123
|
+
improvable: "3ac4a3b1-55ef-de93-3452-61c572a905a3",
|
|
160124
|
+
remote: "2d173a68-c28f-d589-1300-bc127f962810",
|
|
160125
|
+
occasional: "039596ac-784e-f0ac-50cf-d4d2cc96b096",
|
|
160126
|
+
probable: "702cb81f-3bc6-d150-5cc3-daa04d3f0404",
|
|
160127
|
+
frequent: "09fb301a-4448-d8aa-afd2-76d371f501f3"
|
|
160128
|
+
}
|
|
160129
|
+
},
|
|
160130
|
+
p2: {
|
|
160131
|
+
id: "cdada7bb-cb4a-3b00-260b-5e5227e85a74",
|
|
160132
|
+
options: {
|
|
160133
|
+
improvable: "7e044b34-25c4-ffae-5237-48eebb190358",
|
|
160134
|
+
remote: "58257cb8-59e2-5ec7-dd1d-9e966fb13589",
|
|
160135
|
+
occasional: "6cf5ebce-3b07-69b1-b093-9e0ef9def95c",
|
|
160136
|
+
probable: "bbcbfdd1-0c02-6105-e8e4-f60ae6cacb5c",
|
|
160137
|
+
frequent: "e35de539-93d5-f854-c6ed-50067ad8599b"
|
|
160138
|
+
}
|
|
160102
160139
|
}
|
|
160140
|
+
}
|
|
160141
|
+
},
|
|
160142
|
+
rpn: {
|
|
160143
|
+
label: "Risk Score Calculator",
|
|
160144
|
+
modelKey: "risk-model-c3edfff2-bea1-eb85-1f53-1007c429357a",
|
|
160145
|
+
riskSets: {
|
|
160146
|
+
initial: "f0f50906-1516-0826-8e82-009813ce7ff7",
|
|
160147
|
+
current: "069094fa-c4b1-28a1-d330-464f78b4ecb5",
|
|
160148
|
+
final: "d972671a-06c1-cf5d-e73b-20779079b509"
|
|
160103
160149
|
},
|
|
160104
|
-
|
|
160105
|
-
|
|
160106
|
-
|
|
160107
|
-
|
|
160108
|
-
|
|
160109
|
-
|
|
160110
|
-
|
|
160111
|
-
|
|
160150
|
+
classifiers: {
|
|
160151
|
+
severity: {
|
|
160152
|
+
id: "fec8bdcd-0c55-4ab3-87e3-cfd7176aefd5",
|
|
160153
|
+
options: {
|
|
160154
|
+
negligible: "a87a6249-03e4-5419-d50e-0818d824e8cb",
|
|
160155
|
+
minor: "f0f50906-1516-0826-8e82-009813ce7ff7",
|
|
160156
|
+
serious: "15f87aeb-28ec-98ea-7310-4ad04b294127",
|
|
160157
|
+
critical: "bf9cf219-e342-12ef-4305-2963f930138d",
|
|
160158
|
+
catastrophic: "e04cdc89-ffae-6001-4c06-d14b9fea0eee"
|
|
160159
|
+
}
|
|
160160
|
+
},
|
|
160161
|
+
occurrence: {
|
|
160162
|
+
id: "dc6e3abf-8cfa-b48f-5693-0f51a2362c8f",
|
|
160163
|
+
options: {
|
|
160164
|
+
improvable: "421dfccd-e545-2ec1-6d76-74913955cb63",
|
|
160165
|
+
remote: "8933daea-a933-3ea0-59c1-eb8b7aa0120e",
|
|
160166
|
+
occasional: "96861e6d-1b59-6616-7dda-0e6f413f4f65",
|
|
160167
|
+
probable: "40cd4688-3f91-3781-40c1-5ce65f7cb272",
|
|
160168
|
+
frequent: "7d1c1103-238d-a104-28d7-ba312dd4e394"
|
|
160169
|
+
}
|
|
160170
|
+
},
|
|
160171
|
+
detectability: {
|
|
160172
|
+
id: "2c266e79-f190-1234-95d1-201f72c98acc",
|
|
160173
|
+
options: {
|
|
160174
|
+
improvable: "f57c4581-c957-a270-65e6-1d6930b93a7f",
|
|
160175
|
+
remote: "f7fdea4b-5378-8c45-854d-bcd8ba3bee12",
|
|
160176
|
+
occasional: "45fb0720-f204-acf9-33dd-c92ba27910fa",
|
|
160177
|
+
probable: "c1a7a596-6fc4-db5d-1da3-f2b13d64da8c",
|
|
160178
|
+
frequent: "67ea818d-8ed7-a1af-57ff-6ba68a24c4b4"
|
|
160179
|
+
}
|
|
160112
160180
|
}
|
|
160181
|
+
}
|
|
160182
|
+
},
|
|
160183
|
+
cia: {
|
|
160184
|
+
label: "Cyber Sec Risk Model",
|
|
160185
|
+
modelKey: "risk-model-ciaRiskModel",
|
|
160186
|
+
riskSets: {
|
|
160187
|
+
initial: "68f0e9de-26c6-7ad8-5a72-a688ad770b24",
|
|
160188
|
+
current: "b43d25e0-0ab5-3605-cd2d-3f54f904d26c"
|
|
160189
|
+
},
|
|
160190
|
+
ciaWrapper: {
|
|
160191
|
+
id: "54d9d60c-7c53-2454-a48d-3c464bad23a9",
|
|
160192
|
+
riskModelKey: "risk-model-overallCIAImpact"
|
|
160113
160193
|
},
|
|
160114
|
-
|
|
160115
|
-
|
|
160116
|
-
|
|
160117
|
-
|
|
160118
|
-
|
|
160119
|
-
|
|
160120
|
-
|
|
160121
|
-
|
|
160194
|
+
classifiers: {
|
|
160195
|
+
confidentiality: {
|
|
160196
|
+
id: "193ceea6-d531-808b-bb83-d16eb233d73f",
|
|
160197
|
+
options: {
|
|
160198
|
+
negligible: "9dc59ace-7484-108c-77fc-383c85a54052",
|
|
160199
|
+
low: "c1802cd2-a655-3ed9-8138-376297ab39ab",
|
|
160200
|
+
moderate: "d96e2893-515d-29da-d168-c134fb055fa1",
|
|
160201
|
+
high: "dc7f3d58-a8cd-7729-5e0a-37cedfe7996f",
|
|
160202
|
+
severe: "39fe9a59-c8b9-d0b5-a273-fbfcc6efdb6c"
|
|
160203
|
+
}
|
|
160204
|
+
},
|
|
160205
|
+
availability: {
|
|
160206
|
+
id: "1121ee15-e019-dbd7-64f2-47e7af76e789",
|
|
160207
|
+
options: {
|
|
160208
|
+
negligible: "863fd4fd-d939-4e73-fdc9-b27489fcbbb4",
|
|
160209
|
+
low: "cbb40d71-238c-97d7-02cd-4b905929eedb",
|
|
160210
|
+
moderate: "4fbc0ef0-1378-3b2c-7401-75ce94d9443b",
|
|
160211
|
+
high: "33a53544-c011-c30d-dc66-d5f9e0d0bb88",
|
|
160212
|
+
severe: "d9f4a792-0822-c0b0-b463-4c2887ce4d01"
|
|
160213
|
+
}
|
|
160214
|
+
},
|
|
160215
|
+
integrity: {
|
|
160216
|
+
id: "639c61e6-9d11-9bb3-04e7-c1c3512c7e33",
|
|
160217
|
+
options: {
|
|
160218
|
+
negligible: "f35284c1-52a2-edce-e60b-69b97703b891",
|
|
160219
|
+
low: "af67cc1b-9e25-76ce-baf3-d2e8247af569",
|
|
160220
|
+
moderate: "a35a0d14-e8d4-b3c8-35fc-a1f81d2730c7",
|
|
160221
|
+
high: "e535be53-21a8-0f8d-3c78-db4c3d7ebde1",
|
|
160222
|
+
severe: "7a45c4d7-d926-5d01-0034-c9ef929117b3"
|
|
160223
|
+
}
|
|
160224
|
+
},
|
|
160225
|
+
likelihood: {
|
|
160226
|
+
id: "ff7ed5a9-53fe-7e29-f564-b8f3b96bdd5b",
|
|
160227
|
+
options: {
|
|
160228
|
+
rare: "5b3f2233-4603-f34a-9e06-1473e4e1da02",
|
|
160229
|
+
unlikely: "7af594cb-4a87-73c1-2d0a-924124c5f247",
|
|
160230
|
+
possibly: "ed8a2a21-ec63-5e9b-d1d3-60d39ad4ec91",
|
|
160231
|
+
likely: "afe83dfb-fc00-7d3c-9b65-ed0ba6607b96",
|
|
160232
|
+
almost_certain: "86def84c-70c4-15c2-7b7b-f084a9aaf19f"
|
|
160233
|
+
}
|
|
160122
160234
|
}
|
|
160123
160235
|
}
|
|
160124
160236
|
}
|
|
160125
160237
|
};
|
|
160126
|
-
|
|
160127
|
-
|
|
160238
|
+
|
|
160239
|
+
// src/config/project-config.ts
|
|
160240
|
+
function planSetRisk(model, riskSet, classifierOptions, issueKey) {
|
|
160241
|
+
const m3 = RISK_MODELS[model];
|
|
160242
|
+
if (!m3) return { items: [], skipped: [{ classifier: "*", optionName: model }] };
|
|
160243
|
+
const setId = m3.riskSets[riskSet];
|
|
160244
|
+
if (!setId) return { items: [], skipped: [{ classifier: "*", optionName: `riskSet.${riskSet}` }] };
|
|
160245
|
+
const author = process.env.JIRA_EMAIL;
|
|
160246
|
+
if (!author) return { items: [], skipped: [{ classifier: "*", optionName: "JIRA_EMAIL missing" }] };
|
|
160247
|
+
const items = [];
|
|
160248
|
+
const skipped = [];
|
|
160249
|
+
for (const [classifierName, optionName] of Object.entries(classifierOptions)) {
|
|
160250
|
+
if (!optionName) continue;
|
|
160251
|
+
const cls = m3.classifiers[classifierName];
|
|
160252
|
+
if (!cls) {
|
|
160253
|
+
skipped.push({ classifier: classifierName, optionName });
|
|
160254
|
+
continue;
|
|
160255
|
+
}
|
|
160256
|
+
const optionId = cls.options[optionName];
|
|
160257
|
+
if (!optionId) {
|
|
160258
|
+
skipped.push({ classifier: classifierName, optionName });
|
|
160259
|
+
continue;
|
|
160260
|
+
}
|
|
160261
|
+
items.push({
|
|
160262
|
+
model,
|
|
160263
|
+
riskSet,
|
|
160264
|
+
classifierName,
|
|
160265
|
+
optionName,
|
|
160266
|
+
payload: {
|
|
160267
|
+
issueKey,
|
|
160268
|
+
author,
|
|
160269
|
+
riskModelKey: m3.modelKey,
|
|
160270
|
+
riskSetId: setId,
|
|
160271
|
+
classifierValuePayload: { classifierId: cls.id, optionId }
|
|
160272
|
+
}
|
|
160273
|
+
});
|
|
160274
|
+
}
|
|
160275
|
+
return {
|
|
160276
|
+
items: items.map((i2) => ({ payload: i2.payload })),
|
|
160277
|
+
skipped
|
|
160278
|
+
};
|
|
160128
160279
|
}
|
|
160129
160280
|
|
|
160130
160281
|
// src/tools/risk.ts
|
|
160131
|
-
|
|
160282
|
+
var SEVERITY_P1P2 = external_exports.enum(["negligible", "minor", "serious", "critical", "catastrophic"]);
|
|
160283
|
+
var PROB_P1P2 = external_exports.enum(["improvable", "remote", "occasional", "probable", "frequent"]);
|
|
160284
|
+
var SEVERITY_RPN = external_exports.enum(["negligible", "minor", "serious", "critical", "catastrophic"]);
|
|
160285
|
+
var PROB_RPN = external_exports.enum(["improvable", "remote", "occasional", "probable", "frequent"]);
|
|
160286
|
+
var CIA_LEVEL = external_exports.enum(["negligible", "low", "moderate", "high", "severe"]);
|
|
160287
|
+
var LIKELIHOOD = external_exports.enum(["rare", "unlikely", "possibly", "likely", "almost_certain"]);
|
|
160288
|
+
var RISK_SET = external_exports.enum(["initial", "current", "final"]).default("current");
|
|
160289
|
+
var p1P2Payload = external_exports.object({
|
|
160290
|
+
severity: SEVERITY_P1P2.optional(),
|
|
160291
|
+
p1: PROB_P1P2.optional(),
|
|
160292
|
+
p2: PROB_P1P2.optional()
|
|
160293
|
+
}).strict();
|
|
160294
|
+
var rpnPayload = external_exports.object({
|
|
160295
|
+
severity: SEVERITY_RPN.optional(),
|
|
160296
|
+
occurrence: PROB_RPN.optional(),
|
|
160297
|
+
detectability: PROB_RPN.optional()
|
|
160298
|
+
}).strict();
|
|
160299
|
+
var ciaPayload = external_exports.object({
|
|
160300
|
+
confidentiality: CIA_LEVEL.optional(),
|
|
160301
|
+
availability: CIA_LEVEL.optional(),
|
|
160302
|
+
integrity: CIA_LEVEL.optional(),
|
|
160303
|
+
likelihood: LIKELIHOOD.optional()
|
|
160304
|
+
}).strict();
|
|
160305
|
+
function classifierFromId(model, id) {
|
|
160306
|
+
const m3 = RISK_MODELS[model];
|
|
160307
|
+
for (const [name, cls] of Object.entries(m3.classifiers)) {
|
|
160308
|
+
if (cls.id === id) return name;
|
|
160309
|
+
}
|
|
160310
|
+
return id;
|
|
160311
|
+
}
|
|
160312
|
+
function formatSetDetail(line) {
|
|
160313
|
+
const r2 = line.result;
|
|
160132
160314
|
const tag = r2.ok ? "OK" : "FAILED";
|
|
160133
160315
|
const detail = r2.error ? `status=${r2.status}, error=${r2.error}` : `status=${r2.status}${r2.body ? `, body=${r2.body}` : ""}`;
|
|
160134
|
-
return `${
|
|
160316
|
+
return `${tag} [${line.model}] ${line.classifier}=${line.optionName} (${detail})`;
|
|
160317
|
+
}
|
|
160318
|
+
async function runSetPlans(riskStub, plans) {
|
|
160319
|
+
const out = { details: [] };
|
|
160320
|
+
for (const p of plans) {
|
|
160321
|
+
if (p.res.skipped.length > 0) {
|
|
160322
|
+
for (const sk of p.res.skipped) {
|
|
160323
|
+
out.skipped = out.skipped ?? [];
|
|
160324
|
+
out.skipped.push({ classifier: `${p.name}.${sk.classifier}`, reason: "option-not-mapped" });
|
|
160325
|
+
}
|
|
160326
|
+
}
|
|
160327
|
+
for (const { payload } of p.res.items) {
|
|
160328
|
+
const r2 = await riskStub.setRiskValueRaw(p.issueKey, payload);
|
|
160329
|
+
out.details.push({
|
|
160330
|
+
model: p.name,
|
|
160331
|
+
classifier: classifierFromId(p.model, payload.classifierValuePayload.classifierId),
|
|
160332
|
+
optionName: payload.classifierValuePayload.optionId,
|
|
160333
|
+
result: r2
|
|
160334
|
+
});
|
|
160335
|
+
}
|
|
160336
|
+
}
|
|
160337
|
+
return out;
|
|
160135
160338
|
}
|
|
160136
160339
|
var registerRiskTools = (ctx2) => {
|
|
160137
160340
|
const { server: server2, risk: risk2, jira: jira2 } = ctx2;
|
|
@@ -160141,62 +160344,77 @@ var registerRiskTools = (ctx2) => {
|
|
|
160141
160344
|
const ok = await risk2.activateRiskPanel(issue_key);
|
|
160142
160345
|
return { content: [{ type: "text", text: ok ? `Risk panel activated on ${issue_key}` : `Failed to activate risk panel on ${issue_key}` }] };
|
|
160143
160346
|
});
|
|
160144
|
-
server2.tool(
|
|
160145
|
-
|
|
160146
|
-
|
|
160147
|
-
|
|
160148
|
-
|
|
160149
|
-
|
|
160150
|
-
|
|
160151
|
-
|
|
160152
|
-
|
|
160153
|
-
|
|
160154
|
-
|
|
160155
|
-
|
|
160156
|
-
|
|
160157
|
-
|
|
160158
|
-
|
|
160159
|
-
|
|
160160
|
-
|
|
160161
|
-
|
|
160162
|
-
|
|
160163
|
-
|
|
160164
|
-
|
|
160165
|
-
const r2 = await risk2.setRiskValue(issue_key, configForSet, name, value);
|
|
160166
|
-
results.push(formatRiskResult(name, value, r2));
|
|
160347
|
+
server2.tool(
|
|
160348
|
+
"risk_set_values",
|
|
160349
|
+
"Set risk values on an issue via RMP webtrigger. P1-P2 / RPN / CIA \uB3D9\uC2DC \uC785\uB825 \uAC00\uB2A5. \uC635\uC158\uC740 name \uBB38\uC790\uC5F4(UUID \uC790\uB3D9 \uB9E4\uD551). lookup \uC2E4\uD328 \uD56D\uBAA9\uC740 SKIP.",
|
|
160350
|
+
{
|
|
160351
|
+
issue_key: external_exports.string().describe("Issue key"),
|
|
160352
|
+
project_key: external_exports.string().describe("Project key (for context)"),
|
|
160353
|
+
risk_set: RISK_SET,
|
|
160354
|
+
p1_p2_iso14971: p1P2Payload.optional(),
|
|
160355
|
+
rpn: rpnPayload.optional(),
|
|
160356
|
+
cia: ciaPayload.optional()
|
|
160357
|
+
},
|
|
160358
|
+
async ({ issue_key, project_key, risk_set, p1_p2_iso14971, rpn, cia }) => {
|
|
160359
|
+
const tasks = [
|
|
160360
|
+
{ model: "p1_p2_iso14971", name: "P1-P2", res: planSetRisk("p1_p2_iso14971", risk_set, p1_p2_iso14971 ?? {}, issue_key), issueKey: issue_key },
|
|
160361
|
+
{ model: "rpn", name: "RPN", res: planSetRisk("rpn", risk_set, rpn ?? {}, issue_key), issueKey: issue_key },
|
|
160362
|
+
{ model: "cia", name: "CIA", res: planSetRisk("cia", risk_set, cia ?? {}, issue_key), issueKey: issue_key }
|
|
160363
|
+
];
|
|
160364
|
+
const out = await runSetPlans(risk2, tasks);
|
|
160365
|
+
const lines = [`Risk values for ${issue_key} (${risk_set} set):`];
|
|
160366
|
+
if (out.details.length === 0 && (out.skipped ?? []).length === 0) {
|
|
160367
|
+
lines.push(`(no risk values specified for ${project_key})`);
|
|
160167
160368
|
}
|
|
160369
|
+
for (const d2 of out.details) lines.push(formatSetDetail(d2));
|
|
160370
|
+
for (const s2 of out.skipped ?? []) lines.push(`SKIPPED ${s2.classifier} (${s2.reason})`);
|
|
160371
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
160168
160372
|
}
|
|
160169
|
-
|
|
160170
|
-
|
|
160171
|
-
|
|
160172
|
-
|
|
160173
|
-
|
|
160174
|
-
|
|
160175
|
-
|
|
160176
|
-
|
|
160177
|
-
|
|
160178
|
-
|
|
160179
|
-
|
|
160180
|
-
|
|
160181
|
-
|
|
160182
|
-
|
|
160183
|
-
|
|
160184
|
-
|
|
160185
|
-
|
|
160186
|
-
|
|
160187
|
-
|
|
160188
|
-
|
|
160373
|
+
);
|
|
160374
|
+
server2.tool(
|
|
160375
|
+
"risk_get_config",
|
|
160376
|
+
"Get RMP risk model configuration for a project. Returns 3 model identifiers, classifier/option UUID \uD480, \uD658\uACBD \uC548\uB0B4.",
|
|
160377
|
+
{
|
|
160378
|
+
project_key: external_exports.string().describe("Project key")
|
|
160379
|
+
},
|
|
160380
|
+
async ({ project_key }) => {
|
|
160381
|
+
const endpoint = process.env.RISK_PLUGIN_ENDPOINT ?? null;
|
|
160382
|
+
const tokenPresent = !!process.env.RISK_PLUGIN_AUTH_TOKEN;
|
|
160383
|
+
return { content: [{ type: "text", text: JSON.stringify({
|
|
160384
|
+
endpoint,
|
|
160385
|
+
token_present: tokenPresent,
|
|
160386
|
+
diagnostic_note: "token\uC774 \uC5C6\uAC70\uB098 endpoint\uAC00 \uC124\uC815\uB418\uC9C0 \uC54A\uC73C\uBA74 setRiskValue \uD638\uCD9C\uC774 \uC2E4\uD328\uD569\uB2C8\uB2E4. /plugin configure \uB85C RISK_PLUGIN_ENDPOINT / RISK_PLUGIN_AUTH_TOKEN \uC744 \uC785\uB825.",
|
|
160387
|
+
models: Object.fromEntries(
|
|
160388
|
+
Object.keys(RISK_MODELS).map((k) => {
|
|
160389
|
+
const m3 = RISK_MODELS[k];
|
|
160390
|
+
return [k, {
|
|
160391
|
+
label: m3.label,
|
|
160392
|
+
modelKey: m3.modelKey,
|
|
160393
|
+
riskSets: m3.riskSets,
|
|
160394
|
+
classifiers: Object.fromEntries(
|
|
160395
|
+
Object.entries(m3.classifiers).map(([cn, c]) => [cn, { id: c.id, options: Object.keys(c.options) }])
|
|
160396
|
+
),
|
|
160397
|
+
...m3.ciaWrapper ? { ciaWrapper: m3.ciaWrapper } : {}
|
|
160398
|
+
}];
|
|
160399
|
+
})
|
|
160400
|
+
),
|
|
160401
|
+
project: project_key
|
|
160402
|
+
}, null, 2) }] };
|
|
160403
|
+
}
|
|
160404
|
+
);
|
|
160405
|
+
server2.tool("risk_create_hazards", "Batch create Hazard tickets with Risk Source links and (\uC120\uD0DD\uC801) 3 \uBAA8\uB378 risk values \uC790\uB3D9 \uC14B\uD305.", {
|
|
160406
|
+
project_key: external_exports.string(),
|
|
160407
|
+
rmr_key: external_exports.string(),
|
|
160189
160408
|
hazards: external_exports.array(external_exports.object({
|
|
160190
160409
|
summary: external_exports.string(),
|
|
160191
160410
|
description: external_exports.string(),
|
|
160192
160411
|
harm: external_exports.string(),
|
|
160193
|
-
|
|
160194
|
-
|
|
160195
|
-
|
|
160196
|
-
|
|
160197
|
-
})
|
|
160412
|
+
source_keys: external_exports.array(external_exports.string()),
|
|
160413
|
+
p1_p2_iso14971: p1P2Payload.optional(),
|
|
160414
|
+
rpn: rpnPayload.optional(),
|
|
160415
|
+
cia: ciaPayload.optional()
|
|
160416
|
+
}).strict())
|
|
160198
160417
|
}, async ({ project_key, rmr_key, hazards }) => {
|
|
160199
|
-
const riskConfig = getRiskConfig(project_key);
|
|
160200
160418
|
const { textToAdf: textToAdf2 } = await Promise.resolve().then(() => (init_jira_client(), jira_client_exports));
|
|
160201
160419
|
const results = [];
|
|
160202
160420
|
const errors = [];
|
|
@@ -160215,50 +160433,45 @@ ${results.join("\n")}` }] };
|
|
|
160215
160433
|
continue;
|
|
160216
160434
|
}
|
|
160217
160435
|
await risk2.activateRiskPanel(issueKey);
|
|
160218
|
-
|
|
160219
|
-
|
|
160220
|
-
|
|
160221
|
-
|
|
160222
|
-
|
|
160223
|
-
|
|
160224
|
-
|
|
160225
|
-
|
|
160226
|
-
riskSetId: riskConfig.risk_sets[setName],
|
|
160227
|
-
classifiers: riskConfig.classifiers
|
|
160228
|
-
};
|
|
160229
|
-
for (const [name, value] of [["severity", h2.severity], ["p1", h2.p1], ["p2", h2.p2]]) {
|
|
160230
|
-
const r2 = await risk2.setRiskValue(issueKey, setConfig, name, value);
|
|
160231
|
-
if (!r2.ok) riskOk = false;
|
|
160232
|
-
riskDetails.push(`${setName}.${name}=${value}: ${r2.ok ? "OK" : "FAILED"} (${r2.error ?? `status=${r2.status}${r2.body ? `, body=${r2.body}` : ""}`})`);
|
|
160233
|
-
}
|
|
160234
|
-
}
|
|
160235
|
-
} else {
|
|
160236
|
-
riskOk = false;
|
|
160237
|
-
riskDetails.push("no risk config for project");
|
|
160238
|
-
}
|
|
160436
|
+
const tasks = [
|
|
160437
|
+
{ model: "p1_p2_iso14971", name: "P1-P2", res: planSetRisk("p1_p2_iso14971", "initial", h2.p1_p2_iso14971 ?? {}, issueKey), issueKey },
|
|
160438
|
+
{ model: "rpn", name: "RPN", res: planSetRisk("rpn", "initial", h2.rpn ?? {}, issueKey), issueKey },
|
|
160439
|
+
{ model: "cia", name: "CIA", res: planSetRisk("cia", "initial", h2.cia ?? {}, issueKey), issueKey }
|
|
160440
|
+
];
|
|
160441
|
+
const out = await runSetPlans(risk2, tasks);
|
|
160442
|
+
const riskOk = out.details.every((d2) => d2.result.ok);
|
|
160443
|
+
const riskSkipped = out.skipped ?? [];
|
|
160239
160444
|
for (const srcKey of h2.source_keys) {
|
|
160240
160445
|
await jira2.createLink("Risk Source", issueKey, srcKey);
|
|
160241
160446
|
}
|
|
160242
160447
|
await jira2.createLink("Relates", issueKey, rmr_key);
|
|
160243
|
-
results.push({
|
|
160448
|
+
results.push({
|
|
160449
|
+
key: issueKey,
|
|
160450
|
+
summary: h2.summary,
|
|
160451
|
+
status: "created",
|
|
160452
|
+
risk_values: {
|
|
160453
|
+
ok: riskOk,
|
|
160454
|
+
details: out.details.map(formatSetDetail),
|
|
160455
|
+
skipped: riskSkipped
|
|
160456
|
+
}
|
|
160457
|
+
});
|
|
160244
160458
|
} catch (e2) {
|
|
160245
160459
|
errors.push(`${h2.summary}: ${e2.message}`);
|
|
160246
160460
|
}
|
|
160247
160461
|
}
|
|
160248
160462
|
return { content: [{ type: "text", text: JSON.stringify({ created: results.length, failed: errors.length, results, errors }, null, 2) }] };
|
|
160249
160463
|
});
|
|
160250
|
-
server2.tool("risk_create_mitigation", "Create mitigation Requirements, link to Hazards, and update Hazard Current P2
|
|
160251
|
-
project_key: external_exports.string()
|
|
160252
|
-
srs_key: external_exports.string()
|
|
160464
|
+
server2.tool("risk_create_mitigation", "Create mitigation Requirements, link to Hazards, and update Hazard Current P2 (P1-P2 \uBAA8\uB378).", {
|
|
160465
|
+
project_key: external_exports.string(),
|
|
160466
|
+
srs_key: external_exports.string(),
|
|
160253
160467
|
requirements: external_exports.array(external_exports.object({
|
|
160254
160468
|
summary: external_exports.string(),
|
|
160255
160469
|
description: external_exports.string(),
|
|
160256
|
-
mitigates: external_exports.array(external_exports.string())
|
|
160257
|
-
implements: external_exports.array(external_exports.string())
|
|
160470
|
+
mitigates: external_exports.array(external_exports.string()),
|
|
160471
|
+
implements: external_exports.array(external_exports.string())
|
|
160258
160472
|
})),
|
|
160259
|
-
hazard_risk_updates: external_exports.record(external_exports.object({ p2: external_exports.string() }))
|
|
160473
|
+
hazard_risk_updates: external_exports.record(external_exports.object({ p2: external_exports.string() }))
|
|
160260
160474
|
}, async ({ project_key, srs_key, requirements, hazard_risk_updates }) => {
|
|
160261
|
-
const riskConfig = getRiskConfig(project_key);
|
|
160262
160475
|
const { textToAdf: textToAdf2 } = await Promise.resolve().then(() => (init_jira_client(), jira_client_exports));
|
|
160263
160476
|
const results = [];
|
|
160264
160477
|
const errors = [];
|
|
@@ -160288,20 +160501,15 @@ ${results.join("\n")}` }] };
|
|
|
160288
160501
|
}
|
|
160289
160502
|
}
|
|
160290
160503
|
const riskUpdates = [];
|
|
160291
|
-
|
|
160292
|
-
const
|
|
160293
|
-
|
|
160294
|
-
|
|
160295
|
-
|
|
160296
|
-
riskSetId: riskConfig.risk_sets.current,
|
|
160297
|
-
classifiers: riskConfig.classifiers
|
|
160298
|
-
};
|
|
160299
|
-
for (const [hazKey, update] of Object.entries(hazard_risk_updates)) {
|
|
160300
|
-
const r2 = await risk2.setRiskValue(hazKey, currentConfig, "p2", update.p2);
|
|
160301
|
-
riskUpdates.push(`${hazKey} P2\u2192${update.p2}: ${r2.ok ? "OK" : "FAILED"} (${r2.error ?? `status=${r2.status}${r2.body ? `, body=${r2.body}` : ""}`})`);
|
|
160504
|
+
for (const [hazKey, update] of Object.entries(hazard_risk_updates)) {
|
|
160505
|
+
const plan = planSetRisk("p1_p2_iso14971", "current", { p2: update.p2 }, hazKey);
|
|
160506
|
+
if (plan.skipped.length > 0) {
|
|
160507
|
+
riskUpdates.push(`SKIPPED ${hazKey} P2=${update.p2} (option-not-mapped)`);
|
|
160508
|
+
continue;
|
|
160302
160509
|
}
|
|
160303
|
-
|
|
160304
|
-
|
|
160510
|
+
const { payload } = plan.items[0];
|
|
160511
|
+
const r2 = await risk2.setRiskValueRaw(hazKey, payload);
|
|
160512
|
+
riskUpdates.push(formatSetDetail({ model: "P1-P2", classifier: "p2", optionName: update.p2, result: r2 }));
|
|
160305
160513
|
}
|
|
160306
160514
|
return { content: [{ type: "text", text: JSON.stringify({ requirements_created: results.length, results, risk_updates: riskUpdates, errors }, null, 2) }] };
|
|
160307
160515
|
});
|
|
@@ -184760,7 +184968,7 @@ var xrayClientSecret = process.env.XRAY_CLIENT_SECRET || "";
|
|
|
184760
184968
|
var xray = xrayClientId && xrayClientSecret ? new XrayClient(xrayClientId, xrayClientSecret, jiraUrl, jiraEmail, jiraToken) : null;
|
|
184761
184969
|
var server = new McpServer({
|
|
184762
184970
|
name: "jira-confluence",
|
|
184763
|
-
version: "0.1.
|
|
184971
|
+
version: "0.1.21"
|
|
184764
184972
|
});
|
|
184765
184973
|
var ctx = { server, jira, confluence, risk, xray };
|
|
184766
184974
|
registerJiraCrudTools(ctx);
|