## Merge order Merge first; then republish the docs; then coder/coder.com#1100 (the redirects). ## Summary The nine pages under `docs/about/contributing/` are for people working in this repository, not for Coder users or administrators, so they leave the published documentation. The repository becomes their canonical home. Until now the root `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md` were two-line stubs that only linked to the docs site, so contributors on GitHub were bounced out to read them. A companion PR in `coder/coder.com` adds redirects from every retired `/docs/about/contributing/*` URL to the new GitHub location. It must merge only after this PR has merged and the docs have republished. ## Changes | Old path | New path | | -- | -- | | `docs/about/contributing/CONTRIBUTING.md` | `CONTRIBUTING.md` (replaces the stub) | | `docs/about/contributing/CODE_OF_CONDUCT.md` | `CODE_OF_CONDUCT.md` (replaces the stub) | | `docs/about/contributing/SECURITY.md` | deleted; the root `SECURITY.md` already holds the policy | | `docs/about/contributing/AI_CONTRIBUTING.md` | `contributing/AI_CONTRIBUTING.md` | | `docs/about/contributing/backend.md` | `contributing/backend.md` | | `docs/about/contributing/frontend.md` | `contributing/frontend.md` | | `docs/about/contributing/modules.md` | `contributing/modules.md` | | `docs/about/contributing/templates.md` | `contributing/templates.md` | | `docs/about/contributing/documentation.md` | `contributing/documentation.md` (see note below) | For every moved file: the docs front matter is stripped and its `title` becomes the H1, relative links are rewritten for the new depth (`../../../foo` becomes `./foo` at the root and `../foo` under `contributing/`; the two links into `docs/admin/` become `../docs/admin/...`), and the docs-only `<div class="tabs">` wrapper in `CONTRIBUTING.md` is removed. `CONTRIBUTING.md` gains a short intro that links the code of conduct, the security policy and the area guides, since GitHub only auto-surfaces the root files. `docs/manifest.json` loses the About → Contributing group and `docs/images/icons/contributing.svg`, which only that group used. Inbound references updated: - `README.md`: contribution guide link now points at `CONTRIBUTING.md` on GitHub. - `docs/tutorials/example-guide.md` and `docs/install/releases/feature-stages.md`: link to `contributing/documentation.md` on GitHub, since a docs page cannot link to a repo-only file. - `docs/.style/style-guide/README.md`: the "Relationship to" section names the new location. - `scripts/docshtmlcheck/main.go`: both the package comment and the user-facing error string name `contributing/documentation.md`. - `scripts/docshtmlcheck/README.md`: relative link to the new location. - `coderd/database/migrations/migrate_test.go`: `t.Log` link now points at `contributing/backend.md#database-fixtures-for-testing-migrations`. - `.github/pull_request_template.md`: AI contribution guidelines link. - `.github/workflows/contrib.yaml`: commit-message guidelines link in the PR title check. - `.github/workflows/test-docs-preview-mapper.sh`: the mapper test case that used `docs/about/contributing/CONTRIBUTING.md` now uses `docs/admin/security/audit-logs.md`. - `.claude/docs/{ARCHITECTURE,PR_STYLE_GUIDE,WORKFLOWS,DOCS_STYLE_GUIDE}.md`: links to `CONTRIBUTING.md`. `git grep about/contributing` is empty after this change. `CODEOWNERS` had no entry for the old paths. Note on `documentation.md`: it is docs-authoring guidance and is parked in `contributing/` for now. Folding it into `docs/.style/` is tracked separately and is deliberately not attempted here. ## Testing - `go run ./scripts/docshtmlcheck` over `docs/`, and again over `contributing/`, `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md`: clean. - `go vet ./scripts/docshtmlcheck/...` and `go test ./scripts/docshtmlcheck/...`: 47 tests pass. - `go vet ./coderd/database/migrations/...`: clean. `go test` for that package fails to link on this machine (`tailscale.com/tstime/mono: invalid reference to runtime.nanotime1`) identically on unmodified `main`, so it is a local toolchain issue and not exercised here; the change is a string in a `t.Log`. - `pnpm check-docs` (markdownlint-cli2 and markdown-table-formatter over `docs/`, `.claude/docs/`, root `*.md`): 495 files, 0 errors. The same two tools over `contributing/*.md`: 0 errors. - Every relative link in the eight moved files resolves to an existing path (scripted check). - `bash .github/workflows/test-docs-preview-mapper.sh`: the changed `assert_maps_to` case passes; the six `resolve_ref`/`pages_for_image` failures it reports are identical on unmodified `main` on macOS. Linear: [DOCS-975](https://linear.app/codercom/issue/DOCS-975) --- 🤖 Built with AI assistance.
3.6 KiB
docshtmlcheck
docshtmlcheck fails CI when Markdown under docs/ contains invalid inline
HTML that the documentation site's renderer silently drops or mangles. It runs
as make lint/docs-html (part of make lint).
What it catches
- Swallowed angle-bracket placeholders. An unwrapped placeholder such as
<region>or<server>__is parsed as an unknown HTML tag and stripped from the rendered page, so readers see broken text. Wrap placeholders in backticks so they render as inline code (seecontributing/documentation.md). This also covers CLI--helpstrings and Swagger annotations, whose text is generated intodocs/reference/**. - Void-element end tags such as
</br>. Void elements like<br>,<img>, and<hr>have no end tag. - Capitalized or unregistered component tags such as
<Image>or<Table>. The docs renderer reads a capitalized tag as a component reference and drops it unless the component is registered (only the lowercase<children>directive is). Any name outside the standard HTML5 element set is reported the same way. - Unclosed container tags, for example a
<div class="tabs">that is never closed and leaks its wrapper over the rest of the page.
How it works
Each file is parsed with goldmark and only
raw-HTML nodes are inspected, so angle brackets inside fenced code blocks,
inline code spans, HTML comments, and <https://…> / <user@host> autolinks
are ignored. Each raw-HTML node is tokenized as a whole with
golang.org/x/net/html, so a tag whose attributes wrap across lines is not
torn in half. A tag whose raw name is capitalized is reported as a component
reference; otherwise any name outside the standard HTML5 element set (plus the
intentional <children> renderer component, which is still balance-checked) is
reported. Inline SVG and MathML are intentionally not in the allowed set (no
docs page uses them); add the element to allowedElements in main.go if that
changes. A finding on a generated page under docs/reference/** also prints a
note pointing at the generator source, since edits to the generated file do not
persist.
Limitations
A few gaps are accepted because no docs page hits them today:
- A placeholder whose name is itself a real HTML element (
<input>,<time>) is indistinguishable from intended markup and passes. Such placeholders almost always live in fenced code blocks, which are ignored. - The interior of a raw-text element (
<script>,<style>) is a single opaque token to the HTML tokenizer, so a tag nested inside one is not scanned. An unclosed<script>/<style>is still caught.
Usage
$ go run ./scripts/docshtmlcheck # scans docs/
$ go run ./scripts/docshtmlcheck path/to/file.md path/to/dir
Allowlist
allowedUnknownTags in main.go is a deliberately narrow, per-file escape
hatch for placeholders whose source is outside this repository (so they cannot
be fixed by a source edit here). It currently holds a temporary entry for
docs/reference/cli/agent-firewall.md (<host>/<glob>, generated from the
external github.com/coder/boundary CLI help).
The escape hatch is self-clearing: if an allowlisted tag no longer appears
in its file (for example once the upstream fix and dependency bump land and the
generated page no longer emits the bare placeholders), the linter reports a
stale-allowlist-entry and fails until the dead entry is removed, so a
suppression can never silently mask a later regression of the same tag.