@senticor/hive 1.31.3 → 1.33.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.
- package/hive.cjs +137 -18
- package/package.json +1 -1
package/hive.cjs
CHANGED
|
@@ -9014,22 +9014,22 @@ var artifactName = injectedString(
|
|
|
9014
9014
|
true ? "hive-cli" : void 0
|
|
9015
9015
|
) || String(process.env.HIVE_CLI_ARTIFACT_NAME || "hive-cli").trim() || "hive-cli";
|
|
9016
9016
|
var packageVersion = injectedString(
|
|
9017
|
-
true ? "1.
|
|
9017
|
+
true ? "1.33.1" : void 0
|
|
9018
9018
|
) || String(process.env.HIVE_CLI_PACKAGE_VERSION || "").trim() || readPackageVersion();
|
|
9019
9019
|
var releaseVersion = injectedString(
|
|
9020
|
-
true ? "1.
|
|
9020
|
+
true ? "1.33.1" : void 0
|
|
9021
9021
|
) || String(process.env.HIVE_CLI_RELEASE_VERSION || "").trim() || packageVersion || "dev";
|
|
9022
9022
|
var releaseChannel = injectedString(
|
|
9023
9023
|
true ? "final" : void 0
|
|
9024
9024
|
) || String(process.env.HIVE_CLI_RELEASE_CHANNEL || "").trim() || (releaseVersion.includes("-rc.") ? "rc" : releaseVersion === "dev" ? "dev" : "final");
|
|
9025
9025
|
var buildCommit = injectedString(
|
|
9026
|
-
true ? "
|
|
9026
|
+
true ? "0bba73f7b6060454678d8f9f3763cabe75532ad4" : void 0
|
|
9027
9027
|
) || String(process.env.HIVE_CLI_BUILD_COMMIT || "").trim() || "unknown";
|
|
9028
9028
|
var buildTimestamp = injectedString(
|
|
9029
|
-
true ? "2026-09-
|
|
9029
|
+
true ? "2026-09-09T18:17:52Z" : void 0
|
|
9030
9030
|
) || String(process.env.HIVE_CLI_BUILD_TIMESTAMP || "").trim() || "unknown";
|
|
9031
9031
|
var ociRef = injectedString(
|
|
9032
|
-
true ? "registry.onstackit.cloud/senticor/hive-cli:1.
|
|
9032
|
+
true ? "registry.onstackit.cloud/senticor/hive-cli:1.33.1" : void 0
|
|
9033
9033
|
) || String(process.env.HIVE_CLI_OCI_REF || "").trim() || `registry.onstackit.cloud/senticor/${artifactName}:${releaseVersion}`;
|
|
9034
9034
|
var RELEASE_INFO = Object.freeze({
|
|
9035
9035
|
packageVersion,
|
|
@@ -24838,6 +24838,24 @@ function isValidCorsOrigin(value) {
|
|
|
24838
24838
|
}
|
|
24839
24839
|
var ROLE_KEY_RE = /^[a-z0-9][a-z0-9._:-]{0,63}$/;
|
|
24840
24840
|
|
|
24841
|
+
// ../hive-api-contracts/src/mission-kafka-ingest.ts
|
|
24842
|
+
init_cjs_shims();
|
|
24843
|
+
var MISSION_KAFKA_SASL_MECHANISMS = [
|
|
24844
|
+
"plain",
|
|
24845
|
+
"scram-sha-256",
|
|
24846
|
+
"scram-sha-512"
|
|
24847
|
+
];
|
|
24848
|
+
var MISSION_KAFKA_TLS_CA_MAX_BYTES = 64 * 1024;
|
|
24849
|
+
function utf8ByteLength(value) {
|
|
24850
|
+
return new TextEncoder().encode(value).length;
|
|
24851
|
+
}
|
|
24852
|
+
function looksLikePemCertificate(value) {
|
|
24853
|
+
return value.includes("-----BEGIN CERTIFICATE-----") && value.includes("-----END CERTIFICATE-----");
|
|
24854
|
+
}
|
|
24855
|
+
function looksLikeJsonSchema(value) {
|
|
24856
|
+
return "$schema" in value || "type" in value || "$id" in value || "properties" in value;
|
|
24857
|
+
}
|
|
24858
|
+
|
|
24841
24859
|
// src/admin/config.mts
|
|
24842
24860
|
var TENANT_KINDS = ["customer", "organization"];
|
|
24843
24861
|
var RoleKeySchema = external_exports.string().regex(ROLE_KEY_RE, "role key must be lower-case, 1-64 chars of [a-z0-9._:-]");
|
|
@@ -24899,9 +24917,25 @@ var KafkaSchema = external_exports.object({
|
|
|
24899
24917
|
manifestTopic: external_exports.string().min(1).optional(),
|
|
24900
24918
|
consumerGroup: external_exports.string().min(1).optional(),
|
|
24901
24919
|
schemaSource: external_exports.enum(SCHEMA_SOURCES).default("inline"),
|
|
24920
|
+
// Round 8 (#83 review): buildKafkaPatchBody supported these since bms#257,
|
|
24921
|
+
// but the strict schema rejected the keys and the orchestrator never
|
|
24922
|
+
// forwarded them — the documented SCRAM enclave flow exited with
|
|
24923
|
+
// 'Unrecognized key: "saslMechanism"', and removing the key silently
|
|
24924
|
+
// provisioned PLAIN against a SCRAM-SHA-512 broker.
|
|
24925
|
+
saslMechanism: external_exports.enum(MISSION_KAFKA_SASL_MECHANISMS).optional(),
|
|
24926
|
+
// Round 9 (#83 review): trim before the min-length check — a whitespace-only
|
|
24927
|
+
// value otherwise passes local validation and 400s only at the Kafka PATCH,
|
|
24928
|
+
// after tenant/members/mission are already provisioned.
|
|
24929
|
+
fileNameHeaderKey: external_exports.string().trim().min(1).optional(),
|
|
24902
24930
|
// Path (relative to the config file) to an inline JSON Schema. Required
|
|
24903
24931
|
// when schemaSource === 'inline'.
|
|
24904
24932
|
envelopeSchemaPath: external_exports.string().min(1).optional(),
|
|
24933
|
+
// #83 — path (relative to the config file) to the broker CA bundle in PEM
|
|
24934
|
+
// form, for private-CA/self-signed brokers (the normal enclave/Strimzi
|
|
24935
|
+
// setup). Resolved at build time and sent as `tls.caPem`; omit to trust
|
|
24936
|
+
// the default store. A path, not inline PEM: multi-line certificate
|
|
24937
|
+
// blocks do not belong in a JSON config.
|
|
24938
|
+
tlsCaPemPath: external_exports.string().min(1).optional(),
|
|
24905
24939
|
schemaRegistry: SchemaRegistrySchema.optional(),
|
|
24906
24940
|
classification: external_exports.string().min(1).optional(),
|
|
24907
24941
|
sourceType: external_exports.string().min(1).optional()
|
|
@@ -25221,14 +25255,6 @@ async function ensureMission(client, mission2, opts) {
|
|
|
25221
25255
|
|
|
25222
25256
|
// src/admin/steps/kafka.mts
|
|
25223
25257
|
init_cjs_shims();
|
|
25224
|
-
|
|
25225
|
-
// ../hive-api-contracts/src/mission-kafka-ingest.ts
|
|
25226
|
-
init_cjs_shims();
|
|
25227
|
-
function looksLikeJsonSchema(value) {
|
|
25228
|
-
return "$schema" in value || "type" in value || "$id" in value || "properties" in value;
|
|
25229
|
-
}
|
|
25230
|
-
|
|
25231
|
-
// src/admin/steps/kafka.mts
|
|
25232
25258
|
function buildKafkaPatchBody(input) {
|
|
25233
25259
|
if (!input.apiKey || !input.apiSecret) {
|
|
25234
25260
|
throw new Error(
|
|
@@ -25266,6 +25292,7 @@ function buildKafkaPatchBody(input) {
|
|
|
25266
25292
|
if (input.fileNameHeaderKey) body.fileNameHeaderKey = input.fileNameHeaderKey;
|
|
25267
25293
|
if (input.classification) body.classification = input.classification;
|
|
25268
25294
|
if (input.sourceType) body.sourceType = input.sourceType;
|
|
25295
|
+
if (input.tlsCaPem) body.tls = { caPem: input.tlsCaPem };
|
|
25269
25296
|
if (input.schemaSource === "inline") {
|
|
25270
25297
|
body.envelopeSchema = input.envelopeSchema;
|
|
25271
25298
|
} else {
|
|
@@ -25335,8 +25362,13 @@ async function runBootstrap(deps) {
|
|
|
25335
25362
|
topic: config3.kafka.topic,
|
|
25336
25363
|
manifestTopic: config3.kafka.manifestTopic,
|
|
25337
25364
|
consumerGroup: config3.kafka.consumerGroup,
|
|
25365
|
+
// Round 8: forward the bms#257 fields — the schema accepted... nothing, and
|
|
25366
|
+
// this call silently dropped them, so SCRAM configs provisioned PLAIN.
|
|
25367
|
+
saslMechanism: config3.kafka.saslMechanism,
|
|
25368
|
+
fileNameHeaderKey: config3.kafka.fileNameHeaderKey,
|
|
25338
25369
|
schemaSource: config3.kafka.schemaSource,
|
|
25339
25370
|
envelopeSchema: deps.envelopeSchema,
|
|
25371
|
+
tlsCaPem: deps.tlsCaPem,
|
|
25340
25372
|
schemaRegistry: config3.kafka.schemaRegistry ? {
|
|
25341
25373
|
url: config3.kafka.schemaRegistry.url,
|
|
25342
25374
|
apiKey: secrets.schemaRegistryApiKey,
|
|
@@ -25347,6 +25379,20 @@ async function runBootstrap(deps) {
|
|
|
25347
25379
|
apiKey: secrets.kafkaApiKey ?? "",
|
|
25348
25380
|
apiSecret: secrets.kafkaApiSecret ?? ""
|
|
25349
25381
|
});
|
|
25382
|
+
if (deps.tlsCaPem) {
|
|
25383
|
+
const advertised = await advertisedTlsCaLimit(client);
|
|
25384
|
+
if (advertised == null) {
|
|
25385
|
+
throw new Error(
|
|
25386
|
+
"kafka.tlsCaPemPath is set, but this deployment does not advertise maxKafkaTlsCaPemBytes via GET /api/me/limits \u2014 it predates broker-CA support (#83) and would silently drop the CA from the binding. Upgrade the deployment, or remove tlsCaPemPath to trust the default store. Aborting BEFORE any mutation."
|
|
25387
|
+
);
|
|
25388
|
+
}
|
|
25389
|
+
const bytes = utf8ByteLength(deps.tlsCaPem);
|
|
25390
|
+
if (bytes > advertised) {
|
|
25391
|
+
throw new Error(
|
|
25392
|
+
`kafka.tlsCaPemPath: the CA bundle is ${bytes} UTF-8 bytes, but this deployment advertises maxKafkaTlsCaPemBytes=${advertised} via GET /api/me/limits \u2014 shrink the bundle or raise HIVE_MAX_KAFKA_TLS_CA_PEM_BYTES on the server.`
|
|
25393
|
+
);
|
|
25394
|
+
}
|
|
25395
|
+
}
|
|
25350
25396
|
const state = readState(statePath);
|
|
25351
25397
|
log(`Ensuring tenant ${displayKey} \u2026`);
|
|
25352
25398
|
const tenant = await ensureTenant(client, config3.tenant);
|
|
@@ -25415,6 +25461,36 @@ async function runBootstrap(deps) {
|
|
|
25415
25461
|
probe
|
|
25416
25462
|
};
|
|
25417
25463
|
}
|
|
25464
|
+
async function advertisedTlsCaLimit(client) {
|
|
25465
|
+
let res;
|
|
25466
|
+
try {
|
|
25467
|
+
res = await client.request("GET", "/api/me/limits");
|
|
25468
|
+
} catch (err) {
|
|
25469
|
+
throw new Error(
|
|
25470
|
+
`cannot reach GET /api/me/limits to check the deployment's CA size limit \u2014 aborting BEFORE any mutation (${err?.message ?? err})`
|
|
25471
|
+
);
|
|
25472
|
+
}
|
|
25473
|
+
if (!res.ok) {
|
|
25474
|
+
if (res.status === 404) return null;
|
|
25475
|
+
throw new Error(
|
|
25476
|
+
`GET /api/me/limits answered HTTP ${res.status} \u2014 cannot verify the deployment's CA size limit; aborting BEFORE any mutation`
|
|
25477
|
+
);
|
|
25478
|
+
}
|
|
25479
|
+
const body = res.json;
|
|
25480
|
+
if (body === null || typeof body !== "object") {
|
|
25481
|
+
throw new Error(
|
|
25482
|
+
"GET /api/me/limits returned an unparseable body \u2014 cannot verify the deployment's CA size limit; aborting BEFORE any mutation"
|
|
25483
|
+
);
|
|
25484
|
+
}
|
|
25485
|
+
const v = body.ingestLimits?.maxKafkaTlsCaPemBytes;
|
|
25486
|
+
if (v === void 0 || v === null) return null;
|
|
25487
|
+
if (typeof v !== "number" || !Number.isFinite(v) || v <= 0) {
|
|
25488
|
+
throw new Error(
|
|
25489
|
+
`GET /api/me/limits advertises a malformed maxKafkaTlsCaPemBytes (${JSON.stringify(v)}) \u2014 cannot verify the deployment's CA size limit; aborting BEFORE any mutation`
|
|
25490
|
+
);
|
|
25491
|
+
}
|
|
25492
|
+
return v;
|
|
25493
|
+
}
|
|
25418
25494
|
|
|
25419
25495
|
// src/admin/steps/inject.mts
|
|
25420
25496
|
init_cjs_shims();
|
|
@@ -25463,6 +25539,7 @@ async function runConnector(client, missionId, tenant, config3) {
|
|
|
25463
25539
|
// src/admin/cli-support.mts
|
|
25464
25540
|
init_cjs_shims();
|
|
25465
25541
|
var import_node_fs8 = require("fs");
|
|
25542
|
+
var import_node_crypto3 = require("crypto");
|
|
25466
25543
|
var import_node_path7 = require("path");
|
|
25467
25544
|
function loadConfigFile(configPath2, cwd = process.cwd()) {
|
|
25468
25545
|
const abs = (0, import_node_path7.isAbsolute)(configPath2) ? configPath2 : (0, import_node_path7.resolve)(cwd, configPath2);
|
|
@@ -25480,6 +25557,46 @@ function resolveEnvelopeSchema(config3, configDir) {
|
|
|
25480
25557
|
const abs = (0, import_node_path7.isAbsolute)(p) ? p : (0, import_node_path7.resolve)(configDir, p);
|
|
25481
25558
|
return JSON.parse((0, import_node_fs8.readFileSync)(abs, "utf-8"));
|
|
25482
25559
|
}
|
|
25560
|
+
function resolveTlsCaPem(config3, configDir) {
|
|
25561
|
+
const p = config3.kafka.tlsCaPemPath;
|
|
25562
|
+
if (!p) return void 0;
|
|
25563
|
+
const abs = (0, import_node_path7.isAbsolute)(p) ? p : (0, import_node_path7.resolve)(configDir, p);
|
|
25564
|
+
const pem = (0, import_node_fs8.readFileSync)(abs, "utf-8").trim();
|
|
25565
|
+
if (!looksLikePemCertificate(pem)) {
|
|
25566
|
+
throw new Error(
|
|
25567
|
+
`kafka.tlsCaPemPath (${p}) does not look like a PEM certificate bundle (missing BEGIN/END CERTIFICATE markers)`
|
|
25568
|
+
);
|
|
25569
|
+
}
|
|
25570
|
+
if (utf8ByteLength(pem) > MISSION_KAFKA_TLS_CA_MAX_BYTES) {
|
|
25571
|
+
throw new Error(
|
|
25572
|
+
`kafka.tlsCaPemPath (${p}) exceeds ${MISSION_KAFKA_TLS_CA_MAX_BYTES} UTF-8 bytes \u2014 a broker CA bundle should be a handful of certificates`
|
|
25573
|
+
);
|
|
25574
|
+
}
|
|
25575
|
+
for (const match of pem.matchAll(/-----BEGIN ([A-Z0-9 ]+)-----/g)) {
|
|
25576
|
+
if (match[1] !== "CERTIFICATE") {
|
|
25577
|
+
throw new Error(
|
|
25578
|
+
`kafka.tlsCaPemPath (${p}) contains a "${match[1]}" PEM block \u2014 only CERTIFICATE blocks belong in a CA bundle (if it is a private key, treat it as exposed and rotate it)`
|
|
25579
|
+
);
|
|
25580
|
+
}
|
|
25581
|
+
}
|
|
25582
|
+
const blocks = pem.match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g) ?? [];
|
|
25583
|
+
const beginCount = (pem.match(/-----BEGIN CERTIFICATE-----/g) ?? []).length;
|
|
25584
|
+
if (blocks.length === 0 || blocks.length !== beginCount) {
|
|
25585
|
+
throw new Error(
|
|
25586
|
+
`kafka.tlsCaPemPath (${p}) looks truncated \u2014 every certificate needs both its BEGIN and END marker`
|
|
25587
|
+
);
|
|
25588
|
+
}
|
|
25589
|
+
blocks.forEach((block, i) => {
|
|
25590
|
+
try {
|
|
25591
|
+
new import_node_crypto3.X509Certificate(block);
|
|
25592
|
+
} catch {
|
|
25593
|
+
throw new Error(
|
|
25594
|
+
`kafka.tlsCaPemPath (${p}): certificate block ${i + 1} of ${blocks.length} does not parse as X.509 \u2014 re-copy the bundle from its source (truncated or corrupted base64?)`
|
|
25595
|
+
);
|
|
25596
|
+
}
|
|
25597
|
+
});
|
|
25598
|
+
return pem;
|
|
25599
|
+
}
|
|
25483
25600
|
function defaultStatePath(configDir, override, cwd = process.cwd()) {
|
|
25484
25601
|
if (override) return (0, import_node_path7.isAbsolute)(override) ? override : (0, import_node_path7.resolve)(cwd, override);
|
|
25485
25602
|
return (0, import_node_path7.resolve)(configDir, ".bootstrap-state.json");
|
|
@@ -25529,6 +25646,7 @@ async function cmdBootstrap(configPath2, envPath, flags) {
|
|
|
25529
25646
|
const { config: config3, dir } = loadConfigFile(configPath2);
|
|
25530
25647
|
loadEnvFile(envPath);
|
|
25531
25648
|
const envelopeSchema = resolveEnvelopeSchema(config3, dir);
|
|
25649
|
+
const tlsCaPem = resolveTlsCaPem(config3, dir);
|
|
25532
25650
|
const secrets = resolveSecrets(process.env);
|
|
25533
25651
|
const dryRun = flags["dry-run"] === true;
|
|
25534
25652
|
const client = dryRun ? createHttpClient(config3.apiUrl, "") : createHttpClient(config3.apiUrl, await acquireToken({ oidc: config3.oidc, secrets }));
|
|
@@ -25537,6 +25655,7 @@ async function cmdBootstrap(configPath2, envPath, flags) {
|
|
|
25537
25655
|
config: config3,
|
|
25538
25656
|
secrets,
|
|
25539
25657
|
envelopeSchema,
|
|
25658
|
+
tlsCaPem,
|
|
25540
25659
|
statePath: defaultStatePath(dir, flagStr(flags, "state")),
|
|
25541
25660
|
options: { dryRun, force: flags.force === true, probe: flags["no-probe"] !== true },
|
|
25542
25661
|
log: (m) => console.log(m)
|
|
@@ -26144,7 +26263,7 @@ var stack = defineCommand({
|
|
|
26144
26263
|
|
|
26145
26264
|
// src/commands/diag.ts
|
|
26146
26265
|
init_cjs_shims();
|
|
26147
|
-
var
|
|
26266
|
+
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
26148
26267
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
26149
26268
|
var import_node_fs10 = __toESM(require("fs"), 1);
|
|
26150
26269
|
var import_node_path10 = __toESM(require("path"), 1);
|
|
@@ -26213,12 +26332,12 @@ function runDiagOffline(sub, verbose) {
|
|
|
26213
26332
|
"cli"
|
|
26214
26333
|
];
|
|
26215
26334
|
let totalSpec = 0;
|
|
26216
|
-
const masterH =
|
|
26335
|
+
const masterH = import_node_crypto4.default.createHash("sha256");
|
|
26217
26336
|
for (const dir of specDirs) {
|
|
26218
26337
|
const full = import_node_path10.default.join(specsBase, dir);
|
|
26219
26338
|
if (!import_node_fs10.default.existsSync(full)) continue;
|
|
26220
26339
|
const files = import_node_fs10.default.readdirSync(full).filter((f) => /\.(json|ya?ml)$/i.test(f)).sort();
|
|
26221
|
-
const h =
|
|
26340
|
+
const h = import_node_crypto4.default.createHash("sha256");
|
|
26222
26341
|
for (const f of files) h.update(import_node_fs10.default.readFileSync(import_node_path10.default.join(full, f)));
|
|
26223
26342
|
const hash2 = h.digest("hex").slice(0, 12);
|
|
26224
26343
|
totalSpec += files.length;
|
|
@@ -27833,7 +27952,7 @@ var ajvFormatsModule2 = __toESM(require_dist(), 1);
|
|
|
27833
27952
|
|
|
27834
27953
|
// src/lib/application-package.ts
|
|
27835
27954
|
init_cjs_shims();
|
|
27836
|
-
var
|
|
27955
|
+
var import_node_crypto5 = require("crypto");
|
|
27837
27956
|
var import_node_fs12 = require("fs");
|
|
27838
27957
|
var import_node_path11 = require("path");
|
|
27839
27958
|
var ajvModule = __toESM(require_ajv(), 1);
|
|
@@ -27953,7 +28072,7 @@ var envelopeAjv = new AjvCtor({ allErrors: true, strict: false });
|
|
|
27953
28072
|
addFormats(envelopeAjv);
|
|
27954
28073
|
var validateStarterEnvelope = envelopeAjv.compile(DEFAULT_ENVELOPE_SCHEMA);
|
|
27955
28074
|
function sha256Hex(bytes) {
|
|
27956
|
-
return (0,
|
|
28075
|
+
return (0, import_node_crypto5.createHash)("sha256").update(bytes).digest("hex");
|
|
27957
28076
|
}
|
|
27958
28077
|
function formatBytes(n) {
|
|
27959
28078
|
if (n >= 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MiB`;
|