diff --git a/.env.sample b/.env.sample index 4e30c45..f2af8a1 100644 --- a/.env.sample +++ b/.env.sample @@ -1,5 +1,5 @@ TOKEN=ghp_TKN -LEVEL=organization # repository, organization +LEVEL=organization_only # repository_only, organization_only, or organization_and_repository REPO=repo-name ORG=org-name DEBUG=true diff --git a/README.md b/README.md index 78f44c9..5b8a4bf 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ npm install Create a `.env` file by using our sample configuration file `.env.sample`: ```text TOKEN=ghp_TKN -LEVEL=repository +LEVEL=repository_only # repository_only, organization_only, or organization_and_repository REPO=repo-name ORG=org-name DEBUG=false @@ -65,8 +65,9 @@ POLICIES_PATH=policies ``` where `LEVEL` is the scope of the checks: -- `repository` for repository-level checks -- `organization` for organization-level checks +- `repository_only` for repository-level checks +- `organization_only` for organization-level checks +- `organization_and_repository` for organization-level and repositorty_level checks for all the repos in the organization Next, generate a Personal Access Token (PAT) from GitHub and input your settings into the `.env` file. Ensure your token has these permissions: - `repo: admin` @@ -120,7 +121,7 @@ jobs: repo: ${{ github.repository }} org: ${{ github.repository_owner }} token: ${{ TOKEN }} - level: 'organization' + level: 'organization_only' policy-dir: './policies' ``` diff --git a/dist/index.js b/dist/index.js index 1620159..c1c7b06 100644 --- a/dist/index.js +++ b/dist/index.js @@ -49511,6 +49511,7 @@ const run = async () => { by dcodx.com - version 1.0 `); + // Adjusted part of the run function try { const startTime = process.hrtime(); const inputs = (0, Input_1.parseInputs)(); @@ -49519,13 +49520,33 @@ const run = async () => { let report = new Report_1.Report(); report.addInput(inputs); report.addPolicy(policies); - // depending on which input.level is provided, run the appropriate checks - if (inputs.level === "organization") { - Logger_1.logger.info("Running org level checks"); + if (inputs.level === "organization_only") { + Logger_1.logger.info("Running organization level checks only"); const organizationPolicyEvaluator = new OrgPolicyEvaluator_1.OrgPolicyEvaluator(inputs.org, policies.org); await organizationPolicyEvaluator.evaluatePolicy(); organizationPolicyEvaluator.printCheckResults(); report.addOrgEvaluator(organizationPolicyEvaluator); + } + else if (inputs.level === "repository_only") { + Logger_1.logger.info("Running repository level checks only"); + const repository = { + name: inputs.repo, + owner: inputs.org, + }; + const repoPolicyEvaluator = new RepoPolicyEvaluator_1.RepoPolicyEvaluator(repository, policies.repo); + await repoPolicyEvaluator.evaluatePolicy(); + repoPolicyEvaluator.printCheckResults(); + report.addOneRepoEvaluator(repoPolicyEvaluator); + } + else if (inputs.level === "organization_and_repository") { + Logger_1.logger.info("Running both organization and repository level checks"); + Logger_1.logger.warn("⚠️ Running the tool with 'organization_and_repository' level might trigger the GitHub API rate limit. Please use it with caution."); + // Organization checks + const organizationPolicyEvaluator = new OrgPolicyEvaluator_1.OrgPolicyEvaluator(inputs.org, policies.org); + await organizationPolicyEvaluator.evaluatePolicy(); + organizationPolicyEvaluator.printCheckResults(); + report.addOrgEvaluator(organizationPolicyEvaluator); + // Repository checks within the organization const repos = await (0, Organization_1.getRepositoriesForOrg)(inputs.org); Logger_1.logger.info("Total Repos: " + repos.length); await Promise.all(repos.map(async (repo) => { @@ -49539,20 +49560,8 @@ const run = async () => { report.addRepoEvaluatorToOrg(organizationPolicyEvaluator, repoPolicyEvaluator); })); } - else if (inputs.level === "repository") { - const repository = { - name: inputs.repo, - owner: inputs.org, - }; - Logger_1.logger.info("Running repo level checks"); - const policyEvaluator = new RepoPolicyEvaluator_1.RepoPolicyEvaluator(repository, policies.repo); - await policyEvaluator.evaluatePolicy(); - policyEvaluator.printCheckResults(); - report.addOneRepoEvaluator(policyEvaluator); - } else { - // TODO: Implement enterprise level checks - Logger_1.logger.info("Running enterprise level checks => Not implemented yet"); + Logger_1.logger.info("Invalid level specified"); } report.prepareReports(); report.writeReportToFile(); @@ -49647,15 +49656,28 @@ class Report { let jsonReport = {}; // Evaluation section report += "## 📑 Detailed Evaluation Findings \n\n"; - if (this.inputs.level === "repository") { + if (this.inputs.level === "repository_only") { report += "### 📁 Repository Evaluator\n\n"; report += this.formatRepoEvaluator(this.repoEvaluator); - jsonReport.repoEvalator = this.repoEvaluator; + jsonReport.repoEvaluator = this.repoEvaluator; // Corrected typo from 'repoEvalator' to 'repoEvaluator' + } + else if (this.inputs.level === "organization_only") { + report += "### 🏢 Organization Evaluator\n\n"; + this.orgEvaluators.forEach((repoEvaluators, orgEvaluator) => { + report += this.formatOrgEvaluator(orgEvaluator, repoEvaluators); + }); + const orgEvaluatorsJson = Array.from(this.orgEvaluators.entries()).map(([orgEvaluator]) => ({ + orgEvaluator: JSON.stringify(orgEvaluator), + })); + jsonReport.orgEvaluators = orgEvaluatorsJson; } - else if (this.inputs.level === "organization") { - report += `### 🏢 Organization Evaluator\n\n`; + else if (this.inputs.level === "organization_and_repository") { + report += "### 🏢 Organization Evaluator\n\n"; this.orgEvaluators.forEach((repoEvaluators, orgEvaluator) => { report += this.formatOrgEvaluator(orgEvaluator, repoEvaluators); + repoEvaluators.forEach((repoEvaluator) => { + report += this.formatRepoEvaluator(repoEvaluator); + }); }); const orgEvaluatorsJson = Array.from(this.orgEvaluators.entries()).map(([orgEvaluator, repoEvaluators]) => ({ orgEvaluator: JSON.stringify(orgEvaluator), @@ -49819,13 +49841,19 @@ const loadPolicy = async (inputs) => { let policy = {}; try { Logger_1.logger.debug(`Loading policies from: ${inputs.policy_dir}`); - if (inputs.level === "organization") { + if (inputs.level === "organization_only") { const orgPolicyFile = fs_1.default.readFileSync(path_1.default.join(inputs.policy_dir, "organization.yml"), "utf8"); policy.org = js_yaml_1.default.load(orgPolicyFile); + } + else if (inputs.level === "repository_only") { const repoPolicyFile = fs_1.default.readFileSync(path_1.default.join(inputs.policy_dir, "repository.yml"), "utf8"); policy.repo = js_yaml_1.default.load(repoPolicyFile); } - else if (inputs.level === "repository") { + else if (inputs.level === "organization_and_repository") { + // Load organization policy + const orgPolicyFile = fs_1.default.readFileSync(path_1.default.join(inputs.policy_dir, "organization.yml"), "utf8"); + policy.org = js_yaml_1.default.load(orgPolicyFile); + // Load repository policy const repoPolicyFile = fs_1.default.readFileSync(path_1.default.join(inputs.policy_dir, "repository.yml"), "utf8"); policy.repo = js_yaml_1.default.load(repoPolicyFile); } diff --git a/dist/main.js b/dist/main.js index d2d4db5..00d19f0 100644 --- a/dist/main.js +++ b/dist/main.js @@ -38,6 +38,7 @@ const run = async () => { by dcodx.com - version 1.0 `); + // Adjusted part of the run function try { const startTime = process.hrtime(); const inputs = (0, Input_1.parseInputs)(); @@ -46,13 +47,33 @@ const run = async () => { let report = new Report_1.Report(); report.addInput(inputs); report.addPolicy(policies); - // depending on which input.level is provided, run the appropriate checks - if (inputs.level === "organization") { - Logger_1.logger.info("Running org level checks"); + if (inputs.level === "organization_only") { + Logger_1.logger.info("Running organization level checks only"); const organizationPolicyEvaluator = new OrgPolicyEvaluator_1.OrgPolicyEvaluator(inputs.org, policies.org); await organizationPolicyEvaluator.evaluatePolicy(); organizationPolicyEvaluator.printCheckResults(); report.addOrgEvaluator(organizationPolicyEvaluator); + } + else if (inputs.level === "repository_only") { + Logger_1.logger.info("Running repository level checks only"); + const repository = { + name: inputs.repo, + owner: inputs.org, + }; + const repoPolicyEvaluator = new RepoPolicyEvaluator_1.RepoPolicyEvaluator(repository, policies.repo); + await repoPolicyEvaluator.evaluatePolicy(); + repoPolicyEvaluator.printCheckResults(); + report.addOneRepoEvaluator(repoPolicyEvaluator); + } + else if (inputs.level === "organization_and_repository") { + Logger_1.logger.info("Running both organization and repository level checks"); + Logger_1.logger.warn("⚠️ Running the tool with 'organization_and_repository' level might trigger the GitHub API rate limit. Please use it with caution."); + // Organization checks + const organizationPolicyEvaluator = new OrgPolicyEvaluator_1.OrgPolicyEvaluator(inputs.org, policies.org); + await organizationPolicyEvaluator.evaluatePolicy(); + organizationPolicyEvaluator.printCheckResults(); + report.addOrgEvaluator(organizationPolicyEvaluator); + // Repository checks within the organization const repos = await (0, Organization_1.getRepositoriesForOrg)(inputs.org); Logger_1.logger.info("Total Repos: " + repos.length); await Promise.all(repos.map(async (repo) => { @@ -66,20 +87,8 @@ const run = async () => { report.addRepoEvaluatorToOrg(organizationPolicyEvaluator, repoPolicyEvaluator); })); } - else if (inputs.level === "repository") { - const repository = { - name: inputs.repo, - owner: inputs.org, - }; - Logger_1.logger.info("Running repo level checks"); - const policyEvaluator = new RepoPolicyEvaluator_1.RepoPolicyEvaluator(repository, policies.repo); - await policyEvaluator.evaluatePolicy(); - policyEvaluator.printCheckResults(); - report.addOneRepoEvaluator(policyEvaluator); - } else { - // TODO: Implement enterprise level checks - Logger_1.logger.info("Running enterprise level checks => Not implemented yet"); + Logger_1.logger.info("Invalid level specified"); } report.prepareReports(); report.writeReportToFile(); diff --git a/dist/reporting/Report.js b/dist/reporting/Report.js index d3073bc..64a4bc4 100644 --- a/dist/reporting/Report.js +++ b/dist/reporting/Report.js @@ -64,16 +64,29 @@ class Report { let jsonReport = {}; // Evaluation section report += "## 📑 Detailed Evaluation Findings \n\n"; - if (this.inputs.level === "repository") { + if (this.inputs.level === "repository_only") { report += "### 📁 Repository Evaluator\n\n"; report += this.formatRepoEvaluator(this.repoEvaluator); - jsonReport.repoEvalator = this.repoEvaluator; + jsonReport.repoEvaluator = this.repoEvaluator; // Corrected typo from 'repoEvalator' to 'repoEvaluator' } - else if (this.inputs.level === "organization") { - report += `### 🏢 Organization Evaluator\n\n`; + else if (this.inputs.level === "organization_only") { + report += "### 🏢 Organization Evaluator\n\n"; this.orgEvaluators.forEach((repoEvaluators, orgEvaluator) => { report += this.formatOrgEvaluator(orgEvaluator, repoEvaluators); }); + const orgEvaluatorsJson = Array.from(this.orgEvaluators.entries()).map(([orgEvaluator]) => ({ + orgEvaluator: JSON.stringify(orgEvaluator), + })); + jsonReport.orgEvaluators = orgEvaluatorsJson; + } + else if (this.inputs.level === "organization_and_repository") { + report += "### 🏢 Organization Evaluator\n\n"; + this.orgEvaluators.forEach((repoEvaluators, orgEvaluator) => { + report += this.formatOrgEvaluator(orgEvaluator, repoEvaluators); + repoEvaluators.forEach((repoEvaluator) => { + report += this.formatRepoEvaluator(repoEvaluator); + }); + }); const orgEvaluatorsJson = Array.from(this.orgEvaluators.entries()).map(([orgEvaluator, repoEvaluators]) => ({ orgEvaluator: JSON.stringify(orgEvaluator), repoEvaluators: repoEvaluators.map((repoEvaluator) => JSON.stringify(repoEvaluator)), diff --git a/dist/utils/policies.js b/dist/utils/policies.js index 670f3e4..133df0a 100644 --- a/dist/utils/policies.js +++ b/dist/utils/policies.js @@ -12,13 +12,19 @@ const loadPolicy = async (inputs) => { let policy = {}; try { Logger_1.logger.debug(`Loading policies from: ${inputs.policy_dir}`); - if (inputs.level === "organization") { + if (inputs.level === "organization_only") { const orgPolicyFile = fs_1.default.readFileSync(path_1.default.join(inputs.policy_dir, "organization.yml"), "utf8"); policy.org = js_yaml_1.default.load(orgPolicyFile); + } + else if (inputs.level === "repository_only") { const repoPolicyFile = fs_1.default.readFileSync(path_1.default.join(inputs.policy_dir, "repository.yml"), "utf8"); policy.repo = js_yaml_1.default.load(repoPolicyFile); } - else if (inputs.level === "repository") { + else if (inputs.level === "organization_and_repository") { + // Load organization policy + const orgPolicyFile = fs_1.default.readFileSync(path_1.default.join(inputs.policy_dir, "organization.yml"), "utf8"); + policy.org = js_yaml_1.default.load(orgPolicyFile); + // Load repository policy const repoPolicyFile = fs_1.default.readFileSync(path_1.default.join(inputs.policy_dir, "repository.yml"), "utf8"); policy.repo = js_yaml_1.default.load(repoPolicyFile); } diff --git a/src/main.ts b/src/main.ts index b525f51..d566dc0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -16,75 +16,66 @@ const run = async (): Promise => { `); + // Adjusted part of the run function try { const startTime = process.hrtime(); const inputs = parseInputs(); - const policies: any = await loadPolicy(inputs); + const policies: any = await loadPolicy(inputs); logger.debug("DEBUG MODE: " + inputs.debug); let report = new Report(); report.addInput(inputs); report.addPolicy(policies); - // depending on which input.level is provided, run the appropriate checks - if (inputs.level === "organization") { - logger.info("Running org level checks"); - - const organizationPolicyEvaluator = new OrgPolicyEvaluator( - inputs.org, - policies.org as OrgPolicy, - ); - + + if (inputs.level === "organization_only") { + logger.info("Running organization level checks only"); + const organizationPolicyEvaluator = new OrgPolicyEvaluator(inputs.org, policies.org as OrgPolicy); await organizationPolicyEvaluator.evaluatePolicy(); organizationPolicyEvaluator.printCheckResults(); report.addOrgEvaluator(organizationPolicyEvaluator); - - const repos = await getRepositoriesForOrg(inputs.org); - logger.info("Total Repos: " + repos.length); - await Promise.all( - repos.map(async (repo) => { - const repository: Repository = { - name: repo.name, - owner: inputs.org, - }; - const repoPolicyEvaluator = new RepoPolicyEvaluator( - repository, - policies.repo as RepoPolicy, - ); - await repoPolicyEvaluator.evaluatePolicy(); - repoPolicyEvaluator.printCheckResults(); - report.addRepoEvaluatorToOrg( - organizationPolicyEvaluator, - repoPolicyEvaluator, - ); - }), - ); - } else if (inputs.level === "repository") { + } else if (inputs.level === "repository_only") { + logger.info("Running repository level checks only"); const repository: Repository = { name: inputs.repo, owner: inputs.org, }; - logger.info("Running repo level checks"); - - const policyEvaluator = new RepoPolicyEvaluator( - repository, - policies.repo as RepoPolicy, - ); + const repoPolicyEvaluator = new RepoPolicyEvaluator(repository, policies.repo as RepoPolicy); + await repoPolicyEvaluator.evaluatePolicy(); + repoPolicyEvaluator.printCheckResults(); + report.addOneRepoEvaluator(repoPolicyEvaluator); + } else if (inputs.level === "organization_and_repository") { + logger.info("Running both organization and repository level checks"); + logger.warn("⚠️ Running the tool with 'organization_and_repository' level might trigger the GitHub API rate limit. Please use it with caution."); - await policyEvaluator.evaluatePolicy(); - policyEvaluator.printCheckResults(); - report.addOneRepoEvaluator(policyEvaluator); + // Organization checks + const organizationPolicyEvaluator = new OrgPolicyEvaluator(inputs.org, policies.org as OrgPolicy); + await organizationPolicyEvaluator.evaluatePolicy(); + organizationPolicyEvaluator.printCheckResults(); + report.addOrgEvaluator(organizationPolicyEvaluator); + // Repository checks within the organization + const repos = await getRepositoriesForOrg(inputs.org); + logger.info("Total Repos: " + repos.length); + await Promise.all(repos.map(async (repo) => { + const repository: Repository = { + name: repo.name, + owner: inputs.org, + }; + const repoPolicyEvaluator = new RepoPolicyEvaluator(repository, policies.repo as RepoPolicy); + await repoPolicyEvaluator.evaluatePolicy(); + repoPolicyEvaluator.printCheckResults(); + report.addRepoEvaluatorToOrg(organizationPolicyEvaluator, repoPolicyEvaluator); + })); } else { - // TODO: Implement enterprise level checks - logger.info("Running enterprise level checks => Not implemented yet"); + logger.info("Invalid level specified"); } - + report.prepareReports(); report.writeReportToFile(); if (process.env.GITHUB_ACTIONS) { core.setOutput("check-results-json", report.getReportJson()); core.setOutput("check-results-text", report.getReportText()); } - + const endTime = process.hrtime(startTime); logger.debug(`Execution time: ${endTime[0]}s ${endTime[1] / 1000000}ms`); } catch (error) { diff --git a/src/reporting/Report.ts b/src/reporting/Report.ts index a1c1408..67d3124 100644 --- a/src/reporting/Report.ts +++ b/src/reporting/Report.ts @@ -86,16 +86,29 @@ export class Report { // Evaluation section report += "## 📑 Detailed Evaluation Findings \n\n"; - if (this.inputs.level === "repository") { + if (this.inputs.level === "repository_only") { report += "### 📁 Repository Evaluator\n\n"; report += this.formatRepoEvaluator(this.repoEvaluator); - jsonReport.repoEvalator = this.repoEvaluator; - } else if (this.inputs.level === "organization") { - report += `### 🏢 Organization Evaluator\n\n`; + jsonReport.repoEvaluator = this.repoEvaluator; // Corrected typo from 'repoEvalator' to 'repoEvaluator' + } else if (this.inputs.level === "organization_only") { + report += "### 🏢 Organization Evaluator\n\n"; this.orgEvaluators.forEach((repoEvaluators, orgEvaluator) => { report += this.formatOrgEvaluator(orgEvaluator, repoEvaluators); }); + const orgEvaluatorsJson = Array.from(this.orgEvaluators.entries()).map(([orgEvaluator]) => ({ + orgEvaluator: JSON.stringify(orgEvaluator), + })); + jsonReport.orgEvaluators = orgEvaluatorsJson; + } else if (this.inputs.level === "organization_and_repository") { + report += "### 🏢 Organization Evaluator\n\n"; + this.orgEvaluators.forEach((repoEvaluators, orgEvaluator) => { + report += this.formatOrgEvaluator(orgEvaluator,repoEvaluators); + repoEvaluators.forEach((repoEvaluator) => { + report += this.formatRepoEvaluator(repoEvaluator); + }); + }); + const orgEvaluatorsJson = Array.from(this.orgEvaluators.entries()).map( ([orgEvaluator, repoEvaluators]) => ({ orgEvaluator: JSON.stringify(orgEvaluator), diff --git a/src/utils/policies.ts b/src/utils/policies.ts index d899c02..98a59af 100644 --- a/src/utils/policies.ts +++ b/src/utils/policies.ts @@ -8,26 +8,33 @@ export const loadPolicy = async (inputs: Inputs): Promise => { let policy: Policy = {}; try { logger.debug(`Loading policies from: ${inputs.policy_dir}`); - if (inputs.level === "organization") { + if (inputs.level === "organization_only") { const orgPolicyFile = fs.readFileSync( path.join(inputs.policy_dir, "organization.yml"), "utf8", ); policy.org = yaml.load(orgPolicyFile) as OrgPolicy; - + } else if (inputs.level === "repository_only") { const repoPolicyFile = fs.readFileSync( path.join(inputs.policy_dir, "repository.yml"), "utf8", ); policy.repo = yaml.load(repoPolicyFile) as RepoPolicy; - } else if (inputs.level === "repository") { + } else if (inputs.level === "organization_and_repository") { + // Load organization policy + const orgPolicyFile = fs.readFileSync( + path.join(inputs.policy_dir, "organization.yml"), + "utf8", + ); + policy.org = yaml.load(orgPolicyFile) as OrgPolicy; + // Load repository policy const repoPolicyFile = fs.readFileSync( path.join(inputs.policy_dir, "repository.yml"), "utf8", ); policy.repo = yaml.load(repoPolicyFile) as RepoPolicy; } - + logger.debug("Policy:"); logger.debug(yaml.dump(policy)); } catch (error) {