Compare commits

..

71 Commits

Author SHA1 Message Date
Bethany d73abc633f Merge branch 'main' into bethanyj28/fix-test 2024-04-03 17:06:22 -04:00
bethanyj28 3ca50668ea update zip stream logic 2024-04-03 17:05:08 -04:00
bethanyj28 f9bafe97e6 update logging 2024-04-03 15:27:58 -04:00
bethanyj28 e94937595b add throw to function 2024-04-03 14:06:37 -04:00
Vallie Joseph 38f54e9d73 Adding debug statement for upload 2024-04-02 05:39:02 +00:00
Vallie Joseph c5f3463c0b adding more descriptive error 2024-04-02 05:25:10 +00:00
Vallie Joseph 96ef8d5d33 adding more error handling 2024-04-01 20:21:01 +00:00
Vallie Joseph 84d3cef541 Removing extra logs 2024-04-01 20:14:07 +00:00
Vallie Joseph a926fff385 adding queue back 2024-04-01 20:04:49 +00:00
Vallie Joseph a2a8a724c2 test queue 2024-04-01 20:01:19 +00:00
Vallie Joseph a8fa53b609 test async eachof 2024-04-01 19:57:11 +00:00
Vallie Joseph 23039a4345 adding asnyc handler back 2024-04-01 16:57:50 +00:00
Vallie Joseph 4778aebf5b adding asnyc handler back 2024-04-01 16:54:55 +00:00
Vallie Joseph 6eff4e928d adding more debug statements 2024-04-01 15:15:28 +00:00
Vallie Joseph 2c4f0f555e adding error checks 2024-04-01 15:07:28 +00:00
Vallie Joseph dea3595881 re-adding archiver for download 2024-04-01 14:33:36 +00:00
Vallie Joseph 4c878a66e7 adding back archiver 2024-04-01 14:30:14 +00:00
Vallie Joseph 2f2738e4ae removing old packages 2024-04-01 14:01:29 +00:00
Vallie Joseph 2d065559f7 Merge branch 'main' into vmjoseph/node-js-monitor 2024-04-01 13:59:46 +00:00
Vallie Joseph 2da528819c cleanup 2024-04-01 13:58:57 +00:00
Vallie Joseph 90ee020ccd cleaning up debug statements 2024-04-01 13:52:01 +00:00
Vallie Joseph c14e304555 adding more debugging statements 2024-03-28 21:17:54 +00:00
Vallie Joseph a2852cee6f adding catch to upload zip 2024-03-28 21:12:51 +00:00
Vallie Joseph 6d94ad125b Removing uneeded libs 2024-03-28 20:38:01 +00:00
Vallie Joseph d02a834fe3 Remove other debug statements 2024-03-28 20:12:52 +00:00
Vallie Joseph 0f23ae1184 re-adding old async/await pattern 2024-03-28 20:05:16 +00:00
Vallie Joseph 5288db3953 removing debugging statements 2024-03-28 19:57:01 +00:00
Vallie Joseph bc893bf1b4 adding compression level back 2024-03-28 19:48:15 +00:00
Vallie Joseph 9322468ef0 Adding pipe back 2024-03-28 19:32:40 +00:00
Vallie Joseph b6c87ceea7 Adding more error handlrs 2024-03-28 19:22:29 +00:00
Vallie Joseph 17c4cab8b2 adding constant zlib compression level 2024-03-28 19:16:10 +00:00
Vallie Joseph 59593338a6 defaulting compression level 2024-03-28 19:15:10 +00:00
Vallie Joseph 0a0e70d1cd Add another catch to see if upload stream is failing 2024-03-28 19:09:53 +00:00
Vallie Joseph c9e825e841 add blob client property check 2024-03-28 19:06:47 +00:00
Vallie Joseph 31a6086649 Adding concurrency and upload response logs 2024-03-28 18:59:41 +00:00
Vallie Joseph d2d69999e3 adding write check 2024-03-28 18:53:15 +00:00
Vallie Joseph 6ac9cbfda9 check if upload and zipload streams are writable 2024-03-28 18:51:00 +00:00
Vallie Joseph d597cf234f adding upload stream check 2024-03-28 18:46:31 +00:00
Vallie Joseph a768aa30c7 adding more logging 2024-03-28 18:43:58 +00:00
Vallie Joseph e4c0440c3a adding more logging 2024-03-28 18:40:37 +00:00
Vallie Joseph 26b62e0fd5 adding more logging 2024-03-28 18:38:52 +00:00
Vallie Joseph 73f526b642 adding closed check 2024-03-28 18:36:40 +00:00
Vallie Joseph 077846ed34 adding readable check 2024-03-28 18:34:07 +00:00
Vallie Joseph 180b75bf01 wrap promises in chain 2024-03-28 18:29:20 +00:00
Vallie Joseph f33a3f4748 Remove finalize 2024-03-28 18:14:40 +00:00
Vallie Joseph 97e4fcfcd5 wait on write stream 2024-03-28 18:07:20 +00:00
Vallie Joseph fe0c0de7db adding lock 2024-03-28 17:53:08 +00:00
Vallie Joseph c7de68f215 updating resolves 2024-03-28 17:48:56 +00:00
Vallie Joseph 66343faec4 add resolve all promises again 2024-03-28 17:43:17 +00:00
Vallie Joseph fd88cbe6df adding check for running 2024-03-28 17:32:01 +00:00
Vallie Joseph bef1fc5f67 adding check for running 2024-03-28 17:30:06 +00:00
Vallie Joseph 18751738a8 update loop for upload 2024-03-28 17:25:01 +00:00
Vallie Joseph b1f55c6942 adding finalize 2024-03-28 17:15:08 +00:00
Vallie Joseph 9299663297 adding promise all 2024-03-28 17:13:32 +00:00
Vallie Joseph 088b9761b4 cleaning up callback methods 2024-03-28 16:15:29 +00:00
Vallie Joseph d97edf7f61 cleaning up warning callack 2024-03-28 16:11:50 +00:00
Vallie Joseph 06482c6da1 adding promise to upload 2024-03-28 16:06:54 +00:00
Vallie Joseph 7441cc7b8b Removing pipe 2024-03-28 15:55:09 +00:00
Vallie Joseph ca87c5e124 testing debug statements 2024-03-28 15:53:03 +00:00
Vallie Joseph 97629b8767 adding archiver back for download 2024-03-28 15:47:34 +00:00
Vallie Joseph 8e29fb2e30 adding default back to zipstream call 2024-03-28 15:44:27 +00:00
Vallie Joseph 560ae4debd updating archive import 2024-03-28 15:41:52 +00:00
Vallie Joseph fda9d58d06 replacing constructor for zipstream with default 2024-03-28 15:28:14 +00:00
Vallie Joseph 6defe19df1 replacing constructor for zipstream 2024-03-28 15:25:37 +00:00
Vallie Joseph 6e4aebbd4e cleaning up unused imports 2024-03-28 15:17:40 +00:00
Vallie Joseph 14eee6f54a updating event handlers 2024-03-28 15:10:34 +00:00
Vallie Joseph e71ddb9e5a updating append and directory zips 2024-03-28 14:44:20 +00:00
Vallie Joseph 13d981a863 Adding buffer and zlib options 2024-03-28 14:32:03 +00:00
Vallie Joseph 4090623397 update debug statement 2024-03-28 04:20:40 +00:00
Vallie Joseph 4617da254f audit fix 2024-03-15 15:01:45 +00:00
Vallie Joseph 1f22f9faf9 adding debug for mac upload testing 2024-03-15 14:53:33 +00:00
30 changed files with 2788 additions and 4454 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ Note that before a PR will be accepted, you must ensure:
1. In a new branch, create a new Lerna package:
```console
$ npm run new-package [name]
$ npm run create-package new-package
```
This will ask you some questions about the new package. Start with `0.0.0` as the first version (look generally at some of the other packages for how the package.json is structured).
+1839 -3449
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -13,7 +13,7 @@
"lint": "eslint packages/**/*.ts",
"lint-fix": "eslint packages/**/*.ts --fix",
"new-package": "scripts/create-package",
"test": "jest --testTimeout 70000"
"test": "jest --testTimeout 60000"
},
"devDependencies": {
"@types/jest": "^29.5.4",
@@ -27,10 +27,10 @@
"eslint-plugin-prettier": "^5.0.0",
"flow-bin": "^0.115.0",
"jest": "^29.6.4",
"lerna": "^6.4.1",
"lerna": "^7.1.4",
"nx": "16.6.0",
"prettier": "^3.0.0",
"ts-jest": "^29.1.1",
"typescript": "^5.2.2"
}
}
}
+2 -18
View File
@@ -1,21 +1,5 @@
# @actions/artifact Releases
### 2.1.8
- Allows `*.localhost` domains for hostname checks for local development.
### 2.1.7
- Update unzip-stream dependency and reverted to using `unzip.Extract()`
### 2.1.6
- Will retry on invalid request responses.
### 2.1.5
- Bumped `archiver` dependency to 7.0.1
### 2.1.4
- Adds info-level logging for zip extraction
@@ -27,9 +11,9 @@
### 2.1.2
- Updated the stream extract functionality to use `unzip.Parse()` instead of `unzip.Extract()` for greater control of unzipping artifacts
### 2.1.1
- Updated `isGhes` check to include `.ghe.com` and `.ghe.localhost` as accepted hosts
### 2.1.0
@@ -116,54 +116,6 @@ describe('artifact-http-client', () => {
expect(mockPost).toHaveBeenCalledTimes(2)
})
it('should retry if invalid body response', async () => {
const mockPost = jest
.fn(() => {
const msgSucceeded = new http.IncomingMessage(new net.Socket())
msgSucceeded.statusCode = 200
return {
message: msgSucceeded,
readBody: async () => {
return Promise.resolve(
`{"ok": true, "signedUploadUrl": "http://localhost:8080/upload"}`
)
}
}
})
.mockImplementationOnce(() => {
const msgFailed = new http.IncomingMessage(new net.Socket())
msgFailed.statusCode = 502
msgFailed.statusMessage = 'Bad Gateway'
return {
message: msgFailed,
readBody: async () => {
return Promise.resolve('💥')
}
}
})
const mockHttpClient = (
HttpClient as unknown as jest.Mock
).mockImplementation(() => {
return {
post: mockPost
}
})
const client = internalArtifactTwirpClient(clientOptions)
const artifact = await client.CreateArtifact({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678',
name: 'artifact',
version: 4
})
expect(mockHttpClient).toHaveBeenCalledTimes(1)
expect(artifact).toBeDefined()
expect(artifact.ok).toBe(true)
expect(artifact.signedUploadUrl).toBe('http://localhost:8080/upload')
expect(mockPost).toHaveBeenCalledTimes(2)
})
it('should fail if the request fails 5 times', async () => {
const mockPost = jest.fn(() => {
const msgFailed = new http.IncomingMessage(new net.Socket())
@@ -20,11 +20,6 @@ describe('isGhes', () => {
expect(config.isGhes()).toBe(false)
})
it('should return false when the request domain ends with .localhost', () => {
process.env.GITHUB_SERVER_URL = 'https://github.localhost'
expect(config.isGhes()).toBe(false)
})
it('should return false when the request domain is specific to an enterprise', () => {
process.env.GITHUB_SERVER_URL = 'https://my-enterprise.github.com'
expect(config.isGhes()).toBe(true)
@@ -200,12 +200,14 @@ describe('download-artifact', () => {
}
)
const response = await downloadArtifactPublic(
fixtures.artifactID,
fixtures.repositoryOwner,
fixtures.repositoryName,
fixtures.token
)
await expect(
downloadArtifactPublic(
fixtures.artifactID,
fixtures.repositoryOwner,
fixtures.repositoryName,
fixtures.token
)
).rejects.toBeInstanceOf(Error)
expect(downloadArtifactMock).toHaveBeenCalledWith({
owner: fixtures.repositoryOwner,
@@ -221,16 +223,6 @@ describe('download-artifact', () => {
expect(mockGetArtifactMalicious).toHaveBeenCalledWith(
fixtures.blobStorageUrl
)
// ensure path traversal was not possible
expect(
fs.existsSync(path.join(fixtures.workspaceDir, 'x/etc/hosts'))
).toBe(true)
expect(
fs.existsSync(path.join(fixtures.workspaceDir, 'y/etc/hosts'))
).toBe(true)
expect(response.downloadPath).toBe(fixtures.workspaceDir)
})
it('should successfully download an artifact to user defined path', async () => {
@@ -8,9 +8,6 @@ import * as blobUpload from '../src/internal/upload/blob-upload'
import {uploadArtifact} from '../src/internal/upload/upload-artifact'
import {noopLogs} from './common'
import {FilesNotFoundError} from '../src/internal/shared/errors'
import {BlockBlobClient} from '@azure/storage-blob'
import * as fs from 'fs'
import * as path from 'path'
describe('upload-artifact', () => {
beforeEach(() => {
@@ -354,94 +351,4 @@ describe('upload-artifact', () => {
expect(uploadResp).rejects.toThrow()
})
it('should throw an error uploading blob chunks get delayed', async () => {
const mockDate = new Date('2020-01-01')
const dirPath = path.join(__dirname, `plz-upload`)
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, {recursive: true})
}
fs.writeFileSync(path.join(dirPath, 'file1.txt'), 'test file content')
fs.writeFileSync(path.join(dirPath, 'file2.txt'), 'test file content')
fs.writeFileSync(path.join(dirPath, 'file3.txt'), 'test file content')
jest
.spyOn(uploadZipSpecification, 'validateRootDirectory')
.mockReturnValue()
jest
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
.mockReturnValue([
{
sourcePath: path.join(dirPath, 'file1.txt'),
destinationPath: 'file1.txt'
},
{
sourcePath: path.join(dirPath, 'file2.txt'),
destinationPath: 'file2.txt'
},
{
sourcePath: path.join(dirPath, 'file3.txt'),
destinationPath: 'dir/file3.txt'
}
])
jest.spyOn(util, 'getBackendIdsFromToken').mockReturnValue({
workflowRunBackendId: '1234',
workflowJobRunBackendId: '5678'
})
jest
.spyOn(retention, 'getExpiration')
.mockReturnValue(Timestamp.fromDate(mockDate))
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
.mockReturnValue(
Promise.resolve({
ok: true,
signedUploadUrl: 'https://signed-upload-url.com'
})
)
jest
.spyOn(blobUpload, 'uploadZipToBlobStorage')
.mockReturnValue(Promise.reject(new Error('Upload progress stalled.')))
// ArtifactHttpClient mocks
jest.spyOn(config, 'getRuntimeToken').mockReturnValue('test-token')
jest
.spyOn(config, 'getResultsServiceUrl')
.mockReturnValue('https://test-url.com')
BlockBlobClient.prototype.uploadStream = jest
.fn()
.mockImplementation(
async (stream, bufferSize, maxConcurrency, options) => {
return new Promise<void>(resolve => {
// Call the onProgress callback with a progress event
options.onProgress({loadedBytes: 0})
// Wait for 31 seconds before resolving the promise
setTimeout(() => {
// Call the onProgress callback again to simulate progress
options.onProgress({loadedBytes: 100})
resolve()
}, 31000) // Delay longer than your timeout
})
}
)
jest.mock('fs')
const uploadResp = uploadArtifact(
'test-artifact',
[
'/home/user/files/plz-upload/file1.txt',
'/home/user/files/plz-upload/file2.txt',
'/home/user/files/plz-upload/dir/file3.txt'
],
'/home/user/files/plz-upload'
)
expect(uploadResp).rejects.toThrow('Upload progress stalled.')
})
})
+354 -133
View File
@@ -1,12 +1,12 @@
{
"name": "@actions/artifact",
"version": "2.1.8",
"version": "2.1.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@actions/artifact",
"version": "2.1.8",
"version": "2.1.4",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.0",
@@ -18,14 +18,15 @@
"@octokit/plugin-retry": "^3.0.9",
"@octokit/request-error": "^5.0.0",
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
"archiver": "^7.0.1",
"archiver": "^5.3.1",
"async": "^3.2.5",
"crypto": "^1.0.1",
"jwt-decode": "^3.1.2",
"twirp-ts": "^2.5.0",
"unzip-stream": "^0.3.1"
"unzip-stream": "^0.3.1",
"zip-stream": "^6.0.1"
},
"devDependencies": {
"@types/archiver": "^5.3.2",
"@types/unzip-stream": "^0.3.4",
"typedoc": "^0.25.4",
"typedoc-plugin-markdown": "^3.17.1",
@@ -443,15 +444,6 @@
"@protobuf-ts/runtime": "^2.9.1"
}
},
"node_modules/@types/archiver": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.2.tgz",
"integrity": "sha512-IctHreBuWE5dvBDz/0WeKtyVKVRs4h75IblxOACL92wU66v+HGAfEYAOyXkOFphvRJMhuXdI9huDXpX0FC6lCw==",
"dev": true,
"dependencies": {
"@types/readdir-glob": "*"
}
},
"node_modules/@types/node": {
"version": "20.4.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.9.tgz",
@@ -479,15 +471,6 @@
"node": ">= 6"
}
},
"node_modules/@types/readdir-glob": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.1.tgz",
"integrity": "sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/tunnel": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz",
@@ -545,108 +528,143 @@
}
},
"node_modules/archiver": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
"integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz",
"integrity": "sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==",
"dependencies": {
"archiver-utils": "^5.0.2",
"async": "^3.2.4",
"buffer-crc32": "^1.0.0",
"readable-stream": "^4.0.0",
"readdir-glob": "^1.1.2",
"tar-stream": "^3.0.0",
"zip-stream": "^6.0.1"
"archiver-utils": "^2.1.0",
"async": "^3.2.3",
"buffer-crc32": "^0.2.1",
"readable-stream": "^3.6.0",
"readdir-glob": "^1.0.0",
"tar-stream": "^2.2.0",
"zip-stream": "^4.1.0"
},
"engines": {
"node": ">= 14"
"node": ">= 10"
}
},
"node_modules/archiver-utils": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
"integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz",
"integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
"dependencies": {
"glob": "^10.0.0",
"glob": "^7.1.4",
"graceful-fs": "^4.2.0",
"is-stream": "^2.0.1",
"lazystream": "^1.0.0",
"lodash": "^4.17.15",
"lodash.defaults": "^4.2.0",
"lodash.difference": "^4.5.0",
"lodash.flatten": "^4.4.0",
"lodash.isplainobject": "^4.0.6",
"lodash.union": "^4.6.0",
"normalize-path": "^3.0.0",
"readable-stream": "^4.0.0"
"readable-stream": "^2.0.0"
},
"engines": {
"node": ">= 14"
"node": ">= 6"
}
},
"node_modules/archiver-utils/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"node_modules/archiver-utils/node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dependencies": {
"balanced-match": "^1.0.0"
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/archiver-utils/node_modules/glob": {
"version": "10.3.12",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz",
"integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==",
"node_modules/archiver-utils/node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/archiver-utils/node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^2.3.6",
"minimatch": "^9.0.1",
"minipass": "^7.0.4",
"path-scurry": "^1.10.2"
},
"bin": {
"glob": "dist/esm/bin.mjs"
"safe-buffer": "~5.1.0"
}
},
"node_modules/archiver/node_modules/compress-commons": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz",
"integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==",
"dependencies": {
"buffer-crc32": "^0.2.13",
"crc32-stream": "^4.0.2",
"normalize-path": "^3.0.0",
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
"node": ">= 10"
}
},
"node_modules/archiver-utils/node_modules/minimatch": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
"node_modules/archiver/node_modules/crc32-stream": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz",
"integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==",
"dependencies": {
"brace-expansion": "^2.0.1"
"crc-32": "^1.2.0",
"readable-stream": "^3.4.0"
},
"engines": {
"node": ">=16 || 14 >=14.17"
"node": ">= 10"
}
},
"node_modules/archiver/node_modules/zip-stream": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz",
"integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==",
"dependencies": {
"archiver-utils": "^3.0.4",
"compress-commons": "^4.1.2",
"readable-stream": "^3.6.0"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
"engines": {
"node": ">= 10"
}
},
"node_modules/archiver/node_modules/zip-stream/node_modules/archiver-utils": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz",
"integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==",
"dependencies": {
"glob": "^7.2.3",
"graceful-fs": "^4.2.0",
"lazystream": "^1.0.0",
"lodash.defaults": "^4.2.0",
"lodash.difference": "^4.5.0",
"lodash.flatten": "^4.4.0",
"lodash.isplainobject": "^4.0.6",
"lodash.union": "^4.6.0",
"normalize-path": "^3.0.0",
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">= 10"
}
},
"node_modules/async": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
"integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/b4a": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz",
"integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg=="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/bare-events": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz",
"integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==",
"optional": true
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -683,6 +701,16 @@
"node": "*"
}
},
"node_modules/bl": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"dependencies": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/bottleneck": {
"version": "2.19.5",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
@@ -698,9 +726,9 @@
}
},
"node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"funding": [
{
"type": "github",
@@ -717,15 +745,15 @@
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
"ieee754": "^1.1.13"
}
},
"node_modules/buffer-crc32": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz",
"integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==",
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
"engines": {
"node": ">=8.0.0"
"node": "*"
}
},
"node_modules/buffers": {
@@ -806,6 +834,44 @@
"node": ">= 14"
}
},
"node_modules/compress-commons/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/compress-commons/node_modules/readable-stream": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
"integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -839,6 +905,44 @@
"node": ">= 14"
}
},
"node_modules/crc32-stream/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/crc32-stream/node_modules/readable-stream": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
"integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -893,6 +997,14 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
"node_modules/end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dependencies": {
"once": "^1.4.0"
}
},
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
@@ -909,11 +1021,6 @@
"node": ">=0.8.x"
}
},
"node_modules/fast-fifo": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="
},
"node_modules/foreground-child": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@@ -942,6 +1049,11 @@
"node": ">= 6"
}
},
"node_modules/fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -1133,6 +1245,31 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
},
"node_modules/lodash.difference": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
"integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA=="
},
"node_modules/lodash.flatten": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
"integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
},
"node_modules/lodash.union": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
"integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw=="
},
"node_modules/lower-case": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
@@ -1346,24 +1483,17 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/queue-tick": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag=="
},
"node_modules/readable-stream": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
"integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
"node": ">= 6"
}
},
"node_modules/readdir-glob": {
@@ -1468,18 +1598,6 @@
"node": ">=0.10.0"
}
},
"node_modules/streamx": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz",
"integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==",
"dependencies": {
"fast-fifo": "^1.1.0",
"queue-tick": "^1.0.1"
},
"optionalDependencies": {
"bare-events": "^2.2.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -1577,13 +1695,18 @@
}
},
"node_modules/tar-stream": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
"integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"dependencies": {
"b4a": "^1.6.4",
"fast-fifo": "^1.2.0",
"streamx": "^2.15.0"
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
},
"engines": {
"node": ">=6"
}
},
"node_modules/tr46": {
@@ -1738,9 +1861,9 @@
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"node_modules/unzip-stream": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.4.tgz",
"integrity": "sha512-PyofABPVv+d7fL7GOpusx7eRT9YETY2X04PhwbSipdj6bMxVCFJrr+nm0Mxqbf9hUiTin/UsnuFWBXlDZFy0Cw==",
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.1.tgz",
"integrity": "sha512-RzaGXLNt+CW+T41h1zl6pGz3EaeVhYlK+rdAap+7DxW5kqsqePO8kRtWPaCiVqdhZc86EctSPVYNix30YOMzmw==",
"dependencies": {
"binary": "^0.3.0",
"mkdirp": "^0.5.1"
@@ -1934,6 +2057,104 @@
"engines": {
"node": ">= 14"
}
},
"node_modules/zip-stream/node_modules/archiver-utils": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
"integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
"dependencies": {
"glob": "^10.0.0",
"graceful-fs": "^4.2.0",
"is-stream": "^2.0.1",
"lazystream": "^1.0.0",
"lodash": "^4.17.15",
"normalize-path": "^3.0.0",
"readable-stream": "^4.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/zip-stream/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/zip-stream/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/zip-stream/node_modules/glob": {
"version": "10.3.10",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
"integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^2.3.5",
"minimatch": "^9.0.1",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
"path-scurry": "^1.10.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/zip-stream/node_modules/minimatch": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/zip-stream/node_modules/readable-stream": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
"integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
}
}
}
+5 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/artifact",
"version": "2.1.8",
"version": "2.1.4",
"preview": true,
"description": "Actions artifact lib",
"keywords": [
@@ -49,14 +49,15 @@
"@octokit/plugin-retry": "^3.0.9",
"@octokit/request-error": "^5.0.0",
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
"archiver": "^7.0.1",
"archiver": "^5.3.1",
"async": "^3.2.5",
"crypto": "^1.0.1",
"jwt-decode": "^3.1.2",
"twirp-ts": "^2.5.0",
"unzip-stream": "^0.3.1"
"unzip-stream": "^0.3.1",
"zip-stream": "^6.0.1"
},
"devDependencies": {
"@types/archiver": "^5.3.2",
"@types/unzip-stream": "^0.3.4",
"typedoc": "^0.25.4",
"typedoc-plugin-markdown": "^3.17.1",
@@ -1,4 +1,7 @@
import fs from 'fs/promises'
import * as stream from 'stream'
import {createWriteStream} from 'fs'
import * as path from 'path'
import * as github from '@actions/github'
import * as core from '@actions/core'
import * as httpClient from '@actions/http-client'
@@ -44,6 +47,11 @@ async function streamExtract(url: string, directory: string): Promise<void> {
await streamExtractExternal(url, directory)
return
} catch (error) {
if (error.message.includes('Malformed extraction path')) {
throw new Error(
`Artifact download failed with unretryable error: ${error.message}`
)
}
retryCount++
core.debug(
`Failed to download artifact after ${retryCount} retries due to ${error.message}. Retrying in 5 seconds...`
@@ -78,6 +86,8 @@ export async function streamExtractExternal(
}
const timer = setTimeout(timerFn, timeout)
const createdDirectories = new Set<string>()
createdDirectories.add(directory)
response.message
.on('data', () => {
timer.refresh()
@@ -89,8 +99,46 @@ export async function streamExtractExternal(
clearTimeout(timer)
reject(error)
})
.pipe(unzip.Extract({path: directory}))
.on('close', () => {
.pipe(unzip.Parse())
.pipe(
new stream.Transform({
objectMode: true,
transform: async (entry, _, callback) => {
const fullPath = path.normalize(path.join(directory, entry.path))
if (!directory.endsWith(path.sep)) {
directory += path.sep
}
if (!fullPath.startsWith(directory)) {
reject(new Error(`Malformed extraction path: ${fullPath}`))
}
if (entry.type === 'Directory') {
if (!createdDirectories.has(fullPath)) {
createdDirectories.add(fullPath)
await resolveOrCreateDirectory(fullPath).then(() => {
entry.autodrain()
callback()
})
} else {
entry.autodrain()
callback()
}
} else {
core.info(`Extracting artifact entry: ${fullPath}`)
if (!createdDirectories.has(path.dirname(fullPath))) {
createdDirectories.add(path.dirname(fullPath))
await resolveOrCreateDirectory(path.dirname(fullPath))
}
const writeStream = createWriteStream(fullPath)
writeStream.on('finish', callback)
writeStream.on('error', reject)
entry.pipe(writeStream)
}
}
})
)
.on('finish', async () => {
clearTimeout(timer)
resolve()
})
@@ -102,6 +102,7 @@ class ArtifactHttpClient implements Rpc {
} catch (error) {
if (error instanceof SyntaxError) {
debug(`Raw Body: ${rawBody}`)
throw error
}
if (error instanceof UsageError) {
@@ -30,10 +30,10 @@ export function isGhes(): boolean {
const hostname = ghUrl.hostname.trimEnd().toUpperCase()
const isGitHubHost = hostname === 'GITHUB.COM'
const isGheHost = hostname.endsWith('.GHE.COM')
const isLocalHost = hostname.endsWith('.LOCALHOST')
const isGheHost =
hostname.endsWith('.GHE.COM') || hostname.endsWith('.GHE.LOCALHOST')
return !isGitHubHost && !isGheHost && !isLocalHost
return !isGitHubHost && !isGheHost
}
export function getGitHubWorkspaceDir(): string {
@@ -24,30 +24,11 @@ export async function uploadZipToBlobStorage(
zipUploadStream: ZipUploadStream
): Promise<BlobUploadResponse> {
let uploadByteCount = 0
let lastProgressTime = Date.now()
let timeoutId: NodeJS.Timeout | undefined
const chunkTimer = (timeout: number): NodeJS.Timeout => {
// clear the previous timeout
if (timeoutId) {
clearTimeout(timeoutId)
}
timeoutId = setTimeout(() => {
const now = Date.now()
// if there's been more than 30 seconds since the
// last progress event, then we'll consider the upload stalled
if (now - lastProgressTime > timeout) {
throw new Error('Upload progress stalled.')
}
}, timeout)
return timeoutId
}
const maxConcurrency = getConcurrency()
const bufferSize = getUploadChunkSize()
const blobClient = new BlobClient(authenticatedUploadURL)
const blockBlobClient = blobClient.getBlockBlobClient()
const timeoutDuration = 300000 // 30 seconds
core.debug(
`Uploading artifact zip to blob storage with maxConcurrency: ${maxConcurrency}, bufferSize: ${bufferSize}`
@@ -56,8 +37,6 @@ export async function uploadZipToBlobStorage(
const uploadCallback = (progress: TransferProgressEvent): void => {
core.info(`Uploaded bytes ${progress.loadedBytes}`)
uploadByteCount = progress.loadedBytes
chunkTimer(timeoutDuration)
lastProgressTime = Date.now()
}
const options: BlockBlobUploadStreamOptions = {
@@ -75,8 +54,6 @@ export async function uploadZipToBlobStorage(
core.info('Beginning upload of artifact content to blob storage')
try {
// Start the chunk timer
timeoutId = chunkTimer(timeoutDuration)
await blockBlobClient.uploadStream(
uploadStream,
bufferSize,
@@ -87,12 +64,8 @@ export async function uploadZipToBlobStorage(
if (NetworkError.isNetworkErrorCode(error?.code)) {
throw new NetworkError(error?.code)
}
throw error
} finally {
// clear the timeout whether or not the upload completes
if (timeoutId) {
clearTimeout(timeoutId)
}
}
core.info('Finished uploading artifact content to blob storage!')
@@ -106,6 +79,7 @@ export async function uploadZipToBlobStorage(
`No data was uploaded to blob storage. Reported upload byte count is 0.`
)
}
return {
uploadSize: uploadByteCount,
sha256Hash
@@ -67,18 +67,25 @@ export async function uploadArtifact(
'CreateArtifact: response from backend was not ok'
)
}
// Create the zipupload stream for use in blob upload
const zipUploadStream = await createZipUploadStream(
zipSpecification,
options?.compressionLevel
)
).catch(err => {
throw new InvalidResponseError(
`createZipUploadStream: response from backend was not ok: ${err}`
)
})
// Upload zip to blob storage
const uploadResult = await uploadZipToBlobStorage(
createArtifactResp.signedUploadUrl,
zipUploadStream
)
).catch(err => {
throw new InvalidResponseError(
`uploadZipToBlobStorage: response blob was not ok: ${err}`
)
})
// finalize the artifact
const finalizeArtifactReq: FinalizeArtifactRequest = {
workflowRunBackendId: backendIds.workflowRunBackendId,
@@ -86,15 +93,12 @@ export async function uploadArtifact(
name,
size: uploadResult.uploadSize ? uploadResult.uploadSize.toString() : '0'
}
if (uploadResult.sha256Hash) {
finalizeArtifactReq.hash = StringValue.create({
value: `sha256:${uploadResult.sha256Hash}`
})
}
core.info(`Finalizing artifact upload`)
const finalizeArtifactResp =
await artifactClient.FinalizeArtifact(finalizeArtifactReq)
if (!finalizeArtifactResp.ok) {
+34 -18
View File
@@ -1,6 +1,7 @@
import * as stream from 'stream'
import * as archiver from 'archiver'
import * as ZipStream from 'zip-stream'
import * as core from '@actions/core'
import async from 'async'
import {createReadStream} from 'fs'
import {UploadZipSpecification} from './upload-zip-specification'
import {getUploadChunkSize} from '../shared/config'
@@ -30,31 +31,50 @@ export async function createZipUploadStream(
`Creating Artifact archive with compressionLevel: ${compressionLevel}`
)
const zip = archiver.create('zip', {
highWaterMark: getUploadChunkSize(),
zlib: {level: compressionLevel}
})
const zlibOptions = {
zlib: {
level: compressionLevel,
bufferSize: getUploadChunkSize()
}
}
const zip = new ZipStream.default(zlibOptions)
const bufferSize = getUploadChunkSize()
const zipUploadStream = new ZipUploadStream(bufferSize)
zip.pipe(zipUploadStream)
// register callbacks for various events during the zip lifecycle
zip.on('error', zipErrorCallback)
zip.on('warning', zipWarningCallback)
zip.on('finish', zipFinishCallback)
zip.on('end', zipEndCallback)
for (const file of uploadSpecification) {
const addFileToZip = (file: UploadZipSpecification, callback: (error?: Error) => void) => {
if (file.sourcePath !== null) {
// Add a normal file to the zip
zip.append(createReadStream(file.sourcePath), {
name: file.destinationPath
zip.entry(createReadStream(file.sourcePath), { name: file.destinationPath }, (error: any) => {
if (error) {
callback(error)
return
}
callback()
})
} else {
// Add a directory to the zip
zip.append('', {name: file.destinationPath})
zip.entry('', { name: file.destinationPath }, (error: any) => {
if (error) {
callback(error)
return
}
callback()
})
}
}
const bufferSize = getUploadChunkSize()
const zipUploadStream = new ZipUploadStream(bufferSize)
async.eachSeries(uploadSpecification, addFileToZip, (error: any) => {
if (error) {
core.error('Failed to add a file to the zip:')
core.info(error)
return
}
zip.finalize() // Finalize the archive once all files have been added
})
core.debug(
`Zip write high watermark value ${zipUploadStream.writableHighWaterMark}`
@@ -63,9 +83,6 @@ export async function createZipUploadStream(
`Zip read high watermark value ${zipUploadStream.readableHighWaterMark}`
)
zip.pipe(zipUploadStream)
zip.finalize()
return zipUploadStream
}
@@ -76,7 +93,6 @@ const zipErrorCallback = (error: any): void => {
throw new Error('An error has occurred during zip creation for the artifact')
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const zipWarningCallback = (error: any): void => {
if (error.code === 'ENOENT') {
-3
View File
@@ -12,9 +12,6 @@ Once the attestation has been created and signed, it will be uploaded to the GH
attestations API and associated with the repository from which the workflow was
initiated.
See [Using artifact attestations to establish provenance for builds](https://docs.github.com/en/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)
for more information on artifact attestations.
## Usage
### `attest`
-13
View File
@@ -1,23 +1,10 @@
# @actions/attest Releases
### 1.3.0
- Dynamic construction of Sigstore API URLs
- Switch to new GH provenance build type
- Fetch existing Rekor entry on 409 conflict error
- Bump @sigstore/bundle from 2.3.0 to 2.3.2
- Bump @sigstore/sign from 2.3.0 to 2.3.2
### 1.2.1
- Retry request on attestation persistence failure
### 1.2.0
- Generate attestations using the v0.3 Sigstore bundle format.
- Bump @sigstore/bundle from 2.2.0 to 2.3.0.
- Bump @sigstore/sign from 2.2.3 to 2.3.0.
- Remove dependency on make-fetch-happen
### 1.1.0
@@ -4,7 +4,7 @@ exports[`provenance functions buildSLSAProvenancePredicate returns a provenance
{
"params": {
"buildDefinition": {
"buildType": "https://actions.github.io/buildtypes/workflow/v1",
"buildType": "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1",
"externalParameters": {
"workflow": {
"path": ".github/workflows/main.yml",
@@ -17,7 +17,6 @@ exports[`provenance functions buildSLSAProvenancePredicate returns a provenance
"event_name": "push",
"repository_id": "repo-id",
"repository_owner_id": "owner-id",
"runner_environment": "github-hosted",
},
},
"resolvedDependencies": [
@@ -31,7 +30,7 @@ exports[`provenance functions buildSLSAProvenancePredicate returns a provenance
},
"runDetails": {
"builder": {
"id": "https://github.com/owner/workflows/.github/workflows/publish.yml@main",
"id": "https://github.com/actions/runner/github-hosted",
},
"metadata": {
"invocationId": "https://github.com/owner/repo/actions/runs/run-id/attempts/run-attempt",
@@ -1,41 +0,0 @@
import {signingEndpoints} from '../src/endpoints'
describe('signingEndpoints', () => {
const originalEnv = process.env
afterEach(() => {
process.env = originalEnv
})
describe('when using github.com', () => {
beforeEach(async () => {
process.env = {
...originalEnv,
GITHUB_SERVER_URL: 'https://github.com'
}
})
it('returns expected endpoints', async () => {
const endpoints = signingEndpoints('github')
expect(endpoints.fulcioURL).toEqual('https://fulcio.githubapp.com')
expect(endpoints.tsaServerURL).toEqual('https://timestamp.githubapp.com')
})
})
describe('when using custom domain', () => {
beforeEach(async () => {
process.env = {
...originalEnv,
GITHUB_SERVER_URL: 'https://foo.bar.com'
}
})
it('returns a expected endpoints', async () => {
const endpoints = signingEndpoints('github')
expect(endpoints.fulcioURL).toEqual('https://fulcio.foo.bar.com')
expect(endpoints.tsaServerURL).toEqual('https://timestamp.foo.bar.com')
})
})
})
+1 -2
View File
@@ -45,8 +45,7 @@ describe('getIDTokenClaims', () => {
sha: 'sha',
repository: 'repo',
event_name: 'push',
job_workflow_ref: 'job_workflow_ref',
workflow_ref: 'workflow',
workflow_ref: 'main',
repository_id: '1',
repository_owner_id: '1',
runner_environment: 'github-hosted',
+7 -20
View File
@@ -2,8 +2,7 @@ import * as github from '@actions/github'
import {mockFulcio, mockRekor, mockTSA} from '@sigstore/mock'
import * as jose from 'jose'
import nock from 'nock'
import {MockAgent, setGlobalDispatcher} from 'undici'
import {SIGSTORE_PUBLIC_GOOD, signingEndpoints} from '../src/endpoints'
import {SIGSTORE_GITHUB, SIGSTORE_PUBLIC_GOOD} from '../src/endpoints'
import {attestProvenance, buildSLSAProvenancePredicate} from '../src/provenance'
describe('provenance functions', () => {
@@ -13,17 +12,12 @@ describe('provenance functions', () => {
const jwksPath = '/.well-known/jwks.json'
const tokenPath = '/token'
// MockAgent for mocking @actions/github
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)
const claims = {
iss: issuer,
aud: 'nobody',
repository: 'owner/repo',
ref: 'refs/heads/main',
sha: 'babca52ab0c93ae16539e5923cb0d7403b9a093b',
job_workflow_ref: 'owner/workflows/.github/workflows/publish.yml@main',
workflow_ref: 'owner/repo/.github/workflows/main.yml@main',
event_name: 'push',
repository_id: 'repo-id',
@@ -96,19 +90,16 @@ describe('provenance functions', () => {
})
describe('when using the github Sigstore instance', () => {
const {fulcioURL, tsaServerURL} = signingEndpoints('github')
const {fulcioURL, tsaServerURL} = SIGSTORE_GITHUB
beforeEach(async () => {
// Mock Sigstore
await mockFulcio({baseURL: fulcioURL, strict: false})
await mockTSA({baseURL: tsaServerURL})
mockAgent
.get('https://api.github.com')
.intercept({
path: /^\/repos\/.*\/.*\/attestations$/,
method: 'post'
})
// Mock GH attestations API
nock('https://api.github.com')
.post(/^\/repos\/.*\/.*\/attestations$/)
.reply(201, {id: attestationID})
})
@@ -168,12 +159,8 @@ describe('provenance functions', () => {
await mockRekor({baseURL: rekorURL})
// Mock GH attestations API
mockAgent
.get('https://api.github.com')
.intercept({
path: /^\/repos\/.*\/.*\/attestations$/,
method: 'post'
})
nock('https://api.github.com')
.post(/^\/repos\/.*\/.*\/attestations$/)
.reply(201, {id: attestationID})
})
+8 -53
View File
@@ -1,4 +1,4 @@
import {MockAgent, setGlobalDispatcher} from 'undici'
import nock from 'nock'
import {writeAttestation} from '../src/store'
describe('writeAttestation', () => {
@@ -6,9 +6,6 @@ describe('writeAttestation', () => {
const attestation = {foo: 'bar '}
const token = 'token'
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)
beforeEach(() => {
process.env = {
...originalEnv,
@@ -22,14 +19,9 @@ describe('writeAttestation', () => {
describe('when the api call is successful', () => {
beforeEach(() => {
mockAgent
.get('https://api.github.com')
.intercept({
path: '/repos/foo/bar/attestations',
method: 'POST',
headers: {authorization: `token ${token}`},
body: JSON.stringify({bundle: attestation})
})
nock('https://api.github.com')
.matchHeader('authorization', `token ${token}`)
.post('/repos/foo/bar/attestations', {bundle: attestation})
.reply(201, {id: '123'})
})
@@ -40,51 +32,14 @@ describe('writeAttestation', () => {
describe('when the api call fails', () => {
beforeEach(() => {
mockAgent
.get('https://api.github.com')
.intercept({
path: '/repos/foo/bar/attestations',
method: 'POST',
headers: {authorization: `token ${token}`},
body: JSON.stringify({bundle: attestation})
})
nock('https://api.github.com')
.matchHeader('authorization', `token ${token}`)
.post('/repos/foo/bar/attestations', {bundle: attestation})
.reply(500, 'oops')
})
it('throws an error', async () => {
await expect(
writeAttestation(attestation, token, {retry: 0})
).rejects.toThrow(/oops/)
})
})
describe('when the api call fails but succeeds on retry', () => {
beforeEach(() => {
const pool = mockAgent.get('https://api.github.com')
pool
.intercept({
path: '/repos/foo/bar/attestations',
method: 'POST',
headers: {authorization: `token ${token}`},
body: JSON.stringify({bundle: attestation})
})
.reply(500, 'oops')
.times(1)
pool
.intercept({
path: '/repos/foo/bar/attestations',
method: 'POST',
headers: {authorization: `token ${token}`},
body: JSON.stringify({bundle: attestation})
})
.reply(201, {id: '123'})
.times(1)
})
it('persists the attestation', async () => {
await expect(writeAttestation(attestation, token)).resolves.toEqual('123')
await expect(writeAttestation(attestation, token)).rejects.toThrow(/oops/)
})
})
})
+430 -444
View File
File diff suppressed because it is too large Load Diff
+8 -13
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/attest",
"version": "1.3.0",
"version": "1.2.0",
"description": "Actions attestation lib",
"keywords": [
"github",
@@ -35,26 +35,21 @@
"url": "https://github.com/actions/toolkit/issues"
},
"devDependencies": {
"@sigstore/mock": "^0.7.4",
"@sigstore/mock": "^0.6.5",
"@sigstore/rekor-types": "^2.0.0",
"@types/jsonwebtoken": "^9.0.6",
"@types/make-fetch-happen": "^10.0.4",
"jose": "^5.2.3",
"nock": "^13.5.1",
"undici": "^5.28.4"
"nock": "^13.5.1"
},
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"@actions/http-client": "^2.2.1",
"@octokit/plugin-retry": "^6.0.1",
"@sigstore/bundle": "^2.3.2",
"@sigstore/sign": "^2.3.2",
"@sigstore/bundle": "^2.3.0",
"@sigstore/sign": "^2.3.0",
"jsonwebtoken": "^9.0.2",
"jwks-rsa": "^3.1.0"
},
"overrides": {
"@octokit/plugin-retry": {
"@octokit/core": "^5.2.0"
}
"jwks-rsa": "^3.1.0",
"make-fetch-happen": "^13.0.0"
}
}
+9 -14
View File
@@ -6,6 +6,9 @@ const GITHUB_ID = 'github'
const FULCIO_PUBLIC_GOOD_URL = 'https://fulcio.sigstore.dev'
const REKOR_PUBLIC_GOOD_URL = 'https://rekor.sigstore.dev'
const FULCIO_INTERNAL_URL = 'https://fulcio.githubapp.com'
const TSA_INTERNAL_URL = 'https://timestamp.githubapp.com'
export type SigstoreInstance = typeof PUBLIC_GOOD_ID | typeof GITHUB_ID
export type Endpoints = {
@@ -19,6 +22,11 @@ export const SIGSTORE_PUBLIC_GOOD: Endpoints = {
rekorURL: REKOR_PUBLIC_GOOD_URL
}
export const SIGSTORE_GITHUB: Endpoints = {
fulcioURL: FULCIO_INTERNAL_URL,
tsaServerURL: TSA_INTERNAL_URL
}
export const signingEndpoints = (sigstore?: SigstoreInstance): Endpoints => {
let instance: SigstoreInstance
@@ -37,19 +45,6 @@ export const signingEndpoints = (sigstore?: SigstoreInstance): Endpoints => {
case PUBLIC_GOOD_ID:
return SIGSTORE_PUBLIC_GOOD
case GITHUB_ID:
return buildGitHubEndpoints()
}
}
function buildGitHubEndpoints(): Endpoints {
const serverURL = process.env.GITHUB_SERVER_URL || 'https://github.com'
let host = new URL(serverURL).hostname
if (host === 'github.com') {
host = 'githubapp.com'
}
return {
fulcioURL: `https://fulcio.${host}`,
tsaServerURL: `https://timestamp.${host}`
return SIGSTORE_GITHUB
}
}
-1
View File
@@ -11,7 +11,6 @@ const REQUIRED_CLAIMS = [
'sha',
'repository',
'event_name',
'job_workflow_ref',
'workflow_ref',
'repository_id',
'repository_owner_id',
+6 -4
View File
@@ -3,7 +3,10 @@ import {getIDTokenClaims} from './oidc'
import type {Attestation, Predicate} from './shared.types'
const SLSA_PREDICATE_V1_TYPE = 'https://slsa.dev/provenance/v1'
const GITHUB_BUILD_TYPE = 'https://actions.github.io/buildtypes/workflow/v1'
const GITHUB_BUILDER_ID_PREFIX = 'https://github.com/actions/runner'
const GITHUB_BUILD_TYPE =
'https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1'
const DEFAULT_ISSUER = 'https://token.actions.githubusercontent.com'
@@ -52,8 +55,7 @@ export const buildSLSAProvenancePredicate = async (
github: {
event_name: claims.event_name,
repository_id: claims.repository_id,
repository_owner_id: claims.repository_owner_id,
runner_environment: claims.runner_environment
repository_owner_id: claims.repository_owner_id
}
},
resolvedDependencies: [
@@ -67,7 +69,7 @@ export const buildSLSAProvenancePredicate = async (
},
runDetails: {
builder: {
id: `${serverURL}/${claims.job_workflow_ref}`
id: `${GITHUB_BUILDER_ID_PREFIX}/${claims.runner_environment}`
},
metadata: {
invocationId: `${serverURL}/${claims.repository}/actions/runs/${claims.run_id}/attempts/${claims.run_attempt}`
-1
View File
@@ -87,7 +87,6 @@ const initBundleBuilder = (opts: SignOptions): BundleBuilder => {
new RekorWitness({
rekorBaseURL: opts.rekorURL,
entryType: 'dsse',
fetchOnConflict: true,
timeout,
retry
})
+4 -14
View File
@@ -1,12 +1,8 @@
import * as github from '@actions/github'
import {retry} from '@octokit/plugin-retry'
import fetch from 'make-fetch-happen'
const CREATE_ATTESTATION_REQUEST = 'POST /repos/{owner}/{repo}/attestations'
const DEFAULT_RETRY_COUNT = 5
export type WriteOptions = {
retry?: number
}
/**
* Writes an attestation to the repository's attestations endpoint.
* @param attestation - The attestation to write.
@@ -16,11 +12,9 @@ export type WriteOptions = {
*/
export const writeAttestation = async (
attestation: unknown,
token: string,
options: WriteOptions = {}
token: string
): Promise<string> => {
const retries = options.retry ?? DEFAULT_RETRY_COUNT
const octokit = github.getOctokit(token, {retry: {retries}}, retry)
const octokit = github.getOctokit(token, {request: {fetch}})
try {
const response = await octokit.request(CREATE_ATTESTATION_REQUEST, {
@@ -29,11 +23,7 @@ export const writeAttestation = async (
data: {bundle: attestation}
})
const data =
typeof response.data == 'string'
? JSON.parse(response.data)
: response.data
return data?.id
return response.data?.id
} catch (err) {
const message = err instanceof Error ? err.message : err
throw new Error(`Failed to persist attestation: ${message}`)