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
77 changes: 77 additions & 0 deletions .github/workflows/repo-structure.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Reusable org workflow: repo structure-lock (Rollingcat-Software/FIVUCSAS#209).
#
# An ArchUnit-style FREEZE of a repo's root file/folder layout. Any repo in the
# org adds a thin caller that invokes this on pull_request:
#
# # .github/workflows/structure-check.yml in the consuming repo
# name: structure-check
# on:
# pull_request:
# jobs:
# repo-structure:
# uses: Rollingcat-Software/.github/.github/workflows/repo-structure.yml@main
#
# The job checks out the CALLER repo plus this .github repo (for the check
# script), then runs the stdlib-only checker against the caller's
# .repo-structure.yml policy. It FAILS (red check) on any layout drift.
#
# Make it bite: add the resulting status check (job name "structure-check") as a
# REQUIRED check in each repo's branch protection — see the FIVUCSAS PR body.

name: repo-structure (reusable)

on:
workflow_call:
inputs:
policy:
description: >-
Optional explicit policy path relative to the repo root. Defaults to
.repo-structure.yml then .github/repo-structure.yml.
required: false
type: string
default: ""
tools-ref:
description: >-
Ref of Rollingcat-Software/.github to fetch the check script from
(pin to a tag/SHA for reproducibility; defaults to the default branch).
required: false
type: string
default: ""

permissions:
contents: read

jobs:
structure-check:
name: structure-check
# GitHub-hosted on purpose: this is a tiny stdlib-only Python job, so it
# must NOT depend on the resource-constrained self-hosted Hetzner runner.
runs-on: ubuntu-latest
steps:
- name: Check out the calling repository
uses: actions/checkout@v4
with:
# Root-only scan: skip submodule content (each submodule runs its own
# structure-check). Submodule dirs still appear as entries to validate.
submodules: false
persist-credentials: false

- name: Fetch the structure-lock tooling (org .github repo)
uses: actions/checkout@v4
with:
repository: Rollingcat-Software/.github
ref: ${{ inputs.tools-ref }}
path: .repo-structure-tools
persist-credentials: false

- name: Run repo structure-lock
# Pass the input through env (never interpolate ${{ }} into the shell
# line) so a malformed policy path can't inject shell commands.
env:
POLICY: ${{ inputs.policy }}
run: |
if [ -n "$POLICY" ]; then
python3 .repo-structure-tools/tools/check_repo_structure.py --root . --policy "$POLICY"
else
python3 .repo-structure-tools/tools/check_repo_structure.py --root .
fi
12 changes: 12 additions & 0 deletions .github/workflows/structure-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Self-check: the org .github repo enforces its own root layout via the reusable
# structure-lock workflow it ships (Rollingcat-Software/FIVUCSAS#209).
name: structure-check

on:
pull_request:
push:
branches: [main]

jobs:
repo-structure:
uses: ./.github/workflows/repo-structure.yml
22 changes: 22 additions & 0 deletions .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Pre-commit hook definitions exported by the org .github repo so any repo can
# run the structure-lock locally (Rollingcat-Software/FIVUCSAS#209):
#
# # .pre-commit-config.yaml in the consuming repo
# - repo: https://github.com/Rollingcat-Software/.github
# rev: main # pin to a tag/SHA for reproducibility
# hooks:
# - id: repo-structure
#
# The hook runs once per commit (not per-file) and scans the repo root against
# that repo's .repo-structure.yml. Stdlib-only — no extra dependencies.
- id: repo-structure
name: repo structure-lock
description: Freeze the repo root layout; block stray/dated tracking docs.
# language: script runs the checked-out script file directly (no venv/install,
# no third-party deps). pre-commit runs it from the consuming repo's root, so
# --root . scans the right tree.
entry: tools/check_repo_structure.py
args: ["--root", "."]
language: script
pass_filenames: false
always_run: true
32 changes: 32 additions & 0 deletions .repo-structure.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Repo structure-lock policy — org .github repo (Rollingcat-Software/FIVUCSAS#209).
#
# This repo hosts the reusable workflow + check script, so it also eats its own
# dog food: the frozen root below is enforced by structure-check.yml, which calls
# repo-structure.yml against this very repo. See tools/check_repo_structure.py.
#
# To add a NEW root entry, list it here in the SAME PR (the reviewed "unfreeze").

allowed_root_files:
- "CODE_OF_CONDUCT.md"
- "CONTRIBUTING.md"
- "README.md"
- "SECURITY.md"
- "SUPPORT.md"
- ".gitignore"
- ".pre-commit-hooks.yaml"
- ".repo-structure.yml"

allowed_root_dirs:
- ".github" # community-health files, issue templates, reusable workflows
- "profile" # org profile/README.md
- "tools" # check_repo_structure.py + its tests

# Dated / tracking-doc names that must NEVER reappear at the root (single-quoted
# so backslashes stay literal for the regex engine). Tracking goes in issues.
forbidden_root_patterns:
- '.*_(AUDIT|REVIEW|FINDINGS|REGISTER|TRIAGE|SWEEP|STATUS|SESSION|RECONCILIATION)_.*\.md$'
- '.*_\d{4}-\d{2}-\d{2}.*\.md$'
- '^(TODO|ROADMAP|BACKLOG|OPERATOR_TODO|PERSONAL_TODO).*\.md$'

required_files:
- "README.md"
Loading
Loading