diff --git a/README.md b/README.md index 7fd12f7..c6ce147 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,8 @@ jobs: report-config: issues.yaml ``` + + **GitHub Example Action running Nuclei with GitHub Issue reporting** Setting permissions for `GITHUB_TOKEN`, according to the [github actions docs](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token). @@ -130,6 +132,42 @@ permissions: github-token: ${{ secrets.GITHUB_TOKEN }} ``` +Using the `github-report` creates a default configuration to enable reporting to Github Issues + + +**GitHub Example Action running Nuclei with custom GitHub Issue reporting** + +```yaml + - name: Nuclei - Vulnerability Scan + uses: projectdiscovery/nuclei-action@main + with: + target: https://example.com + report-config: github-issue-config.yaml + github-token: ${{ secrets.GITHUB_TOKEN }} +``` + +Create a `yaml` file to define the nuclei github issue reporting behavior: + +```yaml +github: + duplicate-issue-check: true + severity-as-label: true + issue-label: '' +``` + +The `nuclie-action` will fill in the repository settings into the custom configuration. The file don't need to be augmented with these information manually. + +```yaml +github: + username: GITHUB_ACTOR, + owner: GITHUB_REPOSITORY_OWNER, + token, + "project-name": GITHUB_REPOSITORY, +``` + + + + **GitHub Example Action running Nuclei with GitHub Security Dashboard reporting** ```yaml diff --git a/dist/index.js b/dist/index.js index 84201e6..a514ed8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -10747,24 +10747,35 @@ const GITHUB_REPOSITORY_OWNER = process.env.GITHUB_REPOSITORY_OWNER; const GITHUB_REPOSITORY = process.env.GITHUB_REPOSITORY.replace(`${GITHUB_REPOSITORY_OWNER}/`, ''); const GITHUB_WORKSPACE = process.env.GITHUB_WORKSPACE; -async function generateGithubReportFile(token) { - const content = { - "github" : { - "username": GITHUB_ACTOR, - "owner": GITHUB_REPOSITORY_OWNER, - token, - "project-name": GITHUB_REPOSITORY, - "issue-label": "Nuclei Report" - } +async function generateGithubReportFile(token, reportConfigFileName = 'github-report.yaml') { + const gitHubRepoConfig = { + username: GITHUB_ACTOR, + owner: GITHUB_REPOSITORY_OWNER, + token, + "project-name": GITHUB_REPOSITORY, + }; + + let content = {}; + + if (reportConfigFileName) { + try { + const data = await external_fs_.promises.readFile(external_path_.join(GITHUB_WORKSPACE, reportConfigFileName), 'utf8'); + const { github, ...rest } = load(data); + content = { ...rest, github: { ...gitHubRepoConfig, ...github } }; + } catch (err) { + throw new Error(`Error reading the passed report config file: ${err.message}`); } - const githubConfigYml = dump(content, { - flowLevel: 3 - }); + } else { + content.github = gitHubRepoConfig; + } - external_fs_.writeFileSync(external_path_.join(GITHUB_WORKSPACE, 'github-report.yaml'), githubConfigYml, err => { - if (err) - reject(err); - }); + const githubConfigYml = dump(content, { flowLevel: 3 }); + + try { + await external_fs_.promises.writeFile(external_path_.join(GITHUB_WORKSPACE, reportConfigFileName), githubConfigYml); + } catch (err) { + throw new Error(`Error writing the report config file: ${err.message}`); + } } ;// CONCATENATED MODULE: ./src/utils.js function parseFlagsToArray(rawFlags) { @@ -10813,9 +10824,9 @@ options.listeners = { }; async function run() { - try { - // download and install - const binPath = await downloadAndInstall(nucleiVersion); + try { + // download and install + const binPath = await downloadAndInstall(nucleiVersion); const params = []; if (!target && !urls) { @@ -10831,17 +10842,16 @@ async function run() { new URL(templates) params.push(`-turl=${templates}`); } - catch(_) { + catch (_) { params.push(`-t=${templates}`); } } if (workflows) params.push(`-w=${workflows}`); params.push(`-se=${sarifExport ? sarifExport : 'nuclei.sarif'}`); if (markdownExport) params.push(`-me=${markdownExport}`); - if (reportConfig) params.push(`-rc=${reportConfig}`); if (config) params.push(`-config=${config}`); if (userAgent) params.push(`-H=${userAgent}`); - params.push(`-o=${ output ? output : 'nuclei.log' }`); + params.push(`-o=${output ? output : 'nuclei.log'}`); if (src_json) params.push('-json'); if (includeRR) params.push('-irr'); if (omitRaw) params.push('-or'); @@ -10849,17 +10859,21 @@ async function run() { if (flags) params.push(...parseFlagsToArray(flags)); // If everything is fine and github-report is set, generate the yaml config file. - if (githubReport) { + if (githubReport == true) { + // create default config file with name `github-report.yaml` await generateGithubReportFile(githubToken); params.push(`-rc=github-report.yaml`); + } else if (reportConfig != null) { + await generateGithubReportFile(githubToken, reportConfig); + params.push(`-rc=${reportConfig}`); } - // run tool + // run tool delete process.env.GITHUB_TOKEN exec.exec(binPath, params, options); - } catch (error) { - core.setFailed(error.message); - } + } catch (error) { + core.setFailed(error.message); + } } run(); diff --git a/src/index.js b/src/index.js index 62bc11f..1b26234 100644 --- a/src/index.js +++ b/src/index.js @@ -39,9 +39,9 @@ options.listeners = { }; async function run() { - try { - // download and install - const binPath = await installer.downloadAndInstall(nucleiVersion); + try { + // download and install + const binPath = await installer.downloadAndInstall(nucleiVersion); const params = []; if (!target && !urls) { @@ -57,17 +57,16 @@ async function run() { new URL(templates) params.push(`-turl=${templates}`); } - catch(_) { + catch (_) { params.push(`-t=${templates}`); } } if (workflows) params.push(`-w=${workflows}`); params.push(`-se=${sarifExport ? sarifExport : 'nuclei.sarif'}`); if (markdownExport) params.push(`-me=${markdownExport}`); - if (reportConfig) params.push(`-rc=${reportConfig}`); if (config) params.push(`-config=${config}`); if (userAgent) params.push(`-H=${userAgent}`); - params.push(`-o=${ output ? output : 'nuclei.log' }`); + params.push(`-o=${output ? output : 'nuclei.log'}`); if (json) params.push('-json'); if (includeRR) params.push('-irr'); if (omitRaw) params.push('-or'); @@ -75,17 +74,21 @@ async function run() { if (flags) params.push(...parseFlagsToArray(flags)); // If everything is fine and github-report is set, generate the yaml config file. - if (githubReport) { + if (githubReport == true) { + // create default config file with name `github-report.yaml` await generateGithubReportFile(githubToken); params.push(`-rc=github-report.yaml`); + } else if (reportConfig != null) { + await generateGithubReportFile(githubToken, reportConfig); + params.push(`-rc=${reportConfig}`); } - // run tool + // run tool delete process.env.GITHUB_TOKEN exec.exec(binPath, params, options); - } catch (error) { - core.setFailed(error.message); - } + } catch (error) { + core.setFailed(error.message); + } } run(); diff --git a/src/yaml.js b/src/yaml.js index 3b7ed9b..d148a50 100644 --- a/src/yaml.js +++ b/src/yaml.js @@ -7,22 +7,33 @@ const GITHUB_REPOSITORY_OWNER = process.env.GITHUB_REPOSITORY_OWNER; const GITHUB_REPOSITORY = process.env.GITHUB_REPOSITORY.replace(`${GITHUB_REPOSITORY_OWNER}/`, ''); const GITHUB_WORKSPACE = process.env.GITHUB_WORKSPACE; -export async function generateGithubReportFile(token) { - const content = { - "github" : { - "username": GITHUB_ACTOR, - "owner": GITHUB_REPOSITORY_OWNER, - token, - "project-name": GITHUB_REPOSITORY, - "issue-label": "Nuclei Report" - } +export async function generateGithubReportFile(token, reportConfigFileName = 'github-report.yaml') { + const gitHubRepoConfig = { + username: GITHUB_ACTOR, + owner: GITHUB_REPOSITORY_OWNER, + token, + "project-name": GITHUB_REPOSITORY, + }; + + let content = {}; + + if (reportConfigFileName) { + try { + const data = await fs.promises.readFile(path.join(GITHUB_WORKSPACE, reportConfigFileName), 'utf8'); + const { github, ...rest } = yaml.load(data); + content = { ...rest, github: { ...gitHubRepoConfig, ...github } }; + } catch (err) { + throw new Error(`Error reading the passed report config file: ${err.message}`); } - const githubConfigYml = yaml.dump(content, { - flowLevel: 3 - }); + } else { + content.github = gitHubRepoConfig; + } + + const githubConfigYml = yaml.dump(content, { flowLevel: 3 }); - fs.writeFileSync(path.join(GITHUB_WORKSPACE, 'github-report.yaml'), githubConfigYml, err => { - if (err) - reject(err); - }); + try { + await fs.promises.writeFile(path.join(GITHUB_WORKSPACE, reportConfigFileName), githubConfigYml); + } catch (err) { + throw new Error(`Error writing the report config file: ${err.message}`); + } } \ No newline at end of file