@shipfox/api-definitions 11.0.0 → 12.2.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/.turbo/turbo-build.log +13 -12
- package/CHANGELOG.md +106 -0
- package/dist/core/entities/index.d.ts +1 -0
- package/dist/core/entities/index.d.ts.map +1 -1
- package/dist/core/entities/index.js +1 -0
- package/dist/core/entities/index.js.map +1 -1
- package/dist/core/entities/sync-state.d.ts +5 -1
- package/dist/core/entities/sync-state.d.ts.map +1 -1
- package/dist/core/entities/sync-state.js +10 -0
- package/dist/core/entities/sync-state.js.map +1 -1
- package/dist/core/entities/validation-warning.d.ts +6 -0
- package/dist/core/entities/validation-warning.d.ts.map +1 -0
- package/dist/core/entities/validation-warning.js +3 -0
- package/dist/core/entities/validation-warning.js.map +1 -0
- package/dist/core/errors.d.ts +2 -2
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/integrations.d.ts +1 -1
- package/dist/core/parse-definition.d.ts +9 -7
- package/dist/core/parse-definition.d.ts.map +1 -1
- package/dist/core/parse-definition.js +14 -2
- package/dist/core/parse-definition.js.map +1 -1
- package/dist/core/sync-definitions.d.ts +2 -0
- package/dist/core/sync-definitions.d.ts.map +1 -1
- package/dist/core/sync-definitions.js +6 -5
- package/dist/core/sync-definitions.js.map +1 -1
- package/dist/core/validate-definition.d.ts +9 -5
- package/dist/core/validate-definition.d.ts.map +1 -1
- package/dist/core/validate-definition.js +23 -2
- package/dist/core/validate-definition.js.map +1 -1
- package/dist/core/workflow-model/index.d.ts +1 -1
- package/dist/core/workflow-model/index.d.ts.map +1 -1
- package/dist/core/workflow-model/index.js.map +1 -1
- package/dist/core/workflow-model/invalid-workflow-model-error.d.ts +3 -1
- package/dist/core/workflow-model/invalid-workflow-model-error.d.ts.map +1 -1
- package/dist/core/workflow-model/invalid-workflow-model-error.js.map +1 -1
- package/dist/core/workflow-model/normalize-if-condition.d.ts +0 -1
- package/dist/core/workflow-model/normalize-if-condition.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-if-condition.js +0 -1
- package/dist/core/workflow-model/normalize-if-condition.js.map +1 -1
- package/dist/core/workflow-model/normalize-job-checkout.d.ts +15 -3
- package/dist/core/workflow-model/normalize-job-checkout.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-job-checkout.js +83 -4
- package/dist/core/workflow-model/normalize-job-checkout.js.map +1 -1
- package/dist/core/workflow-model/normalize-job-listening.js +0 -1
- package/dist/core/workflow-model/normalize-job-listening.js.map +1 -1
- package/dist/core/workflow-model/normalize-job-success.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-job-success.js +0 -1
- package/dist/core/workflow-model/normalize-job-success.js.map +1 -1
- package/dist/core/workflow-model/normalize-jobs.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-jobs.js +315 -74
- package/dist/core/workflow-model/normalize-jobs.js.map +1 -1
- package/dist/core/workflow-model/normalize-step-gate.js +0 -1
- package/dist/core/workflow-model/normalize-step-gate.js.map +1 -1
- package/dist/core/workflow-model/normalize-triggers.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-triggers.js +0 -1
- package/dist/core/workflow-model/normalize-triggers.js.map +1 -1
- package/dist/core/workflow-model/normalize-workflow-document.d.ts +3 -0
- package/dist/core/workflow-model/normalize-workflow-document.d.ts.map +1 -1
- package/dist/core/workflow-model/normalize-workflow-document.js +34 -4
- package/dist/core/workflow-model/normalize-workflow-document.js.map +1 -1
- package/dist/core/workflow-model/parse-interpolation-field.d.ts +1 -1
- package/dist/core/workflow-model/parse-interpolation-field.d.ts.map +1 -1
- package/dist/core/workflow-model/parse-interpolation-field.js +27 -57
- package/dist/core/workflow-model/parse-interpolation-field.js.map +1 -1
- package/dist/core/workflow-model/validate-literal-name.d.ts +12 -0
- package/dist/core/workflow-model/validate-literal-name.d.ts.map +1 -0
- package/dist/core/workflow-model/validate-literal-name.js +36 -0
- package/dist/core/workflow-model/validate-literal-name.js.map +1 -0
- package/dist/core/workflow-model/validate-predicate-expression.d.ts +1 -2
- package/dist/core/workflow-model/validate-predicate-expression.d.ts.map +1 -1
- package/dist/core/workflow-model/validate-predicate-expression.js +31 -90
- package/dist/core/workflow-model/validate-predicate-expression.js.map +1 -1
- package/dist/core/workflow-model/validation-issue.d.ts +2 -1
- package/dist/core/workflow-model/validation-issue.d.ts.map +1 -1
- package/dist/core/workflow-model/validation-issue.js +8 -2
- package/dist/core/workflow-model/validation-issue.js.map +1 -1
- package/dist/core/workflow-model/workflow-field-label.d.ts.map +1 -1
- package/dist/core/workflow-model/workflow-field-label.js +16 -2
- package/dist/core/workflow-model/workflow-field-label.js.map +1 -1
- package/dist/core/workflow-yaml/invalid-workflow-yaml-error.d.ts.map +1 -1
- package/dist/db/db.d.ts +48 -10
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/schema/definitions.d.ts +1 -1
- package/dist/db/schema/outbox.d.ts +1 -1
- package/dist/db/schema/sync-states.d.ts +22 -3
- package/dist/db/schema/sync-states.d.ts.map +1 -1
- package/dist/db/schema/sync-states.js +3 -1
- package/dist/db/schema/sync-states.js.map +1 -1
- package/dist/db/sync-states.d.ts +2 -1
- package/dist/db/sync-states.d.ts.map +1 -1
- package/dist/db/sync-states.js +4 -0
- package/dist/db/sync-states.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/presentation/dto/definition.d.ts.map +1 -1
- package/dist/presentation/dto/definition.js +2 -1
- package/dist/presentation/dto/definition.js.map +1 -1
- package/dist/presentation/routes/project-access.d.ts +1 -0
- package/dist/presentation/routes/project-access.d.ts.map +1 -1
- package/dist/presentation/routes/validate-definition.d.ts.map +1 -1
- package/dist/presentation/routes/validate-definition.js +5 -3
- package/dist/presentation/routes/validate-definition.js.map +1 -1
- package/dist/presentation/subscribers/index.d.ts +1 -0
- package/dist/presentation/subscribers/index.d.ts.map +1 -1
- package/dist/presentation/subscribers/index.js +1 -0
- package/dist/presentation/subscribers/index.js.map +1 -1
- package/dist/presentation/subscribers/on-integration-connection-available.d.ts +5 -0
- package/dist/presentation/subscribers/on-integration-connection-available.d.ts.map +1 -0
- package/dist/presentation/subscribers/on-integration-connection-available.js +32 -0
- package/dist/presentation/subscribers/on-integration-connection-available.js.map +1 -0
- package/dist/presentation/subscribers/start-definition-sync.d.ts +1 -0
- package/dist/presentation/subscribers/start-definition-sync.d.ts.map +1 -1
- package/dist/presentation/subscribers/start-definition-sync.js +30 -17
- package/dist/presentation/subscribers/start-definition-sync.js.map +1 -1
- package/dist/temporal/activities/sync-activities.d.ts +6 -2
- package/dist/temporal/activities/sync-activities.d.ts.map +1 -1
- package/dist/temporal/activities/sync-activities.js +8 -1
- package/dist/temporal/activities/sync-activities.js.map +1 -1
- package/dist/temporal/workflows/definition-sync.js +4 -1
- package/dist/temporal/workflows/definition-sync.js.map +1 -1
- package/dist/temporal/workflows/index.bundle.js +9029 -3
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0002_lumpy_ben_parker.sql +1 -0
- package/drizzle/meta/0002_snapshot.json +534 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +17 -17
- package/src/core/entities/index.ts +1 -0
- package/src/core/entities/sync-state.ts +23 -0
- package/src/core/entities/validation-warning.ts +5 -0
- package/src/core/parse-definition-warnings.test.ts +33 -0
- package/src/core/parse-definition.test.ts +7 -1
- package/src/core/parse-definition.ts +28 -10
- package/src/core/sync-definitions.test.ts +39 -0
- package/src/core/sync-definitions.ts +14 -4
- package/src/core/validate-definition.test.ts +128 -0
- package/src/core/validate-definition.ts +39 -8
- package/src/core/workflow-model/README.md +2 -2
- package/src/core/workflow-model/index.ts +1 -0
- package/src/core/workflow-model/invalid-workflow-model-error.ts +8 -3
- package/src/core/workflow-model/normalize-if-condition.ts +0 -2
- package/src/core/workflow-model/normalize-job-checkout.ts +105 -8
- package/src/core/workflow-model/normalize-job-listening.ts +0 -1
- package/src/core/workflow-model/normalize-job-success.ts +0 -1
- package/src/core/workflow-model/normalize-jobs.ts +335 -90
- package/src/core/workflow-model/normalize-step-gate.ts +0 -1
- package/src/core/workflow-model/normalize-triggers.ts +0 -1
- package/src/core/workflow-model/normalize-workflow-document.test.ts +876 -202
- package/src/core/workflow-model/normalize-workflow-document.ts +29 -4
- package/src/core/workflow-model/parse-interpolation-field.ts +50 -79
- package/src/core/workflow-model/validate-literal-name.ts +64 -0
- package/src/core/workflow-model/validate-predicate-expression.test.ts +153 -15
- package/src/core/workflow-model/validate-predicate-expression.ts +52 -120
- package/src/core/workflow-model/validation-issue.ts +4 -0
- package/src/core/workflow-model/workflow-field-label.ts +16 -2
- package/src/core/workflow-yaml/README.md +2 -2
- package/src/db/schema/sync-states.ts +4 -1
- package/src/db/sync-states.test.ts +57 -0
- package/src/db/sync-states.ts +6 -0
- package/src/index.ts +12 -1
- package/src/presentation/dto/definition.ts +1 -0
- package/src/presentation/routes/list-definitions.test.ts +1 -0
- package/src/presentation/routes/validate-definition.test.ts +1 -0
- package/src/presentation/routes/validate-definition.ts +7 -1
- package/src/presentation/subscribers/index.ts +1 -0
- package/src/presentation/subscribers/on-integration-connection-available.test.ts +132 -0
- package/src/presentation/subscribers/on-integration-connection-available.ts +44 -0
- package/src/presentation/subscribers/start-definition-sync.ts +35 -19
- package/src/temporal/activities/sync-activities.test.ts +16 -0
- package/src/temporal/activities/sync-activities.ts +18 -3
- package/src/temporal/workflows/definition-sync.ts +1 -1
- package/test/agent-validation-catalog.ts +17 -0
- package/test/fixtures/valid-listening-job.yml +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { secretKeySchema, secretStoreSchema } from '@shipfox/api-secrets-dto';
|
|
2
|
-
import { analyzeContextKeyAccess,
|
|
2
|
+
import { analyzeContextKeyAccess, analyzeContextRootKeyAccess, createWorkflowExpression, getWorkflowContextAvailability, getWorkflowContextDefinition, getWorkflowContextHost, getWorkflowContextTypeEnvironment, getWorkflowInterpolationFieldSelfReference, InvalidWorkflowExpressionError, InvalidWorkflowTemplateError, parseWorkflowTemplate, planInterpolationField, unavailableRootsAt, workflowContextNames, workflowInterpolationFieldAcceptsHost } from '@shipfox/expression';
|
|
3
3
|
import { validateDirectJobReferences } from './validate-job-references.js';
|
|
4
4
|
export function parseInterpolationField(params) {
|
|
5
5
|
const segments = parseTemplate(params);
|
|
@@ -24,6 +24,27 @@ export function parseInterpolationField(params) {
|
|
|
24
24
|
}
|
|
25
25
|
return plan.plan.field.segments;
|
|
26
26
|
}
|
|
27
|
+
function dynamicNameSelfReference(params) {
|
|
28
|
+
const target = getWorkflowInterpolationFieldSelfReference(params.field);
|
|
29
|
+
if (target === undefined) return undefined;
|
|
30
|
+
const access = analyzeContextRootKeyAccess(params.segment.expression, [
|
|
31
|
+
target.root
|
|
32
|
+
]);
|
|
33
|
+
const reference = access.references.find((entry)=>entry.key === target.key);
|
|
34
|
+
const computedReference = access.violations.find((violation)=>violation.root === target.root && (violation.key === undefined || violation.key === target.key));
|
|
35
|
+
if (reference === undefined && computedReference === undefined) return undefined;
|
|
36
|
+
return issue({
|
|
37
|
+
code: 'dynamic-name-self-reference',
|
|
38
|
+
message: `${fieldLabel(params.field)} interpolation cannot reference its own dynamic name.`,
|
|
39
|
+
path: params.path,
|
|
40
|
+
details: {
|
|
41
|
+
field: params.field,
|
|
42
|
+
source: params.source,
|
|
43
|
+
expression: params.segment.expression.source,
|
|
44
|
+
reference: reference === undefined ? `${target.root}[computed]` : `${reference.root}.${reference.key}`
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
27
48
|
function parseTemplate(params) {
|
|
28
49
|
try {
|
|
29
50
|
return parseWorkflowTemplate(params.source);
|
|
@@ -45,15 +66,6 @@ function validateExpressionSegment(params) {
|
|
|
45
66
|
const contextRoots = uniqueStrings(params.segment.contextRoots);
|
|
46
67
|
const knownRoots = contextRoots.filter(isWorkflowContextName);
|
|
47
68
|
const unknownRoots = contextRoots.filter((root)=>!isWorkflowContextName(root));
|
|
48
|
-
const rejectedRoots = knownRoots.filter((root)=>!workflowInterpolationFieldAcceptsContext(params.field, root));
|
|
49
|
-
if (rejectedRoots.length > 0) {
|
|
50
|
-
params.issues.push(untrustedContextIssue({
|
|
51
|
-
...params,
|
|
52
|
-
contextRoots,
|
|
53
|
-
rejectedRoots
|
|
54
|
-
}));
|
|
55
|
-
return undefined;
|
|
56
|
-
}
|
|
57
69
|
const rejectedHostRoots = knownRoots.filter((root)=>!workflowInterpolationFieldAcceptsHost(params.field, getWorkflowContextHost(root)));
|
|
58
70
|
if (rejectedHostRoots.length > 0) {
|
|
59
71
|
params.issues.push(runnerContextInFieldIssue({
|
|
@@ -73,6 +85,11 @@ function validateExpressionSegment(params) {
|
|
|
73
85
|
})));
|
|
74
86
|
return undefined;
|
|
75
87
|
}
|
|
88
|
+
const selfReference = dynamicNameSelfReference(params);
|
|
89
|
+
if (selfReference !== undefined) {
|
|
90
|
+
params.issues.push(selfReference);
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
76
93
|
const invalidReferenceIssue = validateContextKeyReferences({
|
|
77
94
|
...params,
|
|
78
95
|
contextRoots,
|
|
@@ -93,15 +110,6 @@ function validateExpressionSegment(params) {
|
|
|
93
110
|
params.issues.push(invalidJobReferenceIssue);
|
|
94
111
|
return undefined;
|
|
95
112
|
}
|
|
96
|
-
const rejectedPathRoots = findUntrustedPathRoots(params.segment, params.field, knownRoots);
|
|
97
|
-
if (rejectedPathRoots.length > 0) {
|
|
98
|
-
params.issues.push(untrustedContextIssue({
|
|
99
|
-
...params,
|
|
100
|
-
contextRoots,
|
|
101
|
-
rejectedRoots: rejectedPathRoots
|
|
102
|
-
}));
|
|
103
|
-
return undefined;
|
|
104
|
-
}
|
|
105
113
|
if (unknownRoots.length > 0) {
|
|
106
114
|
params.issues.push(issue({
|
|
107
115
|
code: 'unknown-interpolation-context',
|
|
@@ -163,44 +171,6 @@ function validateExpressionSegment(params) {
|
|
|
163
171
|
return undefined;
|
|
164
172
|
}
|
|
165
173
|
}
|
|
166
|
-
function findUntrustedPathRoots(segment, field, knownRoots) {
|
|
167
|
-
if (!isTrustedOnlyField(field)) return [];
|
|
168
|
-
const untrustedPathsByRoot = new Map();
|
|
169
|
-
for (const root of knownRoots){
|
|
170
|
-
const paths = getWorkflowContextUntrustedPaths(root);
|
|
171
|
-
if (paths === undefined || paths.length === 0) continue;
|
|
172
|
-
untrustedPathsByRoot.set(root, paths);
|
|
173
|
-
}
|
|
174
|
-
if (knownRoots.includes('steps')) {
|
|
175
|
-
untrustedPathsByRoot.set('steps', [
|
|
176
|
-
...new Set([
|
|
177
|
-
...untrustedPathsByRoot.get('steps') ?? [],
|
|
178
|
-
'outputs'
|
|
179
|
-
])
|
|
180
|
-
]);
|
|
181
|
-
}
|
|
182
|
-
if (untrustedPathsByRoot.size === 0) return [];
|
|
183
|
-
return extractCelUntrustedPathAccesses({
|
|
184
|
-
source: segment.expression.source,
|
|
185
|
-
untrustedPathsByRoot
|
|
186
|
-
}).filter(isWorkflowContextName);
|
|
187
|
-
}
|
|
188
|
-
function isTrustedOnlyField(field) {
|
|
189
|
-
return !workflowInterpolationFieldAcceptsTrustTier(field, 'untrusted');
|
|
190
|
-
}
|
|
191
|
-
function untrustedContextIssue(params) {
|
|
192
|
-
return issue({
|
|
193
|
-
code: 'untrusted-context-in-field',
|
|
194
|
-
message: params.field === 'run' ? `Run command interpolation cannot use untrusted context ${formatList(params.rejectedRoots)}. Bind untrusted values to env and reference the shell variable from run instead.` : `${fieldLabel(params.field)} interpolation cannot use untrusted context ${formatList(params.rejectedRoots)}.`,
|
|
195
|
-
path: params.path,
|
|
196
|
-
details: {
|
|
197
|
-
field: params.field,
|
|
198
|
-
source: params.source,
|
|
199
|
-
contextRoots: params.contextRoots,
|
|
200
|
-
rejectedRoots: params.rejectedRoots
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
174
|
function runnerContextInFieldIssue(params) {
|
|
205
175
|
return issue({
|
|
206
176
|
code: 'runner-context-in-field',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/workflow-model/parse-interpolation-field.ts"],"sourcesContent":["import {secretKeySchema, secretStoreSchema} from '@shipfox/api-secrets-dto';\nimport {\n type AvailabilitySite,\n analyzeContextKeyAccess,\n createWorkflowExpression,\n type ExpressionTypeEnvironment,\n extractCelUntrustedPathAccesses,\n getWorkflowContextAvailability,\n getWorkflowContextDefinition,\n getWorkflowContextHost,\n getWorkflowContextTypeEnvironment,\n getWorkflowContextUntrustedPaths,\n InvalidWorkflowExpressionError,\n InvalidWorkflowTemplateError,\n type PlanViolation,\n parseWorkflowTemplate,\n planInterpolationField,\n unavailableRootsAt,\n type WorkflowContextName,\n type WorkflowInterpolationField,\n type WorkflowTemplateExprSegment,\n type WorkflowTemplateSegment,\n workflowContextNames,\n workflowInterpolationFieldAcceptsContext,\n workflowInterpolationFieldAcceptsHost,\n workflowInterpolationFieldAcceptsTrustTier,\n} from '@shipfox/expression';\nimport type {WorkflowFieldTemplate} from '../entities/workflow-model.js';\nimport type {\n WorkflowModelValidationIssue,\n WorkflowModelValidationIssueCode,\n WorkflowModelValidationIssuePathSegment,\n} from './invalid-workflow-model-error.js';\nimport {validateDirectJobReferences} from './validate-job-references.js';\n\nexport type StoredInterpolationField =\n | 'run'\n | 'env.value'\n | 'agent.prompt'\n | 'agent.model'\n | 'agent.provider'\n | 'job.outputs'\n | 'job.name'\n | 'job.runner'\n | 'step.name'\n | 'step.feedback';\n\nexport function parseInterpolationField(params: {\n field: StoredInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n issues: WorkflowModelValidationIssue[];\n fillSite?: AvailabilitySite;\n allowedJobReferences?: ReadonlySet<string>;\n typeOverlay?: ExpressionTypeEnvironment | undefined;\n}): WorkflowFieldTemplate | undefined {\n const segments = parseTemplate(params);\n if (segments === undefined) return undefined;\n\n const expressionSegments = segments.filter(isExpressionSegment);\n if (expressionSegments.length === 0) return undefined;\n\n const checkedSegments = segments.map((segment) => {\n if (segment.kind === 'literal') return segment;\n\n const validatedSegment = validateExpressionSegment({...params, segment});\n return validatedSegment ?? segment;\n });\n\n const plan = planInterpolationField({field: params.field, segments: checkedSegments});\n if (!plan.ok) {\n params.issues.push(\n ...plan.violations.map((violation) => planViolationIssue(params, violation)),\n );\n return undefined;\n }\n\n return plan.plan.field.segments;\n}\n\nfunction parseTemplate(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n issues: WorkflowModelValidationIssue[];\n}): WorkflowTemplateSegment[] | undefined {\n try {\n return parseWorkflowTemplate(params.source);\n } catch (error) {\n params.issues.push(\n issue({\n code: 'invalid-interpolation-template',\n message: `${fieldLabel(params.field)} must use valid $${'{{ }}'} interpolation syntax.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n reason:\n error instanceof InvalidWorkflowTemplateError\n ? error.reason\n : 'Template source did not parse.',\n },\n }),\n );\n return undefined;\n }\n}\n\nfunction validateExpressionSegment(params: {\n field: StoredInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n issues: WorkflowModelValidationIssue[];\n segment: WorkflowTemplateExprSegment;\n fillSite?: AvailabilitySite;\n allowedJobReferences?: ReadonlySet<string>;\n typeOverlay?: ExpressionTypeEnvironment | undefined;\n}): WorkflowTemplateExprSegment | undefined {\n const contextRoots = uniqueStrings(params.segment.contextRoots);\n const knownRoots = contextRoots.filter(isWorkflowContextName);\n const unknownRoots = contextRoots.filter((root) => !isWorkflowContextName(root));\n\n const rejectedRoots = knownRoots.filter(\n (root) => !workflowInterpolationFieldAcceptsContext(params.field, root),\n );\n if (rejectedRoots.length > 0) {\n params.issues.push(untrustedContextIssue({...params, contextRoots, rejectedRoots}));\n return undefined;\n }\n\n const rejectedHostRoots = knownRoots.filter(\n (root) => !workflowInterpolationFieldAcceptsHost(params.field, getWorkflowContextHost(root)),\n );\n if (rejectedHostRoots.length > 0) {\n params.issues.push(runnerContextInFieldIssue({...params, contextRoots, rejectedHostRoots}));\n return undefined;\n }\n\n const keyAccess = analyzeContextKeyAccess(params.segment.expression);\n if (keyAccess.violations.length > 0) {\n params.issues.push(\n ...keyAccess.violations.map((violation) =>\n computedContextKeyIssue({\n ...params,\n contextRoots,\n root: violation.root,\n expression: violation.source,\n }),\n ),\n );\n return undefined;\n }\n\n const invalidReferenceIssue = validateContextKeyReferences({\n ...params,\n contextRoots,\n references: keyAccess.references,\n });\n if (invalidReferenceIssue !== undefined) {\n params.issues.push(invalidReferenceIssue);\n return undefined;\n }\n\n const invalidJobReferenceIssue =\n params.allowedJobReferences === undefined\n ? undefined\n : validateDirectJobReferences({\n source: params.source,\n expression: params.segment.expression,\n field: params.field,\n path: params.path,\n allowedJobReferences: params.allowedJobReferences,\n });\n if (invalidJobReferenceIssue !== undefined) {\n params.issues.push(invalidJobReferenceIssue);\n return undefined;\n }\n\n const rejectedPathRoots = findUntrustedPathRoots(params.segment, params.field, knownRoots);\n if (rejectedPathRoots.length > 0) {\n params.issues.push(\n untrustedContextIssue({...params, contextRoots, rejectedRoots: rejectedPathRoots}),\n );\n return undefined;\n }\n\n if (unknownRoots.length > 0) {\n params.issues.push(\n issue({\n code: 'unknown-interpolation-context',\n message: `${fieldLabel(params.field)} interpolation references unknown context ${formatList(\n unknownRoots,\n )}.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.segment.expression.source,\n contextRoots,\n unknownRoots,\n },\n }),\n );\n return undefined;\n }\n\n const fillSite = params.fillSite;\n if (fillSite !== undefined) {\n const serverRoots = knownRoots.filter((root) => getWorkflowContextHost(root) === 'server');\n const unavailableRoots = unavailableRootsAt(serverRoots, fillSite);\n if (unavailableRoots.length > 0) {\n params.issues.push(\n unavailableContextIssue({...params, contextRoots, unavailableRoots, fillSite}),\n );\n return undefined;\n }\n }\n\n if (\n params.typeOverlay === undefined &&\n (knownRoots.length === 0 || knownRoots.some((root) => hasSyntaxOnlyCheckMode(root)))\n ) {\n return params.segment;\n }\n\n try {\n return {\n ...params.segment,\n expression: createWorkflowExpression({\n source: params.segment.expression.source,\n check: {\n mode: 'typed',\n // `undefined` preserves the legacy syntax-only path above. `{}` means\n // callers intentionally requested typed checking with the standard roots.\n typeEnvironment: mergeTypeEnvironments(knownRoots, params.typeOverlay),\n },\n }),\n };\n } catch (error) {\n params.issues.push(\n issue({\n code: 'invalid-interpolation-expression',\n message: `${fieldLabel(params.field)} interpolation expression did not type-check.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.segment.expression.source,\n contextRoots,\n reason:\n error instanceof InvalidWorkflowExpressionError\n ? error.reason\n : 'Expression source did not type-check.',\n },\n }),\n );\n return undefined;\n }\n}\n\nfunction findUntrustedPathRoots(\n segment: WorkflowTemplateExprSegment,\n field: StoredInterpolationField,\n knownRoots: readonly WorkflowContextName[],\n): readonly WorkflowContextName[] {\n if (!isTrustedOnlyField(field)) return [];\n\n const untrustedPathsByRoot = new Map<string, readonly string[]>();\n for (const root of knownRoots) {\n const paths = getWorkflowContextUntrustedPaths(root);\n if (paths === undefined || paths.length === 0) continue;\n untrustedPathsByRoot.set(root, paths);\n }\n if (knownRoots.includes('steps')) {\n untrustedPathsByRoot.set('steps', [\n ...new Set([...(untrustedPathsByRoot.get('steps') ?? []), 'outputs']),\n ]);\n }\n if (untrustedPathsByRoot.size === 0) return [];\n\n return extractCelUntrustedPathAccesses({\n source: segment.expression.source,\n untrustedPathsByRoot,\n }).filter(isWorkflowContextName);\n}\n\nfunction isTrustedOnlyField(field: StoredInterpolationField): boolean {\n return !workflowInterpolationFieldAcceptsTrustTier(field, 'untrusted');\n}\n\nfunction untrustedContextIssue(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n contextRoots: readonly string[];\n rejectedRoots: readonly WorkflowContextName[];\n}): WorkflowModelValidationIssue {\n return issue({\n code: 'untrusted-context-in-field',\n message:\n params.field === 'run'\n ? `Run command interpolation cannot use untrusted context ${formatList(\n params.rejectedRoots,\n )}. Bind untrusted values to env and reference the shell variable from run instead.`\n : `${fieldLabel(params.field)} interpolation cannot use untrusted context ${formatList(\n params.rejectedRoots,\n )}.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n contextRoots: params.contextRoots,\n rejectedRoots: params.rejectedRoots,\n },\n });\n}\n\nfunction runnerContextInFieldIssue(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n contextRoots: readonly string[];\n rejectedHostRoots: readonly WorkflowContextName[];\n}): WorkflowModelValidationIssue {\n return issue({\n code: 'runner-context-in-field',\n message: `${fieldLabel(params.field)} interpolation cannot use runner context ${formatList(\n params.rejectedHostRoots,\n )}. Bind secrets to a run-step env value instead.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n contextRoots: params.contextRoots,\n rejectedRoots: params.rejectedHostRoots,\n },\n });\n}\n\nfunction computedContextKeyIssue(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n contextRoots: readonly string[];\n root: string;\n expression: string;\n}): WorkflowModelValidationIssue {\n return issue({\n code: 'computed-context-key',\n message: `${fieldLabel(params.field)} interpolation must reference ${params.root} with a literal dot key.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.expression,\n contextRoots: params.contextRoots,\n root: params.root,\n },\n });\n}\n\nfunction validateContextKeyReferences(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n contextRoots: readonly string[];\n segment: WorkflowTemplateExprSegment;\n references: ReturnType<typeof analyzeContextKeyAccess>['references'];\n}): WorkflowModelValidationIssue | undefined {\n for (const reference of params.references) {\n if (!secretKeySchema.safeParse(reference.key).success) {\n return computedContextKeyIssue({\n ...params,\n root: reference.root,\n expression: params.segment.expression.source,\n });\n }\n\n if (reference.root !== 'secrets' || reference.store === undefined) continue;\n if (secretStoreSchema.safeParse(reference.store).success) continue;\n\n return issue({\n code: 'unknown-secret-store',\n message: `${fieldLabel(params.field)} interpolation references unknown secret store \"${reference.store}\".`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.segment.expression.source,\n contextRoots: params.contextRoots,\n store: reference.store,\n },\n });\n }\n\n return undefined;\n}\n\nconst availabilitySiteLabels = {\n ingest: 'ingest',\n 'run-creation': 'run creation',\n 'execution-creation': 'execution creation',\n 'job-activation': 'job activation',\n 'step-dispatch': 'step dispatch',\n 'step-report': 'step reporting',\n 'execution-resolution': 'execution resolution',\n 'job-resolution': 'job resolution',\n} as const satisfies Record<AvailabilitySite, string>;\n\nfunction unavailableContextIssue(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n segment: WorkflowTemplateExprSegment;\n contextRoots: readonly string[];\n unavailableRoots: readonly WorkflowContextName[];\n fillSite: AvailabilitySite;\n}): WorkflowModelValidationIssue {\n return issue({\n code: 'context-unavailable-at-fill-site',\n message: `${fieldLabel(params.field)} interpolation references ${contextNoun(\n params.unavailableRoots,\n )} ${formatList(params.unavailableRoots)} that ${availabilityVerb(\n params.unavailableRoots,\n )} not available at ${describeAvailabilitySite(params.fillSite)}. ${params.unavailableRoots\n .map(unavailableRootAvailabilityMessage)\n .join(' ')}`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.segment.expression.source,\n contextRoots: params.contextRoots,\n unavailableRoots: params.unavailableRoots,\n fillSite: params.fillSite,\n },\n });\n}\n\nfunction planViolationIssue(\n params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n },\n violation: PlanViolation,\n): WorkflowModelValidationIssue {\n if (violation.reason === 'computed-context-key') {\n return issue({\n code: 'computed-context-key',\n message: `${fieldLabel(params.field)} interpolation must reference ${formatList(\n violation.contextRoots ?? [],\n )} with a literal dot key.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: violation.source,\n contextRoots: violation.contextRoots,\n },\n });\n }\n\n return issue({\n code: 'runner-context-not-bare',\n message: `${fieldLabel(params.field)} interpolation references runner context in a larger expression; ${violation.hint}.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: violation.source,\n runnerRoots: violation.runnerRoots ?? [],\n },\n });\n}\n\nfunction contextNoun(roots: readonly WorkflowContextName[]): 'context' | 'contexts' {\n return roots.length === 1 ? 'context' : 'contexts';\n}\n\nfunction availabilityVerb(roots: readonly WorkflowContextName[]): 'is' | 'are' {\n return roots.length === 1 ? 'is' : 'are';\n}\n\nfunction unavailableRootAvailabilityMessage(root: WorkflowContextName): string {\n const availability = getWorkflowContextAvailability(root);\n if (availability === undefined) return `\"${root}\" is not available at any server site.`;\n return `\"${root}\" becomes available at ${describeAvailabilitySite(availability)}.`;\n}\n\nfunction describeAvailabilitySite(site: AvailabilitySite): string {\n return availabilitySiteLabels[site];\n}\n\nfunction hasSyntaxOnlyCheckMode(root: WorkflowContextName): boolean {\n return getWorkflowContextDefinition(root).checkMode === 'syntax';\n}\n\nfunction mergeTypeEnvironments(\n roots: readonly WorkflowContextName[],\n typeOverlay?: ExpressionTypeEnvironment,\n): ExpressionTypeEnvironment {\n const typeEnvironment: Record<string, ExpressionTypeEnvironment[string]> = {};\n\n for (const root of roots) {\n const overlayType = typeOverlay?.[root];\n if (overlayType !== undefined) {\n typeEnvironment[root] = overlayType;\n continue;\n }\n\n const contextTypeEnvironment = getWorkflowContextTypeEnvironment(root);\n if (contextTypeEnvironment === undefined) {\n if (typeOverlay !== undefined) typeEnvironment[root] = {kind: 'map'};\n continue;\n }\n\n Object.assign(typeEnvironment, contextTypeEnvironment);\n }\n\n return typeEnvironment;\n}\n\nfunction isExpressionSegment(\n segment: WorkflowTemplateSegment,\n): segment is WorkflowTemplateExprSegment {\n return segment.kind === 'expr';\n}\n\nfunction isWorkflowContextName(root: string): root is WorkflowContextName {\n return (workflowContextNames as readonly string[]).includes(root);\n}\n\nfunction uniqueStrings(values: readonly string[]): readonly string[] {\n return [...new Set(values)];\n}\n\nfunction formatList(values: readonly string[]): string {\n return values.map((value) => `\"${value}\"`).join(', ');\n}\n\nfunction fieldLabel(field: WorkflowInterpolationField): string {\n return `Workflow ${field}`;\n}\n\nfunction issue(params: {\n code: WorkflowModelValidationIssueCode;\n message: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n details?: Readonly<Record<string, unknown>>;\n}): WorkflowModelValidationIssue {\n if (params.details === undefined) {\n return {\n code: params.code,\n message: params.message,\n path: params.path,\n };\n }\n\n return {\n code: params.code,\n message: params.message,\n path: params.path,\n details: params.details,\n };\n}\n"],"names":["secretKeySchema","secretStoreSchema","analyzeContextKeyAccess","createWorkflowExpression","extractCelUntrustedPathAccesses","getWorkflowContextAvailability","getWorkflowContextDefinition","getWorkflowContextHost","getWorkflowContextTypeEnvironment","getWorkflowContextUntrustedPaths","InvalidWorkflowExpressionError","InvalidWorkflowTemplateError","parseWorkflowTemplate","planInterpolationField","unavailableRootsAt","workflowContextNames","workflowInterpolationFieldAcceptsContext","workflowInterpolationFieldAcceptsHost","workflowInterpolationFieldAcceptsTrustTier","validateDirectJobReferences","parseInterpolationField","params","segments","parseTemplate","undefined","expressionSegments","filter","isExpressionSegment","length","checkedSegments","map","segment","kind","validatedSegment","validateExpressionSegment","plan","field","ok","issues","push","violations","violation","planViolationIssue","source","error","issue","code","message","fieldLabel","path","details","reason","contextRoots","uniqueStrings","knownRoots","isWorkflowContextName","unknownRoots","root","rejectedRoots","untrustedContextIssue","rejectedHostRoots","runnerContextInFieldIssue","keyAccess","expression","computedContextKeyIssue","invalidReferenceIssue","validateContextKeyReferences","references","invalidJobReferenceIssue","allowedJobReferences","rejectedPathRoots","findUntrustedPathRoots","formatList","fillSite","serverRoots","unavailableRoots","unavailableContextIssue","typeOverlay","some","hasSyntaxOnlyCheckMode","check","mode","typeEnvironment","mergeTypeEnvironments","isTrustedOnlyField","untrustedPathsByRoot","Map","paths","set","includes","Set","get","size","reference","safeParse","key","success","store","availabilitySiteLabels","ingest","contextNoun","availabilityVerb","describeAvailabilitySite","unavailableRootAvailabilityMessage","join","hint","runnerRoots","roots","availability","site","checkMode","overlayType","contextTypeEnvironment","Object","assign","values","value"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/workflow-model/parse-interpolation-field.ts"],"sourcesContent":["import {secretKeySchema, secretStoreSchema} from '@shipfox/api-secrets-dto';\nimport {\n type AvailabilitySite,\n analyzeContextKeyAccess,\n analyzeContextRootKeyAccess,\n createWorkflowExpression,\n type ExpressionTypeEnvironment,\n getWorkflowContextAvailability,\n getWorkflowContextDefinition,\n getWorkflowContextHost,\n getWorkflowContextTypeEnvironment,\n getWorkflowInterpolationFieldSelfReference,\n InvalidWorkflowExpressionError,\n InvalidWorkflowTemplateError,\n type PlanViolation,\n parseWorkflowTemplate,\n planInterpolationField,\n unavailableRootsAt,\n type WorkflowContextName,\n type WorkflowInterpolationField,\n type WorkflowTemplateExprSegment,\n type WorkflowTemplateSegment,\n workflowContextNames,\n workflowInterpolationFieldAcceptsHost,\n} from '@shipfox/expression';\nimport type {WorkflowFieldTemplate} from '../entities/workflow-model.js';\nimport type {\n WorkflowModelValidationIssue,\n WorkflowModelValidationIssueCode,\n WorkflowModelValidationIssuePathSegment,\n} from './invalid-workflow-model-error.js';\nimport {validateDirectJobReferences} from './validate-job-references.js';\n\nexport type StoredInterpolationField =\n | 'run'\n | 'env.value'\n | 'agent.prompt'\n | 'agent.model'\n | 'agent.provider'\n | 'agent.thinking'\n | 'job.outputs'\n | 'workflow.run_name'\n | 'job.execution_name'\n | 'job.runner'\n | 'step.name'\n | 'step.working_directory'\n | 'step.feedback'\n | 'checkout.project'\n | 'checkout.connection'\n | 'checkout.repository'\n | 'checkout.ref'\n | 'checkout.path';\n\nexport function parseInterpolationField(params: {\n field: StoredInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n issues: WorkflowModelValidationIssue[];\n fillSite?: AvailabilitySite;\n allowedJobReferences?: ReadonlySet<string>;\n typeOverlay?: ExpressionTypeEnvironment | undefined;\n}): WorkflowFieldTemplate | undefined {\n const segments = parseTemplate(params);\n if (segments === undefined) return undefined;\n\n const expressionSegments = segments.filter(isExpressionSegment);\n if (expressionSegments.length === 0) return undefined;\n\n const checkedSegments = segments.map((segment) => {\n if (segment.kind === 'literal') return segment;\n\n const validatedSegment = validateExpressionSegment({...params, segment});\n return validatedSegment ?? segment;\n });\n\n const plan = planInterpolationField({field: params.field, segments: checkedSegments});\n if (!plan.ok) {\n params.issues.push(\n ...plan.violations.map((violation) => planViolationIssue(params, violation)),\n );\n return undefined;\n }\n\n return plan.plan.field.segments;\n}\n\nfunction dynamicNameSelfReference(params: {\n field: StoredInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n segment: WorkflowTemplateExprSegment;\n}): WorkflowModelValidationIssue | undefined {\n const target = getWorkflowInterpolationFieldSelfReference(params.field);\n if (target === undefined) return undefined;\n\n const access = analyzeContextRootKeyAccess(params.segment.expression, [target.root]);\n const reference = access.references.find((entry) => entry.key === target.key);\n const computedReference = access.violations.find(\n (violation) =>\n violation.root === target.root &&\n (violation.key === undefined || violation.key === target.key),\n );\n if (reference === undefined && computedReference === undefined) return undefined;\n\n return issue({\n code: 'dynamic-name-self-reference',\n message: `${fieldLabel(params.field)} interpolation cannot reference its own dynamic name.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.segment.expression.source,\n reference:\n reference === undefined ? `${target.root}[computed]` : `${reference.root}.${reference.key}`,\n },\n });\n}\n\nfunction parseTemplate(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n issues: WorkflowModelValidationIssue[];\n}): WorkflowTemplateSegment[] | undefined {\n try {\n return parseWorkflowTemplate(params.source);\n } catch (error) {\n params.issues.push(\n issue({\n code: 'invalid-interpolation-template',\n message: `${fieldLabel(params.field)} must use valid $${'{{ }}'} interpolation syntax.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n reason:\n error instanceof InvalidWorkflowTemplateError\n ? error.reason\n : 'Template source did not parse.',\n },\n }),\n );\n return undefined;\n }\n}\n\nfunction validateExpressionSegment(params: {\n field: StoredInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n issues: WorkflowModelValidationIssue[];\n segment: WorkflowTemplateExprSegment;\n fillSite?: AvailabilitySite;\n allowedJobReferences?: ReadonlySet<string>;\n typeOverlay?: ExpressionTypeEnvironment | undefined;\n}): WorkflowTemplateExprSegment | undefined {\n const contextRoots = uniqueStrings(params.segment.contextRoots);\n const knownRoots = contextRoots.filter(isWorkflowContextName);\n const unknownRoots = contextRoots.filter((root) => !isWorkflowContextName(root));\n\n const rejectedHostRoots = knownRoots.filter(\n (root) => !workflowInterpolationFieldAcceptsHost(params.field, getWorkflowContextHost(root)),\n );\n if (rejectedHostRoots.length > 0) {\n params.issues.push(runnerContextInFieldIssue({...params, contextRoots, rejectedHostRoots}));\n return undefined;\n }\n\n const keyAccess = analyzeContextKeyAccess(params.segment.expression);\n if (keyAccess.violations.length > 0) {\n params.issues.push(\n ...keyAccess.violations.map((violation) =>\n computedContextKeyIssue({\n ...params,\n contextRoots,\n root: violation.root,\n expression: violation.source,\n }),\n ),\n );\n return undefined;\n }\n\n const selfReference = dynamicNameSelfReference(params);\n if (selfReference !== undefined) {\n params.issues.push(selfReference);\n return undefined;\n }\n\n const invalidReferenceIssue = validateContextKeyReferences({\n ...params,\n contextRoots,\n references: keyAccess.references,\n });\n if (invalidReferenceIssue !== undefined) {\n params.issues.push(invalidReferenceIssue);\n return undefined;\n }\n\n const invalidJobReferenceIssue =\n params.allowedJobReferences === undefined\n ? undefined\n : validateDirectJobReferences({\n source: params.source,\n expression: params.segment.expression,\n field: params.field,\n path: params.path,\n allowedJobReferences: params.allowedJobReferences,\n });\n if (invalidJobReferenceIssue !== undefined) {\n params.issues.push(invalidJobReferenceIssue);\n return undefined;\n }\n\n if (unknownRoots.length > 0) {\n params.issues.push(\n issue({\n code: 'unknown-interpolation-context',\n message: `${fieldLabel(params.field)} interpolation references unknown context ${formatList(\n unknownRoots,\n )}.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.segment.expression.source,\n contextRoots,\n unknownRoots,\n },\n }),\n );\n return undefined;\n }\n\n const fillSite = params.fillSite;\n if (fillSite !== undefined) {\n const serverRoots = knownRoots.filter((root) => getWorkflowContextHost(root) === 'server');\n const unavailableRoots = unavailableRootsAt(serverRoots, fillSite);\n if (unavailableRoots.length > 0) {\n params.issues.push(\n unavailableContextIssue({...params, contextRoots, unavailableRoots, fillSite}),\n );\n return undefined;\n }\n }\n\n if (\n params.typeOverlay === undefined &&\n (knownRoots.length === 0 || knownRoots.some((root) => hasSyntaxOnlyCheckMode(root)))\n ) {\n return params.segment;\n }\n\n try {\n return {\n ...params.segment,\n expression: createWorkflowExpression({\n source: params.segment.expression.source,\n check: {\n mode: 'typed',\n // `undefined` preserves the legacy syntax-only path above. `{}` means\n // callers intentionally requested typed checking with the standard roots.\n typeEnvironment: mergeTypeEnvironments(knownRoots, params.typeOverlay),\n },\n }),\n };\n } catch (error) {\n params.issues.push(\n issue({\n code: 'invalid-interpolation-expression',\n message: `${fieldLabel(params.field)} interpolation expression did not type-check.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.segment.expression.source,\n contextRoots,\n reason:\n error instanceof InvalidWorkflowExpressionError\n ? error.reason\n : 'Expression source did not type-check.',\n },\n }),\n );\n return undefined;\n }\n}\n\nfunction runnerContextInFieldIssue(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n contextRoots: readonly string[];\n rejectedHostRoots: readonly WorkflowContextName[];\n}): WorkflowModelValidationIssue {\n return issue({\n code: 'runner-context-in-field',\n message: `${fieldLabel(params.field)} interpolation cannot use runner context ${formatList(\n params.rejectedHostRoots,\n )}. Bind secrets to a run-step env value instead.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n contextRoots: params.contextRoots,\n rejectedRoots: params.rejectedHostRoots,\n },\n });\n}\n\nfunction computedContextKeyIssue(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n contextRoots: readonly string[];\n root: string;\n expression: string;\n}): WorkflowModelValidationIssue {\n return issue({\n code: 'computed-context-key',\n message: `${fieldLabel(params.field)} interpolation must reference ${params.root} with a literal dot key.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.expression,\n contextRoots: params.contextRoots,\n root: params.root,\n },\n });\n}\n\nfunction validateContextKeyReferences(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n contextRoots: readonly string[];\n segment: WorkflowTemplateExprSegment;\n references: ReturnType<typeof analyzeContextKeyAccess>['references'];\n}): WorkflowModelValidationIssue | undefined {\n for (const reference of params.references) {\n if (!secretKeySchema.safeParse(reference.key).success) {\n return computedContextKeyIssue({\n ...params,\n root: reference.root,\n expression: params.segment.expression.source,\n });\n }\n\n if (reference.root !== 'secrets' || reference.store === undefined) continue;\n if (secretStoreSchema.safeParse(reference.store).success) continue;\n\n return issue({\n code: 'unknown-secret-store',\n message: `${fieldLabel(params.field)} interpolation references unknown secret store \"${reference.store}\".`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.segment.expression.source,\n contextRoots: params.contextRoots,\n store: reference.store,\n },\n });\n }\n\n return undefined;\n}\n\nconst availabilitySiteLabels = {\n ingest: 'ingest',\n 'run-creation': 'run creation',\n 'execution-creation': 'execution creation',\n 'job-activation': 'job activation',\n 'step-dispatch': 'step dispatch',\n 'step-report': 'step reporting',\n 'execution-resolution': 'execution resolution',\n 'job-resolution': 'job resolution',\n} as const satisfies Record<AvailabilitySite, string>;\n\nfunction unavailableContextIssue(params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n segment: WorkflowTemplateExprSegment;\n contextRoots: readonly string[];\n unavailableRoots: readonly WorkflowContextName[];\n fillSite: AvailabilitySite;\n}): WorkflowModelValidationIssue {\n return issue({\n code: 'context-unavailable-at-fill-site',\n message: `${fieldLabel(params.field)} interpolation references ${contextNoun(\n params.unavailableRoots,\n )} ${formatList(params.unavailableRoots)} that ${availabilityVerb(\n params.unavailableRoots,\n )} not available at ${describeAvailabilitySite(params.fillSite)}. ${params.unavailableRoots\n .map(unavailableRootAvailabilityMessage)\n .join(' ')}`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: params.segment.expression.source,\n contextRoots: params.contextRoots,\n unavailableRoots: params.unavailableRoots,\n fillSite: params.fillSite,\n },\n });\n}\n\nfunction planViolationIssue(\n params: {\n field: WorkflowInterpolationField;\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n },\n violation: PlanViolation,\n): WorkflowModelValidationIssue {\n if (violation.reason === 'computed-context-key') {\n return issue({\n code: 'computed-context-key',\n message: `${fieldLabel(params.field)} interpolation must reference ${formatList(\n violation.contextRoots ?? [],\n )} with a literal dot key.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: violation.source,\n contextRoots: violation.contextRoots,\n },\n });\n }\n\n return issue({\n code: 'runner-context-not-bare',\n message: `${fieldLabel(params.field)} interpolation references runner context in a larger expression; ${violation.hint}.`,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n expression: violation.source,\n runnerRoots: violation.runnerRoots ?? [],\n },\n });\n}\n\nfunction contextNoun(roots: readonly WorkflowContextName[]): 'context' | 'contexts' {\n return roots.length === 1 ? 'context' : 'contexts';\n}\n\nfunction availabilityVerb(roots: readonly WorkflowContextName[]): 'is' | 'are' {\n return roots.length === 1 ? 'is' : 'are';\n}\n\nfunction unavailableRootAvailabilityMessage(root: WorkflowContextName): string {\n const availability = getWorkflowContextAvailability(root);\n if (availability === undefined) return `\"${root}\" is not available at any server site.`;\n return `\"${root}\" becomes available at ${describeAvailabilitySite(availability)}.`;\n}\n\nfunction describeAvailabilitySite(site: AvailabilitySite): string {\n return availabilitySiteLabels[site];\n}\n\nfunction hasSyntaxOnlyCheckMode(root: WorkflowContextName): boolean {\n return getWorkflowContextDefinition(root).checkMode === 'syntax';\n}\n\nfunction mergeTypeEnvironments(\n roots: readonly WorkflowContextName[],\n typeOverlay?: ExpressionTypeEnvironment,\n): ExpressionTypeEnvironment {\n const typeEnvironment: Record<string, ExpressionTypeEnvironment[string]> = {};\n\n for (const root of roots) {\n const overlayType = typeOverlay?.[root];\n if (overlayType !== undefined) {\n typeEnvironment[root] = overlayType;\n continue;\n }\n\n const contextTypeEnvironment = getWorkflowContextTypeEnvironment(root);\n if (contextTypeEnvironment === undefined) {\n if (typeOverlay !== undefined) typeEnvironment[root] = {kind: 'map'};\n continue;\n }\n\n Object.assign(typeEnvironment, contextTypeEnvironment);\n }\n\n return typeEnvironment;\n}\n\nfunction isExpressionSegment(\n segment: WorkflowTemplateSegment,\n): segment is WorkflowTemplateExprSegment {\n return segment.kind === 'expr';\n}\n\nfunction isWorkflowContextName(root: string): root is WorkflowContextName {\n return (workflowContextNames as readonly string[]).includes(root);\n}\n\nfunction uniqueStrings(values: readonly string[]): readonly string[] {\n return [...new Set(values)];\n}\n\nfunction formatList(values: readonly string[]): string {\n return values.map((value) => `\"${value}\"`).join(', ');\n}\n\nfunction fieldLabel(field: WorkflowInterpolationField): string {\n return `Workflow ${field}`;\n}\n\nfunction issue(params: {\n code: WorkflowModelValidationIssueCode;\n message: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n details?: Readonly<Record<string, unknown>>;\n}): WorkflowModelValidationIssue {\n if (params.details === undefined) {\n return {\n code: params.code,\n message: params.message,\n path: params.path,\n };\n }\n\n return {\n code: params.code,\n message: params.message,\n path: params.path,\n details: params.details,\n };\n}\n"],"names":["secretKeySchema","secretStoreSchema","analyzeContextKeyAccess","analyzeContextRootKeyAccess","createWorkflowExpression","getWorkflowContextAvailability","getWorkflowContextDefinition","getWorkflowContextHost","getWorkflowContextTypeEnvironment","getWorkflowInterpolationFieldSelfReference","InvalidWorkflowExpressionError","InvalidWorkflowTemplateError","parseWorkflowTemplate","planInterpolationField","unavailableRootsAt","workflowContextNames","workflowInterpolationFieldAcceptsHost","validateDirectJobReferences","parseInterpolationField","params","segments","parseTemplate","undefined","expressionSegments","filter","isExpressionSegment","length","checkedSegments","map","segment","kind","validatedSegment","validateExpressionSegment","plan","field","ok","issues","push","violations","violation","planViolationIssue","dynamicNameSelfReference","target","access","expression","root","reference","references","find","entry","key","computedReference","issue","code","message","fieldLabel","path","details","source","error","reason","contextRoots","uniqueStrings","knownRoots","isWorkflowContextName","unknownRoots","rejectedHostRoots","runnerContextInFieldIssue","keyAccess","computedContextKeyIssue","selfReference","invalidReferenceIssue","validateContextKeyReferences","invalidJobReferenceIssue","allowedJobReferences","formatList","fillSite","serverRoots","unavailableRoots","unavailableContextIssue","typeOverlay","some","hasSyntaxOnlyCheckMode","check","mode","typeEnvironment","mergeTypeEnvironments","rejectedRoots","safeParse","success","store","availabilitySiteLabels","ingest","contextNoun","availabilityVerb","describeAvailabilitySite","unavailableRootAvailabilityMessage","join","hint","runnerRoots","roots","availability","site","checkMode","overlayType","contextTypeEnvironment","Object","assign","includes","values","Set","value"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WorkflowModelValidationIssue, WorkflowModelValidationIssuePathSegment } from './invalid-workflow-model-error.js';
|
|
2
|
+
/** Defense-in-depth for typed callers that bypass workflowDocumentSchema. */
|
|
3
|
+
export declare function validateLiteralName(params: {
|
|
4
|
+
field: 'workflow.name' | 'job.name';
|
|
5
|
+
dynamicField: 'run_name' | 'execution_name';
|
|
6
|
+
source: string;
|
|
7
|
+
path: readonly WorkflowModelValidationIssuePathSegment[];
|
|
8
|
+
message: string;
|
|
9
|
+
issues: WorkflowModelValidationIssue[];
|
|
10
|
+
}): void;
|
|
11
|
+
export declare function unescapeLiteralName(source: string): string;
|
|
12
|
+
//# sourceMappingURL=validate-literal-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-literal-name.d.ts","sourceRoot":"","sources":["../../../src/core/workflow-model/validate-literal-name.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,4BAA4B,EAC5B,uCAAuC,EACxC,MAAM,mCAAmC,CAAC;AAG3C,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,KAAK,EAAE,eAAe,GAAG,UAAU,CAAC;IACpC,YAAY,EAAE,UAAU,GAAG,gBAAgB,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,uCAAuC,EAAE,CAAC;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,4BAA4B,EAAE,CAAC;CACxC,GAAG,IAAI,CAuBP;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { InvalidWorkflowTemplateError, parseWorkflowTemplate } from '@shipfox/expression';
|
|
2
|
+
import { issue } from './validation-issue.js';
|
|
3
|
+
/** Defense-in-depth for typed callers that bypass workflowDocumentSchema. */ export function validateLiteralName(params) {
|
|
4
|
+
try {
|
|
5
|
+
const segments = parseWorkflowTemplate(params.source);
|
|
6
|
+
if (!segments.some((segment)=>segment.kind === 'expr')) return;
|
|
7
|
+
} catch (error) {
|
|
8
|
+
params.issues.push(literalNameIssue({
|
|
9
|
+
...params,
|
|
10
|
+
reason: error instanceof InvalidWorkflowTemplateError ? error.reason : 'Template source did not parse.'
|
|
11
|
+
}));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
params.issues.push(literalNameIssue({
|
|
15
|
+
...params,
|
|
16
|
+
reason: `Static names cannot contain interpolation expressions. Use ${params.dynamicField} for runtime interpolation.`
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
export function unescapeLiteralName(source) {
|
|
20
|
+
return source.replaceAll('$${{', '${{');
|
|
21
|
+
}
|
|
22
|
+
function literalNameIssue(params) {
|
|
23
|
+
return issue({
|
|
24
|
+
code: 'invalid-interpolation-template',
|
|
25
|
+
message: params.message,
|
|
26
|
+
path: params.path,
|
|
27
|
+
details: {
|
|
28
|
+
field: params.field,
|
|
29
|
+
source: params.source,
|
|
30
|
+
dynamicField: params.dynamicField,
|
|
31
|
+
reason: params.reason
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=validate-literal-name.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/core/workflow-model/validate-literal-name.ts"],"sourcesContent":["import {InvalidWorkflowTemplateError, parseWorkflowTemplate} from '@shipfox/expression';\nimport type {\n WorkflowModelValidationIssue,\n WorkflowModelValidationIssuePathSegment,\n} from './invalid-workflow-model-error.js';\nimport {issue} from './validation-issue.js';\n\n/** Defense-in-depth for typed callers that bypass workflowDocumentSchema. */\nexport function validateLiteralName(params: {\n field: 'workflow.name' | 'job.name';\n dynamicField: 'run_name' | 'execution_name';\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n message: string;\n issues: WorkflowModelValidationIssue[];\n}): void {\n try {\n const segments = parseWorkflowTemplate(params.source);\n if (!segments.some((segment) => segment.kind === 'expr')) return;\n } catch (error) {\n params.issues.push(\n literalNameIssue({\n ...params,\n reason:\n error instanceof InvalidWorkflowTemplateError\n ? error.reason\n : 'Template source did not parse.',\n }),\n );\n return;\n }\n\n params.issues.push(\n literalNameIssue({\n ...params,\n reason: `Static names cannot contain interpolation expressions. Use ${params.dynamicField} for runtime interpolation.`,\n }),\n );\n}\n\nexport function unescapeLiteralName(source: string): string {\n return source.replaceAll('$${{', '${{');\n}\n\nfunction literalNameIssue(params: {\n field: 'workflow.name' | 'job.name';\n dynamicField: 'run_name' | 'execution_name';\n source: string;\n path: readonly WorkflowModelValidationIssuePathSegment[];\n message: string;\n reason: string;\n}): WorkflowModelValidationIssue {\n return issue({\n code: 'invalid-interpolation-template',\n message: params.message,\n path: params.path,\n details: {\n field: params.field,\n source: params.source,\n dynamicField: params.dynamicField,\n reason: params.reason,\n },\n });\n}\n"],"names":["InvalidWorkflowTemplateError","parseWorkflowTemplate","issue","validateLiteralName","params","segments","source","some","segment","kind","error","issues","push","literalNameIssue","reason","dynamicField","unescapeLiteralName","replaceAll","code","message","path","details","field"],"mappings":"AAAA,SAAQA,4BAA4B,EAAEC,qBAAqB,QAAO,sBAAsB;AAKxF,SAAQC,KAAK,QAAO,wBAAwB;AAE5C,2EAA2E,GAC3E,OAAO,SAASC,oBAAoBC,MAOnC;IACC,IAAI;QACF,MAAMC,WAAWJ,sBAAsBG,OAAOE,MAAM;QACpD,IAAI,CAACD,SAASE,IAAI,CAAC,CAACC,UAAYA,QAAQC,IAAI,KAAK,SAAS;IAC5D,EAAE,OAAOC,OAAO;QACdN,OAAOO,MAAM,CAACC,IAAI,CAChBC,iBAAiB;YACf,GAAGT,MAAM;YACTU,QACEJ,iBAAiBV,+BACbU,MAAMI,MAAM,GACZ;QACR;QAEF;IACF;IAEAV,OAAOO,MAAM,CAACC,IAAI,CAChBC,iBAAiB;QACf,GAAGT,MAAM;QACTU,QAAQ,CAAC,2DAA2D,EAAEV,OAAOW,YAAY,CAAC,2BAA2B,CAAC;IACxH;AAEJ;AAEA,OAAO,SAASC,oBAAoBV,MAAc;IAChD,OAAOA,OAAOW,UAAU,CAAC,QAAQ;AACnC;AAEA,SAASJ,iBAAiBT,MAOzB;IACC,OAAOF,MAAM;QACXgB,MAAM;QACNC,SAASf,OAAOe,OAAO;QACvBC,MAAMhB,OAAOgB,IAAI;QACjBC,SAAS;YACPC,OAAOlB,OAAOkB,KAAK;YACnBhB,QAAQF,OAAOE,MAAM;YACrBS,cAAcX,OAAOW,YAAY;YACjCD,QAAQV,OAAOU,MAAM;QACvB;IACF;AACF"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ExpressionTypeEnvironment, type WorkflowExpression, type WorkflowPredicateField } from '@shipfox/expression';
|
|
2
2
|
import type { WorkflowModelValidationIssue, WorkflowModelValidationIssueCode, WorkflowModelValidationIssuePathSegment } from './invalid-workflow-model-error.js';
|
|
3
3
|
export declare function validatePredicateExpression(params: {
|
|
4
4
|
field: WorkflowPredicateField;
|
|
5
5
|
source: string;
|
|
6
|
-
site: AvailabilitySite;
|
|
7
6
|
path: readonly WorkflowModelValidationIssuePathSegment[];
|
|
8
7
|
invalidCode: WorkflowModelValidationIssueCode;
|
|
9
8
|
invalidMessage: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-predicate-expression.d.ts","sourceRoot":"","sources":["../../../src/core/workflow-model/validate-predicate-expression.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"validate-predicate-expression.d.ts","sourceRoot":"","sources":["../../../src/core/workflow-model/validate-predicate-expression.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,yBAAyB,EAW9B,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAE5B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EACV,4BAA4B,EAC5B,gCAAgC,EAChC,uCAAuC,EACxC,MAAM,mCAAmC,CAAC;AAK3C,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,KAAK,EAAE,sBAAsB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,uCAAuC,EAAE,CAAC;IACzD,WAAW,EAAE,gCAAgC,CAAC;IAC9C,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,4BAA4B,EAAE,CAAC;IACvC,oBAAoB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3C,WAAW,CAAC,EAAE,yBAAyB,GAAG,SAAS,CAAC;CACrD,GAAG,kBAAkB,GAAG,SAAS,CA0GjC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createWorkflowExpression, extractExactContextRoots, getWorkflowContextDefinition, getWorkflowPredicateContextRoots, getWorkflowPredicateFieldMinimumFillTarget, getWorkflowPredicateFieldTypeEnvironment, InvalidWorkflowExpressionError, predicateSourceIsBooleanShaped, resolveContextRootHost, validateServerEvaluable, workflowContextNames } from '@shipfox/expression';
|
|
2
2
|
import { validateDirectJobReferences } from './validate-job-references.js';
|
|
3
3
|
import { issue } from './validation-issue.js';
|
|
4
4
|
import { workflowFieldLabel } from './workflow-field-label.js';
|
|
5
5
|
export function validatePredicateExpression(params) {
|
|
6
|
+
const site = getWorkflowPredicateFieldMinimumFillTarget(params.field);
|
|
6
7
|
const syntaxExpression = createSyntaxExpression(params);
|
|
7
8
|
if (syntaxExpression === undefined) return undefined;
|
|
8
9
|
const contextRoots = extractExactContextRoots(syntaxExpression.source);
|
|
@@ -19,42 +20,23 @@ export function validatePredicateExpression(params) {
|
|
|
19
20
|
if (!serverEvaluability.ok) {
|
|
20
21
|
params.issues.push(...serverEvaluability.violations.map((violation)=>runnerContextInServerPredicateIssue({
|
|
21
22
|
...params,
|
|
23
|
+
site,
|
|
22
24
|
contextRoots,
|
|
23
25
|
runnerRoots: violation.runnerRoots
|
|
24
26
|
})));
|
|
25
27
|
return undefined;
|
|
26
28
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
params.issues.push(varsContextInServerPredicateIssue({
|
|
30
|
-
...params,
|
|
31
|
-
contextRoots
|
|
32
|
-
}));
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
const unavailableRoots = knownRoots.filter((root)=>!isRootAvailableAt(root, params.site));
|
|
29
|
+
const predicateContextRoots = getWorkflowPredicateContextRoots(params.field);
|
|
30
|
+
const unavailableRoots = knownRoots.filter((root)=>!predicateContextRoots.includes(root));
|
|
36
31
|
if (unavailableRoots.length > 0) {
|
|
37
32
|
params.issues.push(unavailablePredicateContextIssue({
|
|
38
33
|
...params,
|
|
34
|
+
site,
|
|
39
35
|
contextRoots,
|
|
40
36
|
unavailableRoots
|
|
41
37
|
}));
|
|
42
38
|
return undefined;
|
|
43
39
|
}
|
|
44
|
-
const route = routeExpression(syntaxExpression);
|
|
45
|
-
if (route.fillTarget !== 'runner-fill' && !isSiteAtOrAfter(params.site, route.fillTarget)) {
|
|
46
|
-
const unavailableRoots = unavailableRouteReferences(syntaxExpression);
|
|
47
|
-
params.issues.push(unavailableRoots.length > 0 ? unavailablePredicateContextIssue({
|
|
48
|
-
...params,
|
|
49
|
-
contextRoots,
|
|
50
|
-
unavailableRoots
|
|
51
|
-
}) : routeUnavailablePredicateContextIssue({
|
|
52
|
-
...params,
|
|
53
|
-
contextRoots,
|
|
54
|
-
fillTarget: route.fillTarget
|
|
55
|
-
}));
|
|
56
|
-
return undefined;
|
|
57
|
-
}
|
|
58
40
|
const invalidJobReferenceIssue = params.allowedJobReferences === undefined ? undefined : validateDirectJobReferences({
|
|
59
41
|
source: params.source,
|
|
60
42
|
expression: syntaxExpression,
|
|
@@ -66,7 +48,7 @@ export function validatePredicateExpression(params) {
|
|
|
66
48
|
params.issues.push(invalidJobReferenceIssue);
|
|
67
49
|
return undefined;
|
|
68
50
|
}
|
|
69
|
-
if (params.typeOverlay === undefined && knownRoots.
|
|
51
|
+
if (params.typeOverlay === undefined && knownRoots.length > 0 && knownRoots.every((root)=>hasSyntaxOnlyCheckMode(root))) {
|
|
70
52
|
if (isWorkflowFilterPredicateField(params.field) && !predicateSourceIsBooleanShaped(syntaxExpression.source)) {
|
|
71
53
|
params.issues.push(invalidPredicateIssue({
|
|
72
54
|
...params,
|
|
@@ -84,7 +66,7 @@ export function validatePredicateExpression(params) {
|
|
|
84
66
|
mode: 'typed',
|
|
85
67
|
// `undefined` preserves the legacy syntax-only path above. `{}` means
|
|
86
68
|
// callers intentionally requested typed checking with the standard roots.
|
|
87
|
-
typeEnvironment: mergeTypeEnvironments(knownRoots, params.typeOverlay),
|
|
69
|
+
typeEnvironment: mergeTypeEnvironments(params.field, knownRoots, params.typeOverlay),
|
|
88
70
|
expectedResultType: 'bool'
|
|
89
71
|
}
|
|
90
72
|
});
|
|
@@ -151,26 +133,10 @@ function runnerContextInServerPredicateIssue(params) {
|
|
|
151
133
|
}
|
|
152
134
|
});
|
|
153
135
|
}
|
|
154
|
-
function varsContextInServerPredicateIssue(params) {
|
|
155
|
-
return issue({
|
|
156
|
-
code: 'vars-context-in-server-predicate',
|
|
157
|
-
message: `${fieldLabel(params.field)} cannot reference vars because predicate evaluation does not include workflow variables.`,
|
|
158
|
-
path: params.path,
|
|
159
|
-
details: {
|
|
160
|
-
field: params.field,
|
|
161
|
-
source: params.source,
|
|
162
|
-
contextRoots: params.contextRoots,
|
|
163
|
-
rejectedRoots: [
|
|
164
|
-
'vars'
|
|
165
|
-
],
|
|
166
|
-
site: params.site
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
136
|
function unavailablePredicateContextIssue(params) {
|
|
171
137
|
return issue({
|
|
172
138
|
code: 'context-unavailable-at-predicate-site',
|
|
173
|
-
message: `${fieldLabel(params.field)} references ${contextNoun(params.unavailableRoots)} ${formatList(params.unavailableRoots)} that ${availabilityVerb(params.unavailableRoots)} not
|
|
139
|
+
message: `${fieldLabel(params.field)} references ${contextNoun(params.unavailableRoots)} ${formatList(params.unavailableRoots)} that ${availabilityVerb(params.unavailableRoots)} not supplied when ${fieldLabel(params.field)} is evaluated at ${describeAvailabilitySite(params.site)}.`,
|
|
174
140
|
path: params.path,
|
|
175
141
|
details: {
|
|
176
142
|
field: params.field,
|
|
@@ -181,70 +147,48 @@ function unavailablePredicateContextIssue(params) {
|
|
|
181
147
|
}
|
|
182
148
|
});
|
|
183
149
|
}
|
|
184
|
-
function routeUnavailablePredicateContextIssue(params) {
|
|
185
|
-
return issue({
|
|
186
|
-
code: 'context-unavailable-at-predicate-site',
|
|
187
|
-
message: `${fieldLabel(params.field)} requires context filled at ${describeAvailabilitySite(params.fillTarget)}, but it is evaluated at ${describeAvailabilitySite(params.site)}.`,
|
|
188
|
-
path: params.path,
|
|
189
|
-
details: {
|
|
190
|
-
field: params.field,
|
|
191
|
-
source: params.source,
|
|
192
|
-
contextRoots: params.contextRoots,
|
|
193
|
-
fillTarget: params.fillTarget,
|
|
194
|
-
site: params.site
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
function isRootAvailableAt(root, site) {
|
|
199
|
-
const availability = resolveContextRootAvailability(root);
|
|
200
|
-
if (availability === undefined) return false;
|
|
201
|
-
return availabilitySites.indexOf(availability) <= availabilitySites.indexOf(site);
|
|
202
|
-
}
|
|
203
|
-
function unavailableRootAvailabilityMessage(root) {
|
|
204
|
-
if (root === 'execution.failed') {
|
|
205
|
-
return '"execution.failed" becomes available at step dispatch.';
|
|
206
|
-
}
|
|
207
|
-
const availability = resolveContextRootAvailability(root);
|
|
208
|
-
if (availability === undefined) return `"${root}" is not available at any server site.`;
|
|
209
|
-
return `"${root}" becomes available at ${describeAvailabilitySite(availability)}.`;
|
|
210
|
-
}
|
|
211
|
-
function unavailableRouteReferences(expression) {
|
|
212
|
-
const access = analyzeContextRootKeyAccess(expression, [
|
|
213
|
-
'execution'
|
|
214
|
-
]);
|
|
215
|
-
return access.references.some((reference)=>reference.key === 'failed') ? [
|
|
216
|
-
'execution.failed'
|
|
217
|
-
] : [];
|
|
218
|
-
}
|
|
219
150
|
function hasSyntaxOnlyCheckMode(root) {
|
|
220
151
|
if (!isWorkflowContextName(root)) return resolveContextRootHost(root) === 'server';
|
|
221
152
|
return isWorkflowContextName(root) && getWorkflowContextDefinition(root).checkMode === 'syntax';
|
|
222
153
|
}
|
|
223
|
-
function mergeTypeEnvironments(roots, typeOverlay) {
|
|
154
|
+
function mergeTypeEnvironments(field, roots, typeOverlay) {
|
|
224
155
|
const typeEnvironment = {};
|
|
225
156
|
for (const root of roots){
|
|
226
157
|
const overlayType = typeOverlay?.[root];
|
|
227
|
-
if (overlayType !== undefined) {
|
|
228
|
-
typeEnvironment[root] = overlayType;
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
158
|
if (!isWorkflowContextName(root)) {
|
|
232
|
-
if (
|
|
159
|
+
if (overlayType !== undefined) typeEnvironment[root] = overlayType;
|
|
160
|
+
else typeEnvironment[root] = {
|
|
233
161
|
kind: 'map'
|
|
234
162
|
};
|
|
235
163
|
continue;
|
|
236
164
|
}
|
|
237
|
-
const contextTypeEnvironment =
|
|
165
|
+
const contextTypeEnvironment = getWorkflowPredicateFieldTypeEnvironment(field, root);
|
|
238
166
|
if (contextTypeEnvironment === undefined) {
|
|
239
|
-
if (
|
|
167
|
+
if (overlayType !== undefined) typeEnvironment[root] = overlayType;
|
|
168
|
+
else typeEnvironment[root] = {
|
|
240
169
|
kind: 'map'
|
|
241
170
|
};
|
|
242
171
|
continue;
|
|
243
172
|
}
|
|
244
|
-
|
|
173
|
+
const contextType = contextTypeEnvironment[root];
|
|
174
|
+
if (contextType === undefined) continue;
|
|
175
|
+
typeEnvironment[root] = overlayType === undefined ? contextType : overlayKnownFields(contextType, overlayType);
|
|
245
176
|
}
|
|
246
177
|
return typeEnvironment;
|
|
247
178
|
}
|
|
179
|
+
function overlayKnownFields(base, overlay) {
|
|
180
|
+
if (typeof base === 'string' || typeof overlay === 'string') return overlay;
|
|
181
|
+
if (base.kind !== 'object' || overlay.kind !== 'object') return overlay;
|
|
182
|
+
// Preserve output specialization without reintroducing properties absent from this field's
|
|
183
|
+
// runtime shape.
|
|
184
|
+
return {
|
|
185
|
+
kind: 'object',
|
|
186
|
+
fields: Object.fromEntries(Object.entries(base.fields).map(([key, fieldType])=>[
|
|
187
|
+
key,
|
|
188
|
+
overlay.fields[key] ?? fieldType
|
|
189
|
+
]))
|
|
190
|
+
};
|
|
191
|
+
}
|
|
248
192
|
function isWorkflowContextName(root) {
|
|
249
193
|
return workflowContextNames.includes(root);
|
|
250
194
|
}
|
|
@@ -263,9 +207,6 @@ function availabilityVerb(roots) {
|
|
|
263
207
|
function describeAvailabilitySite(site) {
|
|
264
208
|
return availabilitySiteLabels[site];
|
|
265
209
|
}
|
|
266
|
-
function isSiteAtOrAfter(site, fillTarget) {
|
|
267
|
-
return availabilitySites.indexOf(site) >= availabilitySites.indexOf(fillTarget);
|
|
268
|
-
}
|
|
269
210
|
function formatList(values) {
|
|
270
211
|
return values.map((value)=>`"${value}"`).join(', ');
|
|
271
212
|
}
|