snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
This commit is contained in:
158
docs/site/src/components/SecurityUpdates/feed.ts
Normal file
158
docs/site/src/components/SecurityUpdates/feed.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
import {parseAffectedLines, type VersionRange} from './versions';
|
||||
|
||||
export const FEED_URL = 'https://securityupdates.mattermost.com/security_updates.json';
|
||||
|
||||
export type TabId = 'server' | 'desktop' | 'mobile' | 'plugins';
|
||||
|
||||
export type SecurityUpdateRow = {
|
||||
issueId: string;
|
||||
cveId?: string;
|
||||
severity: string;
|
||||
affectedVersions: string[];
|
||||
affectedRanges: VersionRange[];
|
||||
releaseDate: string;
|
||||
fixVersions: string[];
|
||||
details: string;
|
||||
};
|
||||
|
||||
export type SecurityUpdateTab = {
|
||||
id: TabId;
|
||||
label: string;
|
||||
rows: SecurityUpdateRow[];
|
||||
};
|
||||
|
||||
export const TAB_ORDER: {id: TabId; label: string}[] = [
|
||||
{id: 'server', label: 'Server'},
|
||||
{id: 'desktop', label: 'Desktop'},
|
||||
{id: 'mobile', label: 'Mobile'},
|
||||
{id: 'plugins', label: 'Plugins'},
|
||||
];
|
||||
|
||||
const PLATFORM_MAP: Record<string, TabId> = {
|
||||
'Mattermost Server': 'server',
|
||||
'Mattermost Desktop App': 'desktop',
|
||||
'Mattermost Mobile Apps': 'mobile',
|
||||
'Mattermost Plugins': 'plugins',
|
||||
};
|
||||
|
||||
type FeedItem = {
|
||||
issue_id?: string;
|
||||
cve_id?: string;
|
||||
severity?: string;
|
||||
affected_versions?: unknown;
|
||||
fix_release_date?: string;
|
||||
fix_versions?: unknown;
|
||||
details?: string;
|
||||
platform?: string;
|
||||
};
|
||||
|
||||
function normalizeVersions(value: unknown): string[] {
|
||||
if (value == null || value === '') {
|
||||
return [];
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.flatMap((entry) => normalizeVersions(entry)).map((entry) => entry.trim()).filter(Boolean);
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) {
|
||||
return [];
|
||||
}
|
||||
if (trimmed.startsWith('[')) {
|
||||
try {
|
||||
return normalizeVersions(JSON.parse(trimmed));
|
||||
} catch {
|
||||
/* keep as plain string */
|
||||
}
|
||||
}
|
||||
return [trimmed];
|
||||
}
|
||||
return [String(value)];
|
||||
}
|
||||
|
||||
function normalizeSeverity(value: string): string {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed || /^n\/?a$/i.test(trimmed)) {
|
||||
return 'N/A';
|
||||
}
|
||||
return trimmed.replace(/^\w/, (c) => c.toUpperCase());
|
||||
}
|
||||
|
||||
function parseIssueParts(issueId: string) {
|
||||
const parts = issueId.split('-');
|
||||
return {
|
||||
year: Number.parseInt(parts[1] || '', 10) || 0,
|
||||
num: Number.parseInt(parts[2] || '', 10) || 0,
|
||||
extra: Number.parseInt(parts[3] || '', 10) || 0,
|
||||
};
|
||||
}
|
||||
|
||||
function toRow(item: FeedItem): SecurityUpdateRow {
|
||||
const cveId = String(item.cve_id || '').trim();
|
||||
const affectedVersions = normalizeVersions(item.affected_versions);
|
||||
const fixVersions = normalizeVersions(item.fix_versions);
|
||||
return {
|
||||
issueId: String(item.issue_id || '').trim(),
|
||||
...(cveId ? {cveId} : {}),
|
||||
severity: normalizeSeverity(String(item.severity || '')),
|
||||
affectedVersions,
|
||||
affectedRanges: parseAffectedLines(affectedVersions, fixVersions),
|
||||
releaseDate: String(item.fix_release_date || '').slice(0, 10),
|
||||
fixVersions,
|
||||
details: String(item.details || '').replace(/\s+/g, ' ').trim(),
|
||||
};
|
||||
}
|
||||
|
||||
function compareFeedItems(a: FeedItem, b: FeedItem): number {
|
||||
const dateA = Date.parse(String(a.fix_release_date || '').slice(0, 10)) || 0;
|
||||
const dateB = Date.parse(String(b.fix_release_date || '').slice(0, 10)) || 0;
|
||||
if (dateA !== dateB) {
|
||||
return dateB - dateA;
|
||||
}
|
||||
const pa = parseIssueParts(String(a.issue_id || ''));
|
||||
const pb = parseIssueParts(String(b.issue_id || ''));
|
||||
if (pa.year !== pb.year) {
|
||||
return pb.year - pa.year;
|
||||
}
|
||||
if (pa.num !== pb.num) {
|
||||
return pb.num - pa.num;
|
||||
}
|
||||
return pb.extra - pa.extra;
|
||||
}
|
||||
|
||||
export function normalizeFeed(feed: unknown): SecurityUpdateTab[] {
|
||||
if (!Array.isArray(feed)) {
|
||||
throw new Error('Unexpected feed shape: expected an array of advisories.');
|
||||
}
|
||||
|
||||
const tabs = Object.fromEntries(
|
||||
TAB_ORDER.map((tab) => [tab.id, {...tab, rows: [] as SecurityUpdateRow[]}]),
|
||||
) as Record<TabId, SecurityUpdateTab>;
|
||||
|
||||
[...(feed as FeedItem[])]
|
||||
.sort(compareFeedItems)
|
||||
.forEach((item) => {
|
||||
const tabId = PLATFORM_MAP[String(item.platform || '').trim()];
|
||||
if (!tabId) {
|
||||
return;
|
||||
}
|
||||
tabs[tabId].rows.push(toRow(item));
|
||||
});
|
||||
|
||||
return TAB_ORDER.map((tab) => tabs[tab.id]);
|
||||
}
|
||||
|
||||
export async function fetchSecurityUpdates(): Promise<{
|
||||
tabs: SecurityUpdateTab[];
|
||||
lastModified: string | null;
|
||||
}> {
|
||||
const response = await fetch(FEED_URL, {cache: 'no-store'});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Security updates feed returned ${response.status}.`);
|
||||
}
|
||||
const payload: unknown = await response.json();
|
||||
return {
|
||||
tabs: normalizeFeed(payload),
|
||||
lastModified: response.headers.get('Last-Modified'),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user