diff --git a/src/report/web/App.browser.test.tsx b/src/report/web/App.browser.test.tsx
index ce10e7d..a9c2c0f 100644
--- a/src/report/web/App.browser.test.tsx
+++ b/src/report/web/App.browser.test.tsx
@@ -112,22 +112,26 @@ describe('App report shell', () => {
expect(screen.getByTestId(riskStoryTestIds.severityBar)).toBeInTheDocument();
});
- it('summarizes repos with security alerts disabled and lists them in the source note', () => {
+ it('summarizes repos with security alerts disabled and links to the appendix table', () => {
renderReport({ cve: cveExposureOk.build({ reposWithSecurityAlertsDisabled: ['acme/a', 'acme/b'] }) });
const warning = screen.getByTestId(riskStoryTestIds.disabledAlertsWarning);
expect(warning).toHaveTextContent(
'Did you know: 2 of your 24 repos do not have Dependabot security alerts enabled',
);
- expect(warning).not.toHaveTextContent('*');
+
+ const details = screen.getByTestId(methodologyAppendixTestIds.section).querySelector('details');
+ expect(details).not.toHaveAttribute('open');
const restore = suppressNavigation();
- fireEvent.click(within(warning).getByTestId(footnoteReferenceTestId));
+ fireEvent.click(within(warning).getByTestId(riskStoryTestIds.disabledAlertsLink));
restore();
- const sources = screen.getByTestId(methodologyAppendixTestIds.sources);
- expect(sources).toHaveTextContent('Repos without security alerts enabled');
- expect(sources).toHaveTextContent('acme/a, acme/b');
+ // The link opens the collapsed appendix on the Calculation tab, where the repos render as a table.
+ expect(details).toHaveAttribute('open');
+ const table = screen.getByTestId(methodologyAppendixTestIds.disabledAlertsRepos);
+ expect(table).toHaveTextContent('acme/a');
+ expect(table).toHaveTextContent('acme/b');
});
it('limits the top repos by severity table to the top five with an optional expansion', () => {
@@ -144,12 +148,12 @@ describe('App report shell', () => {
});
const table = screen.getByTestId(riskStoryTestIds.topReposTable);
- expect(within(table).getByText('acme/repo-5')).toBeInTheDocument();
- expect(within(table).queryByText('acme/repo-6')).not.toBeInTheDocument();
+ expect(within(table).getByText('repo-5')).toBeInTheDocument();
+ expect(within(table).queryByText('repo-6')).not.toBeInTheDocument();
fireEvent.click(screen.getByTestId(riskStoryTestIds.topReposToggle));
- expect(within(table).getByText('acme/repo-6')).toBeInTheDocument();
+ expect(within(table).getByText('repo-6')).toBeInTheDocument();
expect(screen.getByTestId(riskStoryTestIds.topReposToggle)).toHaveTextContent('Show top 5');
});
diff --git a/src/report/web/acts/MethodologyAppendix.tsx b/src/report/web/acts/MethodologyAppendix.tsx
index 61bfc73..2142d67 100644
--- a/src/report/web/acts/MethodologyAppendix.tsx
+++ b/src/report/web/acts/MethodologyAppendix.tsx
@@ -138,6 +138,10 @@ export function MethodologyAppendix() {
+ New CVEs in {repos.length === 1 ? 'this repo' : 'these repos'} will not appear in this report. +
+| {repo} | +
{empty}
diff --git a/src/report/web/acts/RiskStory.tsx b/src/report/web/acts/RiskStory.tsx index 3886cf3..15fcee1 100644 --- a/src/report/web/acts/RiskStory.tsx +++ b/src/report/web/acts/RiskStory.tsx @@ -1,7 +1,8 @@ import { useState } from 'react'; import { useEmbeddedData } from '../data/EmbeddedDataContext.tsx'; +import { repoShortName } from '../format/repo.ts'; +import { useAssumptionsDisclosure } from '../hooks/useAssumptionsDisclosure.tsx'; import { Citation } from '../primitives/Citation.tsx'; -import { FootnoteReference } from '../primitives/FootnoteReference.tsx'; import { SEGMENTS, StackedBar } from '../primitives/StackedBar.tsx'; export const riskStoryTestIds = { @@ -12,6 +13,7 @@ export const riskStoryTestIds = { topReposTable: 'risk-story-top-repos-table', topReposToggle: 'risk-story-top-repos-toggle', disabledAlertsWarning: 'risk-story-disabled-alerts-warning', + disabledAlertsLink: 'risk-story-disabled-alerts-link', } as const; export const riskStoryCopy = { @@ -25,10 +27,7 @@ export const reposWithoutSecurityAlertsId = 'repos-without-security-alerts'; export function RiskStory() { const { cve, orgOverview } = useEmbeddedData(); - const disabledAlertsNote = - cve.reposWithSecurityAlertsDisabled.length > 0 - ? `Repos without security alerts enabled: ${cve.reposWithSecurityAlertsDisabled.join(', ')}. New CVEs in these repos will not appear in this report.` - : 'These repos returned a not-enabled response for Dependabot security alerts, so new CVEs in them will not appear in this report.'; + const { reveal } = useAssumptionsDisclosure(); if (cve.status === 'scope-missing') { return ( @@ -136,14 +135,18 @@ export function RiskStory() { {cve.reposWithSecurityAlertsDisabled.length} {' '} of your {orgOverview.repoCount} repos{' '} - {cve.reposWithSecurityAlertsDisabled.length === 1 ? 'does' : 'do'} not have Dependabot security alerts enabled -