securenow 8.12.2 → 8.12.4

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.
@@ -0,0 +1,82 @@
1
+ 'use strict';
2
+
3
+ // `securenow threat-model <category>` — print the copy-paste threat-modeling prompt for a category,
4
+ // fetched from the published set at securenow.ai (the same prompt shown on securenow.ai/threat-modeling).
5
+ // Save it and have your coding agent follow the file (prompts run to ~136 KB, over
6
+ // Linux's 128 KB single-argument limit, so `claude -p "$(...)"` fails):
7
+ // npx securenow threat-model authentication --out threat-prompt.md
8
+ // or pipe it on stdin: npx securenow threat-model authentication | claude -p
9
+ const fs = require('fs');
10
+ const ui = require('./ui');
11
+
12
+ const BASE = process.env.SECURENOW_THREAT_PROMPTS_URL || 'https://securenow.ai/threat-prompts';
13
+
14
+ // Published categories (slugs). Aliases map common shorthands to the slug.
15
+ const CATEGORIES = [
16
+ 'authentication', 'authorization', 'xss-csrf-cors', 'client-side-supply-chain', 'injection',
17
+ 'oauth-sso-integrations', 'admin-support-tools', 'payment-business-logic', 'file-upload-download',
18
+ 'messaging-notifications', 'rate-limits-and-abuse', 'legacy-endpoints', 'api-security', 'graphql-security',
19
+ 'webhooks', 'realtime-websocket-sse', 'serverless-and-edge', 'cloud-infrastructure', 'secrets-and-cloud-iam',
20
+ 'dns-tls-certificates', 'supply-chain-cicd', 'storage-and-logs', 'data-privacy-pii', 'ai-llm-features',
21
+ 'secrets-and-api-key-hygiene',
22
+ ];
23
+ const ALIASES = { auth: 'authentication', authz: 'authorization', oauth: 'oauth-sso-integrations', sso: 'oauth-sso-integrations', api: 'api-security', graphql: 'graphql-security', uploads: 'file-upload-download', upload: 'file-upload-download', xss: 'xss-csrf-cors', csrf: 'xss-csrf-cors', cors: 'xss-csrf-cors', rate: 'rate-limits-and-abuse', 'rate-limits': 'rate-limits-and-abuse', secrets: 'secrets-and-api-key-hygiene', privacy: 'data-privacy-pii', pii: 'data-privacy-pii', ai: 'ai-llm-features', llm: 'ai-llm-features' };
24
+
25
+ function resolveSlug(input) {
26
+ const raw = String(input || '').trim().toLowerCase().replace(/\.md$/, '').replace(/^\d+[-_]/, '');
27
+ if (!raw) return null;
28
+ if (CATEGORIES.includes(raw)) return raw;
29
+ if (ALIASES[raw]) return ALIASES[raw];
30
+ return null;
31
+ }
32
+
33
+ function listCategories() {
34
+ ui.heading('SecureNow threat-modeling prompts');
35
+ console.log(' Copy-paste a prompt into your coding agent, or run it with the SecureNow CLI.\n');
36
+ for (const slug of CATEGORIES) console.log(' ' + slug);
37
+ console.log('\n Print one: securenow threat-model authentication');
38
+ console.log(' Save it: securenow threat-model authentication --out threat-prompt.md');
39
+ console.log(' then tell your agent: "Follow threat-prompt.md"');
40
+ console.log(' Pipe it: securenow threat-model authentication | claude -p');
41
+ console.log(' On the web: securenow.ai/threat-modeling');
42
+ }
43
+
44
+ async function run(args, flags = {}) {
45
+ const category = args[0];
46
+ if (flags.list || (!category && !flags.all)) {
47
+ if (!category && !flags.list) ui.info('Pick a category (or --list to see them all):\n');
48
+ listCategories();
49
+ return;
50
+ }
51
+
52
+ const slug = resolveSlug(category);
53
+ if (!slug) {
54
+ ui.error(`Unknown category "${category}". Run "securenow threat-model --list" to see the ${CATEGORIES.length} categories.`);
55
+ process.exitCode = 1;
56
+ return;
57
+ }
58
+
59
+ const url = `${BASE}/${slug}.md`;
60
+ let text;
61
+ try {
62
+ const res = await fetch(url, { headers: { accept: 'text/markdown, text/plain' } });
63
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
64
+ text = await res.text();
65
+ } catch (err) {
66
+ ui.error(`Could not fetch the ${slug} prompt (${err.message}). Open securenow.ai/threat-modeling/${slug} in a browser instead.`);
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+
71
+ if (flags.out) {
72
+ fs.writeFileSync(flags.out, text);
73
+ ui.success(`Saved the ${slug} threat-model prompt to ${flags.out} (${text.length.toLocaleString()} chars).`);
74
+ ui.info('Open it with your coding agent at the root of a project that has the securenow SDK installed.');
75
+ return;
76
+ }
77
+
78
+ // Default: raw prompt to stdout so it pipes cleanly into an agent.
79
+ process.stdout.write(text.endsWith('\n') ? text : text + '\n');
80
+ }
81
+
82
+ module.exports = { run, resolveSlug, CATEGORIES, ALIASES };
package/cli.js CHANGED
@@ -671,6 +671,12 @@ const COMMANDS = {
671
671
  rawArgv: true,
672
672
  run: (rawArgs) => require('./cli/run').run(rawArgs),
673
673
  },
674
+ 'threat-model': {
675
+ desc: 'Print a copy-paste threat-modeling prompt for a category (pipe it into your coding agent)',
676
+ usage: 'securenow threat-model <authentication|authorization|…|--list> [--out prompt.md]',
677
+ flags: { list: 'List all threat-modeling categories', out: 'Write the prompt to a file instead of stdout' },
678
+ run: (a, f) => require('./cli/threatModel').run(a, f),
679
+ },
674
680
  redact: {
675
681
  desc: 'Redact sensitive fields and OTP codes from a JSON payload',
676
682
  usage: "securenow redact '<json>' [--fields f1,f2] [--json]",
@@ -822,7 +828,7 @@ function showHelp(commandName) {
822
828
  'Firewall': ['firewall'],
823
829
  'Remediation': ['automation', 'ratelimit', 'challenge', 'blocklist', 'revoke', 'allowlist', 'trusted'],
824
830
  'Telemetry': ['telemetry', 'log', 'event', 'test-span'],
825
- 'Utilities': ['redact', 'cidr', 'doctor', 'env', 'mcp'],
831
+ 'Utilities': ['threat-model', 'redact', 'cidr', 'doctor', 'env', 'mcp'],
826
832
  'Settings': ['instances', 'config', 'version'],
827
833
  };
828
834
 
package/mcp/catalog.js CHANGED
@@ -1852,6 +1852,54 @@ const TOOLS = [
1852
1852
  },
1853
1853
  ];
1854
1854
 
1855
+ // Annotation policy, matching how Claude's and ChatGPT's directory reviews read
1856
+ // the hints: a write is destructive when it removes or overwrites something,
1857
+ // or can stop production traffic or detection, even if it can be undone. Pure
1858
+ // record-keeping writes (reports, queue closures, read markers, dry runs) are
1859
+ // not. Only tools that reach arbitrary public entities are open-world.
1860
+ const DESTRUCTIVE_TOOLS = new Set([
1861
+ 'securenow_firewall_enable',
1862
+ 'securenow_firewall_disable',
1863
+ 'securenow_firewall_set_threshold',
1864
+ 'securenow_human_action_block',
1865
+ 'securenow_human_action_false_positive',
1866
+ 'securenow_human_case_action_update',
1867
+ 'securenow_automation_defaults_ensure',
1868
+ 'securenow_automation_rule_create',
1869
+ 'securenow_automation_rule_update',
1870
+ 'securenow_automation_rule_execute',
1871
+ 'securenow_automation_rule_delete',
1872
+ 'securenow_rate_limit_remove',
1873
+ 'securenow_rate_limit_create_from_text',
1874
+ 'securenow_alert_rule_rollback',
1875
+ 'securenow_alert_rule_update',
1876
+ 'securenow_alert_rule_query_update',
1877
+ 'securenow_alert_rule_instant_update',
1878
+ 'securenow_alert_rule_condition_update',
1879
+ 'securenow_alert_rule_exclusion_add',
1880
+ 'securenow_alert_rule_exclusion_remove',
1881
+ 'securenow_blocklist_pending_approve',
1882
+ 'securenow_blocklist_pending_reject',
1883
+ 'securenow_blocklist_pending_bulk_approve',
1884
+ 'securenow_blocklist_pending_bulk_reject',
1885
+ 'securenow_blocklist_add',
1886
+ 'securenow_blocklist_remove',
1887
+ 'securenow_blocklist_unblock',
1888
+ 'securenow_allowlist_add',
1889
+ 'securenow_allowlist_remove',
1890
+ 'securenow_trusted_add',
1891
+ 'securenow_trusted_remove',
1892
+ ]);
1893
+
1894
+ const OPEN_WORLD_TOOLS = new Set([
1895
+ 'securenow_ip_lookup', // reputation of any public IP address
1896
+ ]);
1897
+
1898
+ for (const tool of TOOLS) {
1899
+ if (DESTRUCTIVE_TOOLS.has(tool.name)) tool.destructive = true;
1900
+ tool.openWorld = OPEN_WORLD_TOOLS.has(tool.name);
1901
+ }
1902
+
1855
1903
  const RESOURCES = [
1856
1904
  {
1857
1905
  uri: 'securenow://docs/skill-api',
@@ -2247,10 +2295,11 @@ function mcpToolDefinition(tool) {
2247
2295
  inputSchema: tool.inputSchema || objectSchema({}),
2248
2296
  annotations: {
2249
2297
  readOnlyHint: !!tool.readOnly,
2250
- destructiveHint: !!tool.destructive,
2298
+ destructiveHint: !tool.readOnly && !!tool.destructive,
2251
2299
  idempotentHint: !!tool.readOnly,
2252
- },
2253
- };
2300
+ openWorldHint: !!tool.openWorld,
2301
+ },
2302
+ };
2254
2303
  }
2255
2304
 
2256
2305
  function listTools() {
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "securenow",
3
- "version": "8.12.2",
3
+ "version": "8.12.4",
4
+ "mcpName": "ai.securenow/securenow",
4
5
  "description": "OpenTelemetry instrumentation for Node.js, Next.js, and Nuxt - Send traces and logs to any OTLP-compatible backend",
5
6
  "type": "commonjs",
6
7
  "main": "register.js",