@blamejs/core 0.8.39 → 0.8.41

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,116 @@
1
+ "use strict";
2
+ /**
3
+ * b.resourceAccessLock — three-mode access-lock for arbitrary
4
+ * resources (data exports, scheduled jobs, file paths, queue
5
+ * partitions). Different from b.auth.accessLock — that one gates
6
+ * HTTP request flow; this one gates non-HTTP-shaped operator
7
+ * actions. Both share the open / read-only / locked vocabulary.
8
+ *
9
+ * var exportLock = b.resourceAccessLock.create({
10
+ * resource: "data-export-jobs",
11
+ * startMode: "open",
12
+ * audit: b.audit,
13
+ * });
14
+ *
15
+ * if (!exportLock.permits("write")) {
16
+ * throw new b.resourceAccessLock.ResourceAccessLockError(
17
+ * "resource-access-lock/refused",
18
+ * "data export refused: lock mode is " + exportLock.mode());
19
+ * }
20
+ * await runExportJob();
21
+ *
22
+ * exportLock.set("locked", { actor: "alice", reason: "incident-42 freeze" });
23
+ *
24
+ * Mode semantics:
25
+ * open — every action permitted
26
+ * read-only — actions tagged "read" permitted; "write" refused
27
+ * locked — every action refused
28
+ *
29
+ * Audit shape:
30
+ * resourceaccesslock.mode_changed — {resource, from, to, actor, reason}
31
+ * resourceaccesslock.refused — {resource, action, mode, actor}
32
+ */
33
+
34
+ var lazyRequire = require("./lazy-require");
35
+ var validateOpts = require("./validate-opts");
36
+ var { defineClass } = require("./framework-error");
37
+
38
+ var audit = lazyRequire(function () { return require("./audit"); });
39
+
40
+ var ResourceAccessLockError = defineClass("ResourceAccessLockError",
41
+ { alwaysPermanent: true });
42
+
43
+ var VALID_MODES = Object.freeze({ open: 1, "read-only": 1, locked: 1 });
44
+ var READ_ACTIONS = Object.freeze({ read: 1, list: 1, get: 1, query: 1, "read-only": 1 });
45
+
46
+ function create(opts) {
47
+ opts = opts || {};
48
+ validateOpts(opts, ["resource", "startMode", "audit"], "resourceAccessLock.create");
49
+ validateOpts.requireNonEmptyString(opts.resource, "resource",
50
+ ResourceAccessLockError, "resource-access-lock/no-resource");
51
+ var startMode = opts.startMode || "open";
52
+ if (!VALID_MODES[startMode]) {
53
+ throw new ResourceAccessLockError(
54
+ "resource-access-lock/bad-start-mode",
55
+ "startMode must be one of: " + Object.keys(VALID_MODES).join(" / "));
56
+ }
57
+ var auditOn = opts.audit !== false;
58
+ var resource = opts.resource;
59
+ var mode = startMode;
60
+
61
+ function _emit(action, outcome, meta) {
62
+ if (!auditOn) return;
63
+ try {
64
+ audit().safeEmit({
65
+ action: action, outcome: outcome,
66
+ metadata: Object.assign({ resource: resource }, meta || {}),
67
+ });
68
+ } catch (_e) { /* audit best-effort */ }
69
+ }
70
+
71
+ function permits(action) {
72
+ if (mode === "open") return true;
73
+ if (mode === "locked") return false;
74
+ return !!READ_ACTIONS[action];
75
+ }
76
+
77
+ function set(newMode, ctx) {
78
+ ctx = ctx || {};
79
+ if (!VALID_MODES[newMode]) {
80
+ throw new ResourceAccessLockError(
81
+ "resource-access-lock/bad-mode",
82
+ "set: mode must be one of: " + Object.keys(VALID_MODES).join(" / "));
83
+ }
84
+ var prev = mode;
85
+ mode = newMode;
86
+ _emit("resourceaccesslock.mode_changed", "success", {
87
+ from: prev, to: newMode,
88
+ actor: ctx.actor || null, reason: ctx.reason || null,
89
+ });
90
+ }
91
+
92
+ function assertPermits(action, ctx) {
93
+ if (permits(action)) return;
94
+ _emit("resourceaccesslock.refused", "failure", {
95
+ action: action, mode: mode,
96
+ actor: (ctx && ctx.actor) || null,
97
+ });
98
+ throw new ResourceAccessLockError(
99
+ "resource-access-lock/refused",
100
+ resource + " refuses '" + action + "': lock mode is '" + mode + "'");
101
+ }
102
+
103
+ return {
104
+ resource: resource,
105
+ mode: function () { return mode; },
106
+ set: set,
107
+ permits: permits,
108
+ assertPermits: assertPermits,
109
+ };
110
+ }
111
+
112
+ module.exports = {
113
+ create: create,
114
+ VALID_MODES: Object.freeze(Object.keys(VALID_MODES)),
115
+ ResourceAccessLockError: ResourceAccessLockError,
116
+ };
@@ -294,10 +294,33 @@ var vaultAad = require("../vault-aad");
294
294
 
295
295
  var sealPemFileModule = require("./seal-pem-file");
296
296
 
297
+ // _zeroizeAndReplace — best-effort secureZero of prior in-memory keys
298
+ // before a swap. V8 strings can't be reliably overwritten (string
299
+ // interning + GC managed), so the pre-swap pass converts each PEM
300
+ // string to a Buffer, secureZeros the Buffer, and rebinds the
301
+ // property to "ZEROED" before the new keys land. The string copy
302
+ // inside V8 may still linger until GC; this just removes the
303
+ // largest-window heap copy (the ones held by `keys`).
304
+ function _zeroizeAndReplace(replacement) {
305
+ if (!keys) { keys = replacement; return; }
306
+ Object.keys(keys).forEach(function (k) {
307
+ var v = keys[k];
308
+ if (typeof v === "string" && v.length > 0) {
309
+ try {
310
+ var buf = Buffer.from(v, "utf8");
311
+ safeBuffer.secureZero(buf);
312
+ } catch (_e) { /* best-effort */ }
313
+ keys[k] = "ZEROED";
314
+ }
315
+ });
316
+ keys = replacement;
317
+ }
318
+
297
319
  module.exports = {
298
320
  init: init,
299
321
  seal: seal,
300
322
  unseal: unseal,
323
+ _zeroizeAndReplace: _zeroizeAndReplace,
301
324
  aad: vaultAad,
302
325
  getKeysJson: getKeysJson,
303
326
  getCurrentPassphrase: getCurrentPassphrase,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.8.39",
3
+ "version": "0.8.41",
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:319bfdfd-c9b3-4f86-a42e-c3441466295e",
5
+ "serialNumber": "urn:uuid:a6849ba0-e669-440c-8a01-b08d37e28a1e",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-07T16:17:54.954Z",
8
+ "timestamp": "2026-05-07T17:22:17.744Z",
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.39",
22
+ "bom-ref": "@blamejs/core@0.8.41",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.8.39",
25
+ "version": "0.8.41",
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.39",
29
+ "purl": "pkg:npm/%40blamejs/core@0.8.41",
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.39",
57
+ "ref": "@blamejs/core@0.8.41",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]