Compare commits

...

35 Commits

Author SHA1 Message Date
Rob Herley 799f8f5f3d Update artifact release notes
Includes:
- #1815
2024-10-08 14:06:04 -04:00
Rob Herley 201b082ce1 Merge pull request #1844 from actions/robherley/artifact-2.1.11
Properly resolve relative symlinks
2024-10-08 13:08:45 -04:00
Rob Herley 49cbbbcd99 Update symlink bug fix reference number 2024-10-08 13:02:06 -04:00
Rob Herley 545e0e6b95 properly resolve relative symlinks 2024-10-08 12:35:48 -04:00
JoannaaKL c18a7d2f73 Merge pull request #1815 from mydea/fn/remove-crypto
Use native `crypto` package from node
2024-10-07 11:06:38 +02:00
Josh Gross d14afd7973 Explicitly import crypto (#1842)
* Explicitly import `crypto`

* Add release notes for 1.11.1

* Fix crypto mock in test

* Fix `crypto` mock

* Lint
2024-10-04 17:23:42 -04:00
Josh Gross 22a72ac3d7 Include #1551 in @actions/core 1.11.0 release notes (#1840) 2024-10-02 14:30:25 -04:00
Josh Gross 6ca0d9b637 Release @actions/core v1.11.0 (#1839) 2024-10-02 13:49:03 -04:00
Rob Herley 650f7c6aa3 Merge pull request #1830 from actions/robherley/artifact-2.1.10
Fix regression, auto readlink on symlinks again
2024-10-02 13:06:15 -04:00
Josh Gross 78af634e7e Remove dependency on uuid package (#1824) 2024-10-02 12:28:06 -04:00
Rob Herley 2a8f1c5ddd bump package lock version 2024-10-01 16:43:30 -04:00
Rob Herley 5a62022195 / 2024-09-20 17:52:14 -04:00
Rob Herley 8551843690 fix assertion 2024-09-20 17:45:55 -04:00
Rob Herley d6694e491d update release notes 2024-09-20 17:31:40 -04:00
Rob Herley 7f19a7886a fix regression, auto readlink on symlinks again 2024-09-20 17:23:43 -04:00
Brian DeHamer 6dd369c0e6 Merge pull request #1823 from actions/bdehamer/enterprise-issuer
[@actions/attest] Fix bug with customized OIDC issuer
2024-09-05 09:17:37 -07:00
Brian DeHamer 2a07de1333 fix bug with customized oidc issuer
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-09-04 10:24:28 -07:00
Francesco Novy 2e1998fc42 update lockfile 2024-08-30 09:41:33 +02:00
Francesco Novy b7a914b73b Use native crypto package from node 2024-08-30 09:30:02 +02:00
Brian DeHamer 6c4e082c18 Merge pull request #1805 from actions/bdehamer/update-http-client
bump @actions/http-client from 2.2.1 to 2.2.3
2024-08-22 08:39:26 -07:00
Brian DeHamer 1e69bffbba bump @actions/http-client from 2.2.1 to 2.2.3
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-08-22 07:52:03 -07:00
Thomas Boop d1aa255c7f HTTP Client 2.2.3 Release (#1804)
* http-client 2.2.3

* fix audit

* Revert "fix audit"

724956ffa7

* update versions

* Revert "update versions"

139b3391a0

* exclude dev dependencies while we work on removing lerna
2024-08-22 10:13:36 -04:00
Brian DeHamer 7298ff3219 Merge pull request #1799 from actions/bdehamer/http-client-proxy-auth
fix encoding for proxy auth token
2024-08-21 06:41:49 -07:00
Brian DeHamer 571d782946 Merge pull request #1797 from actions/bdehamer/attester-release-notes
improve release notes for @actions/attest
2024-08-19 07:38:36 -07:00
Brian DeHamer ada9e00cda fix encoding for proxy auth token
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-08-16 15:03:40 -07:00
Josh Gross faf9cb2ea2 Include the package name in the Publish Workflow run (#1793) 2024-08-16 16:15:14 -04:00
Brian DeHamer ac3a063583 improve release notes for @actions/attest
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-08-16 12:43:39 -07:00
Brian DeHamer 7cc96bb976 Merge pull request #1796 from actions/bdehamer/attest-issuer
derive default OIDC issuer from current tenant
2024-08-16 12:21:00 -07:00
Brian DeHamer fa6cc53297 derive default OIDC issuer from current tenant
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-08-16 12:07:23 -07:00
Thomas Boop f299e8ba1e HTTP Client 2.2.2 Release (#1794)
* 2.2.2 release

* update nodes
2024-08-16 13:11:10 -04:00
Yu 1b9927d1c7 Handle Encoded URL for Proxy Username and Password in HTTP Client (#1782)
* uri-decode-fix

Signed-off-by: Yu <yu.yang@anz.com>

* http-client URLdecode fix

Signed-off-by: Yu <yu.yang@anz.com>

* http-client URLdecode test typo fix

Signed-off-by: Yu <yu.yang@anz.com>

---------

Signed-off-by: Yu <yu.yang@anz.com>
2024-08-16 12:43:10 -04:00
Brian DeHamer 279e891118 Merge pull request #1790 from actions/bdehamer/attest-headers
support for headers param in attest functions
2024-08-16 07:21:46 -07:00
Brian DeHamer 340a1033a5 support for headers param in attest functions
Signed-off-by: Brian DeHamer <bdehamer@github.com>
2024-08-15 15:35:32 -07:00
Josh Gross 50f2977cce Add glob option to ignore hidden files (#1791)
* Add glob option to ignore hidden files

* Use the basename of the file/directory to check for `.`

* Ensure the `excludeHiddenFiles` is properly copied

* Allow the root directory to be matched

* Fix description of `excludeHiddenFiles`

* Document Windows hidden attribute limitation

* Bump version

* `lint`

* Document 0.5.0 release

* Lint again
2024-08-15 17:13:49 -04:00
Thomas Boop 48a65377c0 Fix HTTP client tests (#1792)
* fix tests and update dependencies
2024-08-15 16:53:06 -04:00
48 changed files with 521 additions and 300 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
run: npm run bootstrap
- name: audit tools (without allow-list)
run: npm audit --audit-level=moderate
run: npm audit --audit-level=moderate --omit dev
- name: audit packages
run: npm run audit-all
+2
View File
@@ -1,5 +1,7 @@
name: Publish NPM
run-name: Publish NPM - ${{ github.event.inputs.package }}
on:
workflow_dispatch:
inputs:
+5 -4
View File
@@ -4925,12 +4925,13 @@
}
},
"node_modules/axios": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz",
"integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==",
"dev": true,
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.0",
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
+10
View File
@@ -1,5 +1,15 @@
# @actions/artifact Releases
### 2.1.11
- Fixed a bug with relative symlinks resolution [#1844](https://github.com/actions/toolkit/pull/1844)
- Use native `crypto` [#1815](https://github.com/actions/toolkit/pull/1815)
### 2.1.10
- Fixed a regression with symlinks not being automatically resolved [#1830](https://github.com/actions/toolkit/pull/1830)
- Fixed a regression with chunk timeout [#1786](https://github.com/actions/toolkit/pull/1786)
### 2.1.9
- Fixed artifact upload chunk timeout logic [#1774](https://github.com/actions/toolkit/pull/1774)
@@ -10,6 +10,7 @@ import {FilesNotFoundError} from '../src/internal/shared/errors'
import {BlockBlobUploadStreamOptions} from '@azure/storage-blob'
import * as fs from 'fs'
import * as path from 'path'
import unzip from 'unzip-stream'
const uploadStreamMock = jest.fn()
const blockBlobClientMock = jest.fn().mockImplementation(() => ({
@@ -27,9 +28,25 @@ jest.mock('@azure/storage-blob', () => ({
const fixtures = {
uploadDirectory: path.join(__dirname, '_temp', 'plz-upload'),
files: [
['file1.txt', 'test 1 file content'],
['file2.txt', 'test 2 file content'],
['file3.txt', 'test 3 file content']
{name: 'file1.txt', content: 'test 1 file content'},
{name: 'file2.txt', content: 'test 2 file content'},
{name: 'file3.txt', content: 'test 3 file content'},
{
name: 'real.txt',
content: 'from a symlink'
},
{
name: 'relative.txt',
content: 'from a symlink',
symlink: 'real.txt',
relative: true
},
{
name: 'absolute.txt',
content: 'from a symlink',
symlink: 'real.txt',
relative: false
}
],
backendIDs: {
workflowRunBackendId: '67dbcc20-e851-4452-a7c3-2cc0d2e0ec67',
@@ -50,12 +67,30 @@ const fixtures = {
describe('upload-artifact', () => {
beforeAll(() => {
if (!fs.existsSync(fixtures.uploadDirectory)) {
fs.mkdirSync(fixtures.uploadDirectory, {recursive: true})
}
fs.mkdirSync(fixtures.uploadDirectory, {
recursive: true
})
for (const [file, content] of fixtures.files) {
fs.writeFileSync(path.join(fixtures.uploadDirectory, file), content)
for (const file of fixtures.files) {
if (file.symlink) {
let symlinkPath = file.symlink
if (!file.relative) {
symlinkPath = path.join(fixtures.uploadDirectory, file.symlink)
}
if (!fs.existsSync(path.join(fixtures.uploadDirectory, file.name))) {
fs.symlinkSync(
symlinkPath,
path.join(fixtures.uploadDirectory, file.name),
'file'
)
}
} else {
fs.writeFileSync(
path.join(fixtures.uploadDirectory, file.name),
file.content
)
}
}
})
@@ -71,8 +106,9 @@ describe('upload-artifact', () => {
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
.mockReturnValue(
fixtures.files.map(file => ({
sourcePath: path.join(fixtures.uploadDirectory, file[0]),
destinationPath: file[0]
sourcePath: path.join(fixtures.uploadDirectory, file.name),
destinationPath: file.name,
stats: new fs.Stats()
}))
)
jest.spyOn(config, 'getRuntimeToken').mockReturnValue(fixtures.runtimeToken)
@@ -185,6 +221,10 @@ describe('upload-artifact', () => {
})
it('should successfully upload an artifact', async () => {
jest
.spyOn(uploadZipSpecification, 'getUploadZipSpecification')
.mockRestore()
jest
.spyOn(ArtifactServiceClientJSON.prototype, 'CreateArtifact')
.mockReturnValue(
@@ -202,6 +242,12 @@ describe('upload-artifact', () => {
})
)
let loadedBytes = 0
const uploadedZip = path.join(
fixtures.uploadDirectory,
'..',
'uploaded.zip'
)
uploadStreamMock.mockImplementation(
async (
stream: NodeJS.ReadableStream,
@@ -209,31 +255,69 @@ describe('upload-artifact', () => {
maxConcurrency?: number,
options?: BlockBlobUploadStreamOptions
) => {
const {onProgress, abortSignal} = options || {}
const {onProgress} = options || {}
if (fs.existsSync(uploadedZip)) {
fs.unlinkSync(uploadedZip)
}
const uploadedZipStream = fs.createWriteStream(uploadedZip)
onProgress?.({loadedBytes: 0})
return new Promise(resolve => {
const timerId = setTimeout(() => {
onProgress?.({loadedBytes: 256})
resolve({})
}, 1_000)
abortSignal?.addEventListener('abort', () => {
clearTimeout(timerId)
return new Promise((resolve, reject) => {
stream.on('data', chunk => {
loadedBytes += chunk.length
uploadedZipStream.write(chunk)
onProgress?.({loadedBytes})
})
stream.on('end', () => {
onProgress?.({loadedBytes})
uploadedZipStream.end()
resolve({})
})
stream.on('error', err => {
reject(err)
})
})
}
)
const {id, size} = await uploadArtifact(
fixtures.inputs.artifactName,
fixtures.inputs.files,
fixtures.inputs.rootDirectory
fixtures.files.map(file =>
path.join(fixtures.uploadDirectory, file.name)
),
fixtures.uploadDirectory
)
expect(id).toBe(1)
expect(size).toBe(256)
expect(size).toBe(loadedBytes)
const extractedDirectory = path.join(
fixtures.uploadDirectory,
'..',
'extracted'
)
if (fs.existsSync(extractedDirectory)) {
fs.rmdirSync(extractedDirectory, {recursive: true})
}
const extract = new Promise((resolve, reject) => {
fs.createReadStream(uploadedZip)
.pipe(unzip.Extract({path: extractedDirectory}))
.on('close', () => {
resolve(true)
})
.on('error', err => {
reject(err)
})
})
await expect(extract).resolves.toBe(true)
for (const file of fixtures.files) {
const filePath = path.join(extractedDirectory, file.name)
expect(fs.existsSync(filePath)).toBe(true)
expect(fs.readFileSync(filePath, 'utf8')).toBe(file.content)
}
})
it('should throw an error uploading blob chunks get delayed', async () => {
@@ -305,4 +305,22 @@ describe('Search', () => {
}
}
})
it('Upload Specification - Includes symlinks', async () => {
const targetPath = path.join(root, 'link-dir', 'symlink-me.txt')
await fs.mkdir(path.dirname(targetPath), {recursive: true})
await fs.writeFile(targetPath, 'symlink file content')
const uploadPath = path.join(root, 'upload-dir', 'symlink.txt')
await fs.mkdir(path.dirname(uploadPath), {recursive: true})
await fs.symlink(targetPath, uploadPath, 'file')
const specifications = getUploadZipSpecification([uploadPath], root)
expect(specifications.length).toEqual(1)
expect(specifications[0].sourcePath).toEqual(uploadPath)
expect(specifications[0].destinationPath).toEqual(
path.join('/upload-dir', 'symlink.txt')
)
expect(specifications[0].stats.isSymbolicLink()).toBe(true)
})
})
+5 -12
View File
@@ -1,12 +1,12 @@
{
"name": "@actions/artifact",
"version": "2.1.9",
"version": "2.1.11",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@actions/artifact",
"version": "2.1.9",
"version": "2.1.11",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.0",
@@ -19,7 +19,6 @@
"@octokit/request-error": "^5.0.0",
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
"archiver": "^7.0.1",
"crypto": "^1.0.1",
"jwt-decode": "^3.1.2",
"twirp-ts": "^2.5.0",
"unzip-stream": "^0.3.1"
@@ -852,12 +851,6 @@
"node": ">= 8"
}
},
"node_modules/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in."
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -1315,9 +1308,9 @@
}
},
"node_modules/path-to-regexp": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
"integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw=="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="
},
"node_modules/prettier": {
"version": "2.8.8",
+1 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/artifact",
"version": "2.1.9",
"version": "2.1.11",
"preview": true,
"description": "Actions artifact lib",
"keywords": [
@@ -50,7 +50,6 @@
"@octokit/request-error": "^5.0.0",
"@protobuf-ts/plugin": "^2.2.3-alpha.1",
"archiver": "^7.0.1",
"crypto": "^1.0.1",
"jwt-decode": "^3.1.2",
"twirp-ts": "^2.5.0",
"unzip-stream": "^0.3.1"
@@ -13,6 +13,12 @@ export interface UploadZipSpecification {
* The destination path in a zip for a file
*/
destinationPath: string
/**
* Information about the file
* https://nodejs.org/api/fs.html#class-fsstats
*/
stats: fs.Stats
}
/**
@@ -75,10 +81,11 @@ export function getUploadZipSpecification(
- file3.txt
*/
for (let file of filesToZip) {
if (!fs.existsSync(file)) {
const stats = fs.lstatSync(file, {throwIfNoEntry: false})
if (!stats) {
throw new Error(`File ${file} does not exist`)
}
if (!fs.statSync(file).isDirectory()) {
if (!stats.isDirectory()) {
// Normalize and resolve, this allows for either absolute or relative paths to be used
file = normalize(file)
file = resolve(file)
@@ -94,7 +101,8 @@ export function getUploadZipSpecification(
specification.push({
sourcePath: file,
destinationPath: uploadPath
destinationPath: uploadPath,
stats
})
} else {
// Empty directory
@@ -103,7 +111,8 @@ export function getUploadZipSpecification(
specification.push({
sourcePath: null,
destinationPath: directoryPath
destinationPath: directoryPath,
stats
})
}
}
+9 -2
View File
@@ -1,4 +1,5 @@
import * as stream from 'stream'
import {realpath} from 'fs/promises'
import * as archiver from 'archiver'
import * as core from '@actions/core'
import {UploadZipSpecification} from './upload-zip-specification'
@@ -42,8 +43,14 @@ export async function createZipUploadStream(
for (const file of uploadSpecification) {
if (file.sourcePath !== null) {
// Add a normal file to the zip
zip.file(file.sourcePath, {
// Check if symlink and resolve the source path
let sourcePath = file.sourcePath
if (file.stats.isSymbolicLink()) {
sourcePath = await realpath(file.sourcePath)
}
// Add the file to the zip
zip.file(sourcePath, {
name: file.destinationPath
})
} else {
+4
View File
@@ -63,6 +63,8 @@ export type AttestOptions = {
// Sigstore instance to use for signing. Must be one of "public-good" or
// "github".
sigstore?: 'public-good' | 'github'
// HTTP headers to include in request to attestations API.
headers?: {[header: string]: string | number | undefined}
// Whether to skip writing the attestation to the GH attestations API.
skipWrite?: boolean
}
@@ -113,6 +115,8 @@ export type AttestProvenanceOptions = {
// Sigstore instance to use for signing. Must be one of "public-good" or
// "github".
sigstore?: 'public-good' | 'github'
// HTTP headers to include in request to attestations API.
headers?: {[header: string]: string | number | undefined}
// Whether to skip writing the attestation to the GH attestations API.
skipWrite?: boolean
// Issuer URL responsible for minting the OIDC token from which the
+23 -12
View File
@@ -1,31 +1,42 @@
# @actions/attest Releases
### 1.4.2
- Fix bug in `buildSLSAProvenancePredicate`/`attestProvenance` when generating provenance statement for enterprise account using customized OIDC issuer value [#1823](https://github.com/actions/toolkit/pull/1823)
### 1.4.1
- Bump @actions/http-client from 2.2.1 to 2.2.3 [#1805](https://github.com/actions/toolkit/pull/1805)
### 1.4.0
- Add new `headers` parameter to the `attest` and `attestProvenance` functions [#1790](https://github.com/actions/toolkit/pull/1790)
- Update `buildSLSAProvenancePredicate`/`attestProvenance` to automatically derive default OIDC issuer URL from current execution context [#1796](https://github.com/actions/toolkit/pull/1796)
### 1.3.1
- Fix bug with proxy support when retrieving JWKS for OIDC issuer
- Fix bug with proxy support when retrieving JWKS for OIDC issuer [#1776](https://github.com/actions/toolkit/pull/1776)
### 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
- Dynamic construction of Sigstore API URLs [#1735](https://github.com/actions/toolkit/pull/1735)
- Switch to new GH provenance build type [#1745](https://github.com/actions/toolkit/pull/1745)
- Fetch existing Rekor entry on 409 conflict error [#1759](https://github.com/actions/toolkit/pull/1759)
- Bump @sigstore/bundle from 2.3.0 to 2.3.2 [#1738](https://github.com/actions/toolkit/pull/1738)
- Bump @sigstore/sign from 2.3.0 to 2.3.2 [#1738](https://github.com/actions/toolkit/pull/1738)
### 1.2.1
- Retry request on attestation persistence failure
- Retry request on attestation persistence failure [#1725](https://github.com/actions/toolkit/pull/1725)
### 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
- Generate attestations using the v0.3 Sigstore bundle format [#1701](https://github.com/actions/toolkit/pull/1701)
- Bump @sigstore/bundle from 2.2.0 to 2.3.0 [#1701](https://github.com/actions/toolkit/pull/1701)
- Bump @sigstore/sign from 2.2.3 to 2.3.0 [#1701](https://github.com/actions/toolkit/pull/1701)
- Remove dependency on make-fetch-happen [#1714](https://github.com/actions/toolkit/pull/1714)
### 1.1.0
- Updates the `attestProvenance` function to retrieve a token from the GitHub OIDC provider and use the token claims to populate the provenance statement.
- Updates the `attestProvenance` function to retrieve a token from the GitHub OIDC provider and use the token claims to populate the provenance statement [#1693](https://github.com/actions/toolkit/pull/1693)
### 1.0.0
@@ -9,7 +9,7 @@ exports[`provenance functions buildSLSAProvenancePredicate returns a provenance
"workflow": {
"path": ".github/workflows/main.yml",
"ref": "main",
"repository": "https://github.com/owner/repo",
"repository": "https://foo.ghe.com/owner/repo",
},
},
"internalParameters": {
@@ -25,16 +25,16 @@ exports[`provenance functions buildSLSAProvenancePredicate returns a provenance
"digest": {
"gitCommit": "babca52ab0c93ae16539e5923cb0d7403b9a093b",
},
"uri": "git+https://github.com/owner/repo@refs/heads/main",
"uri": "git+https://foo.ghe.com/owner/repo@refs/heads/main",
},
],
},
"runDetails": {
"builder": {
"id": "https://github.com/owner/workflows/.github/workflows/publish.yml@main",
"id": "https://foo.ghe.com/owner/workflows/.github/workflows/publish.yml@main",
},
"metadata": {
"invocationId": "https://github.com/owner/repo/actions/runs/run-id/attempts/run-attempt",
"invocationId": "https://foo.ghe.com/owner/repo/actions/runs/run-id/attempts/run-attempt",
},
},
},
+52 -1
View File
@@ -68,6 +68,55 @@ describe('getIDTokenClaims', () => {
})
})
describe('when ID token is valid (w/ enterprise slug)', () => {
const claims = {
iss: `${issuer}/foo-bar`,
aud: audience,
ref: 'ref',
sha: 'sha',
repository: 'repo',
event_name: 'push',
job_workflow_ref: 'job_workflow_ref',
workflow_ref: 'workflow',
repository_id: '1',
repository_owner_id: '1',
runner_environment: 'github-hosted',
run_id: '1',
run_attempt: '1'
}
beforeEach(async () => {
const jwt = await new jose.SignJWT(claims)
.setProtectedHeader({alg: 'PS256'})
.sign(key.privateKey)
nock(issuer).get(tokenPath).query({audience}).reply(200, {value: jwt})
})
it('returns the ID token claims', async () => {
const result = await getIDTokenClaims(issuer)
expect(result).toEqual(claims)
})
})
describe('when ID token is missing the "iss" claim', () => {
const claims = {
aud: audience
}
beforeEach(async () => {
const jwt = await new jose.SignJWT(claims)
.setProtectedHeader({alg: 'PS256'})
.sign(key.privateKey)
nock(issuer).get(tokenPath).query({audience}).reply(200, {value: jwt})
})
it('throws an error', async () => {
await expect(getIDTokenClaims(issuer)).rejects.toThrow(/missing "iss"/i)
})
})
describe('when ID token is missing required claims', () => {
const claims = {
iss: issuer,
@@ -99,7 +148,9 @@ describe('getIDTokenClaims', () => {
})
it('throws an error', async () => {
await expect(getIDTokenClaims(issuer)).rejects.toThrow(/unexpected "iss"/)
await expect(getIDTokenClaims(issuer)).rejects.toThrow(
/unexpected "iss"/i
)
})
})
+10 -15
View File
@@ -8,7 +8,7 @@ import {attestProvenance, buildSLSAProvenancePredicate} from '../src/provenance'
describe('provenance functions', () => {
const originalEnv = process.env
const issuer = 'https://example.com'
const issuer = 'https://token.actions.foo.ghe.com'
const audience = 'nobody'
const jwksPath = '/.well-known/jwks.json'
const tokenPath = '/token'
@@ -38,7 +38,7 @@ describe('provenance functions', () => {
...originalEnv,
ACTIONS_ID_TOKEN_REQUEST_URL: `${issuer}${tokenPath}?`,
ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'token',
GITHUB_SERVER_URL: 'https://github.com',
GITHUB_SERVER_URL: 'https://foo.ghe.com',
GITHUB_REPOSITORY: claims.repository
}
@@ -68,7 +68,7 @@ describe('provenance functions', () => {
describe('buildSLSAProvenancePredicate', () => {
it('returns a provenance hydrated from an OIDC token', async () => {
const predicate = await buildSLSAProvenancePredicate(issuer)
const predicate = await buildSLSAProvenancePredicate()
expect(predicate).toMatchSnapshot()
})
})
@@ -96,9 +96,9 @@ describe('provenance functions', () => {
})
describe('when using the github Sigstore instance', () => {
const {fulcioURL, tsaServerURL} = signingEndpoints('github')
beforeEach(async () => {
const {fulcioURL, tsaServerURL} = signingEndpoints('github')
// Mock Sigstore
await mockFulcio({baseURL: fulcioURL, strict: false})
await mockTSA({baseURL: tsaServerURL})
@@ -118,8 +118,7 @@ describe('provenance functions', () => {
subjectName,
subjectDigest,
token: 'token',
sigstore: 'github',
issuer
sigstore: 'github'
})
expect(attestation).toBeDefined()
@@ -146,8 +145,7 @@ describe('provenance functions', () => {
const attestation = await attestProvenance({
subjectName,
subjectDigest,
token: 'token',
issuer
token: 'token'
})
expect(attestation).toBeDefined()
@@ -183,8 +181,7 @@ describe('provenance functions', () => {
subjectName,
subjectDigest,
token: 'token',
sigstore: 'public-good',
issuer
sigstore: 'public-good'
})
expect(attestation).toBeDefined()
@@ -211,8 +208,7 @@ describe('provenance functions', () => {
const attestation = await attestProvenance({
subjectName,
subjectDigest,
token: 'token',
issuer
token: 'token'
})
expect(attestation).toBeDefined()
@@ -238,8 +234,7 @@ describe('provenance functions', () => {
subjectDigest,
token: 'token',
sigstore: 'public-good',
skipWrite: true,
issuer
skipWrite: true
})
expect(attestation).toBeDefined()
+5 -2
View File
@@ -5,6 +5,7 @@ describe('writeAttestation', () => {
const originalEnv = process.env
const attestation = {foo: 'bar '}
const token = 'token'
const headers = {'X-GitHub-Foo': 'true'}
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)
@@ -27,14 +28,16 @@ describe('writeAttestation', () => {
.intercept({
path: '/repos/foo/bar/attestations',
method: 'POST',
headers: {authorization: `token ${token}`},
headers: {authorization: `token ${token}`, ...headers},
body: JSON.stringify({bundle: attestation})
})
.reply(201, {id: '123'})
})
it('persists the attestation', async () => {
await expect(writeAttestation(attestation, token)).resolves.toEqual('123')
await expect(
writeAttestation(attestation, token, {headers})
).resolves.toEqual('123')
})
})
+9 -9
View File
@@ -1,17 +1,17 @@
{
"name": "@actions/attest",
"version": "1.3.1",
"version": "1.4.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@actions/attest",
"version": "1.3.1",
"version": "1.4.2",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"@actions/http-client": "^2.2.1",
"@actions/http-client": "^2.2.3",
"@octokit/plugin-retry": "^6.0.1",
"@sigstore/bundle": "^2.3.2",
"@sigstore/sign": "^2.3.2",
@@ -46,9 +46,9 @@
}
},
"node_modules/@actions/http-client": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.1.tgz",
"integrity": "sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^5.25.4"
@@ -1767,9 +1767,9 @@
}
},
"@actions/http-client": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.1.tgz",
"integrity": "sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
"requires": {
"tunnel": "^0.0.6",
"undici": "^5.25.4"
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/attest",
"version": "1.3.1",
"version": "1.4.2",
"description": "Actions attestation lib",
"keywords": [
"github",
@@ -44,7 +44,7 @@
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/github": "^6.0.0",
"@actions/http-client": "^2.2.1",
"@actions/http-client": "^2.2.3",
"@octokit/plugin-retry": "^6.0.1",
"@sigstore/bundle": "^2.3.2",
"@sigstore/sign": "^2.3.2",
+7 -1
View File
@@ -28,6 +28,8 @@ export type AttestOptions = {
// Sigstore instance to use for signing. Must be one of "public-good" or
// "github".
sigstore?: SigstoreInstance
// HTTP headers to include in request to attestations API.
headers?: {[header: string]: string | number | undefined}
// Whether to skip writing the attestation to the GH attestations API.
skipWrite?: boolean
}
@@ -61,7 +63,11 @@ export async function attest(options: AttestOptions): Promise<Attestation> {
// Store the attestation
let attestationID: string | undefined
if (options.skipWrite !== true) {
attestationID = await writeAttestation(bundleToJSON(bundle), options.token)
attestationID = await writeAttestation(
bundleToJSON(bundle),
options.token,
{headers: options.headers}
)
}
return toAttestation(bundle, attestationID)
+36 -3
View File
@@ -4,6 +4,11 @@ import * as jose from 'jose'
const OIDC_AUDIENCE = 'nobody'
const VALID_SERVER_URLS = [
'https://github.com',
new RegExp('^https://[a-z0-9-]+\\.ghe\\.com$')
] as const
const REQUIRED_CLAIMS = [
'iss',
'ref',
@@ -25,7 +30,8 @@ type OIDCConfig = {
jwks_uri: string
}
export const getIDTokenClaims = async (issuer: string): Promise<ClaimSet> => {
export const getIDTokenClaims = async (issuer?: string): Promise<ClaimSet> => {
issuer = issuer || getIssuer()
try {
const token = await getIDToken(OIDC_AUDIENCE)
const claims = await decodeOIDCToken(token, issuer)
@@ -43,10 +49,19 @@ const decodeOIDCToken = async (
// Verify and decode token
const jwks = jose.createLocalJWKSet(await getJWKS(issuer))
const {payload} = await jose.jwtVerify(token, jwks, {
audience: OIDC_AUDIENCE,
issuer
audience: OIDC_AUDIENCE
})
if (!payload.iss) {
throw new Error('Missing "iss" claim')
}
// Check that the issuer STARTS WITH the expected issuer URL to account for
// the fact that the value may include an enterprise-specific slug
if (!payload.iss.startsWith(issuer)) {
throw new Error(`Unexpected "iss" claim: ${payload.iss}`)
}
return payload
}
@@ -82,3 +97,21 @@ function assertClaimSet(claims: jose.JWTPayload): asserts claims is ClaimSet {
throw new Error(`Missing claims: ${missingClaims.join(', ')}`)
}
}
// Derive the current OIDC issuer based on the server URL
function getIssuer(): string {
const serverURL = process.env.GITHUB_SERVER_URL || 'https://github.com'
// Ensure the server URL is a valid GitHub server URL
if (!VALID_SERVER_URLS.some(valid_url => serverURL.match(valid_url))) {
throw new Error(`Invalid server URL: ${serverURL}`)
}
let host = new URL(serverURL).hostname
if (host === 'github.com') {
host = 'githubusercontent.com'
}
return `https://token.actions.${host}`
}
+1 -3
View File
@@ -5,8 +5,6 @@ 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 DEFAULT_ISSUER = 'https://token.actions.githubusercontent.com'
export type AttestProvenanceOptions = Omit<
AttestOptions,
'predicate' | 'predicateType'
@@ -24,7 +22,7 @@ export type AttestProvenanceOptions = Omit<
* @returns The SLSA provenance predicate.
*/
export const buildSLSAProvenancePredicate = async (
issuer: string = DEFAULT_ISSUER
issuer?: string
): Promise<Predicate> => {
const serverURL = process.env.GITHUB_SERVER_URL
const claims = await getIDTokenClaims(issuer)
+3
View File
@@ -1,11 +1,13 @@
import * as github from '@actions/github'
import {retry} from '@octokit/plugin-retry'
import {RequestHeaders} from '@octokit/types'
const CREATE_ATTESTATION_REQUEST = 'POST /repos/{owner}/{repo}/attestations'
const DEFAULT_RETRY_COUNT = 5
export type WriteOptions = {
retry?: number
headers?: RequestHeaders
}
/**
* Writes an attestation to the repository's attestations endpoint.
@@ -26,6 +28,7 @@ export const writeAttestation = async (
const response = await octokit.request(CREATE_ATTESTATION_REQUEST, {
owner: github.context.repo.owner,
repo: github.context.repo.repo,
headers: options.headers,
data: {bundle: attestation}
})
+1 -29
View File
@@ -17,12 +17,10 @@
"@azure/abort-controller": "^1.1.0",
"@azure/ms-rest-js": "^2.6.0",
"@azure/storage-blob": "^12.13.0",
"semver": "^6.3.1",
"uuid": "^3.3.3"
"semver": "^6.3.1"
},
"devDependencies": {
"@types/semver": "^6.0.0",
"@types/uuid": "^3.4.5",
"typescript": "^5.2.2"
}
},
@@ -296,12 +294,6 @@
"@types/node": "*"
}
},
"node_modules/@types/uuid": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.10.tgz",
"integrity": "sha512-BgeaZuElf7DEYZhWYDTc/XcLZXdVgFkVSTa13BqKvbnmUrxr3TJFKofUxCtDO9UQOdhnV+HPOESdHiHKZOJV1A==",
"dev": true
},
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@@ -486,15 +478,6 @@
"node": ">=14.17"
}
},
"node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
@@ -764,12 +747,6 @@
"@types/node": "*"
}
},
"@types/uuid": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.10.tgz",
"integrity": "sha512-BgeaZuElf7DEYZhWYDTc/XcLZXdVgFkVSTa13BqKvbnmUrxr3TJFKofUxCtDO9UQOdhnV+HPOESdHiHKZOJV1A==",
"dev": true
},
"abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@@ -900,11 +877,6 @@
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
"dev": true
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+1 -3
View File
@@ -45,12 +45,10 @@
"@azure/abort-controller": "^1.1.0",
"@azure/ms-rest-js": "^2.6.0",
"@azure/storage-blob": "^12.13.0",
"semver": "^6.3.1",
"uuid": "^3.3.3"
"semver": "^6.3.1"
},
"devDependencies": {
"@types/semver": "^6.0.0",
"@types/uuid": "^3.4.5",
"typescript": "^5.2.2"
}
}
+2 -2
View File
@@ -2,11 +2,11 @@ import * as core from '@actions/core'
import * as exec from '@actions/exec'
import * as glob from '@actions/glob'
import * as io from '@actions/io'
import * as crypto from 'crypto'
import * as fs from 'fs'
import * as path from 'path'
import * as semver from 'semver'
import * as util from 'util'
import {v4 as uuidV4} from 'uuid'
import {
CacheFilename,
CompressionMethod,
@@ -34,7 +34,7 @@ export async function createTempDirectory(): Promise<string> {
tempDirectory = path.join(baseLocation, 'actions', 'temp')
}
const dest = path.join(tempDirectory, uuidV4())
const dest = path.join(tempDirectory, crypto.randomUUID())
await io.mkdirP(dest)
return dest
}
+7
View File
@@ -1,5 +1,12 @@
# @actions/core Releases
### 1.11.1
- Fix uses of `crypto.randomUUID` on Node 18 and earlier [#1842](https://github.com/actions/toolkit/pull/1842)
### 1.11.0
- Add platform info utilities [#1551](https://github.com/actions/toolkit/pull/1551)
- Remove dependency on `uuid` package [#1824](https://github.com/actions/toolkit/pull/1824)
### 1.10.1
- Fix error message reference in oidc utils [#1511](https://github.com/actions/toolkit/pull/1511)
+21 -16
View File
@@ -4,9 +4,6 @@ import * as path from 'path'
import * as core from '../src/core'
import {HttpClient} from '@actions/http-client'
import {toCommandProperties} from '../src/utils'
import * as uuid from 'uuid'
jest.mock('uuid')
/* eslint-disable @typescript-eslint/unbound-method */
@@ -49,11 +46,23 @@ const testEnvVars = {
const UUID = '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
const DELIMITER = `ghadelimiter_${UUID}`
jest.mock('crypto', () => ({
...jest.requireActual('crypto'),
randomUUID: jest.fn(() => UUID)
}))
const TEMP_DIR = path.join(__dirname, '_temp')
describe('@actions/core', () => {
beforeAll(() => {
const filePath = path.join(__dirname, `test`)
const filePath = TEMP_DIR
if (!fs.existsSync(filePath)) {
fs.mkdirSync(filePath)
} else {
// Clear out the temp directory
for (const file of fs.readdirSync(filePath)) {
fs.unlinkSync(path.join(filePath, file))
}
}
})
@@ -62,10 +71,6 @@ describe('@actions/core', () => {
process.env[key] = testEnvVars[key as keyof typeof testEnvVars]
}
process.stdout.write = jest.fn()
jest.spyOn(uuid, 'v4').mockImplementation(() => {
return UUID
})
})
afterEach(() => {
@@ -141,7 +146,7 @@ describe('@actions/core', () => {
`Unexpected input: value should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
const filePath = path.join(TEMP_DIR, command)
fs.unlinkSync(filePath)
})
@@ -155,7 +160,7 @@ describe('@actions/core', () => {
`Unexpected input: name should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
const filePath = path.join(TEMP_DIR, command)
fs.unlinkSync(filePath)
})
@@ -347,7 +352,7 @@ describe('@actions/core', () => {
`Unexpected input: value should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
const filePath = path.join(TEMP_DIR, command)
fs.unlinkSync(filePath)
})
@@ -361,7 +366,7 @@ describe('@actions/core', () => {
`Unexpected input: name should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
const filePath = path.join(TEMP_DIR, command)
fs.unlinkSync(filePath)
})
@@ -585,7 +590,7 @@ describe('@actions/core', () => {
`Unexpected input: value should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
const filePath = path.join(TEMP_DIR, command)
fs.unlinkSync(filePath)
})
@@ -599,7 +604,7 @@ describe('@actions/core', () => {
`Unexpected input: name should not contain the delimiter "${DELIMITER}"`
)
const filePath = path.join(__dirname, `test/${command}`)
const filePath = path.join(TEMP_DIR, command)
fs.unlinkSync(filePath)
})
@@ -641,7 +646,7 @@ function assertWriteCalls(calls: string[]): void {
}
function createFileCommandFile(command: string): void {
const filePath = path.join(__dirname, `test/${command}`)
const filePath = path.join(__dirname, `_temp/${command}`)
process.env[`GITHUB_${command}`] = filePath
fs.appendFileSync(filePath, '', {
encoding: 'utf8'
@@ -649,7 +654,7 @@ function createFileCommandFile(command: string): void {
}
function verifyFileCommand(command: string, expectedContents: string): void {
const filePath = path.join(__dirname, `test/${command}`)
const filePath = path.join(__dirname, `_temp/${command}`)
const contents = fs.readFileSync(filePath, 'utf8')
try {
expect(contents).toEqual(expectedContents)
+10 -37
View File
@@ -1,21 +1,19 @@
{
"name": "@actions/core",
"version": "1.10.1",
"version": "1.11.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@actions/core",
"version": "1.10.1",
"version": "1.11.1",
"license": "MIT",
"dependencies": {
"@actions/exec": "^1.1.1",
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
"@actions/http-client": "^2.0.1"
},
"devDependencies": {
"@types/node": "^12.0.2",
"@types/uuid": "^8.3.4"
"@types/node": "^16.18.112"
}
},
"node_modules/@actions/exec": {
@@ -40,15 +38,9 @@
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
},
"node_modules/@types/node": {
"version": "12.0.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
"integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
"dev": true
},
"node_modules/@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"version": "16.18.112",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.112.tgz",
"integrity": "sha512-EKrbKUGJROm17+dY/gMi31aJlGLJ75e1IkTojt9n6u+hnaTBDs+M1bIdOawpk2m6YUAXq/R2W0SxCng1tndHCg==",
"dev": true
},
"node_modules/tunnel": {
@@ -58,14 +50,6 @@
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
}
},
"dependencies": {
@@ -91,26 +75,15 @@
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="
},
"@types/node": {
"version": "12.0.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
"integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
"dev": true
},
"@types/uuid": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
"version": "16.18.112",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.112.tgz",
"integrity": "sha512-EKrbKUGJROm17+dY/gMi31aJlGLJ75e1IkTojt9n6u+hnaTBDs+M1bIdOawpk2m6YUAXq/R2W0SxCng1tndHCg==",
"dev": true
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
}
}
}
+3 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/core",
"version": "1.10.1",
"version": "1.11.1",
"description": "Actions core lib",
"keywords": [
"github",
@@ -37,11 +37,9 @@
},
"dependencies": {
"@actions/exec": "^1.1.1",
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
"@actions/http-client": "^2.0.1"
},
"devDependencies": {
"@types/node": "^12.0.2",
"@types/uuid": "^8.3.4"
"@types/node": "^16.18.112"
}
}
+2 -2
View File
@@ -3,9 +3,9 @@
// We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as crypto from 'crypto'
import * as fs from 'fs'
import * as os from 'os'
import {v4 as uuidv4} from 'uuid'
import {toCommandValue} from './utils'
export function issueFileCommand(command: string, message: any): void {
@@ -25,7 +25,7 @@ export function issueFileCommand(command: string, message: any): void {
}
export function prepareKeyValueMessage(key: string, value: any): string {
const delimiter = `ghadelimiter_${uuidv4()}`
const delimiter = `ghadelimiter_${crypto.randomUUID()}`
const convertedValue = toCommandValue(value)
// These should realistically never happen, but just in case someone finds a
+3
View File
@@ -1,5 +1,8 @@
# @actions/glob Releases
### 0.5.0
- Added `excludeHiddenFiles` option, which is disabled by default to preserve existing behavior [#1791: Add glob option to ignore hidden files](https://github.com/actions/toolkit/pull/1791)
### 0.4.0
- Pass in the current workspace as a parameter to HashFiles [#1318](https://github.com/actions/toolkit/pull/1318)
@@ -708,7 +708,7 @@ describe('globber', () => {
expect(itemPaths).toEqual([])
})
it('returns hidden files', async () => {
it('returns hidden files by default', async () => {
// Create the following layout:
// <root>
// <root>/.emptyFolder
@@ -734,6 +734,26 @@ describe('globber', () => {
])
})
it('ignores hidden files when excludeHiddenFiles is set', async () => {
// Create the following layout:
// <root>
// <root>/.emptyFolder
// <root>/.file
// <root>/.folder
// <root>/.folder/file
const root = path.join(getTestTemp(), 'ignores-hidden-files')
await createHiddenDirectory(path.join(root, '.emptyFolder'))
await createHiddenDirectory(path.join(root, '.folder'))
await createHiddenFile(path.join(root, '.file'), 'test .file content')
await fs.writeFile(
path.join(root, '.folder', 'file'),
'test .folder/file content'
)
const itemPaths = await glob(root, {excludeHiddenFiles: true})
expect(itemPaths).toEqual([root])
})
it('returns normalized paths', async () => {
// Create the following layout:
// <root>/hello/world.txt
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/glob",
"version": "0.4.0",
"version": "0.5.0",
"lockfileVersion": 3,
"requires": true,
"description": "Actions glob lib",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/glob",
"version": "0.4.0",
"version": "0.5.0",
"preview": true,
"description": "Actions glob lib",
"keywords": [
@@ -9,7 +9,8 @@ export function getOptions(copy?: GlobOptions): GlobOptions {
followSymbolicLinks: true,
implicitDescendants: true,
matchDirectories: true,
omitBrokenSymbolicLinks: true
omitBrokenSymbolicLinks: true,
excludeHiddenFiles: false
}
if (copy) {
@@ -32,6 +33,11 @@ export function getOptions(copy?: GlobOptions): GlobOptions {
result.omitBrokenSymbolicLinks = copy.omitBrokenSymbolicLinks
core.debug(`omitBrokenSymbolicLinks '${result.omitBrokenSymbolicLinks}'`)
}
if (typeof copy.excludeHiddenFiles === 'boolean') {
result.excludeHiddenFiles = copy.excludeHiddenFiles
core.debug(`excludeHiddenFiles '${result.excludeHiddenFiles}'`)
}
}
return result
@@ -36,4 +36,13 @@ export interface GlobOptions {
* @default true
*/
omitBrokenSymbolicLinks?: boolean
/**
* Indicates whether to exclude hidden files (files and directories starting with a `.`).
* This does not apply to Windows files and directories with the hidden attribute unless
* they are also prefixed with a `.`.
*
* @default false
*/
excludeHiddenFiles?: boolean
}
+5
View File
@@ -128,6 +128,11 @@ export class DefaultGlobber implements Globber {
continue
}
// Hidden file or directory?
if (options.excludeHiddenFiles && path.basename(item.path).match(/^\./)) {
continue
}
// Directory
if (stats.isDirectory()) {
// Matched
+9
View File
@@ -1,5 +1,14 @@
## Releases
## 2.2.3
- Fixed an issue where proxy username and password were not handled correctly [#1799](https://github.com/actions/toolkit/pull/1799)
## 2.2.2
- Better handling of url encoded usernames and passwords in proxy config [#1782](https://github.com/actions/toolkit/pull/1782)
## 2.2.1
- Make sure RequestOptions.keepAlive is applied properly on node20 runtime [#1572](https://github.com/actions/toolkit/pull/1572)
## 2.2.0
- Add function to return proxy agent dispatcher for compatibility with latest octokit packages [#1547](https://github.com/actions/toolkit/pull/1547)
+32 -31
View File
@@ -37,7 +37,7 @@ describe('basics', () => {
// "user-agent": "typed-test-client-tests"
// },
// "origin": "173.95.152.44",
// "url": "https://postman-echo.com/get"
// "url": "http://postman-echo.com/get"
// }
it('does basic http get request', async () => {
@@ -63,16 +63,17 @@ describe('basics', () => {
expect(obj.headers['user-agent']).toBeFalsy()
})
/* TODO write a mock rather then relying on a third party
it('does basic https get request', async () => {
const res: httpm.HttpClientResponse = await _http.get(
'https://postman-echo.com/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://postman-echo.com/get')
expect(obj.url).toBe('http://postman-echo.com/get')
})
*/
it('does basic http get request with default headers', async () => {
const http: httpm.HttpClient = new httpm.HttpClient(
'http-client-tests',
@@ -125,12 +126,12 @@ describe('basics', () => {
it('pipes a get request', async () => {
return new Promise<void>(async resolve => {
const file = fs.createWriteStream(sampleFilePath)
;(await _http.get('https://postman-echo.com/get')).message
;(await _http.get('http://postman-echo.com/get')).message
.pipe(file)
.on('close', () => {
const body: string = fs.readFileSync(sampleFilePath).toString()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://postman-echo.com/get')
expect(obj.url).toBe('http://postman-echo.com/get')
resolve()
})
})
@@ -138,32 +139,32 @@ describe('basics', () => {
it('does basic get request with redirects', async () => {
const res: httpm.HttpClientResponse = await _http.get(
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://postman-echo.com/get'
`http://postman-echo.com/redirect-to?url=${encodeURIComponent(
'http://postman-echo.com/get'
)}`
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://postman-echo.com/get')
expect(obj.url).toBe('http://postman-echo.com/get')
})
it('does basic get request with redirects (303)', async () => {
const res: httpm.HttpClientResponse = await _http.get(
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://postman-echo.com/get'
`http://postman-echo.com/redirect-to?url=${encodeURIComponent(
'http://postman-echo.com/get'
)}&status_code=303`
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://postman-echo.com/get')
expect(obj.url).toBe('http://postman-echo.com/get')
})
it('returns 404 for not found get request on redirect', async () => {
const res: httpm.HttpClientResponse = await _http.get(
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://postman-echo.com/status/404'
`http://postman-echo.com/redirect-to?url=${encodeURIComponent(
'http://postman-echo.com/status/404'
)}&status_code=303`
)
expect(res.message.statusCode).toBe(404)
@@ -177,8 +178,8 @@ describe('basics', () => {
{allowRedirects: false}
)
const res: httpm.HttpClientResponse = await http.get(
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://postman-echo.com/get'
`http://postman-echo.com/redirect-to?url=${encodeURIComponent(
'http://postman-echo.com/get'
)}`
)
expect(res.message.statusCode).toBe(302)
@@ -191,8 +192,8 @@ describe('basics', () => {
authorization: 'shhh'
}
const res: httpm.HttpClientResponse = await _http.get(
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://www.postman-echo.com/get'
`http://postman-echo.com/redirect-to?url=${encodeURIComponent(
'http://www.postman-echo.com/get'
)}`,
headers
)
@@ -204,7 +205,7 @@ describe('basics', () => {
expect(obj.headers[httpm.Headers.Accept]).toBe('application/json')
expect(obj.headers['Authorization']).toBeUndefined()
expect(obj.headers['authorization']).toBeUndefined()
expect(obj.url).toBe('https://www.postman-echo.com/get')
expect(obj.url).toBe('http://www.postman-echo.com/get')
})
it('does not pass Auth with diff hostname redirects', async () => {
@@ -213,8 +214,8 @@ describe('basics', () => {
Authorization: 'shhh'
}
const res: httpm.HttpClientResponse = await _http.get(
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://www.postman-echo.com/get'
`http://postman-echo.com/redirect-to?url=${encodeURIComponent(
'http://www.postman-echo.com/get'
)}`,
headers
)
@@ -226,7 +227,7 @@ describe('basics', () => {
expect(obj.headers[httpm.Headers.Accept]).toBe('application/json')
expect(obj.headers['Authorization']).toBeUndefined()
expect(obj.headers['authorization']).toBeUndefined()
expect(obj.url).toBe('https://www.postman-echo.com/get')
expect(obj.url).toBe('http://www.postman-echo.com/get')
})
it('does basic head request', async () => {
@@ -289,11 +290,11 @@ describe('basics', () => {
it('gets a json object', async () => {
const jsonObj = await _http.getJson<HttpBinData>(
'https://postman-echo.com/get'
'http://postman-echo.com/get'
)
expect(jsonObj.statusCode).toBe(200)
expect(jsonObj.result).toBeDefined()
expect(jsonObj.result?.url).toBe('https://postman-echo.com/get')
expect(jsonObj.result?.url).toBe('http://postman-echo.com/get')
expect(jsonObj.result?.headers[httpm.Headers.Accept]).toBe(
httpm.MediaTypes.ApplicationJson
)
@@ -304,7 +305,7 @@ describe('basics', () => {
it('getting a non existent json object returns null', async () => {
const jsonObj = await _http.getJson<HttpBinData>(
'https://postman-echo.com/status/404'
'http://postman-echo.com/status/404'
)
expect(jsonObj.statusCode).toBe(404)
expect(jsonObj.result).toBeNull()
@@ -313,12 +314,12 @@ describe('basics', () => {
it('posts a json object', async () => {
const res = {name: 'foo'}
const restRes = await _http.postJson<HttpBinData>(
'https://postman-echo.com/post',
'http://postman-echo.com/post',
res
)
expect(restRes.statusCode).toBe(200)
expect(restRes.result).toBeDefined()
expect(restRes.result?.url).toBe('https://postman-echo.com/post')
expect(restRes.result?.url).toBe('http://postman-echo.com/post')
expect(restRes.result?.json.name).toBe('foo')
expect(restRes.result?.headers[httpm.Headers.Accept]).toBe(
httpm.MediaTypes.ApplicationJson
@@ -334,12 +335,12 @@ describe('basics', () => {
it('puts a json object', async () => {
const res = {name: 'foo'}
const restRes = await _http.putJson<HttpBinData>(
'https://postman-echo.com/put',
'http://postman-echo.com/put',
res
)
expect(restRes.statusCode).toBe(200)
expect(restRes.result).toBeDefined()
expect(restRes.result?.url).toBe('https://postman-echo.com/put')
expect(restRes.result?.url).toBe('http://postman-echo.com/put')
expect(restRes.result?.json.name).toBe('foo')
expect(restRes.result?.headers[httpm.Headers.Accept]).toBe(
@@ -356,12 +357,12 @@ describe('basics', () => {
it('patch a json object', async () => {
const res = {name: 'foo'}
const restRes = await _http.patchJson<HttpBinData>(
'https://postman-echo.com/patch',
'http://postman-echo.com/patch',
res
)
expect(restRes.statusCode).toBe(200)
expect(restRes.result).toBeDefined()
expect(restRes.result?.url).toBe('https://postman-echo.com/patch')
expect(restRes.result?.url).toBe('http://postman-echo.com/patch')
expect(restRes.result?.json.name).toBe('foo')
expect(restRes.result?.headers[httpm.Headers.Accept]).toBe(
httpm.MediaTypes.ApplicationJson
@@ -12,7 +12,7 @@ describe('headers', () => {
it('preserves existing headers on getJson', async () => {
const additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj = await _http.getJson<any>(
'https://postman-echo.com/get',
'http://postman-echo.com/get',
additionalHeaders
)
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('foo')
@@ -26,7 +26,7 @@ describe('headers', () => {
[httpm.Headers.Accept]: 'baz'
}
}
jsonObj = await httpWithHeaders.getJson<any>('https://postman-echo.com/get')
jsonObj = await httpWithHeaders.getJson<any>('http://postman-echo.com/get')
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toContain(
httpm.MediaTypes.ApplicationJson
@@ -36,7 +36,7 @@ describe('headers', () => {
it('preserves existing headers on postJson', async () => {
const additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj = await _http.postJson<any>(
'https://postman-echo.com/post',
'http://postman-echo.com/post',
{},
additionalHeaders
)
@@ -52,7 +52,7 @@ describe('headers', () => {
}
}
jsonObj = await httpWithHeaders.postJson<any>(
'https://postman-echo.com/post',
'http://postman-echo.com/post',
{}
)
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('baz')
@@ -64,7 +64,7 @@ describe('headers', () => {
it('preserves existing headers on putJson', async () => {
const additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj = await _http.putJson<any>(
'https://postman-echo.com/put',
'http://postman-echo.com/put',
{},
additionalHeaders
)
@@ -80,7 +80,7 @@ describe('headers', () => {
}
}
jsonObj = await httpWithHeaders.putJson<any>(
'https://postman-echo.com/put',
'http://postman-echo.com/put',
{}
)
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('baz')
@@ -92,7 +92,7 @@ describe('headers', () => {
it('preserves existing headers on patchJson', async () => {
const additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj = await _http.patchJson<any>(
'https://postman-echo.com/patch',
'http://postman-echo.com/patch',
{},
additionalHeaders
)
@@ -108,7 +108,7 @@ describe('headers', () => {
}
}
jsonObj = await httpWithHeaders.patchJson<any>(
'https://postman-echo.com/patch',
'http://postman-echo.com/patch',
{}
)
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('baz')
+21 -6
View File
@@ -222,30 +222,33 @@ describe('proxy', () => {
expect(_proxyConnects).toHaveLength(0)
})
// TODO mock this out so we don't rely on a third party
/*
it('HttpClient does basic https get request through proxy', async () => {
process.env['https_proxy'] = _proxyUrl
const httpClient = new httpm.HttpClient()
const res: httpm.HttpClientResponse = await httpClient.get(
'https://postman-echo.com/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://postman-echo.com/get')
expect(obj.url).toBe('http://postman-echo.com/get')
expect(_proxyConnects).toEqual(['postman-echo.com:443'])
})
*/
it('HttpClient does basic https get request when bypass proxy', async () => {
process.env['https_proxy'] = _proxyUrl
it('HttpClient does basic http get request when bypass proxy', async () => {
process.env['http_proxy'] = _proxyUrl
process.env['no_proxy'] = 'postman-echo.com'
const httpClient = new httpm.HttpClient()
const res: httpm.HttpClientResponse = await httpClient.get(
'https://postman-echo.com/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://postman-echo.com/get')
expect(obj.url).toBe('http://postman-echo.com/get')
expect(_proxyConnects).toHaveLength(0)
})
@@ -304,6 +307,18 @@ describe('proxy', () => {
console.log(agent)
expect(agent instanceof ProxyAgent).toBe(true)
})
it('proxyAuth is set in tunnel agent when authentication is provided with URIencoding', async () => {
process.env['https_proxy'] =
'http://user%40github.com:p%40ssword@127.0.0.1:8080'
const httpClient = new httpm.HttpClient()
const agent: any = httpClient.getAgent('https://some-url')
// eslint-disable-next-line no-console
console.log(agent)
expect(agent.proxyOptions.host).toBe('127.0.0.1')
expect(agent.proxyOptions.port).toBe('8080')
expect(agent.proxyOptions.proxyAuth).toBe('user@github.com:p@ssword')
})
})
function _clearVars(): void {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/http-client",
"version": "2.2.1",
"version": "2.2.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/http-client",
"version": "2.2.1",
"version": "2.2.3",
"description": "Actions Http Client",
"keywords": [
"github",
+3 -1
View File
@@ -726,7 +726,9 @@ export class HttpClient {
uri: proxyUrl.href,
pipelining: !this._keepAlive ? 0 : 1,
...((proxyUrl.username || proxyUrl.password) && {
token: `${proxyUrl.username}:${proxyUrl.password}`
token: `Basic ${Buffer.from(
`${proxyUrl.username}:${proxyUrl.password}`
).toString('base64')}`
})
})
this._proxyAgentDispatcher = proxyAgent
+21 -2
View File
@@ -15,10 +15,10 @@ export function getProxyUrl(reqUrl: URL): URL | undefined {
if (proxyVar) {
try {
return new URL(proxyVar)
return new DecodedURL(proxyVar)
} catch {
if (!proxyVar.startsWith('http://') && !proxyVar.startsWith('https://'))
return new URL(`http://${proxyVar}`)
return new DecodedURL(`http://${proxyVar}`)
}
} else {
return undefined
@@ -87,3 +87,22 @@ function isLoopbackAddress(host: string): boolean {
hostLower.startsWith('[0:0:0:0:0:0:0:1]')
)
}
class DecodedURL extends URL {
private _decodedUsername: string
private _decodedPassword: string
constructor(url: string | URL, base?: string | URL) {
super(url, base)
this._decodedUsername = decodeURIComponent(super.username)
this._decodedPassword = decodeURIComponent(super.password)
}
get username(): string {
return this._decodedUsername
}
get password(): string {
return this._decodedPassword
}
}
+1 -47
View File
@@ -13,13 +13,11 @@
"@actions/exec": "^1.0.0",
"@actions/http-client": "^2.0.1",
"@actions/io": "^1.1.1",
"semver": "^6.1.0",
"uuid": "^3.3.2"
"semver": "^6.1.0"
},
"devDependencies": {
"@types/nock": "^11.1.0",
"@types/semver": "^6.0.0",
"@types/uuid": "^3.4.4",
"nock": "^13.2.9"
}
},
@@ -71,27 +69,12 @@
"nock": "*"
}
},
"node_modules/@types/node": {
"version": "12.7.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.0.tgz",
"integrity": "sha512-vqcj1MVm2Sla4PpMfYKh1MyDN4D2f/mPIZD7RdAGqEsbE+JxfeqQHHVbRDQ0Nqn8i73gJa1HQ1Pu3+nH4Q0Yiw==",
"dev": true
},
"node_modules/@types/semver": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.0.1.tgz",
"integrity": "sha512-ffCdcrEE5h8DqVxinQjo+2d1q+FV5z7iNtPofw3JsrltSoSVlOGaW0rY8XxtO9XukdTn8TaCGWmk2VFGhI70mg==",
"dev": true
},
"node_modules/@types/uuid": {
"version": "3.4.5",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.5.tgz",
"integrity": "sha512-MNL15wC3EKyw1VLF+RoVO4hJJdk9t/Hlv3rt1OL65Qvuadm4BYo6g9ZJQqoq7X8NBFSsQXgAujWciovh2lpVjA==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -166,15 +149,6 @@
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
},
"node_modules/uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
}
},
"dependencies": {
@@ -224,27 +198,12 @@
"nock": "*"
}
},
"@types/node": {
"version": "12.7.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.0.tgz",
"integrity": "sha512-vqcj1MVm2Sla4PpMfYKh1MyDN4D2f/mPIZD7RdAGqEsbE+JxfeqQHHVbRDQ0Nqn8i73gJa1HQ1Pu3+nH4Q0Yiw==",
"dev": true
},
"@types/semver": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.0.1.tgz",
"integrity": "sha512-ffCdcrEE5h8DqVxinQjo+2d1q+FV5z7iNtPofw3JsrltSoSVlOGaW0rY8XxtO9XukdTn8TaCGWmk2VFGhI70mg==",
"dev": true
},
"@types/uuid": {
"version": "3.4.5",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.5.tgz",
"integrity": "sha512-MNL15wC3EKyw1VLF+RoVO4hJJdk9t/Hlv3rt1OL65Qvuadm4BYo6g9ZJQqoq7X8NBFSsQXgAujWciovh2lpVjA==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -299,11 +258,6 @@
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
}
}
}
+1 -3
View File
@@ -40,13 +40,11 @@
"@actions/exec": "^1.0.0",
"@actions/http-client": "^2.0.1",
"@actions/io": "^1.1.1",
"semver": "^6.1.0",
"uuid": "^3.3.2"
"semver": "^6.1.0"
},
"devDependencies": {
"@types/nock": "^11.1.0",
"@types/semver": "^6.0.0",
"@types/uuid": "^3.4.4",
"nock": "^13.2.9"
}
}
+3 -3
View File
@@ -1,5 +1,6 @@
import * as core from '@actions/core'
import * as io from '@actions/io'
import * as crypto from 'crypto'
import * as fs from 'fs'
import * as mm from './manifest'
import * as os from 'os'
@@ -10,7 +11,6 @@ import * as stream from 'stream'
import * as util from 'util'
import {ok} from 'assert'
import {OutgoingHttpHeaders} from 'http'
import uuidV4 from 'uuid/v4'
import {exec} from '@actions/exec/lib/exec'
import {ExecOptions} from '@actions/exec/lib/interfaces'
import {RetryHelper} from './retry-helper'
@@ -41,7 +41,7 @@ export async function downloadTool(
auth?: string,
headers?: OutgoingHttpHeaders
): Promise<string> {
dest = dest || path.join(_getTempDirectory(), uuidV4())
dest = dest || path.join(_getTempDirectory(), crypto.randomUUID())
await io.mkdirP(path.dirname(dest))
core.debug(`Downloading ${url}`)
core.debug(`Destination ${dest}`)
@@ -651,7 +651,7 @@ export async function findFromManifest(
async function _createExtractFolder(dest?: string): Promise<string> {
if (!dest) {
// create a temp dir
dest = path.join(_getTempDirectory(), uuidV4())
dest = path.join(_getTempDirectory(), crypto.randomUUID())
}
await io.mkdirP(dest)
return dest