@telorun/analyzer 0.67.0 → 0.69.0
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/dist/analysis-registry.d.ts +12 -0
- package/dist/analysis-registry.d.ts.map +1 -1
- package/dist/analysis-registry.js +26 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +23 -0
- package/dist/call-graph.d.ts +80 -1
- package/dist/call-graph.d.ts.map +1 -1
- package/dist/call-graph.js +145 -12
- package/dist/extends-resolution.d.ts +20 -0
- package/dist/extends-resolution.d.ts.map +1 -1
- package/dist/extends-resolution.js +29 -0
- package/dist/import-resolution-diagnostics.d.ts.map +1 -1
- package/dist/import-resolution-diagnostics.js +22 -8
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/invocation-contract.d.ts +20 -0
- package/dist/invocation-contract.d.ts.map +1 -1
- package/dist/invocation-contract.js +74 -0
- package/dist/loaded-types.d.ts +4 -4
- package/dist/loaded-types.d.ts.map +1 -1
- package/dist/manifest-analysis.d.ts +19 -0
- package/dist/manifest-analysis.d.ts.map +1 -1
- package/dist/manifest-analysis.js +27 -0
- package/dist/manifest-loader.d.ts +3 -4
- package/dist/manifest-loader.d.ts.map +1 -1
- package/dist/manifest-loader.js +4 -5
- package/dist/manifest-schemas.d.ts +2 -0
- package/dist/manifest-schemas.d.ts.map +1 -1
- package/dist/manifest-schemas.js +4 -0
- package/dist/module-graph.d.ts +500 -0
- package/dist/module-graph.d.ts.map +1 -0
- package/dist/module-graph.js +1411 -0
- package/dist/reconcile-module-versions.d.ts.map +1 -1
- package/dist/reconcile-module-versions.js +10 -11
- package/dist/release/release-plan.d.ts +1 -1
- package/dist/resolve-zone-containment.d.ts +9 -1
- package/dist/resolve-zone-containment.d.ts.map +1 -1
- package/dist/resolve-zone-containment.js +34 -6
- package/dist/resolve-zone-requirements.d.ts.map +1 -1
- package/dist/resolve-zone-requirements.js +4 -2
- package/dist/schema-keywords.d.ts +16 -1
- package/dist/schema-keywords.d.ts.map +1 -1
- package/dist/schema-keywords.js +20 -0
- package/dist/sources/default-sources.d.ts +6 -6
- package/dist/sources/default-sources.d.ts.map +1 -1
- package/dist/sources/default-sources.js +7 -8
- package/dist/sources/integrity.d.ts +3 -2
- package/dist/sources/integrity.d.ts.map +1 -1
- package/dist/sources/integrity.js +26 -3
- package/dist/sources/versioned-ref.d.ts +17 -12
- package/dist/sources/versioned-ref.d.ts.map +1 -1
- package/dist/sources/versioned-ref.js +22 -24
- package/dist/telo-version.d.ts +1 -1
- package/dist/telo-version.js +1 -1
- package/dist/validate-extends.d.ts.map +1 -1
- package/dist/validate-extends.js +42 -1
- package/dist/validate-sensitive-slots.d.ts +28 -0
- package/dist/validate-sensitive-slots.d.ts.map +1 -0
- package/dist/validate-sensitive-slots.js +75 -0
- package/dist/value-type-keyword.d.ts +1 -1
- package/dist/value-type-keyword.d.ts.map +1 -1
- package/dist/value-type-keyword.js +1 -0
- package/package.json +1 -1
- package/src/analysis-registry.ts +37 -0
- package/src/analyzer.ts +26 -0
- package/src/call-graph.ts +207 -14
- package/src/extends-resolution.ts +33 -0
- package/src/import-resolution-diagnostics.ts +24 -7
- package/src/index.ts +42 -5
- package/src/invocation-contract.ts +71 -0
- package/src/loaded-types.ts +4 -4
- package/src/manifest-analysis.ts +39 -0
- package/src/manifest-loader.ts +4 -5
- package/src/manifest-schemas.ts +4 -0
- package/src/module-graph.ts +2005 -0
- package/src/reconcile-module-versions.ts +10 -11
- package/src/release/release-plan.ts +1 -1
- package/src/resolve-zone-containment.ts +49 -9
- package/src/resolve-zone-requirements.ts +7 -2
- package/src/schema-keywords.ts +33 -1
- package/src/sources/default-sources.ts +7 -8
- package/src/sources/integrity.ts +28 -3
- package/src/sources/versioned-ref.ts +26 -28
- package/src/telo-version.ts +1 -1
- package/src/validate-extends.ts +51 -1
- package/src/validate-sensitive-slots.ts +109 -0
- package/src/value-type-keyword.ts +1 -0
- package/dist/sources/module-ref.d.ts +0 -21
- package/dist/sources/module-ref.d.ts.map +0 -1
- package/dist/sources/module-ref.js +0 -36
- package/dist/sources/registry-source.d.ts +0 -14
- package/dist/sources/registry-source.d.ts.map +0 -1
- package/dist/sources/registry-source.js +0 -45
- package/src/sources/module-ref.ts +0 -49
- package/src/sources/registry-source.ts +0 -52
package/src/index.ts
CHANGED
|
@@ -84,15 +84,19 @@ export {
|
|
|
84
84
|
isInheritedDelegation,
|
|
85
85
|
mappingFieldFor,
|
|
86
86
|
needsContractMapping,
|
|
87
|
+
publishedOwnFields,
|
|
87
88
|
resolveParent,
|
|
88
89
|
} from "./extends-resolution.js";
|
|
89
90
|
export type { ContractDirection, DefResolver } from "./extends-resolution.js";
|
|
91
|
+
export { validateSensitiveSlots } from "./validate-sensitive-slots.js";
|
|
92
|
+
export type { SensitiveSlotIssue } from "./validate-sensitive-slots.js";
|
|
90
93
|
export {
|
|
91
94
|
defaultBearingPaths,
|
|
92
95
|
declaredScalarPaths,
|
|
93
96
|
PERMISSIVE_CONTRACT,
|
|
94
97
|
resolveContract,
|
|
95
98
|
resolveContractSchema,
|
|
99
|
+
sensitivePaths,
|
|
96
100
|
withLiveValuesSkipped,
|
|
97
101
|
} from "./invocation-contract.js";
|
|
98
102
|
export type {
|
|
@@ -108,7 +112,13 @@ export {
|
|
|
108
112
|
RedactionPathError,
|
|
109
113
|
} from "./redaction-path.js";
|
|
110
114
|
export type { RedactionSegment } from "./redaction-path.js";
|
|
111
|
-
export {
|
|
115
|
+
export {
|
|
116
|
+
buildCallGraph,
|
|
117
|
+
nodeIdFor,
|
|
118
|
+
projectToPairs,
|
|
119
|
+
resolveScopedName,
|
|
120
|
+
resourceId,
|
|
121
|
+
} from "./call-graph.js";
|
|
112
122
|
export type {
|
|
113
123
|
BuildCallGraphOptions,
|
|
114
124
|
CallGraph,
|
|
@@ -117,6 +127,31 @@ export type {
|
|
|
117
127
|
ResourceGraphNode,
|
|
118
128
|
StepGraphNode,
|
|
119
129
|
} from "./call-graph.js";
|
|
130
|
+
export {
|
|
131
|
+
AMBIENT_CAPABILITIES,
|
|
132
|
+
buildModuleGraph,
|
|
133
|
+
contentKey,
|
|
134
|
+
edgeClassOf,
|
|
135
|
+
isAmbientCapability,
|
|
136
|
+
isAmbientHold,
|
|
137
|
+
isOrderedRow,
|
|
138
|
+
isUnwired,
|
|
139
|
+
} from "./module-graph.js";
|
|
140
|
+
export type {
|
|
141
|
+
BuildModuleGraphOptions,
|
|
142
|
+
EdgeClass,
|
|
143
|
+
GraphEdge,
|
|
144
|
+
GraphKind,
|
|
145
|
+
GraphNode,
|
|
146
|
+
GraphPort,
|
|
147
|
+
GraphRegion,
|
|
148
|
+
GraphRow,
|
|
149
|
+
ModuleGraph,
|
|
150
|
+
ModuleGraphDeps,
|
|
151
|
+
NodeOwnership,
|
|
152
|
+
PortSlot,
|
|
153
|
+
RowKind,
|
|
154
|
+
} from "./module-graph.js";
|
|
120
155
|
export {
|
|
121
156
|
buildReferenceFieldMap,
|
|
122
157
|
isRefEntry,
|
|
@@ -300,7 +335,12 @@ export { validateDynamicSelectors, validateRefSlotDeclarations } from "./validat
|
|
|
300
335
|
export type { RefSlotIssue } from "./validate-ref-slots.js";
|
|
301
336
|
export { validateValueTypeSlots } from "./validate-value-type-slots.js";
|
|
302
337
|
export type { ValueTypeSlotIssue } from "./validate-value-type-slots.js";
|
|
303
|
-
export {
|
|
338
|
+
export {
|
|
339
|
+
checkSchemaCompatibility,
|
|
340
|
+
collectProperties,
|
|
341
|
+
resolveRefIn,
|
|
342
|
+
selectUnionBranch,
|
|
343
|
+
} from "./schema-compat.js";
|
|
304
344
|
export type { CompatibilityResult, ExternalSchemaResolver } from "./schema-compat.js";
|
|
305
345
|
export {
|
|
306
346
|
ajvErrorToPath,
|
|
@@ -358,7 +398,6 @@ export {
|
|
|
358
398
|
} from "./position-metadata.js";
|
|
359
399
|
export type { DocumentPosition } from "./position-metadata.js";
|
|
360
400
|
export { HttpSource } from "./sources/http-source.js";
|
|
361
|
-
export { RegistrySource } from "./sources/registry-source.js";
|
|
362
401
|
export { defaultSources } from "./sources/default-sources.js";
|
|
363
402
|
export {
|
|
364
403
|
splitIntegrity,
|
|
@@ -369,8 +408,6 @@ export {
|
|
|
369
408
|
sha256Base64Url,
|
|
370
409
|
IntegrityError,
|
|
371
410
|
} from "./sources/integrity.js";
|
|
372
|
-
export { parseModuleRef, isRegistryRef } from "./sources/module-ref.js";
|
|
373
|
-
export type { ParsedModuleRef } from "./sources/module-ref.js";
|
|
374
411
|
export { OCI_SCHEME, isOciRef, parseOciRef } from "./sources/oci-ref.js";
|
|
375
412
|
export type { ParsedOciRef } from "./sources/oci-ref.js";
|
|
376
413
|
export { parseVersionedRef, withRefVersion } from "./sources/versioned-ref.js";
|
|
@@ -334,6 +334,77 @@ export function defaultBearingPaths(
|
|
|
334
334
|
return out;
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
/** Every path in `schema` the author marked `x-telo-sensitive: true` — the
|
|
338
|
+
* values a trace payload must carry as `[redacted]` rather than verbatim.
|
|
339
|
+
*
|
|
340
|
+
* It exists because making a credential a dispatched `Telo.Invocable` turns its
|
|
341
|
+
* material into an invoke OUTPUT, and invoke inputs and outputs ride the debug
|
|
342
|
+
* wire on every call under `--inspect` — which is every watch session. The
|
|
343
|
+
* kernel's substring scrubbing does not reach them: it has one call site, the
|
|
344
|
+
* resource-Created event's properties.
|
|
345
|
+
*
|
|
346
|
+
* Declared by the kind that OWNS the contract, so the kernel names no kind and
|
|
347
|
+
* any module opts in — the `x-telo-eval` shape. Exempting "an Http.Credential
|
|
348
|
+
* result" directly would be kind-knowledge in the kernel, and would stop at
|
|
349
|
+
* that one kind while the same token surfaces wherever else a contract carries
|
|
350
|
+
* it.
|
|
351
|
+
*
|
|
352
|
+
* Bounded by the schema's declarations exactly as {@link defaultBearingPaths}
|
|
353
|
+
* is: a contract marking nothing walks nothing at dispatch. The key is kept and
|
|
354
|
+
* only the value replaced, per the logging spec §14 — a payload that silently
|
|
355
|
+
* loses a key reads as a value that was never produced. */
|
|
356
|
+
export function sensitivePaths(
|
|
357
|
+
schema: Record<string, any>,
|
|
358
|
+
resolveRef?: (ref: string) => Record<string, any> | undefined,
|
|
359
|
+
): string[][] {
|
|
360
|
+
const out: string[][] = [];
|
|
361
|
+
|
|
362
|
+
const walk = (node: unknown, path: string[], chain: readonly object[]): void => {
|
|
363
|
+
if (!node || typeof node !== "object") return;
|
|
364
|
+
let s = node as Record<string, any>;
|
|
365
|
+
if (chain.includes(s)) return;
|
|
366
|
+
if (resolveRef && typeof s.$ref === "string") {
|
|
367
|
+
const target = resolveRef(s.$ref);
|
|
368
|
+
if (!target || chain.includes(target)) return;
|
|
369
|
+
s = { ...target, ...s, $ref: undefined };
|
|
370
|
+
}
|
|
371
|
+
const here = [...chain, node as object];
|
|
372
|
+
|
|
373
|
+
// A marked node is redacted WHOLE, so there is nothing below it to mark:
|
|
374
|
+
// descending would emit paths into a value that is already gone. The EMPTY
|
|
375
|
+
// path is legal and means the whole value — a contract whose entire output
|
|
376
|
+
// is the secret is the simplest shape there is, and refusing it silently
|
|
377
|
+
// (which `path.length > 0` did) left exactly that case unredacted.
|
|
378
|
+
if (s["x-telo-sensitive"] === true) {
|
|
379
|
+
out.push(path);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const properties = s.properties as Record<string, any> | undefined;
|
|
384
|
+
if (properties) {
|
|
385
|
+
for (const [key, child] of Object.entries(properties)) walk(child, [...path, key], here);
|
|
386
|
+
}
|
|
387
|
+
// A map whose VALUES are secrets — `additionalProperties: {x-telo-sensitive}`
|
|
388
|
+
// — is the shape a headers or query bag takes, and it carries no property
|
|
389
|
+
// names to walk. `{}` is the wildcard segment, the `[]` precedent one axis
|
|
390
|
+
// over.
|
|
391
|
+
for (const key of ["additionalProperties", "patternProperties"] as const) {
|
|
392
|
+
const node = s[key];
|
|
393
|
+
if (!node || typeof node !== "object") continue;
|
|
394
|
+
if (key === "additionalProperties") walk(node, [...path, "{}"], here);
|
|
395
|
+
else for (const child of Object.values(node)) walk(child, [...path, "{}"], here);
|
|
396
|
+
}
|
|
397
|
+
for (const branch of ["allOf", "anyOf", "oneOf"] as const) {
|
|
398
|
+
const list = s[branch];
|
|
399
|
+
if (Array.isArray(list)) for (const child of list) walk(child, path, here);
|
|
400
|
+
}
|
|
401
|
+
if (s.items) walk(s.items, [...path, "[]"], here);
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
walk(schema, [], []);
|
|
405
|
+
return out;
|
|
406
|
+
}
|
|
407
|
+
|
|
337
408
|
/** The scalar form a declared node's value takes at runtime. `int64` and
|
|
338
409
|
* `double` are the two JSON scalars whose runtime representation is NOT decided
|
|
339
410
|
* by the value that arrives: a CEL integer is a BigInt and a CEL double a JS
|
package/src/loaded-types.ts
CHANGED
|
@@ -12,9 +12,9 @@ import type { AstDocument } from "./yaml-ast.js";
|
|
|
12
12
|
* cache uses `source` — the URL the source adapter's `read()` returned. */
|
|
13
13
|
export interface LoadedFile {
|
|
14
14
|
/** Canonical identity. The URL the source adapter's `read()` returned —
|
|
15
|
-
* HTTPS for
|
|
15
|
+
* HTTPS for a remote module, an absolute path for local. */
|
|
16
16
|
source: string;
|
|
17
|
-
/** The URL the caller supplied (e.g.
|
|
17
|
+
/** The URL the caller supplied (e.g. `oci://ghcr.io/telorun/javascript@0.3.0`).
|
|
18
18
|
* Differs from `source` only for adapter-resolved URLs. */
|
|
19
19
|
requestedUrl: string;
|
|
20
20
|
/** Raw text exactly as `read()` returned it. */
|
|
@@ -65,8 +65,8 @@ export interface LoadedModule {
|
|
|
65
65
|
export interface ImportEdge {
|
|
66
66
|
/** Canonical resolved URL of the target — a key into `modules`. */
|
|
67
67
|
targetSource: string;
|
|
68
|
-
/** The import's `source` exactly as authored —
|
|
69
|
-
*
|
|
68
|
+
/** The import's `source` exactly as authored — an `oci://` or `https://`
|
|
69
|
+
* ref, or a relative path. Version reconciliation keys on
|
|
70
70
|
* this (minus its version), since it names the module's location
|
|
71
71
|
* independently of what the module declares about itself. */
|
|
72
72
|
targetRef: string;
|
package/src/manifest-analysis.ts
CHANGED
|
@@ -27,7 +27,14 @@ import { CelScopeQuery, type CelScopeQueryContext } from "./cel-scope-query.js";
|
|
|
27
27
|
import { DefinitionRegistry } from "./definition-registry.js";
|
|
28
28
|
import type { ContractDirection } from "./extends-resolution.js";
|
|
29
29
|
import { analyzerContractScope, resolveContract } from "./invocation-contract.js";
|
|
30
|
+
import { buildCallGraph, type CallGraph } from "./call-graph.js";
|
|
30
31
|
import { findManifest } from "./find-manifest.js";
|
|
32
|
+
import {
|
|
33
|
+
buildModuleGraph,
|
|
34
|
+
type BuildModuleGraphOptions,
|
|
35
|
+
type ModuleGraph,
|
|
36
|
+
type ModuleGraphDeps,
|
|
37
|
+
} from "./module-graph.js";
|
|
31
38
|
import { isModuleKind } from "./module-kinds.js";
|
|
32
39
|
|
|
33
40
|
/**
|
|
@@ -43,6 +50,8 @@ export interface ManifestRef {
|
|
|
43
50
|
export class ManifestAnalysis {
|
|
44
51
|
private readonly scopes: ModuleScopes;
|
|
45
52
|
private celScopeQuery: CelScopeQuery | undefined;
|
|
53
|
+
private callGraphMemo: CallGraph | undefined;
|
|
54
|
+
private moduleGraphMemo: ModuleGraph | undefined;
|
|
46
55
|
|
|
47
56
|
constructor(
|
|
48
57
|
readonly manifests: ResourceManifest[],
|
|
@@ -62,6 +71,36 @@ export class ManifestAnalysis {
|
|
|
62
71
|
return (this.celScopeQuery ??= new CelScopeQuery(this.manifests, this.ctx));
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
/** What calls what. Built on first use and kept, so the projection and any
|
|
75
|
+
* other consumer over this set share one. */
|
|
76
|
+
private get callGraph(): CallGraph {
|
|
77
|
+
return (this.callGraphMemo ??= buildCallGraph(this.manifests, this.ctx.defs, {
|
|
78
|
+
aliases: this.ctx.aliases,
|
|
79
|
+
aliasesByModule: this.ctx.aliasesByModule,
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The module graph: boxes, ordered rows and classed edges — the projection an
|
|
85
|
+
* editor draws.
|
|
86
|
+
*
|
|
87
|
+
* Here rather than on the registry because it is the registry AND a manifest
|
|
88
|
+
* set, which is the pairing this class exists to name; a fifth
|
|
89
|
+
* `registry.x(manifests, …)` factory is the accretion naming it stopped. It
|
|
90
|
+
* shares this analysis's call graph rather than building one of its own.
|
|
91
|
+
*
|
|
92
|
+
* `deps` is supplied by the registry, which owns capability resolution — this
|
|
93
|
+
* class holds the manifests, not the rules for reading a kind.
|
|
94
|
+
*/
|
|
95
|
+
moduleGraph(deps: ModuleGraphDeps, options: BuildModuleGraphOptions = {}): ModuleGraph {
|
|
96
|
+
return (this.moduleGraphMemo ??= buildModuleGraph(
|
|
97
|
+
this.manifests,
|
|
98
|
+
this.callGraph,
|
|
99
|
+
deps,
|
|
100
|
+
options,
|
|
101
|
+
));
|
|
102
|
+
}
|
|
103
|
+
|
|
65
104
|
/** The manifest a `(kind, name)` pair addresses. */
|
|
66
105
|
resourceFor(kind: string | undefined, name: string | undefined): ResourceManifest | undefined {
|
|
67
106
|
return findManifest(this.manifests, kind, name);
|
package/src/manifest-loader.ts
CHANGED
|
@@ -146,7 +146,7 @@ export class Loader {
|
|
|
146
146
|
* when a URL it has already canonicalised is requested again — kernel
|
|
147
147
|
* load → boot and the import-controller each ask the loader for the same
|
|
148
148
|
* modules. Without this fast path every duplicate request re-runs the
|
|
149
|
-
* source's `read()` (a `fetch` for `
|
|
149
|
+
* source's `read()` (a `fetch` for `HttpSource`, a disk read for
|
|
150
150
|
* `LocalFileSource`). */
|
|
151
151
|
private readonly urlToSource = new Map<string, string>();
|
|
152
152
|
|
|
@@ -157,8 +157,7 @@ export class Loader {
|
|
|
157
157
|
/** Sources are resolved in order — the first whose `supports(url)` matches
|
|
158
158
|
* wins. The caller (composition root) decides which concrete sources exist
|
|
159
159
|
* and supplies them; `defaultSources()` bundles the browser-safe built-ins
|
|
160
|
-
* (HTTP
|
|
161
|
-
* runtime. */
|
|
160
|
+
* (HTTP) for the common case. `register()` prepends a source at runtime. */
|
|
162
161
|
constructor(sources: ManifestSource[] = [], options: LoaderInitOptions = {}) {
|
|
163
162
|
this.sources = [...sources];
|
|
164
163
|
this.celEnv = buildCelEnvironment(options.celHandlers);
|
|
@@ -181,7 +180,7 @@ export class Loader {
|
|
|
181
180
|
// entry are populated in `urlToSource` + `fileCache` in one read.
|
|
182
181
|
// Callers (kernel.load) immediately call `loadGraph(entryUrl)`
|
|
183
182
|
// afterwards — without this priming, the entry file would be read
|
|
184
|
-
// twice (twice over the network for `
|
|
183
|
+
// twice (twice over the network for `HttpSource`).
|
|
185
184
|
const file = await this.loadFile(url);
|
|
186
185
|
return file.source;
|
|
187
186
|
}
|
|
@@ -469,7 +468,7 @@ export class Loader {
|
|
|
469
468
|
|
|
470
469
|
/** Resolve an `import` URL against the file it appears in. Relative /
|
|
471
470
|
* absolute-path forms run through the owning `ManifestSource`'s
|
|
472
|
-
* `resolveRelative`;
|
|
471
|
+
* `resolveRelative`; scheme-qualified refs and full URLs pass through
|
|
473
472
|
* unchanged. Exposed so the import-controller (and any other
|
|
474
473
|
* caller-side resolver) lands on the *exact same* canonical URL the
|
|
475
474
|
* loader used when walking the entry graph — divergent resolution
|
package/src/manifest-schemas.ts
CHANGED
|
@@ -241,6 +241,10 @@ export const InvokeStepSchema = {
|
|
|
241
241
|
when: {
|
|
242
242
|
title: "When",
|
|
243
243
|
description: "CEL guard — the dispatch is skipped when it evaluates false.",
|
|
244
|
+
// The same role `if:` and `while:` carry: it is the expression that
|
|
245
|
+
// decides whether the statement runs, and a surface showing what a step
|
|
246
|
+
// is conditional on should not have to know which keyword spelled it.
|
|
247
|
+
"x-telo-topology-role": "predicate",
|
|
244
248
|
type: "string",
|
|
245
249
|
},
|
|
246
250
|
retry: {
|