From 045ec472bf83d1073740d4e7f87758a132ce9214 Mon Sep 17 00:00:00 2001 From: Raj-StepSecurity Date: Mon, 13 Apr 2026 10:39:25 +0530 Subject: [PATCH 1/2] feat: added banner and update subscription check to make maintained actions free for public repos --- .github/workflows/actions_release.yml | 5 +++ .github/workflows/audit_package.yml | 5 +++ .github/workflows/auto_cherry_pick.yml | 5 +++ .github/workflows/guarddog.yml | 14 ------- .github/workflows/workflow.yml | 2 +- README.md | 2 + action.yml | 2 +- dist/index.js | 49 ++++++++++++++++-------- src/setup-xcode.ts | 53 +++++++++++++++++++++----- tsconfig.json | 2 +- 10 files changed, 96 insertions(+), 43 deletions(-) delete mode 100644 .github/workflows/guarddog.yml diff --git a/.github/workflows/actions_release.yml b/.github/workflows/actions_release.yml index 8e484ee..a1d7c7d 100644 --- a/.github/workflows/actions_release.yml +++ b/.github/workflows/actions_release.yml @@ -6,6 +6,10 @@ on: tag: description: "Tag for the release" required: true + node_version: + description: "Specify Node.js version (e.g., '18', '20', 'lts/*')" + required: false + default: "24" permissions: contents: read @@ -20,3 +24,4 @@ jobs: uses: step-security/reusable-workflows/.github/workflows/actions_release.yaml@v1 with: tag: "${{ github.event.inputs.tag }}" + node_version: "${{ github.event.inputs.node_version }}" diff --git a/.github/workflows/audit_package.yml b/.github/workflows/audit_package.yml index 2cc740e..4fa5ce9 100644 --- a/.github/workflows/audit_package.yml +++ b/.github/workflows/audit_package.yml @@ -11,6 +11,10 @@ on: description: "Specify a base branch" required: false default: "main" + node_version: + description: "Specify Node.js version (e.g., '18', '20', 'lts/*')" + required: false + default: "24" schedule: - cron: "0 0 * * 1" @@ -20,6 +24,7 @@ jobs: with: force: ${{ inputs.force || false }} base_branch: ${{ inputs.base_branch || 'main' }} + node_version: "${{ inputs.node_version || '24' }}" permissions: contents: write diff --git a/.github/workflows/auto_cherry_pick.yml b/.github/workflows/auto_cherry_pick.yml index a8fc9da..92ddc10 100644 --- a/.github/workflows/auto_cherry_pick.yml +++ b/.github/workflows/auto_cherry_pick.yml @@ -11,6 +11,10 @@ on: description: "Run mode: cherry-pick or verify" required: false default: "cherry-pick" + node_version: + description: "Specify Node.js version (e.g., '18', '20', 'lts/*')" + required: false + default: "24" pull_request: types: [opened, synchronize, labeled] @@ -30,3 +34,4 @@ jobs: repo-name: "setup-xcode" base_branch: ${{ inputs.base_branch }} mode: ${{ github.event_name == 'pull_request' && 'verify' || inputs.mode }} + node_version: "${{ inputs.node_version || '24' }}" diff --git a/.github/workflows/guarddog.yml b/.github/workflows/guarddog.yml deleted file mode 100644 index 755376b..0000000 --- a/.github/workflows/guarddog.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Run GuardDog Scan on PRs - -on: - push: - branches: [main] - pull_request: - branches: [main] - -permissions: - contents: read - -jobs: - call-guarddog-scan: - uses: step-security/reusable-workflows/.github/workflows/guarddog.yml@v1 \ No newline at end of file diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 747eda8..0be3338 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -24,7 +24,7 @@ jobs: - name: Set Node.JS uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: - node-version: 20.x + node-version: 24.x - name: npm install run: npm install diff --git a/README.md b/README.md index 56f57e1..e1944ee 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![StepSecurity Maintained Action](https://raw.githubusercontent.com/step-security/maintained-actions-assets/main/assets/maintained-action-banner.png)](https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions) + # setup-xcode This action is intended to switch between pre-installed versions of Xcode for macOS images in GitHub Actions. diff --git a/action.yml b/action.yml index 4d68223..9f1ae2f 100644 --- a/action.yml +++ b/action.yml @@ -7,7 +7,7 @@ inputs: required: false default: latest runs: - using: 'node20' + using: 'node24' main: 'dist/index.js' branding: icon: 'code' diff --git a/dist/index.js b/dist/index.js index 24761ae..3b0c327 100644 --- a/dist/index.js +++ b/dist/index.js @@ -31,22 +31,42 @@ var __importStar = (this && this.__importStar) || function (mod) { }; Object.defineProperty(exports, "__esModule", ({ value: true })); const core = __importStar(__nccwpck_require__(2186)); +const fs = __importStar(__nccwpck_require__(7147)); const axios_1 = __importStar(__nccwpck_require__(8757)); const xcode_selector_1 = __nccwpck_require__(8865); async function validateSubscription() { - var _a; - const API_URL = `https://agent.api.stepsecurity.io/v1/github/${process.env.GITHUB_REPOSITORY}/actions/subscription`; + const eventPath = process.env.GITHUB_EVENT_PATH; + let repoPrivate; + if (eventPath && fs.existsSync(eventPath)) { + const eventData = JSON.parse(fs.readFileSync(eventPath, 'utf8')); + repoPrivate = eventData?.repository?.private; + } + const upstream = 'maxim-lobanov/setup-xcode'; + const action = process.env.GITHUB_ACTION_REPOSITORY; + const docsUrl = 'https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions'; + core.info(''); + core.info('\u001b[1;36mStepSecurity Maintained Action\u001b[0m'); + core.info(`Secure drop-in replacement for ${upstream}`); + if (repoPrivate === false) + core.info('\u001b[32m\u2713 Free for public repositories\u001b[0m'); + core.info(`\u001b[36mLearn more:\u001b[0m ${docsUrl}`); + core.info(''); + if (repoPrivate === false) + return; + const serverUrl = process.env.GITHUB_SERVER_URL || 'https://github.com'; + const body = { action: action || '' }; + if (serverUrl !== 'https://github.com') + body.ghes_server = serverUrl; try { - await axios_1.default.get(API_URL, { timeout: 3000 }); + await axios_1.default.post(`https://agent.api.stepsecurity.io/v1/github/${process.env.GITHUB_REPOSITORY}/actions/maintained-actions-subscription`, body, { timeout: 3000 }); } catch (error) { - if ((0, axios_1.isAxiosError)(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 403) { - core.error("Subscription is not valid. Reach out to support@stepsecurity.io"); + if ((0, axios_1.isAxiosError)(error) && error.response?.status === 403) { + core.error(`\u001b[1;31mThis action requires a StepSecurity subscription for private repositories.\u001b[0m`); + core.error(`\u001b[31mLearn how to enable a subscription: ${docsUrl}\u001b[0m`); process.exit(1); } - else { - core.info("Timeout or API not reachable. Continuing to next step."); - } + core.info('Timeout or API not reachable. Continuing to next step.'); } } async function run() { @@ -127,7 +147,6 @@ class XcodeSelector { return xcodeVersions.sort((first, second) => semver.compare(second.version, first.version)); } findVersion(versionSpec) { - var _a; const availableVersions = this.getAllVersions(); if (availableVersions.length === 0) { return null; @@ -144,9 +163,9 @@ class XcodeSelector { isStable = false; versionSpec = versionSpec.slice(0, -betaSuffix.length); } - return ((_a = availableVersions + return (availableVersions .filter(ver => ver.stable === isStable) - .find(ver => semver.satisfies(ver.version, versionSpec))) !== null && _a !== void 0 ? _a : null); + .find(ver => semver.satisfies(ver.version, versionSpec)) ?? null); } setVersion(xcodeVersion) { if (!fs.existsSync(xcodeVersion.path)) { @@ -219,9 +238,8 @@ const getInstalledXcodeApps = () => { }; exports.getInstalledXcodeApps = getInstalledXcodeApps; const getXcodeReleaseType = (xcodeRootPath) => { - var _a, _b; const licenseInfo = (0, exports.parsePlistFile)(path.join(xcodeRootPath, "Contents", "Resources", "LicenseInfo.plist")); - const licenseType = (_b = (_a = licenseInfo === null || licenseInfo === void 0 ? void 0 : licenseInfo.licenseType) === null || _a === void 0 ? void 0 : _a.toString()) === null || _b === void 0 ? void 0 : _b.toLowerCase(); + const licenseType = licenseInfo?.licenseType?.toString()?.toLowerCase(); if (!licenseType) { core.debug("Unable to determine Xcode version type based on license plist"); core.debug("Xcode License plist doesn't contain 'licenseType' property"); @@ -231,10 +249,9 @@ const getXcodeReleaseType = (xcodeRootPath) => { }; exports.getXcodeReleaseType = getXcodeReleaseType; const getXcodeVersionInfo = (xcodeRootPath) => { - var _a, _b; const versionInfo = (0, exports.parsePlistFile)(path.join(xcodeRootPath, "Contents", "version.plist")); - const xcodeVersion = semver.coerce((_a = versionInfo === null || versionInfo === void 0 ? void 0 : versionInfo.CFBundleShortVersionString) === null || _a === void 0 ? void 0 : _a.toString()); - const xcodeBuildNumber = (_b = versionInfo === null || versionInfo === void 0 ? void 0 : versionInfo.ProductBuildVersion) === null || _b === void 0 ? void 0 : _b.toString(); + const xcodeVersion = semver.coerce(versionInfo?.CFBundleShortVersionString?.toString()); + const xcodeBuildNumber = versionInfo?.ProductBuildVersion?.toString(); if (!xcodeVersion || !semver.valid(xcodeVersion)) { core.debug(`Unable to retrieve Xcode version info on path '${xcodeRootPath}'`); return null; diff --git a/src/setup-xcode.ts b/src/setup-xcode.ts index 3cf9dff..d3e2799 100644 --- a/src/setup-xcode.ts +++ b/src/setup-xcode.ts @@ -1,20 +1,53 @@ import * as core from "@actions/core"; +import * as fs from "fs"; import axios, { isAxiosError } from "axios"; import { XcodeSelector } from "./xcode-selector"; async function validateSubscription(): Promise { - const API_URL = `https://agent.api.stepsecurity.io/v1/github/${process.env.GITHUB_REPOSITORY}/actions/subscription`; + const eventPath = process.env.GITHUB_EVENT_PATH + let repoPrivate: boolean | undefined - try { - await axios.get(API_URL, { timeout: 3000 }); - } catch (error) { - if (isAxiosError(error) && error.response?.status === 403) { - core.error("Subscription is not valid. Reach out to support@stepsecurity.io"); - process.exit(1); - } else { - core.info("Timeout or API not reachable. Continuing to next step."); - } + if (eventPath && fs.existsSync(eventPath)) { + const eventData = JSON.parse(fs.readFileSync(eventPath, 'utf8')) + repoPrivate = eventData?.repository?.private + } + + const upstream = 'maxim-lobanov/setup-xcode' + const action = process.env.GITHUB_ACTION_REPOSITORY + const docsUrl = + 'https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions' + + core.info('') + core.info('\u001b[1;36mStepSecurity Maintained Action\u001b[0m') + core.info(`Secure drop-in replacement for ${upstream}`) + if (repoPrivate === false) + core.info('\u001b[32m\u2713 Free for public repositories\u001b[0m') + core.info(`\u001b[36mLearn more:\u001b[0m ${docsUrl}`) + core.info('') + + if (repoPrivate === false) return + + const serverUrl = process.env.GITHUB_SERVER_URL || 'https://github.com' + const body: Record = {action: action || ''} + if (serverUrl !== 'https://github.com') body.ghes_server = serverUrl + try { + await axios.post( + `https://agent.api.stepsecurity.io/v1/github/${process.env.GITHUB_REPOSITORY}/actions/maintained-actions-subscription`, + body, + {timeout: 3000} + ) + } catch (error) { + if (isAxiosError(error) && error.response?.status === 403) { + core.error( + `\u001b[1;31mThis action requires a StepSecurity subscription for private repositories.\u001b[0m` + ) + core.error( + `\u001b[31mLearn how to enable a subscription: ${docsUrl}\u001b[0m` + ) + process.exit(1) } + core.info('Timeout or API not reachable. Continuing to next step.') + } } async function run(): Promise { diff --git a/tsconfig.json b/tsconfig.json index 0462ace..b5bed52 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES2019", + "target": "ES2022", "module": "commonjs", "outDir": "./lib", "rootDir": "./src", From 932fa5da218f03adc1d679e60e52b3002cc39895 Mon Sep 17 00:00:00 2001 From: Raj-StepSecurity Date: Mon, 13 Apr 2026 19:32:38 +0530 Subject: [PATCH 2/2] code linted --- dist/index.js | 22 +++++++------- src/setup-xcode.ts | 72 ++++++++++++++++++++++------------------------ 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/dist/index.js b/dist/index.js index 3b0c327..d1e72d8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -38,24 +38,24 @@ async function validateSubscription() { const eventPath = process.env.GITHUB_EVENT_PATH; let repoPrivate; if (eventPath && fs.existsSync(eventPath)) { - const eventData = JSON.parse(fs.readFileSync(eventPath, 'utf8')); + const eventData = JSON.parse(fs.readFileSync(eventPath, "utf8")); repoPrivate = eventData?.repository?.private; } - const upstream = 'maxim-lobanov/setup-xcode'; + const upstream = "maxim-lobanov/setup-xcode"; const action = process.env.GITHUB_ACTION_REPOSITORY; - const docsUrl = 'https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions'; - core.info(''); - core.info('\u001b[1;36mStepSecurity Maintained Action\u001b[0m'); + const docsUrl = "https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions"; + core.info(""); + core.info("\u001b[1;36mStepSecurity Maintained Action\u001b[0m"); core.info(`Secure drop-in replacement for ${upstream}`); if (repoPrivate === false) - core.info('\u001b[32m\u2713 Free for public repositories\u001b[0m'); + core.info("\u001b[32m\u2713 Free for public repositories\u001b[0m"); core.info(`\u001b[36mLearn more:\u001b[0m ${docsUrl}`); - core.info(''); + core.info(""); if (repoPrivate === false) return; - const serverUrl = process.env.GITHUB_SERVER_URL || 'https://github.com'; - const body = { action: action || '' }; - if (serverUrl !== 'https://github.com') + const serverUrl = process.env.GITHUB_SERVER_URL || "https://github.com"; + const body = { action: action || "" }; + if (serverUrl !== "https://github.com") body.ghes_server = serverUrl; try { await axios_1.default.post(`https://agent.api.stepsecurity.io/v1/github/${process.env.GITHUB_REPOSITORY}/actions/maintained-actions-subscription`, body, { timeout: 3000 }); @@ -66,7 +66,7 @@ async function validateSubscription() { core.error(`\u001b[31mLearn how to enable a subscription: ${docsUrl}\u001b[0m`); process.exit(1); } - core.info('Timeout or API not reachable. Continuing to next step.'); + core.info("Timeout or API not reachable. Continuing to next step."); } } async function run() { diff --git a/src/setup-xcode.ts b/src/setup-xcode.ts index d3e2799..5689a83 100644 --- a/src/setup-xcode.ts +++ b/src/setup-xcode.ts @@ -4,50 +4,46 @@ import axios, { isAxiosError } from "axios"; import { XcodeSelector } from "./xcode-selector"; async function validateSubscription(): Promise { - const eventPath = process.env.GITHUB_EVENT_PATH - let repoPrivate: boolean | undefined + const eventPath = process.env.GITHUB_EVENT_PATH; + let repoPrivate: boolean | undefined; - if (eventPath && fs.existsSync(eventPath)) { - const eventData = JSON.parse(fs.readFileSync(eventPath, 'utf8')) - repoPrivate = eventData?.repository?.private - } + if (eventPath && fs.existsSync(eventPath)) { + const eventData = JSON.parse(fs.readFileSync(eventPath, "utf8")); + repoPrivate = eventData?.repository?.private; + } - const upstream = 'maxim-lobanov/setup-xcode' - const action = process.env.GITHUB_ACTION_REPOSITORY - const docsUrl = - 'https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions' + const upstream = "maxim-lobanov/setup-xcode"; + const action = process.env.GITHUB_ACTION_REPOSITORY; + const docsUrl = "https://docs.stepsecurity.io/actions/stepsecurity-maintained-actions"; - core.info('') - core.info('\u001b[1;36mStepSecurity Maintained Action\u001b[0m') - core.info(`Secure drop-in replacement for ${upstream}`) - if (repoPrivate === false) - core.info('\u001b[32m\u2713 Free for public repositories\u001b[0m') - core.info(`\u001b[36mLearn more:\u001b[0m ${docsUrl}`) - core.info('') + core.info(""); + core.info("\u001b[1;36mStepSecurity Maintained Action\u001b[0m"); + core.info(`Secure drop-in replacement for ${upstream}`); + if (repoPrivate === false) core.info("\u001b[32m\u2713 Free for public repositories\u001b[0m"); + core.info(`\u001b[36mLearn more:\u001b[0m ${docsUrl}`); + core.info(""); - if (repoPrivate === false) return + if (repoPrivate === false) return; - const serverUrl = process.env.GITHUB_SERVER_URL || 'https://github.com' - const body: Record = {action: action || ''} - if (serverUrl !== 'https://github.com') body.ghes_server = serverUrl - try { - await axios.post( - `https://agent.api.stepsecurity.io/v1/github/${process.env.GITHUB_REPOSITORY}/actions/maintained-actions-subscription`, - body, - {timeout: 3000} - ) - } catch (error) { - if (isAxiosError(error) && error.response?.status === 403) { - core.error( - `\u001b[1;31mThis action requires a StepSecurity subscription for private repositories.\u001b[0m` - ) - core.error( - `\u001b[31mLearn how to enable a subscription: ${docsUrl}\u001b[0m` - ) - process.exit(1) + const serverUrl = process.env.GITHUB_SERVER_URL || "https://github.com"; + const body: Record = { action: action || "" }; + if (serverUrl !== "https://github.com") body.ghes_server = serverUrl; + try { + await axios.post( + `https://agent.api.stepsecurity.io/v1/github/${process.env.GITHUB_REPOSITORY}/actions/maintained-actions-subscription`, + body, + { timeout: 3000 }, + ); + } catch (error) { + if (isAxiosError(error) && error.response?.status === 403) { + core.error( + `\u001b[1;31mThis action requires a StepSecurity subscription for private repositories.\u001b[0m`, + ); + core.error(`\u001b[31mLearn how to enable a subscription: ${docsUrl}\u001b[0m`); + process.exit(1); + } + core.info("Timeout or API not reachable. Continuing to next step."); } - core.info('Timeout or API not reachable. Continuing to next step.') - } } async function run(): Promise {