Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42f993378f |
+2
-1
@@ -3,7 +3,8 @@
|
||||
"browsers": [
|
||||
{
|
||||
"brand": "Google Chrome",
|
||||
"fullVersion": "150.0.7871.187"
|
||||
"fullVersion": "150.0.7871.187",
|
||||
"supportedMajorVersions": [150, 151]
|
||||
},
|
||||
{
|
||||
"brand": "Microsoft Edge",
|
||||
|
||||
@@ -151,10 +151,13 @@ export function createAdminDiagnosticsProvider(input: {
|
||||
const system: AdminDiagnosticsResponse["system"] = {
|
||||
api_status: "ready",
|
||||
app_version: input.appVersion ?? input.browserSupportRelease?.appVersion ?? "0.0.0",
|
||||
browser_support: (input.browserSupportRelease?.browsers ?? []).map((browser) => ({
|
||||
brand: browser.brand,
|
||||
major: Number.parseInt(browser.fullVersion.split(".")[0] ?? "0", 10),
|
||||
})).filter((browser) => Number.isSafeInteger(browser.major) && browser.major > 0),
|
||||
browser_support: (input.browserSupportRelease?.browsers ?? []).flatMap((browser) => {
|
||||
const majors = browser.supportedMajorVersions
|
||||
?? [Number.parseInt(browser.fullVersion.split(".")[0] ?? "0", 10)];
|
||||
return majors
|
||||
.map((major) => ({ brand: browser.brand, major }))
|
||||
.filter((entry) => Number.isSafeInteger(entry.major) && entry.major > 0);
|
||||
}),
|
||||
worker_status: services.services.find((service) => service.service_id === "worker")?.status === "active"
|
||||
? "ready"
|
||||
: services.services.find((service) => service.service_id === "worker")?.status === "unavailable"
|
||||
|
||||
@@ -43,7 +43,7 @@ export const BrowserSupportSuccessSchema = Type.Object(
|
||||
app_version: Type.String({ maxLength: 80 }),
|
||||
browser: SupportedBrowserSummarySchema,
|
||||
status: Type.Literal("supported"),
|
||||
supported_browsers: Type.Array(SupportedBrowserSummarySchema, { maxItems: 2 }),
|
||||
supported_browsers: Type.Array(SupportedBrowserSummarySchema, { maxItems: 8 }),
|
||||
},
|
||||
{ additionalProperties: false, $id: "BrowserSupportSuccess" },
|
||||
);
|
||||
@@ -57,6 +57,7 @@ export interface BrowserSupportRelease {
|
||||
browsers: ReadonlyArray<{
|
||||
brand: SupportedBrand;
|
||||
fullVersion: string;
|
||||
supportedMajorVersions?: ReadonlyArray<number>;
|
||||
}>;
|
||||
}
|
||||
|
||||
@@ -115,7 +116,14 @@ function supportedIdentity(entries: Array<{ brand: string; version: string }>) {
|
||||
|
||||
export function supportedBrowserSummary(release: BrowserSupportRelease | undefined) {
|
||||
if (!release) return [];
|
||||
return release.browsers.map(({ brand, fullVersion }) => ({ brand, major: major(fullVersion)! }));
|
||||
return release.browsers.flatMap(({ brand, fullVersion, supportedMajorVersions }) => {
|
||||
const majors = supportedMajorVersions ?? [major(fullVersion)!];
|
||||
return majors.map((supportedMajor) => ({ brand, major: supportedMajor }));
|
||||
});
|
||||
}
|
||||
|
||||
function acceptedMajorVersions(browser: BrowserSupportRelease["browsers"][number]) {
|
||||
return browser.supportedMajorVersions ?? [major(browser.fullVersion)!];
|
||||
}
|
||||
|
||||
export function validateBrowserSupportRelease(value: unknown): value is BrowserSupportRelease {
|
||||
@@ -126,13 +134,26 @@ export function validateBrowserSupportRelease(value: unknown): value is BrowserS
|
||||
}
|
||||
if (!Array.isArray(release.browsers) || release.browsers.length !== 2) return false;
|
||||
const brands = new Set(release.browsers.map(({ brand }) => brand));
|
||||
const supportedMajorCount = release.browsers.reduce(
|
||||
(count, browser) => count + (browser.supportedMajorVersions?.length ?? 1),
|
||||
0,
|
||||
);
|
||||
return (
|
||||
brands.size === 2 &&
|
||||
brands.has("Google Chrome") &&
|
||||
brands.has("Microsoft Edge") &&
|
||||
release.browsers.every(
|
||||
({ brand, fullVersion }) => supportedBrands.has(brand) && fullVersionPattern.test(fullVersion),
|
||||
)
|
||||
supportedMajorCount <= 8 &&
|
||||
release.browsers.every(({ brand, fullVersion, supportedMajorVersions }) => {
|
||||
if (!supportedBrands.has(brand) || !fullVersionPattern.test(fullVersion)) return false;
|
||||
const baselineMajor = major(fullVersion);
|
||||
if (!baselineMajor) return false;
|
||||
if (supportedMajorVersions === undefined) return true;
|
||||
return supportedMajorVersions.length > 0
|
||||
&& supportedMajorVersions.length <= 8
|
||||
&& supportedMajorVersions.every((value: number) => Number.isSafeInteger(value) && value >= 1)
|
||||
&& new Set(supportedMajorVersions).size === supportedMajorVersions.length
|
||||
&& supportedMajorVersions.includes(baselineMajor);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -188,7 +209,7 @@ export function checkBrowserSupport(
|
||||
}
|
||||
|
||||
const supported = release?.browsers.find(({ brand }) => brand === fullIdentity.brand);
|
||||
if (!supported || major(supported.fullVersion) !== fullIdentity.major) {
|
||||
if (!supported || !acceptedMajorVersions(supported).includes(fullIdentity.major)) {
|
||||
return { reason: "version_unsupported", supported: false };
|
||||
}
|
||||
return { identity: fullIdentity, supported: true };
|
||||
@@ -268,7 +289,7 @@ export function verifyBrowserSupportCookie(input: {
|
||||
return { reason: "identity_unavailable" as const, supported: false as const };
|
||||
}
|
||||
const supported = input.release.browsers.find(({ brand }) => brand === currentIdentity.brand);
|
||||
if (currentIdentity.major !== payload.major || major(supported?.fullVersion ?? "") !== currentIdentity.major) {
|
||||
if (!supported || currentIdentity.major !== payload.major || !acceptedMajorVersions(supported).includes(currentIdentity.major)) {
|
||||
return { reason: "version_unsupported" as const, supported: false as const };
|
||||
}
|
||||
return { identity: currentIdentity, supported: true as const };
|
||||
|
||||
@@ -281,7 +281,7 @@ export const AdminDiagnosticsResponseSchema = Type.Object({
|
||||
browser_support: Type.Array(Type.Object({
|
||||
brand: Type.Union([Type.Literal("Google Chrome"), Type.Literal("Microsoft Edge")]),
|
||||
major: Type.Integer({ minimum: 1 }),
|
||||
}, { additionalProperties: false }), { maxItems: 2 }),
|
||||
}, { additionalProperties: false }), { maxItems: 8 }),
|
||||
worker_status: Type.Union([Type.Literal("ready"), Type.Literal("degraded"), Type.Literal("unavailable")]),
|
||||
}, { additionalProperties: false }),
|
||||
}, { additionalProperties: false, $id: "AdminDiagnosticsResponse" });
|
||||
|
||||
@@ -83,7 +83,7 @@ export const ErrorDetailsSchema = Type.Object(
|
||||
},
|
||||
{ additionalProperties: false },
|
||||
),
|
||||
{ maxItems: 2 },
|
||||
{ maxItems: 8 },
|
||||
),
|
||||
),
|
||||
capacity_status: Type.Optional(
|
||||
|
||||
@@ -14,7 +14,11 @@ export const DEFERRED_EXTERNAL_TASKS = Object.freeze(["TASK-WP7-03", "TASK-WP7-0
|
||||
export function buildFinalReleaseRecord({ appVersion, browsers, buildCommit, frozenFromCommit, recordedAt, windows }) {
|
||||
const record = {
|
||||
appVersion,
|
||||
browsers: browsers.map(({ brand, fullVersion }) => ({ brand, fullVersion })),
|
||||
browsers: browsers.map(({ brand, fullVersion, supportedMajorVersions }) => ({
|
||||
brand,
|
||||
fullVersion,
|
||||
...(supportedMajorVersions ? { supportedMajorVersions: [...supportedMajorVersions] } : {}),
|
||||
})),
|
||||
buildCommit: buildCommit.toLowerCase(),
|
||||
deferredExternalTasks: [...DEFERRED_EXTERNAL_TASKS],
|
||||
finalRelease: true,
|
||||
@@ -44,8 +48,25 @@ export function validateFinalReleaseRecord(record) {
|
||||
} else {
|
||||
const brands = record.browsers.map(({ brand }) => brand).sort();
|
||||
if (brands.join("|") !== "Google Chrome|Microsoft Edge") errors.push("browserBrands");
|
||||
const supportedMajorCount = record.browsers.reduce(
|
||||
(count, browser) => count + (Array.isArray(browser.supportedMajorVersions)
|
||||
? browser.supportedMajorVersions.length
|
||||
: 1),
|
||||
0,
|
||||
);
|
||||
if (supportedMajorCount > 8) errors.push("supportedMajorVersions.total");
|
||||
for (const browser of record.browsers) {
|
||||
if (!VERSION.test(browser.fullVersion ?? "")) errors.push(`${browser.brand}.fullVersion`);
|
||||
if (browser.supportedMajorVersions !== undefined) {
|
||||
const values = browser.supportedMajorVersions;
|
||||
const baselineMajor = Number.parseInt(browser.fullVersion.split(".")[0] ?? "0", 10);
|
||||
if (!Array.isArray(values) || values.length === 0 || values.length > 8
|
||||
|| values.some((value) => !Number.isSafeInteger(value) || value < 1)
|
||||
|| new Set(values).size !== values.length
|
||||
|| !values.includes(baselineMajor)) {
|
||||
errors.push(`${browser.brand}.supportedMajorVersions`);
|
||||
}
|
||||
}
|
||||
if ("path" in browser || "executablePath" in browser || "executableSha256" in browser) errors.push(`${browser.brand}.privateMetadata`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,14 @@ const supportedEdge = browserSupportFixture({
|
||||
brand: "Microsoft Edge",
|
||||
fullVersion: "150.0.4078.99",
|
||||
});
|
||||
const supportedChrome150 = browserSupportFixture({
|
||||
brand: "Google Chrome",
|
||||
fullVersion: "150.0.7871.187",
|
||||
});
|
||||
const supportedChrome151 = browserSupportFixture({
|
||||
brand: "Google Chrome",
|
||||
fullVersion: "151.0.0.0",
|
||||
});
|
||||
const rejectedIdentityCases = [
|
||||
{
|
||||
expectedReason: "platform_unsupported",
|
||||
@@ -145,6 +153,7 @@ describe("TDD-WP0-BRW-001 supported browser contract", () => {
|
||||
status: "supported",
|
||||
supported_browsers: [
|
||||
{ brand: "Google Chrome", major: 150 },
|
||||
{ brand: "Google Chrome", major: 151 },
|
||||
{ brand: "Microsoft Edge", major: 150 },
|
||||
],
|
||||
});
|
||||
@@ -188,6 +197,26 @@ describe("TDD-WP0-BRW-001 supported browser contract", () => {
|
||||
expect(staleCookie.statusCode).toBe(426);
|
||||
await restarted.close();
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ expectedMajor: 150, fixture: supportedChrome150 },
|
||||
{ expectedMajor: 151, fixture: supportedChrome151 },
|
||||
])("accepts explicitly declared Chrome $expectedMajor", async ({ expectedMajor, fixture }) => {
|
||||
const app = await createApp({ browserSupportRelease: testBrowserSupportRelease } as never);
|
||||
const checked = await app.inject({
|
||||
headers: fixture.headers,
|
||||
method: "POST",
|
||||
payload: fixture.body,
|
||||
url: "/api/v1/support/check",
|
||||
});
|
||||
|
||||
expect(checked.statusCode).toBe(200);
|
||||
expect(checked.json()).toMatchObject({
|
||||
browser: { brand: "Google Chrome", major: expectedMajor },
|
||||
status: "supported",
|
||||
});
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe("TDD-WP0-BRW-002 hard block", () => {
|
||||
@@ -208,6 +237,7 @@ describe("TDD-WP0-BRW-002 hard block", () => {
|
||||
reason: expectedReason,
|
||||
supported_browsers: [
|
||||
{ brand: "Google Chrome", major: 150 },
|
||||
{ brand: "Google Chrome", major: 151 },
|
||||
{ brand: "Microsoft Edge", major: 150 },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const testBrowserSupportRelease = {
|
||||
appVersion: "1.2.3-test",
|
||||
browsers: [
|
||||
{ brand: "Google Chrome", fullVersion: "150.0.7339.1" },
|
||||
{ brand: "Google Chrome", fullVersion: "150.0.7339.1", supportedMajorVersions: [150, 151] },
|
||||
{ brand: "Microsoft Edge", fullVersion: "150.0.4078.99" },
|
||||
],
|
||||
} as const;
|
||||
|
||||
@@ -10,7 +10,7 @@ function release() {
|
||||
return buildFinalReleaseRecord({
|
||||
appVersion: "0.0.0",
|
||||
browsers: [
|
||||
{ brand: "Google Chrome", fullVersion: "150.0.7871.187" },
|
||||
{ brand: "Google Chrome", fullVersion: "150.0.7871.187", supportedMajorVersions: [150, 151] },
|
||||
{ brand: "Microsoft Edge", fullVersion: "151.0.4129.59" },
|
||||
],
|
||||
buildCommit: "a".repeat(40),
|
||||
@@ -26,6 +26,32 @@ test("TDD-WP7-REL-001 creates a browser-gate compatible first-version record", (
|
||||
assert.equal(record.fixedPort, 43121);
|
||||
assert.deepEqual(record.deferredExternalTasks, ["TASK-WP7-03", "TASK-WP7-04"]);
|
||||
assert.deepEqual(record.browsers.map(({ brand }) => brand).sort(), ["Google Chrome", "Microsoft Edge"]);
|
||||
assert.deepEqual(record.browsers[0].supportedMajorVersions, [150, 151]);
|
||||
});
|
||||
|
||||
test("TDD-WP7-REL-001 rejects unsafe or duplicate browser major lists", () => {
|
||||
assert.throws(() => buildFinalReleaseRecord({
|
||||
appVersion: "0.0.0",
|
||||
browsers: [
|
||||
{ brand: "Google Chrome", fullVersion: "150.0.7871.187", supportedMajorVersions: [150, 150] },
|
||||
{ brand: "Microsoft Edge", fullVersion: "151.0.4129.59" },
|
||||
],
|
||||
buildCommit: "a".repeat(40),
|
||||
frozenFromCommit: "b".repeat(40),
|
||||
recordedAt: "2026-08-04T06:00:00.000Z",
|
||||
windows: { arch: "x64", build: "26200.8875", displayVersion: "25H2" },
|
||||
}), /Google Chrome\.supportedMajorVersions/);
|
||||
assert.throws(() => buildFinalReleaseRecord({
|
||||
appVersion: "0.0.0",
|
||||
browsers: [
|
||||
{ brand: "Google Chrome", fullVersion: "150.0.7871.187", supportedMajorVersions: [150, 151, 152, 153, 154, 155, 156, 157] },
|
||||
{ brand: "Microsoft Edge", fullVersion: "151.0.4129.59" },
|
||||
],
|
||||
buildCommit: "a".repeat(40),
|
||||
frozenFromCommit: "b".repeat(40),
|
||||
recordedAt: "2026-08-04T06:00:00.000Z",
|
||||
windows: { arch: "x64", build: "26200.8875", displayVersion: "25H2" },
|
||||
}), /supportedMajorVersions\.total/);
|
||||
});
|
||||
|
||||
test("TDD-WP7-SEC-001 rejects credential shapes and absolute user paths", () => {
|
||||
|
||||
Reference in New Issue
Block a user