Skip to content

Commit ca04590

Browse files
authored
Merge pull request #25 from keepass-web/issue-1-add-release-version-footer
Show build version on distributables
2 parents e1fe809 + 97f8914 commit ca04590

16 files changed

Lines changed: 396 additions & 26 deletions

File tree

.github/workflows/ci.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,24 @@ jobs:
103103
- name: Test
104104
run: npm test
105105

106-
# Step 6 — Build distributables
106+
# Step 6 — Version footer inputs
107+
# Every distributable's footer shows what it was built from. GITHUB_REF_TYPE,
108+
# GITHUB_REF_NAME, and GITHUB_SHA are already set by Actions on every job;
109+
# the commit date isn't, so it's computed here once and persisted via
110+
# $GITHUB_ENV so the later "Record checksums" step (a separate step, hence
111+
# a separate process) sees the same value the build itself used — see
112+
# tools/build/inliner/src/version-label.ts and docs/REPRODUCING.md.
113+
- name: Resolve commit date for the version footer
114+
run: echo "KEEPASS_WEB_COMMIT_DATE=$(git show -s --format=%cI HEAD)" >> "$GITHUB_ENV"
115+
116+
# Step 7 — Build distributables
107117
# The root build script builds argon2 and chacha20, then kdbx, then pages,
108118
# in that dependency order — pages' bundler reads their compiled build/
109119
# output, so they must exist first.
110120
- name: Build distributables
111121
run: npm run build
112122

113-
# Step 7 — Checksums
123+
# Step 8 — Checksums
114124
# Surfaces each distributable's checksum in the workflow summary. For
115125
# tagged releases, these values are attached to the GitHub release as the
116126
# published checksums that third parties verify against.

.github/workflows/release.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,23 @@ jobs:
8181
8282
# The root build script builds argon2 and chacha20, then kdbx, then
8383
# pages, in that dependency order, writing all intermediate output to
84-
# build/ and the final distributables to dist/ — see ci.yml Step 6.
84+
# build/ and the final distributables to dist/ — see ci.yml Step 7.
8585
# Neither directory is committed, so this rebuild from source is the
8686
# only place dist/*.html come from; there's nothing to reuse from CI.
8787
# The inliner prints "sha256:<hex> <output path>" to stdout for each
8888
# built file; the loop below re-runs it and keeps only the first
8989
# whitespace-separated field (the checksum) for the summary. CNAME is
9090
# copied verbatim; its checksum is computed separately since it isn't
9191
# inlined.
92+
#
93+
# KEEPASS_WEB_COMMIT_DATE feeds every distributable's version footer
94+
# (GITHUB_REF_TYPE/GITHUB_REF_NAME/GITHUB_SHA are already set by
95+
# Actions) — see tools/build/inliner/src/version-label.ts and
96+
# docs/REPRODUCING.md for reproducing this outside CI.
9297
- name: Build distributables
9398
if: steps.existing-release.outputs.exists != 'true'
9499
run: |
100+
export KEEPASS_WEB_COMMIT_DATE="$(git show -s --format=%cI HEAD)"
95101
npm run build
96102
cp pages/CNAME dist/CNAME
97103

docs/PIPELINE.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ flowchart TD
8484
DEP -->|pass| LINT
8585
LINT --> TC["tsc --noEmit type check, every workspace"]
8686
TC --> TEST["node:test suite, every workspace"]
87-
TEST --> BUILD["npm run build\nargon2 + chacha20 -> kdbx -> pages\nbundle + inline x 4 pages"]
87+
TEST --> DATE["Resolve KEEPASS_WEB_COMMIT_DATE\ngit show -s --format=%cI HEAD"]
88+
DATE --> BUILD["npm run build\nargon2 + chacha20 -> kdbx -> pages\nbundle + inline x 4 pages\n(version footer: GITHUB_REF_TYPE/NAME/SHA + commit date)"]
8889
BUILD --> SUM["Publish checksums\nto step summary"]
8990
```
9091

@@ -98,7 +99,7 @@ flowchart TD
9899
TAG --> AREL["release.yml"]
99100
AREL --> CI3["Lint · type check · test"]
100101
CI3 --> VER2["Verify tag = package.json version"]
101-
VER2 --> BUILD["Full build from source: compile\npackages and pages, bundle, inline;\ncopy CNAME\nOutputs: 0x67.html · router.html\nindex.html · cloud-google-drive.html\nCNAME"]
102+
VER2 --> BUILD["Full build from source: compile\npackages and pages, bundle, inline;\ncopy CNAME\nOutputs: 0x67.html · router.html\nindex.html · cloud-google-drive.html\nCNAME\n(version footer: tag + commit date)"]
102103
BUILD --> ATTEST["Attest all five files\nactions/attest-build-provenance\nSigns to Sigstore transparency log"]
103104
ATTEST --> GHREL["Create GitHub release\nUpload all five files\nPublish checksums in release notes"]
104105
GHREL --> TOKEN["Generate short-lived App token\nscoped to the deploy repo"]

docs/RELEASES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
Every file served from [keepass-web.app][app] is a verbatim copy of a file published in a GitHub release — nothing is created, modified, or synthesized during deployment. A copy downloaded from Releases and a copy served from the hosted site are the same bytes; see [Reproducing a build][reproducing] to verify that yourself.
1414

15+
Each of the four HTML pages shows its own build's version in the footer — the tag it was released as, linked to that exact tree in this repo, and the date it was committed (shown in whatever locale format the visitor's own browser uses). A non-release build (a plain local `npm run build`, or CI on a branch) shows a linked short commit sha instead of a tag, or "development build" with no link if no commit metadata was supplied at all — see [Reproducing a build][reproducing].
16+
1517
## Overview
1618

1719
```

docs/REPRODUCING.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,29 @@ Any party can reproduce a versioned distributable and verify it against the publ
1616
docker build -t keepass-web-build -f tools/build/Dockerfile .
1717
```
1818

19-
3. Run the build inside the container:
19+
3. Every distributable's footer shows what it was built from — the tag (or commit) and the date it was committed, sourced from four env vars rather than the container's clock, so the same commit always produces the same bytes no matter when it's rebuilt (see "two independent builds" below). `GITHUB_REF_TYPE`, `GITHUB_REF_NAME`, and `GITHUB_SHA` mirror the env vars GitHub Actions already sets on every job; outside Actions, derive them from the tag checked out in step 1:
2020

2121
```sh
22-
docker run --rm -v "$PWD":/workspace keepass-web-build \
22+
ref_name=v<version>
23+
sha=$(git rev-parse HEAD)
24+
commit_date=$(git show -s --format=%cI HEAD)
25+
```
26+
27+
4. Run the build inside the container:
28+
29+
```sh
30+
docker run --rm -v "$PWD":/workspace \
31+
-e GITHUB_REF_TYPE=tag \
32+
-e GITHUB_REF_NAME="$ref_name" \
33+
-e GITHUB_SHA="$sha" \
34+
-e KEEPASS_WEB_COMMIT_DATE="$commit_date" \
35+
keepass-web-build \
2336
sh -c "npm ci && npm run build"
2437
```
2538

2639
`npm run build` builds `argon2`, `chacha20`, and `kdbx`, then bundles and inlines each page. The inliner prints `sha256:<hex> <output path>` to stdout once per distributable (`index.html`, `router.html`, `0x67.html`, `cloud-google-drive.html`), so each checksum is unambiguously tied to the file it belongs to.
2740

28-
4. Compare each printed checksum against the corresponding value published with the release.
41+
5. Compare each printed checksum against the corresponding value published with the release.
2942

3043
Two independent builds of the same source commit must produce an identical checksum. A mismatch means the build is not reproducible and should be treated as suspect.
3144

pages/0x67/page.css

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,32 @@ input.attachment-name:focus {
10701070
opacity: 0.5;
10711071
}
10721072

1073+
/* ============================================================
1074+
Footer
1075+
(a flex-shrink:0 sibling of #root in both body layouts above, so it
1076+
claims its own space instead of being clipped by app-mode's
1077+
height:100vh/overflow:hidden or centered away by the upload/unlock
1078+
layout's justify-content:center)
1079+
============================================================ */
1080+
1081+
footer {
1082+
flex-shrink: 0;
1083+
padding: 0.4rem 1rem;
1084+
border-top: 1px solid var(--border);
1085+
font-size: 0.75rem;
1086+
color: var(--muted);
1087+
text-align: center;
1088+
}
1089+
1090+
footer a {
1091+
color: var(--accent);
1092+
text-decoration: none;
1093+
}
1094+
1095+
footer a:hover {
1096+
text-decoration: underline;
1097+
}
1098+
10731099
/* ============================================================
10741100
Printing (entry detail only — see data-action="print")
10751101
============================================================ */

pages/0x67/page.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ <h2>Choose an icon</h2>
392392
</div>
393393
</dialog>
394394

395+
<footer>MIT licensed &middot; <a href="https://github.com/keepass-web">github.com/keepass-web</a> &middot; <!--VERSION--></footer>
396+
395397
<!--SCRIPTS-->
396398
</body>
397399
</html>

pages/cloud-google-drive/page.css

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ body {
3030
font-size: 15px;
3131
line-height: 1.5;
3232
min-height: 100vh;
33+
display: flex;
34+
flex-direction: column;
3335
}
3436

3537
.wordmark {
@@ -38,6 +40,27 @@ body {
3840
color: var(--accent);
3941
}
4042

43+
/* #root is a flex-shrink:0 sibling away from footer below, so it grows to
44+
fill whatever space footer doesn't need — see .screen-host, which used to
45+
claim a flat 100vh of its own and is now sized off this instead. */
46+
#root {
47+
flex: 1;
48+
min-height: 0;
49+
}
50+
51+
footer {
52+
flex-shrink: 0;
53+
padding: 0.4rem 1rem;
54+
border-top: 1px solid var(--border);
55+
font-size: 0.8rem;
56+
color: var(--muted);
57+
text-align: center;
58+
}
59+
60+
footer a {
61+
color: var(--accent);
62+
}
63+
4164
/* ============================================================
4265
Buttons and shared bits
4366
============================================================ */
@@ -149,7 +172,7 @@ body {
149172
.screen-host {
150173
display: flex;
151174
flex-direction: column;
152-
height: 100vh;
175+
height: 100%;
153176
}
154177

155178
.host-header {

pages/cloud-google-drive/page.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ <h1>Open from Google Drive</h1>
5858
</div>
5959
</template>
6060

61+
<footer>MIT licensed &middot; <a href="https://github.com/keepass-web">github.com/keepass-web</a> &middot; <!--VERSION--></footer>
62+
6163
<!--SCRIPTS-->
6264
</body>
6365
</html>

pages/index/page.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ <h1>Your passwords.<br>Your storage.<br>Your browser.</h1>
3333
<a href="https://github.com/sponsors/keepass-web">Sponsor</a>
3434
</div>
3535
</main>
36-
<footer>MIT licensed &middot; <a href="https://github.com/keepass-web">github.com/keepass-web</a></footer>
36+
<footer>MIT licensed &middot; <a href="https://github.com/keepass-web">github.com/keepass-web</a> &middot; <!--VERSION--></footer>
3737
<!--SCRIPTS-->
3838
</body>
3939
</html>

0 commit comments

Comments
 (0)