Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
506f09d
fix(scripts): ask for HTML when checking external links
LKSNDRTMLKV Oct 27, 2026
f0a0152
chore(deps): upgrade Astro to 7.4 and pin Node 24.18.0 for builds
LKSNDRTMLKV Oct 27, 2026
6a1acfc
docs: rewrite the docs site for developers
LKSNDRTMLKV Oct 27, 2026
4fc903d
docs: say supersede sends the superseded event
LKSNDRTMLKV Oct 27, 2026
8a9794d
fix(scripts): check that link anchors resolve
LKSNDRTMLKV Oct 27, 2026
e853ca3
docs(web): state the Node version builds need
LKSNDRTMLKV Oct 27, 2026
5e0eb4f
docs: name GS1 Digital Link as one digital link
LKSNDRTMLKV Oct 27, 2026
90f6141
docs: say the pages describe main
LKSNDRTMLKV Oct 27, 2026
b0402a8
ci: run CI on staging and aim Dependabot there
LKSNDRTMLKV Oct 27, 2026
bb4884c
chore(docs): vendor the acts from dpp-core
LKSNDRTMLKV Oct 27, 2026
f79b635
docs: render passport dates from the catalog
LKSNDRTMLKV Oct 27, 2026
ecc5dd7
fix(landing): read passport dates from the catalog
LKSNDRTMLKV Oct 27, 2026
2550e9b
fix(docs): give the API page its own frame
LKSNDRTMLKV Oct 27, 2026
fc74890
docs: make the battery the worked example
LKSNDRTMLKV Oct 27, 2026
dd609ee
docs: drop the DID proxy rewrite
LKSNDRTMLKV Oct 27, 2026
3342a43
docs: use the battery in the core overview
LKSNDRTMLKV Oct 27, 2026
daf4ae1
docs: show the battery v2.10.0 quick start output
LKSNDRTMLKV Oct 27, 2026
7b1d75e
fix(landing): label acts that feed other passports
LKSNDRTMLKV Oct 27, 2026
cd04da2
chore(landing): vendor core with battery 2.10
LKSNDRTMLKV Oct 27, 2026
a4b75df
ci: bump actions/setup-node to v7.1.0
LKSNDRTMLKV Oct 27, 2026
c45834d
ci: read .node-version and time-limit CI
LKSNDRTMLKV Oct 27, 2026
96f41a2
ci: scan the lockfile for advisories daily
LKSNDRTMLKV Oct 27, 2026
0480fc5
ci: group Dependabot updates, hold TypeScript 7.0
LKSNDRTMLKV Oct 27, 2026
8112fc2
docs(web): lay the README out like core's
LKSNDRTMLKV Oct 27, 2026
cc2eef5
ci: add the PR-title and workflow-lint gates
LKSNDRTMLKV Oct 28, 2026
2bf7dc6
chore(docs): bump the vendored API spec to 22f8d8b46 (#45)
LKSNDRTMLKV Nov 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,62 @@
version: 2
# Every entry waits a week after a release before proposing it (`cooldown`). A
# release that is malicious or broken is usually withdrawn within days, and
# nothing on these sites needs to be first to adopt one. Security updates ignore
# the cooldown.
updates:
# Version updates open against staging, where the previews are reviewed;
# staging is promoted to main by hand. Security updates always target the
# default branch whatever this says, so retarget those to staging.
- package-ecosystem: npm
directory: "/"
target-branch: staging
schedule:
interval: weekly
day: monday
cooldown:
default-days: 7
labels:
- dependencies
groups:
# Astro, its integrations and the packages that render inside it move
# together. Bumped one at a time, each pull request tests a combination
# nobody will ship, and a peer-range mismatch fails all of them.
astro:
patterns:
- "astro"
- "@astrojs/*"
- "@scalar/*"
- "vue"
# Everything else in one weekly pull request, minor and patch only. A
# major version arrives on its own, so its changes are read on their own.
minor-and-patch:
patterns:
- "*"
update-types:
- minor
- patch
ignore:
# `astro check` refuses TypeScript 7.0 by name ("install TypeScript 6
# instead"), and its successor needs TypeScript 7.1 or later. Lift this
# when the checker supports the release Dependabot proposes.
- dependency-name: typescript
versions:
- "7.0.x"

- package-ecosystem: github-actions
directory: "/"
target-branch: staging
schedule:
interval: weekly
day: monday
cooldown:
default-days: 7
labels:
- dependencies
- ci
groups:
# The workflows pin each action to a commit, so a bump touches several
# files at once; one pull request per week keeps them consistent.
actions:
patterns:
- "*"
4 changes: 2 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

## Checklist

CI runs these on the pull request; run them locally first, since a push to
`staging` alone runs no CI. Links, spacing, llms.txt and sitemaps read the build, so build first.
CI runs these on the pull request and again on the push that lands it on `staging`
or `main`. Links, spacing, llms.txt and sitemaps read the build, so build first.

- [ ] `pnpm -r build` and `pnpm -r check`
- [ ] `pnpm run check:links`, `check:spacing`, `check:leakage`, `check:llms` and `check:sitemaps`
Expand Down
47 changes: 47 additions & 0 deletions .github/workflows/advisories.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Advisories

# A new advisory against an unchanged lockfile reaches nobody otherwise.
#
# The audit step in ci.yml runs on pull requests and pushes, so it answers "is
# this change safe" and nothing else. npm advisories are published against
# packages already in the lockfile: the tree does not change, no run is
# triggered, and the first anyone hears of it is the next pull request, which
# then fails for a reason it did not cause. That is how six Dependabot pull
# requests went red in October 2026.
#
# This run exists to fail on a day when nothing was committed. It reads the
# committed pnpm-lock.yaml only, so it needs no install and no build.

on:
schedule:
# 06:20 UTC daily, after the dpp-core and dpp-engine scans and clear of the
# nightly API-spec sync.
- cron: '20 6 * * *'
workflow_dispatch:

permissions:
contents: read

jobs:
advisories:
name: npm advisories against the committed lockfile
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Enable Corepack
run: corepack enable

- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version-file: .node-version

# The same level the pull-request gate uses, so a finding here is one a
# pull request would also fail on.
- name: Audit dependencies
run: pnpm audit --audit-level high
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI

on:
push:
branches: [main]
branches: [main, staging]
pull_request:

# The job builds and inspects; it never writes to the repository. Without this
Expand All @@ -21,13 +21,17 @@ concurrency:
jobs:
build:
runs-on: ubuntu-latest
# A full run takes a minute or two. Without a limit a hung step holds the
# runner for GitHub's default of six hours.
timeout-minutes: 30
steps:
# Full history: each sitemap <lastmod> is the last commit that changed its
# page (scripts/git-lastmod.mjs), and a shallow clone knows one commit.
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
persist-credentials: false

# The vendored OpenAPI spec is a copy of the engine's. Without the source
# beside it there is nothing to compare against, and a drift check that
Expand Down Expand Up @@ -58,9 +62,9 @@ jobs:
run: corepack enable

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.18.0
node-version-file: .node-version
cache: pnpm

- name: Install dependencies
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/external-links.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Enable Corepack
run: corepack enable

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.18.0
node-version-file: .node-version
cache: pnpm

- name: Install dependencies
Expand Down
74 changes: 74 additions & 0 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# A squashed pull request *is* a commit, and its title becomes that commit's
# subject on staging and then on main. Titles here have reached history as prose
# ("Home page redesign, community page, checklists and roadmap additions",
# "staging → main: the dpp-web audit remediation") because nothing checked them.
# dpp-core and dpp-engine gate the same rule; this brings the sites in line.
#
# The check sits on the title because that is the field the squash reads.
name: PR title

on:
pull_request:
# `edited` matters as much as `opened`: a title corrected after review must
# re-run, and a title broken after approval must fail.
types: [opened, edited, synchronize, reopened]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
conventional-commit:
name: PR title is a conventional commit
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Check title
env:
# Passed as an environment variable, never interpolated into the
# script body. A PR title is attacker-controlled text, and a
# `${{ … }}` expression inside `run:` is substituted before bash sees
# it, so a title containing a quote and a semicolon would execute.
TITLE: ${{ github.event.pull_request.title }}
# The repo's own name is not a scope: a repo's history is already
# scoped to that repo.
FORBIDDEN_SCOPES: 'web|dpp-web'
run: |
set -euo pipefail

TYPES='build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test'

printf 'title: %s\n\n' "$TITLE"

if ! printf '%s' "$TITLE" | grep -qE "^(${TYPES})(\([a-z0-9._,-]+\))?!?: .+"; then
printf '::error::PR title is not a conventional commit\n'
printf '\n'
printf 'Expected: type(scope): subject\n'
printf 'Got: %s\n' "$TITLE"
printf '\n'
printf 'type must be one of: %s\n' "${TYPES//|/, }"
printf 'scope is optional, lowercase, and names the area touched\n'
printf '(landing, docs, seo, ci, deps) rather than the repo. Several may\n'
printf 'be comma-separated: chore(landing,docs).\n'
printf '\n'
printf 'This title becomes the squash commit subject.\n'
exit 1
fi

SCOPE=$(printf '%s' "$TITLE" | sed -nE "s/^(${TYPES})\(([a-z0-9._,-]+)\).*/\2/p")
if [ -n "$SCOPE" ] && printf '%s' "$SCOPE" | grep -qE "^(${FORBIDDEN_SCOPES})$"; then
printf '::error::Scope %s is this repository own name\n' "$SCOPE"
printf 'Use the area touched: landing, docs, seo, ci.\n'
exit 1
fi

# Advisory only. The squash appends " (#NN)", whose width varies, so a
# hard limit here would reject titles that end up fine.
if [ "${#TITLE}" -gt 50 ]; then
printf '::warning::Title is %s characters; the convention is under 50 before the (#NN) suffix\n' "${#TITLE}"
fi

printf 'OK\n'
10 changes: 7 additions & 3 deletions .github/workflows/sync-openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ jobs:
steps:
# Work lands through staging (see the README), so the bump is made on top
# of staging and proposed into it, not into main.
- name: Checkout
#
# This is the one checkout that keeps its credentials: the last step pushes
# the bump branch with them. Nothing in the job uploads an artifact, which
# is how persisted credentials leak, so the finding is accepted here.
- name: Checkout # zizmor: ignore[artipacked]
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: staging
Expand All @@ -59,9 +63,9 @@ jobs:
run: corepack enable

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.18.0
node-version-file: .node-version
cache: pnpm

- name: Install dependencies
Expand Down
96 changes: 96 additions & 0 deletions .github/workflows/workflow-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Workflow lint

# Static analysis of the workflows themselves, the same gate dpp-core runs.
#
# Several workflows here hold something worth taking: `sync-openapi.yml` can
# write to the repository and open pull requests, `deploy.yml` holds a Cloudflare
# API token, and every build runs `pnpm install`, which executes third-party
# install scripts with a token in reach. Two tools, because they find different
# things:
#
# zizmor security: credentials left in `.git/config` by a checkout, actions
# that are not pinned or whose pinned commit is not in the
# repository it names, an action with a published advisory,
# expressions that inject into a shell, and Dependabot settings.
# actionlint correctness: workflow syntax, expression types, and the shell
# inside every `run:` (it runs `shellcheck` where that is installed,
# which it is on the runner).
#
# The one accepted finding is marked where it occurs: `sync-openapi.yml` keeps
# its checkout credentials because it pushes with them. The default `regular`
# persona gates. The `pedantic` one, which reports code smells such as a missing
# `concurrency` block, is deliberately not.
#
# Both tools are downloaded from their release and checked against the SHA-256
# recorded here, the same versions and hashes dpp-core pins, so the bytes that
# run are the bytes that were read. Dependabot cannot see either pin; moving one
# is a deliberate edit, on a pull request of its own, because a newer version may
# find something the pinned one does not.
#
# Not path-filtered, so it can be made a required check without blocking every
# pull request that leaves `.github/` alone. The weekly run covers the other way
# a workflow goes bad: an advisory published against an action already pinned
# here, with no commit to trigger anything.
on:
push:
branches: [main, staging]
pull_request:
schedule:
- cron: "0 5 * * 1"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
ZIZMOR_VERSION: "1.30.1"
ZIZMOR_SHA256: e65324f4430c2717591937edcec90ccbefaf14c174f8ec9415e03ca875b46e1a
ACTIONLINT_VERSION: "1.7.12"
ACTIONLINT_SHA256: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8

jobs:
zizmor:
name: Workflows pass zizmor
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- name: Install zizmor
run: |
curl -fsSL -o zizmor.tar.gz "https://github.com/zizmorcore/zizmor/releases/download/v${ZIZMOR_VERSION}/zizmor-x86_64-unknown-linux-gnu.tar.gz"
echo "${ZIZMOR_SHA256} zizmor.tar.gz" | sha256sum -c -
mkdir -p "$RUNNER_TEMP/bin"
tar -xzf zizmor.tar.gz -C "$RUNNER_TEMP/bin" zizmor
echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
# The token lets zizmor ask GitHub the questions it cannot answer from the
# files: whether a pinned commit belongs to the repository it names, and
# whether an action has a published advisory. It is the workflow's own
# read-only token, and nothing here writes.
- name: zizmor
env:
GH_TOKEN: ${{ github.token }}
run: zizmor --format github .github

actionlint:
name: Workflows pass actionlint
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- name: Install actionlint
run: |
curl -fsSL -o actionlint.tar.gz "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
echo "${ACTIONLINT_SHA256} actionlint.tar.gz" | sha256sum -c -
mkdir -p "$RUNNER_TEMP/bin"
tar -xzf actionlint.tar.gz -C "$RUNNER_TEMP/bin" actionlint
echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
- name: actionlint
run: actionlint -color
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24.18.0
Loading
Loading