DocsRule packs

Rule packs

A rule pack is a set of review rules and regex checks for one area, written from published guidance: vendor documentation, security standards and SRE practice. Each rule names its source.

Packs complement the rules that a repository takes from its own review history. History rules repeat what your reviewers asked for in the past. Packs add what the industry already knows, for areas where your reviewers comment less often, such as CI, images, infrastructure and observability.

The packs

Pack Rules Checks Covers
ci-cd CI-1…CI-11 5 Pinned actions, token permissions, privileged triggers, script injection, OIDC, secrets, lockfile builds, timeouts, provenance, required checks, reusable workflows
containers CT-1…CT-7 4 Pinned bases, non-root, secrets in layers, multi-stage, exec form, COPY, one service per image
kubernetes K8-1…K8-9 4 Pod security standard, secrets, RBAC, network policy, resources, probes, pinned images, disruptions, overlays and values
terraform TF-1…TF-8 3 Pinned versions, remote state, secrets, refactors without destroy, IAM and network, plan in CI, module design, variables
observability OB-1…OB-10 1 Structured logs, no secrets in logs, log levels, trace context, golden signals, metric names, label cardinality, health endpoints, alerts, error context
scalability SC-* 3 Guidelines with proof: see guidelines.md
modularity MD-* 1 Guidelines with proof: see guidelines.md
code-quality CQ-* 5 Guidelines with proof: see guidelines.md
shell-make SH-1…SH-8 2 Strict mode, quoting and ShellCheck, no curl | sh, no fixed sleeps, idempotent scripts, config from env, idiomatic Make

Modularity is part of each pack where it applies: CI-11 (reusable workflows), CT-7 (one service per image), K8-9 (overlays and values), TF-7 (modules), SH-7 and SH-8 (Make and scripts).

The sources are the GitHub Actions hardening guide, GitHub Security Lab, the OpenSSF Scorecard checks, SLSA, the Docker and hadolint docs, the Kubernetes docs, the Helm best practices, the HashiCorp Terraform docs, Google Cloud IAM, the Prometheus practices, the Google SRE book and workbook, OpenTelemetry, W3C Trace Context, the OWASP Logging Cheat Sheet, ShellCheck, the Google Shell Style Guide, GNU Make and the Twelve-Factor App.

Add a pack to a repository

desk packs                          # list the packs; ✔ marks the ones in this repository
desk packs add ci-cd containers     # or: desk init --packs ci-cd,containers
desk preflight                      # see the new checks on your branch

packs add does two things:

  1. It copies the rules to .desk/rules/<pack>.md. Every review loads the file when a changed path matches its paths.
  2. It adds the pack's checks to checks in .desk/config.json. preflight runs them on the added lines of each change, with no model.

After that, the repository owns the copies. Edit or delete a rule that does not fit, change a check from warning to blocking ("blocking": true), or narrow its include globs. A second packs add keeps your edits; --force replaces them with the kit's version.

Most pack checks start as warnings, because an existing repository can have many old hits. A check runs only on added lines, so old code never blocks a PR. Turn a check to blocking when the team agrees.

Which profile uses a pack

The rules of a pack load by path, for every profile. The devops profile also names the pack rule prefixes (CI-*, CT-*, K8-*, TF-*, SH-*, OB-*) and checks them first. The reliability and security profiles use OB-* and the secret rules.

Write a new pack

  1. Create packs/<name>/rules.md in the desk repository. Start it with front matter:

    ---
    description: One line that `desk packs` prints.
    paths: ['globs/**', 'of/the/files/**', 'the/pack/covers/**']
    ---
    
  2. Write each rule in the same form as the existing packs:

    ### XX-1: A short rule, as a command
    
    - **Rule:** What the code must do, in one to three sentences, with the condition first.
    - **Severity:** blocker | important | nit
    - **Scope:** the files it applies to
    - **Detect:** check `CHK-XX1`, or llm-review
    - **Source:** [Name of the page](https://link.to/the/source)
    
    • Use a prefix of two or three capital letters that no other pack or repository uses.
    • Each rule needs a source that a reader can open. Check that the link works.
    • Keep a pack below about 12 rules. A long list gets a shallow review.
  3. If a regex can find a violation on one added line, add a check to packs/<name>/checks.json:

    [
      { "id": "CHK-XX1", "rule": "XX-1: the rule in a few words", "pattern": "regex", "include": ["globs/**"], "blocking": false }
    ]
    
    • The pattern is a JavaScript regular expression, and it runs on one added line at a time.
    • Start with "blocking": false, unless a hit is always a real problem (for example a secret).
    • Add a test in test/cli.test.mjs that plants a violation and checks the file and the line of the hit.
  4. Add a row to the table in this file, run npm test, and open a PR on desk.

A rule that only one repository needs goes into that repository's .desk/rules/, not into a pack.