@kryptosai/mcp-observatory 0.27.0 → 1.28.1

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.
Files changed (160) hide show
  1. package/COMMERCIAL.md +28 -2
  2. package/CONTRIBUTORS.md +39 -0
  3. package/README.md +114 -22
  4. package/dist/src/action-receipt.d.ts +20 -0
  5. package/dist/src/action-receipt.js +85 -0
  6. package/dist/src/action-receipt.js.map +1 -0
  7. package/dist/src/adapters/http.js +1 -5
  8. package/dist/src/adapters/http.js.map +1 -1
  9. package/dist/src/audit.d.ts +64 -0
  10. package/dist/src/audit.js +359 -0
  11. package/dist/src/audit.js.map +1 -0
  12. package/dist/src/cassette.js +3 -2
  13. package/dist/src/cassette.js.map +1 -1
  14. package/dist/src/checks/attack-sim.d.ts +20 -0
  15. package/dist/src/checks/attack-sim.js +316 -0
  16. package/dist/src/checks/attack-sim.js.map +1 -0
  17. package/dist/src/ci-issue.js +4 -3
  18. package/dist/src/ci-issue.js.map +1 -1
  19. package/dist/src/cli.js +25 -4
  20. package/dist/src/cli.js.map +1 -1
  21. package/dist/src/commands/attack-sim.d.ts +2 -0
  22. package/dist/src/commands/attack-sim.js +220 -0
  23. package/dist/src/commands/attack-sim.js.map +1 -0
  24. package/dist/src/commands/audit.d.ts +2 -0
  25. package/dist/src/commands/audit.js +132 -0
  26. package/dist/src/commands/audit.js.map +1 -0
  27. package/dist/src/commands/init-ci.d.ts +3 -0
  28. package/dist/src/commands/init-ci.js +78 -13
  29. package/dist/src/commands/init-ci.js.map +1 -1
  30. package/dist/src/commands/legacy.js +8 -1
  31. package/dist/src/commands/legacy.js.map +1 -1
  32. package/dist/src/commands/receipt.d.ts +2 -0
  33. package/dist/src/commands/receipt.js +113 -0
  34. package/dist/src/commands/receipt.js.map +1 -0
  35. package/dist/src/commands/scan.js +30 -6
  36. package/dist/src/commands/scan.js.map +1 -1
  37. package/dist/src/commands/score.js +63 -0
  38. package/dist/src/commands/score.js.map +1 -1
  39. package/dist/src/commands/serve.js +9 -1
  40. package/dist/src/commands/serve.js.map +1 -1
  41. package/dist/src/commands/setup-ci-conversion.d.ts +3 -1
  42. package/dist/src/commands/setup-ci-conversion.js +23 -8
  43. package/dist/src/commands/setup-ci-conversion.js.map +1 -1
  44. package/dist/src/commands/telemetry.js +20 -14
  45. package/dist/src/commands/telemetry.js.map +1 -1
  46. package/dist/src/commands/test.js +31 -2
  47. package/dist/src/commands/test.js.map +1 -1
  48. package/dist/src/findings.d.ts +1 -0
  49. package/dist/src/findings.js +42 -1
  50. package/dist/src/findings.js.map +1 -1
  51. package/dist/src/history.js +3 -2
  52. package/dist/src/history.js.map +1 -1
  53. package/dist/src/index.d.ts +4 -0
  54. package/dist/src/index.js +4 -0
  55. package/dist/src/index.js.map +1 -1
  56. package/dist/src/integrations/smithery.js +5 -1
  57. package/dist/src/integrations/smithery.js.map +1 -1
  58. package/dist/src/receipt.d.ts +100 -0
  59. package/dist/src/receipt.js +375 -0
  60. package/dist/src/receipt.js.map +1 -0
  61. package/dist/src/reporters/attack-sim.d.ts +2 -0
  62. package/dist/src/reporters/attack-sim.js +89 -0
  63. package/dist/src/reporters/attack-sim.js.map +1 -0
  64. package/dist/src/reporters/pr-comment.js +20 -6
  65. package/dist/src/reporters/pr-comment.js.map +1 -1
  66. package/dist/src/reporters/sarif.js +11 -1
  67. package/dist/src/reporters/sarif.js.map +1 -1
  68. package/dist/src/runner.d.ts +3 -0
  69. package/dist/src/runner.js +5 -0
  70. package/dist/src/runner.js.map +1 -1
  71. package/dist/src/score.js +1 -1
  72. package/dist/src/score.js.map +1 -1
  73. package/dist/src/security-profiles.d.ts +13 -0
  74. package/dist/src/security-profiles.js +59 -0
  75. package/dist/src/security-profiles.js.map +1 -0
  76. package/dist/src/storage.js +3 -2
  77. package/dist/src/storage.js.map +1 -1
  78. package/dist/src/telemetry.d.ts +10 -0
  79. package/dist/src/telemetry.js +17 -1
  80. package/dist/src/telemetry.js.map +1 -1
  81. package/dist/src/types.d.ts +1 -1
  82. package/dist/src/utils/files.d.ts +1 -0
  83. package/dist/src/utils/files.js +21 -0
  84. package/dist/src/utils/files.js.map +1 -0
  85. package/dist/src/utils/ids.js +18 -5
  86. package/dist/src/utils/ids.js.map +1 -1
  87. package/dist/src/utils/url.d.ts +2 -0
  88. package/dist/src/utils/url.js +15 -0
  89. package/dist/src/utils/url.js.map +1 -0
  90. package/dist/src/validate.js +1 -1
  91. package/dist/src/validate.js.map +1 -1
  92. package/docs/10x-agentic-growth-sprint.md +47 -0
  93. package/docs/agent-ecosystem-promotion-plan.md +244 -0
  94. package/docs/agent-tasks.md +95 -0
  95. package/docs/agentic-contributor-outreach.md +52 -0
  96. package/docs/automatic-ci-integration.md +33 -0
  97. package/docs/campaign-attribution.md +58 -0
  98. package/docs/code-scanning-demo.md +57 -0
  99. package/docs/commercial-boundary.md +83 -0
  100. package/docs/contributor-proof-cards/README.md +33 -0
  101. package/docs/contributor-recognition.md +92 -0
  102. package/docs/examples/nsa-mcp-audit-report.md +372 -0
  103. package/docs/examples/nsa-mcp-results.sarif +930 -0
  104. package/docs/examples/nsa-mcp-score.json +13 -0
  105. package/docs/feishu-lark-mcp.md +1 -1
  106. package/docs/github-code-scanning-for-mcp.md +1 -1
  107. package/docs/government-enterprise-pilot.md +93 -0
  108. package/docs/launch.md +64 -0
  109. package/docs/mcp-attack-simulator.md +57 -0
  110. package/docs/mcp-receipts.md +109 -0
  111. package/docs/mcp-server-safety-index.md +29 -22
  112. package/docs/nsa-mcp-audit-ci.md +88 -0
  113. package/docs/procurement-one-pager.md +74 -0
  114. package/docs/proof.md +5 -2
  115. package/docs/public-guidance-crosswalk.md +48 -0
  116. package/docs/receipt-graph.md +54 -0
  117. package/docs/safety-index/artifacts/antv-chart-server.json +40 -22
  118. package/docs/safety-index/artifacts/antv-chart-server.md +22 -9
  119. package/docs/safety-index/artifacts/browsermcp-server.json +36 -18
  120. package/docs/safety-index/artifacts/browsermcp-server.md +22 -9
  121. package/docs/safety-index/artifacts/context7-server.json +83 -26
  122. package/docs/safety-index/artifacts/context7-server.md +33 -20
  123. package/docs/safety-index/artifacts/cyanheads-git-mcp-server.json +2438 -0
  124. package/docs/safety-index/artifacts/cyanheads-git-mcp-server.md +176 -0
  125. package/docs/safety-index/artifacts/everything-server.json +150 -57
  126. package/docs/safety-index/artifacts/everything-server.md +36 -23
  127. package/docs/safety-index/artifacts/executeautomation-playwright-server.json +162 -19
  128. package/docs/safety-index/artifacts/executeautomation-playwright-server.md +25 -12
  129. package/docs/safety-index/artifacts/filesystem-server.json +221 -19
  130. package/docs/safety-index/artifacts/filesystem-server.md +24 -11
  131. package/docs/safety-index/artifacts/kubernetes-server.attack.json +1559 -0
  132. package/docs/safety-index/artifacts/kubernetes-server.attack.md +43 -0
  133. package/docs/safety-index/artifacts/kubernetes-server.attack.sarif +2857 -0
  134. package/docs/safety-index/artifacts/kubernetes-server.json +1573 -0
  135. package/docs/safety-index/artifacts/kubernetes-server.md +176 -0
  136. package/docs/safety-index/artifacts/memory-server.json +93 -32
  137. package/docs/safety-index/artifacts/memory-server.md +45 -25
  138. package/docs/safety-index/artifacts/opentofu-server.json +44 -18
  139. package/docs/safety-index/artifacts/opentofu-server.md +23 -10
  140. package/docs/safety-index/artifacts/playwright-mcp-server.json +177 -21
  141. package/docs/safety-index/artifacts/playwright-mcp-server.md +27 -14
  142. package/docs/safety-index/artifacts/promptopia-server.json +45 -19
  143. package/docs/safety-index/artifacts/promptopia-server.md +21 -8
  144. package/docs/safety-index/artifacts/puppeteer-server.json +77 -22
  145. package/docs/safety-index/artifacts/puppeteer-server.md +28 -15
  146. package/docs/safety-index/artifacts/ref-tools-server.json +36 -18
  147. package/docs/safety-index/artifacts/ref-tools-server.md +21 -8
  148. package/docs/safety-index/artifacts/sequential-thinking-server.json +38 -21
  149. package/docs/safety-index/artifacts/sequential-thinking-server.md +22 -9
  150. package/docs/safety-index/targets.json +90 -14
  151. package/docs/security-due-diligence.md +87 -0
  152. package/docs/setup-ci-doctor.md +13 -1
  153. package/docs/target-gallery.md +49 -0
  154. package/docs/target-registry.md +5 -1
  155. package/docs/tool-call-receipts.md +115 -0
  156. package/examples/insecure-mcp-server/mcp-observatory.target.json +13 -0
  157. package/examples/insecure-mcp-server/server.mjs +62 -0
  158. package/package.json +31 -2
  159. package/schemas/run-artifact.schema.json +1 -0
  160. package/scripts/postinstall.mjs +138 -0
@@ -0,0 +1,220 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { extractObservatoryFindings } from "../findings.js";
3
+ import { runTarget } from "../index.js";
4
+ import { renderAttackSimulationMarkdown } from "../reporters/attack-sim.js";
5
+ import { renderSarif } from "../reporters/sarif.js";
6
+ import { buildEvent, normalizeCampaign, recordEvent } from "../telemetry.js";
7
+ import { validateRunArtifact } from "../validate.js";
8
+ import { renderActionReceipt } from "../action-receipt.js";
9
+ import { maybePrintCloudCta } from "../commercial.js";
10
+ import { ANSI, c, getBinName, quoteShell, resolveTarget, targetFromCommand, writeOutput } from "./helpers.js";
11
+ import { maybeConvertPassingCheckToCi } from "./setup-ci-conversion.js";
12
+ function extractTrailingAttackFlags(commandArgs, options) {
13
+ const flags = { ...options };
14
+ const targetArgs = [];
15
+ for (let i = 0; i < commandArgs.length; i += 1) {
16
+ const arg = commandArgs[i];
17
+ const assign = arg.match(/^(--baseline|--json|--mode|--output|--sarif)=(.+)$/);
18
+ if (arg === "--") {
19
+ targetArgs.push(...commandArgs.slice(i + 1));
20
+ break;
21
+ }
22
+ else if (assign) {
23
+ const [, name, value] = assign;
24
+ if (name === "--baseline")
25
+ flags.baseline = value;
26
+ if (name === "--json")
27
+ flags.json = value;
28
+ if (name === "--mode")
29
+ flags.mode = value;
30
+ if (name === "--output")
31
+ flags.output = value;
32
+ if (name === "--sarif")
33
+ flags.sarif = value;
34
+ }
35
+ else if (arg === "--baseline") {
36
+ const next = commandArgs[i + 1];
37
+ if (!next)
38
+ throw new Error("--baseline requires a run artifact path.");
39
+ flags.baseline = next;
40
+ i += 1;
41
+ }
42
+ else if (arg === "--fail-on-high") {
43
+ flags.failOnHigh = true;
44
+ }
45
+ else if (arg === "--setup-ci") {
46
+ flags.setupCi = true;
47
+ }
48
+ else if (arg === "--yes") {
49
+ flags.yes = true;
50
+ }
51
+ else if (arg === "--no-setup-ci") {
52
+ flags.noSetupCi = true;
53
+ }
54
+ else if (arg === "--no-ci-sarif") {
55
+ flags.ciSarif = false;
56
+ }
57
+ else if (arg === "--force") {
58
+ flags.force = true;
59
+ }
60
+ else if (arg === "--campaign") {
61
+ const next = commandArgs[i + 1];
62
+ if (!next)
63
+ throw new Error("--campaign requires a campaign slug.");
64
+ flags.campaign = normalizeCampaign(next);
65
+ i += 1;
66
+ }
67
+ else if (arg === "--no-color") {
68
+ // Commander handles the color option; keep it out of the server command.
69
+ }
70
+ else if (arg === "--json") {
71
+ const next = commandArgs[i + 1];
72
+ if (!next)
73
+ throw new Error("--json requires an output file.");
74
+ flags.json = next;
75
+ i += 1;
76
+ }
77
+ else if (arg === "--mode") {
78
+ const next = commandArgs[i + 1];
79
+ if (!next)
80
+ throw new Error("--mode requires a value.");
81
+ flags.mode = next;
82
+ i += 1;
83
+ }
84
+ else if (arg === "--output") {
85
+ const next = commandArgs[i + 1];
86
+ if (!next)
87
+ throw new Error("--output requires an output file.");
88
+ flags.output = next;
89
+ i += 1;
90
+ }
91
+ else if (arg === "--sarif") {
92
+ const next = commandArgs[i + 1];
93
+ if (!next)
94
+ throw new Error("--sarif requires an output file.");
95
+ flags.sarif = next;
96
+ i += 1;
97
+ }
98
+ else {
99
+ targetArgs.push(arg);
100
+ }
101
+ }
102
+ return { commandArgs: targetArgs, flags };
103
+ }
104
+ async function readBaseline(path) {
105
+ if (!path)
106
+ return undefined;
107
+ return validateRunArtifact(JSON.parse(await readFile(path, "utf8")));
108
+ }
109
+ function reproductionCommand(options, commandArgs) {
110
+ const parts = ["npx @kryptosai/mcp-observatory", "attack-sim"];
111
+ if (options.target)
112
+ parts.push("--target", quoteShell(options.target));
113
+ if (options.baseline)
114
+ parts.push("--baseline", quoteShell(options.baseline));
115
+ if (!options.target && commandArgs.length > 0)
116
+ parts.push(...commandArgs.map(quoteShell));
117
+ return parts.join(" ");
118
+ }
119
+ function topAttackFindings(artifact) {
120
+ const severityRank = { high: 3, medium: 2, low: 1, info: 0 };
121
+ return extractObservatoryFindings(artifact)
122
+ .filter((finding) => finding.checkId === "attack-sim")
123
+ .sort((a, b) => severityRank[b.severity] - severityRank[a.severity])
124
+ .slice(0, 3);
125
+ }
126
+ export function registerAttackSimCommands(program) {
127
+ program
128
+ .command("attack-sim")
129
+ .passThroughOptions()
130
+ .description("Run safe MCP attack-readiness simulations for Safety Index evidence.")
131
+ .argument("[command...]", "Server command and arguments to run.")
132
+ .option("--target <config>", "Path to a target config JSON file.")
133
+ .option("--baseline <artifact>", "Baseline run artifact for contract drift simulation.")
134
+ .option("--output <file>", "Write the attack simulation Markdown report.")
135
+ .option("--json <file>", "Write the run artifact with attack-sim evidence.")
136
+ .option("--sarif <file>", "Write attack-sim findings as SARIF for GitHub Code Scanning.")
137
+ .option("--mode <mode>", "Simulation mode. Only 'safe' is supported.", "safe")
138
+ .option("--fail-on-high", "Exit nonzero when high-risk attack findings exist.", false)
139
+ .option("--setup-ci", "Offer CI conversion after a successful simulation; use with --yes in non-interactive runs to write files.", false)
140
+ .option("--yes", "Confirm CI conversion without prompting. Only writes when used with --setup-ci.", false)
141
+ .option("--no-setup-ci", "Suppress the post-success CI conversion prompt and hint.")
142
+ .option("--no-ci-sarif", "Generate post-check CI without GitHub Code Scanning SARIF upload.")
143
+ .option("--force", "Overwrite existing generated CI adoption files.", false)
144
+ .option("--campaign <slug>", "Attach a safe campaign/source slug to telemetry for attribution.")
145
+ .option("--no-color", "Disable colored output.")
146
+ .action(async (commandArgs, options) => {
147
+ const extracted = extractTrailingAttackFlags(commandArgs, options);
148
+ commandArgs = extracted.commandArgs;
149
+ options = extracted.flags;
150
+ if (options.campaign)
151
+ options.campaign = normalizeCampaign(options.campaign);
152
+ if (options.mode !== "safe") {
153
+ throw new Error("attack-sim supports only --mode safe.");
154
+ }
155
+ const startedAt = Date.now();
156
+ if (!options.target && commandArgs.length === 0) {
157
+ throw new Error("Provide --target <config.json> or use: mcp-observatory attack-sim <command> [args...]");
158
+ }
159
+ const target = options.target ? await resolveTarget({ target: options.target }) : targetFromCommand(commandArgs);
160
+ const baseline = await readBaseline(options.baseline);
161
+ process.stdout.write(` ${c(ANSI.dim, "⟳")} Running safe attack simulation for ${c(ANSI.bold, target.targetId)}...`);
162
+ const artifact = await runTarget(target, {
163
+ attackSimulation: { baseline },
164
+ securityCheck: true,
165
+ });
166
+ const repro = reproductionCommand(options, commandArgs);
167
+ const attackCheck = artifact.checks.find((check) => check.id === "attack-sim");
168
+ const findings = topAttackFindings(artifact);
169
+ const highCount = extractObservatoryFindings(artifact)
170
+ .filter((finding) => finding.checkId === "attack-sim" && finding.severity === "high").length;
171
+ const icon = attackCheck?.status === "fail" ? c(ANSI.red, "✗") : attackCheck?.status === "partial" ? c(ANSI.yellow, "!") : c(ANSI.green, "✓");
172
+ process.stdout.write(`\r ${icon} ${c(ANSI.bold, target.targetId)} attack-sim: ${attackCheck?.status ?? "skipped"}${" ".repeat(12)}\n`);
173
+ if (attackCheck) {
174
+ process.stdout.write(` ${attackCheck.message}\n`);
175
+ }
176
+ for (const finding of findings) {
177
+ process.stdout.write(` ${c(ANSI.dim, "→")} [${finding.severity}] ${finding.message}\n`);
178
+ }
179
+ process.stdout.write(` ${c(ANSI.dim, "→")} ${renderActionReceipt(artifact).split("\n")[0]}\n`);
180
+ process.stdout.write(`\n ${c(ANSI.bold, "Reproduce:")} ${c(ANSI.cyan, repro)}\n\n`);
181
+ if (options.json) {
182
+ await writeOutput(JSON.stringify(artifact, null, 2), "json", options.json);
183
+ }
184
+ if (options.output) {
185
+ await writeOutput(renderAttackSimulationMarkdown(artifact, repro), "markdown", options.output);
186
+ }
187
+ if (options.sarif) {
188
+ await writeOutput(renderSarif(artifact, { artifactUri: options.json }), "sarif", options.sarif);
189
+ }
190
+ recordEvent(buildEvent("command_complete", "attack-sim", "cli", {
191
+ targetIds: [target.targetId],
192
+ gateResult: attackCheck?.status ?? "skipped",
193
+ securityFindingCount: attackCheck?.evidence[0]?.itemCount ?? 0,
194
+ checkStatuses: attackCheck ? { "attack-sim": attackCheck.status } : undefined,
195
+ executionMs: Date.now() - startedAt,
196
+ campaign: options.campaign,
197
+ }));
198
+ if (artifact.gate === "pass") {
199
+ await maybeConvertPassingCheckToCi({
200
+ artifact,
201
+ bin: getBinName(),
202
+ target,
203
+ targetPath: options.target,
204
+ setupCi: options.setupCi,
205
+ yes: options.yes,
206
+ noSetupCi: options.noSetupCi,
207
+ ciSarif: options.ciSarif,
208
+ force: options.force,
209
+ campaign: options.campaign,
210
+ });
211
+ }
212
+ else if (highCount > 0) {
213
+ maybePrintCloudCta("security");
214
+ }
215
+ if (options.failOnHigh && highCount > 0) {
216
+ process.exitCode = 1;
217
+ }
218
+ });
219
+ }
220
+ //# sourceMappingURL=attack-sim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attack-sim.js","sourceRoot":"","sources":["../../../src/commands/attack-sim.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerAuditCommands(program: Command): void;
@@ -0,0 +1,132 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { auditScore, renderAuditMarkdown, renderAuditSarif, resolveAuditTarget, runAudit, } from "../audit.js";
4
+ import { buildMcpReceipt, receiptFormatFromPath, renderReceipt } from "../receipt.js";
5
+ import { buildEvent, recordEvent } from "../telemetry.js";
6
+ import { ANSI, c } from "./helpers.js";
7
+ function extractTrailingAuditFlags(args, options) {
8
+ const targetArgs = [];
9
+ const nextOptions = { ...options };
10
+ for (let i = 0; i < args.length; i += 1) {
11
+ const arg = args[i];
12
+ if (arg === "--profile") {
13
+ const next = args[i + 1];
14
+ if (!next)
15
+ throw new Error("--profile requires a value.");
16
+ nextOptions.profile = next;
17
+ i += 1;
18
+ }
19
+ else if (arg === "--format") {
20
+ const next = args[i + 1];
21
+ if (!next)
22
+ throw new Error("--format requires a value.");
23
+ nextOptions.format = next;
24
+ i += 1;
25
+ }
26
+ else if (arg === "--output") {
27
+ const next = args[i + 1];
28
+ if (!next)
29
+ throw new Error("--output requires a value.");
30
+ nextOptions.output = next;
31
+ i += 1;
32
+ }
33
+ else if (arg === "--receipt") {
34
+ const next = args[i + 1];
35
+ if (!next)
36
+ throw new Error("--receipt requires a value.");
37
+ nextOptions.receipt = next;
38
+ i += 1;
39
+ }
40
+ else if (arg === "--fail-on-high") {
41
+ nextOptions.failOnHigh = true;
42
+ }
43
+ else if (arg === "--fail-on-critical") {
44
+ nextOptions.failOnCritical = true;
45
+ }
46
+ else if (arg === "--no-color") {
47
+ // Commander handles color globally; keep it out of the target command.
48
+ }
49
+ else {
50
+ targetArgs.push(arg);
51
+ }
52
+ }
53
+ return { targetArgs, options: nextOptions };
54
+ }
55
+ async function writeMaybe(filePath, content) {
56
+ if (!filePath) {
57
+ process.stdout.write(`${content}\n`);
58
+ return;
59
+ }
60
+ await mkdir(path.dirname(filePath), { recursive: true });
61
+ await writeFile(filePath, `${content}\n`, "utf8");
62
+ process.stdout.write(`Wrote audit ${path.extname(filePath).slice(1) || "report"} to ${filePath}\n`);
63
+ }
64
+ export function registerAuditCommands(program) {
65
+ program
66
+ .command("audit")
67
+ .passThroughOptions()
68
+ .description("Run a profile-mapped MCP security audit.")
69
+ .argument("<target...>", "Target directory/config path or server command.")
70
+ .option("--profile <profile>", "Security profile to apply.", "nsa-mcp")
71
+ .option("--format <format>", "markdown, json, or sarif.", "markdown")
72
+ .option("--output <file>", "Write report to a file instead of stdout.")
73
+ .option("--receipt <file>", "Also write a portable MCP receipt (.json or .md).")
74
+ .option("--fail-on-high", "Exit nonzero when high or critical findings are present.", false)
75
+ .option("--fail-on-critical", "Exit nonzero when critical findings are present.", false)
76
+ .option("--no-color", "Disable colored output.")
77
+ .action(async (targetArgs, options) => {
78
+ const extracted = extractTrailingAuditFlags(targetArgs, options);
79
+ targetArgs = extracted.targetArgs;
80
+ options = extracted.options;
81
+ const startedAt = Date.now();
82
+ const target = await resolveAuditTarget(targetArgs);
83
+ if (options.output) {
84
+ process.stdout.write(`${c(ANSI.dim, "⟳")} Auditing ${c(ANSI.bold, target.targetId)} with profile ${c(ANSI.bold, options.profile)}...\n`);
85
+ }
86
+ const report = await runAudit(target, options.profile);
87
+ const format = options.format;
88
+ if (format === "json") {
89
+ await writeMaybe(options.output, JSON.stringify(report, null, 2));
90
+ }
91
+ else if (format === "sarif") {
92
+ await writeMaybe(options.output, renderAuditSarif(report, options.output ? path.basename(options.output).replace(/\.sarif$/i, ".json") : "mcp-observatory-audit.json"));
93
+ }
94
+ else if (format === "markdown") {
95
+ await writeMaybe(options.output, renderAuditMarkdown(report));
96
+ }
97
+ else {
98
+ throw new Error("Unsupported audit format. Use markdown, json, or sarif.");
99
+ }
100
+ if (options.receipt) {
101
+ const receipt = await buildMcpReceipt(report, target, {
102
+ commandInvoked: `mcp-observatory audit ${targetArgs.join(" ")} --profile ${options.profile} --format ${format}${options.output ? ` --output ${options.output}` : ""} --receipt ${options.receipt}`,
103
+ jsonReportPath: format === "json" ? options.output : undefined,
104
+ markdownReportPath: format === "markdown" ? options.output : undefined,
105
+ sarifPath: format === "sarif" ? options.output : undefined,
106
+ });
107
+ const receiptFormat = receiptFormatFromPath(options.receipt, "json");
108
+ await writeMaybe(options.receipt, renderReceipt(receipt, receiptFormat));
109
+ }
110
+ if (options.output) {
111
+ const score = auditScore(report);
112
+ process.stdout.write(`Trust status: ${score.status} (${score.score}/100), findings: ${score.finding_count}\n`);
113
+ }
114
+ recordEvent(buildEvent("command_complete", "audit", "cli", {
115
+ serversScanned: 1,
116
+ gateResult: report.summary.trust_status,
117
+ executionMs: Date.now() - startedAt,
118
+ securityFlag: true,
119
+ securityFindingCount: report.summary.finding_count,
120
+ targetIds: [target.targetId],
121
+ checkStatuses: Object.fromEntries(report.artifact.checks.map((check) => [check.id, check.status])),
122
+ receiptGenerated: Boolean(options.receipt),
123
+ receiptFormat: options.receipt ? receiptFormatFromPath(options.receipt, "json") : undefined,
124
+ receiptProfile: options.profile,
125
+ }));
126
+ if ((options.failOnCritical === true && report.summary.severity_counts.critical > 0) ||
127
+ (options.failOnHigh === true && (report.summary.severity_counts.critical > 0 || report.summary.severity_counts.high > 0))) {
128
+ process.exitCode = 1;
129
+ }
130
+ });
131
+ }
132
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../src/commands/audit.ts"],"names":[],"mappings":"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"}
@@ -12,11 +12,14 @@ export interface InitCiOptions {
12
12
  commentOnPr?: boolean;
13
13
  setStatus?: boolean;
14
14
  sarif?: boolean;
15
+ schedule?: string | boolean;
15
16
  actionRef?: string;
16
17
  all?: boolean;
17
18
  force?: boolean;
18
19
  doctor?: boolean;
20
+ fix?: boolean;
19
21
  fromLastRun?: boolean;
22
+ campaign?: string;
20
23
  }
21
24
  export interface InitCiResult {
22
25
  workflowStatus: string;
@@ -1,7 +1,8 @@
1
1
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { buildEvent, recordEvent } from "../telemetry.js";
3
+ import { buildEvent, normalizeCampaign, recordEvent } from "../telemetry.js";
4
4
  import { defaultRunsDirectory, findLatestSuccessfulRunArtifact, readArtifact } from "../storage.js";
5
+ import { TOOL_VERSION } from "../version.js";
5
6
  import { quoteShell } from "./helpers.js";
6
7
  const DEFAULT_WORKFLOW_PATH = ".github/workflows/mcp-observatory.yml";
7
8
  const DEFAULT_BADGE_PATH = "docs/mcp-observatory-badge.md";
@@ -9,7 +10,8 @@ const DEFAULT_TARGET_CONFIG_PATH = "mcp-observatory.target.json";
9
10
  const DEFAULT_PR_BODY_PATH = "docs/mcp-observatory-pr-body.md";
10
11
  const DEFAULT_ISSUE_BODY_PATH = "docs/mcp-observatory-issue.md";
11
12
  const DEFAULT_SCORE_BADGE_PATH = "docs/mcp-observatory-score-badge.md";
12
- const DEFAULT_ACTION_REF = "v0.26.1";
13
+ const DEFAULT_ACTION_REF = `v${TOOL_VERSION}`;
14
+ const DEFAULT_WEEKLY_CRON = "0 9 * * 1";
13
15
  async function exists(filePath) {
14
16
  try {
15
17
  await access(filePath);
@@ -19,12 +21,23 @@ async function exists(filePath) {
19
21
  return false;
20
22
  }
21
23
  }
24
+ function normalizeSchedule(schedule) {
25
+ if (schedule === undefined || schedule === false)
26
+ return undefined;
27
+ if (schedule === true || schedule === "weekly")
28
+ return DEFAULT_WEEKLY_CRON;
29
+ if (schedule === "daily")
30
+ return "0 9 * * *";
31
+ const value = schedule.trim();
32
+ return value.length > 0 ? value : DEFAULT_WEEKLY_CRON;
33
+ }
22
34
  function workflowYaml(options) {
23
35
  const command = options.command?.trim();
24
36
  const target = options.target?.trim();
25
37
  const commentsEnabled = options.commentOnPr === true;
26
38
  const statusEnabled = options.setStatus === true;
27
39
  const sarifEnabled = options.sarif === true;
40
+ const schedule = normalizeSchedule(options.schedule);
28
41
  const actionRef = options.actionRef?.trim() || DEFAULT_ACTION_REF;
29
42
  const lines = [
30
43
  "name: MCP Observatory",
@@ -33,10 +46,11 @@ function workflowYaml(options) {
33
46
  " pull_request:",
34
47
  " push:",
35
48
  " branches: [main]",
36
- "",
37
- "permissions:",
38
- " contents: read",
39
49
  ];
50
+ if (schedule) {
51
+ lines.push(" schedule:", ` - cron: ${JSON.stringify(schedule)}`);
52
+ }
53
+ lines.push("", "permissions:", " contents: read");
40
54
  if (commentsEnabled)
41
55
  lines.push(" pull-requests: write");
42
56
  if (statusEnabled)
@@ -206,17 +220,42 @@ function checkFile(id, label, filePath, content, expectedText) {
206
220
  }
207
221
  function setupCommand(options) {
208
222
  const sarif = options.sarif ? " --sarif" : "";
223
+ const schedule = normalizeSchedule(options.schedule)
224
+ ? ` --schedule ${quoteShell(String(options.schedule === true ? "weekly" : options.schedule))}`
225
+ : "";
209
226
  if (options.target)
210
- return `npx @kryptosai/mcp-observatory setup-ci --all --target ${options.target}${sarif}`;
227
+ return `npx @kryptosai/mcp-observatory setup-ci --all --target ${options.target}${sarif}${schedule}`;
211
228
  if (options.command)
212
- return `npx @kryptosai/mcp-observatory setup-ci --all --command "${options.command.replaceAll("\"", "\\\"")}"${sarif}`;
213
- return `npx @kryptosai/mcp-observatory setup-ci --all --command "npx -y <server-package>"${sarif}`;
229
+ return `npx @kryptosai/mcp-observatory setup-ci --all --command "${options.command.replaceAll("\"", "\\\"")}"${sarif}${schedule}`;
230
+ return `npx @kryptosai/mcp-observatory setup-ci --all --command "npx -y <server-package>"${sarif}${schedule}`;
214
231
  }
215
- function initCiOptionsFromLastRunArtifact(artifact, force, sarif) {
232
+ function initCiOptionsFromLastRunArtifact(artifact, force, sarif, schedule) {
216
233
  if (artifact.target.adapter !== "local-process")
217
234
  return undefined;
218
235
  const command = [artifact.target.command, ...artifact.target.args].map(quoteShell).join(" ");
219
- return { all: true, command, force, sarif };
236
+ return { all: true, command, force, sarif, schedule };
237
+ }
238
+ function inferWorkflowTargetOptions(workflow) {
239
+ const target = workflow?.match(/(^|\n)\s+target:\s+(.+)/)?.[2]?.trim();
240
+ if (target)
241
+ return { target };
242
+ const command = workflow?.match(/(^|\n)\s+command:\s+(.+)/)?.[2]?.trim();
243
+ if (command)
244
+ return { command };
245
+ return {};
246
+ }
247
+ function doctorFixOptions(options, workflow) {
248
+ const inferred = options.command || options.target ? {} : inferWorkflowTargetOptions(workflow);
249
+ return {
250
+ ...options,
251
+ ...inferred,
252
+ all: true,
253
+ force: true,
254
+ sarif: true,
255
+ schedule: options.schedule ?? "weekly",
256
+ doctor: false,
257
+ fix: false,
258
+ };
220
259
  }
221
260
  export async function doctorSetupCi(options = {}) {
222
261
  const workflowPath = options.workflow ?? DEFAULT_WORKFLOW_PATH;
@@ -364,14 +403,19 @@ function addInitCiOptions(command) {
364
403
  .option("--comment-on-pr", "Allow the generated workflow to post PR comments. This adds pull-requests: write permission.", false)
365
404
  .option("--set-status", "Allow the generated workflow to set commit statuses. This adds statuses: write permission.", false)
366
405
  .option("--sarif", "Upload normalized findings to GitHub Code Scanning. This adds security-events: write permission.", false)
406
+ .option("--schedule [cadence]", "Also run the workflow on a schedule: weekly, daily, or a cron expression.")
367
407
  .option("--action-ref <ref>", "Git ref for KryptosAI/mcp-observatory/action. Use a full commit SHA for strict third-party action pinning.", DEFAULT_ACTION_REF)
368
408
  .option("--all", "Write the full adoption kit: workflow, badge, target config, PR body, issue body, and score badge instructions.", false)
369
409
  .option("--force", "Overwrite existing files.", false)
370
410
  .option("--doctor", "Inspect the current repository's MCP Observatory CI adoption state.", false)
371
- .option("--from-last-run", "Generate the adoption kit from the latest successful local run artifact.", false);
411
+ .option("--fix", "With --doctor, repair the adoption kit with deep, security, SARIF, and weekly scheduled checks.", false)
412
+ .option("--from-last-run", "Generate the adoption kit from the latest successful local run artifact.", false)
413
+ .option("--campaign <slug>", "Attach a safe campaign/source slug to telemetry for attribution.");
372
414
  }
373
415
  function initCiAction(commandName) {
374
416
  return async (options) => {
417
+ if (options.campaign)
418
+ options.campaign = normalizeCampaign(options.campaign);
375
419
  if (options.doctor) {
376
420
  const result = await doctorSetupCi(options);
377
421
  process.stdout.write("MCP Observatory CI doctor\n\n");
@@ -382,14 +426,34 @@ function initCiAction(commandName) {
382
426
  process.stdout.write(` fix: ${check.fix}\n`);
383
427
  }
384
428
  process.stdout.write(`\nNext best action:\n ${result.nextCommand}\n`);
385
- if (!result.ready)
429
+ if (options.fix) {
430
+ const workflow = await readOptional(options.workflow ?? DEFAULT_WORKFLOW_PATH);
431
+ const fixed = await initCi(doctorFixOptions(options, workflow));
432
+ process.stdout.write("\nApplied repair:\n");
433
+ process.stdout.write(`${fixed.workflowStatus}: ${fixed.workflowPath}\n`);
434
+ if (fixed.badgePath && fixed.badgeStatus)
435
+ process.stdout.write(`${fixed.badgeStatus}: ${fixed.badgePath}\n`);
436
+ if (fixed.targetConfigPath && fixed.targetConfigStatus)
437
+ process.stdout.write(`${fixed.targetConfigStatus}: ${fixed.targetConfigPath}\n`);
438
+ if (fixed.prBodyPath && fixed.prBodyStatus)
439
+ process.stdout.write(`${fixed.prBodyStatus}: ${fixed.prBodyPath}\n`);
440
+ if (fixed.issueBodyPath && fixed.issueBodyStatus)
441
+ process.stdout.write(`${fixed.issueBodyStatus}: ${fixed.issueBodyPath}\n`);
442
+ if (fixed.scoreBadgePath && fixed.scoreBadgeStatus)
443
+ process.stdout.write(`${fixed.scoreBadgeStatus}: ${fixed.scoreBadgePath}\n`);
444
+ process.stdout.write("\nAutomated checks: pull requests, pushes to main, and weekly scheduled runs.\n");
445
+ }
446
+ else if (!result.ready) {
386
447
  process.exitCode = 1;
448
+ }
387
449
  recordEvent(buildEvent("command_complete", commandName, "cli", {
388
450
  ciProvider: "github-actions",
389
451
  setupCiDoctor: true,
390
452
  setupCiReady: result.ready,
391
453
  setupCiFailCount: result.checks.filter((check) => check.status === "fail").length,
392
454
  setupCiWarnCount: result.checks.filter((check) => check.status === "warn").length,
455
+ setupCiFixApplied: options.fix === true,
456
+ campaign: options.campaign,
393
457
  }));
394
458
  return;
395
459
  }
@@ -405,7 +469,7 @@ function initCiAction(commandName) {
405
469
  if (artifact.artifactType !== "run") {
406
470
  throw new Error(`Latest artifact is not a run artifact: ${latestPath}`);
407
471
  }
408
- const fromRunOptions = initCiOptionsFromLastRunArtifact(artifact, options.force, options.sarif);
472
+ const fromRunOptions = initCiOptionsFromLastRunArtifact(artifact, options.force, options.sarif, options.schedule);
409
473
  if (!fromRunOptions) {
410
474
  throw new Error(`Latest successful run does not contain enough target information for setup-ci: ${latestPath}`);
411
475
  }
@@ -441,6 +505,7 @@ function initCiAction(commandName) {
441
505
  recordEvent(buildEvent("command_complete", commandName, "cli", {
442
506
  ciProvider: "github-actions",
443
507
  commitStatusSet: !skipped,
508
+ campaign: options.campaign,
444
509
  }));
445
510
  };
446
511
  }