Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cef9ee9223 | |||
| 554882dca6 | |||
| bdb27c47d0 | |||
| c44ed442f4 | |||
| 4eb88dc0f0 | |||
| 6f4be31791 | |||
| 20984daf61 | |||
| 858f1cb727 | |||
| 0345c893f4 | |||
| 75dea93e1d |
+15
-9
@@ -2,20 +2,26 @@
|
||||
* Unit tests for the action's entrypoint, src/index.ts
|
||||
*/
|
||||
|
||||
import * as core from '@actions/core'
|
||||
import * as main from '../src/main'
|
||||
import { jest, describe, expect, beforeEach } from '@jest/globals'
|
||||
|
||||
// Mock the action's entrypoint
|
||||
const runMock = jest.spyOn(main, 'run').mockImplementation()
|
||||
const getBooleanInputMock = jest.spyOn(core, 'getBooleanInput')
|
||||
// Mock modules before importing them
|
||||
const runMock = jest.fn<() => Promise<void>>()
|
||||
|
||||
jest.unstable_mockModule('../src/main', () => ({
|
||||
run: runMock
|
||||
}))
|
||||
|
||||
jest.unstable_mockModule('@actions/core', () => ({
|
||||
getInput: jest.fn(() => ''),
|
||||
getBooleanInput: jest.fn(() => false)
|
||||
}))
|
||||
|
||||
describe('index', () => {
|
||||
beforeEach(() => {
|
||||
getBooleanInputMock.mockImplementation(() => false)
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
it('calls run when imported', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
require('../src/index')
|
||||
it('calls run when imported', async () => {
|
||||
await import('../src/index.js')
|
||||
|
||||
expect(runMock).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
+180
-83
@@ -5,41 +5,110 @@
|
||||
* Specifically, the inputs listed in `action.yml` should be set as environment
|
||||
* variables following the pattern `INPUT_<INPUT_NAME>`.
|
||||
*/
|
||||
import * as core from '@actions/core'
|
||||
import * as github from '@actions/github'
|
||||
import { mockFulcio, mockRekor, mockTSA } from '@sigstore/mock'
|
||||
import * as oci from '@sigstore/oci'
|
||||
import * as attest from '@actions/attest'
|
||||
import * as localAttest from '../src/attest'
|
||||
import fs from 'fs/promises'
|
||||
import nock from 'nock'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import { MockAgent, setGlobalDispatcher } from 'undici'
|
||||
import { SEARCH_PUBLIC_GOOD_URL } from '../src/endpoints'
|
||||
import * as main from '../src/main'
|
||||
import {
|
||||
jest,
|
||||
describe,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
it
|
||||
} from '@jest/globals'
|
||||
import type { RunInputs } from '../src/main.js'
|
||||
|
||||
// Mock the GitHub Actions core library
|
||||
const infoMock = jest.spyOn(core, 'info')
|
||||
const warningMock = jest.spyOn(core, 'warning')
|
||||
const startGroupMock = jest.spyOn(core, 'startGroup')
|
||||
const setOutputMock = jest.spyOn(core, 'setOutput')
|
||||
const setFailedMock = jest.spyOn(core, 'setFailed')
|
||||
// Create mock functions for core
|
||||
const infoMock = jest.fn()
|
||||
const warningMock = jest.fn()
|
||||
const startGroupMock = jest.fn()
|
||||
const endGroupMock = jest.fn()
|
||||
const setOutputMock = jest.fn()
|
||||
const setFailedMock = jest.fn()
|
||||
const summaryWriteMock = jest.fn<() => Promise<void>>()
|
||||
|
||||
// Ensure that setFailed doesn't set an exit code during tests
|
||||
setFailedMock.mockImplementation(() => {})
|
||||
// Create a mock summary object
|
||||
const mockSummary = {
|
||||
addHeading: jest.fn().mockReturnThis(),
|
||||
addRaw: jest.fn().mockReturnThis(),
|
||||
addTable: jest.fn().mockReturnThis(),
|
||||
addSeparator: jest.fn().mockReturnThis(),
|
||||
addLink: jest.fn().mockReturnThis(),
|
||||
addBreak: jest.fn().mockReturnThis(),
|
||||
addList: jest.fn().mockReturnThis(),
|
||||
write: summaryWriteMock.mockResolvedValue(undefined)
|
||||
}
|
||||
|
||||
const summaryWriteMock = jest.spyOn(core.summary, 'write')
|
||||
summaryWriteMock.mockResolvedValue(core.summary)
|
||||
// Mock @actions/core before importing
|
||||
jest.unstable_mockModule('@actions/core', () => ({
|
||||
info: infoMock,
|
||||
warning: warningMock,
|
||||
startGroup: startGroupMock,
|
||||
endGroup: endGroupMock,
|
||||
setOutput: setOutputMock,
|
||||
setFailed: setFailedMock,
|
||||
summary: mockSummary
|
||||
}))
|
||||
|
||||
// Mock the action's main function
|
||||
const runMock = jest.spyOn(main, 'run')
|
||||
// Create mocks for OCI and attest modules
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
const getRegistryCredentialsMock = jest.fn<(...args: any[]) => any>()
|
||||
const attachArtifactToImageMock = jest.fn<(...args: any[]) => any>()
|
||||
const createStorageRecordMock = jest.fn<(...args: any[]) => any>()
|
||||
const attestMock = jest.fn<(...args: any[]) => any>()
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
|
||||
// Mock @sigstore/oci
|
||||
jest.unstable_mockModule('@sigstore/oci', () => ({
|
||||
getRegistryCredentials: getRegistryCredentialsMock,
|
||||
attachArtifactToImage: attachArtifactToImageMock
|
||||
}))
|
||||
|
||||
// Mock @actions/attest
|
||||
jest.unstable_mockModule('@actions/attest', () => ({
|
||||
attest: attestMock,
|
||||
createStorageRecord: createStorageRecordMock
|
||||
}))
|
||||
|
||||
// Create a mutable context object for @actions/github
|
||||
const mockContext: Record<string, unknown> = {}
|
||||
|
||||
// Mock for getOctokit to return a mock octokit client
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const mockReposGet = jest.fn<(...args: any[]) => any>()
|
||||
const mockOctokit = {
|
||||
rest: {
|
||||
repos: {
|
||||
get: mockReposGet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jest.unstable_mockModule('@actions/github', () => ({
|
||||
context: mockContext,
|
||||
getOctokit: jest.fn(() => mockOctokit)
|
||||
}))
|
||||
|
||||
// Helper to set the mocked GitHub context
|
||||
function setGHContext(context: object): void {
|
||||
Object.keys(mockContext).forEach(key => delete mockContext[key])
|
||||
Object.assign(mockContext, context)
|
||||
}
|
||||
|
||||
// Now import the modules after mocking
|
||||
const { mockFulcio, mockRekor, mockTSA } = await import('@sigstore/mock')
|
||||
const fs = (await import('fs/promises')).default
|
||||
const nock = (await import('nock')).default
|
||||
const os = (await import('os')).default
|
||||
const path = (await import('path')).default
|
||||
const { MockAgent, setGlobalDispatcher } = await import('undici')
|
||||
const { SEARCH_PUBLIC_GOOD_URL } = await import('../src/endpoints.js')
|
||||
const { run } = (await import('../src/main.js')) as {
|
||||
run: (inputs: RunInputs) => Promise<void>
|
||||
}
|
||||
|
||||
// MockAgent for mocking @actions/github
|
||||
const mockAgent = new MockAgent()
|
||||
setGlobalDispatcher(mockAgent)
|
||||
|
||||
const defaultInputs: main.RunInputs = {
|
||||
const defaultInputs: RunInputs = {
|
||||
predicate: '',
|
||||
predicateType: '',
|
||||
predicatePath: '',
|
||||
@@ -55,10 +124,8 @@ const defaultInputs: main.RunInputs = {
|
||||
}
|
||||
|
||||
describe('action', () => {
|
||||
// Capture original environment variables and GitHub context so we can restore
|
||||
// them after each test
|
||||
// Capture original environment variables so we can restore them after each test
|
||||
const originalEnv = process.env
|
||||
const originalContext = { ...github.context }
|
||||
|
||||
// Mock OIDC token endpoint
|
||||
const tokenURL = 'https://token.url'
|
||||
@@ -82,6 +149,34 @@ describe('action', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
|
||||
// Set up default GitHub context with empty payload
|
||||
setGHContext({
|
||||
payload: {},
|
||||
repo: { owner: 'test-owner', repo: 'test-repo' }
|
||||
})
|
||||
|
||||
// Set up default return value for attestMock (without tlogID for private/GitHub sigstore)
|
||||
attestMock.mockResolvedValue({
|
||||
attestationID,
|
||||
bundle: {
|
||||
mediaType: 'application/vnd.dev.sigstore.bundle.v0.3+json',
|
||||
verificationMaterial: {
|
||||
certificate: {
|
||||
rawBytes: Buffer.from(
|
||||
'-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----'
|
||||
).toString('base64')
|
||||
},
|
||||
tlogEntries: []
|
||||
},
|
||||
content: {}
|
||||
},
|
||||
certificate:
|
||||
'-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----'
|
||||
})
|
||||
|
||||
// Set up default return value for createStorageRecordMock (returns array of record IDs)
|
||||
createStorageRecordMock.mockResolvedValue([storageRecordID])
|
||||
|
||||
nock(tokenURL)
|
||||
.get('/')
|
||||
.query({ audience: 'sigstore' })
|
||||
@@ -114,12 +209,12 @@ describe('action', () => {
|
||||
// Restore the original environment
|
||||
process.env = originalEnv
|
||||
|
||||
// Restore the original github.context
|
||||
setGHContext(originalContext)
|
||||
// Clear the github context
|
||||
setGHContext({ payload: {}, repo: { owner: '', repo: '' } })
|
||||
})
|
||||
|
||||
describe('when ACTIONS_ID_TOKEN_REQUEST_URL is not set', () => {
|
||||
const inputs: main.RunInputs = {
|
||||
const inputs: RunInputs = {
|
||||
...defaultInputs,
|
||||
subjectDigest,
|
||||
subjectName,
|
||||
@@ -134,9 +229,8 @@ describe('action', () => {
|
||||
})
|
||||
|
||||
it('sets a failed status', async () => {
|
||||
await main.run(inputs)
|
||||
await run(inputs)
|
||||
|
||||
expect(runMock).toHaveReturned()
|
||||
expect(setFailedMock).toHaveBeenCalledWith(
|
||||
new Error(
|
||||
'missing "id-token" permission. Please add "permissions: id-token: write" to your workflow.'
|
||||
@@ -147,9 +241,8 @@ describe('action', () => {
|
||||
|
||||
describe('when no inputs are provided', () => {
|
||||
it('sets a failed status', async () => {
|
||||
await main.run(defaultInputs)
|
||||
await run(defaultInputs)
|
||||
|
||||
expect(runMock).toHaveReturned()
|
||||
expect(setFailedMock).toHaveBeenCalledWith(
|
||||
new Error(
|
||||
'One of subject-path, subject-digest, or subject-checksums must be provided'
|
||||
@@ -159,7 +252,7 @@ describe('action', () => {
|
||||
})
|
||||
|
||||
describe('when the repository is private', () => {
|
||||
const inputs: main.RunInputs = {
|
||||
const inputs: RunInputs = {
|
||||
...defaultInputs,
|
||||
subjectDigest,
|
||||
subjectName,
|
||||
@@ -183,10 +276,9 @@ describe('action', () => {
|
||||
})
|
||||
|
||||
it('invokes the action w/o error', async () => {
|
||||
await main.run(inputs)
|
||||
await run(inputs)
|
||||
|
||||
expect(runMock).toHaveReturned()
|
||||
expect(setFailedMock).not.toHaveBeenCalledWith()
|
||||
expect(setFailedMock).not.toHaveBeenCalled()
|
||||
expect(infoMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.stringMatching(
|
||||
@@ -229,13 +321,7 @@ describe('action', () => {
|
||||
})
|
||||
|
||||
describe('when the repository is public', () => {
|
||||
const getRegCredsSpy = jest.spyOn(oci, 'getRegistryCredentials')
|
||||
const attachArtifactSpy = jest.spyOn(oci, 'attachArtifactToImage')
|
||||
const repoOwnerIsOrgSpy = jest.spyOn(localAttest, 'repoOwnerIsOrg')
|
||||
const createStorageRecordSpy = jest.spyOn(attest, 'createStorageRecord')
|
||||
const createAttestationSpy = jest.spyOn(localAttest, 'createAttestation')
|
||||
|
||||
const inputs: main.RunInputs = {
|
||||
const inputs: RunInputs = {
|
||||
...defaultInputs,
|
||||
subjectDigest,
|
||||
subjectName,
|
||||
@@ -258,28 +344,50 @@ describe('action', () => {
|
||||
})
|
||||
await mockRekor({ baseURL: 'https://rekor.sigstore.dev' })
|
||||
|
||||
getRegCredsSpy.mockImplementation(() => ({
|
||||
getRegistryCredentialsMock.mockImplementation(() => ({
|
||||
username: 'username',
|
||||
password: 'password'
|
||||
}))
|
||||
attachArtifactSpy.mockResolvedValue({
|
||||
attachArtifactToImageMock.mockResolvedValue({
|
||||
digest: 'sha256:123456',
|
||||
mediaType: 'application/vnd.cncf.notary.v2',
|
||||
size: 123456
|
||||
})
|
||||
repoOwnerIsOrgSpy.mockResolvedValue(true)
|
||||
|
||||
// Set up attestMock with tlogID for public good sigstore
|
||||
attestMock.mockResolvedValue({
|
||||
attestationID,
|
||||
bundle: {
|
||||
mediaType: 'application/vnd.dev.sigstore.bundle.v0.3+json',
|
||||
verificationMaterial: {
|
||||
certificate: {
|
||||
rawBytes: Buffer.from(
|
||||
'-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----'
|
||||
).toString('base64')
|
||||
},
|
||||
tlogEntries: [{ logIndex: '123' }]
|
||||
},
|
||||
content: {}
|
||||
},
|
||||
certificate:
|
||||
'-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----',
|
||||
tlogID: '123'
|
||||
})
|
||||
|
||||
// Mock the repos.get API call for repoOwnerIsOrg check
|
||||
mockReposGet.mockResolvedValue({
|
||||
data: { owner: { type: 'Organization' } }
|
||||
})
|
||||
})
|
||||
|
||||
it('invokes the action w/o error', async () => {
|
||||
await main.run(inputs)
|
||||
await run(inputs)
|
||||
|
||||
expect(runMock).toHaveReturned()
|
||||
expect(setFailedMock).not.toHaveBeenCalled()
|
||||
expect(getRegCredsSpy).toHaveBeenCalledWith(subjectName)
|
||||
expect(attachArtifactSpy).toHaveBeenCalled()
|
||||
expect(createAttestationSpy).toHaveBeenCalled()
|
||||
expect(repoOwnerIsOrgSpy).toHaveBeenCalled()
|
||||
expect(createStorageRecordSpy).toHaveBeenCalled()
|
||||
expect(getRegistryCredentialsMock).toHaveBeenCalledWith(subjectName)
|
||||
expect(attachArtifactToImageMock).toHaveBeenCalled()
|
||||
expect(attestMock).toHaveBeenCalled()
|
||||
expect(createStorageRecordMock).toHaveBeenCalled()
|
||||
expect(warningMock).not.toHaveBeenCalled()
|
||||
expect(infoMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
@@ -344,16 +452,14 @@ describe('action', () => {
|
||||
|
||||
it('catches error when storage record creation fails and continues', async () => {
|
||||
// Mock the createStorageRecord function and throw an error
|
||||
createStorageRecordSpy.mockRejectedValueOnce(
|
||||
createStorageRecordMock.mockRejectedValueOnce(
|
||||
new Error('Failed to persist storage record: Not Found')
|
||||
)
|
||||
|
||||
await main.run(inputs)
|
||||
await run(inputs)
|
||||
|
||||
expect(runMock).toHaveReturned()
|
||||
expect(createAttestationSpy).toHaveBeenCalled()
|
||||
expect(repoOwnerIsOrgSpy).toHaveBeenCalled()
|
||||
expect(createStorageRecordSpy).toHaveBeenCalled()
|
||||
expect(attestMock).toHaveBeenCalled()
|
||||
expect(createStorageRecordMock).toHaveBeenCalled()
|
||||
expect(setFailedMock).not.toHaveBeenCalled()
|
||||
expect(warningMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
@@ -362,17 +468,16 @@ describe('action', () => {
|
||||
})
|
||||
|
||||
it('does not create a storage record when the repo is owned by a user', async () => {
|
||||
repoOwnerIsOrgSpy.mockResolvedValueOnce(false)
|
||||
// Mock the repos.get API to return a user-owned repo
|
||||
mockReposGet.mockResolvedValueOnce({ data: { owner: { type: 'User' } } })
|
||||
|
||||
await main.run(inputs)
|
||||
await run(inputs)
|
||||
|
||||
expect(runMock).toHaveReturned()
|
||||
expect(setFailedMock).not.toHaveBeenCalled()
|
||||
expect(getRegCredsSpy).toHaveBeenCalledWith(subjectName)
|
||||
expect(attachArtifactSpy).toHaveBeenCalled()
|
||||
expect(createAttestationSpy).toHaveBeenCalled()
|
||||
expect(repoOwnerIsOrgSpy).toHaveBeenCalled()
|
||||
expect(createStorageRecordSpy).not.toHaveBeenCalled()
|
||||
expect(getRegistryCredentialsMock).toHaveBeenCalledWith(subjectName)
|
||||
expect(attachArtifactToImageMock).toHaveBeenCalled()
|
||||
expect(attestMock).toHaveBeenCalled()
|
||||
expect(createStorageRecordMock).not.toHaveBeenCalled()
|
||||
expect(warningMock).not.toHaveBeenCalled()
|
||||
expect(infoMock).toHaveBeenCalledWith(
|
||||
expect.stringMatching(
|
||||
@@ -436,16 +541,15 @@ describe('action', () => {
|
||||
})
|
||||
|
||||
it('invokes the action w/o error', async () => {
|
||||
const inputs: main.RunInputs = {
|
||||
const inputs: RunInputs = {
|
||||
...defaultInputs,
|
||||
subjectPath: path.join(dir, `${filename}-*`),
|
||||
predicateType,
|
||||
predicate,
|
||||
githubToken: 'gh-token'
|
||||
}
|
||||
await main.run(inputs)
|
||||
await run(inputs)
|
||||
|
||||
expect(runMock).toHaveReturned()
|
||||
expect(setFailedMock).not.toHaveBeenCalled()
|
||||
expect(infoMock).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
@@ -484,16 +588,15 @@ describe('action', () => {
|
||||
})
|
||||
|
||||
it('sets a failed status', async () => {
|
||||
const inputs: main.RunInputs = {
|
||||
const inputs: RunInputs = {
|
||||
...defaultInputs,
|
||||
subjectPath: path.join(dir, `${filename}-*`),
|
||||
predicateType,
|
||||
predicate,
|
||||
githubToken: 'gh-token'
|
||||
}
|
||||
await main.run(inputs)
|
||||
await run(inputs)
|
||||
|
||||
expect(runMock).toHaveReturned()
|
||||
expect(setFailedMock).toHaveBeenCalledWith(
|
||||
new Error(
|
||||
'Too many subjects specified. The maximum number of subjects is 1024.'
|
||||
@@ -502,9 +605,3 @@ describe('action', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Stubbing the GitHub context is a bit tricky. We need to use
|
||||
// `Object.defineProperty` because `github.context` is read-only.
|
||||
function setGHContext(context: object): void {
|
||||
Object.defineProperty(github, 'context', { value: context })
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs/promises'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import { predicateFromInputs, PredicateInputs } from '../src/predicate'
|
||||
import { predicateFromInputs, PredicateInputs } from '../src/predicate.js'
|
||||
|
||||
describe('subjectFromInputs', () => {
|
||||
const blankInputs: PredicateInputs = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { highlight, mute } from '../src/style'
|
||||
import { highlight, mute } from '../src/style.js'
|
||||
|
||||
describe('style', () => {
|
||||
describe('highlight', () => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
formatSubjectDigest,
|
||||
subjectFromInputs,
|
||||
SubjectInputs
|
||||
} from '../src/subject'
|
||||
} from '../src/subject.js'
|
||||
|
||||
describe('subjectFromInputs', () => {
|
||||
const blankInputs: SubjectInputs = {
|
||||
@@ -264,10 +264,15 @@ describe('subjectFromInputs', () => {
|
||||
expect(subjects).toBeDefined()
|
||||
expect(subjects).toHaveLength(3)
|
||||
|
||||
subjects.forEach((subject, i) => {
|
||||
expect(subject.name).toEqual(`${filename}-${i}`)
|
||||
expect(subject.digest).toEqual({ sha256: expectedDigest })
|
||||
})
|
||||
subjects.forEach(
|
||||
(
|
||||
subject: { name: string; digest: Record<string, string> },
|
||||
i: number
|
||||
) => {
|
||||
expect(subject.name).toEqual(`${filename}-${i}`)
|
||||
expect(subject.digest).toEqual({ sha256: expectedDigest })
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
+3
-5
@@ -1,7 +1,6 @@
|
||||
"use strict";
|
||||
exports.id = 606;
|
||||
exports.ids = [606];
|
||||
exports.modules = {
|
||||
export const id = 606;
|
||||
export const ids = [606];
|
||||
export const modules = {
|
||||
|
||||
/***/ 606:
|
||||
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
||||
@@ -298,4 +297,3 @@ const pMapSkip = Symbol('skip');
|
||||
/***/ })
|
||||
|
||||
};
|
||||
;
|
||||
+895
-1699
File diff suppressed because one or more lines are too long
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
@@ -89,6 +89,13 @@ export default tseslint.config(
|
||||
allowObject: true
|
||||
}
|
||||
]
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
project: './tsconfig.lint.json'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
export default {
|
||||
preset: "ts-jest",
|
||||
verbose: true,
|
||||
clearMocks: true,
|
||||
testEnvironment: 'node',
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
testMatch: ['**/*.test.ts'],
|
||||
testPathIgnorePatterns: [
|
||||
"/node_modules/",
|
||||
"/dist/"
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.ts$': [
|
||||
'ts-jest',
|
||||
{
|
||||
useESM: true,
|
||||
diagnostics: {
|
||||
ignoreCodes: [151002]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
coverageReporters: [
|
||||
"json-summary",
|
||||
"text",
|
||||
"lcov"
|
||||
],
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: [
|
||||
"./src/**"
|
||||
],
|
||||
extensionsToTreatAsEsm: ['.ts'],
|
||||
transformIgnorePatterns: ['node_modules/(?!(@actions)/)'],
|
||||
moduleNameMapper: {
|
||||
'^(\\.{1,2}/.*)\\.js$': '$1'
|
||||
},
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
process.stdout.write = jest.fn()
|
||||
Generated
+118
@@ -18,12 +18,14 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@jest/globals": "^30.2.0",
|
||||
"@sigstore/mock": "^0.11.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/make-fetch-happen": "^10.0.4",
|
||||
"@types/node": "^25.2.0",
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jest": "^29.12.1",
|
||||
"jest": "^30.2.0",
|
||||
@@ -4460,6 +4462,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-context": {
|
||||
"version": "0.1.9",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz",
|
||||
"integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-tsconfig": "^4.10.1",
|
||||
"stable-hash-x": "^0.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint-import-context"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"unrs-resolver": "^1.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"unrs-resolver": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-node": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
|
||||
@@ -4482,6 +4509,41 @@
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-typescript": {
|
||||
"version": "4.4.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz",
|
||||
"integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"debug": "^4.4.1",
|
||||
"eslint-import-context": "^0.1.8",
|
||||
"get-tsconfig": "^4.10.1",
|
||||
"is-bun-module": "^2.0.0",
|
||||
"stable-hash-x": "^0.2.0",
|
||||
"tinyglobby": "^0.2.14",
|
||||
"unrs-resolver": "^1.7.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.17.0 || >=18.6.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint-import-resolver-typescript"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "*",
|
||||
"eslint-plugin-import": "*",
|
||||
"eslint-plugin-import-x": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"eslint-plugin-import": {
|
||||
"optional": true
|
||||
},
|
||||
"eslint-plugin-import-x": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-module-utils": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
|
||||
@@ -5093,6 +5155,19 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-tsconfig": {
|
||||
"version": "4.13.3",
|
||||
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.3.tgz",
|
||||
"integrity": "sha512-vp8Cj/+9Q/ibZUrq1rhy8mCTQpCk31A3uu9wc1C50yAb3x2pFHOsGdAZQ7jD86ARayyxZUViYeIztW+GE8dcrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"resolve-pkg-maps": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
|
||||
@@ -5592,6 +5667,29 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-bun-module": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
|
||||
"integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/is-bun-module/node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-callable": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||
@@ -8667,6 +8765,16 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-pkg-maps": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||
@@ -9023,6 +9131,16 @@
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stable-hash-x": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz",
|
||||
"integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stack-utils": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
|
||||
|
||||
+5
-34
@@ -2,6 +2,7 @@
|
||||
"name": "actions/attest",
|
||||
"description": "Generate signed attestations for workflow artifacts",
|
||||
"version": "3.2.0",
|
||||
"type": "module",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"homepage": "https://github.com/actions/attest",
|
||||
@@ -24,7 +25,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"bundle": "npm run format:write && npm run package",
|
||||
"ci-test": "jest",
|
||||
"ci-test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
||||
"format:write": "prettier --write **/*.ts",
|
||||
"format:check": "prettier --check **/*.ts",
|
||||
"lint:eslint": "npx eslint",
|
||||
@@ -32,42 +33,10 @@
|
||||
"lint": "npm run lint:eslint && npm run lint:markdown",
|
||||
"package": "ncc build src/index.ts --license licenses.txt",
|
||||
"package:watch": "npm run package -- --watch",
|
||||
"test": "jest",
|
||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
||||
"all": "npm run format:write && npm run lint && npm run test && npm run package"
|
||||
},
|
||||
"license": "MIT",
|
||||
"jest": {
|
||||
"preset": "ts-jest",
|
||||
"setupFilesAfterEnv": [
|
||||
"./jest.setup.js"
|
||||
],
|
||||
"verbose": true,
|
||||
"clearMocks": true,
|
||||
"testEnvironment": "node",
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"ts"
|
||||
],
|
||||
"testMatch": [
|
||||
"**/*.test.ts"
|
||||
],
|
||||
"testPathIgnorePatterns": [
|
||||
"/node_modules/",
|
||||
"/dist/"
|
||||
],
|
||||
"transform": {
|
||||
"^.+\\.ts$": "ts-jest"
|
||||
},
|
||||
"coverageReporters": [
|
||||
"json-summary",
|
||||
"text",
|
||||
"lcov"
|
||||
],
|
||||
"collectCoverage": true,
|
||||
"collectCoverageFrom": [
|
||||
"./src/**"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/attest": "^2.2.1",
|
||||
"@actions/core": "^2.0.2",
|
||||
@@ -78,12 +47,14 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@jest/globals": "^30.2.0",
|
||||
"@sigstore/mock": "^0.11.0",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/make-fetch-happen": "^10.0.4",
|
||||
"@types/node": "^25.2.0",
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jest": "^29.12.1",
|
||||
"jest": "^30.2.0",
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import {
|
||||
createStorageRecord
|
||||
} from '@actions/attest'
|
||||
import { attachArtifactToImage, getRegistryCredentials } from '@sigstore/oci'
|
||||
import { formatSubjectDigest } from './subject'
|
||||
import { formatSubjectDigest } from './subject.js'
|
||||
import * as core from '@actions/core'
|
||||
import * as github from '@actions/github'
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
* The entrypoint for the action.
|
||||
*/
|
||||
import * as core from '@actions/core'
|
||||
import { run, RunInputs } from './main'
|
||||
import { run, RunInputs } from './main.js'
|
||||
|
||||
const inputs: RunInputs = {
|
||||
subjectPath: core.getInput('subject-path'),
|
||||
|
||||
+5
-5
@@ -3,15 +3,15 @@ import * as github from '@actions/github'
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import path from 'path'
|
||||
import { AttestResult, SigstoreInstance, createAttestation } from './attest'
|
||||
import { SEARCH_PUBLIC_GOOD_URL } from './endpoints'
|
||||
import { PredicateInputs, predicateFromInputs } from './predicate'
|
||||
import * as style from './style'
|
||||
import { AttestResult, SigstoreInstance, createAttestation } from './attest.js'
|
||||
import { SEARCH_PUBLIC_GOOD_URL } from './endpoints.js'
|
||||
import { PredicateInputs, predicateFromInputs } from './predicate.js'
|
||||
import * as style from './style.js'
|
||||
import {
|
||||
SubjectInputs,
|
||||
formatSubjectDigest,
|
||||
subjectFromInputs
|
||||
} from './subject'
|
||||
} from './subject.js'
|
||||
|
||||
import type { Subject } from '@actions/attest'
|
||||
|
||||
|
||||
+1
-1
@@ -16,5 +16,5 @@
|
||||
"skipLibCheck": true,
|
||||
"newLine": "lf"
|
||||
},
|
||||
"exclude": ["./dist", "./node_modules", "./__tests__", "./coverage"]
|
||||
"exclude": ["./dist", "./node_modules", "./__tests__", "./coverage", "./jest.config.ts"]
|
||||
}
|
||||
|
||||
+3
-2
@@ -2,8 +2,9 @@
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true
|
||||
"noEmit": true,
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["./__tests__/**/*", "./src/**/*"],
|
||||
"include": ["./__tests__/**/*", "./src/**/*", "./jest.config.ts"],
|
||||
"exclude": ["./dist", "./node_modules", "./coverage", "*.json"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user