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
31 changes: 19 additions & 12 deletions .github/workflows/gitignore-baseline-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
# Triggered on any PR that touches:
# - scripts/lib/gitignore-baseline.sh
# - scripts/sync-gitignore-baseline.sh
# - scripts/seed-repo-template.sh
# - scripts/emit-standard-file.sh
# - scripts/compliance-remediate.sh
# - test/scripts/lib/gitignore-baseline.bats
# - test/scripts/sync-gitignore-baseline/**
# - test/scripts/compliance-remediate/**
# - tests/test_seed_repo_template_gitignore.bats
# - tests/test_seed_repo_template_workflows.bats
# - tests/test_emit_standard_file_gitignore.bats
# - tests/test_emit_standard_file_workflows.bats
# - tests/test_seed_repo_template_single_home.bats
# - any file named seed-repo-template.sh (it must not exist here, #1927)
#
# Gates (all must pass before merge):
# 1. shellcheck — static analysis of the lib + sync + seed + remediate scripts
Expand All @@ -23,27 +25,31 @@ on:
paths:
- 'scripts/lib/gitignore-baseline.sh'
- 'scripts/sync-gitignore-baseline.sh'
- 'scripts/seed-repo-template.sh'
- 'scripts/emit-standard-file.sh'
- '**/seed-repo-template.sh'
- 'scripts/compliance-remediate.sh'
- 'test/scripts/lib/gitignore-baseline.bats'
- 'test/scripts/sync-gitignore-baseline/**'
- 'test/scripts/compliance-remediate/**'
- 'tests/test_seed_repo_template_gitignore.bats'
- 'tests/test_seed_repo_template_workflows.bats'
- 'tests/test_emit_standard_file_gitignore.bats'
- 'tests/test_emit_standard_file_workflows.bats'
- 'tests/test_seed_repo_template_single_home.bats'
- '.github/workflows/gitignore-baseline-tests.yml'
push:
branches:
- main
paths:
- 'scripts/lib/gitignore-baseline.sh'
- 'scripts/sync-gitignore-baseline.sh'
- 'scripts/seed-repo-template.sh'
- 'scripts/emit-standard-file.sh'
- '**/seed-repo-template.sh'
- 'scripts/compliance-remediate.sh'
- 'test/scripts/lib/gitignore-baseline.bats'
- 'test/scripts/sync-gitignore-baseline/**'
- 'test/scripts/compliance-remediate/**'
- 'tests/test_seed_repo_template_gitignore.bats'
- 'tests/test_seed_repo_template_workflows.bats'
- 'tests/test_emit_standard_file_gitignore.bats'
- 'tests/test_emit_standard_file_workflows.bats'
- 'tests/test_seed_repo_template_single_home.bats'
- '.github/workflows/gitignore-baseline-tests.yml'

permissions:
Expand Down Expand Up @@ -95,7 +101,7 @@ jobs:
shellcheck --severity=warning -x \
scripts/lib/gitignore-baseline.sh \
scripts/sync-gitignore-baseline.sh \
scripts/seed-repo-template.sh \
scripts/emit-standard-file.sh \
scripts/compliance-remediate.sh

- name: Run bats suite
Expand All @@ -104,5 +110,6 @@ jobs:
test/scripts/lib/gitignore-baseline.bats \
test/scripts/sync-gitignore-baseline/ \
test/scripts/compliance-remediate/ \
tests/test_seed_repo_template_gitignore.bats \
tests/test_seed_repo_template_workflows.bats
tests/test_emit_standard_file_gitignore.bats \
tests/test_emit_standard_file_workflows.bats \
tests/test_seed_repo_template_single_home.bats
9 changes: 9 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ and have `.github-private` **consume** it — the way repo-seeding tooling fetch
`standards/workflows/` from `.github`. Do **not** add new org-wide standards or rulesets
to `.github-private`.

**`seed-repo-template.sh` has one home: `petry-projects/.github-private`.** That script writes
the baseline scaffold into `petry-projects/repo-template` and opens the seed PR. It reads this
repo's `standards/` at a pinned ref, so it is a consumer of the standards, not a standard. This
repo's `scripts/emit-standard-file.sh` is a different tool: it only prints one standard file (the
`.gitignore` baseline, or a workflow stub verbatim) from a local checkout. The two used to share a
name and were mistaken for diverged copies (`petry-projects/.github-private#1927`). Do not add a
`seed-repo-template.sh` here; `tests/test_seed_repo_template_single_home.bats` fails if one
reappears.

> **Known exception being remediated:** `code-quality.json` and `pr-quality.json`
> currently live in `.github-private/.github/rulesets/` (added ad-hoc under
> compliance fix #60, before this boundary was documented) and are being relocated
Expand Down
8 changes: 5 additions & 3 deletions docs/bootstrap/new-repo-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ produces a fully org-compliant repo, exercised under `DRY_RUN` with no drift.
## Primary onboarding path (one-click + one-command)

1. **Use this template.** Create the repo from `petry-projects/repo-template`
(`seed-repo-template.sh` keeps that template in sync with `petry-projects/.github`
(`seed-repo-template.sh`, in `petry-projects/.github-private`, keeps that template in sync with `petry-projects/.github`
`standards/`). This seeds day-0 only: the thin-caller workflow stubs pinned to
their published `@<name>/stable` channel tags plus the root/baseline files
(CODEOWNERS, AGENTS.md/CLAUDE.md pointers, LICENSE, SECURITY.md, `.gitignore`,
Expand Down Expand Up @@ -121,5 +121,7 @@ this branch. The cutover content to apply:
## See also

- `scripts/bootstrap-new-repo.sh` — the orchestrator (issues #967, #968)
- `scripts/seed-repo-template.sh` — day-0 template seeding + the generated `BOOTSTRAP.md` (#966)
- `tests/test_bootstrap_new_repo.bats`, `tests/test_seed_repo_template.bats` — the executable validation
- `scripts/seed-repo-template.sh` in `petry-projects/.github-private` — day-0 template seeding + the generated
`BOOTSTRAP.md` (#966), with its suite `tests/test_seed_repo_template.bats` there. That repo is the one home of
the seeder; this repo's `scripts/emit-standard-file.sh` only prints a standard file.
- `tests/test_bootstrap_new_repo.bats` — the executable validation of the orchestrator
13 changes: 10 additions & 3 deletions scripts/seed-repo-template.sh → scripts/emit-standard-file.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
#!/usr/bin/env bash
# scripts/seed-repo-template.sh — emit standard file content for the
# scripts/emit-standard-file.sh — emit standard file content for the
# org repo-template to distribute to all new repos (#798, Story: SEED + DISTRIBUTE).
#
# This script only PRINTS a file. It does not seed anything. The tool that writes
# the scaffold into petry-projects/repo-template is `scripts/seed-repo-template.sh`
# in petry-projects/.github-private, the one home of that name. This file used to
# share the name, which made the two look like diverged copies of one script
# (petry-projects/.github-private#1927). Do not add a `seed-repo-template.sh` here:
# tests/test_seed_repo_template_single_home.bats fails if one reappears.
#
# Usage:
# STANDARDS_DIR=<path> bash scripts/seed-repo-template.sh --emit-baseline .gitignore
# STANDARDS_DIR=<path> bash scripts/seed-repo-template.sh --emit-workflow dev-lead.yml
# STANDARDS_DIR=<path> bash scripts/emit-standard-file.sh --emit-baseline .gitignore
# STANDARDS_DIR=<path> bash scripts/emit-standard-file.sh --emit-workflow dev-lead.yml
#
# --emit-baseline .gitignore
# Print the seeded .gitignore: the marker-wrapped L1 secrets baseline on top
Expand Down Expand Up @@ -60,7 +67,7 @@
# refs and third-party actions are not '<...>-reusable.yml@' and are exempt.)
unmarked="$(grep -E '^[[:space:]]*uses:[[:space:]]*petry-projects/[^[:space:]]*-reusable\.yml@' "$file" 2>/dev/null \
| grep -vE 'S7637\) first-party channel ref' || true)"
if [ -n "$unmarked" ]; then

Check failure on line 70 in scripts/emit-standard-file.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=petry-projects_.github&issues=AaEo8P0eD7fi3b5Vq9WL&open=AaEo8P0eD7fi3b5Vq9WL&pullRequest=1294
echo "::error::refusing to emit '${file#"${STANDARDS_DIR}"/}': first-party reusable uses: line(s) missing the '# NOSONAR(githubactions:S7637) first-party channel ref' marker — cannot validate the channel pin (fail-closed):" >&2
printf '%s\n' "$unmarked" | sed 's/^/ /' >&2
exit 3
Expand All @@ -68,7 +75,7 @@
bad="$(grep -E 'S7637\) first-party channel ref' "$file" 2>/dev/null \
| sed -E 's/.*-reusable\.yml@([^[:space:]]+).*/\1/' \
| grep -vE '^[a-z0-9-]+/v[0-9]+-(stable|next|ring[0-9]+)$' || true)"
if [ -n "$bad" ]; then

Check failure on line 78 in scripts/emit-standard-file.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=petry-projects_.github&issues=AaEo8P0eD7fi3b5Vq9WM&open=AaEo8P0eD7fi3b5Vq9WM&pullRequest=1294
echo "::error::refusing to emit '${file#"${STANDARDS_DIR}"/}': bare channel pin(s) — must be major-scoped <agent>/v<M>-<tier>:" >&2
printf '%s\n' "$bad" | sed 's/^/ /' >&2
exit 3
Expand All @@ -80,7 +87,7 @@
agentref_bad="$(grep -E '^[[:space:]]*agent_ref:[[:space:]]' "$file" 2>/dev/null \
| sed -E 's/.*agent_ref:[[:space:]]*([^[:space:]#]+).*/\1/' \
| grep -vE '^[a-z0-9-]+/v[0-9]+-(stable|next|ring[0-9]+)$' || true)"
if [ -n "$agentref_bad" ]; then

Check failure on line 90 in scripts/emit-standard-file.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=petry-projects_.github&issues=AaEo8P0eD7fi3b5Vq9WN&open=AaEo8P0eD7fi3b5Vq9WN&pullRequest=1294
echo "::error::refusing to emit '${file#"${STANDARDS_DIR}"/}': agent_ref value(s) not major-scoped <agent>/v<M>-<tier>:" >&2
printf '%s\n' "$agentref_bad" | sed 's/^/ /' >&2
exit 3
Expand All @@ -91,10 +98,10 @@
# gated by the v-form pin guard above.
_emit_workflow() {
local name="$1" src="${STANDARDS_DIR}/standards/workflows/$1"
case "$name" in

Check failure on line 101 in scripts/emit-standard-file.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add a default case (*) to handle unexpected values.

See more on https://sonarcloud.io/project/issues?id=petry-projects_.github&issues=AaEo8P0eD7fi3b5Vq9WO&open=AaEo8P0eD7fi3b5Vq9WO&pullRequest=1294
*/*|.*|"") echo "::error::invalid workflow name '${name}'" >&2; exit 2 ;;
esac
if [ ! -f "$src" ]; then

Check failure on line 104 in scripts/emit-standard-file.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=petry-projects_.github&issues=AaEo8P0eD7fi3b5Vq9WP&open=AaEo8P0eD7fi3b5Vq9WP&pullRequest=1294
echo "::error::unknown workflow '${name}' — no template at standards/workflows/${name}" >&2
exit 2
fi
Expand All @@ -102,7 +109,7 @@
cat "$src"
}

[ $# -ge 2 ] || _usage

Check failure on line 112 in scripts/emit-standard-file.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use '[[' instead of '[' for conditional tests. The '[[' construct is safer and more feature-rich.

See more on https://sonarcloud.io/project/issues?id=petry-projects_.github&issues=AaEo8P0eD7fi3b5Vq9WQ&open=AaEo8P0eD7fi3b5Vq9WQ&pullRequest=1294

case "$1" in
--emit-workflow) _emit_workflow "$2"; exit 0 ;;
Expand Down
2 changes: 1 addition & 1 deletion standards/standards-versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,5 @@ degrades cleanly to "accepts current" while `previous` is empty.
- **No behavior change for anything that does not opt in.** Scripts and repos
that pass an explicit ref or a local standards directory keep resolving exactly
as they do; this channel adds a tag, it does not change any existing
resolution path in this repo. In particular `scripts/seed-repo-template.sh`
resolution path in this repo. In particular `scripts/emit-standard-file.sh`
(which reads a local `STANDARDS_DIR` checkout) is untouched.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bats
# Tests for the repo-template .gitignore generator in
# scripts/seed-repo-template.sh (#798).
# scripts/emit-standard-file.sh (#798).
#
# The seeded template must carry the marker-wrapped org secrets baseline (L1) on
# top, with the template's own ecosystem/OS entries (L2) below the END marker —
Expand All @@ -12,7 +12,7 @@

setup() {
REPO_ROOT="$(cd -- "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
SEED="${REPO_ROOT}/scripts/seed-repo-template.sh"
SEED="${REPO_ROOT}/scripts/emit-standard-file.sh"
export STANDARDS_DIR="$REPO_ROOT"
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bats
# Tests for the repo-template WORKFLOW-STUB generator in
# scripts/seed-repo-template.sh (#886).
# scripts/emit-standard-file.sh (#886).
#
# The repo-template baseline re-seed ("chore: seed org baseline file scaffold")
# must source its workflow stubs from the canonical standards/workflows/ — which
Expand All @@ -21,7 +21,7 @@

setup() {
REPO_ROOT="$(cd -- "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
SEED="${REPO_ROOT}/scripts/seed-repo-template.sh"
SEED="${REPO_ROOT}/scripts/emit-standard-file.sh"
WF_DIR="${REPO_ROOT}/standards/workflows"
export STANDARDS_DIR="$REPO_ROOT"
}
Expand Down Expand Up @@ -151,7 +151,7 @@ RESEEDED_STUBS="dev-lead.yml auto-rebase.yml dependabot-automerge.yml"
}

@test "STANDARDS_REF defaults to standards/v1-stable when unset (environment variable resolution)" {
# Verify that seed-repo-template.sh accepts STANDARDS_REF and defaults to v1-stable
# Verify that emit-standard-file.sh accepts STANDARDS_REF and defaults to v1-stable
# when unset. The script should complete successfully with default reference.
run env -u STANDARDS_REF STANDARDS_DIR="$REPO_ROOT" bash "$SEED" --emit-workflow dev-lead.yml
[ "$status" -eq 0 ]
Expand Down
53 changes: 53 additions & 0 deletions tests/test_seed_repo_template_single_home.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bats
# Guard: this repo carries no `seed-repo-template.sh`
# (petry-projects/.github-private#1927).
#
# The seeder that writes the baseline scaffold into petry-projects/repo-template
# lives in petry-projects/.github-private, the one home of that name. This repo
# once had a different, smaller script under the same name. It only printed a
# standard file, yet the two were read as diverged copies of one tool and nothing
# said which was authoritative. That script is now scripts/emit-standard-file.sh.
# This guard keeps a second `seed-repo-template.sh` from reappearing here.

setup() {
REPO_ROOT="$(cd -- "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
: "${SINGLE_HOME_ROOT:=$REPO_ROOT}"
}

# seed_copies — every tracked or untracked-but-not-ignored file named
# seed-repo-template.sh under the repo, one path per line.
seed_copies() {
git -C "$SINGLE_HOME_ROOT" ls-files --cached --others --exclude-standard \
| grep -E '(^|/)seed-repo-template\.sh$' || true
}

@test "no seed-repo-template.sh exists in this repo — its one home is petry-projects/.github-private" {
run seed_copies
[ "$status" -eq 0 ]
if [ -n "$output" ]; then
echo "Found a seed-repo-template.sh in petry-projects/.github:"
echo "$output"
echo "The seeder's one home is petry-projects/.github-private/scripts/seed-repo-template.sh."
echo "Change it there. To print a standard file from this repo, use scripts/emit-standard-file.sh."
return 1
fi
}

@test "the guard finds a copy when one is added, at any depth" {
SINGLE_HOME_ROOT="$BATS_TEST_TMPDIR/repo"
mkdir -p "$SINGLE_HOME_ROOT/scripts" "$SINGLE_HOME_ROOT/tools/nested"
git -C "$SINGLE_HOME_ROOT" init -q
: > "$SINGLE_HOME_ROOT/scripts/emit-standard-file.sh"
: > "$SINGLE_HOME_ROOT/scripts/not-seed-repo-template.sh"
run seed_copies
[ -z "$output" ]
: > "$SINGLE_HOME_ROOT/scripts/seed-repo-template.sh"
: > "$SINGLE_HOME_ROOT/tools/nested/seed-repo-template.sh"
run seed_copies
[ "$output" = "$(printf 'scripts/seed-repo-template.sh\ntools/nested/seed-repo-template.sh')" ]
}

@test "the emitter exists under its own name and says where the seeder lives" {
[ -f "$REPO_ROOT/scripts/emit-standard-file.sh" ]
grep -q 'petry-projects/.github-private' "$REPO_ROOT/scripts/emit-standard-file.sh"
}
Loading