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
53 changes: 53 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# =============================================================================
# EditorConfig — https://editorconfig.org
# =============================================================================
# Enforces consistent formatting across all editors without requiring plugin
# configuration. Supported natively in VS Code, JetBrains, Vim, Emacs, etc.
# =============================================================================

root = true

# ---------------------------------------------------------------------------
# All files
# ---------------------------------------------------------------------------
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

# ---------------------------------------------------------------------------
# YAML (Ansible playbooks, roles, vars)
# ---------------------------------------------------------------------------
[*.{yml,yaml}]
indent_style = space
indent_size = 2

# ---------------------------------------------------------------------------
# Jinja2 templates
# ---------------------------------------------------------------------------
[*.j2]
indent_style = space
indent_size = 2

# ---------------------------------------------------------------------------
# Markdown — preserve trailing spaces (line breaks) but trim blank lines
# ---------------------------------------------------------------------------
[*.md]
trim_trailing_whitespace = false
max_line_length = off

# ---------------------------------------------------------------------------
# JSON (release-please manifest, pre-commit config)
# ---------------------------------------------------------------------------
[*.json]
indent_style = space
indent_size = 2

# ---------------------------------------------------------------------------
# Makefile — tabs required
# ---------------------------------------------------------------------------
[Makefile]
indent_style = tab
1 change: 1 addition & 0 deletions .framework-pin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
363c5b4cd7555bb0a80ba8cbe6f7c72418d267b4
1 change: 1 addition & 0 deletions .github/terraform-framework-pin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
546d80b1ea75d4a98870bbbb137e5ca329b33697
510 changes: 510 additions & 0 deletions .github/workflows/aws-deploy.yml

Large diffs are not rendered by default.

48 changes: 48 additions & 0 deletions .github/workflows/powershell.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# =========================================================================================== #
# File: '.github/workflows/powershell.yml'
# --- [ Description ] ----------------------------------------------------------------------- #
#
# Thin caller for the organization's standardized PowerShell test suite. Everything of
# substance lives in NWarila/powershell-template (the single org definition of PowerShell):
# its reusable pester-matrix workflow discovers every <Name>.ps1 + <Name>.pester.ps1 pair
# under scripts/ (the generic script home, shared with Python/bash tooling; only .ps1 files
# participate) and runs one matrix leg per script — house PSScriptAnalyzer settings
# (custom rules included, zero findings), then the self-contained Pester spec.
#
# Runs when a PowerShell file changes in a pull request, and again on the merge to main —
# the main run is what publishes default-branch artifacts and code-scanning analyses.
# Adopting new organizational tests is a pin bump on the `uses:` line — nothing else in
# this repository changes.
#
# =========================================================================================== #
---
name: 'PowerShell'

"on":
pull_request:
paths:
- 'scripts/**.ps1' # script pairs (<Name>.ps1 + <Name>.pester.ps1)
- '.github/workflows/powershell.yml' # pin bumps must re-prove the matrix
push:
branches:
- 'main'
paths:
- 'scripts/**.ps1'
- '.github/workflows/powershell.yml'

permissions:
contents: 'read'

jobs:
pester-matrix:
permissions:
contents: 'read'
checks: 'write' # report job: check run with per-test results
pull-requests: 'write' # report job: sticky results comment on the PR
security-events: 'write' # test legs: SARIF upload to code scanning
uses: 'NWarila/powershell-template/.github/workflows/pester-matrix.yaml@758b3313d34269f10dcf1a1b07837c0b887bdc87' # main (#31)
with:
scan-path: 'scripts'
# Must match the `uses:` ref: the ref selects the workflow file, while template-ref
# is what the workflow checks out for the harness and analyzer settings.
template-ref: '758b3313d34269f10dcf1a1b07837c0b887bdc87' # main (#31)
109 changes: 109 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# =========================================================================================== #
# Repository-local Ansible and shell quality gate.
# Fleet-uniform port of the golden pdq-deploy-inventory workflow: role names are DISCOVERED
# from ansible/applications/ instead of hard-coded, and every Ansible step gates on the tree
# existing, so the same file is correct in a repo whose application work has not started yet.
# =========================================================================================== #
---
name: Quality

"on":
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false

- name: Detect the ansible tree
id: detect
run: |
set -euo pipefail
if compgen -G 'ansible/applications/*/tasks' > /dev/null; then
echo 'has_ansible=true' >> "${GITHUB_OUTPUT}"
else
echo 'has_ansible=false' >> "${GITHUB_OUTPUT}"
echo 'no ansible applications yet; ansible lint steps are skipped'
fi

- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: '3.12'

- name: Install quality tools
run: |
set -euo pipefail
pip install -r requirements-quality.txt
# ansible-lint resolves modules offline, so the collections the roles call must be
# present before the syntax check runs.
ansible-galaxy collection install --force \
--requirements-file requirements-quality.yml

- name: Lint YAML
if: steps.detect.outputs.has_ansible == 'true'
run: yamllint -c .yamllint.yml ansible

- name: Read framework pin
id: pins
run: |
set -euo pipefail
mapfile -t lines < .framework-pin
if [ "${#lines[@]}" -ne 1 ]; then
echo '.framework-pin must contain exactly one line' >&2
exit 1
fi
pin="${lines[0]}"
if [[ ! "${pin}" =~ ^[0-9a-f]{40}$ ]]; then
echo '.framework-pin must contain one lowercase 40-character Git SHA' >&2
exit 1
fi
printf 'ansible=%s\n' "${pin}" >> "${GITHUB_OUTPUT}"

- name: Checkout ansible-framework (pinned)
if: steps.detect.outputs.has_ansible == 'true'
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
repository: nwarila-platform/ansible-framework
ref: ${{ steps.pins.outputs.ansible }}
path: .frameworks/ansible-framework
persist-credentials: false

- name: Compose application roles
if: steps.detect.outputs.has_ansible == 'true'
run: |
set -euo pipefail
scripts/materialize-role-scripts.sh
# The framework's roles carry stubs of their own; materialize them in the checkout
# before the overlay, for the same reason the deploy workflow does.
if [ -x .frameworks/ansible-framework/scripts/materialize-role-scripts.sh ]; then
(cd .frameworks/ansible-framework && ./scripts/materialize-role-scripts.sh)
fi
for role_source in ansible/applications/*/; do
role_name="$(basename "${role_source}")"
rsync -a --delete "${role_source}" \
".frameworks/ansible-framework/applications/${role_name}/"
done

- name: Lint Ansible
if: steps.detect.outputs.has_ansible == 'true'
working-directory: .frameworks/ansible-framework
run: |
set -euo pipefail
roles=()
for role_source in "${GITHUB_WORKSPACE}"/ansible/applications/*/; do
roles+=("applications/$(basename "${role_source}")")
done
ansible-lint "${roles[@]}"

- name: Check shell syntax
run: bash -n scripts/compose-and-run.sh scripts/materialize-role-scripts.sh
54 changes: 54 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# =========================================================================================== #
# File: '.gitignore'
# --- [ Description ] ----------------------------------------------------------------------- #
#
# DEFAULT-DENY, EXPLICIT INCLUDES ONLY. Nothing in this working tree is tracked unless it is
# explicitly allowed below, by name — no wildcard allowances. Adding a new file therefore
# requires allowing it here first — that is deliberate: it makes publishing a file an
# explicit act rather than an accident.
#
# =========================================================================================== #

# Ignore everything ...
**

# --- [ directory spine ] -------------------------------------------------------------------- #
# Git does not descend into an excluded directory, so every directory on the path to an
# allowed file is re-included by name. This publishes no files by itself: files inside these
# directories stay ignored until named in a section below.
!/.github/
!/.github/workflows/
!/ansible/
!/ansible/inventory/
!/scripts/

# --- [ allowed: repository configuration ] -------------------------------------------------- #
!/.editorconfig
!/.framework-pin
!/.gitignore
!/.yamllint.yml

# --- [ allowed: top-level documents ] ------------------------------------------------------- #
!/AGENTS.md
!/CLAUDE.md
!/LICENSE
!/README.md
!/SECURITY.md
!/quality-tools.env
!/requirements-quality.txt
!/requirements-quality.yml

# --- [ allowed: GitHub configuration ] ------------------------------------------------------ #
!/.github/CODEOWNERS
!/.github/terraform-framework-pin
!/.github/workflows/aws-deploy.yml
!/.github/workflows/powershell.yml
!/.github/workflows/quality.yml

# --- [ allowed: the ansible tree ] ---------------------------------------------------------- #
!/ansible/inventory/README.md
!/ansible/inventory/aws_ec2.yml

# --- [ allowed: scripts ] ------------------------------------------------------------------- #
!/scripts/compose-and-run.sh
!/scripts/materialize-role-scripts.sh
86 changes: 86 additions & 0 deletions .yamllint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
# =============================================================================
# yamllint Configuration
# =============================================================================
# Extends the default ruleset with Ansible-appropriate overrides.
# Ansible YAML files tend to have long module parameter blocks and inline
# Jinja2 expressions — configure accordingly without sacrificing correctness.
# =============================================================================

extends: default

rules:

# ---------------------------------------------------------------------------
# Line Length
# ---------------------------------------------------------------------------
# 160 chars accommodates verbose module parameter blocks. Warning-only so
# pipelines don't fail on rare exceptions; keep lines short by convention.
# ---------------------------------------------------------------------------
line-length:
max: 160
level: warning

# ---------------------------------------------------------------------------
# Truthy Values
# ---------------------------------------------------------------------------
# Enforce canonical YAML 1.2 booleans (true/false). Ansible historically
# accepted yes/no/on/off, but these are ambiguous and deprecated in
# Ansible 2.17+ (YAML 1.1 legacy). Quoted 'yes'/'no' strings are allowed.
# ---------------------------------------------------------------------------
truthy:
allowed-values: ['true', 'false']
check-keys: true

# ---------------------------------------------------------------------------
# Document Start
# ---------------------------------------------------------------------------
# Disabled — Ansible task files and role files commonly start with comments
# or directly with list items. Enforce via convention, not linting.
# ---------------------------------------------------------------------------
document-start: disable

# ---------------------------------------------------------------------------
# Comments
# ---------------------------------------------------------------------------
# Require 1 space between code and inline comment (#).
# Disable indentation enforcement — region comments and block headers
# intentionally sit at column 0 or use custom indentation.
# ---------------------------------------------------------------------------
comments:
min-spaces-from-content: 1
comments-indentation: disable

# ---------------------------------------------------------------------------
# Braces & Brackets
# ---------------------------------------------------------------------------
# Allow up to 1 space inside braces and brackets to match common Jinja2
# and Ansible inline dict/list style: { key: value } and [ item ].
# ---------------------------------------------------------------------------
braces:
min-spaces-inside: 0
max-spaces-inside: 1
brackets:
min-spaces-inside: 0
max-spaces-inside: 1

# ---------------------------------------------------------------------------
# Indentation
# ---------------------------------------------------------------------------
# Standard 2-space indentation. indent-sequences: consistent allows both
# block and flow sequence styles as long as they're internally consistent.
# ---------------------------------------------------------------------------
indentation:
spaces: 2
indent-sequences: consistent
check-multi-line-strings: false

# ---------------------------------------------------------------------------
# New Line at End of File
# ---------------------------------------------------------------------------
new-line-at-end-of-file: enable

# ---------------------------------------------------------------------------
# Trailing Spaces
# ---------------------------------------------------------------------------
trailing-spaces: enable
17 changes: 17 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# AGENTS.md

Guidance for AI agents working in this repository.

- **No AI attribution, org-wide**: commit messages carry no co-authorship trailers naming
an AI model, assistant, or vendor, and PR bodies, issues, and comments carry no
tool-credit footers or badges. windows-fileserver-ha enforces this with commit hooks
that reject even a mention of such names or attribution phrases in messages and staged
content; the rule applies to every nwarila-platform repository regardless.
- This repository is part of the nwarila-platform fleet normalization:
**pdq-deploy-inventory is the Golden Repo** for structure, coding style, workflows, and
least privilege. Defer to its patterns before any check-in unless this repository has a
stated reason to differ.
- `main` is protected (PRs only, squash merges, signed commits, code-owner review): work on
feature branches, never push to `main`.
- The `.gitignore` is DEFAULT-DENY: a new file must be allowlisted there, by exact name,
before it can be committed. That is deliberate — publishing a file is an explicit act.
5 changes: 5 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# CLAUDE.md

Follow the repository guidance in AGENTS.md:

@AGENTS.md
Loading
Loading