diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/ProfileQuestion.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/ProfileQuestion.cs index 6083cba19..3bec62d3c 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/ProfileQuestion.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Question/ProfileQuestion.cs @@ -236,7 +236,7 @@ public void SetValidation(bool validate) //{ // oldQuestionValues.SubLabelNumber = SubLabelNumber; // oldQuestionValues.Question = Question; - // oldQuestionValues.Comments = Comments; + // oldQuestionValues.Comment = Comment; // oldQuestionValues.References = References; // oldQuestionValues.IsSelect = IsSelect; // oldQuestionValues.SupplementalInfo = SupplementalInfo; @@ -246,7 +246,7 @@ public void SetValidation(bool validate) //{ // this.SubLabelNumber = oldQuestionValues.SubLabelNumber; // this.Question = oldQuestionValues.Question; - // this.Comments = oldQuestionValues.Comments; + // this.Comment = oldQuestionValues.Comment; // this.References = oldQuestionValues.References; // this.IsSelect = oldQuestionValues.IsSelect; diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Reports/ReportsDataBusiness.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Reports/ReportsDataBusiness.cs index 14a2247ab..03cfc4091 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Reports/ReportsDataBusiness.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Reports/ReportsDataBusiness.cs @@ -1557,6 +1557,54 @@ public List GetRankedQuestions() return list; } + public List GetQuestionsWithSupplementals() + { + var lang = _tokenManager.GetCurrentLanguage(); + + var rm = new Question.RequirementBusiness(_assessmentUtil, _questionRequirement, _context, _tokenManager); + + List list = new List(); + List rankedQuestionList = _context.usp_GetRankedQuestions(_assessmentId).ToList(); + + + var supplementalLookups = (from a in _context.NEW_REQUIREMENT + join b in _context.REQUIREMENT_SETS on a.Requirement_Id equals b.Requirement_Id + where b.Set_Name == "MOPhysical" + select a).ToDictionary(x=> x.Requirement_Id, x=> x); + + foreach (usp_GetRankedQuestions_Result q in rankedQuestionList) + { + if (q.RequirementId != null) + { + var reqOverlay = _overlay.GetRequirement((int)q.RequirementId, lang); + if (reqOverlay != null) + { + q.QuestionText = reqOverlay.RequirementText; + } + + } + + + q.QuestionText = rm.ResolveParameters(q.QuestionOrRequirementID, q.AnswerID, q.QuestionText); + + q.Category = _overlay.GetPropertyValue("STANDARD_CATEGORY", q.Category.ToLower(), lang) ?? q.Category; + var comment = _context.Answer_Requirements.Where(x => x.Question_Or_Requirement_Id == q.QuestionOrRequirementID).FirstOrDefault()?.Comment; + var supplemental = supplementalLookups[q.RequirementId??0].Supplemental_Info; + list.Add(new PhysicalQuestions() + { + Answer = q.AnswerText, + CategoryAndNumber = q.Category + " #" + q.QuestionRef, + Level = q.Level, + Question = q.QuestionText, + Rank = q.Rank ?? 0, + Supplemental = supplemental, + Comment = comment + }); + } + + return list; + } + public List GetDocumentLibrary() { @@ -2791,7 +2839,6 @@ from b in _context.VIEW_QUESTIONS_STATUS.Where(x => x.Answer_Id == a.Answer_Id). return maturityDomains; } - // } } diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Interfaces/Reports/IReportsDataBusiness.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Interfaces/Reports/IReportsDataBusiness.cs index 8826e70fb..332cb4ac4 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Interfaces/Reports/IReportsDataBusiness.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Interfaces/Reports/IReportsDataBusiness.cs @@ -64,5 +64,6 @@ void BuildSubGroupings(MaturityGrouping g, int? parentID, List GetCieQuestionList(int matLevel, bool filterForNa = false); List GetCieDocumentsForAssessment(); List GetCieMfrQuestionList(); + List GetQuestionsWithSupplementals(); } } \ No newline at end of file diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Model/Reports/BasicReportData.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Model/Reports/BasicReportData.cs index 69726064a..49003d10c 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Model/Reports/BasicReportData.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Model/Reports/BasicReportData.cs @@ -41,7 +41,7 @@ public class BasicReportData public List ComponentQuestions { get; set; } public List> Zones { get; set; } public List QuestionAnswerPairings { get; set; } - + public List QuestionsWithSupplementals { get; set; } public class INFORMATION { @@ -174,6 +174,12 @@ public class RankedQuestions } + public class PhysicalQuestions : RankedQuestions + { + public string Supplemental { get; set; } + public string Comment { get; set; } + } + public class QuestionsWithComments { public string CategoryAndNumber { get; set; } diff --git a/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/ReportsController.cs b/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/ReportsController.cs index e9c48dc0f..727c8d04a 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/ReportsController.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/ReportsController.cs @@ -541,6 +541,22 @@ public IActionResult GetSiteSummary() data.QuestionsWithAltJust = _report.GetQuestionsWithAlternateJustification(); return Ok(data); } + [HttpGet] + [Route("api/reports/physicalsummary")] + public IActionResult GetPhysicalSummary() + { + int assessmentId = _token.AssessmentForUser(); + + _report.SetReportsAssessmentId(assessmentId); + BasicReportData data = new BasicReportData(); + data.information = _report.GetInformation(); + data.QuestionsWithSupplementals = _report.GetQuestionsWithSupplementals(); + data.RankedQuestionsTable = _report.GetRankedQuestions(); + data.QuestionsWithComments = _report.GetQuestionsWithComments(); + data.QuestionsMarkedForReview = _report.GetQuestionsMarkedForReview(); + data.QuestionsWithAltJust = _report.GetQuestionsWithAlternateJustification(); + return Ok(data); + } [HttpGet] diff --git a/CSETWebNg/src/app/app-routing.module.ts b/CSETWebNg/src/app/app-routing.module.ts index c3c77753b..3ba597471 100644 --- a/CSETWebNg/src/app/app-routing.module.ts +++ b/CSETWebNg/src/app/app-routing.module.ts @@ -93,6 +93,7 @@ import { SecurityplanComponent } from './reports/securityplan/securityplan.compo import { TrendReportComponent } from './reports/trendreport/trendreport.component'; import { CompareReportComponent } from './reports/comparereport/comparereport.component'; import { SiteSummaryComponent } from './reports/site-summary/site-summary.component'; +import { PhysicalSummaryComponent} from './reports/physical-summary/physical-summary.component'; import { ModelSelectComponent } from './assessment/prepare/maturity/model-select/model-select.component'; import { CmmcLevelsComponent } from './assessment/prepare/maturity/cmmc-levels/cmmc-levels.component'; import { MaturityQuestionsComponent } from './assessment/questions/maturity-questions/maturity-questions.component'; @@ -530,6 +531,7 @@ const appRoutes: Routes = [ { path: 'executive', component: ExecutiveSummaryComponent }, { path: 'securityplan', component: SecurityplanComponent }, { path: 'sitesummary', component: SiteSummaryComponent }, + { path: 'physicalsummary', component: PhysicalSummaryComponent }, { path: 'trendreport', component: TrendReportComponent }, { path: 'comparereport', component: CompareReportComponent }, { path: 'executivecmmc', component: ExecutiveCMMCComponent }, diff --git a/CSETWebNg/src/app/app.module.ts b/CSETWebNg/src/app/app.module.ts index 55afcf246..df35bf2e2 100644 --- a/CSETWebNg/src/app/app.module.ts +++ b/CSETWebNg/src/app/app.module.ts @@ -667,6 +667,7 @@ import { UploadDemographicsComponent } from './dialogs/import demographics/impor import { CieMfrReportComponent } from './reports/cie/cie-mfr-report/cie-mfr-report.component'; import { ReportListComponent } from './assessment/results/reports/report-list/report-list.component'; import { ReportListCommonComponent } from './assessment/results/reports/report-list/report-list-common.component'; +import { PhysicalSummaryComponent } from './reports/physical-summary/physical-summary.component'; @NgModule({ @@ -910,6 +911,7 @@ import { ReportListCommonComponent } from './assessment/results/reports/report-l ExecutiveSummaryComponent, SecurityplanComponent, SiteSummaryComponent, + PhysicalSummaryComponent, TrendReportComponent, TrendCompareCompatibilityComponent, CompareReportComponent, diff --git a/CSETWebNg/src/app/assessment/results/reports/report-list/report-list.json b/CSETWebNg/src/app/assessment/results/reports/report-list/report-list.json index d61624de4..0f8b35364 100644 --- a/CSETWebNg/src/app/assessment/results/reports/report-list/report-list.json +++ b/CSETWebNg/src/app/assessment/results/reports/report-list/report-list.json @@ -256,6 +256,26 @@ } ] }, + { + "title": "MOPhysical", + "reportList": [ + { + "linkUrl": "physicalsummary" + }, + { + "linkUrl": "executive" + }, + { + "linkUrl": "sitesummary" + }, + { + "linkUrl": "securityplan" + }, + { + "linkUrl": "detail" + } + ] + }, { "title": "STANDARD", "reportList": [ diff --git a/CSETWebNg/src/app/assessment/results/reports/reports.component.ts b/CSETWebNg/src/app/assessment/results/reports/reports.component.ts index 7dab8cc90..9bc5eea25 100644 --- a/CSETWebNg/src/app/assessment/results/reports/reports.component.ts +++ b/CSETWebNg/src/app/assessment/results/reports/reports.component.ts @@ -344,7 +344,9 @@ export class ReportsComponent implements OnInit, AfterViewInit { updateSectionId(): void { if (!!this.assessSvc.assessment) { // Network diagram and standard assessments use the same assessment list. sectionId will be passed as DIAGRAM - if (this.assessSvc.assessment.useStandard && !this.isMobile) { + if (this.assessSvc.usesStandard('MOPhysical')) { + this.currentSectionId = 'MOPhysical'; + } else if (this.assessSvc.assessment.useStandard && !this.isMobile) { this.currentSectionId = 'STANDARD'; } else if (this.assessSvc.assessment.useDiagram && !this.isMobile) { this.currentSectionId = 'DIAGRAM'; diff --git a/CSETWebNg/src/app/reports/physical-summary/physical-summary.component.html b/CSETWebNg/src/app/reports/physical-summary/physical-summary.component.html new file mode 100644 index 000000000..7de48ecc9 --- /dev/null +++ b/CSETWebNg/src/app/reports/physical-summary/physical-summary.component.html @@ -0,0 +1,117 @@ + +
+ +
+
+

+ VULNERABILITIES AND OPTIONS FOR CONSIDERATION +

+
+
+

+ cset +

+
+ +
+ + +
+
+ + + +
+

+ During the assessment process, personnel conducting the assessment along with facility stakeholders identified potential vulnerabilities along with suggested options for consideration. The process and listed options for consideration provide an opportunity for the facility owners/operators (stakeholders) to mitigate vulnerabilities, increase resilience, and implement protective measures. This process involves an assessment of risk tailored to the facility that takes into consideration the threat, assets to be protected, facility characteristics and capital expenditures planning. The options for consideration are not prescriptive endorsements of specific protective measures to be installed and/or used at the facility. The critical infrastructure owner or operator determines for the facility whether the options for consideration provide the desired enhancements in light of the facility’s current security and resilience posture, anticipated growth or organizational changes, budgetary outlook, etc. No assessment process or respective options for consideration have the ability to provide solutions which fully eliminate the possibility of undesirable events or associated outcomes. +

+ +
+ +
+ +
+ + + +
+

{{t('reports.site information')}}

+ +
+ +
+

+ Vulnerabilities and Options For Consideration +

+ +

+ During the assessment process, personnel conducting the assessment along with facility stakeholders identified potential vulnerabilities + along with suggested options for consideration. The process and listed options for consideration provide an opportunity for the facility + owners/operators (stakeholders) to mitigate vulnerabilities, increase resilience, and implement protective measures. This process involves + an assessment of risk tailored to the facility that takes into consideration the threat, assets to be protected, facility characteristics + and capital expenditures planning. The options for consideration are not prescriptive endorsements of specific protective measures to be + installed and/or used at the facility. The critical infrastructure owner or operator determines for the facility whether the options for + consideration provide the desired enhancements in light of the facility’s current security and resilience posture, anticipated growth or + organizational changes, budgetary outlook, etc. No assessment process or respective options for consideration have the ability to provide + solutions which fully eliminate the possibility of undesirable events or associated outcomes. +

+ + + + + + + + + + + + + + + + + + +
{{t('reports.core.rank')}}: {{rq.rank}}{{rq.categoryAndNumber}}{{t('reports.core.level')}}: {{t('titles.sal.level.' + rq.level.toLowerCase())}}
{{t('answer-options.labels.' + rq.answer.toLowerCase())}}
{{t('reports.core.questions comments.comment')}}:
+
+ + + +
+ +
+ + + +
+ +
+ + +
+ +
+ +
\ No newline at end of file diff --git a/CSETWebNg/src/app/reports/physical-summary/physical-summary.component.ts b/CSETWebNg/src/app/reports/physical-summary/physical-summary.component.ts new file mode 100644 index 000000000..cf4a1b51b --- /dev/null +++ b/CSETWebNg/src/app/reports/physical-summary/physical-summary.component.ts @@ -0,0 +1,90 @@ +//////////////////////////////// +// +// Copyright 2024 Battelle Energy Alliance, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +//////////////////////////////// +import { Component, OnInit, AfterViewInit } from '@angular/core'; +import { ReportAnalysisService } from '../../services/report-analysis.service'; +import { ReportService } from '../../services/report.service'; +import { ConfigService } from '../../services/config.service'; +import { Title, DomSanitizer, SafeHtml } from '@angular/platform-browser'; +import { AcetDashboard } from '../../models/acet-dashboard.model'; +import { AdminTableData, AdminPageData, HoursOverride } from '../../models/admin-save.model'; +import { ACETService } from '../../services/acet.service'; +import { MaturityService } from '../../services/maturity.service'; +import { QuestionsService } from '../../services/questions.service'; +import Chart from 'chart.js/auto'; +import { AssessmentService } from '../../services/assessment.service'; +import { TranslocoService } from '@jsverse/transloco'; + +@Component({ + selector: 'physical-summary', + templateUrl: './physical-summary.component.html', + styleUrls: ['../reports.scss'] +}) +export class PhysicalSummaryComponent implements OnInit, AfterViewInit { + chartStandardsSummary: Chart; + chartPercentCompliance: Chart; + translationSub: any; + response: any; + responseResultsByCategory: any; + + networkDiagramImage: SafeHtml; + + pageInitialized = false; + + + constructor( + public analysisSvc: ReportAnalysisService, + public reportSvc: ReportService, + public questionsSvc: QuestionsService, + public configSvc: ConfigService, + private titleService: Title, + private sanitizer: DomSanitizer, + private maturitySvc: MaturityService, + public tSvc: TranslocoService + ) { } + + ngOnInit() { + this.translationSub = this.tSvc.selectTranslate('reports.core.physical summary.report title') + .subscribe(value => + this.titleService.setTitle(this.tSvc.translate('reports.core.physical summary.report title') + ' - ' + this.configSvc.behaviors.defaultTitle)); + + this.reportSvc.getReport('physicalsummary').subscribe( + (r: any) => { + this.response = r; + }, + error => console.log('Physical Summary report load Error: ' + (error).message) + ); + } + + /** + * + */ + ngAfterViewInit() { + + } + + + ngOnDestroy() { + this.translationSub.unsubscribe() + } +} diff --git a/CSETWebNg/src/assets/i18n/en.json b/CSETWebNg/src/assets/i18n/en.json index 6defc4e37..553ddd474 100644 --- a/CSETWebNg/src/assets/i18n/en.json +++ b/CSETWebNg/src/assets/i18n/en.json @@ -887,6 +887,29 @@ "desc": "This document consolidates all practices that have received comments or have been flagged for review during the assessment process. It provides an overview of areas where further attention or clarification may be needed." } }, + "mophysical": { + "sectionTitle": "Standard Reports", + "1":{ + "title": "Vulnerabilities and Options For Consideration", + "desc": "This report includes all unfavorable findings with options for consideration and comments." + }, + "2": { + "title": "Executive Summary", + "desc": "This report includes the high-level assessment description, the executive summary, the Security Assurance Level (SAL), and a set of charts that highlight overall compliance and compliance by component type." + }, + "3": { + "title": "Site Summary Report", + "desc": "This report includes the same information as the Executive Summary as well as site information, the network diagram, component compliance by subject area, findings and recommendations from basic network analysis, the document library, comments, alternate justifications for responses, and questions marked for review." + }, + "4": { + "title": "Site Cybersecurity Plan", + "desc": "This template is intended to be used as a tool for the development of a security plan. The template assists in identifying the controls in place and those needing further implementation based upon the answers provided in the assessment. The purpose of the security plan is to provide an overview of the security requirements of the system and describe the controls in place or planned, for meeting those requirements. " + }, + "5": { + "title": "Site Detail Report", + "desc": "This report includes the same information as the Site Summary Report as well as a list of all network component questions and their corresponding answers." + } + }, "standard": { "sectionTitle": "Standard Reports", "1": { @@ -997,6 +1020,16 @@ "economic impact": "Economic Impact", "environmental impact": "Environmental Impact" }, + "physical summary": { + "report title": "Physical Assessment Vulnerabilities and Options For Consideration Summary", + "high-level assessment description": "High-Level Assessment Description", + "standards compliance": "Standards Compliance", + "security assurance level": "Security Assurance Level (SAL)", + "document library": "Document Library", + "ranked categories": "Ranked Categories", + "summary of ranked questions": "Summary of Ranked Questions", + "summary of ranked questions desc": "Each question that did not meet the required Security Assurance Level (SAL) is shown in ranking order below. The displayed levels are the SALs applicable to that question. They are: Low (L), Moderate (M), High (H), and Very High (VH). CNSSI levels are for Confidentiality (C), Integrity (I), and Availability (A). DoD Instruction 8500.2 levels are for Confidentiality (Conf) and Mission Assurance Category (MAC). They are: Classified (C), Sensitive (S), and Public (P) for Confidentiality; MAC I, II, and III for Mission Assurance Category." + }, "site summary": { "report title": "Site Summary", "high-level assessment description": "High-Level Assessment Description",