Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 17 additions & 1 deletion .claude/cloud-bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,24 @@ fi
if [[ -f package-lock.json ]]; then
if [[ ! -f node_modules/.package-lock.json ]] ||
[[ package-lock.json -nt node_modules/.package-lock.json ]]; then
npm ci --no-audit --no-fund >/dev/null 2>&1 ||
if npm ci --no-audit --no-fund >/dev/null 2>&1; then
# A repo whose .npmrc sets ignore-scripts=true skips Lefthook's
# postinstall, so install the hooks through `prepare`, skipped under
# the same condition as that postinstall: CI set and LEFTHOOK unset
# (a value of "", 0 or false counts as unset).
hooks_skipped=false
case "${CI:-}" in
'' | 0 | false) ;;
*) case "${LEFTHOOK:-}" in '' | 0 | false) hooks_skipped=true ;; *) ;; esac ;;
esac
if [[ "$hooks_skipped" == false &&
"$(npm config get ignore-scripts 2>/dev/null)" == true ]]; then
npm run prepare --if-present >/dev/null 2>&1 ||
toolchain_warn 'npm run prepare failed; git hooks are not installed'
fi
else
toolchain_warn 'npm ci failed; node_modules is unavailable this session'
fi
fi
fi

Expand Down
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ package-lock.json -diff
packages.lock.json -diff
*.lock -diff

###############################################################################
# Append-only lists: one entry per line, order carries no meaning, and each
# list's checker compares sets (keyed lists fail on a key listed twice). A union
# merge keeps both sides' appended lines instead of conflicting. These paths
# exist only in claude-code-plugins; in other repositories they match nothing.
###############################################################################

scripts/affected-tests-no-suite.txt merge=union
scripts/em-dash-purged-paths.txt merge=union
scripts/fragment-plugins.txt merge=union
scripts/outside-node-packages.txt merge=union
scripts/shared-copies.txt merge=union
scripts/skill-leaf-name-registry.txt merge=union

###############################################################################
# Binary: no line-ending conversion, no diff.
###############################################################################
Expand Down
15 changes: 13 additions & 2 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# gitleaks: https://github.com/gitleaks/gitleaks
# Config reference: https://github.com/gitleaks/gitleaks#configuration
#
# Root-canonical policy: inherit the upstream default ruleset and add nothing
# repo-specific. Managed consumers do not edit this file. Intentional findings
# Root-canonical policy: inherit the upstream default ruleset and add only
# rules that are broadly valid, none repo-specific. Managed consumers do not edit this file. Intentional findings
# use a repository-owned .gitleaksignore or inline `gitleaks:allow` comment.

# Floor the engine version: silences the "no minVersion specified" debug
Expand All @@ -12,3 +12,14 @@ minVersion = "v8.25.0"

[extend]
useDefault = true

# GitHub App installation tokens in both formats: the classic `ghs_` + 36
# characters and the stateless `ghs_<appid>_<jwt>`. The default
# `github-app-token` rule stops at the `_` after the app id and the default
# `jwt` rule's `\b` cannot match between `_` and `eyJ`. GitHub's recommended
# regex: https://github.blog/changelog/2026-05-15-github-app-installation-tokens-per-request-override-header/
[[rules]]
id = "github-app-installation-token"
description = "GitHub App installation token, classic and stateless (ghs_<appid>_<jwt>) formats"
regex = '''ghs_[A-Za-z0-9._-]{36,}'''
keywords = ["ghs_"]
110 changes: 110 additions & 0 deletions REVIEW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Review instructions

Managed Code Review injects this file verbatim as the highest-priority
instruction block for every review agent. It does not expand `@` imports and
does not read a cited file into the prompt. It sees only the words printed
below (see "Depth"). A self-hosted or local review running the `review`
plugin reads this file too, and additionally follows its citations into the
`standards` repository for the full reasoned criterion behind each line.

Review in this organization is split into two mutually exclusive scopes,
so a finding belongs to exactly one scope and is never reported twice.
The **code-review lane** (`pr-review`, and Managed Code Review)
reads this file and applies the code-review scope below. The **security
lane** (`pr-review-security`) runs from its own security-only prompt
rather than reading this file; its scope section below records the same
split for every surface that does read it, so the code-review lane
knows what to leave to the security lane, and so a self-hosted or local
review (for example a `review`-plugin security agent) applies the right
section.

## Severity

This organization's criteria (`conventions/review/` in `standards`) resolve
to three severities: **Critical**, **Important**, **Suggestion**. On this
surface's three markers:

| SSOT severity | Managed marker |
| --- | --- |
| Critical | 🔴 Important |
| Important | 🔴 Important |
| Suggestion | 🟡 Nit |

🟣 Pre-existing is not an SSOT severity. It is this surface's own <!-- ai-slop-ignore: severity-marker vocabulary, load-bearing -->
detection-time judgment of whether a finding predates the diff, orthogonal
to the three-tier vocabulary above and not something a criterion assigns.

A finding tagged `blocking` is always 🔴 Important here, regardless of what
severity its underlying criterion would otherwise carry in context.
`blocking` is this file's own tag, not a severity a `conventions/review/`
criterion assigns.

## Depth

Managed Code Review cannot resolve a citation below: `@` imports are not
expanded and cited files are not read into the prompt. A self-hosted or
local review using the `review` plugin can follow one into the full
criterion, its severity nuance, and its sources. A citation is a path of the
form `conventions/review/<file>.md#<heading>`, resolved relative to wherever
the `standards` checkout root is available: this repository's own root when
`standards` reviews itself, or the `--add-dir` mount root everywhere else.

## Code-review lane scope

This lane owns every review dimension except security: correctness,
design, conventions, error handling, observability, tests, and
documentation. On a repository whose CI runs the security lane (a
`.github/workflows/pr-review-security*.yml` workflow exists), it does
**not** report security findings, such as vulnerabilities, authorization
or tenancy gaps, credential exposure, or injection: every security
finding belongs exclusively to that lane and is omitted here even when a
hunk plainly contains one.
On a repository with no such workflow no security lane exists yet, and
suppressed findings would have no other reader: report security findings
under this lane too, applying the security-scope checks below.

Always check:

- A high-risk security action, such as authentication, an authorization
failure, a privilege change, or sensitive-data access, has a
corresponding audit-log
entry (`conventions/review/observability.md#logging`). This is an
observability completeness check on the logging seam; whether the action
itself is safe is the security lane's question.
- A change that writes two or more related records, files, or state
locations carries an atomicity mechanism spanning them: a transaction,
an atomic rename, a constraint, or a compensation step. An
interruption between steps must not leave state no code path expects
(`conventions/review/error-handling.md#atomicity`).
- No Dependabot pull request waits on a human. One whose updates are all
non-major, with GitHub Actions only from `actions/*`, `github/*` or
`anthropics/*`, and none in the policy's `reviewOnly` security-critical
list, merges once `ci-status` passes; any other, a major included, merges
on an AI review lane's `merge` verdict at its current head once
`ci-status` passes, and a verdict on a security-critical dependency cites
the threat-model control it checked. A change that adds an action from another
publisher says why no vendor action or `gh` or script step serves
(`components/dependabot-policy/README.md#merge-tiers-for-dependabot-pull-requests`).

## Security lane scope

This lane reports **only** security findings: vulnerabilities, missing
authorization or tenant scoping, exposed secrets or credentials, injection,
and their direct enablers. Everything else is out of scope here and is
owned by the code-review lane; omit it. That includes style, design,
correctness with no security impact, and test coverage.

Always check:

- A handler or endpoint that receives an object id (a path segment, body
field, or query parameter) checks the caller is authorized for that
specific record, not only that the id is well-formed. Tagged `blocking`
(`conventions/review/security.md#object-level-authorization`).
- A data-access path that reaches tenant-owned data carries an explicit
tenant scope. Tagged `blocking`
(`conventions/review/multi-tenancy.md#tenant-scoped-data-access`).
- No secret, token, or credential is added to tracked source or config.
Tagged `blocking` (`conventions/review/security.md#secrets-and-credentials`).
- A query or process invocation built from external input is parameterized,
never string-concatenated. Tagged `blocking`
(`conventions/review/security.md#trust-boundaries-and-injection`).
4 changes: 4 additions & 0 deletions lychee.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ exclude = [
# pass was not enough evidence to drop it. A workstation gets 200 with
# lychee's User-Agent.
'^https?://help\.miro\.com/hc/en-us/articles/31624028247058/?([?#].*)?$',
# GitHub REST API endpoints: docs cite them as how a fact was fetched. The
# runner gets 403 (unauthenticated API limits), so a failure says nothing
# about the endpoint.
'^https://api\.github\.com/',
# Loopback hosts: never reachable from the checker. The example.com/.org/.net
# placeholder domains need no entry: lychee excludes them by default.
'^https?://localhost',
Expand Down