@x12i/map-store-client 0.1.3 → 0.1.5
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/README.md +155 -1
- package/dist/estate/analytics.d.ts +50 -0
- package/dist/estate/analytics.d.ts.map +1 -0
- package/dist/estate/analytics.js +128 -0
- package/dist/estate/analytics.js.map +1 -0
- package/dist/estate/census.d.ts +123 -0
- package/dist/estate/census.d.ts.map +1 -0
- package/dist/estate/census.js +275 -0
- package/dist/estate/census.js.map +1 -0
- package/dist/estate/client.d.ts +66 -0
- package/dist/estate/client.d.ts.map +1 -0
- package/dist/estate/client.js +10 -0
- package/dist/estate/client.js.map +1 -0
- package/dist/estate/content.d.ts +91 -0
- package/dist/estate/content.d.ts.map +1 -0
- package/dist/estate/content.js +251 -0
- package/dist/estate/content.js.map +1 -0
- package/dist/estate/contract.d.ts +76 -0
- package/dist/estate/contract.d.ts.map +1 -0
- package/dist/estate/contract.js +291 -0
- package/dist/estate/contract.js.map +1 -0
- package/dist/estate/decisions.d.ts +32 -0
- package/dist/estate/decisions.d.ts.map +1 -0
- package/dist/estate/decisions.js +113 -0
- package/dist/estate/decisions.js.map +1 -0
- package/dist/estate/ids.d.ts +3 -0
- package/dist/estate/ids.d.ts.map +1 -0
- package/dist/estate/ids.js +6 -0
- package/dist/estate/ids.js.map +1 -0
- package/dist/estate/index.d.ts +30 -0
- package/dist/estate/index.d.ts.map +1 -0
- package/dist/estate/index.js +19 -0
- package/dist/estate/index.js.map +1 -0
- package/dist/estate/localStories.d.ts +28 -0
- package/dist/estate/localStories.d.ts.map +1 -0
- package/dist/estate/localStories.js +980 -0
- package/dist/estate/localStories.js.map +1 -0
- package/dist/estate/pack.d.ts +45 -0
- package/dist/estate/pack.d.ts.map +1 -0
- package/dist/estate/pack.js +83 -0
- package/dist/estate/pack.js.map +1 -0
- package/dist/estate/predictedAttack.d.ts +79 -0
- package/dist/estate/predictedAttack.d.ts.map +1 -0
- package/dist/estate/predictedAttack.js +321 -0
- package/dist/estate/predictedAttack.js.map +1 -0
- package/dist/estate/readState.d.ts +33 -0
- package/dist/estate/readState.d.ts.map +1 -0
- package/dist/estate/readState.js +58 -0
- package/dist/estate/readState.js.map +1 -0
- package/dist/estate/stories.d.ts +93 -0
- package/dist/estate/stories.d.ts.map +1 -0
- package/dist/estate/stories.js +224 -0
- package/dist/estate/stories.js.map +1 -0
- package/dist/estate/verdictReason.d.ts +17 -0
- package/dist/estate/verdictReason.d.ts.map +1 -0
- package/dist/estate/verdictReason.js +49 -0
- package/dist/estate/verdictReason.js.map +1 -0
- package/dist/fetch.d.ts +2 -0
- package/dist/fetch.d.ts.map +1 -1
- package/dist/fetch.js +13 -3
- package/dist/fetch.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/queries.d.ts +98 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +180 -0
- package/dist/queries.js.map +1 -0
- package/package.json +14 -1
package/README.md
CHANGED
|
@@ -36,4 +36,158 @@ import { fetchBootstrap, walkWorkingPages, mapFetch } from '@x12i/map-store-clie
|
|
|
36
36
|
import { asRecord } from '@x12i/map-store-client/util';
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Subpath exports: `/util`, `/types`, `/errors`, `/products`, `/bagCatalog`, `/attackSurfaces`, `/packets`.
|
|
39
|
+
Subpath exports: `/util`, `/types`, `/errors`, `/products`, `/bagCatalog`, `/attackSurfaces`, `/packets`, `/estate`.
|
|
40
|
+
|
|
41
|
+
`queryFindings` and `fetchVulnerabilitiesBriefing` are exported from the package root. They are the two map-store routes that are POST queries rather than working products.
|
|
42
|
+
|
|
43
|
+
## The `estate` entry
|
|
44
|
+
|
|
45
|
+
`@x12i/map-store-client/estate` holds the reads that do not go through map-store: the Memorix content lists, the census and analytics records, the triage decisions, and the story pipeline. It takes the Memorix read client you build yourself, so it adds no dependency on `@x12i/memorix-client-api-client`.
|
|
46
|
+
|
|
47
|
+
Drawing stories needs `@x12i/storyflowix` at version 1.2.0 or newer. It is an optional peer: install it when you import `estate`. The rest of the package does not use it.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { createMemorixReadClient } from '@x12i/memorix-client-api-client';
|
|
51
|
+
import { listContent, PREDICTED_ATTACK_LIST, isPredictedAttack } from '@x12i/map-store-client/estate';
|
|
52
|
+
|
|
53
|
+
const memorix = createMemorixReadClient({
|
|
54
|
+
baseUrl: 'http://memorix-client.invalid', // rewritten onto the /memorix-client proxy
|
|
55
|
+
orgId: 'tgi',
|
|
56
|
+
agentIds: ['network-synapix'],
|
|
57
|
+
caller: 'your-app',
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// One list per object type the contract declares, markdown included, up to 20 pages of 200.
|
|
61
|
+
const attacks = (
|
|
62
|
+
await Promise.all(
|
|
63
|
+
PREDICTED_ATTACK_LIST.objectTypes.map((objectType) =>
|
|
64
|
+
listContent(memorix.data, { objectType, contentType: 'predicted-attack', includeMarkdown: true })
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
).flat().filter((row) => isPredictedAttack(row.data));
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The browser reaches the Memorix client API through your proxy at `/memorix-client`, with `x-memorix-org-id`, `x-memorix-agent-ids`, and `x-memorix-caller`. Story functions run through your proxy at `/skill-api` (`runStoryFunction`, agent `network-synapix`). Neither call goes to Memorix directly.
|
|
71
|
+
|
|
72
|
+
## What each page reads
|
|
73
|
+
|
|
74
|
+
Pins (`snapshotSetId`, `analysisSnapshotId`) come from `fetchBootstrap` and are passed as `expectedPair` on walks. They are never sent back as URL pins. A working product that pages returns `pageVariants`; `walkWorkingPages` fetches each of them.
|
|
75
|
+
|
|
76
|
+
### Once per session, shared by every page
|
|
77
|
+
|
|
78
|
+
| Read | Call |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `GET /map-store/v1/health` | `fetchHealth` |
|
|
81
|
+
| `GET /map-store/v1/bootstrap` | `fetchBootstrap` |
|
|
82
|
+
| `working/estate-object-inventory`, all pages | `walkWorkingPages('estate-object-inventory', parseInventoryObject)` |
|
|
83
|
+
| `working/object-pre-ai-context`, all pages | `walkWorkingPages('object-pre-ai-context', …)` |
|
|
84
|
+
| `working/findings-query`, entry variant `open-vuln` | `walkWorkingPages('findings-query', …)`. If no row carries a CVE, fall back to `investigation-assessment` |
|
|
85
|
+
| `working/cve-catalog`, all pages | `walkWorkingPages('cve-catalog', …)` |
|
|
86
|
+
| `working/source-capability` | `fetchWorkingProduct('source-capability')` |
|
|
87
|
+
| `working/object-classification-census` | `fetchWorkingProduct('object-classification-census')` |
|
|
88
|
+
| `working/attack-surfaces` and `working/vpn-sites` | `fetchAttackSurfacesIndex`, `fetchVpnSitesIndex` |
|
|
89
|
+
| `working/open-questions` | `fetchWorkingProduct('open-questions')` |
|
|
90
|
+
| `working/known-unknowns-summary`, falling back to `known-unknowns` | `fetchWorkingProduct` |
|
|
91
|
+
| `working/reachability-claims-summary` | `fetchWorkingProduct('reachability-claims-summary')` |
|
|
92
|
+
| `working/attack-path-assessments` | `fetchWorkingProduct('attack-path-assessments')` |
|
|
93
|
+
| `working/alerts-query?variant=all` and `?variant=relevant` | `fetchWorkingProduct('alerts-query', 'all' \| 'relevant')` |
|
|
94
|
+
| `working/alerts-briefing` | `fetchWorkingProduct('alerts-briefing')` |
|
|
95
|
+
| `working/live-bootstrap` | `fetchLiveBootstrap` |
|
|
96
|
+
| `working/prospective-capability` | `fetchWorkingProduct('prospective-capability')` |
|
|
97
|
+
| `security-map` / `estate-analytics` / `working/estate-analytics`, discriminator `publication` | `readEstateAnalytics` |
|
|
98
|
+
| Connector census | `readSourceCensus` |
|
|
99
|
+
| Ranked CVE hubs | `fetchVulnerabilitiesBriefing` |
|
|
100
|
+
|
|
101
|
+
When `estateAnalyticsSuppliesTallies` is false, the triage counts are not on that record. Count them from `TRIAGE_TALLY_LISTS` with `listContent`: `finding` / `triage` (up to 400 pages) and `endpoint-asset` / `triage` (up to 20).
|
|
102
|
+
|
|
103
|
+
### Data sources
|
|
104
|
+
|
|
105
|
+
**Asset inventory** (`/assets`, plus `/assets/vulnerable`, `/endpoints`, `/identified`, `/unidentified`)
|
|
106
|
+
|
|
107
|
+
- The walked inventory, identities, and findings, and the CVE catalog for the severity dots.
|
|
108
|
+
- `loadTier0Census(data, 'asset')` — `security-map` / `tier0-analytics` / `working/asset-census`, discriminator `asset-census`.
|
|
109
|
+
- `listContent` of `endpoint-asset` / `triage`.
|
|
110
|
+
- A drill-down by decision uses `loadAssetDecisionIds` instead of the full list. It filters `data.decisionType=asset-triage` plus `data.urgency`, `data.decision=NOT_APPLICABLE`, or `data.assessmentState`. `loadAssetUrgencies` maps each asset to its urgency.
|
|
111
|
+
- `walkWorkingPages('attack-path-assessments', …)` for the zone reach tier. A row's `toZoneId` plus a `hypothesis` containing "deny" marks the zone cleared; any other hypothesis marks it possible.
|
|
112
|
+
|
|
113
|
+
**Networks** (`/networks`)
|
|
114
|
+
|
|
115
|
+
- Subnets and zones are derived from the walked inventory. No separate read.
|
|
116
|
+
- The attack-surfaces index, the VPN-sites index, and `reachability-claims-summary`.
|
|
117
|
+
- `readEstateAnalytics`.
|
|
118
|
+
|
|
119
|
+
**Vulnerability catalog** (`/vulnerabilities`, plus `/cves`, `/kev`, `/exploitable`, `/findings`)
|
|
120
|
+
|
|
121
|
+
- The walked findings joined to the inventory, the CVE catalog, and `fetchVulnerabilitiesBriefing`.
|
|
122
|
+
- `queryFindings` for scanner severity, CVSS, KEV, EPSS, and the vendor description. Join on finding id and on CVE id.
|
|
123
|
+
- `loadTier0Census(data, 'vulnerability')` — `working/vulnerability-census`.
|
|
124
|
+
- `listContent` of `finding` / `triage`, up to 120 pages.
|
|
125
|
+
- One finding's decision: `listRecordContent` of `finding` / `triage` with `discriminator: { field: 'decisionType', value: 'finding-triage' }`. `triageInstance(objectType)` names the instance.
|
|
126
|
+
- The CVE panel's analyses: `listContent` of `finding` / `analysis` filtered by `data.cveId`.
|
|
127
|
+
- A verdict line: `listRecordContent` of `finding` / `verdict-reason` for that record id, with markdown.
|
|
128
|
+
|
|
129
|
+
**Recent alerts** (`/alerts`)
|
|
130
|
+
|
|
131
|
+
- `source-capability`, `alerts-query` (`all` and `relevant`), and `alerts-briefing`.
|
|
132
|
+
- The walked inventory, for the asset names.
|
|
133
|
+
|
|
134
|
+
### Analysis
|
|
135
|
+
|
|
136
|
+
Both pages list one content type on every object type that declares it (`PREDICTED_ATTACK_LIST`, `MITIGATION_LIST`), with markdown, up to 20 pages of 200.
|
|
137
|
+
|
|
138
|
+
**Predicted attacks** (`/predicted-attacks`)
|
|
139
|
+
|
|
140
|
+
- `listContent` of `predicted-attack` on `finding`, `endpoint-asset`, `alert`, `network-device`, and `network-zone`. Keep a row when `isPredictedAttack` is true (`data.predictionType` is `finding-attack`, `asset-attack`, `alert-attack`, `device-attack`, or `zone-attack`).
|
|
141
|
+
- Fields read: `summary`, `scenarioSupport`, `score`, `asOf`, and `actions[]` (`action`, `phase`, `technique`, `assets`, `controls`, `chance`). `steps[]` is the fallback when no action names a technique.
|
|
142
|
+
|
|
143
|
+
**Mitigations** (`/mitigations`)
|
|
144
|
+
|
|
145
|
+
- `listContent` of `mitigation` on `finding`, `endpoint-asset`, `alert`, and `network-zone`. Keep a row when `isMitigationPlan` is true (`data.mitigationType` is `response-plan` and `data.plan.schemaVersion` is `response-plan/v1`).
|
|
146
|
+
- Fields read: `planStatus`, `summary`, `plan.subject.displayName`, and `plan.recommendations[]` (`title`, `readiness`, `conditions[].statement`, `steps`, `proposedOwnerRole`, `why`, `targetEffect`).
|
|
147
|
+
|
|
148
|
+
**Subject names.** `inventoryDisplayName(data, objectType, recordId)` reads `data.displayName` from that subject's `inventory` row.
|
|
149
|
+
|
|
150
|
+
**The diagram.** `predictionStepsFrom(row)` reads the steps, and `predictionDiagram(source)` builds the Storyflowix input. Every step carrying a technique id uses the `attack-path` template. Otherwise it uses `predicted-attack`, which `predictedAttackReady()` checks for in the installed Storyflowix. No steps, or `scenarioSupport` of `INSUFFICIENT_EVIDENCE`, produces the withheld block. No further request is made.
|
|
151
|
+
|
|
152
|
+
### Exposure
|
|
153
|
+
|
|
154
|
+
**Attack surfaces** (`/attack-surfaces/entries`, `/attack-surfaces/shared`)
|
|
155
|
+
|
|
156
|
+
- `fetchAttackSurfacesIndex`, then `fetchAttackSurfaceDossier(surfaceId)` per surface. Read `epistemicBuckets`, `destZones`, `instances`, and `honesty`.
|
|
157
|
+
|
|
158
|
+
**Exploitability assessments** (`/epa`)
|
|
159
|
+
|
|
160
|
+
- `walkWorkingPages('object-exploitability-assessments', …)`.
|
|
161
|
+
- `fetchBootstrap().assessmentCoverage` and `loadTier0Census(data, 'asset')`.
|
|
162
|
+
|
|
163
|
+
**VPN sites** (`/vpn-sites/sites`, `/vpn-sites/shared`)
|
|
164
|
+
|
|
165
|
+
- `fetchVpnSitesIndex`, then `fetchVpnSiteDossier(siteId)` per site. Read `peerPublicIp`, `remoteInnerOrigins`, `localInnerSelectors`, `nativeAcceptDestZones`, and `epistemicBuckets`.
|
|
166
|
+
|
|
167
|
+
**Reachability** (`/reachability`)
|
|
168
|
+
|
|
169
|
+
- `reachability-claims-summary`, the walked inventory, and `loadTier0Census(data, 'asset')`.
|
|
170
|
+
- `listContent` of `endpoint-asset` / `reachability-analysis`.
|
|
171
|
+
|
|
172
|
+
The estate census board, where a page shows one, is `loadTier0Census(data, 'estate')` — `working/estate-census`.
|
|
173
|
+
|
|
174
|
+
### Opening one record
|
|
175
|
+
|
|
176
|
+
**Context diagram.** An asset reads `listRecordContent` of `triage` with `triageInstance(objectType)`, and of `analysis`, using the `asset-exposure` and `zone-candidate` rows. A finding reads `finding` / `triage` with `finding-triage`, and `finding` / `analysis`, using the `vulnerability` or `detection` row.
|
|
177
|
+
|
|
178
|
+
**Story.**
|
|
179
|
+
|
|
180
|
+
1. `loadStoryTabs(catalog, objectType)` — `GET /api/v1/object-types/{type}` for `functions[]`, and `GET /api/v1/object-types/{type}/content-types/story` for the presentation labels.
|
|
181
|
+
2. `readStoredStory(data, objectType, recordId, template)` — the stored `story` row. Render `input` with Storyflowix and show `text`, `facts`, and `gaps`.
|
|
182
|
+
3. When nothing is stored, `runStoryFunction(functionId, objectType, recordId)` — `POST /skill-api/api/v1/agent-functions/agents/network-synapix/functions/{id}/run` with `{ objectType, recordId }`. Render `result.storyInput`.
|
|
183
|
+
4. When the run stops, `loadRecordContents(catalog, objectType, recordId)` then `buildLocalStory(template, objectType, contents)`. One `listRecords` call with `representation: 'both'`.
|
|
184
|
+
|
|
185
|
+
`declaringObjectTypes(contentType)` and `skillsContentTypes(objectType)` are the contract behind the lists: which object types declare which content types, and which discriminator values a row may carry. `requiredDiscriminator` reads the installed pack and names the instance a single-record read must send, so the API does not reject it with `READ_DISCRIMINATOR_REQUIRED`.
|
|
186
|
+
|
|
187
|
+
### Read states
|
|
188
|
+
|
|
189
|
+
`classifyReadError` and `isPlaceholderRecord` sort a Memorix answer into `declared-empty` (404), `undeclared` (`400 ROUTE_UNKNOWN_CONTENT_TYPE`), `placeholder` (a body whose `disposition` is `empty-from-frozen-bag` or `unavailable`), or `error`. `UNPUBLISHED_BY_AGENT` is the sentence for the last two that are not failures.
|
|
190
|
+
|
|
191
|
+
`readContentResult`, `listContentResult`, `readEstateAnalyticsResult`, `loadTier0CensusResult`, and `readStoredStoryResult` return `{ state, data }`. The older functions still return the row or `null`. A placeholder land is `null` from those, not a rollup. `verdictReasonView(rows, verdict)` is the finding-drawer text: summary, evidence, and gaps, with a failed skill run dropped.
|
|
192
|
+
|
|
193
|
+
`CONSUMER_MANIFEST` is every `{ objectType, contentType }` these pages read, including `finding` / `verdict-reason`, `story`, and `tier0-analytics`. Compare it with the installed pack to list what the agent has not declared.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The materialized estate rollup, and the connector census.
|
|
3
|
+
* Both are single Memorix reads. Neither is a working product.
|
|
4
|
+
*/
|
|
5
|
+
import type { EstateAnalyticsApi, EstateData } from './client';
|
|
6
|
+
import { type ReadResult } from './readState';
|
|
7
|
+
export declare const ESTATE_ANALYTICS_TARGET: {
|
|
8
|
+
readonly objectType: "security-map";
|
|
9
|
+
readonly contentType: "estate-analytics";
|
|
10
|
+
readonly recordId: "working/estate-analytics";
|
|
11
|
+
readonly discriminatorValue: "publication";
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* `data` of `working/estate-analytics`.
|
|
15
|
+
* `placeholder` is a land such as `empty-from-frozen-bag`: the address is taken and the rollup is not published.
|
|
16
|
+
* `declared-empty` is a 404. `undeclared` means the pack does not register the content type.
|
|
17
|
+
*/
|
|
18
|
+
export declare function readEstateAnalyticsResult(client: EstateData, signal?: AbortSignal): Promise<ReadResult<Record<string, unknown>>>;
|
|
19
|
+
/**
|
|
20
|
+
* `data` of `working/estate-analytics`.
|
|
21
|
+
* Null when the record is missing, the content type is not registered, or the
|
|
22
|
+
* body is a placeholder land. Any other error is thrown.
|
|
23
|
+
* Use {@link readEstateAnalyticsResult} to tell those apart.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readEstateAnalytics(client: EstateData, signal?: AbortSignal): Promise<Record<string, unknown> | null>;
|
|
26
|
+
/**
|
|
27
|
+
* True when the estate-analytics record already carries the triage counts:
|
|
28
|
+
* finding decisions, asset decisions, priority bands, findings triaged,
|
|
29
|
+
* and both exploitability measures.
|
|
30
|
+
* When this is false, count them from the triage lists instead
|
|
31
|
+
* (`finding` / `triage` and `endpoint-asset` / `triage`). Nothing else is walked.
|
|
32
|
+
*/
|
|
33
|
+
export declare function estateAnalyticsSuppliesTallies(raw: unknown): boolean;
|
|
34
|
+
/** Lists to count when {@link estateAnalyticsSuppliesTallies} is false. */
|
|
35
|
+
export declare const TRIAGE_TALLY_LISTS: readonly [{
|
|
36
|
+
readonly objectType: "finding";
|
|
37
|
+
readonly contentType: "triage";
|
|
38
|
+
readonly maxPages: 400;
|
|
39
|
+
}, {
|
|
40
|
+
readonly objectType: "endpoint-asset";
|
|
41
|
+
readonly contentType: "triage";
|
|
42
|
+
readonly maxPages: 20;
|
|
43
|
+
}];
|
|
44
|
+
/**
|
|
45
|
+
* Connector census from `analytics.sourceCensus`.
|
|
46
|
+
* Null when the call fails or the body has no `status` and `subjects`.
|
|
47
|
+
* A `status` other than `live` is returned as-is and is not ready to render.
|
|
48
|
+
*/
|
|
49
|
+
export declare function readSourceCensus(analytics: EstateAnalyticsApi, signal?: AbortSignal): Promise<Record<string, unknown> | null>;
|
|
50
|
+
//# sourceMappingURL=analytics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/estate/analytics.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE/D,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtF,eAAO,MAAM,uBAAuB;;;;;CAK1B,CAAC;AAEX;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,UAAU,EAClB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAc9C;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,UAAU,EAClB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAIzC;AAsBD;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAsBpE;AAED,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB;;;;;;;;EAGrB,CAAC;AAEX;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,kBAAkB,EAC7B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CASzC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The materialized estate rollup, and the connector census.
|
|
3
|
+
* Both are single Memorix reads. Neither is a working product.
|
|
4
|
+
*/
|
|
5
|
+
import { asRecord } from '../util';
|
|
6
|
+
import { contentData } from './content';
|
|
7
|
+
import { classifyReadError, isPlaceholderRecord } from './readState';
|
|
8
|
+
export const ESTATE_ANALYTICS_TARGET = {
|
|
9
|
+
objectType: 'security-map',
|
|
10
|
+
contentType: 'estate-analytics',
|
|
11
|
+
recordId: 'working/estate-analytics',
|
|
12
|
+
discriminatorValue: 'publication',
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* `data` of `working/estate-analytics`.
|
|
16
|
+
* `placeholder` is a land such as `empty-from-frozen-bag`: the address is taken and the rollup is not published.
|
|
17
|
+
* `declared-empty` is a 404. `undeclared` means the pack does not register the content type.
|
|
18
|
+
*/
|
|
19
|
+
export async function readEstateAnalyticsResult(client, signal) {
|
|
20
|
+
if (signal?.aborted)
|
|
21
|
+
return { state: 'declared-empty', data: null };
|
|
22
|
+
try {
|
|
23
|
+
const page = await client.getContent({ ...ESTATE_ANALYTICS_TARGET });
|
|
24
|
+
if (signal?.aborted)
|
|
25
|
+
return { state: 'declared-empty', data: null };
|
|
26
|
+
const data = contentData(page);
|
|
27
|
+
if (!data)
|
|
28
|
+
return { state: 'declared-empty', data: null };
|
|
29
|
+
if (isPlaceholderRecord(data))
|
|
30
|
+
return { state: 'placeholder', data: null };
|
|
31
|
+
return { state: 'ready', data };
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const kind = classifyReadError(err);
|
|
35
|
+
if (kind === 'error')
|
|
36
|
+
return { state: 'error', data: null, error: err };
|
|
37
|
+
return { state: kind, data: null };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* `data` of `working/estate-analytics`.
|
|
42
|
+
* Null when the record is missing, the content type is not registered, or the
|
|
43
|
+
* body is a placeholder land. Any other error is thrown.
|
|
44
|
+
* Use {@link readEstateAnalyticsResult} to tell those apart.
|
|
45
|
+
*/
|
|
46
|
+
export async function readEstateAnalytics(client, signal) {
|
|
47
|
+
const result = await readEstateAnalyticsResult(client, signal);
|
|
48
|
+
if (result.state === 'error')
|
|
49
|
+
throw result.error;
|
|
50
|
+
return result.data;
|
|
51
|
+
}
|
|
52
|
+
const TRIAGE_DECISIONS = ['FIX_NOW', 'PATCH_NOW', 'MITIGATE', 'ACCEPT_RISK'];
|
|
53
|
+
function readCount(leaf) {
|
|
54
|
+
if (typeof leaf === 'number' && Number.isFinite(leaf))
|
|
55
|
+
return leaf;
|
|
56
|
+
const rec = asRecord(leaf);
|
|
57
|
+
if (!rec || rec.produced === false)
|
|
58
|
+
return null;
|
|
59
|
+
const raw = rec.value ?? rec.count;
|
|
60
|
+
return typeof raw === 'number' && Number.isFinite(raw) ? raw : null;
|
|
61
|
+
}
|
|
62
|
+
function metricProduced(root, key) {
|
|
63
|
+
if (!root)
|
|
64
|
+
return false;
|
|
65
|
+
const direct = asRecord(root[key]);
|
|
66
|
+
if (direct?.produced === true && typeof direct.value === 'number')
|
|
67
|
+
return true;
|
|
68
|
+
const [section, name] = key.split('.');
|
|
69
|
+
const bag = asRecord(root[section ?? '']);
|
|
70
|
+
const nested = name ? asRecord(bag?.[name]) : null;
|
|
71
|
+
return nested?.produced === true && typeof nested.value === 'number';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* True when the estate-analytics record already carries the triage counts:
|
|
75
|
+
* finding decisions, asset decisions, priority bands, findings triaged,
|
|
76
|
+
* and both exploitability measures.
|
|
77
|
+
* When this is false, count them from the triage lists instead
|
|
78
|
+
* (`finding` / `triage` and `endpoint-asset` / `triage`). Nothing else is walked.
|
|
79
|
+
*/
|
|
80
|
+
export function estateAnalyticsSuppliesTallies(raw) {
|
|
81
|
+
const top = asRecord(raw);
|
|
82
|
+
const groups = asRecord(top?.groups);
|
|
83
|
+
if (!top || !groups)
|
|
84
|
+
return false;
|
|
85
|
+
const bagReady = (group) => {
|
|
86
|
+
if (!group || group.produced === false)
|
|
87
|
+
return false;
|
|
88
|
+
const bag = asRecord(group.buckets) ?? group;
|
|
89
|
+
return TRIAGE_DECISIONS.every((code) => readCount(bag[code] ?? bag[code.toLowerCase()]) != null);
|
|
90
|
+
};
|
|
91
|
+
if (!bagReady(asRecord(groups.findingDecisions)) || !bagReady(asRecord(groups.assetDecisions)))
|
|
92
|
+
return false;
|
|
93
|
+
const priority = asRecord(groups.priorityBands);
|
|
94
|
+
if (!priority || priority.produced === false)
|
|
95
|
+
return false;
|
|
96
|
+
if (readCount(priority.high) == null || readCount(priority.medium) == null || readCount(priority.low) == null) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
const measures = asRecord(top.measures);
|
|
100
|
+
return ((metricProduced(measures, 'exploitability.reviewed') || metricProduced(top, 'exploitability.reviewed')) &&
|
|
101
|
+
(metricProduced(measures, 'exploitability.highOrCritical') ||
|
|
102
|
+
metricProduced(top, 'exploitability.highOrCritical')) &&
|
|
103
|
+
(metricProduced(measures, 'planned.findingsTriaged') || metricProduced(top, 'planned.findingsTriaged')));
|
|
104
|
+
}
|
|
105
|
+
/** Lists to count when {@link estateAnalyticsSuppliesTallies} is false. */
|
|
106
|
+
export const TRIAGE_TALLY_LISTS = [
|
|
107
|
+
{ objectType: 'finding', contentType: 'triage', maxPages: 400 },
|
|
108
|
+
{ objectType: 'endpoint-asset', contentType: 'triage', maxPages: 20 },
|
|
109
|
+
];
|
|
110
|
+
/**
|
|
111
|
+
* Connector census from `analytics.sourceCensus`.
|
|
112
|
+
* Null when the call fails or the body has no `status` and `subjects`.
|
|
113
|
+
* A `status` other than `live` is returned as-is and is not ready to render.
|
|
114
|
+
*/
|
|
115
|
+
export async function readSourceCensus(analytics, signal) {
|
|
116
|
+
try {
|
|
117
|
+
const body = asRecord(await analytics.sourceCensus());
|
|
118
|
+
if (signal?.aborted)
|
|
119
|
+
return null;
|
|
120
|
+
if (!body || typeof body.status !== 'string' || !Array.isArray(body.subjects))
|
|
121
|
+
return null;
|
|
122
|
+
return body;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=analytics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../src/estate/analytics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-0 census records. Three processes count published lander rows and each
|
|
3
|
+
* save one content record. They do not read AI products. They are not
|
|
4
|
+
* `estate-analytics` and they are not a bag total.
|
|
5
|
+
*
|
|
6
|
+
* One GET per board, after `working/bootstrap` has pinned the session:
|
|
7
|
+
* `security-map` / `tier0-analytics` / `working/{vulnerability,asset,estate}-census`.
|
|
8
|
+
* `data.kind` selects the record.
|
|
9
|
+
*
|
|
10
|
+
* `produced: true` and `value: 0` is a finished empty count.
|
|
11
|
+
* `produced: false` and `value: 0` means that source was not read.
|
|
12
|
+
* A missing field is the bucket `absent`. A missing KEV flag is `absent`, not `false`.
|
|
13
|
+
*/
|
|
14
|
+
import type { EstateData } from './client';
|
|
15
|
+
import { type ReadResult } from './readState';
|
|
16
|
+
export type Tier0Metric = {
|
|
17
|
+
value: number;
|
|
18
|
+
produced: boolean;
|
|
19
|
+
};
|
|
20
|
+
export type MetricMap = Record<string, Tier0Metric>;
|
|
21
|
+
export type VulnerabilityCensusRow = {
|
|
22
|
+
id: string;
|
|
23
|
+
cveId: string | null;
|
|
24
|
+
label: string | null;
|
|
25
|
+
affectedAssets: number | null;
|
|
26
|
+
findings: number | null;
|
|
27
|
+
};
|
|
28
|
+
export type AssetCensusRow = {
|
|
29
|
+
id: string;
|
|
30
|
+
label: string | null;
|
|
31
|
+
findings: number | null;
|
|
32
|
+
distinctCves: number | null;
|
|
33
|
+
};
|
|
34
|
+
export type VulnerabilityCensus = {
|
|
35
|
+
kind: 'vulnerability-census';
|
|
36
|
+
totals: {
|
|
37
|
+
findings: Tier0Metric;
|
|
38
|
+
vulnerabilities: Tier0Metric;
|
|
39
|
+
distinctCves: Tier0Metric;
|
|
40
|
+
};
|
|
41
|
+
rows: VulnerabilityCensusRow[];
|
|
42
|
+
groups: Record<string, MetricMap>;
|
|
43
|
+
};
|
|
44
|
+
export type AssetCensus = {
|
|
45
|
+
kind: 'asset-census';
|
|
46
|
+
totals: {
|
|
47
|
+
assets: Tier0Metric;
|
|
48
|
+
findings: Tier0Metric;
|
|
49
|
+
};
|
|
50
|
+
rows: AssetCensusRow[];
|
|
51
|
+
groups: Record<string, MetricMap>;
|
|
52
|
+
};
|
|
53
|
+
export type EstateCensus = {
|
|
54
|
+
kind: 'estate-census';
|
|
55
|
+
totals: {
|
|
56
|
+
subjects: {
|
|
57
|
+
endpointAssets: Tier0Metric;
|
|
58
|
+
findings: Tier0Metric;
|
|
59
|
+
alerts: Tier0Metric;
|
|
60
|
+
zones: Tier0Metric;
|
|
61
|
+
devices: Tier0Metric;
|
|
62
|
+
unresolvedSubjects: Tier0Metric;
|
|
63
|
+
};
|
|
64
|
+
bags: {
|
|
65
|
+
hypothesizedPaths: Tier0Metric;
|
|
66
|
+
reachabilityClaims: Tier0Metric;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
rows: readonly [];
|
|
70
|
+
groups: Record<string, MetricMap>;
|
|
71
|
+
};
|
|
72
|
+
export type Tier0Census = VulnerabilityCensus | AssetCensus | EstateCensus;
|
|
73
|
+
export declare const EMPTY_VULNERABILITY_ROWS: VulnerabilityCensusRow[];
|
|
74
|
+
export declare const EMPTY_ASSET_ROWS: AssetCensusRow[];
|
|
75
|
+
export type Tier0BoardId = 'vulnerability' | 'asset' | 'estate';
|
|
76
|
+
export declare const TIER0_TARGETS: {
|
|
77
|
+
readonly vulnerability: {
|
|
78
|
+
readonly recordId: "working/vulnerability-census";
|
|
79
|
+
readonly kind: "vulnerability-census";
|
|
80
|
+
};
|
|
81
|
+
readonly asset: {
|
|
82
|
+
readonly recordId: "working/asset-census";
|
|
83
|
+
readonly kind: "asset-census";
|
|
84
|
+
};
|
|
85
|
+
readonly estate: {
|
|
86
|
+
readonly recordId: "working/estate-census";
|
|
87
|
+
readonly kind: "estate-census";
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
/** A figure the census has not produced is absent, not zero. */
|
|
91
|
+
export declare function tier0Value(metric: Tier0Metric | undefined): number | null;
|
|
92
|
+
export declare function publishedCount(value: number | null | undefined): string;
|
|
93
|
+
/**
|
|
94
|
+
* List figure. A loaded census uses its own number, including a finished `0`.
|
|
95
|
+
* A missing row on a loaded census is unavailable.
|
|
96
|
+
* Before that document exists, the lander figure keeps the column from going blank.
|
|
97
|
+
*/
|
|
98
|
+
export declare function censusOrLander(censusReady: boolean, censusRow: object | null, censusValue: number | null | undefined, landerValue: number | null | undefined): number | null;
|
|
99
|
+
/** Parse one census body. A mismatched `data.kind` is not that board's record. */
|
|
100
|
+
export declare function parseTier0Census(page: unknown, kind: Tier0Census['kind']): Tier0Census | null;
|
|
101
|
+
/**
|
|
102
|
+
* One client-API read of `security-map` / `tier0-analytics`.
|
|
103
|
+
* `declared-empty` is a missing record. `undeclared` means the content type is not registered.
|
|
104
|
+
* `placeholder` is a land with no census. A transport failure is `error` and is not logged here.
|
|
105
|
+
*/
|
|
106
|
+
export declare function loadTier0CensusResult(client: EstateData, board: Tier0BoardId, signal?: AbortSignal): Promise<ReadResult<Tier0Census>>;
|
|
107
|
+
/**
|
|
108
|
+
* One client-API read of `security-map` / `tier0-analytics`.
|
|
109
|
+
* A missing record, an unregistered content type, a placeholder land, or a failed read yields null.
|
|
110
|
+
* Use {@link loadTier0CensusResult} to tell those apart.
|
|
111
|
+
*/
|
|
112
|
+
export declare function loadTier0Census(client: EstateData, board: Tier0BoardId, signal?: AbortSignal): Promise<Tier0Census | null>;
|
|
113
|
+
/** Dialog lookup. `rows[].id` is the lander record id. */
|
|
114
|
+
export declare function censusEntryById<T extends {
|
|
115
|
+
id: string;
|
|
116
|
+
}>(rows: readonly T[], id: string): T | null;
|
|
117
|
+
/**
|
|
118
|
+
* CVE dialog join. The panel's key is the CVE text. Use the lander id when that
|
|
119
|
+
* id is the CVE, otherwise the single census row that publishes this `cveId`.
|
|
120
|
+
* Several rows for one CVE stay unresolved here. Each dialog still matches by id.
|
|
121
|
+
*/
|
|
122
|
+
export declare function vulnerabilityEntryForCve(rows: readonly VulnerabilityCensusRow[], cveId: string): VulnerabilityCensusRow | null;
|
|
123
|
+
//# sourceMappingURL=census.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"census.d.ts","sourceRoot":"","sources":["../../src/estate/census.ts"],"names":[],"mappings":"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"}
|