Validate secrets passed in to reusable workflow job
This commit is contained in:
@@ -21,6 +21,8 @@ export function convertJob(context: TemplateContext, jobKey: StringToken, token:
|
||||
let steps: Step[] = [];
|
||||
let workflowJobRef: StringToken | undefined;
|
||||
let workflowJobInputs: MappingToken | undefined;
|
||||
let inheritSecrets = false;
|
||||
let workflowJobSecrets: MappingToken | undefined;
|
||||
|
||||
for (const item of token) {
|
||||
const propertyName = item.key.assertString("job property name");
|
||||
@@ -95,6 +97,12 @@ export function convertJob(context: TemplateContext, jobKey: StringToken, token:
|
||||
case "with":
|
||||
workflowJobInputs = item.value.assertMapping("uses-with value");
|
||||
break;
|
||||
case "secrets":
|
||||
if (isString(item.value) && item.value.value === "inherit") {
|
||||
inheritSecrets = true;
|
||||
} else {
|
||||
workflowJobSecrets = item.value.assertMapping("uses-secrets value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +116,9 @@ export function convertJob(context: TemplateContext, jobKey: StringToken, token:
|
||||
ref: workflowJobRef,
|
||||
"input-definitions": undefined,
|
||||
"input-values": workflowJobInputs,
|
||||
"secret-definitions": undefined,
|
||||
"secret-values": workflowJobSecrets,
|
||||
"inherit-secrets": inheritSecrets || undefined,
|
||||
outputs: undefined,
|
||||
concurrency,
|
||||
strategy
|
||||
|
||||
@@ -39,7 +39,7 @@ export function convertWorkflowJobInputs(context: TemplateContext, job: Reusable
|
||||
}
|
||||
}
|
||||
|
||||
function createTokenMap(mapping: MappingToken | undefined, description: string): TokenMap | undefined {
|
||||
export function createTokenMap(mapping: MappingToken | undefined, description: string): TokenMap | undefined {
|
||||
if (!mapping) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import {TemplateContext} from "../../../templates/template-context";
|
||||
import {NullToken} from "../../../templates/tokens";
|
||||
import {ReusableWorkflowJob} from "../../workflow-template";
|
||||
import {createTokenMap} from "./inputs";
|
||||
|
||||
export function convertWorkflowJobSecrets(context: TemplateContext, job: ReusableWorkflowJob) {
|
||||
// No validation if job passes all secrets
|
||||
if (!!job["inherit-secrets"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const secretDefinitions = createTokenMap(
|
||||
job["secret-definitions"]?.assertMapping("workflow job secret definitions"),
|
||||
"secrets"
|
||||
);
|
||||
|
||||
const secretValues = createTokenMap(job["secret-values"]?.assertMapping("workflow job secret values"), "secrets");
|
||||
|
||||
if (secretDefinitions !== undefined) {
|
||||
for (const [_, [name, value]] of secretDefinitions) {
|
||||
if (value instanceof NullToken) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const secretSpec = createTokenMap(value.assertMapping(`secret ${name}`), `secret ${name} key`)!;
|
||||
|
||||
const required = secretSpec.get("required")?.[1].assertBoolean(`secret ${name} required`).value;
|
||||
if (required) {
|
||||
if (secretValues == undefined || !secretValues.has(name.toLowerCase())) {
|
||||
context.error(job.ref, `Secret ${name} is required, but not provided while calling.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (secretValues !== undefined) {
|
||||
for (const [_, [name, value]] of secretValues) {
|
||||
if (!secretDefinitions?.has(name.toLowerCase())) {
|
||||
context.error(value, `Invalid secret, ${name} is not defined in the referenced workflow.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import {TokenType} from "../../templates/tokens/types";
|
||||
import {ReusableWorkflowJob} from "../workflow-template";
|
||||
import {handleTemplateTokenErrors} from "./handle-errors";
|
||||
import {convertWorkflowJobInputs} from "./job/inputs";
|
||||
import {convertWorkflowJobSecrets} from "./job/secrets";
|
||||
import {convertJobs} from "./jobs";
|
||||
|
||||
export function convertReferencedWorkflow(
|
||||
@@ -41,6 +42,7 @@ function convertReferencedWorkflowOn(context: TemplateContext, on: TemplateToken
|
||||
const event = on.assertString("Reference workflow on value").value;
|
||||
if (event === "workflow_call") {
|
||||
handleTemplateTokenErrors(tokenForErrors, context, undefined, () => convertWorkflowJobInputs(context, job));
|
||||
handleTemplateTokenErrors(tokenForErrors, context, undefined, () => convertWorkflowJobSecrets(context, job));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -52,6 +54,7 @@ function convertReferencedWorkflowOn(context: TemplateContext, on: TemplateToken
|
||||
const event = eventToken.assertString(`Reference workflow on value ${eventToken}`).value;
|
||||
if (event === "workflow_call") {
|
||||
handleTemplateTokenErrors(tokenForErrors, context, undefined, () => convertWorkflowJobInputs(context, job));
|
||||
handleTemplateTokenErrors(tokenForErrors, context, undefined, () => convertWorkflowJobSecrets(context, job));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -69,6 +72,7 @@ function convertReferencedWorkflowOn(context: TemplateContext, on: TemplateToken
|
||||
|
||||
if (pair.value.templateTokenType === TokenType.Null) {
|
||||
handleTemplateTokenErrors(tokenForErrors, context, undefined, () => convertWorkflowJobInputs(context, job));
|
||||
handleTemplateTokenErrors(tokenForErrors, context, undefined, () => convertWorkflowJobSecrets(context, job));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,10 +87,15 @@ function convertReferencedWorkflowOn(context: TemplateContext, on: TemplateToken
|
||||
case "outputs":
|
||||
job.outputs = definition.value.assertMapping(`on-workflow_call-${definition.key}`);
|
||||
break;
|
||||
|
||||
case "secrets":
|
||||
job["secret-definitions"] = definition.value.assertMapping(`on-workflow_call-${definition.key}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleTemplateTokenErrors(tokenForErrors, context, undefined, () => convertWorkflowJobInputs(context, job));
|
||||
handleTemplateTokenErrors(tokenForErrors, context, undefined, () => convertWorkflowJobSecrets(context, job));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -60,6 +60,9 @@ export type ReusableWorkflowJob = BaseJob & {
|
||||
ref: StringToken;
|
||||
"input-definitions"?: MappingToken;
|
||||
"input-values"?: MappingToken;
|
||||
"secret-definitions"?: MappingToken;
|
||||
"secret-values"?: MappingToken;
|
||||
"inherit-secrets"?: boolean;
|
||||
jobs?: WorkflowJob[];
|
||||
};
|
||||
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
include-source: false # Drop file/line/col from output
|
||||
skip:
|
||||
- Go
|
||||
- TypeScript
|
||||
---
|
||||
on: push
|
||||
jobs:
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
include-source: false # Drop file/line/col from output
|
||||
skip:
|
||||
- Go
|
||||
- TypeScript
|
||||
---
|
||||
on: push
|
||||
jobs:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
include-source: false # Drop file/line/col from output
|
||||
skip:
|
||||
- Go
|
||||
- TypeScript
|
||||
---
|
||||
on: push
|
||||
jobs:
|
||||
|
||||
Reference in New Issue
Block a user