diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b79735a..110f1e9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ defaults: shell: bash jobs: - test: + test-basic-setup: name: Test Setup ORAS CLI runs-on: ${{ matrix.os }} strategy: @@ -56,3 +56,81 @@ jobs: echo --- read -ra ORAS_VERSION_INSTALLED <<<$(oras version) [ "${ORAS_VERSION_INSTALLED[1]}" == "$ORAS_VERSION_EXPECTED" ] + + create-test-variables: + runs-on: ubuntu-latest + outputs: + url: ${{ steps.get-checksum-url.outputs.URL }} + checksum: ${{ steps.get-checksum-url.outputs.CHECKSUM }} + steps: + - id: checkout + uses: actions/checkout@v3 + - id: get-checksum-url + run: | + RELEASE=$(jq -r 'keys_unsorted[0] as $k | .[$k].linux.amd64' src/lib/data/releases.json) + echo "CHECKSUM=$(echo $RELEASE | jq -r '.checksum')" >> "$GITHUB_OUTPUT" + echo "URL=$(echo $RELEASE | jq -r '.url')" >> "$GITHUB_OUTPUT" + + test-custom-url: + name: Test Setup using URL + runs-on: ubuntu-latest + needs: create-test-variables + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup ORAS using URL + uses: ./ + with: + url: ${{ needs.create-test-variables.outputs.url }} + checksum: ${{ needs.create-test-variables.outputs.checksum }} + + - name: Setup ORAS using URL without checksum + id: no-checksum + continue-on-error: true + uses: ./ + with: + url: ${{ needs.create-test-variables.outputs.url }} + - name: 'Should Fail: Setup ORAS using URL without checksum' + if: steps.no-checksum.outcome != 'failure' + run: | + echo "Setup ORAS using URL without checksum should fail, but succeeded." + exit 1 + + - name: Setup ORAS using checksum without url + id: no-url + continue-on-error: true + uses: ./ + with: + checksum: ${{ needs.create-test-variables.outputs.checksum }} + - name: 'Should Fail: Setup ORAS using checksum without url' + if: steps.no-url.outcome != 'failure' + run: | + echo "Setup ORAS using checksum without url should fail, but succeeded." + exit 1 + + - name: Setup ORAS using URL and invalid checksum + id: invalid-checksum + continue-on-error: true + uses: ./ + with: + url: ${{ needs.create-test-variables.outputs.url }} + checksum: abcedf + - name: 'Should Fail: Setup ORAS using URL and invalid checksum' + if: steps.invalid-checksum.outcome != 'failure' + run: | + echo "Setup ORAS using URL and invalid checksum should fail, but succeeded." + exit 1 + + - name: Setup ORAS using invalid URL + id: invalid-url + continue-on-error: true + uses: ./ + with: + url: invalid-url + checksum: test + - name: 'Should Fail: Setup ORAS using invalid URL' + if: steps.invalid-url.outcome != 'failure' + run: | + echo "Setup ORAS using invalid URL should fail, but succeeded." + exit 1 diff --git a/action.yml b/action.yml index a75273e..a8099c0 100644 --- a/action.yml +++ b/action.yml @@ -18,9 +18,15 @@ branding: color: blue inputs: version: - description: Version of ORAS CLI to install + description: Version of the official ORAS CLI to install required: false default: 1.1.0 + url: + description: URL of the customized ORAS CLI to install + required: false + checksum: + description: SHA256 of the customized ORAS CLI. Required if 'url' is present. + required: false runs: using: node20 main: dist/index.js diff --git a/dist/index.js b/dist/index.js index c47bc41..9d20e09 100644 --- a/dist/index.js +++ b/dist/index.js @@ -6691,7 +6691,22 @@ exports.getBinaryExtension = exports.mapArch = exports.mapPlatform = exports.get const os = __importStar(__nccwpck_require__(2037)); const releases_json_1 = __importDefault(__nccwpck_require__(2387)); // Get release info of a certain verion of ORAS CLI -function getReleaseInfo(version) { +function getReleaseInfo(version, url, checksum) { + if (url && checksum) { + // if customized ORAS CLI link and checksum are provided, version is ignored + return { + checksum: checksum, + url: url + }; + } + // sanity checks + if (url && !checksum) { + throw new Error("user provided url of customized ORAS CLI release but without SHA256 checksum"); + } + if (!url && checksum) { + throw new Error("user provided SHA256 checksum but without url"); + } + // get the official release const releases = releases_json_1.default; if (!(version in releases)) { console.log(`official ORAS CLI releases does not contain version ${version}`); @@ -6808,19 +6823,21 @@ function setup() { try { // inputs from user const version = core.getInput('version'); + const url = core.getInput('url'); + const checksum = core.getInput('checksum').toLowerCase(); // download ORAS CLI and validate checksum - const info = (0, release_1.getReleaseInfo)(version); - const url = info.url; - console.log(`downloading ORAS CLI from ${url}`); - const pathToTarball = yield tc.downloadTool(url); + const info = (0, release_1.getReleaseInfo)(version, url, checksum); + const download_url = info.url; + console.log(`downloading ORAS CLI from ${download_url}`); + const pathToTarball = yield tc.downloadTool(download_url); console.log("downloading ORAS CLI completed"); - const checksum = yield (0, checksum_1.hash)(pathToTarball); - if (checksum !== info.checksum) { - throw new Error(`checksum of downloaded ORAS CLI ${checksum} does not match expected checksum ${info.checksum}`); + const actual_checksum = yield (0, checksum_1.hash)(pathToTarball); + if (actual_checksum !== info.checksum) { + throw new Error(`checksum of downloaded ORAS CLI ${actual_checksum} does not match expected checksum ${info.checksum}`); } console.log("successfully verified downloaded release checksum"); // extract the tarball/zipball onto host runner - const extract = url.endsWith('.zip') ? tc.extractZip : tc.extractTar; + const extract = download_url.endsWith('.zip') ? tc.extractZip : tc.extractTar; const pathToCLI = yield extract(pathToTarball); // add `ORAS` to PATH core.addPath(pathToCLI); diff --git a/package-lock.json b/package-lock.json index 6d1efd5..1ae01db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,88 +1,121 @@ { "name": "setup-oras", "version": "0.1.0", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@actions/core": { + "packages": { + "": { + "name": "setup-oras", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "@actions/core": "^1.10.0", + "@actions/tool-cache": "^2.0.1", + "@types/node": "^20.4.0", + "@vercel/ncc": "^0.36.1", + "typescript": "^5.2.2" + } + }, + "node_modules/@actions/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", - "requires": { + "dependencies": { "@actions/http-client": "^2.0.1", "uuid": "^8.3.2" } }, - "@actions/exec": { + "node_modules/@actions/exec": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", - "requires": { + "dependencies": { "@actions/io": "^1.0.1" } }, - "@actions/http-client": { + "node_modules/@actions/http-client": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.1.tgz", "integrity": "sha512-qhrkRMB40bbbLo7gF+0vu+X+UawOvQQqNAA/5Unx774RS8poaOhThDOG6BGmxvAnxhQnDp2BG/ZUm65xZILTpw==", - "requires": { + "dependencies": { "tunnel": "^0.0.6" } }, - "@actions/io": { + "node_modules/@actions/io": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==" }, - "@actions/tool-cache": { + "node_modules/@actions/tool-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.1.tgz", "integrity": "sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA==", - "requires": { + "dependencies": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.0", "@actions/http-client": "^2.0.1", "@actions/io": "^1.1.1", "semver": "^6.1.0", "uuid": "^3.3.2" - }, - "dependencies": { - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - } } }, - "@types/node": { + "node_modules/@actions/tool-cache/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/@types/node": { "version": "20.5.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==" }, - "@vercel/ncc": { + "node_modules/@vercel/ncc": { "version": "0.36.1", "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.36.1.tgz", - "integrity": "sha512-S4cL7Taa9yb5qbv+6wLgiKVZ03Qfkc4jGRuiUQMQ8HGBD5pcNRnHeYM33zBvJE4/zJGjJJ8GScB+WmTsn9mORw==" + "integrity": "sha512-S4cL7Taa9yb5qbv+6wLgiKVZ03Qfkc4jGRuiUQMQ8HGBD5pcNRnHeYM33zBvJE4/zJGjJJ8GScB+WmTsn9mORw==", + "bin": { + "ncc": "dist/ncc/cli.js" + } }, - "semver": { + "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } }, - "tunnel": { + "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } }, - "typescript": { + "node_modules/typescript": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==" + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } }, - "uuid": { + "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==" + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } } } } diff --git a/src/lib/release.ts b/src/lib/release.ts index c0c0a89..c67c233 100644 --- a/src/lib/release.ts +++ b/src/lib/release.ts @@ -27,7 +27,24 @@ interface releases { } // Get release info of a certain verion of ORAS CLI -export function getReleaseInfo(version: string) { +export function getReleaseInfo(version: string, url: string, checksum: string) { + if (url && checksum) { + // if customized ORAS CLI link and checksum are provided, version is ignored + return { + checksum: checksum, + url: url + } + } + + // sanity checks + if (url && !checksum) { + throw new Error("user provided url of customized ORAS CLI release but without SHA256 checksum"); + } + if (!url && checksum) { + throw new Error("user provided SHA256 checksum but without url"); + } + + // get the official release const releases = releaseJson as releases; if (!(version in releases)) { console.log(`official ORAS CLI releases does not contain version ${version}`) diff --git a/src/setup.ts b/src/setup.ts index f40f508..cfec8a5 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -21,21 +21,23 @@ async function setup(): Promise { try { // inputs from user const version: string = core.getInput('version'); + const url: string = core.getInput('url'); + const checksum = core.getInput('checksum').toLowerCase(); // download ORAS CLI and validate checksum - const info = getReleaseInfo(version); - const url = info.url; - console.log(`downloading ORAS CLI from ${url}`); - const pathToTarball: string = await tc.downloadTool(url); + const info = getReleaseInfo(version, url, checksum); + const download_url = info.url; + console.log(`downloading ORAS CLI from ${download_url}`); + const pathToTarball: string = await tc.downloadTool(download_url); console.log("downloading ORAS CLI completed"); - const checksum = await hash(pathToTarball); - if (checksum !== info.checksum) { - throw new Error(`checksum of downloaded ORAS CLI ${checksum} does not match expected checksum ${info.checksum}`); + const actual_checksum = await hash(pathToTarball); + if (actual_checksum !== info.checksum) { + throw new Error(`checksum of downloaded ORAS CLI ${actual_checksum} does not match expected checksum ${info.checksum}`); } console.log("successfully verified downloaded release checksum"); // extract the tarball/zipball onto host runner - const extract = url.endsWith('.zip') ? tc.extractZip : tc.extractTar; + const extract = download_url.endsWith('.zip') ? tc.extractZip : tc.extractTar; const pathToCLI: string = await extract(pathToTarball); // add `ORAS` to PATH