Skip to content
qcloud-systemsPublic

About

[PROD] - Demo info website for deployment by Github Actions on GHPages

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

QCS — Trust & Status Center

Status License Version

Source for info.qcloud.systems, the QCS Trust & Status Center: upstream service status, notices (incidents, maintenance, security advisories, service changes), the roadmap, and QCS's policies. A Go program renders static HTML into ./public, which GitHub Actions publishes to managed static hosting.

How the generator works is documented on the site itself, at /how-its-built.html (source: templates/pages/how-its-built.html).

Everything this site serves is public by design. Agreements and executed client documents are not published from this repo.


What this site is

The Trust & Status Center has one job: show that QCS is reliable and accountable. Its sections, in home-page order:

Section Source Purpose
Overview templates/pages/index.html What the site is, with links to status and notices
Status statusServices() in content.go, static/js/status.js Live status of the upstream providers QCS depends on
Notices notices/*.md Incident reports, maintenance, security advisories, service changes
What's New CHANGELOG.MD (latest entry) Release highlights for this site
Roadmap roadmap() in content.go In progress, planned, shipped
Policies static/*.html, templates/pages/*.html Privacy, Security, Terms of Use, Accessibility
FAQ faqs() in content.go Trust and status questions
How It's Built templates/pages/how-its-built.html Public documentation of the Go generator

Rules that keep it working

These are easy to break by accident and expensive to get wrong. Read them before changing structure, URLs, or the engine.

  1. Never change the site address or the policy URLs. /.well-known/security.txt points researchers at /security.html, and the policy pages (/privacy-policy.html, /terms-of-use.html, /security.html) may be linked from elsewhere. Renaming the subdomain or moving those files breaks those references. If a move is ever unavoidable, keep a page at the old URL that redirects to the new one.
  2. Keep How It's Built accurate. That page documents the code in detail and is meant to show the engine is understood. Any pull request that changes behaviour must update templates/pages/how-its-built.html in the same pull request. Check in particular:
    • the dependency count and approximate size (At a glance)
    • the list of build-failing rules (Validation and safety), against validate() in main.go
    • the secret patterns (The notices engine, step 1), against secretPatterns in notices.go, including how many there are
    • the notice categories, against noticeCategories() in content.go
    • the tests table (Testing and CI), against notices_test.go
    • the CI steps, against .github/workflows/deploy.yml
  3. Everything here is public. The repository and the site are public. Do not add gated content, credentials, client documents, or internal details. Notices are scanned for credential-like strings and the build fails on a match, but the scanner cannot catch everything: read each notice before merging.
  4. No links to other QCS sites. This site stands alone. Links to the QCS GitHub organization and Medium profile are fine; links to other QCS websites, or the names of other QCS repositories, are not.
  5. Notices speak for QCS. They are published in the organization's name. Name in author() in content.go is intentionally empty; setting it adds a personal byline and author box to every notice.
  6. Deploy at least once a year. security.txt gets a new Expires date (one year out) on every build; without a deploy it eventually expires.

Before merging any change

make fmt vet     # formatting and static analysis
make test        # unit tests, including validation of the real content
make check       # content validation only
make dev         # preview at http://localhost:8080 (restart after adding a notice)

CI runs go vet, go test and the build again on merge; a failure at any step leaves the live site unchanged.

Quick start

make dev      # live server on http://localhost:8080
make build    # render the site into ./public
make check    # validate content without writing anything
make fmt vet  # gofmt + go vet

Without make: go run . serve, go run . build, go run . check.

To run this alongside another local site that also uses :8080, give one of them a different port:

go run . serve -addr :8081

Adding a status provider

Add an entry to statusServices() in content.go with a Role (what the provider does; this is the only label shown) and the Kind matching its feed format:

  • kindAPIv2 — the feed has /api/v2/status.json and /api/v2/incidents.json; set both API and Incidents.
  • kindSummary — the feed has a single /summary.json; leave Incidents empty.

go run . check enforces both. A provider whose feed does not allow cross-origin requests cannot be added without a server-side proxy.

The daily bars are built from each provider's reported incidents, which is the only history these feeds expose. They track disclosure, not measured uptime.

The only dependency is Go. There is no Node toolchain.


Layout

main.go                  serve | build | check, plus the content validator
content.go               site metadata, nav, roadmap, FAQ, notice categories, pages
notices.go               the notices engine: notices/*.md -> /notices/ pages, with
                         front matter, categories, TOC, git dates, related
                         notices, search data, structured data, secret scanner
notices_test.go          unit tests (go test ./... / make test)
notices/                 Markdown notices, one file per notice
extras.go                build-time extras: What's New, sitemap.xml, robots.txt,
                         .well-known/security.txt, notices RSS feed
CHANGELOG.MD             latest entry feeds What's New; full log linked on GitHub
templates/
  base.html              shared chrome: sidebar, nav, meta tags, footer
  pages/index.html       the home page
  pages/how-its-built.html  documentation of this generator, published on the site
  pages/notices.html     the Notices index (search + category filter)
  pages/notice.html      a single notice (TOC, related notices)
  pages/category.html    one page per category, e.g. /notices/categories/incident.html
  pages/security.html    vulnerability disclosure policy
  pages/accessibility.html  accessibility statement
  pages/404.html         served by the host for any missing path
  partials/              shared snippets, loaded with every page
static/                  copied verbatim into ./public, "static/" stripped
  css/site.css           site styles
  css/doc.css            shared styles for the long documents
  js/status.js           live upstream status, fetched in the browser
  js/notices.js          copy buttons, heading links, search and filtering
  og-image.png           1200x630 link-preview image
  privacy-policy.html    hand-written, kept as authored
  terms-of-use.html      hand-written, kept as authored
  CONTRIBUTING.html      hand-written, kept as authored
  CNAME                  custom domain — must survive every deploy
  favicon.ico
public/                  BUILD OUTPUT — wiped on every build, gitignored

build also writes .nojekyll so Pages serves the output as-is.

Everyday content edits

To change… Edit
What's New, changelog Add a ## [x.y.z] — date entry to CHANGELOG.MD
Roadmap roadmap() in content.go
FAQ faqs() in content.go
Notice categories noticeCategories() in content.go
Notices Add notices/short-name.md starting with # Title

Publishing a notice

Notices are published on the next deploy. The file name becomes the URL, the first # heading the title, and the first paragraph the summary on the index. Every notice needs at least one category from noticeCategories() (Incident, Maintenance, Security Advisory, Service Change); anything else fails the build.

---
description: One sentence for search results and link previews.
categories: [Incident]
---
# API errors on 12 November

Between 14:05 and 14:40 UTC some requests failed. ...

Published and updated dates come from git history automatically (the deploy checks out full history for this); published: / updated: override them. Each category gets its own page, notices sharing categories are cross-linked, and every notice is listed in sitemap.xml and the RSS feed at /notices/feed.xml.

Every notice is scanned for things that look like credentials (cloud keys, tokens, private keys, password = …, passwords in URLs); a match fails the build so it never reaches the public site. Raw HTML in a notice is escaped. In make dev, edits to a notice show on refresh; a new notice needs a restart.

Notices are published in QCS's name. To credit an individual instead, set Name in author() in content.go; that adds a byline and author box.

.well-known/security.txt gets a fresh Expires date (one year out) on every build. Deploy at least once a year so it never expires.


Design

  • Palette: charcoal ink (#1a2332), action blue (#0066cc), sky-blue accent (#6cc5e6) from the qcloud systems wordmark, on grey/white surfaces
  • Typography: Inter
  • Layout: fixed sidebar on desktop, stacked on narrow screens
  • QCS brand palette and type

Adding a page

  1. Create templates/pages/yourpage.html wrapped in {{define "content"}} … {{end}}.
  2. Add a Page entry to pages() in content.go.

go run . check fails on a missing template, a missing document, a project without a URL, a missing CNAME, an unknown roadmap stage, an incomplete FAQ entry, a changelog without a version heading, or a malformed analytics token.


Deployment

Pushing to main triggers .github/workflows/deploy.yml: go vet, go test, go run . build, then publish ./public to the static host, which also provides HTTPS. Deployment needs no stored credentials.


Custom domain

static/CNAME holds the site's custom domain. The build copies it into the output on every deploy, and the validator fails the build if it goes missing, because losing it would silently drop the domain.


Working in GitHub Codespaces

Day-to-day workflow

main only accepts changes through pull requests, so every change goes on a branch:

git switch main && git pull           # start from the latest main
git switch -c YYMMDDShortName          # e.g. 261014PrivacyRepair
# ...edit, then run `make check` (and `make test` where available)...
git add -A
git commit -m "Short summary" -m "Longer explanation of what and why."
git push -u origin YYMMDDShortName

Then open the pull request and merge it, either on github.com (use the Compare & pull request banner, then Merge pull request) or with gh pr create --fill and gh pr merge --merge. Merging to main deploys.

Afterwards, bring your local copy up to date and delete the merged branch:

git switch main && git pull && git branch -d YYMMDDShortName

Working on another repository in the same codespace

A codespace's built-in token can only access the repository the codespace was created from. Cloning or pushing any other private repository fails with 403 Write access to repository not granted, and SSH URLs fail because a codespace has no SSH key. Use HTTPS with your personal GitHub login instead.

Sign in once per codespace, if gh is not already logged in with your account:

env -u GITHUB_TOKEN gh auth login      # GitHub.com → HTTPS → browser login

Clone with credentials stored in the new clone, so later pull and push work without extra steps:

cd /workspaces
git clone \
  -c credential.helper= \
  -c 'credential.helper=!env -u GITHUB_TOKEN gh auth git-credential' \
  https://github.com/OWNER/REPO.git

For a repository that was already cloned and now refuses to pull or push, run this once inside it:

git config credential.helper ''
git config --add credential.helper '!env -u GITHUB_TOKEN gh auth git-credential'

In those repositories, prefix gh commands the same way, for example env -u GITHUB_TOKEN gh pr create --fill.

Optional shortcut, saved to your shell profile in this codespace:

cat >> ~/.bashrc <<'BASHRC'
ghclone() {
  cd /workspaces && git clone \
    -c credential.helper= \
    -c 'credential.helper=!env -u GITHUB_TOKEN gh auth git-credential' \
    "https://github.com/$1.git" && cd "$(basename "$1")"
}
BASHRC
source ~/.bashrc
ghclone OWNER/REPO

To see several repositories side by side in the Explorer, use File → Add Folder to Workspace…, or save a .code-workspace file in /workspaces (outside every repository) and open it with File → Open Workspace from File….

Codespace usage and billing

Typical usage (measured 2026-10-14 on a 2-core codespace):

Item Usage Notes
A cloned repository a few MB each Clones are tiny next to everything else
Tools and caches in ~ about 1.6 GB Go module cache, CLI tools, editor settings
Codespace disk overall about 12 GB of 32 GB Mostly the base image: OS, languages, tools
Memory (RAM) about 2–3 GB of 8 GB Comes with the machine size; not billed separately

Free monthly allowance on a GitHub Free personal account:

Included Counts when
Compute 120 core-hours (60 hours on a 2-core machine) the codespace is running
Storage 15 GB-month the codespace exists, running or stopped

One codespace kept for a whole month uses most of the storage allowance; a second codespace kept alongside it is what pushes usage over, not extra clones.

When GitHub charges: only if a Codespaces spending limit above $0 is set. With the default $0 limit, codespaces stop when the allowance runs out and can be used again when it resets at the start of the next month. Nothing is billed and files are kept.

Check actual usage: github.com/settings/billing, under Codespaces. The allowances above can change; GitHub's documentation page "About billing for GitHub Codespaces" has the current figures.

Keeping usage low:

  • Stop the codespace when you finish (Command Palette → Codespaces: Stop Current Codespace) rather than closing the tab; idle codespaces keep running until they time out.
  • Shorten the idle timeout to 10–15 minutes at github.com/settings/codespaces.
  • Stay on a 2-core machine; larger machines use the allowance faster.
  • Keep one codespace and clone extra repositories into it, rather than creating a codespace per repository.
  • Push your work before deleting a codespace; anything not pushed is lost.
  • Delete clones you no longer need once their work is pushed.

Contributing

See CONTRIBUTING.html. Fork, branch, test locally with make dev, open a pull request.


Version history

  • 3.2.1 — Vendor-neutral site, docs and code
  • 3.2.0 — Trust & Status Center: notices engine, How It's Built page
  • 3.1.0 — Engineering Notes, roadmap, FAQ, articles, policy pages, SEO
  • 3.0.0 — Go static site generator; agreements removed from this site
  • 2.0.0 — Grey/blue redesign, GitHub Actions deployment
  • 1.0.0 — Initial documentation hub

Links


License

MIT. See the LICENSE file.

About

[PROD] - Demo info website for deployment by Github Actions on GHPages

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages