Site for SAFE — Secure (µ)Architecture and Formal Engineering, a research group at KTH. Plain static files, no build step.
This is a standalone site. It is a separate repository from any personal page and shares no files with one at runtime — the stylesheet and the two rendering scripts were copied in as a starting point and are now this project's own, free to diverge. Its content (people, projects, publications, favicon) is the group's, not an individual's.
One scrolling page (index.html) with five sections, driven by three data files:
| Section | Source |
|---|---|
| About + research areas | index.html |
| People | data/people.json |
| News | data/news.json |
| Projects & Tools | data/projects.json |
| Publications | biblio.bib |
| Join us | index.html |
style/main.css carries the base look; style/group.css adds the group-specific
pieces (masthead, people grid, project cards). Rendering is js/bibtex.js +
js/publications.js (publications), js/group.js (people and projects), and
js/site.js (scroll-spy nav).
tools/editor.html edits the people list, the project list and the publications, and
commits the result to GitHub. Once deployed it works from any browser — no terminal,
no git, no local checkout.
One-time setup. On GitHub: Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate. Repository access: only the site repository. Permissions: Contents → Read and write, nothing else. Paste it into the editor's Publishing target panel and press Connect.
All three sections are full lists — add, edit, delete, and reorder people and projects with the arrows — each with a live preview of how the entry will look. Publications use a dropdown instead of a second list — the public page already shows them all. Pick a paper (grouped by year, newest first) to load its BibTeX into the form and replace that entry in place, or Delete to remove it; either way the rest of the file is left byte-identical.
The lists load as soon as you open the page, so you can read and stage changes before entering a token. Changes are held in the browser until you press Publish, so a batch of edits becomes one commit. Connecting reloads from GitHub and asks first if you have staged changes.
Safety features:
- Dry run (on by default) does everything except the commit.
- Branch is configurable, so you can practise against a scratch branch.
- Duplicate BibTeX keys and missing author/title/year are flagged before publishing.
- If a file changed underneath you, the editor re-reads it and re-applies your change rather than overwriting someone else's work.
The token lives only in your browser and is sent only to api.github.com. Untick
Remember on a shared machine and revoke it on GitHub whenever you like. The page
carries no credentials of its own, so it is safe to deploy publicly — a visitor
without a token can look but cannot write.
python3 tools/selftest.py # 45 checks, no network, no commitsRenders every page headlessly checking for console errors, verifies the page shows everything in the data files, and drives the editor's add/edit/reorder/delete/publish paths against a stubbed GitHub API to check the JSON it would commit.
Edit data/people.json. Each entry looks like:
{
"name": "...",
"role": "pi | postdoc | engineer | phd | cosupervised",
"title": "PhD Student",
"topic": "One short line about their work",
"photo": "img/name.jpg",
"links": { "web": "", "scholar": "", "github": "", "linkedin": "", "email": "" }
}Leave photo empty and the person's initials are shown instead, so the page looks
finished before anyone sends a picture. Empty groups disappear automatically, so
deleting all the co-supervised entries removes that heading too.
Ticking Alumni in the editor (or "alumni": true in the file) moves someone out of
the cards and into an Alumni list at the foot of the People section. They keep their
title, topic and links — the row is simply lighter than a card, so past members do not
outweigh current ones. If title is empty their role supplies the label, and for
alumni the topic line is a good place to say where they are now.
Links may be written with or without a scheme: example.com is treated the same as
https://example.com.
data/news.json holds the posts, newest first (the page sorts by timestamp, so the
order in the file does not matter). Each post needs text and an ISO-8601
timestamp; title, image, linkedin and kind are optional. kind is one of
hiring, research, award, talk or update and is guessed from the text when
omitted. URLs in the text become short readable links.
The seeded post was written from the group's own bibliography — check the wording, and delete it from the editor if you would rather start empty.
data/projects.json was populated from the actual repositories under
https://github.com/KTH-SAFE — names, languages and descriptions came from there.
repo is the name under that organization, or a full URL for anything hosted elsewhere.
Each project has a visibility:
| value | on the page |
|---|---|
public (default) |
shown, with a link to the repository |
soon |
shown, but with no repository link and a Coming soon badge — for work announced before the code is out, or an artefact still under review |
hidden |
left off the page entirely |
Open http://localhost:8001/index.html?preview=1 to see hidden entries too, marked as such, so you can check how something reads before making it public. The editor has the same choice as a dropdown on each project.
python3 tools/set_visibility.py # show the current state
python3 tools/set_visibility.py llvm-opt-verif public # change oneIt refuses to mark a project public while its repository is still private on GitHub,
since that is precisely what puts a 404 on the page — --force overrides if you are
about to flip the repository anyway. Editing the visibility line in
data/projects.json by hand does the same thing.
In the editor, each project's form has an "On the public page" dropdown with the
same three choices, and the list marks non-public entries. Press Save to file to
write the change to data/projects.json — in Chrome and Edge you pick the file once and
later saves go straight there; elsewhere it downloads a copy to move into the
repository. Publish commits it instead, once the site repository exists.
python3 tools/check_repos.pyIt asks GitHub whether each repository is public and compares that with the
visibility you set. It catches the two mistakes that matter: a project marked
public whose repository visitors cannot open, and a repository that has since become
public while the page still hides it. Because it uses gh, it sees what you see —
which is the point, since a private repo looks fine when you click it yourself.
biblio.bib is the group's bibliography. It is seeded with the six papers that have
a corresponding tool in the KTH-SAFE organization (CryptoBAP ×3, HolBA ×2, Plumber ×1) —
a starting point, not a claim about what belongs here. Add the rest of the group's
output and remove anything that does not fit.
Optional per-entry fields: Abstract, Artifact, Award, Miscellaneous, plus the
usual url, doi and eprint.
PDFs live in paper/ and are referenced relatively, e.g. url = {paper/name.pdf}.
Keep the file in this repository rather than pointing at another site, so the group
page does not break when that site changes. tools/selftest.py fails if an entry
references a PDF that is not here.
The organization has no Pages site yet. Create a repository named
KTH-SAFE.github.io under the KTH-SAFE organization, push these files to its default
branch, and the site is served at https://kth-safe.github.io/. Alternatively, enable
Pages on any repository and serve from /docs.
python3 tools/serve.py # then open http://localhost:8001
python3 tools/build_group_preview.py # one shareable, self-contained HTML fileUse tools/serve.py rather than a bare python3 -m http.server: it disables browser
caching and uses port 8001, which is this project's alone. The personal site is a
separate project with the same file names, and served on the same localhost port the
browser treats both as one origin and mixes their cached files.