Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
24 changes: 20 additions & 4 deletions scripts/seed-repo-template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,14 @@ readonly -a WORKFLOW_MANIFEST=(

# Baseline files (AC #3). One row per file: "path|source".
# source=gen → generated inline by _gen_baseline.
# source=fetch:<standards-path> → fetched verbatim from STANDARDS_REPO.
# source=fetch:<standards-path> → fetched verbatim from STANDARDS_REPO at that path.
# source=fetch (bare) → the Dependabot stack special case (path is DEPENDABOT_STACK-derived).
readonly -a BASELINE_MANIFEST=(
"AGENTS.md|gen"
"CLAUDE.md|gen"
".github/CODEOWNERS|gen"
".github/dependabot.yml|fetch"
".gitleaks.toml|fetch:standards/gitleaks.toml"
"sonar-project.properties|gen"
Comment thread
don-petry marked this conversation as resolved.
".gitignore|gen"
"LICENSE|gen"
Expand Down Expand Up @@ -309,13 +311,27 @@ _emit_baseline() {
echo "::error::unknown baseline file: $path" >&2
return 2
fi
local content std_path
if [ "$source" = "gen" ]; then
_gen_baseline "$path"
else
local content
content="$(_fetch_standard "standards/dependabot/${DEPENDABOT_STACK}.yml")" || true
if [ "$source" = "fetch" ]; then
# Dependabot special case: the standards path is DEPENDABOT_STACK-derived.
std_path="standards/dependabot/${DEPENDABOT_STACK}.yml"
elif [ "${source#fetch:}" != "$source" ]; then
# General verbatim fetch: source=fetch:<standards-path> (e.g. .gitleaks.toml).
std_path="${source#fetch:}"
if [ -z "$std_path" ]; then
echo "::error::empty standards path in source '${source}' for ${path}" >&2
return 2
fi
else
echo "::error::unknown baseline source '${source}' for ${path}" >&2
return 2
fi
content="$(_fetch_standard "$std_path")" || true
if [ -z "$content" ]; then
echo "::error::could not fetch standards/dependabot/${DEPENDABOT_STACK}.yml from ${STANDARDS_REPO}" >&2
echo "::error::could not fetch ${std_path} from ${STANDARDS_REPO}" >&2
return 1
fi
printf '%s\n' "$content"
Expand Down
1 change: 1 addition & 0 deletions scripts/template_stub_drift.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ readonly -a TEMPLATE_DRIFT_FILES=(
".github/dependabot.yml|--emit-baseline|.github/dependabot.yml"
".github/CODEOWNERS|--emit-baseline|.github/CODEOWNERS"
"CLAUDE.md|--emit-baseline|CLAUDE.md"
".gitleaks.toml|--emit-baseline|.gitleaks.toml"
)

# ── Documented allowlist (AC #2) ──────────────────────────────────────────────
Expand Down
1 change: 1 addition & 0 deletions tests/template_stub_drift.bats
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ setup() {
[[ "$output" == *".github/dependabot.yml"* ]]
[[ "$output" == *".github/CODEOWNERS"* ]]
[[ "$output" == *"CLAUDE.md"* ]]
[[ "$output" == *".gitleaks.toml"* ]]
}

@test "covered set: excludes the allowlisted ci.yml (per-stack customizable)" {
Expand Down
28 changes: 26 additions & 2 deletions tests/test_seed_repo_template.bats
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ _stub_gh_empty() {
run bash "$SEED" --list-baseline
[ "$status" -eq 0 ]
for f in AGENTS.md CLAUDE.md .github/CODEOWNERS .github/dependabot.yml \
sonar-project.properties .gitignore LICENSE SECURITY.md \
README.md BOOTSTRAP.md; do
.gitleaks.toml sonar-project.properties .gitignore LICENSE \
SECURITY.md README.md BOOTSTRAP.md; do
[[ "$output" == *"$f"* ]] || { echo "missing baseline: $f" >&2; false; }
done
}
Expand Down Expand Up @@ -237,6 +237,27 @@ EOF
[[ "$output" == *"auto-trigger"* ]]
}

# ── .gitleaks.toml baseline is fetched verbatim from standards/gitleaks.toml ───
# Seeds the secret-scan job's required config (push-protection.md); without it the
# template ci.yml's `gitleaks detect --config .gitleaks.toml` fails file-not-found.
@test "baseline: .gitleaks.toml is fetched verbatim from standards/gitleaks.toml (#575)" {
printf 'title = "gitleaks config"\n[allowlist]\npaths = [ %s ]\n' "'''_bmad/'''" \
> "$STANDARDS_DIR/standards/gitleaks.toml"
run bash "$SEED" --emit-baseline .gitleaks.toml
[ "$status" -eq 0 ]
[[ "$output" == *'title = "gitleaks config"'* ]]
[[ "$output" == *"_bmad/"* ]]
}

@test "baseline: .gitleaks.toml FAILS LOUD when standards/gitleaks.toml is absent" {
# No fixture written; empty gh stub blocks the network fallback so the general
# fetch:<path> source must fail loud, not emit empty (it exists in the live repo).
_stub_gh_empty
run bash "$SEED" --emit-baseline .gitleaks.toml
[ "$status" -ne 0 ]
[[ "$output" == *"standards/gitleaks.toml"* ]]
}

# ── dependabot baseline is sourced from the chosen standards/ stack template ───
@test "baseline: dependabot.yml comes from the chosen standards/dependabot stack" {
printf 'version: 2\nupdates:\n - package-ecosystem: npm\n' \
Expand Down Expand Up @@ -295,11 +316,13 @@ EOF
fi
done
printf 'version: 2\n' > "$STANDARDS_DIR/standards/dependabot/frontend.yml"
printf 'title = "gitleaks config"\n' > "$STANDARDS_DIR/standards/gitleaks.toml"
run env DEPENDABOT_STACK=frontend bash "$SEED" --repo petry-projects/repo-template
[ "$status" -eq 0 ]
[ -f "$CALLS" ]
grep -q "contents/.github/workflows/auto-rebase.yml" "$CALLS"
grep -q "contents/.github/CODEOWNERS" "$CALLS"
grep -q "contents/.gitleaks.toml" "$CALLS"
grep -q "pr create" "$CALLS"
}

Expand All @@ -323,6 +346,7 @@ EOF
fi
done
printf 'version: 2\n' > "$STANDARDS_DIR/standards/dependabot/frontend.yml"
printf 'title = "gitleaks config"\n' > "$STANDARDS_DIR/standards/gitleaks.toml"
run env DEPENDABOT_STACK=frontend bash "$SEED" --repo petry-projects/repo-template
[ "$status" -eq 0 ]
[[ "$output" == *"PR #42 already open"* ]]
Expand Down
Loading