limit attestation subject count (#53)
Signed-off-by: Brian DeHamer <[email protected]>
This commit is contained in:
@@ -65,7 +65,7 @@ See [action.yml](action.yml)
|
|||||||
with:
|
with:
|
||||||
# Path to the artifact serving as the subject of the attestation. Must
|
# Path to the artifact serving as the subject of the attestation. Must
|
||||||
# specify exactly one of "subject-path" or "subject-digest". May contain
|
# specify exactly one of "subject-path" or "subject-digest". May contain
|
||||||
# a glob pattern or list of paths.
|
# a glob pattern or list of paths (total subject count cannot exceed 64).
|
||||||
subject-path:
|
subject-path:
|
||||||
|
|
||||||
# SHA256 digest of the subject for the attestation. Must be in the form
|
# SHA256 digest of the subject for the attestation. Must be in the form
|
||||||
|
|||||||
+49
-1
@@ -5,12 +5,14 @@
|
|||||||
* Specifically, the inputs listed in `action.yml` should be set as environment
|
* Specifically, the inputs listed in `action.yml` should be set as environment
|
||||||
* variables following the pattern `INPUT_<INPUT_NAME>`.
|
* variables following the pattern `INPUT_<INPUT_NAME>`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as github from '@actions/github'
|
import * as github from '@actions/github'
|
||||||
import { mockFulcio, mockRekor, mockTSA } from '@sigstore/mock'
|
import { mockFulcio, mockRekor, mockTSA } from '@sigstore/mock'
|
||||||
import * as oci from '@sigstore/oci'
|
import * as oci from '@sigstore/oci'
|
||||||
|
import fs from 'fs/promises'
|
||||||
import nock from 'nock'
|
import nock from 'nock'
|
||||||
|
import os from 'os'
|
||||||
|
import path from 'path'
|
||||||
import { MockAgent, setGlobalDispatcher } from 'undici'
|
import { MockAgent, setGlobalDispatcher } from 'undici'
|
||||||
import { SEARCH_PUBLIC_GOOD_URL } from '../src/endpoints'
|
import { SEARCH_PUBLIC_GOOD_URL } from '../src/endpoints'
|
||||||
import * as main from '../src/main'
|
import * as main from '../src/main'
|
||||||
@@ -286,6 +288,52 @@ describe('action', () => {
|
|||||||
expect(setFailedMock).not.toHaveBeenCalled()
|
expect(setFailedMock).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('when too many subjects are specified', () => {
|
||||||
|
let dir = ''
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const filename = 'subject'
|
||||||
|
const content = 'file content'
|
||||||
|
|
||||||
|
// Set-up temp directory
|
||||||
|
const tmpDir = await fs.realpath(os.tmpdir())
|
||||||
|
dir = await fs.mkdtemp(tmpDir + path.sep)
|
||||||
|
|
||||||
|
// Add files for glob testing
|
||||||
|
for (let i = 0; i < 65; i++) {
|
||||||
|
await fs.writeFile(path.join(dir, `${filename}-${i}`), content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the GH context with private repository visibility and a repo owner.
|
||||||
|
setGHContext({
|
||||||
|
payload: { repository: { visibility: 'private' } },
|
||||||
|
repo: { owner: 'foo', repo: 'bar' }
|
||||||
|
})
|
||||||
|
|
||||||
|
// Mock the action's inputs
|
||||||
|
getInputMock.mockImplementation(
|
||||||
|
mockInput({
|
||||||
|
predicate: '{}',
|
||||||
|
'subject-path': path.join(dir, `${filename}-*`)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
// Clean-up temp directory
|
||||||
|
await fs.rm(dir, { recursive: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets a failed status', async () => {
|
||||||
|
await main.run()
|
||||||
|
|
||||||
|
expect(runMock).toHaveReturned()
|
||||||
|
expect(setFailedMock).toHaveBeenCalledWith(
|
||||||
|
'Too many subjects specified. The maximum number of subjects is 64.'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
function mockInput(inputs: Record<string, string>): typeof core.getInput {
|
function mockInput(inputs: Record<string, string>): typeof core.getInput {
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ inputs:
|
|||||||
description: >
|
description: >
|
||||||
Path to the artifact serving as the subject of the attestation. Must
|
Path to the artifact serving as the subject of the attestation. Must
|
||||||
specify exactly one of "subject-path" or "subject-digest". May contain a
|
specify exactly one of "subject-path" or "subject-digest". May contain a
|
||||||
glob pattern or list of paths.
|
glob pattern or list of paths (total subject count cannot exceed 64).
|
||||||
required: false
|
required: false
|
||||||
subject-digest:
|
subject-digest:
|
||||||
description: >
|
description: >
|
||||||
|
|||||||
+5
-1
@@ -79644,6 +79644,7 @@ const subject_1 = __nccwpck_require__(95206);
|
|||||||
const COLOR_CYAN = '\x1B[36m';
|
const COLOR_CYAN = '\x1B[36m';
|
||||||
const COLOR_DEFAULT = '\x1B[39m';
|
const COLOR_DEFAULT = '\x1B[39m';
|
||||||
const ATTESTATION_FILE_NAME = 'attestation.jsonl';
|
const ATTESTATION_FILE_NAME = 'attestation.jsonl';
|
||||||
|
const MAX_SUBJECT_COUNT = 64;
|
||||||
/**
|
/**
|
||||||
* The main function for the action.
|
* The main function for the action.
|
||||||
* @returns {Promise<void>} Resolves when the action is complete.
|
* @returns {Promise<void>} Resolves when the action is complete.
|
||||||
@@ -79661,8 +79662,11 @@ async function run() {
|
|||||||
if (!process.env.ACTIONS_ID_TOKEN_REQUEST_URL) {
|
if (!process.env.ACTIONS_ID_TOKEN_REQUEST_URL) {
|
||||||
throw new Error('missing "id-token" permission. Please add "permissions: id-token: write" to your workflow.');
|
throw new Error('missing "id-token" permission. Please add "permissions: id-token: write" to your workflow.');
|
||||||
}
|
}
|
||||||
// Calculate subject from inputs and generate provenance
|
// Gather list of subjets
|
||||||
const subjects = await (0, subject_1.subjectFromInputs)();
|
const subjects = await (0, subject_1.subjectFromInputs)();
|
||||||
|
if (subjects.length > MAX_SUBJECT_COUNT) {
|
||||||
|
throw new Error(`Too many subjects specified. The maximum number of subjects is ${MAX_SUBJECT_COUNT}.`);
|
||||||
|
}
|
||||||
const predicate = (0, predicate_1.predicateFromInputs)();
|
const predicate = (0, predicate_1.predicateFromInputs)();
|
||||||
const outputPath = path_1.default.join(tempDir(), ATTESTATION_FILE_NAME);
|
const outputPath = path_1.default.join(tempDir(), ATTESTATION_FILE_NAME);
|
||||||
// Generate attestations for each subject serially
|
// Generate attestations for each subject serially
|
||||||
|
|||||||
+9
-1
@@ -16,6 +16,8 @@ const COLOR_CYAN = '\x1B[36m'
|
|||||||
const COLOR_DEFAULT = '\x1B[39m'
|
const COLOR_DEFAULT = '\x1B[39m'
|
||||||
const ATTESTATION_FILE_NAME = 'attestation.jsonl'
|
const ATTESTATION_FILE_NAME = 'attestation.jsonl'
|
||||||
|
|
||||||
|
const MAX_SUBJECT_COUNT = 64
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main function for the action.
|
* The main function for the action.
|
||||||
* @returns {Promise<void>} Resolves when the action is complete.
|
* @returns {Promise<void>} Resolves when the action is complete.
|
||||||
@@ -38,8 +40,14 @@ export async function run(): Promise<void> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate subject from inputs and generate provenance
|
// Gather list of subjets
|
||||||
const subjects = await subjectFromInputs()
|
const subjects = await subjectFromInputs()
|
||||||
|
if (subjects.length > MAX_SUBJECT_COUNT) {
|
||||||
|
throw new Error(
|
||||||
|
`Too many subjects specified. The maximum number of subjects is ${MAX_SUBJECT_COUNT}.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const predicate = predicateFromInputs()
|
const predicate = predicateFromInputs()
|
||||||
const outputPath = path.join(tempDir(), ATTESTATION_FILE_NAME)
|
const outputPath = path.join(tempDir(), ATTESTATION_FILE_NAME)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user