rechtzeitig

The workflow

Everything you can set when you run rechtzeitig, and what you get back.

§ 1Inputs

InputDefaultMeaning
urlemptyStart page to check. Empty scans only the repository.
languagedeLanguage of the site: de, en or all. Decides which words count as "Impressum", "Datenschutz" and so on.
subscriptionsfalsetrue if visitors can sign up for subscriptions. Turns on the cancellation button check (§ 312k BGB).
salesfalsetrue if consumers buy or sign contracts on the site. Turns on the withdrawal button check (§ 356a BGB).
modulesallComma list of check groups: legal, privacy, security, sustainability, accessibility, repo.
report-languagelanguagede or en. The whole report follows it: messages, details, titles and fix hints. Empty uses the site language; with all the report is in English.
fail-onneverWhen the run turns red, see fail-on.
max-pages10Pages to visit at most.
repositoryworkspaceFolder to read lockfiles, licenses and secrets from. Needs actions/checkout before rechtzeitig.
ipinfo-tokenemptyOpt-in. Token from ipinfo.io, passed from the secret IPINFO_TOKEN. Turns on the third-country check. Empty skips it, see Secrets.
vulnerabilitiestrueLooks up known vulnerabilities of locked components at osv.dev. false sends nothing there and the vulnerability check is skipped.
require-sandboxtrueStops the scan when Chrome cannot start with its sandbox. false scans without it, see Safe use.
retention-days7Days GitHub keeps the report artifact, see The report.

The output result is pass, warn or fail.

§ 2What runs when

Most checks run whenever their target is there. The ones below need a setting. A check that is off shows as skip in the report, with the reason and the setting that turns it on. The example workflow scans the website and the repository.

CheckRuns when
All website checksOnly with a url.
All repository checksOnly when actions/checkout runs before rechtzeitig (folder: input repository).
A group of checksmodules picks groups: legal, privacy, security, sustainability, accessibility, repo. Empty runs all.
Cancellation button for subscriptions
LEG-DE-BTN-001
Opt-in: only with subscriptions: true.
Withdrawal button for online contracts
LEG-DE-BTN-002
Opt-in: only with sales: true.
Privacy policy names transfers outside the EU
LEG-EU-DSE-005
Opt-in: only when the secret IPINFO_TOKEN is set (input ipinfo-token, token from ipinfo.io). Without it the check is skipped and nothing is sent.
Sends data to ipinfo.io (opt-in)
No dependencies with known vulnerabilities
SEC-DEPS-001
On by default; sends data to api.osv.dev. Turn it off with vulnerabilities: false.
Sends data to api.osv.dev

§ 3fail-on

Every check ends as pass warn fail info or skip. fail-on decides which of these make the run red. The report is the same either way.

fail-onRun is red when1 fail, 2 warn0 fail, 2 warn
never (default)nevergreengreen
failany check failsredgreen
warnany check fails or warnsredred

The default never turns a run red, so adding rechtzeitig cannot break anything. Choose fail once the findings are fixed and you want to keep it that way, or warn before a launch.

§ 4Secrets

Every check that needs an API token is opt-in. It runs only when you add the token as a repository secret. Without the secret it shows as skip in the report, and nothing is sent to that service. All other checks need no secret.

SecretInputTurns onToken from
IPINFO_TOKENipinfo-tokenTransfers outside the EU (LEG-EU-DSE-005)ipinfo.io, the free plan is enough

To add a secret: repository Settings → Secrets and variables → Actions → New repository secret, with the name from the table. The example workflow already passes it to the input.

rechtzeitig sends only the IP addresses of third-party servers to IPinfo, never data about your visitors.

§ 5The report

The summary page of the run shows a table of all checks with details, in the report language. Findings in a file of the repository also appear as annotations: in a pull request at the line, otherwise on the run page. GitHub shows at most 10 errors and 10 warnings there; the summary and the artifact always have all of them. The artifact rechtzeitig-report contains:

FileContent
rechtzeitig-report.mdThe same report as Markdown
rechtzeitig-report.jsonFindings: rule id, severity, status, message in the report language with its key and parameters, and locations. No page text or file contents
rechtzeitig-sbom.cdx.jsonSBOM in CycloneDX 1.6 format, with vulnerabilities

Keep the SBOM with each release. It shows which versions you shipped and that you checked them.

GitHub deletes the artifact after retention-days (default 7). On a public repository anyone signed in to GitHub can download it, including the list of your dependencies and where findings were found.

§ 6How the website is visited

Each page is loaded twice in a fresh Chromium, once with JavaScript off and once with it on. Nothing is clicked and no consent is given, so every request and cookie in the report happened before consent. rechtzeitig opens the start page, every legal page it finds, a sample of other pages, and a short list of paths that must not be public (/.env, /.git/config, backups).

GitHub's runners are in US data centers. A site that shows its consent banner only to EU visitors will look different here, and that is a finding in itself. Pages behind a login are not checked.

§ 7Data that leaves the runner

Besides visiting your website, rechtzeitig sends data to two services. Nothing else leaves the runner.

ServiceWhat is sentWhen
api.osv.devPackage URLs (name and version) of all locked components, for example pkg:npm/lodash@4.17.21By default, when the repository is scanned. Turn it off with vulnerabilities: false
ipinfo.ioIP addresses of third-party servers that rechtzeitig does not knowOnly when IPINFO_TOKEN is set

§ 8Safe use

Never run rechtzeitig in a workflow triggered by pull_request_target. That trigger runs with your secrets and a token that can write to the repository, while the scanned code comes from a fork. Use workflow_dispatch, schedule, push or pull_request.

Check out with persist-credentials: false as in the example workflow. rechtzeitig does not need the token, so it should not be left in the checkout.

The scanned site is untrusted. Chrome runs with its sandbox. On GitHub-hosted runners with Ubuntu 23.10 or later, the action installs an AppArmor profile that allows the user namespaces the sandbox needs, for the Chrome binary only; those runners are discarded after the job. On self-hosted runners it changes nothing. Where the runner has no sandbox, the scan stops. require-sandbox: false scans anyway; only do that for sites you trust. Neither the browser nor any other request reaches private addresses (localhost, 10.x, cloud metadata), except the host of url itself.

rechtzeitig is a composite action and sets up Node 24 with actions/setup-node. That Node stays on the PATH for the steps after it in the same job. Set up your own Node version after rechtzeitig, or run it in a separate job.