Skip to content

Commit 7fa0c00

Browse files
committed
[chore] align primary website with deployed security and release inputs
Signed-off-by: Viwat Vchirawongkwin <viwat.v@chula.ac.th>
1 parent b4dd0c7 commit 7fa0c00

10 files changed

Lines changed: 391 additions & 236 deletions

‎tools/web/package-lock.json‎

Lines changed: 311 additions & 217 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎tools/web/package.json‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@
2929
"dependencies": {
3030
"@material/web": "2.2.0",
3131
"esp-web-tools": "10.4.0",
32-
"next": "16.2.12",
32+
"next": "16.3.4",
3333
"react": "19.2.8",
3434
"react-dom": "19.2.8",
3535
"react-server-dom-webpack": "19.2.8",
3636
"vinext": "1.0.0-beta.8"
3737
},
3838
"devDependencies": {
3939
"@eslint/js": "10.0.1",
40-
"@next/eslint-plugin-next": "16.2.12",
40+
"@next/eslint-plugin-next": "16.3.4",
4141
"@testing-library/jest-dom": "7.0.0",
4242
"@testing-library/react": "16.3.2",
4343
"@types/node": "26.1.2",
@@ -53,12 +53,12 @@
5353
"typescript": "5.9.3",
5454
"typescript-eslint": "8.65.0",
5555
"vite": "8.1.5",
56-
"vitest": "4.1.10"
56+
"vitest": "4.1.11"
5757
},
5858
"overrides": {
5959
"next": {
6060
"postcss": "8.5.26",
61-
"sharp": "0.35.3"
61+
"sharp": "0.35.4"
6262
}
6363
}
6464
}

‎tools/web/public/WEBSITE_THIRD_PARTY_LICENSES.txt‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -563,11 +563,11 @@ License file: LICENSE
563563
limitations under the License.
564564

565565
================================================================================
566-
@next/env 16.2.12
566+
@next/env 16.3.4
567567
Installed path: node_modules/@next/env
568568
SPDX license: MIT
569-
Source: https://registry.npmjs.org/@next/env/-/env-16.2.12.tgz
570-
License file: reviewed fallback for node_modules/@next/env@16.2.12
569+
Source: https://registry.npmjs.org/@next/env/-/env-16.3.4.tgz
570+
License file: reviewed fallback for node_modules/@next/env@16.3.4
571571

572572
The MIT License (MIT)
573573

@@ -1088,10 +1088,10 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
10881088
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10891089

10901090
================================================================================
1091-
@swc/helpers 0.5.15
1091+
@swc/helpers 0.5.23
10921092
Installed path: node_modules/@swc/helpers
10931093
SPDX license: Apache-2.0
1094-
Source: https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz
1094+
Source: https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz
10951095
License file: LICENSE
10961096

10971097
Apache License
@@ -3995,10 +3995,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39953995
SOFTWARE.
39963996

39973997
================================================================================
3998-
next 16.2.12
3998+
next 16.3.4
39993999
Installed path: node_modules/next
40004000
SPDX license: MIT
4001-
Source: https://registry.npmjs.org/next/-/next-16.2.12.tgz
4001+
Source: https://registry.npmjs.org/next/-/next-16.3.4.tgz
40024002
License file: license.md
40034003

40044004
The MIT License (MIT)

‎tools/web/scripts/generate-website-third-party-licenses.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ SOFTWARE.`;
6060

6161
const reviewedLicenseFallbacks = {
6262
"node_modules/@next/env": {
63-
version: "16.2.12",
63+
version: "16.3.4",
6464
text: mitLicense(
6565
"Copyright (c) 2025 Vercel, Inc.",
6666
"The MIT License (MIT)",

‎tools/web/src/app/flash/page.tsx‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { PageIntro } from "@/components/page-intro";
77
import { WaveshareBoardPhoto } from "@/components/waveshare-board-photo";
88
import {
99
firmwareVersionUsesFiveProfiles,
10+
isOwnerConfirmedFirmwareRelease,
1011
releaseIncludesWaveshareLcd147b,
1112
} from "@/lib/firmware-release";
1213
import {
@@ -33,6 +34,7 @@ export default function FlashPage() {
3334
const release = preview ? null : firmwareReleaseSelectedAtBuild();
3435
const publicBeta = release?.deployment === "public-beta";
3536
const candidate = release?.deployment === "candidate";
37+
const ownerConfirmed = isOwnerConfirmedFirmwareRelease(release);
3638
const waveshareLcd147b = releaseIncludesWaveshareLcd147b(release);
3739
const fiveProfileRelease =
3840
release !== null && firmwareVersionUsesFiveProfiles(release.version);
@@ -59,7 +61,9 @@ export default function FlashPage() {
5961
<p>
6062
One-time wired provisioning installs PyBLE-enabled MicroPython. Then
6163
develop over Bluetooth Low Energy from the tablet-first PyBLE app.
62-
{preview
64+
{ownerConfirmed
65+
? " Firmware v0.6.1 is available for all five board profiles following qualification confirmed by the project owner."
66+
: preview
6367
? ` LOCAL ENGINEERING PREVIEW v${preview.version} — UNQUALIFIED. This is not a public release.`
6468
: publicBeta
6569
? " The current v0.4.2 installer is a hardware-tested firmware beta. Production Chrome erase/install and deliberately interrupted-flash recovery passed on both exact profiles. Complete release qualification is still pending; this is not a qualified release."

‎tools/web/src/components/flash-status.tsx‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { verifyFirmwareProfile } from "@/lib/firmware-integrity";
1010
import {
1111
hasExactFirmwareProfileDescriptors,
1212
isExactPublicBetaFirmwareRelease,
13+
isOwnerConfirmedFirmwareRelease,
1314
releaseIncludesWaveshareLcd147b,
1415
firmwareVersionUsesFiveProfiles,
1516
type FirmwareProfileDescriptor,
@@ -159,7 +160,8 @@ function policyFailure(release: FirmwareReleaseDescriptor | null | undefined) {
159160
body: "Hardware validation is still required on every profile included in a v0.6.0-derived candidate before the public installer can be enabled.",
160161
};
161162
}
162-
if (release.deployment !== "public" && release.deployment !== "candidate") {
163+
if (release.deployment !== "public" && release.deployment !== "candidate" &&
164+
!isOwnerConfirmedFirmwareRelease(release)) {
163165
if (
164166
release.deployment !== "public-beta" ||
165167
!isExactPublicBetaFirmwareRelease(release)
@@ -379,6 +381,7 @@ function FlashStatusForRelease({
379381
: profileConsentItems;
380382
const everyConsent = requiredConsentItems.every(({ id }) => consents[id]);
381383
const candidate = activeRelease.deployment === "candidate";
384+
const ownerConfirmed = isOwnerConfirmedFirmwareRelease(activeRelease);
382385
const publicBeta = activeRelease.deployment === "public-beta";
383386

384387
function chooseProfile(profileId: FirmwareProfileId) {
@@ -485,7 +488,9 @@ function FlashStatusForRelease({
485488
<div>
486489
<p className="flash-status__eyebrow">Installer status</p>
487490
<h2 id="installer-status-title">
488-
{candidate
491+
{ownerConfirmed
492+
? "Owner-qualified release"
493+
: candidate
489494
? "Protected release candidate"
490495
: publicBeta
491496
? "Hardware-tested firmware beta"
@@ -498,7 +503,11 @@ function FlashStatusForRelease({
498503
role={candidate || publicBeta ? "status" : undefined}
499504
className="flash-status__message"
500505
>
501-
{candidate
506+
{ownerConfirmed ? (
507+
<>Firmware v0.6.1 qualification was confirmed by the project owner.
508+
{" "}<a href="/firmware-v0.6.1-owner-confirmation.md">Publication record</a>.
509+
{" "}Select and verify your exact board profile before installation.</>
510+
) : candidate
502511
? "Protected release candidate: hardware validation is pending."
503512
: publicBeta
504513
? "Hardware-tested firmware beta: exact PyBLE v0.4.2 browser installation and interrupted-flash recovery passed on real esp32-4mb and esp32-s3-n16r8 hardware. Complete release qualification is still pending; this is not a qualified release."

‎tools/web/src/lib/firmware-integrity.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
historicalFirmwareProfileTable,
99
firmwareVersionUsesFiveProfiles,
1010
isExactPublicBetaFirmwareRelease,
11+
isOwnerConfirmedFirmwareRelease,
1112
publicBetaFirmwareVersion,
1213
type FirmwareProfileDescriptor,
1314
type FirmwareProfileId,
@@ -378,7 +379,8 @@ function validateDescriptor(
378379
if (
379380
descriptor.deployment !== "public" &&
380381
descriptor.deployment !== "candidate" &&
381-
descriptor.deployment !== "public-beta"
382+
descriptor.deployment !== "public-beta" &&
383+
!isOwnerConfirmedFirmwareRelease(descriptor)
382384
) {
383385
fail("Selected firmware deployment mode is invalid");
384386
}

‎tools/web/src/lib/firmware-release-selection.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
hasExactFirmwareProfileDescriptors,
99
hasExactHistoricalFirmwareProfileDescriptors,
1010
isExactPublicBetaFirmwareRelease,
11+
isOwnerConfirmedFirmwareRelease,
1112
releaseIncludesWaveshareLcd147b,
1213
type FirmwareReleaseDescriptor,
1314
} from "@/lib/firmware-release";
@@ -89,7 +90,8 @@ export function firmwareReleaseSelectedAtBuild(): FirmwareReleaseDescriptor | nu
8990
if (
9091
descriptor.deployment !== "public" &&
9192
descriptor.deployment !== "candidate" &&
92-
descriptor.deployment !== "public-beta"
93+
descriptor.deployment !== "public-beta" &&
94+
!isOwnerConfirmedFirmwareRelease(descriptor)
9395
) {
9496
throw new Error(
9597
"Build-selected firmware descriptor has an invalid deployment mode",

‎tools/web/src/lib/firmware-release.ts‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export type HistoricalFirmwareProfileId =
7474
(typeof historicalFirmwareProfileTable)[number]["id"];
7575
export type PlannedFirmwareProfileId =
7676
(typeof plannedFirmwareProfileTable)[number]["id"];
77-
export type FirmwareDeployment = "public" | "candidate" | "public-beta";
77+
export type FirmwareDeployment = "public" | "candidate" | "public-beta" | "owner-confirmed";
7878
export type FirmwareHilStatus = "pending" | "passed";
7979
export type FirmwareProvisioningKind =
8080
"esp-web-serial" | "verified-uf2-bootsel";
@@ -150,6 +150,23 @@ export interface FirmwareReleaseDescriptor {
150150
readonly profiles: readonly FirmwareProfileDescriptor[];
151151
}
152152

153+
// Explicit owner authorization for these immutable bytes only; automated HIL
154+
// records stay pending. This does not relax the qualified-public release gate.
155+
export function isOwnerConfirmedFirmwareRelease(
156+
descriptor: FirmwareReleaseDescriptor | null | undefined,
157+
): boolean {
158+
return Boolean(
159+
descriptor?.deployment === "owner-confirmed" &&
160+
descriptor.accessControlled === false &&
161+
descriptor.version === "0.6.1" &&
162+
descriptor.hilStatus === "pending" &&
163+
descriptor.releaseJson.path === "/firmware/v0.6.1/release.json" &&
164+
descriptor.releaseJson.sha256 ===
165+
"71f6aca6df07e31a1f54c7f70a48d82c7fe26b1c8ca0626a8ffc57c804fbb1bd" &&
166+
hasExactFirmwareProfileDescriptors(descriptor.version, descriptor.profiles),
167+
);
168+
}
169+
153170
export interface VerifiedFirmwareProfile {
154171
readonly profileId: FirmwareProfileId;
155172
readonly provisioningKind?: FirmwareProvisioningKind;

‎tools/web/src/test/build-contract.test.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,33 @@ describe("production build contract", () => {
9999
});
100100
});
101101

102+
it("pins the patched Next, Sharp, and Vitest security closure", async () => {
103+
const [packageJson, packageLock] = await Promise.all(
104+
["package.json", "package-lock.json"].map(async (file) =>
105+
JSON.parse(await readFile(join(process.cwd(), file), "utf8")),
106+
),
107+
);
108+
109+
expect(packageJson.dependencies?.next).toBe("16.3.4");
110+
expect(packageJson.devDependencies?.["@next/eslint-plugin-next"]).toBe(
111+
"16.3.4",
112+
);
113+
expect(packageJson.devDependencies?.vitest).toBe("4.1.11");
114+
expect(packageJson.overrides?.next?.sharp).toBe("0.35.4");
115+
for (const [name, version] of [
116+
["next", "16.3.4"],
117+
["@next/env", "16.3.4"],
118+
["@next/eslint-plugin-next", "16.3.4"],
119+
["sharp", "0.35.4"],
120+
["vitest", "4.1.11"],
121+
["@vitest/mocker", "4.1.11"],
122+
]) {
123+
expect(packageLock.packages?.[`node_modules/${name}`]?.version).toBe(
124+
version,
125+
);
126+
}
127+
});
128+
102129
it("pins the audited build closure and excludes the vulnerable image parser package", async () => {
103130
const [packageJson, packageLock, appFiles, sourceFiles] = await Promise.all(
104131
[

0 commit comments

Comments
 (0)