diff --git a/scripts/reportgenerator.js b/scripts/reportgenerator.js
deleted file mode 100644
index 93e8cce..0000000
--- a/scripts/reportgenerator.js
+++ /dev/null
@@ -1,657 +0,0 @@
-// n8n Code node (JavaScript)
-// Relatório HTML -> PDF (Gotenberg):
-// - Capa
-// - Purpose + Disclaimer juntos
-// - TOC em nova página (listando cada recomendação: "Rec — Title")
-// - Executive Summary em nova página (se existir)
-// - Findings Overview em nova página (tabela DOMAINS / TOTAL CONTROLS / FAILED / PASSED)
-// - Seções (cards): Asset Management começa em nova página
-//
-// Seções:
-// - "Logging and Monitoring1" -> "Logging and Monitoring"
-// - Remove seção "Storage" genérica; mantém apenas:
-// Storage - Block Volumes / Storage - File Storage Service / Storage - Object Storage
-//
-// Status:
-// - Compliant = Yes
-// - Non-compliant = tudo que NÃO for Yes (inclui Unknown)
-//
-// Deduplicação forte para evitar duplicatas vindas do fluxo/merge.
-//
-// Alteração pedida AGORA:
-// - Remove o valor que aparece logo abaixo do gráfico (ex.: "100%").
-// Ou seja: mantém o gráfico + o % dentro do próprio gráfico (lado esquerdo), mas remove a linha extra.
-
-const items = $input.all();
-
-// ====== INPUT SPLIT ======
-const summaryTexts = items
- .map(i => i.json?.output)
- .filter(v => typeof v === "string")
- .map(s => String(s).trim())
- .filter(Boolean);
-
-const allRowsRaw = items
- .map(i => i.json?.output)
- .filter(v => v && typeof v === "object" && !Array.isArray(v));
-
-// Ajuste se tenancyName vier em outro campo:
-const tenancyName = ($json?.tenancyName || $json?.tenancy || "Nome do Tenancy");
-const version = "1.0";
-
-// Texto fixo
-const PURPOSE_STATEMENT_TEXT =
- "The purpose of the cloud security assessment is to comprehensively evaluate the organization's security posture in its cloud environment, identifying vulnerabilities and gaps that could compromise data integrity, confidentiality, and availability. This assessment aims to enhance information security maturity, strengthen defenses against cyber threats, ensure compliance with regulations, and foster a culture of security awareness. Through periodic assessments, the organization proactively mitigates risks, ensuring continuous security for cloud-configured assets and maintaining stakeholders' trust in data protection capabilities.";
-
-const DISCLAIMER_TEXT =
- "This document in any form, software or printed matter, contains proprietary information that is the exclusive property of Oracle. Your access to and use of this confidential material is subject to the terms and conditions of your Oracle software license and service agreement, which has been executed and with which you agree to comply. This document and information contained herein may not be disclosed, copied, reproduced or distributed to anyone outside Oracle without prior written consent of Oracle. This document is not part of your license agreement, nor can it be incorporated into any contractual agreement with Oracle or its subsidiaries or affiliates.\n\nThis document is for informational purposes only and is intended solely to assist you in planning for the implementation and upgrade of the product features described. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, timing, and pricing of any features or functionality described in this document remains at the sole discretion of Oracle. Due to the nature of the product architecture, it may not be possible to safely include all features described in this document without risking significant destabilization of the code.";
-
-// ====== HELPERS ======
-function escapeHtml(value) {
- return String(value ?? "")
- .replaceAll("&", "&")
- .replaceAll("<", "<")
- .replaceAll(">", ">")
- .replaceAll('"', """)
- .replaceAll("'", "'");
-}
-
-function normStr(v) {
- return String(v ?? "").trim();
-}
-
-// Apenas Yes/No (Unknown vira No)
-function normStatus2(v) {
- const s = normStr(v).toLowerCase();
- if (["yes", "true", "compliant", "ok"].includes(s)) return "Yes";
- return "No";
-}
-
-function parsePercent(value) {
- const s = normStr(value);
- if (!s) return null;
- const m = s.replace(",", ".").match(/(\d+(\.\d+)?)/);
- if (!m) return null;
- const n = Number(m[1]);
- if (!Number.isFinite(n)) return null;
- return Math.max(0, Math.min(100, n));
-}
-
-function parseFindingsNumber(value) {
- const s = normStr(value);
- if (!s) return null;
- const m = s.replaceAll(",", "").match(/\d+/);
- if (!m) return null;
- const n = Number(m[0]);
- return Number.isFinite(n) ? n : null;
-}
-
-function groupBy(arr, keyFn) {
- const map = new Map();
- for (const x of arr) {
- const k = keyFn(x);
- if (!map.has(k)) map.set(k, []);
- map.get(k).push(x);
- }
- return map;
-}
-
-// Ordenação "1.2" < "1.10" < "2.1"
-function sortRecommendation(a, b) {
- const pa = String(a ?? "").split(".").map(x => Number(x));
- const pb = String(b ?? "").split(".").map(x => Number(x));
- for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
- const da = pa[i] ?? 0;
- const db = pb[i] ?? 0;
- if (da !== db) return da - db;
- }
- return 0;
-}
-
-function monthYearPt(date = new Date()) {
- const months = [
- "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho",
- "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro",
- ];
- return `${months[date.getMonth()]}, ${date.getFullYear()}`;
-}
-
-function progressBar(pct) {
- if (pct === null) {
- return `
`;
- }
- const width = Math.max(0, Math.min(100, pct));
- const cls = pct <= 20 ? "bad" : pct <= 60 ? "warn" : "ok";
- return `
-
- `.trim();
-}
-
-function field(label, value, opts = {}) {
- const v = value === undefined || value === null ? "" : String(value);
- if (!opts.showWhenEmpty && !normStr(v)) return "";
- return `
-
-
${escapeHtml(label)}
-
${escapeHtml(v)}
-
- `.trim();
-}
-
-function pill(label, value) {
- const v = normStr(value);
- if (!v) return "";
- return `${escapeHtml(label)}: ${escapeHtml(v)}`;
-}
-
-function badge2(status2) {
- return status2 === "Yes"
- ? `Compliant`
- : `Non-compliant`;
-}
-
-function slugify(s) {
- return String(s ?? "")
- .trim()
- .toLowerCase()
- .replace(/[\u0300-\u036f]/g, "")
- .replace(/[^\w\s-]/g, "")
- .replace(/\s+/g, "-")
- .replace(/-+/g, "-")
- .replace(/^-|-$/g, "");
-}
-
-function sectionId(sectionName) {
- return `section-${slugify(sectionName) || "unspecified"}`;
-}
-
-// ====== SECTION NORMALIZATION + FILTERING ======
-const ALLOWED_SECTIONS = new Set([
- "Asset Management",
- "Compute",
- "Identity and Access Management",
- "Logging and Monitoring",
- "Networking",
- "Storage - Block Volumes",
- "Storage - File Storage Service",
- "Storage - Object Storage",
-]);
-
-function normalizeSectionName(raw) {
- let s = String(raw ?? "").trim();
- s = s.replace(/\s+/g, " ");
-
- if (/^Logging and Monitoring\s*\d*$/i.test(s)) return "Logging and Monitoring";
- if (/^Storage$/i.test(s)) return null;
-
- if (/^Storage\s*-\s*Block Volumes$/i.test(s)) return "Storage - Block Volumes";
- if (/^Storage\s*-\s*File Storage Service$/i.test(s)) return "Storage - File Storage Service";
- if (/^Storage\s*-\s*Object Storage$/i.test(s)) return "Storage - Object Storage";
-
- return s || null;
-}
-
-// ====== DEDUPE ======
-function makeDedupKey(row, normalizedSection) {
- const section = normalizedSection || "Unspecified";
- const rec = normStr(row["Recommendation #"]) || "no-rec";
- const title = normStr(row["Title"]) || "no-title";
- return `${section}||${rec}||${title}`.toLowerCase();
-}
-
-const dedupMap = new Map();
-for (const r of allRowsRaw) {
- const sec = normalizeSectionName(r["Section"]);
- if (!sec) continue;
- if (!ALLOWED_SECTIONS.has(sec)) continue;
-
- const key = makeDedupKey(r, sec);
- if (!dedupMap.has(key)) {
- dedupMap.set(key, { ...r, Section: sec });
- }
-}
-const allRows = [...dedupMap.values()];
-
-// ====== ENRICH ======
-const now = new Date();
-const monthYear = monthYearPt(now);
-
-const enrichedAll = allRows.map(r => {
- const pctRaw = r["Compliance Percentage Per Recommendation"];
- const pct = parsePercent(pctRaw);
- const findingsRaw = r["Findings"];
- const findingsNum = parseFindingsNumber(findingsRaw);
- const status2 = normStatus2(r["Compliant"]);
-
- const rec = normStr(r["Recommendation #"]) || "rec";
- const section = normStr(r["Section"]) || "Unspecified";
- const recIdVal = `rec-${slugify(section)}-${slugify(rec)}`;
-
- return {
- ...r,
- __status2: status2,
- __pct: pct,
- __pctRaw: pctRaw,
- __findingsNum: findingsNum,
- __findingsRaw: findingsRaw,
- __recId: recIdVal,
- };
-});
-
-const bySection = groupBy(enrichedAll, r => normStr(r["Section"]) || "Unspecified");
-
-const SECTION_ORDER = [
- "Asset Management",
- "Compute",
- "Identity and Access Management",
- "Logging and Monitoring",
- "Networking",
- "Storage - Block Volumes",
- "Storage - File Storage Service",
- "Storage - Object Storage",
-];
-
-const sectionEntries = SECTION_ORDER
- .map(name => {
- const rows = bySection.get(name) || [];
- const total = rows.length;
- const passed = rows.filter(r => r.__status2 === "Yes").length;
- const failed = total - passed;
- return { name, id: sectionId(name), total, passed, failed, rows };
- })
- .filter(s => s.total > 0);
-
-const totalAll = enrichedAll.length;
-const counts = enrichedAll.reduce((acc, r) => {
- acc[r.__status2] = (acc[r.__status2] ?? 0) + 1;
- return acc;
-}, { Yes: 0, No: 0 });
-
-const extractDates = [...new Set(allRows.map(r => normStr(r["extract_date"])).filter(Boolean))];
-const extractDateCover = extractDates.length ? extractDates[0] : "";
-
-// ====== TOC: Section + each recommendation ======
-const toc = [];
-toc.push({ title: "Purpose statement", href: "#purpose", right: "" });
-toc.push({ title: "Disclaimer", href: "#disclaimer", right: "" });
-if (summaryTexts.length) toc.push({ title: "Executive Summary", href: "#exec-summary", right: "" });
-toc.push({ title: "Findings Overview", href: "#findings-overview", right: "" });
-
-for (const s of sectionEntries) {
- toc.push({ title: s.name, href: `#${s.id}`, right: String(s.total), level: 0 });
-
- const rowsSorted = [...s.rows].sort((a, b) =>
- sortRecommendation(a["Recommendation #"], b["Recommendation #"])
- );
-
- for (const r of rowsSorted) {
- const rec = normStr(r["Recommendation #"]) || "-";
- const title = normStr(r["Title"]) || "-";
- toc.push({
- title: `${rec} — ${title}`,
- href: `#${r.__recId}`,
- right: "",
- level: 1,
- });
- }
-}
-
-function tocLine({ title, href, right, level = 0 }) {
- const indentClass = level === 1 ? "toc-l1" : "toc-l0";
- const safeRight = right ? escapeHtml(right) : " ";
- return `
-
- `.trim();
-}
-
-// ====== HTML ======
-const html = `
-
-
-
-
- Oracle Cloud Security Assessment
-
-
-
-
-
-
-
-
-
-
ORACLE
-
-
-
Oracle Cloud Security
Assessment
-
Tenancy – Oracle Cloud Infrastructure
-
-
-
-
-
-
-
Purpose Statement
-
${escapeHtml(PURPOSE_STATEMENT_TEXT)}
-
-
Disclaimer
-
${escapeHtml(DISCLAIMER_TEXT)}
-
-
-
-
-
ORACLE
-
Table of contents
-
-
- ${toc.map(t => tocLine(t)).join("")}
-
-
-
- ${summaryTexts.length ? `
-
-
-
Executive Summary
-
Conteúdo gerado dinamicamente pelo fluxo
- ${summaryTexts.map(t => `
${escapeHtml(t)}
`).join("")}
-
- ` : ""}
-
-
-
-
Findings Overview
-
Resumo por domínio (Section)
-
-
-
-
- | DOMAINS |
- TOTAL CONTROLS |
- FAILED |
- PASSED |
-
-
-
- ${sectionEntries.map(s => `
-
- | ${escapeHtml(s.name)} |
- ${s.total} |
- ${s.failed} |
- ${s.passed} |
-
- `).join("")}
-
-
-
-
- Total: ${totalAll} • Passed: ${counts.Yes} • Failed: ${counts.No}
-
-
-
-
- ${sectionEntries.map(s => {
- const yesRows = s.rows
- .filter(r => r.__status2 === "Yes")
- .sort((a, b) => sortRecommendation(a["Recommendation #"], b["Recommendation #"]));
-
- const noRows = s.rows
- .filter(r => r.__status2 === "No")
- .sort((a, b) => sortRecommendation(a["Recommendation #"], b["Recommendation #"]));
-
- const renderCards = (rows) => `
-
- ${rows.map(r => `
-
-
-
-
- ${escapeHtml(normStr(r["Recommendation #"]) || "-")} — ${escapeHtml(normStr(r["Title"]) || "-")}
-
-
- ${badge2(r.__status2)}
- ${pill("Section", r["Section"])}
- ${pill("Level", r["Level"])}
- ${pill("Findings", r.__findingsNum === null ? "N/A" : r.__findingsNum)}
- ${pill("CIS v8", r["CIS v8"])}
- ${pill("extract_date", r["extract_date"])}
- ${pill("Filename", r["Filename"])}
-
-
-
-
- ${progressBar(r.__pct)}
-
-
-
- ${field("Findings (raw)", r.__findingsRaw, { showWhenEmpty: true })}
- ${field("Remediation", r["Remediation"], { showWhenEmpty: true })}
- ${field("CCCS Guard Rail", r["CCCS Guard Rail"], { showWhenEmpty: false })}
-
- `).join("")}
-
- `;
-
- const sectionExtraClass = s.name === "Asset Management" ? "page-break-before" : "";
-
- // Compliant primeiro, depois Non-compliant
- return `
-
- `;
- }).join("")}
-
-
-
-
-`.trim();
-
-return [{ json: { html } }];
\ No newline at end of file