@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 +0 -0
- package/index.js +2 -0
- package/lib/audit.js +1 -0
- package/lib/sec-cyber.js +214 -0
- package/package.json +1 -1
- package/sbom.cyclonedx.json +6 -6
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
|
|
package/lib/sec-cyber.js
ADDED
|
@@ -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
package/sbom.cyclonedx.json
CHANGED
|
@@ -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:
|
|
5
|
+
"serialNumber": "urn:uuid:a6056d34-71d3-41f1-a99f-80454c5b2780",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-07T13:
|
|
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.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.8.25",
|
|
23
23
|
"type": "library",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.8.
|
|
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.
|
|
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.
|
|
57
|
+
"ref": "@blamejs/core@0.8.25",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|