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
2 changes: 2 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ before submitting. Keep PRs focused on one concern — split when the diff
outgrows the concern, not at an arbitrary line count. Prerequisite cleanup
the change itself surfaces (e.g., a tidy-drift fix needed for a new gate to
land green) can ride along when called out in the PR body.

For pattern OTTL stanzas / recipe content, see STYLE.md §"Commits".
-->

## What this PR does
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/pr-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ jobs:
exit 1
fi

- name: title doesn't reference recipes/pattern-N path
# Issue #427 convention gate. See STYLE.md §"Commits".
if: github.actor != 'dependabot[bot]'
env:
TITLE: ${{ github.event.pull_request.title }}
run: bash scripts/recipes-path-check.sh "${TITLE:-}"

# DCO sign-off is gated on first external contributor (NORTHSTARS O5
# target: ≥5 external contributors by M6). Pre-alpha solo-maintainer
# commits don't need the legal trail — re-enable by uncommenting when
Expand Down
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
.PHONY: coverage coverage-check

# Policy gates (each enforces a specific RFC-bound invariant)
.PHONY: license-check license-fix govulncheck dco-check ci-fuzz-nccl-fr nccl-fr-rce-gate register-lint actionlint zizmor doc-check doc-check-release no-autoupdate-check anonymize-pod-evicted-fixture-check base-digest-check build-tags attribute-namespace-check deprecation-check rfc-status-check cut-criteria-status cut-criteria-status-all cut-criteria-render cut-criteria-check slo-rules-check test-flake-audit
.PHONY: license-check license-fix govulncheck dco-check ci-fuzz-nccl-fr nccl-fr-rce-gate register-lint actionlint zizmor doc-check doc-check-release no-autoupdate-check recipes-path-check anonymize-pod-evicted-fixture-check base-digest-check build-tags attribute-namespace-check deprecation-check rfc-status-check cut-criteria-status cut-criteria-status-all cut-criteria-render cut-criteria-check slo-rules-check test-flake-audit

# Aggregate gates: pre-commit / pre-push / fast-CI / full-CI
.PHONY: check verify ci ci-fast ci-full
Expand Down Expand Up @@ -403,6 +403,9 @@ no-autoupdate-check: ## Enforce RFC-0008: cmd/, components/, internal/, pkg/ co
@scripts/no-autoupdate-check.sh
@scripts/no-autoupdate-check_test.sh

recipes-path-check: ## Issue #427 convention gate: assert PR titles / commit subjects don't reference an aspirational `recipes/pattern-N/` directory. Runs the gate's own regression test against a fixture suite of accept/reject subject shapes.
@scripts/recipes-path-check_test.sh

anonymize-pod-evicted-fixture-check: ## M19 carry-forward #1: verify every operator-contributed pod_evicted replay fixture under _real_world/ carries no PII shapes (IPv4, email, cloud-instance node names, image refs). Also runs the anonymizer's own mutation regression tests.
@set -e; for d in module/pkg/replay/pod_evicted/_real_world/*/; do \
if [ -f "$$d/manifest.json" ]; then \
Expand All @@ -414,7 +417,7 @@ anonymize-pod-evicted-fixture-check: ## M19 carry-forward #1: verify every oper
zizmor: ## Security-lint GitHub Actions workflows (template injection, untrusted-input-in-script, over-broad permissions, cache poisoning). Gates at --min-severity=high.
@scripts/zizmor.sh

ci-fast: lint vet mod-verify attribute-namespace-check doc-check test-flake-audit ## Fast-feedback CI subset. <60s on a dev laptop; the gates that catch the most defects per second. Run on every save / pre-commit; not a substitute for `ci-full`. See PRINCIPLES.md §10.
ci-fast: lint vet mod-verify attribute-namespace-check doc-check recipes-path-check test-flake-audit ## Fast-feedback CI subset. <60s on a dev laptop; the gates that catch the most defects per second. Run on every save / pre-commit; not a substitute for `ci-full`. See PRINCIPLES.md §10.

# `ci-full` is the full superset CI enforces on every PR. `ci` is kept as a
# back-compat alias so existing scripts, docs, and hooks invoking `make ci`
Expand All @@ -428,7 +431,7 @@ ci-fast: lint vet mod-verify attribute-namespace-check doc-check test-flake-audi
# the ratchet path. We accept the wall-time hit because local `ci-full`
# divergence from CI surfaces ceiling breaches only post-PR-open, which
# defeats the per-PR enforcement intent of #302.
ci-full: license-check generate-fixtures-check verdict-fixtures-check vet build-tags tidy-check mod-verify lint nccl-fr-rce-gate register-lint actionlint zizmor coverage-check ci-fuzz-nccl-fr govulncheck doc-check deprecation-check no-autoupdate-check anonymize-pod-evicted-fixture-check test-flake-audit pre-push-test build smoke smoke-quickstart bench-allocs-check ## Everything CI runs. Run before opening a PR.
ci-full: license-check generate-fixtures-check verdict-fixtures-check vet build-tags tidy-check mod-verify lint nccl-fr-rce-gate register-lint actionlint zizmor coverage-check ci-fuzz-nccl-fr govulncheck doc-check deprecation-check no-autoupdate-check recipes-path-check anonymize-pod-evicted-fixture-check test-flake-audit pre-push-test build smoke smoke-quickstart bench-allocs-check ## Everything CI runs. Run before opening a PR.

pre-push-test: ## Regression harness for .githooks/pre-push path-filter routing. Cheap (<1s); runs the hook in dry-run mode against synthetic diff ranges and asserts each gate fires only when its source paths change.
@bash scripts/pre-push-test.sh
Expand Down
4 changes: 4 additions & 0 deletions STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ That's it. No copyright block, no Apache header text. The `LICENSE` file at the
- **Imperative present tense**: "Add NCCL receiver", not "Added NCCL receiver".
- **Subject ≤ 72 chars**, body wraps at 72.
- **DCO sign-off required**: `git commit -s`.
- **Reference real paths, not aspirational ones.** Pattern OTTL stanzas and recipe content live under [`docs/integrations/examples/`](docs/integrations/examples/) (per-target YAML files) with prose in [`docs/integrations/`](docs/integrations/). See issue [#427](https://github.com/TraceCoreAI/tracecore/issues/427).
- **Do not** write `feat(recipes): pattern-N ...` implying a top-level `recipes/pattern-N/{ottl.yaml,README.md}` directory; that layout does not exist and migrating into it would rot cross-links across six-plus docs.
- **Acceptable subject shapes:** `feat(integrations/examples): pattern-N OTTL stanza`, `feat(filelog-container): pattern-N ...`, or `feat(pattern-N): OTTL stanza in docs/integrations/examples/`.
- **Enforced** by `scripts/recipes-path-check.sh` (run in `.github/workflows/pr-lint.yml`).

## Changelog

Expand Down
53 changes: 53 additions & 0 deletions scripts/recipes-path-check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bash
# recipes-path-check.sh — issue #427 convention gate. See STYLE.md §"Commits".

set -euo pipefail

subject="${1:-}"

if [ -z "$subject" ]; then
exit 0
fi

# Rule 1: literal `recipes/pattern-N` path (filesystem reference).
if printf '%s' "$subject" | grep -qE '(^|[^/])recipes/pattern-[0-9]+'; then
cat >&2 <<EOF
::error::PR title / commit subject references a 'recipes/pattern-N/' path:

$subject

That layout does not exist in this repo. Pattern OTTL stanzas and
recipe content live under 'docs/integrations/examples/' (per-target
YAML files) with prose in 'docs/integrations/'. See STYLE.md §"Commits"
and issue #427 for the rationale.

Acceptable subject shapes:
feat(integrations/examples): pattern-N OTTL stanza
feat(<target>): pattern-N ...
feat(pattern-N): OTTL stanza in docs/integrations/examples/
EOF
exit 1
fi

# Rule 2: `feat(recipes?):` scope paired with pattern-N context (audit #421).
if printf '%s' "$subject" \
| grep -qiE '^[a-z]+\(recipes?\):.*pattern[^a-zA-Z0-9]*[0-9]+'; then
cat >&2 <<EOF
::error::PR title / commit subject uses a 'recipes' / 'recipe' scope
for pattern-N content:

$subject

That implies a top-level 'recipes/pattern-N/' directory layout that
does not exist. Pattern OTTL stanzas live under
'docs/integrations/examples/'. See STYLE.md §"Commits" and issue #427.

Acceptable subject shapes:
feat(integrations/examples): pattern-N OTTL stanza
feat(<target>): pattern-N ...
feat(pattern-N): OTTL stanza in docs/integrations/examples/
EOF
exit 1
fi

exit 0
51 changes: 51 additions & 0 deletions scripts/recipes-path-check_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# recipes-path-check_test.sh — regression test for the issue #427 gate.

set -euo pipefail

gate="$(cd "$(dirname "$0")" && pwd)/recipes-path-check.sh"

if [ ! -x "$gate" ]; then
echo "FAIL: gate script not found or not executable: $gate"
exit 1
fi

# Run the gate against one input string; return its exit code.
run_gate() { bash "$gate" "$1" >/dev/null 2>&1; }

assert_fails() {
if run_gate "$2"; then
echo "FAIL [$1]: gate exited 0 on '$2' (expected reject)"
return 1
fi
echo "ok: $1"
}

assert_passes() {
if ! run_gate "$2"; then
echo "FAIL [$1]: gate exited 1 on '$2' (expected accept)"
return 1
fi
echo "ok: $1"
}

# --- Reject cases: aspirational recipes/pattern-N/ layout --------------

assert_fails "rejects bare recipes/pattern-N path" "feat(recipes): recipes/pattern-7/ottl.yaml"
assert_fails "rejects scope recipes/pattern-N" "chore(recipes/pattern-2): bump"
assert_fails "rejects two-digit pattern" "docs: see recipes/pattern-13/README.md"
assert_fails "rejects feat(recipes) without explicit path" "feat(recipes): OTTL stanzas + bridge for pattern #7"
assert_fails "rejects feat(recipe) singular" "feat(recipe): pattern-2 IB link flap OTTL stanza"
assert_fails "rejects colon-prefixed recipes/pattern-N" "chore(foo):recipes/pattern-7"

# --- Accept cases: real placement and unrelated subjects ---------------

assert_passes "accepts docs/integrations/examples path" "feat(integrations/examples): pattern-7 OTTL stanza"
assert_passes "accepts per-target scope" "feat(filelog-container): pattern-7 dataloader OTTL"
assert_passes "accepts pattern-N scope" "feat(pattern-7): OTTL stanza in docs/integrations/examples/"
assert_passes "accepts unrelated subject" "feat(processor): add silent_data_corruption detector"
assert_passes "accepts internal/recipes Go path" "test: cover ./internal/recipes/... against live exporter"
assert_passes "accepts internal/recipes/pattern-N path" "test: refactor internal/recipes/pattern-7 detector"
assert_passes "accepts empty input" ""

echo "all recipes-path-check tests passed"