@sverka/sdk 0.2.22 → 0.2.24
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/index.d.mts +46 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +328 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -4
package/dist/index.d.mts
CHANGED
|
@@ -87,7 +87,7 @@ type PlannerErrorCode = "ENTRY_NOT_FOUND" | "ROOT_NOT_FOUND" | "MISSING_INPUT" |
|
|
|
87
87
|
export declare function expandMatrixSteps(steps: readonly StepDefinition[]): readonly StepDefinition[];
|
|
88
88
|
//#endregion
|
|
89
89
|
//#region src/errors.d.ts
|
|
90
|
-
type SdkErrorCode = "INVALID_INTERPOLATION" | "INVALID_IMAGE" | "CONFIG_NOT_FOUND" | "CONFIG_INVALID" | "CONFIG_LOAD_FAILED" | "CONFIG_PATH_ESCAPE" | "EXECUTION_FAILED";
|
|
90
|
+
type SdkErrorCode = "INVALID_INTERPOLATION" | "INVALID_IMAGE" | "CONFIG_NOT_FOUND" | "CONFIG_INVALID" | "CONFIG_LOAD_FAILED" | "CONFIG_PATH_ESCAPE" | "EXECUTION_FAILED" | "INVALID_FRONTMATTER" | "INVALID_STEP" | "INVALID_TRIGGER" | "EXTENDS_NOT_FOUND";
|
|
91
91
|
export declare class SdkError extends Error {
|
|
92
92
|
readonly cause?: unknown;
|
|
93
93
|
readonly code: SdkErrorCode;
|
|
@@ -394,5 +394,49 @@ interface AgentStepBuilder {
|
|
|
394
394
|
*/
|
|
395
395
|
export declare function agent(strings: TemplateStringsArray, ...values: readonly (string | Reference)[]): AgentStepBuilder;
|
|
396
396
|
//#endregion
|
|
397
|
-
|
|
397
|
+
//#region src/markdown.d.ts
|
|
398
|
+
/** Frontmatter shape (Spec 37 + Spec 54 `on:` alias and event kinds). */
|
|
399
|
+
interface MarkdownFrontmatter {
|
|
400
|
+
readonly pipeline: string;
|
|
401
|
+
readonly triggers?: readonly MarkdownTrigger[];
|
|
402
|
+
/** gh-aw-style shorthand for `triggers`. */
|
|
403
|
+
readonly on?: string | readonly string[] | Record<string, unknown>;
|
|
404
|
+
readonly extends?: string;
|
|
405
|
+
readonly inputs?: Readonly<Record<string, Input>>;
|
|
406
|
+
}
|
|
407
|
+
/** A single frontmatter trigger entry. */
|
|
408
|
+
interface MarkdownTrigger {
|
|
409
|
+
readonly kind: "push" | "changeRequest" | "manual" | "schedule" | "comment" | "issue";
|
|
410
|
+
readonly branches?: readonly string[];
|
|
411
|
+
readonly tags?: readonly string[];
|
|
412
|
+
readonly paths?: readonly string[];
|
|
413
|
+
readonly cron?: string;
|
|
414
|
+
readonly timezone?: string;
|
|
415
|
+
readonly mention?: string;
|
|
416
|
+
readonly on?: "mergeRequest" | "issue" | "commit";
|
|
417
|
+
readonly action?: "opened" | "reopened" | "labeled";
|
|
418
|
+
readonly labels?: readonly string[];
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Parse a `.sverka.md` source string into a Project construct.
|
|
422
|
+
* `filePath` anchors `extends` resolution and error messages; without it
|
|
423
|
+
* `extends` cannot resolve and throws EXTENDS_NOT_FOUND.
|
|
424
|
+
*/
|
|
425
|
+
export declare function parseMarkdown(source: string, filePath?: string): Project;
|
|
426
|
+
/**
|
|
427
|
+
* Read + parse a `.sverka.md` file. When frontmatter declares `extends`,
|
|
428
|
+
* the referenced config module is imported and the markdown pipeline is
|
|
429
|
+
* merged into that Project (Spec 37 escape hatch).
|
|
430
|
+
*/
|
|
431
|
+
export declare function loadMarkdownFile(path: string): Promise<Project>;
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/markdown-errors.d.ts
|
|
434
|
+
type MarkdownParseErrorCode = "INVALID_FRONTMATTER" | "INVALID_STEP" | "INVALID_TRIGGER" | "EXTENDS_NOT_FOUND";
|
|
435
|
+
/** Raised when a `.sverka.md` file cannot be parsed into a Project. */
|
|
436
|
+
export declare class MarkdownParseError extends SdkError {
|
|
437
|
+
readonly code: MarkdownParseErrorCode;
|
|
438
|
+
constructor(message: string, code: MarkdownParseErrorCode, cause?: unknown);
|
|
439
|
+
}
|
|
440
|
+
//#endregion
|
|
441
|
+
export { type AgentStepBuilder, type Artifact, type ArtifactDeclaration, type BindRunPlanOptions, type CacheDeclaration, type CallPipelineBuilder, type ChangedFile, CheckError, type CheckErrorCode, type CheckOutput, type CheckResolver, type ComponentBuilder, CompositionError, CoreError, type CredentialDeclaration, DEFAULT_POLICY, type DetectedLanguage, type DetectedPackageManager, type DiscoverOptions, type DiscoveryErrorCode, type DiscoveryExplanation, type ExecutionResult, type ExecutorSpec, type Expression, type FailOnRule, type Finding, type FindingSource, type ImageRef, type LocalSignal, type LocalSignalType, type MarkdownFrontmatter, type MarkdownParseErrorCode, type MarkdownTrigger, type MonorepoMarker, type NetworkPolicy, type Operation, type OperationKind, type OperationOutcome, type OperationSpec, type PipelineConfig, type Plan, type PlanContext, type PlanMetadata, type PlanOperation, type PlanProposal, type PlanResult, type Planner, type PlannerErrorCode, PlanningError, type Policy, type PolicyConfig, type PolicyResult, type ProjectContext, type ProposedCheck, type ResolvedCheck, type Runtime, type RuntimeMode, type RuntimeResult, type SdkErrorCode, type Severity, type ShellProxy, type StepBuilder, type Sverka, type SverkaOptions, type Verdict, type Workflow, type WorkflowDefinition, computeFingerprint, computePlanId, createBaseline, createBuiltinResolver, createPolicy, evaluatePolicy, extractFindings, filterOnlyNew, loadBaseline, matrix, matrix$1 as matrixContext, normalizeSarif, parallel, pipeline, pipeline$1 as pipelineV0, run, run$1 as runContext, saveBaseline, updateBaseline, validatePlan, when, when$1 as whenV0, workflow };
|
|
398
442
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/planner/bind.ts","../src/planner/planner.ts","../src/planner/errors.ts","../src/planner/matrix.ts","../src/errors.ts","../src/types.ts","../src/compat/config.ts","../src/sverka.ts","../src/compat/helpers.ts","../src/dollar.ts","../src/shell.ts","../src/artifact.ts","../src/pipeline.ts","../src/call-pipeline.ts","../src/component.ts","../src/when.ts","../src/expr.ts","../src/status.ts","../src/images.ts","../src/context.ts","../src/agent.ts"],"mappings":";;;;UAeiB;WACN,OAAO;WACP;WACA,SAAS,SAAS,eAAe;;;;;;wBAS5B,YAAY,SAAS,qBAAqB;;;;;;;wBAiO1C,sBACd,gBAAgB,kBAChB,oCACU;;;;;;UChNK;EACf,SAAS,SAAS,kBAAkB,QAAQ;EAC5C,KAAK,SAAS,iBAAiB,QAAQ;EACvC,YAAY,SAAS,qBAAqB;;wBAG5B,iBAAiB;UAIhB;EACf;EACA;EACA;;;;;;;;EAQA;;UAGe;EACf,SAAS;EACT,iBAAiB;EACjB;EACA;;;;;;;;qBCvEW,uBAAuB;WACzB,MAAM;WACG;EACN,YAAA,iBAAiB,MAAM,oBAAoB;;KAQ7C;;;;qBAUC,qBAAqB;WACvB,MAAM;WACG;EACN,YAAA,iBAAiB,MAAM,kBAAkB;;KAQ3C;;;;;;;;;;;;;;;wBCVI,kBACd,gBAAgB,4BACN;;;KC1BA;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/planner/bind.ts","../src/planner/planner.ts","../src/planner/errors.ts","../src/planner/matrix.ts","../src/errors.ts","../src/types.ts","../src/compat/config.ts","../src/sverka.ts","../src/compat/helpers.ts","../src/dollar.ts","../src/shell.ts","../src/artifact.ts","../src/pipeline.ts","../src/call-pipeline.ts","../src/component.ts","../src/when.ts","../src/expr.ts","../src/status.ts","../src/images.ts","../src/context.ts","../src/agent.ts","../src/markdown.ts","../src/markdown-errors.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -2,11 +2,12 @@ import { existsSync, mkdtempSync, readFileSync, realpathSync } from "node:fs";
|
|
|
2
2
|
import path, { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
|
-
import { AgentStep, ComponentStep, CompositionError, CoreError, Pipeline, PipelineCallStep, PlanningError, ShellStep, canonicalStringify, computeGraphId, computePlanId, computePlanId as computePlanId$1, computeRunPlanId, expandPipelineCalls, matrix, parallel, pipeline, run, validateGraph, validatePlan, validatePlan as validatePlan$1, when, workflow, workflow as workflow$1 } from "@sverka/workflow";
|
|
5
|
+
import { AgentStep, ComponentStep, CompositionError, CoreError, Entry, Pipeline, PipelineCallStep, PlanningError, Project, ShellStep, canonicalStringify, computeGraphId, computePlanId, computePlanId as computePlanId$1, computeRunPlanId, expandPipelineCalls, matrix, parallel, pipeline, run, validateGraph, validatePlan, validatePlan as validatePlan$1, when, workflow, workflow as workflow$1 } from "@sverka/workflow";
|
|
6
6
|
import { CheckError, DEFAULT_POLICY, DEFAULT_POLICY as DEFAULT_POLICY$1, computeFingerprint, createBaseline, createBuiltinResolver, createBuiltinResolver as createBuiltinResolver$1, createPolicy, createPolicy as createPolicy$1, evaluatePolicy, evaluatePolicy as evaluatePolicy$1, extractFindings, extractFindings as extractFindings$1, filterOnlyNew, filterOnlyNew as filterOnlyNew$1, loadBaseline, loadBaseline as loadBaseline$1, normalizeSarif, saveBaseline, updateBaseline } from "@sverka/verification";
|
|
7
7
|
import { pathToFileURL } from "node:url";
|
|
8
|
-
import { rm } from "node:fs/promises";
|
|
8
|
+
import { readFile, rm } from "node:fs/promises";
|
|
9
9
|
import { tmpdir } from "node:os";
|
|
10
|
+
import { parse } from "yaml";
|
|
10
11
|
//#region src/planner/internal/git-cli.ts
|
|
11
12
|
/**
|
|
12
13
|
* Resolve the absolute path to the `git` executable by searching `PATH`
|
|
@@ -2211,6 +2212,330 @@ function agent(strings, ...values) {
|
|
|
2211
2212
|
});
|
|
2212
2213
|
}
|
|
2213
2214
|
//#endregion
|
|
2214
|
-
|
|
2215
|
+
//#region src/markdown-errors.ts
|
|
2216
|
+
/** Raised when a `.sverka.md` file cannot be parsed into a Project. */
|
|
2217
|
+
var MarkdownParseError = class extends SdkError {
|
|
2218
|
+
constructor(message, code, cause) {
|
|
2219
|
+
super(message, code, cause);
|
|
2220
|
+
this.name = "MarkdownParseError";
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
2223
|
+
//#endregion
|
|
2224
|
+
//#region src/markdown.ts
|
|
2225
|
+
/**
|
|
2226
|
+
* Parse a `.sverka.md` source string into a Project construct.
|
|
2227
|
+
* `filePath` anchors `extends` resolution and error messages; without it
|
|
2228
|
+
* `extends` cannot resolve and throws EXTENDS_NOT_FOUND.
|
|
2229
|
+
*/
|
|
2230
|
+
function parseMarkdown(source, filePath) {
|
|
2231
|
+
const { frontmatter, body } = splitFrontmatter(source, filePath);
|
|
2232
|
+
const project = new Project(frontmatter.pipeline);
|
|
2233
|
+
buildMarkdownPipeline(project, frontmatter, body, filePath);
|
|
2234
|
+
return project;
|
|
2235
|
+
}
|
|
2236
|
+
/**
|
|
2237
|
+
* Read + parse a `.sverka.md` file. When frontmatter declares `extends`,
|
|
2238
|
+
* the referenced config module is imported and the markdown pipeline is
|
|
2239
|
+
* merged into that Project (Spec 37 escape hatch).
|
|
2240
|
+
*/
|
|
2241
|
+
async function loadMarkdownFile(path) {
|
|
2242
|
+
const abs = isAbsolute(path) ? path : resolve(process.cwd(), path);
|
|
2243
|
+
let source;
|
|
2244
|
+
try {
|
|
2245
|
+
source = await readFile(abs, "utf-8");
|
|
2246
|
+
} catch (e) {
|
|
2247
|
+
throw new MarkdownParseError(`cannot read markdown file: ${abs}`, "INVALID_FRONTMATTER", e);
|
|
2248
|
+
}
|
|
2249
|
+
const { frontmatter, body } = splitFrontmatter(source, abs);
|
|
2250
|
+
if (frontmatter.extends !== void 0) {
|
|
2251
|
+
const base = await loadExtends(frontmatter.extends, abs);
|
|
2252
|
+
buildMarkdownPipeline(base, frontmatter, body, abs);
|
|
2253
|
+
return base;
|
|
2254
|
+
}
|
|
2255
|
+
const project = new Project(frontmatter.pipeline);
|
|
2256
|
+
buildMarkdownPipeline(project, frontmatter, body, abs);
|
|
2257
|
+
return project;
|
|
2258
|
+
}
|
|
2259
|
+
function splitFrontmatter(source, filePath) {
|
|
2260
|
+
const where = filePath !== void 0 ? ` in ${filePath}` : "";
|
|
2261
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(source);
|
|
2262
|
+
if (m === null) throw new MarkdownParseError(`invalid .sverka.md${where}: missing YAML frontmatter (expected '---' delimiters)`, "INVALID_FRONTMATTER");
|
|
2263
|
+
let parsed;
|
|
2264
|
+
try {
|
|
2265
|
+
parsed = parse(m[1]);
|
|
2266
|
+
} catch (e) {
|
|
2267
|
+
throw new MarkdownParseError(`invalid .sverka.md frontmatter${where}: ${e instanceof Error ? e.message : String(e)}`, "INVALID_FRONTMATTER", e);
|
|
2268
|
+
}
|
|
2269
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new MarkdownParseError(`invalid .sverka.md frontmatter${where}: expected a mapping`, "INVALID_FRONTMATTER");
|
|
2270
|
+
const fm = parsed;
|
|
2271
|
+
if (typeof fm.pipeline !== "string" || fm.pipeline === "") throw new MarkdownParseError(`invalid .sverka.md frontmatter${where}: missing required 'pipeline' field`, "INVALID_FRONTMATTER");
|
|
2272
|
+
return {
|
|
2273
|
+
frontmatter: fm,
|
|
2274
|
+
body: m[2]
|
|
2275
|
+
};
|
|
2276
|
+
}
|
|
2277
|
+
function frontmatterTriggers(fm) {
|
|
2278
|
+
return collectTriggerEntries(fm).map((entry, i) => toTrigger(entry, i));
|
|
2279
|
+
}
|
|
2280
|
+
/**
|
|
2281
|
+
* Normalize `triggers:` (array of objects) and `on:` (gh-aw shorthand:
|
|
2282
|
+
* string, list of kind strings, or map of kind → options) into uniform
|
|
2283
|
+
* entries. `triggers` wins when both are present.
|
|
2284
|
+
*/
|
|
2285
|
+
function collectTriggerEntries(fm) {
|
|
2286
|
+
if (fm.triggers !== void 0) {
|
|
2287
|
+
if (!Array.isArray(fm.triggers)) throw new MarkdownParseError("invalid .sverka.md frontmatter: 'triggers' must be an array", "INVALID_TRIGGER");
|
|
2288
|
+
return fm.triggers.map((t) => {
|
|
2289
|
+
if (typeof t !== "object" || t === null || typeof t.kind !== "string") throw new MarkdownParseError("invalid .sverka.md trigger: each entry needs a string 'kind'", "INVALID_TRIGGER");
|
|
2290
|
+
const { kind, ...opts } = t;
|
|
2291
|
+
return {
|
|
2292
|
+
kind,
|
|
2293
|
+
opts
|
|
2294
|
+
};
|
|
2295
|
+
});
|
|
2296
|
+
}
|
|
2297
|
+
if (fm.on === void 0) return [];
|
|
2298
|
+
const on = fm.on;
|
|
2299
|
+
if (typeof on === "string") return [{
|
|
2300
|
+
kind: on,
|
|
2301
|
+
opts: {}
|
|
2302
|
+
}];
|
|
2303
|
+
if (Array.isArray(on)) return on.map((kind) => {
|
|
2304
|
+
if (typeof kind !== "string") throw new MarkdownParseError("invalid .sverka.md 'on': entries must be trigger kind strings", "INVALID_TRIGGER");
|
|
2305
|
+
return {
|
|
2306
|
+
kind,
|
|
2307
|
+
opts: {}
|
|
2308
|
+
};
|
|
2309
|
+
});
|
|
2310
|
+
if (typeof on === "object" && on !== null) return Object.entries(on).map(([kind, opts]) => ({
|
|
2311
|
+
kind,
|
|
2312
|
+
opts: typeof opts === "object" && opts !== null ? opts : {}
|
|
2313
|
+
}));
|
|
2314
|
+
throw new MarkdownParseError("invalid .sverka.md 'on': expected a trigger kind, list of kinds, or kind→options map", "INVALID_TRIGGER");
|
|
2315
|
+
}
|
|
2316
|
+
const FILTER_KEYS = [
|
|
2317
|
+
"branches",
|
|
2318
|
+
"tags",
|
|
2319
|
+
"paths"
|
|
2320
|
+
];
|
|
2321
|
+
function toTrigger(entry, index) {
|
|
2322
|
+
const { kind, opts } = entry;
|
|
2323
|
+
const at = `trigger[${index}] (${kind})`;
|
|
2324
|
+
const filter = buildFilter(opts, at);
|
|
2325
|
+
switch (kind) {
|
|
2326
|
+
case "push": return filter !== void 0 ? {
|
|
2327
|
+
kind: "push",
|
|
2328
|
+
filter
|
|
2329
|
+
} : { kind: "push" };
|
|
2330
|
+
case "changeRequest": return filter !== void 0 ? {
|
|
2331
|
+
kind: "changeRequest",
|
|
2332
|
+
filter
|
|
2333
|
+
} : { kind: "changeRequest" };
|
|
2334
|
+
case "manual": return filter !== void 0 ? {
|
|
2335
|
+
kind: "manual",
|
|
2336
|
+
filter
|
|
2337
|
+
} : { kind: "manual" };
|
|
2338
|
+
case "schedule": return toScheduleTrigger(opts, at);
|
|
2339
|
+
case "comment": return toCommentTrigger(opts, at);
|
|
2340
|
+
case "issue": return toIssueTrigger(opts, at);
|
|
2341
|
+
default: throw new MarkdownParseError(`invalid .sverka.md ${at}: unknown trigger kind '${kind}'`, "INVALID_TRIGGER");
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
function toScheduleTrigger(opts, at) {
|
|
2345
|
+
if (typeof opts.cron !== "string" || opts.cron === "") throw new MarkdownParseError(`invalid .sverka.md ${at}: schedule trigger requires a 'cron' string`, "INVALID_TRIGGER");
|
|
2346
|
+
if (opts.timezone !== void 0 && typeof opts.timezone !== "string") throw new MarkdownParseError(`invalid .sverka.md ${at}: schedule 'timezone' must be a string`, "INVALID_TRIGGER");
|
|
2347
|
+
return {
|
|
2348
|
+
kind: "schedule",
|
|
2349
|
+
cron: opts.cron,
|
|
2350
|
+
...opts.timezone !== void 0 ? { timezone: opts.timezone } : {}
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
function toCommentTrigger(opts, at) {
|
|
2354
|
+
const on = opts.on;
|
|
2355
|
+
if (on !== void 0 && on !== "mergeRequest" && on !== "issue" && on !== "commit") throw new MarkdownParseError(`invalid .sverka.md ${at}: comment 'on' must be mergeRequest|issue|commit`, "INVALID_TRIGGER");
|
|
2356
|
+
if (opts.mention !== void 0 && typeof opts.mention !== "string") throw new MarkdownParseError(`invalid .sverka.md ${at}: comment 'mention' must be a string`, "INVALID_TRIGGER");
|
|
2357
|
+
return {
|
|
2358
|
+
kind: "comment",
|
|
2359
|
+
...opts.mention !== void 0 ? { mention: opts.mention } : {},
|
|
2360
|
+
...on !== void 0 ? { on } : {}
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2363
|
+
function toIssueTrigger(opts, at) {
|
|
2364
|
+
const action = opts.action;
|
|
2365
|
+
if (action !== void 0 && action !== "opened" && action !== "reopened" && action !== "labeled") throw new MarkdownParseError(`invalid .sverka.md ${at}: issue 'action' must be opened|reopened|labeled`, "INVALID_TRIGGER");
|
|
2366
|
+
const labels = opts.labels;
|
|
2367
|
+
if (labels !== void 0 && (!Array.isArray(labels) || !labels.every((l) => typeof l === "string"))) throw new MarkdownParseError(`invalid .sverka.md ${at}: issue 'labels' must be an array of strings`, "INVALID_TRIGGER");
|
|
2368
|
+
return {
|
|
2369
|
+
kind: "issue",
|
|
2370
|
+
...action !== void 0 ? { action } : {},
|
|
2371
|
+
...labels !== void 0 ? { labels } : {}
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
function buildFilter(opts, at) {
|
|
2375
|
+
const filter = {};
|
|
2376
|
+
for (const key of FILTER_KEYS) {
|
|
2377
|
+
const v = opts[key];
|
|
2378
|
+
if (v === void 0) continue;
|
|
2379
|
+
if (!Array.isArray(v) || !v.every((s) => typeof s === "string")) throw new MarkdownParseError(`invalid .sverka.md ${at}: '${key}' must be an array of strings`, "INVALID_TRIGGER");
|
|
2380
|
+
filter[key] = v;
|
|
2381
|
+
}
|
|
2382
|
+
return Object.keys(filter).length > 0 ? filter : void 0;
|
|
2383
|
+
}
|
|
2384
|
+
const STEP_HEADING = /^##\s+(\S+)\s*$/;
|
|
2385
|
+
function parseSteps(body) {
|
|
2386
|
+
const steps = [];
|
|
2387
|
+
const lines = body.split("\n");
|
|
2388
|
+
let i = 0;
|
|
2389
|
+
while (i < lines.length) {
|
|
2390
|
+
const heading = STEP_HEADING.exec(lines[i]);
|
|
2391
|
+
if (heading === null) {
|
|
2392
|
+
i++;
|
|
2393
|
+
continue;
|
|
2394
|
+
}
|
|
2395
|
+
const id = heading[1];
|
|
2396
|
+
const section = [];
|
|
2397
|
+
let j = i + 1;
|
|
2398
|
+
while (j < lines.length && !STEP_HEADING.test(lines[j])) {
|
|
2399
|
+
section.push(lines[j]);
|
|
2400
|
+
j++;
|
|
2401
|
+
}
|
|
2402
|
+
steps.push(parseStepSection(id, section));
|
|
2403
|
+
i = j;
|
|
2404
|
+
}
|
|
2405
|
+
return steps;
|
|
2406
|
+
}
|
|
2407
|
+
/**
|
|
2408
|
+
* Parse one `- key: value` bullet line. Hand-rolled linear scan — a regex
|
|
2409
|
+
* over uncontrolled markdown is a ReDoS vector.
|
|
2410
|
+
*/
|
|
2411
|
+
function parseBulletLine(line) {
|
|
2412
|
+
const isSpace = (c) => c !== void 0 && /\s/.test(c);
|
|
2413
|
+
const isKeyChar = (c) => c !== void 0 && /[\w-]/.test(c);
|
|
2414
|
+
if (!line.startsWith("-") || !isSpace(line[1])) return null;
|
|
2415
|
+
let i = skipWhile(line, 1, isSpace);
|
|
2416
|
+
if (!isKeyStart(line[i])) return null;
|
|
2417
|
+
const keyStart = i;
|
|
2418
|
+
i = skipWhile(line, i, isKeyChar);
|
|
2419
|
+
const key = line.slice(keyStart, i);
|
|
2420
|
+
i = skipWhile(line, i, isSpace);
|
|
2421
|
+
if (line[i] !== ":") return null;
|
|
2422
|
+
return {
|
|
2423
|
+
key,
|
|
2424
|
+
rest: line.slice(i + 1).trimStart()
|
|
2425
|
+
};
|
|
2426
|
+
}
|
|
2427
|
+
function skipWhile(line, from, pred) {
|
|
2428
|
+
let i = from;
|
|
2429
|
+
while (i < line.length && pred(line[i])) i++;
|
|
2430
|
+
return i;
|
|
2431
|
+
}
|
|
2432
|
+
function isKeyStart(c) {
|
|
2433
|
+
return c !== void 0 && /[a-zA-Z_]/.test(c);
|
|
2434
|
+
}
|
|
2435
|
+
/**
|
|
2436
|
+
* Parse one `## step` section: `- key: value` bullets (indented blocks
|
|
2437
|
+
* belong to the preceding bullet). Non-bullet prose is ignored so a step
|
|
2438
|
+
* can carry documentation.
|
|
2439
|
+
*/
|
|
2440
|
+
function parseStepSection(id, lines) {
|
|
2441
|
+
return toParsedStep(id, collectStepProps(id, lines));
|
|
2442
|
+
}
|
|
2443
|
+
/** Validate collected props and build the ParsedStep. */
|
|
2444
|
+
function toParsedStep(id, props) {
|
|
2445
|
+
if (typeof props.command !== "string" || props.command === "") throw new MarkdownParseError(`invalid .sverka.md step '${id}': missing required '- command:' line`, "INVALID_STEP");
|
|
2446
|
+
const dependsOn = props.dependsOn ?? props["depends_on"];
|
|
2447
|
+
if (dependsOn !== void 0 && (!Array.isArray(dependsOn) || !dependsOn.every((d) => typeof d === "string"))) throw new MarkdownParseError(`invalid .sverka.md step '${id}': 'dependsOn' must be an array of step ids`, "INVALID_STEP");
|
|
2448
|
+
if (props.timeout !== void 0 && (typeof props.timeout !== "number" || !Number.isFinite(props.timeout))) throw new MarkdownParseError(`invalid .sverka.md step '${id}': 'timeout' must be a number (ms)`, "INVALID_STEP");
|
|
2449
|
+
if (props.image !== void 0 && typeof props.image !== "string") throw new MarkdownParseError(`invalid .sverka.md step '${id}': 'image' must be a string`, "INVALID_STEP");
|
|
2450
|
+
return {
|
|
2451
|
+
id,
|
|
2452
|
+
command: props.command,
|
|
2453
|
+
...dependsOn !== void 0 ? { dependsOn } : {},
|
|
2454
|
+
...props.image !== void 0 ? { image: props.image } : {},
|
|
2455
|
+
...props.timeout !== void 0 ? { timeout: props.timeout } : {},
|
|
2456
|
+
...props.outputs !== void 0 ? { outputs: props.outputs } : {}
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
/**
|
|
2460
|
+
* Collect `- key: value` bullets (with indented continuation blocks) into
|
|
2461
|
+
* a props map. Non-bullet prose is ignored.
|
|
2462
|
+
*/
|
|
2463
|
+
function collectStepProps(id, lines) {
|
|
2464
|
+
const props = {};
|
|
2465
|
+
let i = 0;
|
|
2466
|
+
while (i < lines.length) {
|
|
2467
|
+
const bullet = parseBulletLine(lines[i]);
|
|
2468
|
+
if (bullet === null) {
|
|
2469
|
+
i++;
|
|
2470
|
+
continue;
|
|
2471
|
+
}
|
|
2472
|
+
const { key, rest } = bullet;
|
|
2473
|
+
if (rest === "") {
|
|
2474
|
+
const block = [];
|
|
2475
|
+
let j = i + 1;
|
|
2476
|
+
while (j < lines.length && /^\s+\S/.test(lines[j])) {
|
|
2477
|
+
block.push(lines[j]);
|
|
2478
|
+
j++;
|
|
2479
|
+
}
|
|
2480
|
+
props[key] = block.length > 0 ? parseYamlScalar(block.join("\n"), id, key) : null;
|
|
2481
|
+
i = j;
|
|
2482
|
+
} else {
|
|
2483
|
+
props[key] = parseYamlScalar(rest, id, key);
|
|
2484
|
+
i++;
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
return props;
|
|
2488
|
+
}
|
|
2489
|
+
function parseYamlScalar(rest, stepId, key) {
|
|
2490
|
+
try {
|
|
2491
|
+
return parse(rest);
|
|
2492
|
+
} catch (e) {
|
|
2493
|
+
throw new MarkdownParseError(`invalid .sverka.md step '${stepId}': cannot parse '${key}' value: ${e instanceof Error ? e.message : String(e)}`, "INVALID_STEP", e);
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
function buildMarkdownPipeline(scope, fm, body, _filePath) {
|
|
2497
|
+
const pipeline = new Pipeline(scope, fm.pipeline, { ...fm.inputs !== void 0 ? { inputs: fm.inputs } : {} });
|
|
2498
|
+
const roots = parseSteps(body).map((step) => new ShellStep(pipeline, step.id, {
|
|
2499
|
+
command: step.command,
|
|
2500
|
+
...step.dependsOn !== void 0 ? { dependsOn: step.dependsOn } : {},
|
|
2501
|
+
...step.image !== void 0 ? { runtime: {
|
|
2502
|
+
mode: "container",
|
|
2503
|
+
image: step.image
|
|
2504
|
+
} } : {},
|
|
2505
|
+
...step.timeout !== void 0 ? { timeout: step.timeout } : {},
|
|
2506
|
+
...step.outputs !== void 0 ? { outputs: step.outputs } : {}
|
|
2507
|
+
})).map((s) => s.node.id);
|
|
2508
|
+
const triggers = frontmatterTriggers(fm);
|
|
2509
|
+
const usedIds = /* @__PURE__ */ new Set();
|
|
2510
|
+
for (const trigger of triggers) {
|
|
2511
|
+
const base = `on-${trigger.kind}`;
|
|
2512
|
+
let id = base;
|
|
2513
|
+
let n = 2;
|
|
2514
|
+
while (usedIds.has(id)) {
|
|
2515
|
+
id = `${base}-${n}`;
|
|
2516
|
+
n++;
|
|
2517
|
+
}
|
|
2518
|
+
const entry = new Entry(pipeline, id, {
|
|
2519
|
+
trigger,
|
|
2520
|
+
roots
|
|
2521
|
+
});
|
|
2522
|
+
usedIds.add(entry.node.id);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
async function loadExtends(extendsPath, mdPath) {
|
|
2526
|
+
const resolved = resolve(dirname(mdPath), extendsPath);
|
|
2527
|
+
if (!existsSync(resolved)) throw new MarkdownParseError(`extends path does not resolve: ${extendsPath} (from ${mdPath})`, "EXTENDS_NOT_FOUND");
|
|
2528
|
+
let mod;
|
|
2529
|
+
try {
|
|
2530
|
+
mod = await import(pathToFileURL(resolved).href);
|
|
2531
|
+
} catch (e) {
|
|
2532
|
+
throw new MarkdownParseError(`failed to load extends config ${extendsPath}: ${e instanceof Error ? e.message : String(e)}`, "EXTENDS_NOT_FOUND", e);
|
|
2533
|
+
}
|
|
2534
|
+
const construct = mod.project ?? mod.default;
|
|
2535
|
+
if (typeof construct !== "object" || construct === null || !("node" in construct)) throw new MarkdownParseError(`extends config ${extendsPath} must export a Project or Pipeline`, "EXTENDS_NOT_FOUND");
|
|
2536
|
+
return construct.node.scope ?? construct;
|
|
2537
|
+
}
|
|
2538
|
+
//#endregion
|
|
2539
|
+
export { $, CheckError, CompositionError, CoreError, DEFAULT_POLICY, DiscoveryError, MarkdownParseError, PlannerError, PlanningError, SdkError, agent, artifact, bindRunPlan, callPipeline, change, component, computeFingerprint, computePlanId, computeReachableSteps, createBaseline, createBuiltinResolver, createPlanner, createPolicy, createSverka, defineWorkflow, env, evaluatePolicy, event, execute, expandMatrixSteps, expr, extractFindings, filterOnlyNew, findConfig, git, image, images, inputs, loadBaseline, loadMarkdownFile, loadWorkflow, matrix, matrix$1 as matrixContext, normalizeSarif, parallel, parseMarkdown, pipeline, pipeline$1 as pipelineV0, plan, run, run$1 as runContext, saveBaseline, secrets, shell, status, task, toPlan, updateBaseline, validatePlan, when, when$1 as whenV0, workflow };
|
|
2215
2540
|
|
|
2216
2541
|
//# sourceMappingURL=index.mjs.map
|