fix(policy): reject uses block scalar action refs

Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-08-04 00:20:39 +00:00
parent 514464637e
commit 7399fb6577
No known key found for this signature in database
2 changed files with 28 additions and 2 deletions

View file

@ -236,8 +236,10 @@ jobs:
// starts a block scalar. Lines inside ANY block scalar are not parsed
// as structural YAML keys — they are content. For run: block scalars,
// the content is still scanned for expression injection (expressions
// must flow through env:). For non-run block scalars (e.g. script:,
// name:), the content is skipped entirely — no uses: or run: detection.
// must flow through env:). uses: block scalars are rejected because an
// action ref must be an inline scalar to validate its immutable pin.
// For other non-run block scalars (e.g. script:, name:), the content
// is skipped entirely — no uses: or run: detection.
//
// Quoted keys: "uses", 'uses', "run", 'run', "permissions" are all
// recognized in addition to their unquoted forms.
@ -373,6 +375,10 @@ jobs:
const blockM = line.match(/^([ \t]*)(?:-[ \t]+)?("([^"]*)"|'([^']*)'|([\w-]+)):[ \t]*([|>](?:[1-9][-+]?|[-+][1-9]?)?)[ \t]*(?:#.*)?$/);
if (blockM) {
const keyName = blockM[3] !== undefined ? blockM[3] : (blockM[4] !== undefined ? blockM[4] : (blockM[5] || ''));
if (keyName === 'uses') {
errs.push(filename + ':' + (i + 1) + ': uses: block scalar is not supported — action refs must be inline and pinned to an immutable SHA [fnv:' + fnv1a32(line.trim()) + ']');
continue;
}
inBlock = true;
blockIndent = blockM[1].length;
blockIsRun = (keyName === 'run');

View file

@ -1089,6 +1089,26 @@ describe('validateWorkflowContent — quoted keys and block-scalar tracking', ()
assert.deepEqual(v.validateWorkflowContent(content, BASE), [], "single-quoted 'uses' with valid SHA should pass");
});
it('rejects uses block scalar before opaque block handling can hide it', () => {
const content = [
...wfHeader().split('\n'),
' - uses: >-',
' actions/checkout@v4',
].join('\n');
const errs = v.validateWorkflowContent(content, BASE);
assert.ok(errs.some(e => e.includes('uses: block scalar')), 'uses: folded block scalar must fail: ' + errs.join('; '));
});
it('rejects quoted uses block scalar before pin validation can be bypassed', () => {
const content = [
...wfHeader().split('\n'),
' - "uses": |-',
' actions/checkout@v4',
].join('\n');
const errs = v.validateWorkflowContent(content, BASE);
assert.ok(errs.some(e => e.includes('uses: block scalar')), 'quoted uses: literal block scalar must fail: ' + errs.join('; '));
});
it('recognises sequence-form "- run: |" and does not flag uses: inside as action ref', () => {
// The sequence item `- run: |` opens a run block scalar.
// uses: lines inside must not be treated as action references.