netresearch / nr-wellknown
Serve the well-known resources a TYPO3 site should provide (security.txt, change-password, gpc.json, llms.txt, agent-skills.json) from per-site configuration.
Package info
github.com/netresearch/t3x-nr-wellknown
Type:typo3-cms-extension
pkg:composer/netresearch/nr-wellknown
Requires
- php: ^8.2
- typo3/cms-core: ^12.4 || ^13.4 || ^14.3
Requires (Dev)
- ergebnis/phpstan-rules: ^2.6
- friendsofphp/php-cs-fixer: ^3.68
- netresearch/typo3-ci-workflows: ^1.2
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.5 || ^11.5
- typo3/testing-framework: ^8.2 || ^9.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-01 08:44:55 UTC
README
Serve the well-known resources a TYPO3 site should provide, from per-site
configuration. Static content is written into the docroot and served by the web
server; the one redirect (change-password) is answered by a PSR-15
middleware.
What it provides
Only the resources a corporate site genuinely should serve, each emitted only when configured:
| Resource | Path | Kind |
|---|---|---|
| Security contact (RFC 9116) | /.well-known/security.txt |
static |
| Password-change hint | /.well-known/change-password |
redirect |
| Global Privacy Control | /.well-known/gpc.json |
static |
| Agent guidance | /llms.txt |
static |
| Agent skills discovery | /.well-known/agent-skills.json |
static |
Resources this extension deliberately does not create — OAuth, WebAuthn,
NodeInfo/fediverse, apple-app-site-association, api-catalog, IndexNow and
the other agent-readiness documents — are genuinely not-applicable to a site that
does not offer them. A 404 is the correct answer there; do not fabricate them.
Scope: frontend only, never the backend
Well-known URIs describe the site to its visitors — the frontend. Nothing this extension serves may reference the TYPO3 backend:
change-passwordtargets the page where a frontend user (fe_users— member area, customer portal) changes their password. It must never point at the backend login (/typo3): a well-known URI advertising the admin login is an invitation, not a service. The extension has no default target — a site without frontend accounts simply leaveschangePasswordunconfigured and the path answers404, which is the correct, honest response.- The same rule applies to every other resource: content is site/visitor-facing configuration, never backend URLs, backend users or internal infrastructure.
Requirements on the web server
The static files must be reachable under /.well-known/ and absent paths must
fall through to TYPO3 so the change-password middleware is reached. In the
Netresearch t3re runtime the nginx block must read:
location ^~ /.well-known/ {
try_files $uri $uri/ @t3frontend;
}
A block that only allow all serves static files but 404s absent paths before
PHP — the change-password redirect would never be reached.
Configuration
Per site, in config/sites/<site>/config.yaml under a wellknown key. Every
value is optional; a resource is emitted only when its required fields are set:
wellknown:
security:
contacts: ["mailto:security@netresearch.de"] # >=1 required to emit
policy: "https://www.netresearch.de/security-policy"
preferredLanguages: ["de", "en"]
expiresMonths: 6 # default 6, minimum 1
changePassword:
target: "https://www.netresearch.de/mein-konto/passwort" # required to emit
gpc: true # default true
llms:
source: "EXT:sitepackage/Resources/Public/llms.txt" # file ref or inline text
agentSkills:
skills: [] # emitted only if non-empty
Generation and refresh
Run at deploy time:
vendor/bin/typo3 nr:wellknown:generate
This writes the configured files into public/.well-known/ (and public/llms.txt)
and recomputes security.txt's Expires as now + expiresMonths, where
expiresMonths is floored at 1 so a value of 0 or a negative one cannot
produce an already-expired file. Re-running on every deploy keeps Expires
valid, so the file never silently lapses. A site that deploys rarely should add
a Scheduler task or CI cron invoking the same command. The generated files carry a moving date and are not committed to git.
Acceptance
Verify with the Website-Specification conformance checker: the in-scope criteria
flip to met, the out-of-scope ones stay correctly not applicable, and
curl -sI https://<host>/.well-known/security.txt returns 200 with a future
Expires.
Architecture and security
docs/SECURITY-ASSURANCE.md describes the components, actors and data flows, what the extension does and does not guarantee in terms of security, its trust boundaries, and how it counters common weaknesses.
Governance and policies
This extension follows the organisation-wide Netresearch policies:
- Governance: ownership, roles, how decisions are made and conflicts resolved.
- Roadmap: planned and excluded work for the next twelve months.
- Handling of dependency and code analysis findings: which vulnerability, licence and static-analysis findings must be fixed, by when, and how exceptions are recorded.
- Secret management: where CI and release credentials are stored, who may use them, how committed secrets are detected, and when secrets are rotated.
- Access roster: the people and teams with administrative or write access to this repository.
Checks that run on every pull request in this repository:
.github/workflows/checks.yml: Composer Audit (fails on any advisory for an installed package;composer.jsonlists noconfig.audit.ignoreexceptions) and Opengrep SAST (fails a pull request as the organisation rule sets out), both throughtypo3-ci-workflows'security.yml; Dependency Review (fails on newly added dependencies with a vulnerability of severity high or higher); PHP License Audit (license-check.yml, fails whencomposer licensesreports a dependency licence ofSSPL,BSLorBUSL, or anSSPL-orBUSL-identifier of any version;BSL-1.0passes); CodeQL with language auto-detection, which finds no JavaScript or Go here and analyses the workflow files (CodeQL has no PHP analysis; PHPStan and Opengrep cover the PHP code); Betterleaks secret scanning; zizmor for the workflow files (reported to code scanning, not blocking);pr-quality(the pull request size check, and the automatic approval of pull requests that maintainers open); the aggregate gateAll security checks, which fails when any of these jobs fails. The fuzz job finds noBuild/phpunit.xmland is skipped. The OpenSSF Scorecard job runs only on pushes tomainand on the weekly schedule..github/workflows/ci.yml: PHP lint on PHP 8.2 to 8.5; code style (PHP-CS-Fixer,Build/.php-cs-fixer.dist.php) and Rector (Build/rector.php) on PHP 8.2; PHPStan (level 10,Build/phpstan.neon), the advisoryPHPStan (unpinned PHPUnit)job, which runs PHPStan once more against the newest PHPUnit, unit tests and functional tests (SQLite) on PHP 8.2 to 8.5 with TYPO3 ^12.4, ^13.4 and ^14.3. Fractor is not part of the CI run, and there is noDocumentation/directory to render. The aggregate gateci / All CI checksfails when any of these jobs fails.