@blamejs/core 0.8.24 → 0.8.25

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/CHANGELOG.md CHANGED
Binary file
package/index.js CHANGED
@@ -101,6 +101,7 @@ var aiInput = require("./lib/ai-input");
101
101
  var a2a = require("./lib/a2a");
102
102
  var darkPatterns = require("./lib/dark-patterns");
103
103
  var budr = require("./lib/budr");
104
+ var secCyber = require("./lib/sec-cyber");
104
105
  var safeUrl = require("./lib/safe-url");
105
106
  var safeRedirect = require("./lib/safe-redirect");
106
107
  var pick = require("./lib/pick");
@@ -289,6 +290,7 @@ module.exports = {
289
290
  a2a: a2a,
290
291
  darkPatterns: darkPatterns,
291
292
  budr: budr,
293
+ secCyber: secCyber,
292
294
  safeUrl: safeUrl,
293
295
  safeRedirect: safeRedirect,
294
296
  pick: pick,
package/lib/audit.js CHANGED
@@ -239,6 +239,7 @@ var FRAMEWORK_NAMESPACES = [
239
239
  "a2a", // b.a2a (a2a.card_signed / verified / rejected)
240
240
  "darkpatterns", // b.darkPatterns (darkPatterns.attest / cancel-blocked)
241
241
  "budr", // b.budr (budr.declared)
242
+ "seccyber", // b.secCyber (seccyber.eight_k_artifact)
242
243
  ];
243
244
  var registeredNamespaces = new Set(FRAMEWORK_NAMESPACES);
244
245
 
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ /**
3
+ * b.secCyber — SEC Cybersecurity Disclosure Item 1.05 (Form 8-K)
4
+ * artifact generator.
5
+ *
6
+ * Required by 17 CFR §229.106 / Form 8-K Item 1.05 (final rule
7
+ * effective 2023-12-18). When a registrant determines that a
8
+ * cybersecurity incident is material, it MUST file a Form 8-K within
9
+ * 4 business days of the materiality determination, describing:
10
+ *
11
+ * - The material aspects of the nature, scope, and timing
12
+ * - The material impact or reasonably likely material impact on
13
+ * the registrant (financial condition + results of operations)
14
+ *
15
+ * Materiality determination MUST be made "without unreasonable
16
+ * delay." The Attorney General can authorize a delay (when public
17
+ * disclosure would pose substantial risk to national security or
18
+ * public safety) — registrant requests the delay before the 4-day
19
+ * window elapses.
20
+ *
21
+ * The framework can't decide materiality (that's a fact-and-circum-
22
+ * stances judgment). What it CAN do:
23
+ *
24
+ * - Structure the operator's materiality finding into a
25
+ * tamper-evident audit-chain row (the regulator-facing record).
26
+ * - Generate the 8-K Item 1.05 narrative skeleton with the
27
+ * operator's content slotted in.
28
+ * - Compute the 4-business-day deadline so the operator's
29
+ * filing-system gate refuses to slip past it.
30
+ * - Emit an AG-delay-request artifact when the operator asserts
31
+ * national-security / public-safety risk.
32
+ *
33
+ * Public API:
34
+ *
35
+ * b.secCyber.eightKArtifact(opts) -> { artifact, deadline, audit }
36
+ * opts:
37
+ * incidentId: operator-supplied incident reference (string).
38
+ * registrant: { name, cik, filer }
39
+ * detectedAt: Unix-ms when the incident was detected.
40
+ * materialityDeterminedAt: Unix-ms when materiality was determined.
41
+ * materialityFinding: "material" | "not-material" | "pending".
42
+ * materialityReasoning: operator-provided narrative
43
+ * explaining the materiality call.
44
+ * nature: string describing the incident's nature.
45
+ * scope: string describing the scope.
46
+ * timing: string describing the timing.
47
+ * impact: string describing material/likely-material
48
+ * impact on financial condition + operations.
49
+ * agDelayRequested: bool. When true, the artifact includes the
50
+ * AG-delay-request template and the 4-day
51
+ * deadline is suspended pending DOJ response.
52
+ * agDelayJustification: string explaining the national-security
53
+ * / public-safety risk that justifies delay
54
+ * (REQUIRED when agDelayRequested = true).
55
+ * audit: bool, default true.
56
+ *
57
+ * Returns:
58
+ * artifact: structured 8-K Item 1.05 content (markdown
59
+ * + JSON for downstream EDGAR filing).
60
+ * deadline: Unix-ms 4-business-day deadline (null when
61
+ * AG-delay-requested).
62
+ * deadlineBusinessDays: business-day count (4 by default; spec
63
+ * gives no exception).
64
+ *
65
+ * The framework does NOT submit to EDGAR — operators wire the
66
+ * artifact into their existing filer-attorney workflow.
67
+ */
68
+
69
+ var audit = require("./audit");
70
+ var C = require("./constants");
71
+ var validateOpts = require("./validate-opts");
72
+ var nb = require("./numeric-bounds");
73
+ var { defineClass } = require("./framework-error");
74
+ var SecCyberError = defineClass("SecCyberError", { alwaysPermanent: true });
75
+
76
+ var FINDINGS = ["material", "not-material", "pending"];
77
+
78
+ function _addBusinessDays(startMs, days) {
79
+ // Walk forward N business days (Mon-Fri). Doesn't honor US federal
80
+ // holidays — operators with a calendar-aware filing system override
81
+ // by reading deadlineBusinessDays and computing themselves.
82
+ var t = new Date(startMs);
83
+ var added = 0;
84
+ while (added < days) {
85
+ t = new Date(t.getTime() + C.TIME.days(1));
86
+ var dow = t.getUTCDay();
87
+ if (dow !== 0 && dow !== 6) added += 1;
88
+ }
89
+ return t.getTime();
90
+ }
91
+
92
+ function eightKArtifact(opts) {
93
+ if (!opts || typeof opts !== "object") {
94
+ throw SecCyberError.factory("BAD_OPTS",
95
+ "secCyber.eightKArtifact: opts required");
96
+ }
97
+ validateOpts.requireNonEmptyString(opts.incidentId,
98
+ "secCyber.eightKArtifact: incidentId", SecCyberError, "BAD_INCIDENT_ID");
99
+ if (!opts.registrant || typeof opts.registrant !== "object") {
100
+ throw SecCyberError.factory("BAD_REGISTRANT",
101
+ "secCyber.eightKArtifact: registrant object required");
102
+ }
103
+ validateOpts.requireNonEmptyString(opts.registrant.name,
104
+ "secCyber.eightKArtifact: registrant.name", SecCyberError, "BAD_REGISTRANT_NAME");
105
+ validateOpts.requireNonEmptyString(opts.registrant.cik,
106
+ "secCyber.eightKArtifact: registrant.cik", SecCyberError, "BAD_CIK");
107
+ nb.requirePositiveFiniteIntIfPresent(opts.detectedAt,
108
+ "secCyber.eightKArtifact: detectedAt", SecCyberError, "BAD_DETECTED_AT");
109
+ nb.requirePositiveFiniteIntIfPresent(opts.materialityDeterminedAt,
110
+ "secCyber.eightKArtifact: materialityDeterminedAt", SecCyberError, "BAD_MAT_AT");
111
+
112
+ if (FINDINGS.indexOf(opts.materialityFinding) === -1) {
113
+ throw SecCyberError.factory("BAD_FINDING",
114
+ "secCyber.eightKArtifact: materialityFinding must be one of " + FINDINGS.join(", "));
115
+ }
116
+ validateOpts.requireNonEmptyString(opts.materialityReasoning,
117
+ "secCyber.eightKArtifact: materialityReasoning", SecCyberError, "BAD_REASONING");
118
+
119
+ if (opts.materialityFinding === "material") {
120
+ validateOpts.requireNonEmptyString(opts.nature,
121
+ "secCyber.eightKArtifact: nature", SecCyberError, "BAD_NATURE");
122
+ validateOpts.requireNonEmptyString(opts.scope,
123
+ "secCyber.eightKArtifact: scope", SecCyberError, "BAD_SCOPE");
124
+ validateOpts.requireNonEmptyString(opts.timing,
125
+ "secCyber.eightKArtifact: timing", SecCyberError, "BAD_TIMING");
126
+ validateOpts.requireNonEmptyString(opts.impact,
127
+ "secCyber.eightKArtifact: impact", SecCyberError, "BAD_IMPACT");
128
+ }
129
+
130
+ var agDelayRequested = opts.agDelayRequested === true;
131
+ if (agDelayRequested) {
132
+ validateOpts.requireNonEmptyString(opts.agDelayJustification,
133
+ "secCyber.eightKArtifact: agDelayJustification (required when agDelayRequested=true)",
134
+ SecCyberError, "BAD_AG_JUSTIFICATION");
135
+ }
136
+
137
+ var matAt = opts.materialityDeterminedAt || Date.now();
138
+ var deadline = agDelayRequested ? null : _addBusinessDays(matAt, 4);
139
+
140
+ var markdown = "# Form 8-K — Item 1.05 Material Cybersecurity Incident\n\n" +
141
+ "**Registrant:** " + opts.registrant.name + " (CIK: " + opts.registrant.cik + ")\n\n" +
142
+ "**Incident ID:** " + opts.incidentId + "\n\n" +
143
+ "**Materiality determination date:** " + new Date(matAt).toISOString() + "\n\n" +
144
+ "**Materiality finding:** " + opts.materialityFinding + "\n\n" +
145
+ "**Reasoning:**\n\n" + opts.materialityReasoning + "\n\n";
146
+
147
+ if (opts.materialityFinding === "material") {
148
+ markdown +=
149
+ "## Item 1.05(a) — Material aspects\n\n" +
150
+ "**Nature.** " + opts.nature + "\n\n" +
151
+ "**Scope.** " + opts.scope + "\n\n" +
152
+ "**Timing.** " + opts.timing + "\n\n" +
153
+ "## Item 1.05(b) — Material impact\n\n" + opts.impact + "\n\n";
154
+ }
155
+
156
+ if (agDelayRequested) {
157
+ markdown += "## AG-delay request (17 CFR §229.106(c)(1)(ii))\n\n" +
158
+ "Registrant asserts that disclosure of this incident would pose a substantial " +
159
+ "risk to national security or public safety. Pursuant to the rule, registrant " +
160
+ "requests that the Attorney General authorize a delay of disclosure.\n\n" +
161
+ "**Justification:** " + opts.agDelayJustification + "\n\n";
162
+ }
163
+
164
+ markdown += "**Filing deadline:** " +
165
+ (deadline ? new Date(deadline).toISOString() + " (4 business days from materiality determination)" :
166
+ "suspended pending DOJ response to AG-delay request") + "\n";
167
+
168
+ var artifactJson = {
169
+ form: "8-K",
170
+ item: "1.05",
171
+ incidentId: opts.incidentId,
172
+ registrant: { name: opts.registrant.name, cik: opts.registrant.cik },
173
+ detectedAt: opts.detectedAt || null,
174
+ materialityDeterminedAt: matAt,
175
+ materialityFinding: opts.materialityFinding,
176
+ materialityReasoning: opts.materialityReasoning,
177
+ items: opts.materialityFinding === "material" ? {
178
+ "1.05(a)": {
179
+ nature: opts.nature, scope: opts.scope, timing: opts.timing,
180
+ },
181
+ "1.05(b)": { impact: opts.impact },
182
+ } : null,
183
+ agDelayRequested: agDelayRequested,
184
+ agDelayJustification: agDelayRequested ? opts.agDelayJustification : null,
185
+ deadlineMs: deadline,
186
+ };
187
+
188
+ if (opts.audit !== false) {
189
+ audit.safeEmit({
190
+ action: "seccyber.eight_k_artifact",
191
+ outcome: "success",
192
+ metadata: {
193
+ incidentId: opts.incidentId,
194
+ registrant: opts.registrant.name,
195
+ cik: opts.registrant.cik,
196
+ materialityFinding: opts.materialityFinding,
197
+ deadlineMs: deadline,
198
+ agDelayRequested: agDelayRequested,
199
+ },
200
+ });
201
+ }
202
+
203
+ return {
204
+ artifact: { markdown: markdown, json: artifactJson },
205
+ deadline: deadline,
206
+ deadlineBusinessDays: agDelayRequested ? null : 4, // allow:raw-byte-literal — SEC Item 1.05 4-business-day deadline (17 CFR §229.106(c)(1))
207
+ };
208
+ }
209
+
210
+ module.exports = {
211
+ eightKArtifact: eightKArtifact,
212
+ FINDINGS: FINDINGS.slice(),
213
+ SecCyberError: SecCyberError,
214
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.8.24",
3
+ "version": "0.8.25",
4
4
  "description": "The Node framework that owns its stack.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:05943c33-3381-4aac-9f4b-b0f06a2a3caf",
5
+ "serialNumber": "urn:uuid:a6056d34-71d3-41f1-a99f-80454c5b2780",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-07T13:14:30.419Z",
8
+ "timestamp": "2026-05-07T13:31:44.359Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/core@0.8.24",
22
+ "bom-ref": "@blamejs/core@0.8.25",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.8.24",
25
+ "version": "0.8.25",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "The Node framework that owns its stack.",
29
- "purl": "pkg:npm/%40blamejs/core@0.8.24",
29
+ "purl": "pkg:npm/%40blamejs/core@0.8.25",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/core@0.8.24",
57
+ "ref": "@blamejs/core@0.8.25",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]