@secureci/cli 1.0.0 → 1.1.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/README.md +36 -15
- package/dist/advisories.js +33 -6
- package/dist/cli.js +103 -4
- package/dist/config.js +12 -1
- package/dist/inventory.js +52 -0
- package/dist/org-scan-script.js +6 -0
- package/dist/org-scan.js +88 -0
- package/dist/parser/pipeline-contract-validator.js +56 -25
- package/dist/runner/action-fetcher.js +6 -1
- package/dist/runner/actions.js +7 -7
- package/dist/runner/checkout.js +124 -8
- package/dist/runner/container-policy.js +32 -0
- package/dist/runner/docker-action.js +1 -1
- package/dist/runner/executor.js +28 -6
- package/dist/runner/expression.js +125 -3
- package/dist/runner/job-container.js +57 -11
- package/dist/runner/job-runtime.js +4 -3
- package/dist/runner/node-action.js +1 -1
- package/dist/runner/runner-env.js +20 -0
- package/dist/runner/steps.js +2 -2
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ exports.substituteExpressions = substituteExpressions;
|
|
|
6
6
|
exports.substituteRecord = substituteRecord;
|
|
7
7
|
exports.withImplicitSuccess = withImplicitSuccess;
|
|
8
8
|
exports.evaluateCondition = evaluateCondition;
|
|
9
|
+
exports.staticCondition = staticCondition;
|
|
9
10
|
exports.ifEvaluationError = ifEvaluationError;
|
|
10
11
|
exports.validateExpression = validateExpression;
|
|
11
12
|
exports.expressionDataFlow = expressionDataFlow;
|
|
@@ -388,16 +389,46 @@ function callFunction(name, rawArgs, ctx) {
|
|
|
388
389
|
}
|
|
389
390
|
/** The `*` filter in `x.*` / `x[*]`, as opposed to a `'*'` key. */
|
|
390
391
|
const STAR = Symbol('*');
|
|
392
|
+
/**
|
|
393
|
+
* A value static evaluation (`staticCondition`) doesn't know, with its
|
|
394
|
+
* truthiness when that is known anyway (`unknown || true` is truthy).
|
|
395
|
+
*/
|
|
396
|
+
class Unknown {
|
|
397
|
+
constructor(truthy) {
|
|
398
|
+
this.truthy = truthy;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/** Contexts an expression may name; static evaluation knows only some. */
|
|
402
|
+
const NAMED_CONTEXTS = new Set([
|
|
403
|
+
'env',
|
|
404
|
+
'inputs',
|
|
405
|
+
'secrets',
|
|
406
|
+
'steps',
|
|
407
|
+
'github',
|
|
408
|
+
'matrix',
|
|
409
|
+
'needs',
|
|
410
|
+
'job',
|
|
411
|
+
'runner',
|
|
412
|
+
'vars',
|
|
413
|
+
'strategy'
|
|
414
|
+
]);
|
|
415
|
+
/** Truthiness of a (possibly Unknown) value; undefined when unknown. */
|
|
416
|
+
function truthOf(value) {
|
|
417
|
+
return value instanceof Unknown ? value.truthy : toBoolean(unwrap(value));
|
|
418
|
+
}
|
|
391
419
|
class Parser {
|
|
392
420
|
/**
|
|
393
421
|
* With a scope, only check names and syntax; with `flow`, compute data
|
|
394
422
|
* flow (Flow values) instead. Either way nothing is evaluated.
|
|
395
423
|
*/
|
|
396
|
-
constructor(tokens, ctx, scope, flow = false
|
|
424
|
+
constructor(tokens, ctx, scope, flow = false,
|
|
425
|
+
/** Static evaluation: only these contexts are known (see Unknown). */
|
|
426
|
+
known) {
|
|
397
427
|
this.tokens = tokens;
|
|
398
428
|
this.ctx = ctx;
|
|
399
429
|
this.scope = scope;
|
|
400
430
|
this.flow = flow;
|
|
431
|
+
this.known = known;
|
|
401
432
|
this.pos = 0;
|
|
402
433
|
}
|
|
403
434
|
peek() {
|
|
@@ -429,6 +460,16 @@ class Parser {
|
|
|
429
460
|
while (this.isOp('||')) {
|
|
430
461
|
this.next();
|
|
431
462
|
const right = this.parseAnd();
|
|
463
|
+
if (this.known) {
|
|
464
|
+
const l = truthOf(left);
|
|
465
|
+
left =
|
|
466
|
+
l === true
|
|
467
|
+
? left
|
|
468
|
+
: l === false
|
|
469
|
+
? right
|
|
470
|
+
: new Unknown(truthOf(right) === true ? true : undefined);
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
432
473
|
left = this.flow
|
|
433
474
|
? Flow.union(left, right)
|
|
434
475
|
: toBoolean(unwrap(left))
|
|
@@ -442,6 +483,16 @@ class Parser {
|
|
|
442
483
|
while (this.isOp('&&')) {
|
|
443
484
|
this.next();
|
|
444
485
|
const right = this.parseEquality();
|
|
486
|
+
if (this.known) {
|
|
487
|
+
const l = truthOf(left);
|
|
488
|
+
left =
|
|
489
|
+
l === false
|
|
490
|
+
? left
|
|
491
|
+
: l === true
|
|
492
|
+
? right
|
|
493
|
+
: new Unknown(truthOf(right) === false ? false : undefined);
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
445
496
|
left = this.flow
|
|
446
497
|
? Flow.union(left, right)
|
|
447
498
|
: toBoolean(unwrap(left))
|
|
@@ -455,6 +506,10 @@ class Parser {
|
|
|
455
506
|
while (this.isOp('==', '!=')) {
|
|
456
507
|
const op = this.next().value;
|
|
457
508
|
const right = this.parseComparison();
|
|
509
|
+
if (left instanceof Unknown || right instanceof Unknown) {
|
|
510
|
+
left = new Unknown();
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
458
513
|
const eq = looseEquals(unwrap(left), unwrap(right));
|
|
459
514
|
left = op === '==' ? eq : !eq;
|
|
460
515
|
}
|
|
@@ -465,6 +520,10 @@ class Parser {
|
|
|
465
520
|
while (this.isOp('<', '<=', '>', '>=')) {
|
|
466
521
|
const op = this.next().value;
|
|
467
522
|
const right = this.parseUnary();
|
|
523
|
+
if (left instanceof Unknown || right instanceof Unknown) {
|
|
524
|
+
left = new Unknown();
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
468
527
|
const c = compare(unwrap(left), unwrap(right));
|
|
469
528
|
left =
|
|
470
529
|
!Number.isNaN(c) &&
|
|
@@ -481,7 +540,11 @@ class Parser {
|
|
|
481
540
|
parseUnary() {
|
|
482
541
|
if (this.isOp('!')) {
|
|
483
542
|
this.next();
|
|
484
|
-
|
|
543
|
+
const operand = this.parseUnary();
|
|
544
|
+
if (operand instanceof Unknown) {
|
|
545
|
+
return new Unknown(operand.truthy === undefined ? undefined : !operand.truthy);
|
|
546
|
+
}
|
|
547
|
+
return !toBoolean(unwrap(operand));
|
|
485
548
|
}
|
|
486
549
|
return this.parsePostfix(this.parsePrimary());
|
|
487
550
|
}
|
|
@@ -509,7 +572,12 @@ class Parser {
|
|
|
509
572
|
}
|
|
510
573
|
else {
|
|
511
574
|
const key = unwrap(this.parseOr());
|
|
512
|
-
value =
|
|
575
|
+
value =
|
|
576
|
+
key instanceof Unknown
|
|
577
|
+
? new Unknown()
|
|
578
|
+
: this.access(value, typeof key === 'number' || key instanceof Flow
|
|
579
|
+
? key
|
|
580
|
+
: toText(key));
|
|
513
581
|
}
|
|
514
582
|
this.expect('rbracket');
|
|
515
583
|
}
|
|
@@ -526,6 +594,12 @@ class Parser {
|
|
|
526
594
|
// `.*` and a computed key (`x[matrix.field]`) may be any key.
|
|
527
595
|
return value.member(key === STAR || key instanceof Flow ? '*' : String(key).toLowerCase());
|
|
528
596
|
}
|
|
597
|
+
if (this.known) {
|
|
598
|
+
if (value instanceof Unknown)
|
|
599
|
+
return new Unknown();
|
|
600
|
+
const result = key === STAR ? star(value) : member(value, key);
|
|
601
|
+
return result === undefined ? new Unknown() : result;
|
|
602
|
+
}
|
|
529
603
|
if (key === STAR)
|
|
530
604
|
return star(value);
|
|
531
605
|
return member(value, key);
|
|
@@ -566,6 +640,8 @@ class Parser {
|
|
|
566
640
|
}
|
|
567
641
|
if (this.flow)
|
|
568
642
|
return flowCall(tok.value, args);
|
|
643
|
+
if (this.known)
|
|
644
|
+
return this.staticCall(tok.value, args);
|
|
569
645
|
return callFunction(tok.value, args, this.ctx);
|
|
570
646
|
}
|
|
571
647
|
if (this.scope) {
|
|
@@ -576,12 +652,34 @@ class Parser {
|
|
|
576
652
|
}
|
|
577
653
|
if (this.flow)
|
|
578
654
|
return new Flow([[lower]]);
|
|
655
|
+
if (this.known) {
|
|
656
|
+
if (!NAMED_CONTEXTS.has(lower)) {
|
|
657
|
+
throw new Error(`Unrecognized named-value: '${tok.value}'`);
|
|
658
|
+
}
|
|
659
|
+
return lower in this.known ? this.known[lower] : new Unknown();
|
|
660
|
+
}
|
|
579
661
|
return rootContext(lower, this.ctx);
|
|
580
662
|
}
|
|
581
663
|
default:
|
|
582
664
|
throw new Error(`Unexpected token: ${tok.type}`);
|
|
583
665
|
}
|
|
584
666
|
}
|
|
667
|
+
/**
|
|
668
|
+
* A function call in static evaluation: `success()` and `always()` hold
|
|
669
|
+
* for a step that runs at all; other status functions, `hashFiles` and
|
|
670
|
+
* calls with an unknown argument are unknown.
|
|
671
|
+
*/
|
|
672
|
+
staticCall(name, args) {
|
|
673
|
+
checkCall(name, args.length);
|
|
674
|
+
const lower = name.toLowerCase();
|
|
675
|
+
if (lower === 'success' || lower === 'always')
|
|
676
|
+
return true;
|
|
677
|
+
if (['failure', 'cancelled', 'hashfiles'].includes(lower) ||
|
|
678
|
+
args.some((arg) => arg instanceof Unknown)) {
|
|
679
|
+
return new Unknown();
|
|
680
|
+
}
|
|
681
|
+
return callFunction(name, args, this.ctx);
|
|
682
|
+
}
|
|
585
683
|
}
|
|
586
684
|
function evaluate(expr, ctx) {
|
|
587
685
|
return new Parser(tokenize(expr), ctx).parse();
|
|
@@ -670,6 +768,30 @@ function evaluateCondition(expr, ctx) {
|
|
|
670
768
|
// it fails the step or job), never a condition that passes.
|
|
671
769
|
return toBoolean(evaluate(trimmed, ctx));
|
|
672
770
|
}
|
|
771
|
+
/**
|
|
772
|
+
* Whether an `if:` holds when only the `known` contexts are known, e.g.
|
|
773
|
+
* `{ github: { event_name: 'push' } }`: true or false when that settles
|
|
774
|
+
* it, undefined when it depends on anything else (or can't be parsed).
|
|
775
|
+
* Used to check a contract without running the workflow.
|
|
776
|
+
*/
|
|
777
|
+
function staticCondition(expr, known) {
|
|
778
|
+
if (expr === undefined || typeof expr === 'boolean')
|
|
779
|
+
return expr ?? true;
|
|
780
|
+
let trimmed = expr.trim();
|
|
781
|
+
const wrapped = trimmed.match(/^\$\{\{([\s\S]*)\}\}$/);
|
|
782
|
+
if (wrapped)
|
|
783
|
+
trimmed = wrapped[1].trim();
|
|
784
|
+
if (trimmed === '')
|
|
785
|
+
return true;
|
|
786
|
+
try {
|
|
787
|
+
return truthOf(new Parser(tokenize(trimmed), createContext(), undefined, false, {
|
|
788
|
+
...known
|
|
789
|
+
}).parse());
|
|
790
|
+
}
|
|
791
|
+
catch {
|
|
792
|
+
return undefined;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
673
795
|
/** The error for an `if:` that couldn't be evaluated, worded like GitHub's. */
|
|
674
796
|
function ifEvaluationError(target, error) {
|
|
675
797
|
return `Error when evaluating 'if' for ${target}. ${error instanceof Error ? error.message : String(error)}`;
|
|
@@ -50,6 +50,13 @@ const expression_1 = require("./expression");
|
|
|
50
50
|
const container_runtime_1 = require("./container-runtime");
|
|
51
51
|
const shell_1 = require("./shell");
|
|
52
52
|
const container_policy_1 = require("./container-policy");
|
|
53
|
+
/**
|
|
54
|
+
* `jobs.<id>.container.options` the CLI sets on the job container itself:
|
|
55
|
+
* it idles with its own entrypoint and steps run in the mounted workspace.
|
|
56
|
+
*/
|
|
57
|
+
const JOB_CONTAINER_RESERVED = new Set(['--entrypoint', '--workdir', '-w']);
|
|
58
|
+
/** Also reserved when `--container-memory-limit` caps the job container. */
|
|
59
|
+
const MEMORY_OPTIONS = ['--memory', '-m', '--memory-swap'];
|
|
53
60
|
/**
|
|
54
61
|
* Image for jobs whose `runs-on` has no image mapping. Runner-like (Node.js,
|
|
55
62
|
* git, curl and common tools), as used by nektos/act.
|
|
@@ -123,14 +130,6 @@ async function startJobContainer(job, ctx, options, runtime, runDir) {
|
|
|
123
130
|
logger_1.logger.error(noRuntimeMessage(preference));
|
|
124
131
|
return false;
|
|
125
132
|
}
|
|
126
|
-
if (spec &&
|
|
127
|
-
'image' in spec &&
|
|
128
|
-
(('options' in spec && spec.options) ||
|
|
129
|
-
('volumes' in spec && spec.volumes) ||
|
|
130
|
-
('ports' in spec && spec.ports) ||
|
|
131
|
-
('credentials' in spec && spec.credentials))) {
|
|
132
|
-
logger_1.logger.warn('jobs.<id>.container: only image and env are supported; ignoring options/volumes/ports/credentials.');
|
|
133
|
-
}
|
|
134
133
|
// `container: ${{ inputs.image || null }}` that comes out empty means no
|
|
135
134
|
// container image, as on GitHub: use the image for runs-on.
|
|
136
135
|
const specImage = spec?.image
|
|
@@ -140,19 +139,25 @@ async function startJobContainer(job, ctx, options, runtime, runDir) {
|
|
|
140
139
|
options.containerImage ||
|
|
141
140
|
runnerImage(job?.['runs-on'], ctx, options);
|
|
142
141
|
const containerEnv = (0, expression_1.substituteRecord)(specImage && spec && 'env' in spec ? spec.env : undefined, ctx);
|
|
142
|
+
const extras = specImage && spec
|
|
143
|
+
? jobContainerExtras(spec, ctx, options, runtime.workspace)
|
|
144
|
+
: {};
|
|
145
|
+
if (!extras)
|
|
146
|
+
return false;
|
|
143
147
|
const exchangeDir = fs.mkdtempSync(path.join(runDir, 'container-'));
|
|
144
148
|
fs.chmodSync(exchangeDir, 0o777);
|
|
145
149
|
fs.copyFileSync(runtime.eventPath, path.join(exchangeDir, 'event.json'));
|
|
146
150
|
logger_1.logger.info(`Starting job container: ${image} (${containerRuntime.name})`);
|
|
147
151
|
const started = await containerRuntime.start({
|
|
148
152
|
image,
|
|
149
|
-
workingDir:
|
|
153
|
+
workingDir: runtime.workspace,
|
|
150
154
|
readOnlyPaths: protectedWorkspacePaths(options),
|
|
151
155
|
exchangeDir,
|
|
152
156
|
env: containerEnv,
|
|
153
157
|
memoryLimit: options.containerMemoryLimit,
|
|
154
158
|
networkDisabled: options.networkDisabled === true,
|
|
155
|
-
network: runtime.services?.network
|
|
159
|
+
network: runtime.services?.network,
|
|
160
|
+
...extras
|
|
156
161
|
});
|
|
157
162
|
if (!started.success || !started.id) {
|
|
158
163
|
logger_1.logger.error(`Failed to start job container (${image}): ${started.error}`);
|
|
@@ -173,6 +178,47 @@ async function startJobContainer(job, ctx, options, runtime, runDir) {
|
|
|
173
178
|
activeContainers.add(runtime.container);
|
|
174
179
|
return true;
|
|
175
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* The `options`, `ports` and `volumes` of `jobs.<id>.container`, checked
|
|
183
|
+
* with the same policy as service containers: options and host mounts that
|
|
184
|
+
* would reach this machine are refused (undefined: the job fails), options
|
|
185
|
+
* the CLI sets itself are dropped with a warning.
|
|
186
|
+
*/
|
|
187
|
+
function jobContainerExtras(spec, ctx, options, workspace) {
|
|
188
|
+
const label = `jobs.${ctx.github.job ?? '<id>'}.container`;
|
|
189
|
+
const args = spec.options
|
|
190
|
+
? (0, shell_1.splitArgs)((0, expression_1.substituteExpressions)(spec.options, ctx))
|
|
191
|
+
: [];
|
|
192
|
+
const unsafe = (0, container_policy_1.unsafeServiceOptions)(args);
|
|
193
|
+
if (unsafe.length > 0) {
|
|
194
|
+
logger_1.logger.error(`${label}: refusing unsafe options ${[...new Set(unsafe)].join(', ')}: they would give the container access to this machine.`);
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
const reserved = new Set([
|
|
198
|
+
...JOB_CONTAINER_RESERVED,
|
|
199
|
+
...(options.containerMemoryLimit ? MEMORY_OPTIONS : [])
|
|
200
|
+
]);
|
|
201
|
+
const { kept, dropped } = (0, container_policy_1.splitReservedOptions)(args, reserved);
|
|
202
|
+
if (dropped.length > 0) {
|
|
203
|
+
logger_1.logger.warn(`${label}: ignoring options the CLI sets itself: ${[...new Set(dropped)].join(', ')}.`);
|
|
204
|
+
}
|
|
205
|
+
const volumes = (spec.volumes ?? []).map((v) => (0, expression_1.substituteExpressions)(v, ctx));
|
|
206
|
+
for (const volume of volumes) {
|
|
207
|
+
const reason = (0, container_policy_1.unsafeServiceVolumeReason)(volume, workspace);
|
|
208
|
+
if (reason) {
|
|
209
|
+
logger_1.logger.error(`${label}: ${reason}.`);
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (spec.credentials) {
|
|
214
|
+
logger_1.logger.warn(`${label}: credentials are ignored; log in with \`docker login\` instead.`);
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
extraArgs: kept,
|
|
218
|
+
ports: (spec.ports ?? []).map((port) => (0, expression_1.substituteExpressions)(String(port), ctx)),
|
|
219
|
+
volumes
|
|
220
|
+
};
|
|
221
|
+
}
|
|
176
222
|
/**
|
|
177
223
|
* The image for a job's `runs-on`: the first label with a mapping in
|
|
178
224
|
* `runner-images` (or the built-in one), else the default image, with a
|
|
@@ -267,7 +313,7 @@ async function startJobServices(job, ctx, options, runtime) {
|
|
|
267
313
|
return false;
|
|
268
314
|
}
|
|
269
315
|
for (const volume of volumes) {
|
|
270
|
-
const reason = (0, container_policy_1.unsafeServiceVolumeReason)(volume,
|
|
316
|
+
const reason = (0, container_policy_1.unsafeServiceVolumeReason)(volume, runtime.workspace);
|
|
271
317
|
if (reason) {
|
|
272
318
|
logger_1.logger.error(`services.${serviceId}: ${reason}.`);
|
|
273
319
|
return false;
|
|
@@ -107,7 +107,7 @@ function runnerContext(runtime) {
|
|
|
107
107
|
return {
|
|
108
108
|
name: 'secureci',
|
|
109
109
|
os: runtime.runnerEnv.RUNNER_OS,
|
|
110
|
-
arch:
|
|
110
|
+
arch: runtime.runnerEnv.RUNNER_ARCH,
|
|
111
111
|
temp: runtime.runnerEnv.RUNNER_TEMP,
|
|
112
112
|
tool_cache: runtime.runnerEnv.RUNNER_TOOL_CACHE
|
|
113
113
|
};
|
|
@@ -126,12 +126,13 @@ function hostHasBash() {
|
|
|
126
126
|
}
|
|
127
127
|
return hostBash;
|
|
128
128
|
}
|
|
129
|
-
function createJobRuntime(github, runDir, defaults = {}) {
|
|
129
|
+
function createJobRuntime(github, runDir, defaults = {}, workspace = process.cwd()) {
|
|
130
130
|
const homeDir = process.env.HOME || process.env.USERPROFILE || os.tmpdir();
|
|
131
131
|
const eventPath = path.join(runDir, 'event.json');
|
|
132
132
|
return {
|
|
133
|
+
workspace,
|
|
133
134
|
runnerEnv: (0, runner_env_1.buildRunnerEnv)(github, {
|
|
134
|
-
workspace
|
|
135
|
+
workspace,
|
|
135
136
|
eventPath,
|
|
136
137
|
// Per job, so concurrent jobs don't share $RUNNER_TEMP.
|
|
137
138
|
tempDir: fs.mkdtempSync(path.join(runDir, 'tmp-')),
|
|
@@ -144,7 +144,7 @@ async function executeNodeAction(action, actionPath, step, actionInputs, callerC
|
|
|
144
144
|
}
|
|
145
145
|
try {
|
|
146
146
|
const { stdout, stderr } = await execFileAsync(node.path, [path.join(actionDir, script)], {
|
|
147
|
-
cwd:
|
|
147
|
+
cwd: runtime.workspace,
|
|
148
148
|
maxBuffer: 64 * 1024 * 1024,
|
|
149
149
|
timeout: limit.ms,
|
|
150
150
|
killSignal: 'SIGKILL',
|
|
@@ -38,6 +38,7 @@ exports.createStepFiles = createStepFiles;
|
|
|
38
38
|
exports.readStepFiles = readStepFiles;
|
|
39
39
|
exports.cleanupStepFiles = cleanupStepFiles;
|
|
40
40
|
exports.processWorkflowCommands = processWorkflowCommands;
|
|
41
|
+
exports.runnerArch = runnerArch;
|
|
41
42
|
exports.buildRunnerEnv = buildRunnerEnv;
|
|
42
43
|
exports.prependPath = prependPath;
|
|
43
44
|
exports.hostBaseEnv = hostBaseEnv;
|
|
@@ -248,6 +249,24 @@ function runnerOs() {
|
|
|
248
249
|
return 'Linux';
|
|
249
250
|
}
|
|
250
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* `RUNNER_ARCH` / `runner.arch` for a Node.js architecture, using GitHub's
|
|
254
|
+
* values (X86, X64, ARM, ARM64). Jobs run natively (a job container has the
|
|
255
|
+
* host's architecture), so the host's is the runner's. Anything else reports
|
|
256
|
+
* X64, as before this was mapped.
|
|
257
|
+
*/
|
|
258
|
+
function runnerArch(arch = process.arch) {
|
|
259
|
+
switch (arch) {
|
|
260
|
+
case 'arm64':
|
|
261
|
+
return 'ARM64';
|
|
262
|
+
case 'arm':
|
|
263
|
+
return 'ARM';
|
|
264
|
+
case 'ia32':
|
|
265
|
+
return 'X86';
|
|
266
|
+
default:
|
|
267
|
+
return 'X64';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
251
270
|
/**
|
|
252
271
|
* The default environment variables GitHub's runner exports to every step,
|
|
253
272
|
* derived from the (local, best-effort) `github` context.
|
|
@@ -274,6 +293,7 @@ function buildRunnerEnv(github, options) {
|
|
|
274
293
|
GITHUB_WORKSPACE: options.workspace,
|
|
275
294
|
GITHUB_EVENT_PATH: options.eventPath,
|
|
276
295
|
RUNNER_OS: runnerOs(),
|
|
296
|
+
RUNNER_ARCH: runnerArch(),
|
|
277
297
|
RUNNER_TEMP: options.tempDir,
|
|
278
298
|
RUNNER_TOOL_CACHE: options.toolCache
|
|
279
299
|
};
|
package/dist/runner/steps.js
CHANGED
|
@@ -143,8 +143,8 @@ async function executeStep(step, options, runtime, ctx) {
|
|
|
143
143
|
timeout: limit.ms,
|
|
144
144
|
killSignal: 'SIGKILL',
|
|
145
145
|
cwd: workingDirectory
|
|
146
|
-
? path.resolve(
|
|
147
|
-
:
|
|
146
|
+
? path.resolve(runtime.workspace, workingDirectory)
|
|
147
|
+
: runtime.workspace,
|
|
148
148
|
env: {
|
|
149
149
|
...(0, runner_env_1.hostBaseEnv)(),
|
|
150
150
|
...runtime.runnerEnv,
|