From 51cf03d38907c7c7e976ed7a32448974f0617e1e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:13:21 +0000 Subject: [PATCH 01/19] Initial plan From 4f837633e0cf8d7b1dbce6934cb72b96617ef4ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:14:50 +0000 Subject: [PATCH 02/19] feat(lint): add lint caller workflow for this repository Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/c8f7e2c6-3a6d-4092-a67d-5b6e167e52ec Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint-caller.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/lint-caller.yml diff --git a/.github/workflows/lint-caller.yml b/.github/workflows/lint-caller.yml new file mode 100644 index 0000000..55b05e8 --- /dev/null +++ b/.github/workflows/lint-caller.yml @@ -0,0 +1,21 @@ +--- +name: Lint + +on: + pull_request: + push: + branches: + - main + +permissions: + contents: read + +jobs: + lint: + uses: DevSecNinja/.github/.github/workflows/lint.yml@e7037884132e77504ca7f50a23e98f594d1c764b # v1.1.0 + permissions: + contents: read + security-events: write + with: + # renovate: datasource=github-releases depName=jdx/mise + mise-version: "2026.4.9" From 4d799d366e6af6fd45ca2e7c4dfce6c12467fe09 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:23:01 +0000 Subject: [PATCH 03/19] fix(lint): configure repo lint tooling Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/13b11d79-ed71-4974-a327-ffbeb7be6104 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint-caller.yml | 2 +- .github/workflows/lint.yml | 2 +- .gitleaks.toml | 3 +++ .mise.toml | 9 +++++++++ .shellcheckrc | 8 ++++++++ .yamlfmt.yaml | 16 ++++++++++++++++ .yamllint.yaml | 16 ++++++++++++++++ dprint.json | 2 +- trivy.yaml | 3 +++ 9 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 .gitleaks.toml create mode 100644 .shellcheckrc create mode 100644 .yamlfmt.yaml create mode 100644 .yamllint.yaml create mode 100644 trivy.yaml diff --git a/.github/workflows/lint-caller.yml b/.github/workflows/lint-caller.yml index 55b05e8..f275ae8 100644 --- a/.github/workflows/lint-caller.yml +++ b/.github/workflows/lint-caller.yml @@ -12,7 +12,7 @@ permissions: jobs: lint: - uses: DevSecNinja/.github/.github/workflows/lint.yml@e7037884132e77504ca7f50a23e98f594d1c764b # v1.1.0 + uses: ./.github/workflows/lint.yml permissions: contents: read security-events: write diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e17286d..4913f08 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -95,7 +95,7 @@ jobs: version: ${{ inputs.mise-version }} - name: Check formatting with dprint - run: mise exec -- dprint check + run: mise exec -- dprint check --allow-no-files yamlfmt: name: yamlfmt diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..292d0a7 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,3 @@ +[allowlist] +description = "Global gitleaks allowlist" +regexes = ["\\d+/api/verify"] diff --git a/.mise.toml b/.mise.toml index d9051de..035e83e 100644 --- a/.mise.toml +++ b/.mise.toml @@ -2,6 +2,15 @@ min_version = "2026.4.9" [tools] +actionlint = "1.7.12" cocogitto = "7.0.0" dprint = "0.54.0" +gitleaks = "8.30.1" git-cliff = "2.12.0" +"pipx:checkov" = "3.2.521" +"pipx:yamllint" = "1.38.0" +shellcheck = "0.11.0" +shfmt = "3.13.1" +trivy = "0.70.0" +yamlfmt = "0.21.0" +zizmor = "1.24.1" diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 0000000..cf3fc32 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,8 @@ +# Default shell dialect; individual scripts override this via their shebang +shell=bash + +# Error severity: error, warning, info, style (default: style — show everything) +severity=style + +# Enable optional checks not on by default +enable=add-default-case,avoid-nullary-conditions,check-extra-masked-returns,check-set-e-suppressed,deprecate-which,quote-safe-variables,require-variable-braces diff --git a/.yamlfmt.yaml b/.yamlfmt.yaml new file mode 100644 index 0000000..6c79680 --- /dev/null +++ b/.yamlfmt.yaml @@ -0,0 +1,16 @@ +--- +doublestar: true +formatter: + type: basic + disable_alias_key_correction: true + indent: 2 + max_line_length: 120 + pad_line_comments: 1 + drop_merge_tag: true + eof_newline: true + force_array_style: block + include_document_start: true + line_ending: lf + retain_line_breaks_single: true + scan_folded_as_literal: true + trim_trailing_whitespace: true diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 0000000..2d2e080 --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,16 @@ +--- +extends: default + +rules: + # Inline comment spacing varies by author style — not auto-fixable + comments: disable + # Long lines are unavoidable with image digests, Traefik labels, and URLs — not auto-fixable + line-length: disable + # Let yamlfmt handle document start markers + document-start: disable + # Allow 'on:' as a mapping key in GitHub Actions workflows + truthy: + allowed-values: + - "true" + - "false" + check-keys: false diff --git a/dprint.json b/dprint.json index 1538838..25ad7a7 100644 --- a/dprint.json +++ b/dprint.json @@ -1,7 +1,7 @@ { "$schema": "https://dprint.dev/schemas/v0.json", "includes": ["**/*.md"], - "excludes": ["**/node_modules"], + "excludes": ["**/node_modules", "config-sync/files/**"], "plugins": [ "https://plugins.dprint.dev/markdown-0.21.1.wasm" ] diff --git a/trivy.yaml b/trivy.yaml new file mode 100644 index 0000000..5dba7f0 --- /dev/null +++ b/trivy.yaml @@ -0,0 +1,3 @@ +--- +scan: + skip-files: [] From 50dab71ff6022ec449cf284ff3b0eaa8c2c7f3c6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:24:03 +0000 Subject: [PATCH 04/19] fix(lint): pin reusable lint workflow reference Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/13b11d79-ed71-4974-a327-ffbeb7be6104 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint-caller.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-caller.yml b/.github/workflows/lint-caller.yml index f275ae8..3a116de 100644 --- a/.github/workflows/lint-caller.yml +++ b/.github/workflows/lint-caller.yml @@ -12,7 +12,7 @@ permissions: jobs: lint: - uses: ./.github/workflows/lint.yml + uses: DevSecNinja/.github/.github/workflows/lint.yml@4d799d366e6af6fd45ca2e7c4dfce6c12467fe09 # PR #66 permissions: contents: read security-events: write From 20b1f453501df9aab2eff1d09ff939601a8e74f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:24:48 +0000 Subject: [PATCH 05/19] fix(lint): use released reusable workflow Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/13b11d79-ed71-4974-a327-ffbeb7be6104 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint-caller.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint-caller.yml b/.github/workflows/lint-caller.yml index 3a116de..649317c 100644 --- a/.github/workflows/lint-caller.yml +++ b/.github/workflows/lint-caller.yml @@ -12,10 +12,11 @@ permissions: jobs: lint: - uses: DevSecNinja/.github/.github/workflows/lint.yml@4d799d366e6af6fd45ca2e7c4dfce6c12467fe09 # PR #66 + uses: DevSecNinja/.github/.github/workflows/lint.yml@e7037884132e77504ca7f50a23e98f594d1c764b # v1.1.0 permissions: contents: read security-events: write with: # renovate: datasource=github-releases depName=jdx/mise mise-version: "2026.4.9" + lint-dprint: false From 6773e469dee0fc49fa248300ed14b93e51c8c74e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:25:50 +0000 Subject: [PATCH 06/19] fix(lint): avoid broad root gitleaks allowlist Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/13b11d79-ed71-4974-a327-ffbeb7be6104 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .gitleaks.toml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .gitleaks.toml diff --git a/.gitleaks.toml b/.gitleaks.toml deleted file mode 100644 index 292d0a7..0000000 --- a/.gitleaks.toml +++ /dev/null @@ -1,3 +0,0 @@ -[allowlist] -description = "Global gitleaks allowlist" -regexes = ["\\d+/api/verify"] From 574bfab1dd46422e0c87ae131c04965f71710673 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:26:16 +0000 Subject: [PATCH 07/19] fix(lint): document temporary dprint disablement Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/13b11d79-ed71-4974-a327-ffbeb7be6104 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint-caller.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lint-caller.yml b/.github/workflows/lint-caller.yml index 649317c..4b1a82d 100644 --- a/.github/workflows/lint-caller.yml +++ b/.github/workflows/lint-caller.yml @@ -19,4 +19,5 @@ jobs: with: # renovate: datasource=github-releases depName=jdx/mise mise-version: "2026.4.9" + # Temporarily disabled pending reusable workflow fix for --allow-no-files. lint-dprint: false From 6007676335df77e0858cab6bb5b9bb09316140e1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:29:57 +0000 Subject: [PATCH 08/19] feat(lint): support shared config directory Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint-caller.yml | 5 +- .github/workflows/lint.yml | 77 ++++++++++++++++++++++--- .shellcheckrc | 8 --- .yamlfmt.yaml | 16 ----- .yamllint.yaml | 16 ----- docs/architecture.md | 2 + dprint.json | 2 +- trivy.yaml | 3 - workflow-templates/lint.properties.json | 2 +- workflow-templates/lint.yml | 2 + 10 files changed, 78 insertions(+), 55 deletions(-) delete mode 100644 .shellcheckrc delete mode 100644 .yamlfmt.yaml delete mode 100644 .yamllint.yaml delete mode 100644 trivy.yaml diff --git a/.github/workflows/lint-caller.yml b/.github/workflows/lint-caller.yml index 4b1a82d..3e54b4f 100644 --- a/.github/workflows/lint-caller.yml +++ b/.github/workflows/lint-caller.yml @@ -12,12 +12,11 @@ permissions: jobs: lint: - uses: DevSecNinja/.github/.github/workflows/lint.yml@e7037884132e77504ca7f50a23e98f594d1c764b # v1.1.0 + uses: ./.github/workflows/lint.yml permissions: contents: read security-events: write with: # renovate: datasource=github-releases depName=jdx/mise mise-version: "2026.4.9" - # Temporarily disabled pending reusable workflow fix for --allow-no-files. - lint-dprint: false + lint-config-dir: config-sync/files diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4913f08..6f1611f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,6 +8,11 @@ on: description: "mise version to install" required: true type: string + lint-config-dir: + description: "Directory containing optional linter config files" + required: false + type: string + default: "" lint-dprint: description: "Run dprint (Markdown formatting)" required: false @@ -95,7 +100,14 @@ jobs: version: ${{ inputs.mise-version }} - name: Check formatting with dprint - run: mise exec -- dprint check --allow-no-files + env: + CONFIG_DIR: ${{ inputs.lint-config-dir }} + run: |- + if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/dprint.json" ]; then + mise exec -- dprint check --config "${CONFIG_DIR}/dprint.json" --allow-no-files . + else + mise exec -- dprint check --allow-no-files + fi yamlfmt: name: yamlfmt @@ -114,7 +126,16 @@ jobs: version: ${{ inputs.mise-version }} - name: Check YAML formatting - run: find . \( -name '*.yaml' -o -name '*.yml' \) -print0 | xargs -0 mise exec -- yamlfmt -lint + env: + CONFIG_DIR: ${{ inputs.lint-config-dir }} + run: |- + if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.yamlfmt.yaml" ]; then + find . \( -name '*.yaml' -o -name '*.yml' \) -print0 | + xargs -0 mise exec -- yamlfmt -conf "${CONFIG_DIR}/.yamlfmt.yaml" -lint + else + find . \( -name '*.yaml' -o -name '*.yml' \) -print0 | + xargs -0 mise exec -- yamlfmt -lint + fi yamllint: name: yamllint @@ -133,7 +154,16 @@ jobs: version: ${{ inputs.mise-version }} - name: Run yamllint - run: find . \( -name '*.yaml' -o -name '*.yml' \) -print0 | xargs -0 mise exec -- yamllint + env: + CONFIG_DIR: ${{ inputs.lint-config-dir }} + run: |- + if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.yamllint.yaml" ]; then + find . \( -name '*.yaml' -o -name '*.yml' \) -print0 | + xargs -0 mise exec -- yamllint -c "${CONFIG_DIR}/.yamllint.yaml" + else + find . \( -name '*.yaml' -o -name '*.yml' \) -print0 | + xargs -0 mise exec -- yamllint + fi actionlint: name: actionlint @@ -172,7 +202,14 @@ jobs: version: ${{ inputs.mise-version }} - name: Run gitleaks - run: mise exec -- gitleaks detect --redact + env: + CONFIG_DIR: ${{ inputs.lint-config-dir }} + run: |- + if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.gitleaks.toml" ]; then + mise exec -- gitleaks detect --redact --config "${CONFIG_DIR}/.gitleaks.toml" + else + mise exec -- gitleaks detect --redact + fi shellcheck: name: shellcheck @@ -192,12 +229,27 @@ jobs: - name: Run shellcheck env: + CONFIG_DIR: ${{ inputs.lint-config-dir }} EXCLUDE_PATTERN: ${{ inputs.lint-shellcheck-exclude }} run: | + shellcheck_args=() + if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.shellcheckrc" ]; then + while IFS= read -r line; do + line="${line%%#*}" + line="${line#"${line%%[![:space:]]*}"}" + line="${line%"${line##*[![:space:]]}"}" + if [ -n "${line}" ]; then + shellcheck_args+=("--${line}") + fi + done < "${CONFIG_DIR}/.shellcheckrc" + fi + if [ -n "${EXCLUDE_PATTERN}" ]; then - find . -name '*.sh' -not -path "./${EXCLUDE_PATTERN}" -print0 | xargs -0 mise exec -- shellcheck + find . -name '*.sh' -not -path "./${EXCLUDE_PATTERN}" -print0 | + xargs -0 mise exec -- shellcheck "${shellcheck_args[@]}" else - find . -name '*.sh' -print0 | xargs -0 mise exec -- shellcheck + find . -name '*.sh' -print0 | + xargs -0 mise exec -- shellcheck "${shellcheck_args[@]}" fi shfmt: @@ -289,7 +341,18 @@ jobs: version: ${{ inputs.mise-version }} - name: Run trivy - run: mise exec -- trivy fs --scanners misconfig,secret --format sarif --output trivy.sarif . || true + env: + CONFIG_DIR: ${{ inputs.lint-config-dir }} + run: |- + trivy_args=() + if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/trivy.yaml" ]; then + trivy_args+=(--config "${CONFIG_DIR}/trivy.yaml") + fi + + mise exec -- trivy fs "${trivy_args[@]}" \ + --scanners misconfig,secret \ + --format sarif \ + --output trivy.sarif . || true - name: Upload SARIF report uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 diff --git a/.shellcheckrc b/.shellcheckrc deleted file mode 100644 index cf3fc32..0000000 --- a/.shellcheckrc +++ /dev/null @@ -1,8 +0,0 @@ -# Default shell dialect; individual scripts override this via their shebang -shell=bash - -# Error severity: error, warning, info, style (default: style — show everything) -severity=style - -# Enable optional checks not on by default -enable=add-default-case,avoid-nullary-conditions,check-extra-masked-returns,check-set-e-suppressed,deprecate-which,quote-safe-variables,require-variable-braces diff --git a/.yamlfmt.yaml b/.yamlfmt.yaml deleted file mode 100644 index 6c79680..0000000 --- a/.yamlfmt.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -doublestar: true -formatter: - type: basic - disable_alias_key_correction: true - indent: 2 - max_line_length: 120 - pad_line_comments: 1 - drop_merge_tag: true - eof_newline: true - force_array_style: block - include_document_start: true - line_ending: lf - retain_line_breaks_single: true - scan_folded_as_literal: true - trim_trailing_whitespace: true diff --git a/.yamllint.yaml b/.yamllint.yaml deleted file mode 100644 index 2d2e080..0000000 --- a/.yamllint.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -extends: default - -rules: - # Inline comment spacing varies by author style — not auto-fixable - comments: disable - # Long lines are unavoidable with image digests, Traefik labels, and URLs — not auto-fixable - line-length: disable - # Let yamlfmt handle document start markers - document-start: disable - # Allow 'on:' as a mapping key in GitHub Actions workflows - truthy: - allowed-values: - - "true" - - "false" - check-keys: false diff --git a/docs/architecture.md b/docs/architecture.md index 6362eee..657be7f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -49,6 +49,7 @@ boolean inputs; all default to `true`. | Input | Description | | ------------------- | ------------------------------------------------ | | `mise-version` | **Required.** mise version to install. | +| `lint-config-dir` | Optional linter config directory. Default: `""`. | | `lint-dprint` | Markdown formatting (dprint). Default: `true`. | | `lint-yamlfmt` | YAML formatting (yamlfmt). Default: `true`. | | `lint-yamllint` | YAML linting (yamllint). Default: `true`. | @@ -73,6 +74,7 @@ jobs: with: # renovate: datasource=github-releases depName=jdx/mise mise-version: "2026.4.5" + # lint-config-dir: config-sync/files ``` ### Release (`release.yml`) diff --git a/dprint.json b/dprint.json index 25ad7a7..1538838 100644 --- a/dprint.json +++ b/dprint.json @@ -1,7 +1,7 @@ { "$schema": "https://dprint.dev/schemas/v0.json", "includes": ["**/*.md"], - "excludes": ["**/node_modules", "config-sync/files/**"], + "excludes": ["**/node_modules"], "plugins": [ "https://plugins.dprint.dev/markdown-0.21.1.wasm" ] diff --git a/trivy.yaml b/trivy.yaml deleted file mode 100644 index 5dba7f0..0000000 --- a/trivy.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -scan: - skip-files: [] diff --git a/workflow-templates/lint.properties.json b/workflow-templates/lint.properties.json index 190bdf0..4aaefab 100644 --- a/workflow-templates/lint.properties.json +++ b/workflow-templates/lint.properties.json @@ -1,6 +1,6 @@ { "name": "Lint", - "description": "Centralized linting workflow with toggles for dprint, yamlfmt, yamllint, actionlint, gitleaks, shellcheck, shfmt, checkov, trivy, zizmor, and config-drift checking.", + "description": "Centralized linting workflow with config-directory support and toggles for dprint, yamlfmt, yamllint, actionlint, gitleaks, shellcheck, shfmt, checkov, trivy, zizmor, and config-drift checking.", "categories": ["Continuous integration"], "filePatterns": ["\\.ya?ml$", "\\.sh$", "\\.md$"] } diff --git a/workflow-templates/lint.yml b/workflow-templates/lint.yml index 264855a..842d87a 100644 --- a/workflow-templates/lint.yml +++ b/workflow-templates/lint.yml @@ -19,6 +19,8 @@ jobs: with: # renovate: datasource=github-releases depName=jdx/mise mise-version: "2026.4.9" + # Optional: use configs from a non-root directory. + # lint-config-dir: config-sync/files # Toggle linters on/off (all default to true): # lint-dprint: true # lint-yamlfmt: true From e843af37f4374d06790d3f6a7ba78afd583b7762 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:30:10 +0000 Subject: [PATCH 09/19] fix(lint): pin shared config workflow revision Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint-caller.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-caller.yml b/.github/workflows/lint-caller.yml index 3e54b4f..e939a4c 100644 --- a/.github/workflows/lint-caller.yml +++ b/.github/workflows/lint-caller.yml @@ -12,7 +12,7 @@ permissions: jobs: lint: - uses: ./.github/workflows/lint.yml + uses: DevSecNinja/.github/.github/workflows/lint.yml@60076760e7e1cb6a94d40def5ae7fac07c357153 # PR #66 permissions: contents: read security-events: write From 444ee98e367fcf7e8807f6df887b21219b2331c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:31:15 +0000 Subject: [PATCH 10/19] fix(lint): validate local reusable workflow Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint-caller.yml | 3 ++- .github/workflows/lint.yml | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint-caller.yml b/.github/workflows/lint-caller.yml index e939a4c..9185cb6 100644 --- a/.github/workflows/lint-caller.yml +++ b/.github/workflows/lint-caller.yml @@ -12,7 +12,8 @@ permissions: jobs: lint: - uses: DevSecNinja/.github/.github/workflows/lint.yml@60076760e7e1cb6a94d40def5ae7fac07c357153 # PR #66 + # Local reference validates reusable workflow changes in this repository. + uses: ./.github/workflows/lint.yml permissions: contents: read security-events: write diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6f1611f..71bbdc5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -239,7 +239,13 @@ jobs: line="${line#"${line%%[![:space:]]*}"}" line="${line%"${line##*[![:space:]]}"}" if [ -n "${line}" ]; then - shellcheck_args+=("--${line}") + if [[ "${line}" == *=* ]]; then + key="${line%%=*}" + value="${line#*=}" + shellcheck_args+=("--${key}=${value}") + else + shellcheck_args+=("--${line}") + fi fi done < "${CONFIG_DIR}/.shellcheckrc" fi From 458919c2a693769edffa8cdcd2bfdc4aacc5438e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:31:57 +0000 Subject: [PATCH 11/19] fix(lint): declare bash for shellcheck step Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 71bbdc5..dfcdc36 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -228,6 +228,7 @@ jobs: version: ${{ inputs.mise-version }} - name: Run shellcheck + shell: bash env: CONFIG_DIR: ${{ inputs.lint-config-dir }} EXCLUDE_PATTERN: ${{ inputs.lint-shellcheck-exclude }} From 99d6cf4b44ce0a34506dcfd7531e9bfae38fcca6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:32:39 +0000 Subject: [PATCH 12/19] refactor(lint): simplify shellcheck config handling Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index dfcdc36..1ad1f32 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -236,9 +236,7 @@ jobs: shellcheck_args=() if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.shellcheckrc" ]; then while IFS= read -r line; do - line="${line%%#*}" - line="${line#"${line%%[![:space:]]*}"}" - line="${line%"${line##*[![:space:]]}"}" + line="$(printf '%s\n' "${line%%#*}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" if [ -n "${line}" ]; then if [[ "${line}" == *=* ]]; then key="${line%%=*}" @@ -252,13 +250,14 @@ jobs: fi if [ -n "${EXCLUDE_PATTERN}" ]; then - find . -name '*.sh' -not -path "./${EXCLUDE_PATTERN}" -print0 | - xargs -0 mise exec -- shellcheck "${shellcheck_args[@]}" + find_args=(-name '*.sh' -not -path "./${EXCLUDE_PATTERN}") else - find . -name '*.sh' -print0 | - xargs -0 mise exec -- shellcheck "${shellcheck_args[@]}" + find_args=(-name '*.sh') fi + find . "${find_args[@]}" -print0 | + xargs -0 mise exec -- shellcheck "${shellcheck_args[@]}" + shfmt: name: shfmt if: ${{ inputs.lint-shfmt }} From 881664ed164e3b9dc5fae0890e88f3dd58d8b434 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:33:21 +0000 Subject: [PATCH 13/19] refactor(lint): clarify shellcheck config parsing Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1ad1f32..f5f8a8d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -236,6 +236,7 @@ jobs: shellcheck_args=() if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.shellcheckrc" ]; then while IFS= read -r line; do + # Strip inline comments and surrounding whitespace. line="$(printf '%s\n' "${line%%#*}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" if [ -n "${line}" ]; then if [[ "${line}" == *=* ]]; then @@ -249,10 +250,9 @@ jobs: done < "${CONFIG_DIR}/.shellcheckrc" fi + find_args=(-name '*.sh') if [ -n "${EXCLUDE_PATTERN}" ]; then - find_args=(-name '*.sh' -not -path "./${EXCLUDE_PATTERN}") - else - find_args=(-name '*.sh') + find_args+=(-not -path "./${EXCLUDE_PATTERN}") fi find . "${find_args[@]}" -print0 | From e1df9b01b01d273bc2ea217871574e85b955967f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:34:14 +0000 Subject: [PATCH 14/19] refactor(lint): use native shellcheck config discovery Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint.yml | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f5f8a8d..f6c9a7a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -82,6 +82,10 @@ on: permissions: contents: read +defaults: + run: + shell: bash + jobs: dprint: name: dprint @@ -228,35 +232,21 @@ jobs: version: ${{ inputs.mise-version }} - name: Run shellcheck - shell: bash env: CONFIG_DIR: ${{ inputs.lint-config-dir }} EXCLUDE_PATTERN: ${{ inputs.lint-shellcheck-exclude }} run: | - shellcheck_args=() if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.shellcheckrc" ]; then - while IFS= read -r line; do - # Strip inline comments and surrounding whitespace. - line="$(printf '%s\n' "${line%%#*}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" - if [ -n "${line}" ]; then - if [[ "${line}" == *=* ]]; then - key="${line%%=*}" - value="${line#*=}" - shellcheck_args+=("--${key}=${value}") - else - shellcheck_args+=("--${line}") - fi - fi - done < "${CONFIG_DIR}/.shellcheckrc" + cp "${CONFIG_DIR}/.shellcheckrc" .shellcheckrc fi - find_args=(-name '*.sh') + find_match_args=(-name '*.sh') if [ -n "${EXCLUDE_PATTERN}" ]; then - find_args+=(-not -path "./${EXCLUDE_PATTERN}") + find_match_args+=(-not -path "./${EXCLUDE_PATTERN}") fi - find . "${find_args[@]}" -print0 | - xargs -0 mise exec -- shellcheck "${shellcheck_args[@]}" + find . "${find_match_args[@]}" -print0 | + xargs -0 mise exec -- shellcheck shfmt: name: shfmt From 6be655d0072a1b1a51ff539fb857fdbebc1ae74d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:34:55 +0000 Subject: [PATCH 15/19] fix(lint): document shellcheck config discovery Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f6c9a7a..ef4a99d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -237,17 +237,18 @@ jobs: EXCLUDE_PATTERN: ${{ inputs.lint-shellcheck-exclude }} run: | if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.shellcheckrc" ]; then + # ShellCheck has no --rcfile flag, so copy the shared config for native discovery. cp "${CONFIG_DIR}/.shellcheckrc" .shellcheckrc fi - find_match_args=(-name '*.sh') if [ -n "${EXCLUDE_PATTERN}" ]; then - find_match_args+=(-not -path "./${EXCLUDE_PATTERN}") + find . -name '*.sh' -not -path "./${EXCLUDE_PATTERN}" -print0 | + xargs -0 mise exec -- shellcheck + else + find . -name '*.sh' -print0 | + xargs -0 mise exec -- shellcheck fi - find . "${find_match_args[@]}" -print0 | - xargs -0 mise exec -- shellcheck - shfmt: name: shfmt if: ${{ inputs.lint-shfmt }} From c8846feec1585a0ed338f4ee0bae6f3d48e6b671 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:35:40 +0000 Subject: [PATCH 16/19] fix(lint): avoid overwriting local shellcheck config Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index ef4a99d..6fea5d6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -108,7 +108,7 @@ jobs: CONFIG_DIR: ${{ inputs.lint-config-dir }} run: |- if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/dprint.json" ]; then - mise exec -- dprint check --config "${CONFIG_DIR}/dprint.json" --allow-no-files . + mise exec -- dprint check --config "${CONFIG_DIR}/dprint.json" --allow-no-files else mise exec -- dprint check --allow-no-files fi @@ -238,7 +238,11 @@ jobs: run: | if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.shellcheckrc" ]; then # ShellCheck has no --rcfile flag, so copy the shared config for native discovery. - cp "${CONFIG_DIR}/.shellcheckrc" .shellcheckrc + if [ -f .shellcheckrc ]; then + echo "::notice::.shellcheckrc already exists; using the local file" + else + cp "${CONFIG_DIR}/.shellcheckrc" .shellcheckrc + fi fi if [ -n "${EXCLUDE_PATTERN}" ]; then From 8bbf8f41e6104bb74641d8bf6d90786d4880eba5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:36:22 +0000 Subject: [PATCH 17/19] fix(lint): clean up temporary shellcheck config Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint.yml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6fea5d6..c9bbb1d 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -236,12 +236,16 @@ jobs: CONFIG_DIR: ${{ inputs.lint-config-dir }} EXCLUDE_PATTERN: ${{ inputs.lint-shellcheck-exclude }} run: | + copied_shellcheck_config=false + trap 'if [ "${copied_shellcheck_config}" = "true" ]; then rm -f .shellcheckrc; fi' EXIT + if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.shellcheckrc" ]; then # ShellCheck has no --rcfile flag, so copy the shared config for native discovery. if [ -f .shellcheckrc ]; then echo "::notice::.shellcheckrc already exists; using the local file" else cp "${CONFIG_DIR}/.shellcheckrc" .shellcheckrc + copied_shellcheck_config=true fi fi @@ -350,10 +354,17 @@ jobs: trivy_args+=(--config "${CONFIG_DIR}/trivy.yaml") fi - mise exec -- trivy fs "${trivy_args[@]}" \ - --scanners misconfig,secret \ - --format sarif \ - --output trivy.sarif . || true + if [ "${#trivy_args[@]}" -gt 0 ]; then + mise exec -- trivy fs "${trivy_args[@]}" \ + --scanners misconfig,secret \ + --format sarif \ + --output trivy.sarif . || true + else + mise exec -- trivy fs \ + --scanners misconfig,secret \ + --format sarif \ + --output trivy.sarif . || true + fi - name: Upload SARIF report uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 From 408bc8ebcba4204337ada457944deacb6c198907 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:37:18 +0000 Subject: [PATCH 18/19] fix(lint): isolate shared shellcheck config Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/e8acf18f-4a23-40d0-bfca-e7d44cd8a653 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/workflows/lint.yml | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c9bbb1d..1d93fdd 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -236,25 +236,25 @@ jobs: CONFIG_DIR: ${{ inputs.lint-config-dir }} EXCLUDE_PATTERN: ${{ inputs.lint-shellcheck-exclude }} run: | - copied_shellcheck_config=false - trap 'if [ "${copied_shellcheck_config}" = "true" ]; then rm -f .shellcheckrc; fi' EXIT + repo_dir="${GITHUB_WORKSPACE:-$PWD}" + shellcheck_workdir="${repo_dir}" if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.shellcheckrc" ]; then - # ShellCheck has no --rcfile flag, so copy the shared config for native discovery. - if [ -f .shellcheckrc ]; then + if [ -f "${repo_dir}/.shellcheckrc" ]; then echo "::notice::.shellcheckrc already exists; using the local file" else - cp "${CONFIG_DIR}/.shellcheckrc" .shellcheckrc - copied_shellcheck_config=true + shellcheck_workdir="${RUNNER_TEMP:-/tmp}/shellcheck-config" + mkdir -p "${shellcheck_workdir}" + cp "${CONFIG_DIR}/.shellcheckrc" "${shellcheck_workdir}/.shellcheckrc" fi fi if [ -n "${EXCLUDE_PATTERN}" ]; then - find . -name '*.sh' -not -path "./${EXCLUDE_PATTERN}" -print0 | - xargs -0 mise exec -- shellcheck + find "${repo_dir}" -name '*.sh' -not -path "${repo_dir}/${EXCLUDE_PATTERN}" -print0 | + (cd "${shellcheck_workdir}" && xargs -0 mise exec -- shellcheck) else - find . -name '*.sh' -print0 | - xargs -0 mise exec -- shellcheck + find "${repo_dir}" -name '*.sh' -print0 | + (cd "${shellcheck_workdir}" && xargs -0 mise exec -- shellcheck) fi shfmt: @@ -354,17 +354,10 @@ jobs: trivy_args+=(--config "${CONFIG_DIR}/trivy.yaml") fi - if [ "${#trivy_args[@]}" -gt 0 ]; then - mise exec -- trivy fs "${trivy_args[@]}" \ - --scanners misconfig,secret \ - --format sarif \ - --output trivy.sarif . || true - else - mise exec -- trivy fs \ - --scanners misconfig,secret \ - --format sarif \ - --output trivy.sarif . || true - fi + mise exec -- trivy fs "${trivy_args[@]}" \ + --scanners misconfig,secret \ + --format sarif \ + --output trivy.sarif . || true - name: Upload SARIF report uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 From 50e419ed5f56872cf92086b7cf4f55790924b2de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 07:46:13 +0000 Subject: [PATCH 19/19] fix(lint): add and run shared autofix workflow Agent-Logs-Url: https://github.com/DevSecNinja/.github/sessions/ee6a7326-e7f7-40e8-8ac9-49d2e52b3326 Co-authored-by: DevSecNinja <14926452+DevSecNinja@users.noreply.github.com> --- .github/actions/notify-irm/README.md | 10 +- .github/skills/commit-and-release/SKILL.md | 2 +- .../workflows/assign-issue-to-codeowners.yml | 2 +- .github/workflows/autofix-caller.yml | 19 +++ .github/workflows/autofix.yml | 27 +++- .github/workflows/config-sync.yml | 3 +- .github/workflows/lint.yml | 5 +- .github/workflows/todo-to-issue.yml | 3 +- CHANGELOG.md | 77 ++++++------ actions/harden-runner/README.md | 2 +- actions/open-pr/README.md | 42 +++---- actions/open-pr/action.yml | 2 +- actions/release-publish/README.md | 24 ++-- actions/release-publish/action.yml | 2 +- docs/architecture.md | 118 ++++++++++-------- .../0001-reusable-workflow-version-inputs.md | 36 +++--- docs/design-decisions/README.md | 8 +- dprint.json | 8 -- workflow-templates/autofix.properties.json | 2 +- workflow-templates/autofix.yml | 2 + workflow-templates/config-sync.yml | 6 +- workflow-templates/labeler.yml | 4 +- 22 files changed, 229 insertions(+), 175 deletions(-) create mode 100644 .github/workflows/autofix-caller.yml delete mode 100644 dprint.json diff --git a/.github/actions/notify-irm/README.md b/.github/actions/notify-irm/README.md index 3d1a4f7..3cffbad 100644 --- a/.github/actions/notify-irm/README.md +++ b/.github/actions/notify-irm/README.md @@ -18,11 +18,11 @@ auto-resolve once the workflow goes green again. ## Inputs -| Name | Required | Default | Description | -| -------------------- | :------: | ------- | ---------------------------------------------------------------------------------------------------------- | -| `webhook-url` | yes | — | Grafana IRM Custom webhook URL. Empty value disables the step. | -| `job-failed` | yes | — | `'true'` when any prior job failed/was cancelled, `'false'` otherwise. | -| `service` | no | `ci` | Logical service tag for IRM routing/labelling. | +| Name | Required | Default | Description | +| -------------------- | :------: | ------- | ------------------------------------------------------------------------------------------------------------ | +| `webhook-url` | yes | — | Grafana IRM Custom webhook URL. Empty value disables the step. | +| `job-failed` | yes | — | `'true'` when any prior job failed/was cancelled, `'false'` otherwise. | +| `service` | no | `ci` | Logical service tag for IRM routing/labelling. | | `resolve-on-success` | no | `true` | When `true`, a green run posts `state=ok` to auto-resolve. Set `false` for unique-uid workflows (e.g. tags). | ## Usage diff --git a/.github/skills/commit-and-release/SKILL.md b/.github/skills/commit-and-release/SKILL.md index 11d2723..dd247eb 100644 --- a/.github/skills/commit-and-release/SKILL.md +++ b/.github/skills/commit-and-release/SKILL.md @@ -211,4 +211,4 @@ The tag push triggers `.github/workflows/release.yml`, which generates release-s After every successful release, end with a celebrative message. Be enthusiastic, reference the version number, and congratulate the team on shipping. Make it fun — this is a milestone worth celebrating! Example: -> "SHIP IT! v0.12.0 is now LIVE and sailing into production! The stacks are deployed, the changelog is fresh, and the CI is green. Take a beer — you've earned it!" \ No newline at end of file +> "SHIP IT! v0.12.0 is now LIVE and sailing into production! The stacks are deployed, the changelog is fresh, and the CI is green. Take a beer — you've earned it!" diff --git a/.github/workflows/assign-issue-to-codeowners.yml b/.github/workflows/assign-issue-to-codeowners.yml index c004fc1..1be5c66 100644 --- a/.github/workflows/assign-issue-to-codeowners.yml +++ b/.github/workflows/assign-issue-to-codeowners.yml @@ -38,7 +38,7 @@ jobs: EXCLUDE_RENOVATE_ISSUES: ${{ inputs.exclude-renovate-issues }} ISSUE_NUMBER: ${{ inputs.issue-number }} with: - script: | + script: |- // Try to read CODEOWNERS from common locations const paths = ['.github/CODEOWNERS', 'CODEOWNERS', 'docs/CODEOWNERS']; let content = null; diff --git a/.github/workflows/autofix-caller.yml b/.github/workflows/autofix-caller.yml new file mode 100644 index 0000000..03276c6 --- /dev/null +++ b/.github/workflows/autofix-caller.yml @@ -0,0 +1,19 @@ +--- +name: Auto-fix formatting + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + autofix: + # Local reference validates reusable workflow changes in this repository. + uses: ./.github/workflows/autofix.yml + permissions: + contents: write + with: + # renovate: datasource=github-releases depName=jdx/mise + mise-version: "2026.4.9" + autofix-config-dir: config-sync/files diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml index ed0d87d..6b20482 100644 --- a/.github/workflows/autofix.yml +++ b/.github/workflows/autofix.yml @@ -8,6 +8,11 @@ on: description: "mise version to install" required: true type: string + autofix-config-dir: + description: "Directory containing optional formatter config files" + required: false + type: string + default: "" autofix-dprint: description: "Run dprint fmt (Markdown auto-format)" required: false @@ -48,11 +53,29 @@ jobs: - name: Auto-fix with dprint if: ${{ inputs.autofix-dprint }} - run: mise exec -- dprint fmt + env: + CONFIG_DIR: ${{ inputs.autofix-config-dir }} + run: |- + if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/dprint.json" ]; then + mise exec -- dprint fmt \ + --config "${CONFIG_DIR}/dprint.json" \ + --config-discovery=false + else + mise exec -- dprint fmt + fi - name: Auto-fix with yamlfmt if: ${{ inputs.autofix-yamlfmt }} - run: find . \( -name '*.yaml' -o -name '*.yml' \) -print0 | xargs -0 mise exec -- yamlfmt + env: + CONFIG_DIR: ${{ inputs.autofix-config-dir }} + run: |- + if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/.yamlfmt.yaml" ]; then + find . \( -name '*.yaml' -o -name '*.yml' \) -print0 | + xargs -0 mise exec -- yamlfmt -conf "${CONFIG_DIR}/.yamlfmt.yaml" + else + find . \( -name '*.yaml' -o -name '*.yml' \) -print0 | + xargs -0 mise exec -- yamlfmt + fi - name: Auto-fix with shfmt if: ${{ inputs.autofix-shfmt }} diff --git a/.github/workflows/config-sync.yml b/.github/workflows/config-sync.yml index 44e5c25..6c25b92 100644 --- a/.github/workflows/config-sync.yml +++ b/.github/workflows/config-sync.yml @@ -9,7 +9,8 @@ on: workflow_call: inputs: sync-templates: - description: "Also sync template files (only copies if file does not exist locally — will not overwrite customized files)" + description: "Also sync template files (only copies if file does not exist locally — will not overwrite customized + files)" required: false type: boolean default: false diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1d93fdd..db03baf 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -108,7 +108,10 @@ jobs: CONFIG_DIR: ${{ inputs.lint-config-dir }} run: |- if [ -n "${CONFIG_DIR}" ] && [ -f "${CONFIG_DIR}/dprint.json" ]; then - mise exec -- dprint check --config "${CONFIG_DIR}/dprint.json" --allow-no-files + mise exec -- dprint check \ + --config "${CONFIG_DIR}/dprint.json" \ + --config-discovery=false \ + --allow-no-files else mise exec -- dprint check --allow-no-files fi diff --git a/.github/workflows/todo-to-issue.yml b/.github/workflows/todo-to-issue.yml index 674d084..3130649 100644 --- a/.github/workflows/todo-to-issue.yml +++ b/.github/workflows/todo-to-issue.yml @@ -34,4 +34,5 @@ jobs: with: AUTO_ASSIGN: "${{ inputs.auto_assign }}" IDENTIFIERS: >- - ${{ inputs.label != '' && format('[{{"name": "TODO", "labels": ["{0}"]}}]', inputs.label) || '[{"name": "TODO", "labels": []}]' }} + ${{ inputs.label != '' && format('[{{"name": "TODO", "labels": ["{0}"]}}]', inputs.label) || '[{"name": "TODO", + "labels": []}]' }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f54973..33b9c84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,56 +4,53 @@ All notable changes to this project will be documented in this file. ## [1.2.0](https://github.com/DevSecNinja/.github/compare/v1.1.0...v1.2.0) (2026-05-01) - ### Features -* **actions:** add notify-irm composite action ([#51](https://github.com/DevSecNinja/.github/issues/51)) ([a877d35](https://github.com/DevSecNinja/.github/commit/a877d35266a54e54ef043e60a290ed76b4d7b34e)) -* **labels:** rename automerge to `merge: auto` and add release-please labels ([#45](https://github.com/DevSecNinja/.github/issues/45)) ([fa92001](https://github.com/DevSecNinja/.github/commit/fa92001d3877b58e3c8f8b0fa2f6f9230fbb0792)) -* **mise:** update tool zizmor ( 1.23.1 ➔ 1.24.1 ) ([9e3203f](https://github.com/DevSecNinja/.github/commit/9e3203f70c12fe4b918fa0cd26238b553964a413)) -* **mise:** update tool zizmor ( 1.23.1 ➔ 1.24.1 ) ([#39](https://github.com/DevSecNinja/.github/issues/39)) ([e3291b1](https://github.com/DevSecNinja/.github/commit/e3291b1e914c6930a726cbcdc56ccab4fcbdb61a)) -* **open-pr:** add composite action to open or update PRs from working tree ([#49](https://github.com/DevSecNinja/.github/issues/49)) ([6764c0f](https://github.com/DevSecNinja/.github/commit/6764c0fb5ffc25207571b159dc255c8f77922c62)) -* **renovate:** add `merge: manual` label rules ([#46](https://github.com/DevSecNinja/.github/issues/46)) ([f447e9e](https://github.com/DevSecNinja/.github/commit/f447e9eeefdcfc24fba0b4b600be4c321fa8f208)) +- **actions:** add notify-irm composite action ([#51](https://github.com/DevSecNinja/.github/issues/51)) ([a877d35](https://github.com/DevSecNinja/.github/commit/a877d35266a54e54ef043e60a290ed76b4d7b34e)) +- **labels:** rename automerge to `merge: auto` and add release-please labels ([#45](https://github.com/DevSecNinja/.github/issues/45)) ([fa92001](https://github.com/DevSecNinja/.github/commit/fa92001d3877b58e3c8f8b0fa2f6f9230fbb0792)) +- **mise:** update tool zizmor ( 1.23.1 ➔ 1.24.1 ) ([9e3203f](https://github.com/DevSecNinja/.github/commit/9e3203f70c12fe4b918fa0cd26238b553964a413)) +- **mise:** update tool zizmor ( 1.23.1 ➔ 1.24.1 ) ([#39](https://github.com/DevSecNinja/.github/issues/39)) ([e3291b1](https://github.com/DevSecNinja/.github/commit/e3291b1e914c6930a726cbcdc56ccab4fcbdb61a)) +- **open-pr:** add composite action to open or update PRs from working tree ([#49](https://github.com/DevSecNinja/.github/issues/49)) ([6764c0f](https://github.com/DevSecNinja/.github/commit/6764c0fb5ffc25207571b159dc255c8f77922c62)) +- **renovate:** add `merge: manual` label rules ([#46](https://github.com/DevSecNinja/.github/issues/46)) ([f447e9e](https://github.com/DevSecNinja/.github/commit/f447e9eeefdcfc24fba0b4b600be4c321fa8f208)) ## [1.1.0](https://github.com/DevSecNinja/.github/compare/v1.0.0...v1.1.0) (2026-05-01) - ### Features -* add custom manager for Ansible inventory YAML files ([46eb1be](https://github.com/DevSecNinja/.github/commit/46eb1be9eba6a1e16b068f956880bedfe3900431)) -* add host rules and registry aliases for dhi.io ([641aa02](https://github.com/DevSecNinja/.github/commit/641aa0204e8cddbad9b515b6954221309307d841)) -* add labels and vulnerability alerts to Renovate configuration ([b9273f0](https://github.com/DevSecNinja/.github/commit/b9273f0e9f610757c8c6a0971218f1c0a7cc8d98)) -* **config-sync:** ensure label exists before opening a PR ([1cc371b](https://github.com/DevSecNinja/.github/commit/1cc371b697c812683b878d0e2201bb1f65718424)) -* **labeler:** add issue labeling via github/issue-labeler ([794bec0](https://github.com/DevSecNinja/.github/commit/794bec023309821156952f39b2ab000f5a438ce3)) -* **lint:** add auto-fix mode reusable workflow and template ([f163ca1](https://github.com/DevSecNinja/.github/commit/f163ca18a0a8644c916c8a034f39335f848de491)) -* **lint:** add shellcheck/shfmt exclude inputs ([17aa697](https://github.com/DevSecNinja/.github/commit/17aa6976bea066f1834c052e8da01fa19962ebfe)) -* **lint:** add shellcheck/shfmt exclude inputs to reusable lint workflow ([0c4551a](https://github.com/DevSecNinja/.github/commit/0c4551a1ebe5f5332511514e4d45a9bb4df2df09)) -* **mise:** update tool dprint ( 0.53.2 ➔ 0.54.0 ) ([963e1d1](https://github.com/DevSecNinja/.github/commit/963e1d1bdc261be68c68a632fe3f4dac84df43ae)) -* **release-please:** wire GitHub App token + onboarding doc ([217074e](https://github.com/DevSecNinja/.github/commit/217074ec255c5d73af534576479c34844667a2d1)) -* **release-please:** wire GitHub App token + onboarding doc ([e29c6a9](https://github.com/DevSecNinja/.github/commit/e29c6a934b4210dd13f909d5c5745914f584f020)) -* **release:** add release-please reusable workflow ([4890fa8](https://github.com/DevSecNinja/.github/commit/4890fa871a85bacb5a6f25e56415849d33652712)) -* **release:** add release-please reusable workflow ([7ed381a](https://github.com/DevSecNinja/.github/commit/7ed381a72cf3d86d34aa5db3818dd468968e46ce)) -* **release:** add release-publish composite action ([ee0804b](https://github.com/DevSecNinja/.github/commit/ee0804b737700aeecd6d1b1bc85ab57107c880e3)) -* **release:** add release-publish composite action ([1f5bcf2](https://github.com/DevSecNinja/.github/commit/1f5bcf20495c36c07f1040a4f79a8053a4649cdb)) -* **release:** onboard .github repo to release-please ([7d8ca17](https://github.com/DevSecNinja/.github/commit/7d8ca17e0611196f47e35113f25754e0d73e7994)) -* **release:** onboard .github repo to release-please ([0e0be6d](https://github.com/DevSecNinja/.github/commit/0e0be6da7f1bf0e0e331792e181417a55349e16d)) -* **renovate:** add custom manager for dotfiles log.sh release pin ([aab92ba](https://github.com/DevSecNinja/.github/commit/aab92ba8d190f80d2dce8393c37b3394ee078fb3)) -* **renovate:** expand auto-merge to all minor/patch updates ([78be78d](https://github.com/DevSecNinja/.github/commit/78be78dd79bc07729a7daa0bddd91ecf90c006a7)) -* **todo-to-issue:** add auto_assign and label inputs, fix todo-to-issue label ([f830665](https://github.com/DevSecNinja/.github/commit/f830665929b67060bac3a65d4cfc4dde3f81a82f)) -* update Renovate configuration to extend best practices and remove deprecated settings ([632d58e](https://github.com/DevSecNinja/.github/commit/632d58e4ec6b8b0d618b871d823c6f970f6bfc15)) -* **workflow-templates:** pin all template refs to v1.0.0 and add changelog category ([8b63cf9](https://github.com/DevSecNinja/.github/commit/8b63cf9fda6a2ea132593ff03755d90234a250ca)) - +- add custom manager for Ansible inventory YAML files ([46eb1be](https://github.com/DevSecNinja/.github/commit/46eb1be9eba6a1e16b068f956880bedfe3900431)) +- add host rules and registry aliases for dhi.io ([641aa02](https://github.com/DevSecNinja/.github/commit/641aa0204e8cddbad9b515b6954221309307d841)) +- add labels and vulnerability alerts to Renovate configuration ([b9273f0](https://github.com/DevSecNinja/.github/commit/b9273f0e9f610757c8c6a0971218f1c0a7cc8d98)) +- **config-sync:** ensure label exists before opening a PR ([1cc371b](https://github.com/DevSecNinja/.github/commit/1cc371b697c812683b878d0e2201bb1f65718424)) +- **labeler:** add issue labeling via github/issue-labeler ([794bec0](https://github.com/DevSecNinja/.github/commit/794bec023309821156952f39b2ab000f5a438ce3)) +- **lint:** add auto-fix mode reusable workflow and template ([f163ca1](https://github.com/DevSecNinja/.github/commit/f163ca18a0a8644c916c8a034f39335f848de491)) +- **lint:** add shellcheck/shfmt exclude inputs ([17aa697](https://github.com/DevSecNinja/.github/commit/17aa6976bea066f1834c052e8da01fa19962ebfe)) +- **lint:** add shellcheck/shfmt exclude inputs to reusable lint workflow ([0c4551a](https://github.com/DevSecNinja/.github/commit/0c4551a1ebe5f5332511514e4d45a9bb4df2df09)) +- **mise:** update tool dprint ( 0.53.2 ➔ 0.54.0 ) ([963e1d1](https://github.com/DevSecNinja/.github/commit/963e1d1bdc261be68c68a632fe3f4dac84df43ae)) +- **release-please:** wire GitHub App token + onboarding doc ([217074e](https://github.com/DevSecNinja/.github/commit/217074ec255c5d73af534576479c34844667a2d1)) +- **release-please:** wire GitHub App token + onboarding doc ([e29c6a9](https://github.com/DevSecNinja/.github/commit/e29c6a934b4210dd13f909d5c5745914f584f020)) +- **release:** add release-please reusable workflow ([4890fa8](https://github.com/DevSecNinja/.github/commit/4890fa871a85bacb5a6f25e56415849d33652712)) +- **release:** add release-please reusable workflow ([7ed381a](https://github.com/DevSecNinja/.github/commit/7ed381a72cf3d86d34aa5db3818dd468968e46ce)) +- **release:** add release-publish composite action ([ee0804b](https://github.com/DevSecNinja/.github/commit/ee0804b737700aeecd6d1b1bc85ab57107c880e3)) +- **release:** add release-publish composite action ([1f5bcf2](https://github.com/DevSecNinja/.github/commit/1f5bcf20495c36c07f1040a4f79a8053a4649cdb)) +- **release:** onboard .github repo to release-please ([7d8ca17](https://github.com/DevSecNinja/.github/commit/7d8ca17e0611196f47e35113f25754e0d73e7994)) +- **release:** onboard .github repo to release-please ([0e0be6d](https://github.com/DevSecNinja/.github/commit/0e0be6da7f1bf0e0e331792e181417a55349e16d)) +- **renovate:** add custom manager for dotfiles log.sh release pin ([aab92ba](https://github.com/DevSecNinja/.github/commit/aab92ba8d190f80d2dce8393c37b3394ee078fb3)) +- **renovate:** expand auto-merge to all minor/patch updates ([78be78d](https://github.com/DevSecNinja/.github/commit/78be78dd79bc07729a7daa0bddd91ecf90c006a7)) +- **todo-to-issue:** add auto_assign and label inputs, fix todo-to-issue label ([f830665](https://github.com/DevSecNinja/.github/commit/f830665929b67060bac3a65d4cfc4dde3f81a82f)) +- update Renovate configuration to extend best practices and remove deprecated settings ([632d58e](https://github.com/DevSecNinja/.github/commit/632d58e4ec6b8b0d618b871d823c6f970f6bfc15)) +- **workflow-templates:** pin all template refs to v1.0.0 and add changelog category ([8b63cf9](https://github.com/DevSecNinja/.github/commit/8b63cf9fda6a2ea132593ff03755d90234a250ca)) ### Bug Fixes -* **checkov:** filter skipped checks from SARIF before upload ([36b12c2](https://github.com/DevSecNinja/.github/commit/36b12c20b17e9ae1d596524928fae013cd9a4cbb)) -* **config-sync:** replace stash with force-checkout and restore from tmp ([26b001e](https://github.com/DevSecNinja/.github/commit/26b001eb16d0f67887e26dfab340573a6398efce)) -* **config-sync:** stash untracked files before branch checkout and auto-create label ([b9b199e](https://github.com/DevSecNinja/.github/commit/b9b199e6ef225c6e8da6ded4da2cf2c492f6d94e)) -* **github-release:** update release jdx/mise ( v2026.4.5 ➔ v2026.4.9 ) ([bb51292](https://github.com/DevSecNinja/.github/commit/bb51292e9a07d5e6d1a512047949bf07028388e1)) -* **mise:** update tool pipx:checkov ( 3.2.513 ➔ 3.2.521 ) ([48fd48b](https://github.com/DevSecNinja/.github/commit/48fd48b1d523ecd73bf1fa99a5d4dfcbb5b1b115)) -* **mise:** update tool shfmt ( 3.13.0 ➔ 3.13.1 ) ([f268d08](https://github.com/DevSecNinja/.github/commit/f268d0881372f838b16d32c3f92a14665237bbac)) -* **renovate:** auto-merge github-actions pinDigest updates ([5979dc3](https://github.com/DevSecNinja/.github/commit/5979dc3c548db482fd2fa730c312bec33caa6f00)) -* **workflow-templates:** update event types format in assign-issue-to-codeowners.yml ([edb5985](https://github.com/DevSecNinja/.github/commit/edb5985189b734443c2948205d52939cdc24a6e9)) -* **workflows:** quote IDENTIFIERS expression in todo-to-issue workflow ([27869fe](https://github.com/DevSecNinja/.github/commit/27869febccdd16c256414c265650ec3ba0aba04e)) +- **checkov:** filter skipped checks from SARIF before upload ([36b12c2](https://github.com/DevSecNinja/.github/commit/36b12c20b17e9ae1d596524928fae013cd9a4cbb)) +- **config-sync:** replace stash with force-checkout and restore from tmp ([26b001e](https://github.com/DevSecNinja/.github/commit/26b001eb16d0f67887e26dfab340573a6398efce)) +- **config-sync:** stash untracked files before branch checkout and auto-create label ([b9b199e](https://github.com/DevSecNinja/.github/commit/b9b199e6ef225c6e8da6ded4da2cf2c492f6d94e)) +- **github-release:** update release jdx/mise ( v2026.4.5 ➔ v2026.4.9 ) ([bb51292](https://github.com/DevSecNinja/.github/commit/bb51292e9a07d5e6d1a512047949bf07028388e1)) +- **mise:** update tool pipx:checkov ( 3.2.513 ➔ 3.2.521 ) ([48fd48b](https://github.com/DevSecNinja/.github/commit/48fd48b1d523ecd73bf1fa99a5d4dfcbb5b1b115)) +- **mise:** update tool shfmt ( 3.13.0 ➔ 3.13.1 ) ([f268d08](https://github.com/DevSecNinja/.github/commit/f268d0881372f838b16d32c3f92a14665237bbac)) +- **renovate:** auto-merge github-actions pinDigest updates ([5979dc3](https://github.com/DevSecNinja/.github/commit/5979dc3c548db482fd2fa730c312bec33caa6f00)) +- **workflow-templates:** update event types format in assign-issue-to-codeowners.yml ([edb5985](https://github.com/DevSecNinja/.github/commit/edb5985189b734443c2948205d52939cdc24a6e9)) +- **workflows:** quote IDENTIFIERS expression in todo-to-issue workflow ([27869fe](https://github.com/DevSecNinja/.github/commit/27869febccdd16c256414c265650ec3ba0aba04e)) ## [1.0.0] - 2026-04-21 diff --git a/actions/harden-runner/README.md b/actions/harden-runner/README.md index fa681f4..8316ec8 100644 --- a/actions/harden-runner/README.md +++ b/actions/harden-runner/README.md @@ -22,7 +22,7 @@ audit findings to create `allowed-endpoints`, then switch high-value jobs to | `token` | no | `${{ github.token }}` | GitHub token used by Harden-Runner to avoid API rate limits. | | `disable-telemetry` | no | `false` | Disable telemetry to StepSecurity. Only supported when `egress-policy` is `block`. | | `disable-sudo-and-containers` | no | `false` | Disable sudo and container access for the runner account. | -| `disable-file-monitoring` | no | `false` | Disable file monitoring. | +| `disable-file-monitoring` | no | `false` | Disable file monitoring. | | `policy` | no | `""` | Policy name to use from the policy store. Requires `id-token: write`. | | `use-policy-store` | no | `false` | Fetch policy from the StepSecurity policy store. | | `api-key` | no | `""` | StepSecurity API key for policy-store authentication. Store this in GitHub Secrets. | diff --git a/actions/open-pr/README.md b/actions/open-pr/README.md index e3c989b..98f74dd 100644 --- a/actions/open-pr/README.md +++ b/actions/open-pr/README.md @@ -25,30 +25,30 @@ GitHub-hosted runners. ## Inputs -| Name | Required | Default | Description | -| ---------------- | -------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `branch` | yes | — | Working branch to create or force-push to. Use a stable per-purpose name (e.g. `chore/sign-powershell-scripts`) so repeat runs reuse the same PR. | -| `base` | no | `main` | Branch to merge into. | -| `title` | yes | — | PR title (also default commit message). Should be a Conventional Commit subject. | -| `body` | no | `""` | PR body, plain Markdown. | -| `commit-message` | no | `title` | Commit message for the staged changes. Defaults to `title`. | -| `paths` | no | `.` | Newline-delimited pathspecs to `git add`. Globs are forwarded literally. | -| `labels` | no | `""` | Newline-delimited labels to apply on PR creation. | -| `draft` | no | `false` | Open as draft. | -| `signoff` | no | `false` | Add a `Signed-off-by` trailer to the commit. | -| `if-no-changes` | no | `skip` | Behaviour when there's nothing to commit: `skip` (exit 0) or `fail` (exit non-zero). | -| `git-user-name` | no | `github-actions[bot]` | Author name for the commit. | -| `git-user-email` | no | `41898282+github-actions[bot]@users.noreply.github.com` | Author email for the commit. | -| `github-token` | no | `${{ github.token }}` | Token used for the `git push` and `gh` API call. The default `GITHUB_TOKEN` will NOT retrigger workflows on the bot's push, which is what you want inside loops like signing-on-push. Pass a PAT/App token for cross-repo PRs or to retrigger CI on the new branch. | +| Name | Required | Default | Description | +| ---------------- | -------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `branch` | yes | — | Working branch to create or force-push to. Use a stable per-purpose name (e.g. `chore/sign-powershell-scripts`) so repeat runs reuse the same PR. | +| `base` | no | `main` | Branch to merge into. | +| `title` | yes | — | PR title (also default commit message). Should be a Conventional Commit subject. | +| `body` | no | `""` | PR body, plain Markdown. | +| `commit-message` | no | `title` | Commit message for the staged changes. Defaults to `title`. | +| `paths` | no | `.` | Newline-delimited pathspecs to `git add`. Globs are forwarded literally. | +| `labels` | no | `""` | Newline-delimited labels to apply on PR creation. | +| `draft` | no | `false` | Open as draft. | +| `signoff` | no | `false` | Add a `Signed-off-by` trailer to the commit. | +| `if-no-changes` | no | `skip` | Behaviour when there's nothing to commit: `skip` (exit 0) or `fail` (exit non-zero). | +| `git-user-name` | no | `github-actions[bot]` | Author name for the commit. | +| `git-user-email` | no | `41898282+github-actions[bot]@users.noreply.github.com` | Author email for the commit. | +| `github-token` | no | `${{ github.token }}` | Token used for the `git push` and `gh` API call. The default `GITHUB_TOKEN` will NOT retrigger workflows on the bot's push, which is what you want inside loops like signing-on-push. Pass a PAT/App token for cross-repo PRs or to retrigger CI on the new branch. | ## Outputs -| Name | Description | -| ----------- | -------------------------------------------------------------------------------------------------------- | -| `changed` | `true` when there were uncommitted changes and a PR was opened or updated. | +| Name | Description | +| ----------- | --------------------------------------------------------------------------------------------------------- | +| `changed` | `true` when there were uncommitted changes and a PR was opened or updated. | | `created` | `true` when a brand-new PR was opened, `false` when an existing PR for `branch` was reused, or no change. | -| `pr-number` | PR number. Empty when `changed=false`. | -| `pr-url` | PR URL. Empty when `changed=false`. | +| `pr-number` | PR number. Empty when `changed=false`. | +| `pr-url` | PR URL. Empty when `changed=false`. | ## Caller responsibilities @@ -127,7 +127,7 @@ jobs: ## Example — regenerate manifest, fail if no drift detected -Useful when you *expect* the regeneration to produce changes (because +Useful when you _expect_ the regeneration to produce changes (because something else in the pipeline implies they should exist). ```yaml diff --git a/actions/open-pr/action.yml b/actions/open-pr/action.yml index 161f4ed..d7f8842 100644 --- a/actions/open-pr/action.yml +++ b/actions/open-pr/action.yml @@ -195,7 +195,7 @@ runs: BODY: ${{ inputs.body }} LABELS: ${{ inputs.labels }} DRAFT: ${{ inputs.draft }} - run: | + run: |- set -euo pipefail # Build label flags from newline-delimited input. diff --git a/actions/release-publish/README.md b/actions/release-publish/README.md index 8255643..e333c49 100644 --- a/actions/release-publish/README.md +++ b/actions/release-publish/README.md @@ -9,9 +9,9 @@ Release. Optional asset upload and preset notes blocks. ## Why a composite action (and not a reusable workflow)? -Reusable workflows run with the OIDC subject of *the workflow file's -repository*. That breaks `actions/attest-build-provenance` when the -attestation needs to verify against the *caller's* repo. Composite +Reusable workflows run with the OIDC subject of _the workflow file's +repository_. That breaks `actions/attest-build-provenance` when the +attestation needs to verify against the _caller's_ repo. Composite actions run inside the caller's job, inheriting its OIDC subject — which is what consumers expect when they run `gh attestation verify ... --repo /`. @@ -21,13 +21,13 @@ action to publish. ## Inputs -| Name | Required | Default | Description | -| -------------- | -------- | ------------------ | ---------------------------------------------------------------------------- | -| `mise-version` | yes | — | mise version to install. Used to provision `git-cliff`. | -| `tag` | yes | — | Git tag (e.g. `v1.2.0`). Usually `${{ github.ref_name }}`. | -| `assets` | no | `""` | Newline-delimited list of file paths to attach. No globbing — be explicit. | -| `extra-notes` | no | `""` | Preset key for an appended notes block. See [Presets](#presets). | -| `github-token` | no | `${{ github.token }}` | Token used by `gh release create`. | +| Name | Required | Default | Description | +| -------------- | -------- | --------------------- | -------------------------------------------------------------------------- | +| `mise-version` | yes | — | mise version to install. Used to provision `git-cliff`. | +| `tag` | yes | — | Git tag (e.g. `v1.2.0`). Usually `${{ github.ref_name }}`. | +| `assets` | no | `""` | Newline-delimited list of file paths to attach. No globbing — be explicit. | +| `extra-notes` | no | `""` | Preset key for an appended notes block. See [Presets](#presets). | +| `github-token` | no | `${{ github.token }}` | Token used by `gh release create`. | ## Presets @@ -41,12 +41,12 @@ in two or more repos. ## Caller responsibilities -- Check out the repo *before* calling this action (`actions/checkout` with +- Check out the repo _before_ calling this action (`actions/checkout` with `fetch-depth: 0` so `git-cliff` can see history). - Set job permissions yourself: at minimum `contents: write`. Add `id-token: write` and `attestations: write` if you also call `actions/attest-build-provenance` in the same job. -- Build any artifacts and call `attest-build-provenance` *before* this +- Build any artifacts and call `attest-build-provenance` _before_ this action so the attestation is bound to the caller's OIDC. ## Example — notes-only release diff --git a/actions/release-publish/action.yml b/actions/release-publish/action.yml index 2d6e527..6e5ddf6 100644 --- a/actions/release-publish/action.yml +++ b/actions/release-publish/action.yml @@ -100,7 +100,7 @@ runs: TAG: ${{ inputs.tag }} REPO: ${{ github.repository }} ASSETS: ${{ inputs.assets }} - run: | + run: |- set -euo pipefail # Convert newline-delimited assets into a bash array, stripping diff --git a/docs/architecture.md b/docs/architecture.md index 657be7f..cbfb13a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -77,14 +77,28 @@ jobs: # lint-config-dir: config-sync/files ``` +### Auto-fix formatting (`autofix.yml`) + +Runs dprint, yamlfmt, and shfmt in write mode, then commits and pushes any +formatting changes. + +| Input | Description | +| -------------------- | ------------------------------------------------------ | +| `mise-version` | **Required.** mise version to install. | +| `autofix-config-dir` | Optional formatter config directory. Default: `""`. | +| `autofix-dprint` | Markdown formatting (dprint). Default: `true`. | +| `autofix-yamlfmt` | YAML formatting (yamlfmt). Default: `true`. | +| `autofix-shfmt` | Shell formatting (shfmt). Default: `true`. | +| `commit-message` | Commit message. Default: `style: auto-fix formatting`. | + ### Release (`release.yml`) Creates a GitHub Release from a version tag using `git-cliff` for release notes. -| Input | Description | -| -------------- | --------------------------------------- | -| `mise-version` | **Required.** mise version to install. | +| Input | Description | +| -------------- | -------------------------------------- | +| `mise-version` | **Required.** mise version to install. | | `tag` | **Required.** Tag name, e.g. `v1.2.3`. | **Example caller:** @@ -222,21 +236,21 @@ Key properties: spam duplicate PRs. - Branch protection on the base branch stays fully enforced. -| Input | Required | Default | Description | -| ---------------- | -------- | ----------------------- | -------------------------------------------------------------------------- | -| `branch` | yes | — | Working branch to create or force-push to. | -| `title` | yes | — | PR title (also default commit message). Conventional Commit subject. | -| `base` | no | `main` | Branch to merge into. | -| `body` | no | `""` | PR body (Markdown). | -| `commit-message` | no | `title` | Override the commit message. | -| `paths` | no | `.` | Newline-delimited pathspecs to `git add`. | -| `labels` | no | `""` | Newline-delimited labels. | -| `draft` | no | `false` | Open as draft. | -| `signoff` | no | `false` | Add `Signed-off-by` trailer. | -| `if-no-changes` | no | `skip` | `skip` = exit 0; `fail` = error when nothing to commit. | -| `git-user-name` | no | `github-actions[bot]` | Commit author name. | -| `git-user-email` | no | github-actions[bot] noreply | Commit author email. | -| `github-token` | no | `${{ github.token }}` | Token for `git push` and `gh`. Override with PAT/App for cross-repo PRs. | +| Input | Required | Default | Description | +| ---------------- | -------- | --------------------------- | ------------------------------------------------------------------------ | +| `branch` | yes | — | Working branch to create or force-push to. | +| `title` | yes | — | PR title (also default commit message). Conventional Commit subject. | +| `base` | no | `main` | Branch to merge into. | +| `body` | no | `""` | PR body (Markdown). | +| `commit-message` | no | `title` | Override the commit message. | +| `paths` | no | `.` | Newline-delimited pathspecs to `git add`. | +| `labels` | no | `""` | Newline-delimited labels. | +| `draft` | no | `false` | Open as draft. | +| `signoff` | no | `false` | Add `Signed-off-by` trailer. | +| `if-no-changes` | no | `skip` | `skip` = exit 0; `fail` = error when nothing to commit. | +| `git-user-name` | no | `github-actions[bot]` | Commit author name. | +| `git-user-email` | no | github-actions[bot] noreply | Commit author email. | +| `github-token` | no | `${{ github.token }}` | Token for `git push` and `gh`. Override with PAT/App for cross-repo PRs. | Outputs: `changed`, `created`, `pr-number`, `pr-url`. @@ -307,15 +321,15 @@ the GitHub UI under **Actions → New workflow** for repositories in this organisation. Each template has a matching `.properties.json` file that provides the display name, description, and category shown in the picker. -| Template | Purpose | -| -------------------------------- | ------------------------------------- | -| `lint.yml` | Linting pipeline | -| `release.yml` | GitHub Release on tag push | -| `config-sync.yml` | Weekly config drift sync | -| `label-sync.yml` | Sync labels from `.github/labels.yaml`| -| `labeler.yml` | Auto-label PRs and issues | -| `todo-to-issue.yml` | Convert TODO comments to issues | -| `assign-issue-to-codeowners.yml` | Assign issues to CODEOWNERS | +| Template | Purpose | +| -------------------------------- | -------------------------------------- | +| `lint.yml` | Linting pipeline | +| `release.yml` | GitHub Release on tag push | +| `config-sync.yml` | Weekly config drift sync | +| `label-sync.yml` | Sync labels from `.github/labels.yaml` | +| `labeler.yml` | Auto-label PRs and issues | +| `todo-to-issue.yml` | Convert TODO comments to issues | +| `assign-issue-to-codeowners.yml` | Assign issues to CODEOWNERS | --- @@ -371,34 +385,34 @@ PRs **without** this label require manual review and merge. **What auto-merges (minor + patch, via GitHub platform automerge):** -| Ecosystem | Scope | Condition | -| --------- | ----- | --------- | -| GitHub Actions | `actions/*`, `docker/*`, `github/*` | All versions | -| Docker images | All | Current version ≥ 1.0 | -| GitHub releases | All | Current version ≥ 1.0 | -| Mise tools | All | Current version ≥ 1.0 | -| npm | All | Current version ≥ 1.0 | -| pip | All | Current version ≥ 1.0 | -| Go modules | All | Current version ≥ 1.0 | -| Lock file maintenance | All | Always (branch merge, no PR) | +| Ecosystem | Scope | Condition | +| --------------------- | ----------------------------------- | ---------------------------- | +| GitHub Actions | `actions/*`, `docker/*`, `github/*` | All versions | +| Docker images | All | Current version ≥ 1.0 | +| GitHub releases | All | Current version ≥ 1.0 | +| Mise tools | All | Current version ≥ 1.0 | +| npm | All | Current version ≥ 1.0 | +| pip | All | Current version ≥ 1.0 | +| Go modules | All | Current version ≥ 1.0 | +| Lock file maintenance | All | Always (branch merge, no PR) | **What does NOT auto-merge:** -- Major version updates (all ecosystems) -- Pre-1.0 packages (`0.x` — semver minor can introduce breaking changes) -- GitHub Actions from untrusted organisations -- Digest-only updates (disabled entirely for supply-chain safety) +- Major version updates (all ecosystems) +- Pre-1.0 packages (`0.x` — semver minor can introduce breaking changes) +- GitHub Actions from untrusted organisations +- Digest-only updates (disabled entirely for supply-chain safety) ### Safety nets -- **14-day `minimumReleaseAge`** on Docker images, GitHub releases, mise - tools, and all major updates — ensures community vetting before adoption. -- **CI must pass** — `platformAutomerge: true` uses GitHub's native - auto-merge, which respects required status checks. -- **OSV vulnerability alerts** bypass `minimumReleaseAge` (set to `0`) so - security fixes merge immediately. -- **Schedule** — Renovate only runs on weekends and Fridays. -- **Digest updates disabled** — prevents merging potentially hijacked tags. +- **14-day `minimumReleaseAge`** on Docker images, GitHub releases, mise + tools, and all major updates — ensures community vetting before adoption. +- **CI must pass** — `platformAutomerge: true` uses GitHub's native + auto-merge, which respects required status checks. +- **OSV vulnerability alerts** bypass `minimumReleaseAge` (set to `0`) so + security fixes merge immediately. +- **Schedule** — Renovate only runs on weekends and Fridays. +- **Digest updates disabled** — prevents merging potentially hijacked tags. ### Consuming the preset @@ -429,6 +443,6 @@ Repositories import the shared fragments in their `renovate.json5`: Architecture Decision Records are stored in [`docs/design-decisions/`](design-decisions/README.md). -| ADR | Title | Status | -| ----------------------------------------------------------------------- | ---------------------------------------------------- | -------- | -| [0001](design-decisions/0001-reusable-workflow-version-inputs.md) | Reusable workflows must not default package versions | Accepted | +| ADR | Title | Status | +| ----------------------------------------------------------------- | ---------------------------------------------------- | -------- | +| [0001](design-decisions/0001-reusable-workflow-version-inputs.md) | Reusable workflows must not default package versions | Accepted | diff --git a/docs/design-decisions/0001-reusable-workflow-version-inputs.md b/docs/design-decisions/0001-reusable-workflow-version-inputs.md index c6f298a..6d0c565 100644 --- a/docs/design-decisions/0001-reusable-workflow-version-inputs.md +++ b/docs/design-decisions/0001-reusable-workflow-version-inputs.md @@ -14,7 +14,7 @@ caller runs. If the reusable workflow hard-codes a tool version (or provides a default that most callers omit), bumping that version in this repository effectively ships -a new version to every consumer the next time their workflow runs — *without* +a new version to every consumer the next time their workflow runs — _without_ that consumer's CI ever having validated the new version against their code. The caller carries the operational risk of an upgrade that was never tested against their repository. @@ -89,15 +89,15 @@ It does **not** apply to: - Declare every version input as `required: true` with a clear description: - ```yaml - on: - workflow_call: - inputs: - mise-version: - description: "mise version to install" - required: true - type: string - ``` + ```yaml + on: + workflow_call: + inputs: + mise-version: + description: "mise version to install" + required: true + type: string + ``` - Pass the input through to the installing action via `${{ inputs. }}`. Never hard-code a version number elsewhere in the workflow. @@ -109,14 +109,14 @@ It does **not** apply to: - Set the version explicitly in `with:` and annotate with `# renovate:` so the value is maintained automatically: - ```yaml - jobs: - lint: - uses: DevSecNinja/.github/.github/workflows/lint.yml@ # main - with: - # renovate: datasource=github-releases depName=jdx/mise - mise-version: "2026.4.3" - ``` + ```yaml + jobs: + lint: + uses: DevSecNinja/.github/.github/workflows/lint.yml@ # main + with: + # renovate: datasource=github-releases depName=jdx/mise + mise-version: "2026.4.3" + ``` - Treat the value as production configuration — review it in PRs, keep it in lockstep with `.mise.toml` when applicable, and merge Renovate PRs diff --git a/docs/design-decisions/README.md b/docs/design-decisions/README.md index 71b6187..a313a89 100644 --- a/docs/design-decisions/README.md +++ b/docs/design-decisions/README.md @@ -11,7 +11,7 @@ that supersedes the old one. ## Index -| ADR | Title | Status | -| ------------------------------------------------------------------- | ------------------------------------------------------ | -------- | -| [0001](0001-reusable-workflow-version-inputs.md) | Reusable workflows must not default package versions | Accepted | -| [0002](0002-runtime-ci-hardening.md) | Use Harden-Runner for runtime CI hardening | Accepted | +| ADR | Title | Status | +| ------------------------------------------------ | ---------------------------------------------------- | -------- | +| [0001](0001-reusable-workflow-version-inputs.md) | Reusable workflows must not default package versions | Accepted | +| [0002](0002-runtime-ci-hardening.md) | Use Harden-Runner for runtime CI hardening | Accepted | diff --git a/dprint.json b/dprint.json deleted file mode 100644 index 1538838..0000000 --- a/dprint.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://dprint.dev/schemas/v0.json", - "includes": ["**/*.md"], - "excludes": ["**/node_modules"], - "plugins": [ - "https://plugins.dprint.dev/markdown-0.21.1.wasm" - ] -} diff --git a/workflow-templates/autofix.properties.json b/workflow-templates/autofix.properties.json index 03396b1..13dc382 100644 --- a/workflow-templates/autofix.properties.json +++ b/workflow-templates/autofix.properties.json @@ -1,6 +1,6 @@ { "name": "Auto-fix formatting", - "description": "Manually triggered workflow that auto-fixes formatting issues using dprint fmt, yamlfmt, and shfmt --write, then commits and pushes the changes.", + "description": "Manually triggered workflow that auto-fixes formatting issues using dprint fmt, yamlfmt, and shfmt --write, then commits and pushes the changes. Supports formatter configs from an optional config directory.", "categories": ["Continuous integration"], "filePatterns": ["\\.ya?ml$", "\\.sh$", "\\.md$"] } diff --git a/workflow-templates/autofix.yml b/workflow-templates/autofix.yml index f57a55a..387f32b 100644 --- a/workflow-templates/autofix.yml +++ b/workflow-templates/autofix.yml @@ -15,6 +15,8 @@ jobs: with: # renovate: datasource=github-releases depName=jdx/mise mise-version: "2026.4.9" + # Optional: use formatter configs from a non-root directory. + # autofix-config-dir: config-sync/files # Toggle formatters on/off (all default to true): # autofix-dprint: true # autofix-yamlfmt: true diff --git a/workflow-templates/config-sync.yml b/workflow-templates/config-sync.yml index 03e90c1..d466229 100644 --- a/workflow-templates/config-sync.yml +++ b/workflow-templates/config-sync.yml @@ -16,6 +16,6 @@ jobs: permissions: contents: write pull-requests: write - # Uncomment to also bootstrap template files for new repos: - # with: - # sync-templates: true + # Uncomment to also bootstrap template files for new repos: + # with: + # sync-templates: true diff --git a/workflow-templates/labeler.yml b/workflow-templates/labeler.yml index d11cc08..59fd595 100644 --- a/workflow-templates/labeler.yml +++ b/workflow-templates/labeler.yml @@ -7,7 +7,9 @@ on: branches: - $default-branch issues: - types: [opened, edited] + types: + - opened + - edited permissions: contents: read