infracensus-collector 1.6.21 → 1.6.23
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/LICENSE +23 -23
- package/dist/a10-index.js +4 -4
- package/dist/azure-index.js +8 -7
- package/dist/azure-index.js.map +1 -1
- package/dist/{chunk-SSKRKLNM.js → chunk-25TNYVF5.js} +131 -38
- package/dist/chunk-25TNYVF5.js.map +7 -0
- package/dist/{chunk-NH4RDH3P.js → chunk-2CKQ2AXQ.js} +24 -5
- package/dist/chunk-2CKQ2AXQ.js.map +7 -0
- package/dist/{chunk-SSELCAMT.js → chunk-3WK4UW4I.js} +3 -3
- package/dist/chunk-3WK4UW4I.js.map +7 -0
- package/dist/{chunk-WYJH3AW5.js → chunk-42UQ3SP6.js} +48 -4
- package/dist/chunk-42UQ3SP6.js.map +7 -0
- package/dist/{chunk-QW4IV7RU.js → chunk-6YAG2LJC.js} +3 -3
- package/dist/chunk-6YAG2LJC.js.map +7 -0
- package/dist/{chunk-4RUBV5WB.js → chunk-7ESBA5C5.js} +1 -1
- package/dist/chunk-7ESBA5C5.js.map +7 -0
- package/dist/{chunk-2XRLDUAC.js → chunk-ALPMCXOV.js} +5487 -6073
- package/dist/chunk-ALPMCXOV.js.map +7 -0
- package/dist/{chunk-MP6JAAFY.js → chunk-CMBYYYAZ.js} +4 -4
- package/dist/{chunk-HGADZRD3.js → chunk-H2WWXFBM.js} +10 -9
- package/dist/chunk-H2WWXFBM.js.map +7 -0
- package/dist/{chunk-FJ22GRKW.js → chunk-I5A5QI3R.js} +45 -7
- package/dist/chunk-I5A5QI3R.js.map +7 -0
- package/dist/{chunk-FQNQEK35.js → chunk-MAEF22DU.js} +3 -3
- package/dist/{chunk-FNCTUV2L.js → chunk-Q6MEI374.js} +2 -2
- package/dist/{chunk-FNCTUV2L.js.map → chunk-Q6MEI374.js.map} +1 -1
- package/dist/{chunk-4UOTVQ2D.js → chunk-QQ67FRXQ.js} +218 -29
- package/dist/chunk-QQ67FRXQ.js.map +7 -0
- package/dist/{chunk-FXUH6FPP.js → chunk-QZS2SMFT.js} +68 -9
- package/dist/chunk-QZS2SMFT.js.map +7 -0
- package/dist/{chunk-YWOXCYLX.js → chunk-S6QIVL5K.js} +4 -4
- package/dist/{chunk-DIS3S4SY.js → chunk-TGEOODHQ.js} +32 -2
- package/dist/{chunk-DIS3S4SY.js.map → chunk-TGEOODHQ.js.map} +3 -3
- package/dist/{chunk-DI6WLXKR.js → chunk-VSG4FRGL.js} +2 -33
- package/dist/{chunk-DI6WLXKR.js.map → chunk-VSG4FRGL.js.map} +3 -3
- package/dist/chunk-X46NKIFT.js +96 -0
- package/dist/chunk-X46NKIFT.js.map +7 -0
- package/dist/{chunk-HDNYHF57.js → chunk-XCEVKY55.js} +41 -9
- package/dist/chunk-XCEVKY55.js.map +7 -0
- package/dist/{chunk-32BYFAKO.js → chunk-XLB7GCCC.js} +38 -17
- package/dist/chunk-XLB7GCCC.js.map +7 -0
- package/dist/{chunk-WPRMFIPU.js → chunk-XNSIIJRX.js} +16 -3
- package/dist/chunk-XNSIIJRX.js.map +7 -0
- package/dist/{chunk-CW3YCPEC.js → chunk-XSHYWQAH.js} +1 -1
- package/dist/chunk-XSHYWQAH.js.map +7 -0
- package/dist/cli.js +14 -13
- package/dist/cli.js.map +1 -1
- package/dist/{config-5S3SX2ZB.js → config-W26KGYIS.js} +4 -4
- package/dist/configimport-index.js +5 -5
- package/dist/configimport-index.js.map +1 -1
- package/dist/hyperv-index.js +15 -7
- package/dist/hyperv-index.js.map +2 -2
- package/dist/identity-index.js +8 -7
- package/dist/identity-index.js.map +1 -1
- package/dist/index.js +938 -118
- package/dist/index.js.map +4 -4
- package/dist/{linux-7OIQNB4O.js → linux-Y4ZUMDY3.js} +2 -2
- package/dist/linux-Y4ZUMDY3.js.map +7 -0
- package/dist/pkgRoot-RFOX7XXU.js +7 -0
- package/dist/sensitive-data-index.js +88 -11
- package/dist/sensitive-data-index.js.map +3 -3
- package/dist/{service-AFZPX4K7.js → service-RDLVUKU2.js} +2 -2
- package/dist/sql-index.js +15 -7
- package/dist/sql-index.js.map +2 -2
- package/dist/{status-7YZQI2LY.js → status-Y34C7AR5.js} +8 -8
- package/dist/{tools-BTYQGJEB.js → tools-KT77LANU.js} +2 -2
- package/dist/tools-KT77LANU.js.map +7 -0
- package/dist/vmware-index.js +16 -8
- package/dist/vmware-index.js.map +2 -2
- package/dist/voice-index.js +8 -8
- package/dist/{windows-2P76ECNN.js → windows-B4L24PIR.js} +2 -2
- package/package.json +97 -97
- package/scripts/bundle.mjs +124 -124
- package/scripts/lib/enrolment.d.mts +62 -62
- package/scripts/lib/prompt.mjs +98 -98
- package/dist/chunk-2XRLDUAC.js.map +0 -7
- package/dist/chunk-32BYFAKO.js.map +0 -7
- package/dist/chunk-4RUBV5WB.js.map +0 -7
- package/dist/chunk-4UOTVQ2D.js.map +0 -7
- package/dist/chunk-CW3YCPEC.js.map +0 -7
- package/dist/chunk-FJ22GRKW.js.map +0 -7
- package/dist/chunk-FXUH6FPP.js.map +0 -7
- package/dist/chunk-HDNYHF57.js.map +0 -7
- package/dist/chunk-HGADZRD3.js.map +0 -7
- package/dist/chunk-NH4RDH3P.js.map +0 -7
- package/dist/chunk-QW4IV7RU.js.map +0 -7
- package/dist/chunk-SSELCAMT.js.map +0 -7
- package/dist/chunk-SSKRKLNM.js.map +0 -7
- package/dist/chunk-WPRMFIPU.js.map +0 -7
- package/dist/chunk-WYJH3AW5.js.map +0 -7
- package/dist/linux-7OIQNB4O.js.map +0 -7
- package/dist/pkgRoot-TT3C3BUM.js +0 -7
- package/dist/tools-BTYQGJEB.js.map +0 -7
- /package/dist/{chunk-MP6JAAFY.js.map → chunk-CMBYYYAZ.js.map} +0 -0
- /package/dist/{chunk-FQNQEK35.js.map → chunk-MAEF22DU.js.map} +0 -0
- /package/dist/{chunk-YWOXCYLX.js.map → chunk-S6QIVL5K.js.map} +0 -0
- /package/dist/{config-5S3SX2ZB.js.map → config-W26KGYIS.js.map} +0 -0
- /package/dist/{pkgRoot-TT3C3BUM.js.map → pkgRoot-RFOX7XXU.js.map} +0 -0
- /package/dist/{service-AFZPX4K7.js.map → service-RDLVUKU2.js.map} +0 -0
- /package/dist/{status-7YZQI2LY.js.map → status-Y34C7AR5.js.map} +0 -0
- /package/dist/{windows-2P76ECNN.js.map → windows-B4L24PIR.js.map} +0 -0
package/LICENSE
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
InfraCensus Collector
|
|
2
|
-
Copyright (c) 2026 Zentrosoft. All rights reserved.
|
|
3
|
-
|
|
4
|
-
This software is proprietary. It is published to the npm registry so that
|
|
5
|
-
licensed InfraCensus tenants can install and update the collector with
|
|
6
|
-
standard tooling; publication is not a grant of rights.
|
|
7
|
-
|
|
8
|
-
You may install and run this software only to connect infrastructure you
|
|
9
|
-
control to an InfraCensus deployment you are licensed to use. You may not
|
|
10
|
-
copy (except as required to install and run it), modify, translate, reverse
|
|
11
|
-
engineer, decompile, disassemble, sublicense, sell, lease, or redistribute
|
|
12
|
-
this software, in whole or in part, except as permitted by applicable law
|
|
13
|
-
notwithstanding this restriction, or with prior written permission.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
-
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
21
|
-
DEALINGS IN THE SOFTWARE.
|
|
22
|
-
|
|
23
|
-
Contact: info@infracensus.com
|
|
1
|
+
InfraCensus Collector
|
|
2
|
+
Copyright (c) 2026 Zentrosoft. All rights reserved.
|
|
3
|
+
|
|
4
|
+
This software is proprietary. It is published to the npm registry so that
|
|
5
|
+
licensed InfraCensus tenants can install and update the collector with
|
|
6
|
+
standard tooling; publication is not a grant of rights.
|
|
7
|
+
|
|
8
|
+
You may install and run this software only to connect infrastructure you
|
|
9
|
+
control to an InfraCensus deployment you are licensed to use. You may not
|
|
10
|
+
copy (except as required to install and run it), modify, translate, reverse
|
|
11
|
+
engineer, decompile, disassemble, sublicense, sell, lease, or redistribute
|
|
12
|
+
this software, in whole or in part, except as permitted by applicable law
|
|
13
|
+
notwithstanding this restriction, or with prior written permission.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
21
|
+
DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
Contact: info@infracensus.com
|
package/dist/a10-index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AxapiClient,
|
|
3
3
|
buildLoadBalancerInventory
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2CKQ2AXQ.js";
|
|
5
5
|
import {
|
|
6
6
|
requireEntitlementToScan
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QQ67FRXQ.js";
|
|
8
8
|
import {
|
|
9
9
|
ROUTES
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-ALPMCXOV.js";
|
|
11
|
+
import "./chunk-XSHYWQAH.js";
|
|
12
12
|
|
|
13
13
|
// src/a10-index.ts
|
|
14
14
|
var LEVEL_RANK = { debug: 10, info: 20, warn: 30, error: 40 };
|
package/dist/azure-index.js
CHANGED
|
@@ -2,19 +2,20 @@ import {
|
|
|
2
2
|
ArmClient,
|
|
3
3
|
buildAzureInventory,
|
|
4
4
|
listAccessibleSubscriptions
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XLB7GCCC.js";
|
|
6
|
+
import "./chunk-X46NKIFT.js";
|
|
6
7
|
import {
|
|
7
8
|
pushAzureInventory
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-S6QIVL5K.js";
|
|
10
|
+
import "./chunk-Q6MEI374.js";
|
|
10
11
|
import {
|
|
11
12
|
loadAzureConfig
|
|
12
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-MAEF22DU.js";
|
|
13
14
|
import {
|
|
14
15
|
requireEntitlementToScan
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-QQ67FRXQ.js";
|
|
17
|
+
import "./chunk-ALPMCXOV.js";
|
|
18
|
+
import "./chunk-XSHYWQAH.js";
|
|
18
19
|
|
|
19
20
|
// src/azure-index.ts
|
|
20
21
|
var LEVEL_RANK = { debug: 10, info: 20, warn: 30, error: 40 };
|
package/dist/azure-index.js.map
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/azure-index.ts"],
|
|
4
4
|
"sourcesContent": ["/**\r\n * Azure Cloud Posture (CSPM) collector CLI entry point.\r\n *\r\n * pnpm azure-scan inventory every subscription the configured ARM\r\n * service principal can see (or the AZURE_SUBSCRIPTIONS\r\n * allow-list, if set) and push each to /ingest/azure\r\n * pnpm azure-scan:dry inventory and print a summary WITHOUT pushing\r\n * tsx src/azure-index.ts --dry-run (equivalent to azure-scan:dry)\r\n *\r\n * ONE service principal (ARM app registration, OAuth2 client-credentials) that\r\n * may see MANY subscriptions \u2014 unlike identity-index.ts's \"one Graph app\r\n * registration = one cloud org\", this loops {@link listAccessibleSubscriptions}\r\n * and builds + pushes ONE AzureInventory PER subscription, each versioned\r\n * independently on the control plane by subscriptionId. A gather that 403s on a\r\n * missing role/unregistered resource provider degrades that ONE signal\r\n * gracefully within a single subscription's build (see azure/plugin.ts); only a\r\n * failure to acquire a token or list subscriptions at all fails the whole run.\r\n *\r\n * Ctrl-C (SIGINT) triggers a cooperative AbortSignal so in-flight requests stop.\r\n */\r\nimport { loadAzureConfig } from \"./config.js\";\r\nimport { pushAzureInventory } from \"./core/push.js\";\r\nimport { ArmClient } from \"./azure/arm.js\";\r\nimport { buildAzureInventory, listAccessibleSubscriptions, type AzureStamp } from \"./azure/plugin.js\";\r\nimport type { Logger } from \"./core/runner.js\";\r\nimport type { AzureInventory } from \"@netdoc/collector-contract\";\r\nimport { requireEntitlementToScan } from \"./entitlement/index.js\";\r\n\r\nconst LEVEL_RANK = { debug: 10, info: 20, warn: 30, error: 40 } as const;\r\n\r\nfunction makeLogger(minLevel: keyof typeof LEVEL_RANK = \"info\"): Logger {\r\n const min = LEVEL_RANK[minLevel];\r\n return (level, msg, meta) => {\r\n if (LEVEL_RANK[level] < min) return;\r\n const line = `${new Date().toISOString()} ${level.toUpperCase().padEnd(5)} ${msg}`;\r\n const out = level === \"error\" ? console.error : level === \"warn\" ? console.warn : console.log;\r\n if (meta !== undefined) out(line, meta);\r\n else out(line);\r\n };\r\n}\r\n\r\nfunction errMsg(err: unknown): string {\r\n return err instanceof Error ? err.message : String(err);\r\n}\r\n\r\nfunction printSummary(inv: AzureInventory, log: Logger): void {\r\n log(\"info\", \"=== DRY RUN \u2014 AzureInventory NOT pushed ===\");\r\n log(\"info\", `subscription : ${inv.subscription.name} (${inv.subscriptionId})`);\r\n log(\"info\", `tenant : ${inv.tenantId}`);\r\n log(\"info\", `directory tenant : ${inv.tenantDirId}`);\r\n log(\"info\", `capturedAt : ${inv.capturedAt}`);\r\n log(\"info\", `state : ${inv.subscription.state}`);\r\n log(\r\n \"info\",\r\n `management group : ${inv.subscription.managementGroupName ?? inv.subscription.managementGroupId ?? \"not observed\"}`,\r\n );\r\n log(\"info\", `resources : ${inv.resources.length}`);\r\n // `hasRiskyInbound` is true when SOME inbound Allow rule names an any-source\r\n // prefix; it says nothing about which port that rule opens, so an NSG fronting\r\n // a public web server (443 from the internet, exactly as intended) sets it.\r\n // Reporting that count as \"risky\" told the operator about an exposure this\r\n // payload cannot substantiate \u2014 the per-port verdict belongs to the control\r\n // plane's audit engine, which reads the rules shipped alongside the flag.\r\n const internetFacingNsgs = inv.network.filter((n) => n.kind === \"nsg\" && n.hasRiskyInbound).length;\r\n log(\"info\", `network entities : ${inv.network.length} (${internetFacingNsgs} NSG(s) with any-source inbound)`);\r\n log(\"info\", `rbac assignments : ${inv.rbac.length} (${inv.rbac.filter((r) => r.isPrivileged).length} privileged)`);\r\n if (inv.defender) {\r\n log(\r\n \"info\",\r\n `defender : secureScore=${inv.defender.secureScore ?? \"?\"} ` +\r\n `${Object.keys(inv.defender.planCoverage).length} plan(s), ${inv.defender.recommendations.length} recommendation(s)`,\r\n );\r\n } else {\r\n log(\"info\", \"defender : not observed (missing Microsoft.Security role/RP registration?)\");\r\n }\r\n const nonCompliant = inv.policy.filter((p) => p.complianceState === \"NonCompliant\").length;\r\n log(\"info\", `policy : ${inv.policy.length} assignment(s) (${nonCompliant} non-compliant)`);\r\n}\r\n\r\nasync function main(): Promise<void> {\r\n const argv = process.argv.slice(2);\r\n const dryRun = argv.includes(\"--dry-run\");\r\n const debug = argv.includes(\"--debug\") || process.env.LOG_LEVEL === \"debug\";\r\n const log = makeLogger(debug ? \"debug\" : \"info\");\r\n\r\n const config = loadAzureConfig();\r\n\r\n // \u2500\u2500 PAID-LICENCE GATE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n //\r\n // BEFORE the client is built and before a credential leaves this process.\r\n // `core/planRefusal.ts` named this exact path as the one its own refusal\r\n // handling could not save: \"a refusal is learned at PUSH \u2014 which for a\r\n // one-shot `netdoc-collector scan azure` is after the collector has already\r\n // logged into the customer's Azure subscriptions and read their whole inventory\". Asking\r\n // first is what closes it.\r\n //\r\n // `--dry-run` IS GATED TOO, deliberately. A dry run still authenticates to\r\n // the customer's appliance and reads their estate; it merely declines to\r\n // upload it. The connection is the thing an unentitled tenant must not make.\r\n await requireEntitlementToScan(config, log, \"the one-shot Azure Cloud Posture scan\");\r\n\r\n\r\n const controller = new AbortController();\r\n const onSigint = (): void => {\r\n log(\"warn\", \"SIGINT received \u2014 shutting down\u2026\");\r\n controller.abort();\r\n };\r\n process.on(\"SIGINT\", onSigint);\r\n\r\n log(\"info\", `Azure Cloud Posture (CSPM) collector starting (dryRun=${dryRun}) \u2014 ARM tenant ${config.azureTenantId}`);\r\n\r\n try {\r\n const client = new ArmClient(\r\n {\r\n tenantId: config.azureTenantId,\r\n clientId: config.azureClientId,\r\n clientSecret: config.azureClientSecret,\r\n signal: controller.signal,\r\n },\r\n log,\r\n );\r\n\r\n const subs = await listAccessibleSubscriptions(client, config.azureSubscriptions);\r\n log(\r\n \"info\",\r\n `found ${subs.length} accessible subscription(s): ${subs.map((s) => `${s.displayName} (${s.subscriptionId})`).join(\", \")}`,\r\n );\r\n\r\n for (const sub of subs) {\r\n const stamp: AzureStamp = {\r\n collectorId: config.collectorId,\r\n tenantId: config.tenantId,\r\n siteId: config.siteId,\r\n tenantDirId: config.azureTenantId,\r\n };\r\n const inventory = await buildAzureInventory(client, sub, stamp, log);\r\n\r\n if (dryRun) {\r\n printSummary(inventory, log);\r\n continue;\r\n }\r\n\r\n log(\"info\", `pushing Azure inventory for subscription ${sub.subscriptionId} to ${config.controlPlaneUrl}`);\r\n const result = await pushAzureInventory(\r\n inventory,\r\n { controlPlaneUrl: config.controlPlaneUrl, apiKey: config.apiKey },\r\n log,\r\n controller.signal,\r\n );\r\n log(\"info\", `=== PUSH OK (subscription ${sub.subscriptionId}) ===`);\r\n if (result.snapshotId) log(\"info\", `snapshotId : ${result.snapshotId}`);\r\n if (result.version !== undefined) log(\"info\", `version : ${result.version}`);\r\n }\r\n } finally {\r\n process.off(\"SIGINT\", onSigint);\r\n }\r\n}\r\n\r\nmain().catch((err) => {\r\n console.error(`${new Date().toISOString()} ERROR ${errMsg(err)}`);\r\n process.exitCode = 1;\r\n});\r\n"],
|
|
5
|
-
"mappings": "
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
insecureDispatcher
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7ESBA5C5.js";
|
|
4
4
|
import {
|
|
5
5
|
DialPlanEntry,
|
|
6
6
|
UnityVoicemail,
|
|
@@ -13,10 +13,23 @@ import {
|
|
|
13
13
|
VoiceRegion,
|
|
14
14
|
VoiceSystem,
|
|
15
15
|
WebexCalling
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ALPMCXOV.js";
|
|
17
17
|
|
|
18
18
|
// src/voice/axl.ts
|
|
19
19
|
import { XMLParser } from "fast-xml-parser";
|
|
20
|
+
var AXL_REQUEST_TIMEOUT_MS = 12e4;
|
|
21
|
+
var RISPORT_REQUEST_TIMEOUT_MS = 6e4;
|
|
22
|
+
function requestSignal(signal, timeoutMs) {
|
|
23
|
+
const timeout = AbortSignal.timeout(timeoutMs);
|
|
24
|
+
return signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
25
|
+
}
|
|
26
|
+
function macFromCucmDeviceName(name) {
|
|
27
|
+
if (!name) return void 0;
|
|
28
|
+
const m = /^(?:SEP|ATA|AN|VGC)([0-9A-F]{12})$/i.exec(name.trim());
|
|
29
|
+
if (!m) return void 0;
|
|
30
|
+
const hex = m[1].toUpperCase();
|
|
31
|
+
return hex.match(/.{2}/g).join(":");
|
|
32
|
+
}
|
|
20
33
|
var noopLog = () => {
|
|
21
34
|
};
|
|
22
35
|
function xml(v) {
|
|
@@ -33,6 +46,11 @@ function buildListRequest(spec) {
|
|
|
33
46
|
function errMsg(err) {
|
|
34
47
|
return err instanceof Error ? err.message : String(err);
|
|
35
48
|
}
|
|
49
|
+
function isSchemaRejection(err) {
|
|
50
|
+
return /cvc-complex-type|cvc-|unmarshall?ing error|invalid content was found|not expected|returnedTags/i.test(
|
|
51
|
+
errMsg(err)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
36
54
|
function bodySnippet(text) {
|
|
37
55
|
const flat = text.replace(/\s+/g, " ").trim();
|
|
38
56
|
return flat.length > 120 ? `${flat.slice(0, 120)}\u2026` : flat;
|
|
@@ -124,25 +142,52 @@ var AxlClient = class {
|
|
|
124
142
|
const ret = asRecord(pick(firstResponse(body), "return"));
|
|
125
143
|
return asStr(ret.componentVersion) ?? asStr(pick(ret.componentVersion, "version"));
|
|
126
144
|
}
|
|
127
|
-
/**
|
|
145
|
+
/**
|
|
146
|
+
* listPhone — every registered/provisioned phone + soft-client device.
|
|
147
|
+
*
|
|
148
|
+
* ── TWO TAG SETS (2026-09-15) ───────────────────────────────────────────────
|
|
149
|
+
*
|
|
150
|
+
* `ownerUserName` and `loadInformation` (the configured firmware load) are
|
|
151
|
+
* both returned by `listPhone` and both have had a home in the contract
|
|
152
|
+
* (`VoiceEndpoint.ownerUser` / `.firmware`) since it was written — they were
|
|
153
|
+
* simply never asked for, so every phone the portal shows has no owner and no
|
|
154
|
+
* firmware. They are asked for now. But a returnedTag the cluster's schema
|
|
155
|
+
* does not know fails the WHOLE request with a schema fault — and listPhone is
|
|
156
|
+
* the one call that gives the estate its phones — so a schema rejection is
|
|
157
|
+
* retried once with the original six tags, and the retreat is logged, rather
|
|
158
|
+
* than letting two optional columns cost the endpoint list.
|
|
159
|
+
*/
|
|
128
160
|
async listPhones() {
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
})
|
|
134
|
-
)
|
|
161
|
+
const baseTags = ["name", "description", "product", "protocol", "devicePoolName", "callingSearchSpaceName"];
|
|
162
|
+
const extraTags = ["ownerUserName", "loadInformation"];
|
|
163
|
+
let body;
|
|
164
|
+
try {
|
|
165
|
+
body = await this.call(buildListRequest({ op: "listPhone", tags: [...baseTags, ...extraTags] }));
|
|
166
|
+
} catch (err) {
|
|
167
|
+
if (!isSchemaRejection(err)) throw err;
|
|
168
|
+
this.log(
|
|
169
|
+
"warn",
|
|
170
|
+
`listPhone: this cluster's AXL schema rejected the ${extraTags.join("/")} tags (${errMsg(err)}); retrying without them \u2014 phones in this snapshot carry no owner or firmware`
|
|
171
|
+
);
|
|
172
|
+
body = await this.call(buildListRequest({ op: "listPhone", tags: baseTags }));
|
|
173
|
+
}
|
|
135
174
|
const ret = asRecord(pick(firstResponse(body), "return"));
|
|
136
175
|
return toArray(ret.phone).map((raw) => {
|
|
137
176
|
const p = asRecord(raw);
|
|
177
|
+
const name = asStr(p.name);
|
|
178
|
+
const firmware = asStr(p.loadInformation);
|
|
179
|
+
const macAddress = macFromCucmDeviceName(name);
|
|
138
180
|
return {
|
|
139
181
|
uuid: asStr(p["@_uuid"]),
|
|
140
|
-
name
|
|
182
|
+
name,
|
|
141
183
|
description: asStr(p.description),
|
|
142
184
|
model: asStr(p.product),
|
|
143
185
|
protocol: asStr(p.protocol),
|
|
144
186
|
devicePoolName: asStr(p.devicePoolName),
|
|
145
|
-
callingSearchSpaceName: asStr(p.callingSearchSpaceName)
|
|
187
|
+
callingSearchSpaceName: asStr(p.callingSearchSpaceName),
|
|
188
|
+
...asStr(p.ownerUserName) ? { ownerUserName: asStr(p.ownerUserName) } : {},
|
|
189
|
+
...firmware ? { firmware } : {},
|
|
190
|
+
...macAddress ? { macAddress } : {}
|
|
146
191
|
};
|
|
147
192
|
});
|
|
148
193
|
}
|
|
@@ -943,7 +988,9 @@ var AxlClient = class {
|
|
|
943
988
|
Authorization: this.authHeader
|
|
944
989
|
},
|
|
945
990
|
body: envelope,
|
|
946
|
-
|
|
991
|
+
// Bounded: a hung RIS service is the best-effort field staying "unknown",
|
|
992
|
+
// not the whole build waiting on it. See RISPORT_REQUEST_TIMEOUT_MS.
|
|
993
|
+
signal: requestSignal(this.signal, RISPORT_REQUEST_TIMEOUT_MS)
|
|
947
994
|
});
|
|
948
995
|
const text = await res.text();
|
|
949
996
|
if (!res.ok) throw new Error(`RisPort70 request failed: HTTP ${res.status}`);
|
|
@@ -960,8 +1007,14 @@ var AxlClient = class {
|
|
|
960
1007
|
if (!name) continue;
|
|
961
1008
|
const statusRaw = (asStr(dev.Status) ?? "").toLowerCase();
|
|
962
1009
|
const status = statusRaw.includes("unregistered") ? "unregistered" : statusRaw.includes("registered") ? "registered" : "unknown";
|
|
963
|
-
const
|
|
964
|
-
|
|
1010
|
+
const ipItems = toArray(asRecord(dev.IPAddress).item);
|
|
1011
|
+
const ipAddress = asStr(pick(ipItems[0], "IP")) ?? asStr(pick(asRecord(dev.IPAddress), "IP"));
|
|
1012
|
+
const firmware = asStr(dev.ActiveLoadID);
|
|
1013
|
+
out.set(name, {
|
|
1014
|
+
status,
|
|
1015
|
+
...ipAddress ? { ipAddress } : {},
|
|
1016
|
+
...firmware ? { firmware } : {}
|
|
1017
|
+
});
|
|
965
1018
|
}
|
|
966
1019
|
}
|
|
967
1020
|
} catch (err) {
|
|
@@ -974,17 +1027,28 @@ var AxlClient = class {
|
|
|
974
1027
|
async call(innerXml) {
|
|
975
1028
|
if (this.signal?.aborted) throw new Error("AXL request aborted");
|
|
976
1029
|
const envelope = `<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/${xml(this.version)}"><soapenv:Body>${innerXml}</soapenv:Body></soapenv:Envelope>`;
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1030
|
+
let res;
|
|
1031
|
+
try {
|
|
1032
|
+
res = await fetch(this.base, {
|
|
1033
|
+
...this.tlsInit,
|
|
1034
|
+
method: "POST",
|
|
1035
|
+
headers: {
|
|
1036
|
+
"Content-Type": "text/xml; charset=utf-8",
|
|
1037
|
+
SOAPAction: `CUCM:DB ver=${this.version}`,
|
|
1038
|
+
Authorization: this.authHeader
|
|
1039
|
+
},
|
|
1040
|
+
body: envelope,
|
|
1041
|
+
// Job cancellation OR the per-request ceiling — see AXL_REQUEST_TIMEOUT_MS.
|
|
1042
|
+
signal: requestSignal(this.signal, AXL_REQUEST_TIMEOUT_MS)
|
|
1043
|
+
});
|
|
1044
|
+
} catch (err) {
|
|
1045
|
+
if (err instanceof Error && err.name === "TimeoutError") {
|
|
1046
|
+
throw new Error(
|
|
1047
|
+
`AXL at ${this.base} did not answer within ${Math.round(AXL_REQUEST_TIMEOUT_MS / 1e3)}s \u2014 the connection opened but no reply came back, so the node is reachable and something behind port 8443 is hung or the request is being dropped in flight (a stateful firewall, a CUCM mid-upgrade, a stopped Cisco AXL Web Service)`
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
throw err;
|
|
1051
|
+
}
|
|
988
1052
|
const text = await res.text();
|
|
989
1053
|
if (res.status === 401) {
|
|
990
1054
|
throw new Error(
|
|
@@ -1028,6 +1092,7 @@ var AxlClient = class {
|
|
|
1028
1092
|
// src/voice/cupi.ts
|
|
1029
1093
|
var noopLog2 = () => {
|
|
1030
1094
|
};
|
|
1095
|
+
var CUPI_REQUEST_TIMEOUT_MS = 3e4;
|
|
1031
1096
|
function errMsg2(err) {
|
|
1032
1097
|
return err instanceof Error ? err.message : String(err);
|
|
1033
1098
|
}
|
|
@@ -1093,12 +1158,23 @@ var CupiClient = class {
|
|
|
1093
1158
|
// --- transport -------------------------------------------------------------
|
|
1094
1159
|
async get(path) {
|
|
1095
1160
|
if (this.signal?.aborted) throw new Error("CUPI request aborted");
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1161
|
+
const timeout = AbortSignal.timeout(CUPI_REQUEST_TIMEOUT_MS);
|
|
1162
|
+
let res;
|
|
1163
|
+
try {
|
|
1164
|
+
res = await fetch(`${this.base}${path}`, {
|
|
1165
|
+
...this.tlsInit,
|
|
1166
|
+
method: "GET",
|
|
1167
|
+
headers: { Accept: "application/json", Authorization: this.authHeader },
|
|
1168
|
+
signal: this.signal ? AbortSignal.any([this.signal, timeout]) : timeout
|
|
1169
|
+
});
|
|
1170
|
+
} catch (err) {
|
|
1171
|
+
if (err instanceof Error && err.name === "TimeoutError") {
|
|
1172
|
+
throw new Error(
|
|
1173
|
+
`CUPI GET ${path} at ${this.base} did not answer within ${Math.round(CUPI_REQUEST_TIMEOUT_MS / 1e3)}s \u2014 the connection opened but no reply came back (Unity Connection hung, or the request dropped in flight)`
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1176
|
+
throw err;
|
|
1177
|
+
}
|
|
1102
1178
|
const text = await res.text();
|
|
1103
1179
|
if (!res.ok) {
|
|
1104
1180
|
throw new Error(`CUPI GET ${path} failed: HTTP ${res.status}: ${text.slice(0, 300)}`);
|
|
@@ -1116,6 +1192,7 @@ var CupiClient = class {
|
|
|
1116
1192
|
var noopLog3 = () => {
|
|
1117
1193
|
};
|
|
1118
1194
|
var BASE = "https://webexapis.com/v1/";
|
|
1195
|
+
var WEBEX_REQUEST_TIMEOUT_MS = 3e4;
|
|
1119
1196
|
function errMsg3(err) {
|
|
1120
1197
|
return err instanceof Error ? err.message : String(err);
|
|
1121
1198
|
}
|
|
@@ -1224,11 +1301,22 @@ var WebexClient = class {
|
|
|
1224
1301
|
}
|
|
1225
1302
|
async getPage(url) {
|
|
1226
1303
|
if (this.signal?.aborted) throw new Error("Webex request aborted");
|
|
1227
|
-
const
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1304
|
+
const timeout = AbortSignal.timeout(WEBEX_REQUEST_TIMEOUT_MS);
|
|
1305
|
+
let res;
|
|
1306
|
+
try {
|
|
1307
|
+
res = await fetch(url, {
|
|
1308
|
+
method: "GET",
|
|
1309
|
+
headers: { Accept: "application/json", Authorization: `Bearer ${this.token}` },
|
|
1310
|
+
signal: this.signal ? AbortSignal.any([this.signal, timeout]) : timeout
|
|
1311
|
+
});
|
|
1312
|
+
} catch (err) {
|
|
1313
|
+
if (err instanceof Error && err.name === "TimeoutError") {
|
|
1314
|
+
throw new Error(
|
|
1315
|
+
`Webex GET ${url} did not answer within ${Math.round(WEBEX_REQUEST_TIMEOUT_MS / 1e3)}s \u2014 the connection opened but no reply came back (a Webex outage, or an egress proxy holding the request)`
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
throw err;
|
|
1319
|
+
}
|
|
1232
1320
|
const text = await res.text();
|
|
1233
1321
|
if (!res.ok) {
|
|
1234
1322
|
throw new Error(`Webex GET ${url} failed: HTTP ${res.status}: ${text.slice(0, 300)}`);
|
|
@@ -1678,9 +1766,14 @@ async function buildCucmInventory(client, host, stamp, log = noopLog4) {
|
|
|
1678
1766
|
callingSearchSpace: p.callingSearchSpaceName ?? null,
|
|
1679
1767
|
registrationStatus: reg?.status ?? "unknown",
|
|
1680
1768
|
ownerUser: p.ownerUserName ?? null,
|
|
1769
|
+
// Derived from the device name by listPhones (2026-09-15) — the join key
|
|
1770
|
+
// the plane's voice_endpoints MAC index exists for; it was always null.
|
|
1681
1771
|
macAddress: p.macAddress ?? null,
|
|
1682
1772
|
ipAddress: reg?.ipAddress ?? p.ipAddress ?? null,
|
|
1683
|
-
|
|
1773
|
+
// The load the phone is RUNNING (RisPort ActiveLoadID) over the load it is
|
|
1774
|
+
// CONFIGURED for (listPhone loadInformation, blank when the device pool's
|
|
1775
|
+
// default applies) — the first is what an upgrade audit needs.
|
|
1776
|
+
firmware: reg?.firmware ?? p.firmware ?? null
|
|
1684
1777
|
});
|
|
1685
1778
|
});
|
|
1686
1779
|
const dialPlan = [
|
|
@@ -1951,4 +2044,4 @@ export {
|
|
|
1951
2044
|
buildUnityInventory,
|
|
1952
2045
|
buildWebexInventory
|
|
1953
2046
|
};
|
|
1954
|
-
//# sourceMappingURL=chunk-
|
|
2047
|
+
//# sourceMappingURL=chunk-25TNYVF5.js.map
|