Skip to content

Commit e55e1d3

Browse files
r-ramachandranRamachandran Rclaude
authored
feat(power-pages): add security skills (#151)
* feat(security-review): add HTML report generation and supporting documentation - Introduced a new HTML report template for security reviews, providing a structured overview of findings, scores, and recommendations. - Created a script (`render-review.js`) to render the HTML report from JSON data files. - Added documentation for the seven-step conversation flow used in the security review process. - Included a glossary of technical terms relevant to the security review findings. - Defined the data format for sections and findings to ensure consistency in report generation. * feat(security-review): enhance security review flow and parallelize sub-skill execution * Refactor manage-code-scan and manage-site-scan skills for clarity and consistency - Updated terminology in SKILL.md files to replace "quick/deep" with "basic/advanced" for better understanding. - Adjusted command parameters in commands.md to reflect new terminology. - Removed get-security-score.js script as its functionality is no longer needed. - Simplified start-deep-scan.js to eliminate unnecessary username/password parameters. - Enhanced review-security skill to streamline user interactions and improve clarity in reporting. - Updated HTML report to remove score display and adjust layout for better readability. - Revised flow.md and section-data-format.md to align with the latest changes in skill behavior and reporting structure. * fix(security-review): update terminology for clarity in security review steps * refactor(manage-site-scan): update descriptions and remove quick scan script for clarity and consistency * feat(security-review): add HTML report generation and supporting documentation - Introduced a new HTML report template for the security review skill, providing a structured overview of findings, summaries, and next steps. - Created a script to render the HTML report from JSON data, ensuring required keys are validated. - Added documentation for the seven-step conversation flow used in the security review process. - Included a glossary of technical terms relevant to the security review findings. - Defined the data format for sections and findings to standardize report generation. * Add scan-site skill and related scripts for Power Pages security scanning - Implemented `scan-site` skill to perform security scans on deployed Power Pages sites. - Created scripts for starting deep scans, polling scan status, and fetching latest reports. - Added command reference documentation for the new scan-site functionality. - Updated existing security review skill to integrate with the new scan-site capabilities. - Introduced `run-trivy.js` script for scanning code dependencies and vulnerabilities. * refactor(skills): remove progress tracking tables from manage-firewall, manage-headers, and scan-site skills for clarity * refactor(manage-firewall, manage-headers, scan-code, scan-site, security-review): standardize JSON formatting and improve clarity in user prompts * refactor(manage-firewall): enforce rule naming conventions and update examples for clarity * Refactor firewall management scripts and documentation - Deleted outdated rule cookbook documentation and replaced it with a new rule reference document that provides a comprehensive guide on creating and managing firewall rules. - Updated scripts for deleting, enabling, disabling, and retrieving firewall rules to use the Power Platform API instead of the Admin API. - Enhanced error handling and output formatting in the get-rules and get-status scripts. - Modified set-rules script to accept inline JSON data for rule creation and updates, improving usability. - Added timeout settings for rule deletion and creation to accommodate longer processing times. * Refactor scan-site scripts to use Power Platform API; update command documentation and add scan reference schema - Changed admin-api references to power-platform-api in scripts: get-latest-report.js, poll-deep-scan.js, start-deep-scan.js. - Updated command documentation to reflect changes in output and usage. - Added scan-reference.md for detailed schema of scan report and alert normalization. - Improved error handling and response structures in get-latest-report.js and poll-deep-scan.js. * Add headers reference documentation and remove obsolete scripts - Created a new documentation file for headers reference detailing site settings and response headers in Power Pages. - Removed the `inspect-headers.js` script as it is no longer needed. - Removed the `scan-external-urls.js` script due to redundancy. - Updated the `SKILL.md` and `commands.md` files to clarify rate limits and scan statuses. - Adjusted severity mapping in `scan-reference.md` to align with API values. * refactor(manage-headers): enhance security recommendations and clarify CSP directives * refactor(manage-headers): update skill tracking instructions for clarity and brevity * Refactor scan-code commands and tool installation documentation - Simplified command descriptions and usage for `check-tools.js`, `run-opengrep.js`, and `run-trivy.js`. - Updated output format to return JSON directly to stdout instead of writing to files. - Removed the tool installation guide as a separate document; now users are instructed to install tools based on `check-tools.js` output. - Enhanced error handling and timeout settings in `check-tools.js`, `run-opengrep.js`, and `run-trivy.js`. - Adjusted the security review skill documentation to reflect changes in workflow and terminology. * refactor(scan-code): update scan depth options and enhance trivy command flags * refactor(security-review): improve clarity and consistency in documentation and remove obsolete glossary * fix(scan-code): clarify description for Basic risk coverage in user prompts * Refactor security review and scan report scripts - Added a new script `render-review.js` to generate security review HTML reports from JSON data. - Removed the obsolete `render-scan-report.js` script. - Updated documentation in `manage-firewall` skill to reflect changes in JSON structure and usage. - Standardized example usage across various scripts to replace `<guid>` with `<portal-id>`. - Enhanced `run-opengrep.js` and `run-trivy.js` to output raw JSON directly, removing unnecessary parsing. - Deleted the `section-data-format.md` reference file as it was no longer needed. - Removed the old `render-review.js` script from the security review skill, consolidating functionality into the new script. * Enhance scan-code and scan-site skills with unified JSON output and transformation scripts - Updated scan-code skill to save raw JSON outputs from opengrep and trivy to temporary files, and introduced a new transform script to normalize findings into a unified format. - Revised documentation for scan-code to reflect changes in output handling and normalization process. - Added transform-report script for scan-site to convert deep-scan reports into a unified findings shape, including detailed severity mapping. - Improved scan-site skill documentation to clarify the fetching and transformation of reports, including handling of empty report cases. - Updated security-review skill to ensure findings are processed verbatim from transform scripts, with clear policies on severity and annotations for inventory sections. * fix: update usage examples to replace <guid> with <portal-id> in scripts and documentation * Refactor scan-code functionality: remove scripts and documentation - Deleted the following scripts: check-tools.js, run-opengrep.js, run-trivy.js, transform-scan-code.js. - Removed associated documentation from commands.md. - Updated scan-site and security-review skills documentation to reflect changes in functionality and clarify usage. - Adjusted the flow of the security-review skill to streamline the conversation steps and improve user experience. * feat(security-review): integrate scan-code skill for local source and package vulnerability checks - Added scan-code skill to scan local Power Pages projects for dependency vulnerabilities and code issues using npm audit and ESLint. - Updated security-review skill to incorporate scan-code findings alongside live-site checks. - Enhanced HTML report generation to include separate sections for package and code findings with verbatim severities. - Modified existing styles and severity labels in the security review report template to accommodate new severities. - Documented the scan-code skill with detailed usage instructions and workflow. * Revert "feat(security-review): integrate scan-code skill for local source and package vulnerability checks" This reverts commit 4c87aca. * feat(security-review): enhance security review skill with improved flow and error handling * Refactor scan-site and security-review skills for improved user experience and code clarity - Updated SKILL.md for scan-site to streamline user options and remove unnecessary confirmation steps before scanning. - Enhanced get-latest-report.js to improve error handling and modularize the main function. - Refactored poll-deep-scan.js to introduce better timeout handling and improve readability. - Simplified start-deep-scan.js by consolidating argument parsing and error handling. - Transformed transform-report.js to improve report parsing and error messaging, ensuring better handling of malformed reports. - Revised security-review SKILL.md to reduce phases from seven to six, clarifying workflow and user interactions. - Updated flow.md to reflect changes in the security-review skill phases and improve clarity on user-facing beats. * test(power-pages): address Copilot PR #151 review comments Reconciles three doc inconsistencies and adds node:test coverage for the four scripts Copilot flagged as untested. Doc fixes: - security-review SKILL.md § 3.1.2: skipped subagent placeholders are now rendered without a severity field, matching the no-severity policy in § 3.1.3. build-review-data.js's skippedSection() drops severity:'info' and the totals.info bump. - scan-site SKILL.md § 5.1 + transform-report.js: the empty status now emits a single info finding (via new emptyReport() helper) rather than an empty findings array, so review-mode output never produces an empty section. - security-review SKILL.md Constraints: the template reference now points at scripts/lib/templates/security-review-report.html (the real location) instead of the non-existent assets/. New tests under scripts/tests/ (64 cases total, all passing): - build-review-data.test.js: SECTION_MAP shape, SEVERITIES order, buildSections behaviour (skipped without severity, totals aggregation, unknown severities, empty dir, JSON-parse failures), TZ-pinned formatGeneratedAt, and CLI surface (--help, missing flags, --inputDir validation, --nextStepsFile folding). - render-review.test.js: missing --output/--data exits, missing data file, unparseable JSON, parameterised required-key validation over all 6 keys (asserts stderr names the missing key), and end-to-end render that verifies REPORT_NAME/SITE_NAME/ REVIEW_DATA-derived values reach the rendered HTML. - power-platform-api.test.js: parseCliArgs, parseTimeoutMs (with parameterised rejection of 'abc'/'0'/'-1'/'-0.5'/'NaN'/''), hasErrorCode is status-agnostic, isFeatureUnsupported variants, pollUntil happy/timeout/error paths plus a stub-clock test that pins DEFAULT_POLL_INTERVAL_MS as the wired-up default and another that asserts a caller-supplied intervalMs flows through. - website.test.js: nextSkipFrom and recordIdOf edge cases plus findWebsite pagination via @odata.nextLink, case-insensitive match, non-advancing-server guard, request/context errors, and empty-websiteId rejection. Uses require.cache injection to stub the api module — documented Node API, restored in finally. Full plugin suite: 984 tests pass, 0 fail. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Ramachandran R <ramacr@microsoft.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2c82e39 commit e55e1d3

37 files changed

Lines changed: 5474 additions & 28 deletions

plugins/power-pages/PLUGIN_DEVELOPMENT_GUIDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ LLMs are probabilistic. When an LLM constructs inline bash commands for Datavers
220220
| `dataverse-request.js` | Generic authenticated Dataverse API request helper |
221221
| `verify-dataverse-access.js` | Verifies Dataverse connectivity and permissions |
222222
| `check-activation-status.js` | Queries Power Platform API for site activation status |
223-
| `clear-site-cache.js` | Clears site cache via Power Platform admin API |
223+
| `clear-site-cache.js` | Clears site cache via Power Platform API |
224224

225225
### Usage Pattern
226226

plugins/power-pages/references/skill-tracking-reference.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ If the tracking script creates or updates site setting YAML files, include those
4141
| add-server-logic | AddServerLogic | Site/AI/Skills/AddServerLogic |
4242
| add-cloud-flow | AddCloudFlow | Site/AI/Skills/AddCloudFlow |
4343
| integrate-backend | IntegrateBackend | Site/AI/Skills/IntegrateBackend |
44+
| scan-site | ScanSite | Site/AI/Skills/ScanSite |
45+
| manage-headers | ManageHeaders | Site/AI/Skills/ManageHeaders |
46+
| manage-firewall | ManageFirewall | Site/AI/Skills/ManageFirewall |
47+
| security-review | SecurityReview | Site/AI/Skills/SecurityReview |
4448
| setup-solution | SetupSolution | Site/AI/Skills/SetupSolution |
4549
| export-solution | ExportSolution | Site/AI/Skills/ExportSolution |
4650
| import-solution | ImportSolution | Site/AI/Skills/ImportSolution |
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
6+
const REQUIRED_FLAGS = [
7+
'reportName',
8+
'inputDir',
9+
'siteName',
10+
'goalLabel',
11+
'scopeLabel',
12+
'output',
13+
];
14+
15+
const SECTION_MAP = {
16+
'scan-site.json': { id: 'site-scan', label: 'Live Site Scan', icon: '◐' },
17+
'manage-headers.json': { id: 'headers', label: 'Browser Headers', icon: '◑' },
18+
'manage-firewall.json': {
19+
id: 'firewall',
20+
label: 'Web Application Firewall',
21+
icon: '◆',
22+
},
23+
'audit-permissions.json': { id: 'permissions', label: 'Roles & Permissions', icon: '◇' },
24+
'setup-auth.json': { id: 'auth', label: 'Access & Identity', icon: '◈' },
25+
};
26+
27+
// Every severity a finding may carry. `pass` is shown as a stat but excluded
28+
// from the issue count by the report template.
29+
const SEVERITIES = ['critical', 'high', 'warning', 'medium', 'info', 'low', 'pass'];
30+
31+
const HELP = `build-review-data.js — Consolidate per-skill JSON into a single review data file.
32+
33+
Usage:
34+
node build-review-data.js --reportName <name> --inputDir <dir> --siteName <name> --goalLabel <label> --scopeLabel <label> --output <path> [--summary <text>] [--nextStepsFile <path>]
35+
36+
Flags:
37+
--reportName Top-bar report title (e.g., "Security Review", "Site Scan") (required)
38+
--inputDir Directory containing per-skill review JSON files (required)
39+
--siteName Site display name (required)
40+
--goalLabel Plain-language goal label (required)
41+
--scopeLabel Plain-language scope label (required)
42+
--output Output data-file path (required)
43+
--summary Overall plain-language summary, 2-4 sentences (optional)
44+
--nextStepsFile Path to a JSON file containing an array of next-step strings (optional)
45+
--help Show this help message
46+
47+
Exit codes:
48+
0 Success (data file written; status JSON on stdout)
49+
1 Invocation error (missing flag or unreadable input dir)
50+
`;
51+
52+
function getArg(name, fallback = null) {
53+
const idx = process.argv.indexOf('--' + name);
54+
return idx !== -1 && idx + 1 < process.argv.length ? process.argv[idx + 1] : fallback;
55+
}
56+
57+
function readNextSteps(filePath) {
58+
try {
59+
const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
60+
return Array.isArray(parsed) ? parsed.filter((x) => typeof x === 'string') : [];
61+
} catch (err) {
62+
process.stderr.write(`Could not read next-steps file: ${err.message}\n`);
63+
return [];
64+
}
65+
}
66+
67+
function formatGeneratedAt(now) {
68+
const pad = (n) => String(n).padStart(2, '0');
69+
// Intl returns "GMT+5:30" on some platforms; keep only the short abbreviation when present.
70+
const tzName =
71+
new Intl.DateTimeFormat(undefined, { timeZoneName: 'short' })
72+
.formatToParts(now)
73+
.find((p) => p.type === 'timeZoneName')?.value || '';
74+
const stamp =
75+
`${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ` +
76+
`${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
77+
return tzName ? `${stamp} ${tzName}` : stamp;
78+
}
79+
80+
function skippedSection(meta, reason) {
81+
return {
82+
id: meta.id,
83+
icon: meta.icon,
84+
label: meta.label,
85+
description: '',
86+
findings: [
87+
{
88+
id: `${meta.id}-skipped`,
89+
title: `${meta.label} check was skipped`,
90+
details: reason || 'No additional detail.',
91+
},
92+
],
93+
details: {},
94+
};
95+
}
96+
97+
function buildSections(inputDir, outputBasename) {
98+
const sections = [];
99+
const totals = Object.fromEntries(SEVERITIES.map((s) => [s, 0]));
100+
101+
for (const fileName of fs.readdirSync(inputDir).sort()) {
102+
if (!fileName.endsWith('.json')) continue;
103+
if (fileName === outputBasename) continue;
104+
const meta = SECTION_MAP[fileName];
105+
if (!meta) continue;
106+
107+
const filePath = path.join(inputDir, fileName);
108+
let raw;
109+
try {
110+
raw = JSON.parse(fs.readFileSync(filePath, 'utf8'));
111+
} catch (err) {
112+
process.stderr.write(`Skipping ${fileName}: ${err.message}\n`);
113+
continue;
114+
}
115+
116+
if (raw?.status === 'skipped') {
117+
sections.push(skippedSection(meta, raw.reason));
118+
continue;
119+
}
120+
121+
const findings = Array.isArray(raw?.findings) ? raw.findings : [];
122+
sections.push({
123+
id: meta.id,
124+
icon: meta.icon,
125+
label: meta.label,
126+
description: '',
127+
findings,
128+
details: raw?.details || {},
129+
});
130+
131+
for (const f of findings) {
132+
if (f.severity && totals[f.severity] !== undefined) totals[f.severity] += 1;
133+
}
134+
}
135+
136+
return { sections, totals };
137+
}
138+
139+
function main() {
140+
if (process.argv.includes('--help')) {
141+
process.stdout.write(HELP);
142+
return;
143+
}
144+
145+
const values = Object.fromEntries(REQUIRED_FLAGS.map((flag) => [flag, getArg(flag)]));
146+
for (const flag of REQUIRED_FLAGS) {
147+
if (!values[flag]) {
148+
process.stderr.write(`Missing required flag: --${flag}\n`);
149+
process.exit(1);
150+
}
151+
}
152+
153+
const inputDir = values.inputDir;
154+
const outputPath = values.output;
155+
if (!fs.existsSync(inputDir)) {
156+
process.stderr.write(`Input dir not found: ${inputDir}\n`);
157+
process.exit(1);
158+
}
159+
160+
const summary = getArg('summary', '');
161+
const nextStepsFile = getArg('nextStepsFile');
162+
const nextSteps = nextStepsFile ? readNextSteps(nextStepsFile) : [];
163+
164+
const { sections, totals } = buildSections(inputDir, path.basename(outputPath));
165+
166+
const payload = {
167+
REPORT_NAME: values.reportName,
168+
SITE_NAME: values.siteName,
169+
GOAL_LABEL: values.goalLabel,
170+
SCOPE_LABEL: values.scopeLabel,
171+
GENERATED_AT: formatGeneratedAt(new Date()),
172+
REVIEW_DATA: { summary: summary || '', totals, sections, nextSteps },
173+
};
174+
175+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
176+
fs.writeFileSync(outputPath, JSON.stringify(payload, null, 2));
177+
178+
process.stdout.write(
179+
JSON.stringify({
180+
status: 'ok',
181+
outputPath,
182+
totals,
183+
sectionsCount: sections.length,
184+
}) + '\n'
185+
);
186+
}
187+
188+
if (require.main === module) {
189+
main();
190+
}
191+
192+
module.exports = { buildSections, formatGeneratedAt, SECTION_MAP, SEVERITIES };

plugins/power-pages/scripts/clear-site-cache.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env node
22

33
// Clears the runtime cache of an activated Power Pages site by restarting it
4-
// via the Power Platform admin API.
4+
// via the Power Platform API.
55
//
66
// Usage:
77
// node clear-site-cache.js --projectRoot "<path>"

0 commit comments

Comments
 (0)