Compare commits

..

40 Commits

Author SHA1 Message Date
renovate[bot]
0fba4a9657 chore(actions): update anchore/sbom-action action (v0.20.0 → v0.23.0)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-09 00:47:12 +00:00
4360ea39c7 fix(ci): use the latest openssf scorecard action (#503)
* fix(ci): use the latest openssf scorecard action

* fix(ci): replace scorecard workflow with upstream reference

Replace our custom scorecard workflow with the official ossf/scorecard
workflow template for better alignment with upstream recommendations.
2026-03-09 02:46:23 +02:00
renovate[bot]
cfff9253d8 chore(actions): update aquasecurity/trivy-action action (0.34.2 → 0.35.0) (#504)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-09 02:35:58 +02:00
renovate[bot]
77394763a6 chore(deps)!: update actions/attest-build-provenance action (v2.3.0 → v4.1.0) (#500)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-09 00:23:30 +00:00
renovate[bot]
ca8482e2c3 chore(deps)!: update actions/upload-artifact action (v4.6.2 → v7.0.0) (#470)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-09 02:20:41 +02:00
a0cc32995f feat(security): add OpenSSF Scorecard workflow and maximize score (#498)
* feat(security): add OpenSSF Scorecard workflow and maximize score

- Add scorecard.yml workflow (weekly + push to main) with SARIF upload
- Add CONTRIBUTING.md for contributor guidelines
- Add SLSA provenance attestation job to release workflow
- Add CycloneDX SBOM generation job to release workflow
- Pin Dockerfile base images to sha256 digests
- Enable Renovate pinDigests and platformAutomerge
- Add OpenSSF Scorecard badge to README

* fix(docs): address PR #498 review comments and remove .coderabbit.yaml

- Delete .coderabbit.yaml (falls back to shared org-level config)
- Add missing linter deps to CONTRIBUTING.md install step
- Separate make all and make test into distinct steps
- Fix line length note to match EditorConfig (200 chars, no MD override)
- Add yamllint/markdownlint to YAML/JSON/Markdown linter list
- Refine action references guidance
- Expand "Adding a New Action" section with action-docs and catalog info
2026-03-09 01:59:07 +02:00
34372bcd36 feat(pr-lint): consolidate dependency review into pr-lint action (#497)
* feat(pr-lint): consolidate dependency review into pr-lint action

Move dependency review from standalone workflow into the pr-lint
composite action. Adds repository visibility check via GitHub API
and runs dependency-review-action only on public repos during
pull_request events, before MegaLinter.

* fix(pr-lint): harden dependency review visibility check

Address PR review feedback from Copilot and CodeRabbit:
- Skip visibility check on non-PR events (if: pull_request)
- Add continue-on-error so API failures don't block MegaLinter
- Use curl --fail --show-error to surface HTTP errors in logs
- Use github.token directly instead of inputs.token fallback
- Add Accept header for GitHub API versioning
- Validate jq output type to fail closed on bad API responses

* fix(pr-lint): use event payload for visibility, unblock MegaLinter on dep review

Replace curl API call with local jq read from $GITHUB_EVENT_PATH for
the repository visibility check — simpler, faster, no auth needed.

Add continue-on-error to dependency review so MegaLinter always runs,
with a re-fail step after artifacts upload to preserve the failure signal.
2026-03-08 21:44:45 +02:00
f995f89a21 chore(claude): add hooks, skills, and agents for Claude Code (#496)
* chore(claude): add hooks, skills, and agents for Claude Code

Add auto-formatting hooks (ruff, shfmt, prettier, actionlint),
rules.yml edit blocker, 5 skills (/release, /test-action,
/new-action, /validate, /check-pins), and 2 subagents
(action-validator, test-coverage-reviewer). Update CLAUDE.md
with hook documentation.

* fix(claude): add tool availability guards and fix skill docs

Add jq availability checks to hook scripts (block-rules-yml.sh,
post-edit-write.sh) and wrap actionlint call in command -v guard,
consistent with project rules #2 and #10. Fix validate skill to
reflect actual make all pipeline order and note that make test
runs separately.

* fix(claude): correct skill docs per PR review feedback

Fix validate skill description to say "precommit" instead of "test",
and fix check-pins SHA guidance to use origin/main instead of HEAD.

* feat(tools): add SHA-pinning enforcement to check-version-refs

The check-version-refs script previously only displayed existing
SHA-pinned refs but silently skipped non-SHA references. Add a
validation pass that detects and reports any ivuorinen/actions/*
references not using a 40-char hex SHA, exiting 1 on violations.

* fix(tools): fix temp file leak in check-version-refs.sh

Write find output directly to $violations_file instead of
$violations_file.all so the EXIT trap covers cleanup on all
exit paths, not just the happy path.
2026-03-08 04:22:02 +02:00
renovate[bot]
242ecca8f0 chore(deps): update pre-commit hook astral-sh/ruff-pre-commit (v0.15.4 → v0.15.5) (#495)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-07 17:07:03 +02:00
renovate[bot]
97105fc2a9 chore(deps): lock file maintenance (#494)
* chore(deps): update actions/setup-node action (v6.2.0 → v6.3.0)

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): lock file maintenance

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

---------

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 11:17:12 +02:00
renovate[bot]
e9deac2a01 chore(deps)!: update docker/metadata-action (v5.10.0 → v6.0.0) (#493)
* chore(deps): update actions/setup-node action (v6.2.0 → v6.3.0)

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps)!: update docker/metadata-action (v5.10.0 → v6.0.0)

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

---------

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 11:16:38 +02:00
renovate[bot]
480c06b83b chore(deps): update actions/setup-node action (v6.2.0 → v6.3.0) (#491)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 11:16:07 +02:00
renovate[bot]
07ce8df887 chore(deps)!: update docker/build-push-action (v6.19.2 → v7.0.0) (#492)
* chore(deps): update actions/setup-node action (v6.2.0 → v6.3.0)

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps)!: update docker/build-push-action (v6.19.2 → v7.0.0)

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

---------

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 11:15:36 +02:00
renovate[bot]
0f29424163 chore(deps): update actions/setup-dotnet action (v5.1.0 → v5.2.0) (#490)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 11:15:00 +02:00
renovate[bot]
ce81e51641 chore(deps): update raven-actions/actionlint action (v2.1.1 → v2.1.2) (#488)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 11:14:39 +02:00
renovate[bot]
261323db29 chore(deps): update actions/dependency-review-action action (v4.8.3 → v4.9.0) (#489)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 11:14:15 +02:00
renovate[bot]
c679f0c863 chore(deps): update pre-commit hook astral-sh/uv-pre-commit (0.10.7 → 0.10.8) (#486)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 02:51:06 +02:00
renovate[bot]
128b2f1713 chore(deps): update oven-sh/setup-bun action (v2.1.2 → v2.1.3) (#485)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 02:50:33 +02:00
renovate[bot]
08393e8063 chore(deps): update github/codeql-action action (v4.32.4 → v4.32.6) (#484)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 02:49:32 +02:00
renovate[bot]
ed9f205433 chore(deps): update aquasecurity/trivy-action action (0.34.1 → 0.34.2) (#483)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 02:49:00 +02:00
Copilot
ae4ad9ec80 fix: harden workflow permissions with deny-all top-level and least-privilege job scopes (#482) 2026-03-06 02:44:56 +02:00
renovate[bot]
455267f892 chore(deps): update pre-commit hook bridgecrewio/checkov (3.2.506 → 3.2.507) (#487)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-06 02:41:33 +02:00
renovate[bot]
d1af04260d chore(deps)!: update docker/login-action (v3.7.0 → v4.0.0) (#477) 2026-03-05 22:41:05 +02:00
renovate[bot]
0921e373ce chore(deps)!: update docker/setup-buildx-action (v3.12.0 → v4.0.0) (#478) 2026-03-05 22:26:51 +02:00
renovate[bot]
6bbe5089d2 chore(deps)!: update docker/setup-qemu-action (v3.7.0 → v4.0.0) (#479) 2026-03-05 22:15:39 +02:00
renovate[bot]
7cf51e5364 chore(deps): lock file maintenance (#481) 2026-03-05 22:14:11 +02:00
renovate[bot]
72c6155089 chore(deps)!: update github/issue-metrics (v3.25.5 → v4.1.0) (#480) 2026-03-05 22:07:00 +02:00
renovate[bot]
6e8f2aae9d chore(deps): update pre-commit hook astral-sh/uv-pre-commit (0.10.5 → 0.10.7) (#475)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-02 17:22:01 +02:00
renovate[bot]
f15daec6dc chore(deps): update pre-commit hook astral-sh/ruff-pre-commit (v0.15.2 → v0.15.4) (#474)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-02 17:21:37 +02:00
renovate[bot]
66870c6d0c chore(deps): update oxsecurity/megalinter action (v9.3.0 → v9.4.0) (#476)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-02 17:20:54 +02:00
renovate[bot]
03eeb4c39f chore(deps): update astral-sh/setup-uv action (v7.3.0 → v7.3.1) (#473)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-02 03:04:57 +02:00
renovate[bot]
992b64a580 chore(deps)!: update hashicorp/setup-terraform (v3.1.2 → v4.0.0) (#471)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-02 02:35:56 +02:00
renovate[bot]
f114b11df1 chore(deps): lock file maintenance (#472)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-02 02:35:20 +02:00
bd59245cd7 fix(deps): replace step-security/retry and update action pins (#468)
* fix(deps): replace step-security/retry with nick-fields/retry

* chore(deps): update github action sha pins via pinact

* refactor: remove common-retry references from tests and validators

* chore: simplify description fallback and update action count

* docs: remove hardcoded test counts from memory and docs

Replace exact "769 tests" references with qualitative language
so these files don't go stale as test count grows.
2026-03-02 02:31:26 +02:00
dependabot[bot]
d919327c7e chore(deps): bump minimatch (#466) 2026-02-28 16:20:54 +02:00
renovate[bot]
8faacf8a1c chore(deps): update actions/dependency-review-action action (v4.8.2 → v4.8.3) (#461)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-24 20:09:57 +02:00
renovate[bot]
bbca76975e chore(deps): update pre-commit hook astral-sh/ruff-pre-commit (v0.15.1 → v0.15.2) (#462)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-24 20:06:53 +02:00
renovate[bot]
b75d237069 chore(deps): update pre-commit hook bridgecrewio/checkov (3.2.502 → 3.2.506) (#464)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-24 20:06:32 +02:00
renovate[bot]
7973e4945b chore(deps): update markdownlint-cli2 (0.20.0 → 0.21.0) (#465)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-24 20:06:10 +02:00
renovate[bot]
2ce9325ff9 chore(deps): update pre-commit hook astral-sh/uv-pre-commit (0.10.3 → 0.10.5) (#463)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-24 20:05:35 +02:00
66 changed files with 989 additions and 412 deletions

View File

@@ -0,0 +1,30 @@
You review action.yml files against the repository's critical prevention rules.
Check each action.yml file for these violations:
1. All external action refs are SHA-pinned (not @main/@v1)
2. All internal action refs use `ivuorinen/actions/name@SHA` format
3. Shell scripts use `set -eu` (POSIX, not bash)
4. Steps with referenced outputs have `id:` fields
5. Tool availability checked before use (`command -v`)
6. Variables properly quoted (`"$var"`)
7. `$GITHUB_OUTPUT` uses `printf`, not `echo`
8. No nested `${{ }}` in quoted YAML strings
9. Token inputs use `${{ github.token }}` default
10. Fallbacks provided for tools not on all runners
Run `actionlint` on each file. Report violations with file path, line, and fix suggestion.
To find all action.yml files:
```bash
find . -name "action.yml" -not -path "./.git/*"
```
For each file, read it and check against all 10 rules. Then run:
```bash
actionlint <file>
```
Output a summary table of violations found, grouped by action.

View File

@@ -0,0 +1,33 @@
You review test coverage for GitHub Actions in this monorepo.
For each action:
1. Read the action.yml to understand inputs, outputs, and steps
2. Read the corresponding test files in `_tests/unit/<action-name>/`
3. Check if all inputs have validation tests
4. Check if error paths are tested (missing required inputs, invalid values)
5. Check if shell scripts have edge case tests (spaces in paths, empty strings, special chars)
6. Report coverage gaps with specific test suggestions
To find all actions and their tests:
```bash
ls -d */action.yml | sed 's|/action.yml||'
ls -d _tests/unit/*/
```
Compare the two lists to find actions without any tests.
For each action with tests, check coverage of:
- All required inputs validated
- All optional inputs with defaults tested
- Error conditions (missing inputs, invalid formats)
- Edge cases in shell logic (empty strings, special characters, spaces in paths)
- Output values verified
Output a coverage report with:
- Actions with no tests (critical)
- Actions with partial coverage (list missing test cases)
- Actions with good coverage (brief confirmation)

View File

@@ -0,0 +1,21 @@
#!/bin/sh
set -eu
# Read JSON input from stdin to get the file path
if ! command -v jq >/dev/null 2>&1; then
echo "Error: jq is required but not found" >&2
exit 1
fi
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.filePath // empty')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
case "$FILE_PATH" in
*/rules.yml)
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"rules.yml files are auto-generated. Run make update-validators instead."}}'
;;
esac

View File

@@ -0,0 +1,46 @@
#!/bin/sh
set -eu
# Read JSON input from stdin to get the file path
if ! command -v jq >/dev/null 2>&1; then
echo "Error: jq is required but not found" >&2
exit 1
fi
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.filePath // empty')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
case "$FILE_PATH" in
*/rules.yml)
# rules.yml should not be reached here (blocked by PreToolUse),
# but skip formatting just in case
exit 0
;;
*.py)
ruff format --quiet "$FILE_PATH" 2>/dev/null || true
ruff check --fix --quiet "$FILE_PATH" 2>/dev/null || true
;;
*.sh)
shfmt -w "$FILE_PATH" 2>/dev/null || true
shellcheck "$FILE_PATH" 2>&1 || true
;;
*.yml | *.yaml | *.json)
npx prettier --write "$FILE_PATH" 2>/dev/null || true
;;
*.md)
npx prettier --write "$FILE_PATH" 2>/dev/null || true
;;
esac
# Run actionlint on action.yml files
case "$FILE_PATH" in
*/action.yml)
if command -v actionlint >/dev/null 2>&1; then
actionlint "$FILE_PATH" 2>&1 || true
fi
;;
esac

26
.claude/settings.json Normal file
View File

@@ -0,0 +1,26 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-rules-yml.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/post-edit-write.sh"
}
]
}
]
}
}

View File

@@ -0,0 +1,40 @@
---
name: check-pins
description: Verify all action references are properly SHA-pinned
disable-model-invocation: true
---
# Check SHA-Pinned Action References
## 1. Check version references
```bash
make check-version-refs
```
This verifies that all `ivuorinen/actions/*` references in `action.yml` files use SHA-pinned commits.
## 2. Check local references
```bash
make check-local-refs
```
This verifies that test workflows use `./action-name` format (local references are allowed in tests).
## 3. Interpret results
**Violations to fix:**
- `@main` or `@v*` references in `action.yml` files must be replaced with full SHA commits
- `./action-name` in `action.yml` (non-test) files must use `ivuorinen/actions/action-name@<SHA>`
- External actions must be pinned to SHA commits, not version tags
**How to get the SHA for pinning:**
```bash
# After pushing, get the SHA of the latest commit on the remote
git rev-parse origin/main
```
Use a SHA that exists on the remote. Local-only commits won't resolve when the action is used externally.

View File

@@ -0,0 +1,60 @@
---
name: new-action
description: Scaffold a new GitHub Action with all required files
disable-model-invocation: true
---
# Scaffold a New GitHub Action
## 1. Gather information
Ask the user for:
- **Action name** (kebab-case, e.g. `my-new-action`)
- **Description** (one line)
- **Category** (setup, linting, testing, build, publishing, repository, utility)
- **Inputs** (name, description, required, default for each)
- **What it does** (shell commands, composite steps, etc.)
## 2. Create directory and action.yml
Create `<action-name>/action.yml` following the existing action patterns:
- Use `composite` runs type
- Include `set -eu` in shell scripts (POSIX sh, not bash)
- Use `${{ github.token }}` for token defaults
- Pin all external action references to SHA commits
- Pin internal action references using `ivuorinen/actions/action-name@<SHA>`
- Add `id:` to steps whose outputs are referenced
## 3. Generate validation rules
```bash
make update-validators
```
This generates `<action-name>/rules.yml` from the action's inputs.
## 4. Generate test scaffolding
```bash
make generate-tests
```
## 5. Generate README
```bash
make docs
```
## 6. Run validation
```bash
make all
```
Fix any issues before considering the action complete.
## 7. Update repository overview
Remind the user to update the Serena memory `repository_overview` if they use Serena.

View File

@@ -0,0 +1,57 @@
---
name: release
description: Create a new CalVer release with validation checks
disable-model-invocation: true
---
# Release Workflow
Follow these steps to create a new CalVer release:
## 1. Pre-flight checks
Run the full validation pipeline:
```bash
make all
```
If any step fails, fix the issues before proceeding.
## 2. Check version references
Verify all action references are properly pinned:
```bash
make check-version-refs
make check-local-refs
```
## 3. Prepare the release
Run release preparation (updates version references):
```bash
make release-prep
```
Review the changes with `git diff`.
## 4. Confirm with user
Ask the user to confirm:
- The version number (defaults to `vYYYY.MM.DD` based on today's date)
- That all changes look correct
## 5. Create the release
```bash
make release VERSION=vYYYY.MM.DD
```
Replace `vYYYY.MM.DD` with the confirmed version.
## 6. Verify
Show the user the created tag and any output from the release process.

View File

@@ -0,0 +1,34 @@
---
name: test-action
description: Run tests for a specific GitHub Action by name
disable-model-invocation: true
---
# Test a Specific Action
## 1. Identify the action
Ask the user which action to test if not already specified.
List available actions if needed:
```bash
ls -d */action.yml | sed 's|/action.yml||'
```
## 2. Run tests
```bash
make test-action ACTION=<action-name>
```
## 3. Display results
Show the test output. If tests fail, read the relevant test files in `_tests/unit/<action-name>/` and the action's `action.yml` to help diagnose the issue.
## 4. Coverage (optional)
If the user wants coverage information:
```bash
make test-coverage
```

View File

@@ -0,0 +1,51 @@
---
name: validate
description: Run full validation pipeline (docs, format, lint, precommit)
disable-model-invocation: true
---
# Full Validation Pipeline
Run the complete validation pipeline:
```bash
make all
```
This runs in order: `install-tools` -> `update-validators` -> `docs` -> `update-catalog` -> `format` -> `lint` -> `precommit`
**Note:** `make test` must be run separately.
## If validation fails
### Formatting issues
```bash
make format
```
Then re-run `make all`.
### Linting issues
- **actionlint**: Check action.yml syntax, step IDs, expression usage
- **shellcheck**: POSIX compliance, quoting, variable usage
- **ruff**: Python style and errors
- **markdownlint**: Markdown formatting
- **prettier**: YAML/JSON/MD formatting
### Test failures
```bash
make test
```
Read the failing test output and fix the underlying action or test.
### Documentation drift
```bash
make docs
```
Regenerates READMEs from action.yml files.

View File

@@ -1,18 +0,0 @@
---
# yaml-language-server: $schema=https://www.coderabbit.ai/integrations/schema.v2.json
remote_config:
url: 'https://raw.githubusercontent.com/ivuorinen/coderabbit/1985ff756ef62faf7baad0c884719339ffb652bd/coderabbit.yaml'
path_instructions:
- path: '.serena/**/*'
instructions: >-
- These are files for Serena LLM. Do not review them.
- path: '**/*/README.md'
instructions: >-
- README.md files next to action.yml files are autogenerated
and should not be reviewed.
- README.md file in the root of the repository should be reviewed.
- README.md files for actions use `@main` version for the action as an illustration.
Do not review them.
- path: '**/*.md'
instructions: >-
- The repository uses CalVer for versioning. Do not review version numbers in the documentation.

View File

@@ -17,7 +17,7 @@ runs:
using: composite
steps:
- name: Install uv
uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
with:
enable-cache: true
@@ -31,7 +31,7 @@ runs:
run: uv sync --frozen
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '24'
cache: npm

View File

@@ -4,6 +4,8 @@
"github>ivuorinen/renovate-config",
"customManagers:biomeVersions"
],
"pinDigests": true,
"platformAutomerge": true,
"packageRules": [
{
"matchUpdateTypes": [

View File

@@ -17,10 +17,7 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
actions: read
pull-requests: read
permissions: {}
jobs:
analyze:
@@ -29,6 +26,9 @@ jobs:
timeout-minutes: 30
permissions:
contents: read
actions: read
pull-requests: read
security-events: write
statuses: write
issues: write

View File

@@ -23,25 +23,26 @@ on:
default: 'latest'
type: string
permissions:
contents: read
packages: write
permissions: {}
jobs:
build-and-push:
name: Build and Push Testing Image
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Log in to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -49,7 +50,7 @@ jobs:
- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
images: ghcr.io/${{ github.repository_owner }}/actions
tags: |
@@ -59,7 +60,7 @@ jobs:
type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event.inputs.tag != '' }}
- name: Build and push Docker image
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: _tools/docker-testing-tools
file: _tools/docker-testing-tools/Dockerfile

View File

@@ -13,17 +13,16 @@ on:
- cron: '30 1 * * 0' # Run at 1:30 AM UTC every Sunday
merge_group:
permissions:
actions: read
contents: read
permissions: {}
jobs:
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest
permissions:
security-events: write
actions: read
contents: read
security-events: write
strategy:
fail-fast: false

View File

@@ -1,17 +0,0 @@
---
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: 'Dependency Review'
on:
- pull_request
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta
- name: 'Dependency Review'
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2

View File

@@ -5,8 +5,7 @@ on:
schedule:
- cron: '3 2 1 * *'
permissions:
contents: read
permissions: {}
jobs:
build:
@@ -30,7 +29,7 @@ jobs:
echo "last_month=$first_day..$last_day" >> "$GITHUB_ENV"
- name: Run issue-metrics tool
uses: github/issue-metrics@67526e7bd8100b870f10b1c120780a8375777b43 # v3.25.5
uses: github/issue-metrics@41a7961f701cc64490f32e143af8ef479b93e87d # v4.1.0
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SEARCH_QUERY: 'repo:ivuorinen/actions is:issue created:${{ env.last_month }} -reason:"not planned"'

View File

@@ -6,7 +6,7 @@ on:
schedule:
- cron: '0 21 * * *' # 00:00 at Europe/Helsinki
permissions: read-all
permissions: {}
jobs:
new-daily-release:

View File

@@ -37,9 +37,7 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
packages: read # Required for private dependencies
permissions: {}
jobs:
megalinter:
@@ -74,7 +72,7 @@ jobs:
- name: Upload SARIF Report
if: always() && hashFiles('megalinter-reports/sarif/*.sarif')
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: megalinter-reports/sarif
category: megalinter

View File

@@ -7,8 +7,7 @@ on:
tags:
- 'v*'
permissions:
contents: read
permissions: {}
jobs:
release:
@@ -20,3 +19,49 @@ jobs:
- uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
generate_release_notes: true
provenance:
needs: release
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
attestations: write
steps:
- uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta
- name: Create source archive
env:
TAG: ${{ github.ref_name }}
run: |
set -eu
git archive --format=tar.gz --prefix="${TAG}/" HEAD > "${TAG}-source.tar.gz"
sha256sum "${TAG}-source.tar.gz" > "${TAG}-source.tar.gz.sha256"
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: '${{ github.ref_name }}-source.tar.gz'
- name: Upload release assets
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
set -eu
gh release upload "$TAG" "${TAG}-source.tar.gz" "${TAG}-source.tar.gz.sha256" --clobber
sbom:
needs: release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@71cf2267d89c5cb81562390fa70a37fa40b1305e # v6-beta
- uses: anchore/sbom-action@17ae1740179002c89186b61233e0f892c3118b11 # v0.23.0
with:
format: cyclonedx-json
output-file: sbom.cdx.json
- name: Upload SBOM to release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
set -eu
gh release upload "$TAG" sbom.cdx.json --clobber

58
.github/workflows/scorecard.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
---
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
name: Scorecard analysis workflow
on:
push:
# Only the default branch is supported.
branches:
- main
schedule:
# Weekly on Saturdays.
- cron: '30 1 * * 6'
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed for Code scanning upload
security-events: write
# Needed for GitHub OIDC token if publish_results is true
id-token: write
steps:
- name: 'Checkout code'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: 'Run analysis'
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
# Scorecard team runs a weekly scan of public GitHub repos,
# see https://github.com/ossf/scorecard#public-data.
# Setting `publish_results: true` helps us scale by leveraging your workflow to
# extract the results instead of relying on our own infrastructure to run scans.
# And it's free for you!
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable
# uploads of run results in SARIF format to the repository Actions tab.
# https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts
- name: 'Upload artifact'
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: 'Upload to code-scanning'
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: results.sarif

View File

@@ -18,11 +18,7 @@ on:
- '**/*.yaml'
- '.github/workflows/**'
permissions:
contents: read
pull-requests: write
issues: write
actions: read
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
@@ -32,6 +28,11 @@ jobs:
security-analysis:
name: Security Analysis
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
actions: read
steps:
- name: Checkout PR

View File

@@ -8,10 +8,7 @@ on:
workflow_call:
workflow_dispatch:
permissions:
contents: read
packages: read
statuses: read
permissions: {}
jobs:
stale:

View File

@@ -22,7 +22,7 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: read-all
permissions: {}
jobs:
labels:
@@ -31,6 +31,7 @@ jobs:
timeout-minutes: 10
permissions:
contents: read
issues: write
steps:

View File

@@ -73,14 +73,14 @@ jobs:
if: always()
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
if: always() && hashFiles('_tests/reports/test-results.sarif') != ''
with:
sarif_file: _tests/reports/test-results.sarif
category: github-actions-tests
- name: Upload unit test results
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: always()
with:
name: unit-test-results
@@ -133,7 +133,7 @@ jobs:
fi
- name: Upload integration test results
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: always() && steps.check-integration-reports.outputs.reports-found == 'true'
with:
name: integration-test-results
@@ -167,7 +167,7 @@ jobs:
run: make test-coverage
- name: Upload coverage report
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: coverage-report
path: _tests/coverage/
@@ -263,7 +263,7 @@ jobs:
steps:
- name: Download test results
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
pattern: '*-test-results'
merge-multiple: true

View File

@@ -12,15 +12,16 @@ on:
required: false
type: string
permissions:
contents: write
pull-requests: write
issues: write
permissions: {}
jobs:
check-and-update:
name: Check Version References
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
steps:
- name: Checkout Repository

View File

@@ -14,7 +14,7 @@ repos:
types: [markdown, python, yaml]
files: ^(docs/.*|README\.md|CONTRIBUTING\.md|CHANGELOG\.md|.*\.py|.*\.ya?ml)$
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.10.3
rev: 0.10.8
hooks:
- id: uv-lock
- id: uv-sync
@@ -55,7 +55,7 @@ repos:
- id: yamllint
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.1
rev: v0.15.5
hooks:
# Run the linter with auto-fix
- id: ruff-check
@@ -84,7 +84,7 @@ repos:
args: ['-shellcheck=']
- repo: https://github.com/bridgecrewio/checkov.git
rev: '3.2.502'
rev: '3.2.507'
hooks:
- id: checkov
args:

View File

@@ -5,28 +5,28 @@
- **Path**: /Users/ivuorinen/Code/ivuorinen/actions
- **Branch**: main
- **External Usage**: `ivuorinen/actions/<action-name>@main`
- **Total Actions**: 44 self-contained actions
- **Total Actions**: 43 self-contained actions
- **Dogfooding**: Workflows use local actions (pr-lint, codeql-analysis, security-scan)
## Structure
```text
/
├── <action-dirs>/ # 44 self-contained actions
├── <action-dirs>/ # 43 self-contained actions
│ ├── action.yml # Action definition
│ ├── README.md # Auto-generated
│ └── CustomValidator.py # Optional validator
├── validate-inputs/ # Centralized validation
│ ├── validators/ # 9 specialized modules
│ ├── scripts/ # Rule/test generators
│ └── tests/ # 769 pytest tests
│ └── tests/ # pytest tests
├── _tests/ # ShellSpec framework
├── _tools/ # Development utilities
├── .github/workflows/ # CI/CD workflows
└── Makefile # Build automation
```
## Action Categories (44 total)
## Action Categories (43 total)
**Setup (7)**: node-setup, set-git-config, php-version-detect, python-version-detect, python-version-detect-v2, go-version-detect, dotnet-version-detect
@@ -40,7 +40,7 @@
**Testing (3)**: php-tests, php-laravel-phpunit, php-composer
**Repository (9)**: github-release, release-monthly, sync-labels, stale, compress-images, common-cache, common-file-check, common-retry, codeql-analysis
**Repository (8)**: github-release, release-monthly, sync-labels, stale, compress-images, common-cache, common-file-check, codeql-analysis
**Utilities (3)**: version-file-parser, version-validator, validate-inputs
@@ -77,12 +77,12 @@ make test # All tests (pytest + ShellSpec)
## Testing Framework
- **ShellSpec**: GitHub Actions and shell scripts
- **pytest**: Python validators (769 tests, 100% pass rate)
- **pytest**: Python validators (100% pass rate)
- **Test Generator**: Automatic scaffolding for new actions
## Current Status
- ✅ All tests passing (769/769)
- ✅ All tests passing
- ✅ Zero linting issues
- ✅ Modular validator architecture
- ✅ Convention-based validation

View File

@@ -2,7 +2,7 @@
## Status: PRODUCTION READY ✅
- 769 tests passing (100%)
- All tests passing (100%)
- Zero linting issues
- Modular architecture complete
@@ -60,7 +60,7 @@ validate-inputs/
├── scripts/
│ ├── update-validators.py # Rule generator
│ └── generate-tests.py # Test generator
└── tests/ # 769 pytest tests
└── tests/ # pytest tests
<action>/CustomValidator.py # Action-specific validators
```

View File

@@ -60,10 +60,75 @@ excluded_tools: []
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ''
# the name by which the project can be referenced within Serena
project_name: 'actions'
# list of languages for which language servers are started; choose from:
# al bash clojure cpp csharp
# csharp_omnisharp dart elixir elm erlang
# fortran fsharp go groovy haskell
# java julia kotlin lua markdown
# matlab nix pascal perl php
# php_phpactor powershell python python_jedi r
# rego ruby ruby_solargraph rust scala
# swift terraform toml typescript typescript_vts
# vue yaml zig
# (This list may be outdated. For the current list, see values of Language enum here:
# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py
# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.)
# Note:
# - For C, use cpp
# - For JavaScript, use typescript
# - For Free Pascal/Lazarus, use pascal
# Special requirements:
# Some languages require additional setup/installations.
# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers
# When using multiple languages, the first language server that supports a given file will be used for that file.
# The first language is the default language and the respective language server will be used as a fallback.
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
languages:
- bash
- python
# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default)
included_optional_tools: []
# the encoding used by text files in the project
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
encoding: utf-8
# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools.
# This cannot be combined with non-empty excluded_tools or included_optional_tools.
fixed_tools: []
# list of mode names to that are always to be included in the set of active modes
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this setting overrides the global configuration.
# Set this to [] to disable base modes for this project.
# Set this to a list of mode names to always include the respective modes for this project.
base_modes:
# list of mode names that are to be activated by default.
# The full set of modes to be activated is base_modes + default_modes.
# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply.
# Otherwise, this overrides the setting from the global configuration (serena_config.yml).
# This setting can, in turn, be overridden by CLI parameters (--mode).
default_modes:
# time budget (seconds) per tool call for the retrieval of additional symbol information
# such as docstrings or parameter information.
# This overrides the corresponding setting in the global configuration; see the documentation there.
# If null or missing, use the setting from the global configuration.
symbol_info_budget:
# The language backend to use for this project.
# If not set, the global setting from serena_config.yml is used.
# Valid values: LSP, JetBrains
# Note: the backend is fixed at startup. If a project with a different backend
# is activated post-init, an error will be returned.
language_backend:
# list of regex patterns which, when matched, mark a memory entry as readonly.
# Extends the list from the global configuration, merging the two lists.
read_only_memory_patterns: []

View File

@@ -25,12 +25,22 @@
### Folders
- `.serena/` Internal config (do not edit)
- `.claude/hooks/` Claude Code hook scripts (auto-format, lint, block rules.yml edits)
- `.claude/skills/` Claude Code skills (`/release`, `/test-action`, `/new-action`, `/validate`, `/check-pins`)
- `.claude/agents/` Claude Code subagents (action-validator, test-coverage-reviewer)
- `.github/` Workflows/templates
- `_tests/` ShellSpec tests
- `_tools/` Helper tools
- `validate-inputs/` Python validation system + tests
- `*/rules.yml` Auto-generated validation rules
### Claude Code Hooks
**Auto-formatting**: PostToolUse hooks auto-format files on Edit/Write (ruff for .py, shfmt for .sh, prettier for .yml/.yaml/.json/.md, actionlint for action.yml)
**Blocked edits**: PreToolUse hook blocks direct edits to `rules.yml` (auto-generated, use `make update-validators`)
**Hook schema**: `matcher` is a regex string matching tool names (e.g. `"Edit|Write"`), not an object. File filtering done in hook scripts via stdin JSON (`jq -r '.tool_input.file_path'`)
**Reference**: `$CLAUDE_PROJECT_DIR` for project-relative paths in hook commands
### Memory System
**Location**: `.serena/memories/` (9 consolidated memories for context)

75
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,75 @@
# Contributing to ivuorinen/actions
Thank you for your interest in contributing to this GitHub Actions monorepo.
## Reporting Issues
- **Bugs**: Open an issue using the bug report template.
- **Security vulnerabilities**: See [SECURITY.md](SECURITY.md) for responsible disclosure.
- **Feature requests**: Open an issue describing the use case.
## Development Setup
1. Clone the repository:
```bash
git clone https://github.com/ivuorinen/actions.git
cd actions
```
2. Install dependencies (Node.js, Python 3, ShellSpec, shellcheck, actionlint, ruff, prettier, markdownlint, yamllint).
3. Run formatting, linting, and pre-commit checks:
```bash
make all
```
4. Run the test suite:
```bash
make test
```
## Code Style
- **EditorConfig**: 2-space indentation, UTF-8, LF line endings, max 200 chars.
- **Shell scripts**: POSIX `sh` with `set -eu`. No bash-only syntax.
- **Python**: Formatted and linted with `ruff`.
- **YAML/JSON/Markdown**: Formatted with `prettier`; linted with `yamllint` and `markdownlint`.
- **Action references**: SHA-pinned in `action.yml` files. Date-based tags or commit SHAs for published refs.
Run `make dev` (format + lint) to check your changes.
## Pull Request Process
1. Branch from `main`.
2. Make focused changes (one feature or fix per PR).
3. Ensure all checks pass: `make all` and `make test`.
4. Follow existing patterns in the codebase.
5. Update documentation if adding or modifying actions.
## Testing
```bash
make test # All tests (ShellSpec + pytest)
make test-actions # GitHub Actions tests only
make test-python # Python validation tests only
make test-coverage # All tests with coverage
```
See [\_tests/README.md](_tests/README.md) for details on the ShellSpec testing framework.
## Adding a New Action
Each action is a self-contained directory at the repository root containing:
- `action.yml` with inputs, outputs, and runs definition
- `README.md` generated via `action-docs` (`make docs`)
- Tests in `_tests/`
Do not manually edit sections between `<!--LISTING-->` markers in the root README.
Use `npm run update-catalog` to regenerate the catalog.
## License
By contributing, you agree that your contributions will be licensed under the [MIT License](LICENSE.md).

View File

@@ -210,7 +210,7 @@ bump-major-version: ## Replace one major version with another (usage: make bump-
@sh _tools/bump-major-version.sh "$(OLD)" "$(NEW)"
@echo "$(GREEN)✅ Major version bumped$(RESET)"
check-version-refs: ## List all current SHA-pinned action references
check-version-refs: ## Verify all action references are SHA-pinned
@echo "$(BLUE)🔍 Checking action references...$(RESET)"
@sh _tools/check-version-refs.sh

132
README.md
View File

@@ -1,5 +1,7 @@
# ivuorinen/actions - My Reusable GitHub Actions and Workflows
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/ivuorinen/actions/badge)](https://scorecard.dev/viewer/?uri=github.com/ivuorinen/actions)
## Overview
This repository contains a collection of reusable GitHub Actions
@@ -27,73 +29,73 @@ This repository contains **26 reusable GitHub Actions** for CI/CD automation.
### Quick Reference (26 Actions)
| Icon | Action | Category | Description | Key Features |
|:----:|:-----------------------------------------------------|:-----------|:----------------------------------------------------------------|:---------------------------------------------|
| :--: | :--------------------------------------------------- | :--------- | :-------------------------------------------------------------- | :------------------------------------------- |
| 🔀 | [`action-versioning`][action-versioning] | Utilities | Automatically update SHA-pinned action references to match l... | Token auth, Outputs |
| 📦 | [`ansible-lint-fix`][ansible-lint-fix] | Linting | Lints and fixes Ansible playbooks, commits changes, and uplo... | Caching, Token auth, Outputs |
| ✅ | [`biome-lint`][biome-lint] | Linting | Run Biome linter in check or fix mode | Caching, Auto-detection, Token auth, Outputs |
| 🛡️ | [`codeql-analysis`][codeql-analysis] | Repository | Run CodeQL security analysis for a single language with conf... | Auto-detection, Token auth, Outputs |
| 🖼️ | [`compress-images`][compress-images] | Repository | Compress images on demand (workflow_dispatch), and at 11pm e... | Token auth, Outputs |
| ✅ | [`biome-lint`][biome-lint] | Linting | Run Biome linter in check or fix mode | Caching, Auto-detection, Token auth, Outputs |
| 🛡️ | [`codeql-analysis`][codeql-analysis] | Repository | Run CodeQL security analysis for a single language with conf... | Auto-detection, Token auth, Outputs |
| 🖼️ | [`compress-images`][compress-images] | Repository | Compress images on demand (workflow_dispatch), and at 11pm e... | Token auth, Outputs |
| 📝 | [`csharp-build`][csharp-build] | Build | Builds and tests C# projects. | Caching, Auto-detection, Token auth, Outputs |
| 📝 | [`csharp-lint-check`][csharp-lint-check] | Linting | Runs linters like StyleCop or dotnet-format for C# code styl... | Caching, Auto-detection, Token auth, Outputs |
| 📦 | [`csharp-publish`][csharp-publish] | Publishing | Publishes a C# project to GitHub Packages. | Caching, Auto-detection, Token auth, Outputs |
| 📦 | [`docker-build`][docker-build] | Build | Builds a Docker image for multiple architectures with enhanc... | Caching, Auto-detection, Token auth, Outputs |
| ☁️ | [`docker-publish`][docker-publish] | Publishing | Simple wrapper to publish Docker images to GitHub Packages a... | Token auth, Outputs |
| ✅ | [`eslint-lint`][eslint-lint] | Linting | Run ESLint in check or fix mode with advanced configuration ... | Caching, Auto-detection, Token auth, Outputs |
| ✅ | [`eslint-lint`][eslint-lint] | Linting | Run ESLint in check or fix mode with advanced configuration ... | Caching, Auto-detection, Token auth, Outputs |
| 📦 | [`go-build`][go-build] | Build | Builds the Go project. | Caching, Auto-detection, Token auth, Outputs |
| 📝 | [`go-lint`][go-lint] | Linting | Run golangci-lint with advanced configuration, caching, and ... | Caching, Token auth, Outputs |
| 📝 | [`language-version-detect`][language-version-detect] | Setup | DEPRECATED: This action is deprecated. Inline version detect... | Auto-detection, Token auth, Outputs |
| 📦 | [`npm-publish`][npm-publish] | Publishing | Publishes the package to the NPM registry with configurable ... | Caching, Auto-detection, Token auth, Outputs |
| ✅ | [`php-tests`][php-tests] | Testing | Run PHPUnit tests with optional Laravel setup and Composer d... | Caching, Auto-detection, Token auth, Outputs |
| ✅ | [`pr-lint`][pr-lint] | Linting | Runs MegaLinter against pull requests | Caching, Auto-detection, Token auth, Outputs |
| ✅ | [`php-tests`][php-tests] | Testing | Run PHPUnit tests with optional Laravel setup and Composer d... | Caching, Auto-detection, Token auth, Outputs |
| ✅ | [`pr-lint`][pr-lint] | Linting | Runs MegaLinter against pull requests | Caching, Auto-detection, Token auth, Outputs |
| 📦 | [`pre-commit`][pre-commit] | Linting | Runs pre-commit on the repository and pushes the fixes back ... | Auto-detection, Token auth, Outputs |
| ✅ | [`prettier-lint`][prettier-lint] | Linting | Run Prettier in check or fix mode with advanced configuratio... | Caching, Auto-detection, Token auth, Outputs |
| ✅ | [`prettier-lint`][prettier-lint] | Linting | Run Prettier in check or fix mode with advanced configuratio... | Caching, Auto-detection, Token auth, Outputs |
| 📝 | [`python-lint-fix`][python-lint-fix] | Linting | Lints and fixes Python files, commits changes, and uploads S... | Caching, Auto-detection, Token auth, Outputs |
| 📦 | [`release-monthly`][release-monthly] | Repository | Creates a release for the current month, incrementing patch ... | Token auth, Outputs |
| 🛡️ | [`security-scan`][security-scan] | Security | Comprehensive security scanning for GitHub Actions including... | Caching, Token auth, Outputs |
| 🛡️ | [`security-scan`][security-scan] | Security | Comprehensive security scanning for GitHub Actions including... | Caching, Token auth, Outputs |
| 📦 | [`stale`][stale] | Repository | A GitHub Action to close stale issues and pull requests. | Token auth, Outputs |
| 🏷️ | [`sync-labels`][sync-labels] | Repository | Sync labels from a YAML file to a GitHub repository | Token auth, Outputs |
| 🖥️ | [`terraform-lint-fix`][terraform-lint-fix] | Linting | Lints and fixes Terraform files with advanced validation and... | Token auth, Outputs |
| 🛡️ | [`validate-inputs`][validate-inputs] | Validation | Centralized Python-based input validation for GitHub Actions... | Token auth, Outputs |
| 🏷️ | [`sync-labels`][sync-labels] | Repository | Sync labels from a YAML file to a GitHub repository | Token auth, Outputs |
| 🖥️ | [`terraform-lint-fix`][terraform-lint-fix] | Linting | Lints and fixes Terraform files with advanced validation and... | Token auth, Outputs |
| 🛡️ | [`validate-inputs`][validate-inputs] | Validation | Centralized Python-based input validation for GitHub Actions... | Token auth, Outputs |
### Actions by Category
#### 🔧 Setup (1 action)
| Action | Description | Languages | Features |
|:--------------------------------------------------------|:------------------------------------------------------|:-------------------------------|:------------------------------------|
| :------------------------------------------------------ | :---------------------------------------------------- | :----------------------------- | :---------------------------------- |
| 📝 [`language-version-detect`][language-version-detect] | DEPRECATED: This action is deprecated. Inline vers... | PHP, Python, Go, .NET, Node.js | Auto-detection, Token auth, Outputs |
#### 🛠️ Utilities (1 action)
| Action | Description | Languages | Features |
|:--------------------------------------------|:------------------------------------------------------|:---------------|:--------------------|
| :------------------------------------------ | :---------------------------------------------------- | :------------- | :------------------ |
| 🔀 [`action-versioning`][action-versioning] | Automatically update SHA-pinned action references ... | GitHub Actions | Token auth, Outputs |
#### 📝 Linting (10 actions)
| Action | Description | Languages | Features |
|:-----------------------------------------------|:------------------------------------------------------|:---------------------------------------------|:---------------------------------------------|
| 📦 [`ansible-lint-fix`][ansible-lint-fix] | Lints and fixes Ansible playbooks, commits changes... | Ansible, YAML | Caching, Token auth, Outputs |
| ✅ [`biome-lint`][biome-lint] | Run Biome linter in check or fix mode | JavaScript, TypeScript, JSON | Caching, Auto-detection, Token auth, Outputs |
| 📝 [`csharp-lint-check`][csharp-lint-check] | Runs linters like StyleCop or dotnet-format for C#... | C#, .NET | Caching, Auto-detection, Token auth, Outputs |
| ✅ [`eslint-lint`][eslint-lint] | Run ESLint in check or fix mode with advanced conf... | JavaScript, TypeScript | Caching, Auto-detection, Token auth, Outputs |
| 📝 [`go-lint`][go-lint] | Run golangci-lint with advanced configuration, cac... | Go | Caching, Token auth, Outputs |
| ✅ [`pr-lint`][pr-lint] | Runs MegaLinter against pull requests | Conventional Commits | Caching, Auto-detection, Token auth, Outputs |
| 📦 [`pre-commit`][pre-commit] | Runs pre-commit on the repository and pushes the f... | Python, Multiple Languages | Auto-detection, Token auth, Outputs |
| ✅ [`prettier-lint`][prettier-lint] | Run Prettier in check or fix mode with advanced co... | JavaScript, TypeScript, Markdown, YAML, JSON | Caching, Auto-detection, Token auth, Outputs |
| 📝 [`python-lint-fix`][python-lint-fix] | Lints and fixes Python files, commits changes, and... | Python | Caching, Auto-detection, Token auth, Outputs |
| Action | Description | Languages | Features |
| :-------------------------------------------- | :---------------------------------------------------- | :------------------------------------------- | :------------------------------------------- |
| 📦 [`ansible-lint-fix`][ansible-lint-fix] | Lints and fixes Ansible playbooks, commits changes... | Ansible, YAML | Caching, Token auth, Outputs |
| ✅ [`biome-lint`][biome-lint] | Run Biome linter in check or fix mode | JavaScript, TypeScript, JSON | Caching, Auto-detection, Token auth, Outputs |
| 📝 [`csharp-lint-check`][csharp-lint-check] | Runs linters like StyleCop or dotnet-format for C#... | C#, .NET | Caching, Auto-detection, Token auth, Outputs |
| ✅ [`eslint-lint`][eslint-lint] | Run ESLint in check or fix mode with advanced conf... | JavaScript, TypeScript | Caching, Auto-detection, Token auth, Outputs |
| 📝 [`go-lint`][go-lint] | Run golangci-lint with advanced configuration, cac... | Go | Caching, Token auth, Outputs |
| ✅ [`pr-lint`][pr-lint] | Runs MegaLinter against pull requests | Conventional Commits | Caching, Auto-detection, Token auth, Outputs |
| 📦 [`pre-commit`][pre-commit] | Runs pre-commit on the repository and pushes the f... | Python, Multiple Languages | Auto-detection, Token auth, Outputs |
| ✅ [`prettier-lint`][prettier-lint] | Run Prettier in check or fix mode with advanced co... | JavaScript, TypeScript, Markdown, YAML, JSON | Caching, Auto-detection, Token auth, Outputs |
| 📝 [`python-lint-fix`][python-lint-fix] | Lints and fixes Python files, commits changes, and... | Python | Caching, Auto-detection, Token auth, Outputs |
| 🖥️ [`terraform-lint-fix`][terraform-lint-fix] | Lints and fixes Terraform files with advanced vali... | Terraform, HCL | Token auth, Outputs |
#### 🧪 Testing (1 action)
| Action | Description | Languages | Features |
|:---------------------------|:------------------------------------------------------|:-------------|:---------------------------------------------|
| Action | Description | Languages | Features |
| :-------------------------- | :---------------------------------------------------- | :----------- | :------------------------------------------- |
| ✅ [`php-tests`][php-tests] | Run PHPUnit tests with optional Laravel setup and ... | PHP, Laravel | Caching, Auto-detection, Token auth, Outputs |
#### 🏗️ Build (3 actions)
| Action | Description | Languages | Features |
|:----------------------------------|:------------------------------------------------------|:----------|:---------------------------------------------|
| :-------------------------------- | :---------------------------------------------------- | :-------- | :------------------------------------------- |
| 📝 [`csharp-build`][csharp-build] | Builds and tests C# projects. | C#, .NET | Caching, Auto-detection, Token auth, Outputs |
| 📦 [`docker-build`][docker-build] | Builds a Docker image for multiple architectures w... | Docker | Caching, Auto-detection, Token auth, Outputs |
| 📦 [`go-build`][go-build] | Builds the Go project. | Go | Caching, Auto-detection, Token auth, Outputs |
@@ -101,68 +103,68 @@ This repository contains **26 reusable GitHub Actions** for CI/CD automation.
#### 🚀 Publishing (3 actions)
| Action | Description | Languages | Features |
|:--------------------------------------|:------------------------------------------------------|:-------------|:---------------------------------------------|
| :------------------------------------ | :---------------------------------------------------- | :----------- | :------------------------------------------- |
| 📦 [`csharp-publish`][csharp-publish] | Publishes a C# project to GitHub Packages. | C#, .NET | Caching, Auto-detection, Token auth, Outputs |
| ☁️ [`docker-publish`][docker-publish] | Simple wrapper to publish Docker images to GitHub ... | Docker | Token auth, Outputs |
| 📦 [`npm-publish`][npm-publish] | Publishes the package to the NPM registry with con... | Node.js, npm | Caching, Auto-detection, Token auth, Outputs |
#### 📦 Repository (5 actions)
| Action | Description | Languages | Features |
|:-----------------------------------------|:------------------------------------------------------|:--------------------------------------------------------|:------------------------------------|
| Action | Description | Languages | Features |
| :-------------------------------------- | :---------------------------------------------------- | :------------------------------------------------------ | :---------------------------------- |
| 🛡️ [`codeql-analysis`][codeql-analysis] | Run CodeQL security analysis for a single language... | JavaScript, TypeScript, Python, Java, C#, C++, Go, Ruby | Auto-detection, Token auth, Outputs |
| 🖼️ [`compress-images`][compress-images] | Compress images on demand (workflow_dispatch), and... | Images, PNG, JPEG | Token auth, Outputs |
| 📦 [`release-monthly`][release-monthly] | Creates a release for the current month, increment... | GitHub Actions | Token auth, Outputs |
| 📦 [`stale`][stale] | A GitHub Action to close stale issues and pull req... | GitHub Actions | Token auth, Outputs |
| 📦 [`release-monthly`][release-monthly] | Creates a release for the current month, increment... | GitHub Actions | Token auth, Outputs |
| 📦 [`stale`][stale] | A GitHub Action to close stale issues and pull req... | GitHub Actions | Token auth, Outputs |
| 🏷️ [`sync-labels`][sync-labels] | Sync labels from a YAML file to a GitHub repositor... | YAML, GitHub | Token auth, Outputs |
#### 🛡️ Security (1 action)
| Action | Description | Languages | Features |
|:-------------------------------------|:------------------------------------------------------|:----------|:-----------------------------|
| Action | Description | Languages | Features |
| :---------------------------------- | :---------------------------------------------------- | :-------- | :--------------------------- |
| 🛡️ [`security-scan`][security-scan] | Comprehensive security scanning for GitHub Actions... | - | Caching, Token auth, Outputs |
#### ✅ Validation (1 action)
| Action | Description | Languages | Features |
|:-----------------------------------------|:------------------------------------------------------|:---------------------|:--------------------|
| Action | Description | Languages | Features |
| :-------------------------------------- | :---------------------------------------------------- | :------------------- | :------------------ |
| 🛡️ [`validate-inputs`][validate-inputs] | Centralized Python-based input validation for GitH... | YAML, GitHub Actions | Token auth, Outputs |
### Feature Matrix
| Action | Caching | Auto-detection | Token auth | Outputs |
|:-----------------------------------------------------|:-------:|:--------------:|:----------:|:-------:|
| [`action-versioning`][action-versioning] | - | - | ✅ | ✅ |
| [`ansible-lint-fix`][ansible-lint-fix] | ✅ | - | ✅ | ✅ |
| [`biome-lint`][biome-lint] | ✅ | ✅ | ✅ | ✅ |
| [`codeql-analysis`][codeql-analysis] | - | ✅ | ✅ | ✅ |
| [`compress-images`][compress-images] | - | - | ✅ | ✅ |
| [`csharp-build`][csharp-build] | ✅ | ✅ | ✅ | ✅ |
| [`csharp-lint-check`][csharp-lint-check] | ✅ | ✅ | ✅ | ✅ |
| [`csharp-publish`][csharp-publish] | ✅ | ✅ | ✅ | ✅ |
| [`docker-build`][docker-build] | ✅ | ✅ | ✅ | ✅ |
| [`docker-publish`][docker-publish] | - | - | ✅ | ✅ |
| [`eslint-lint`][eslint-lint] | ✅ | ✅ | ✅ | ✅ |
| [`go-build`][go-build] | ✅ | ✅ | ✅ | ✅ |
| [`go-lint`][go-lint] | ✅ | - | ✅ | ✅ |
| [`language-version-detect`][language-version-detect] | - | ✅ | ✅ | ✅ |
| [`npm-publish`][npm-publish] | ✅ | ✅ | ✅ | ✅ |
| [`php-tests`][php-tests] | ✅ | ✅ | ✅ | ✅ |
| [`pr-lint`][pr-lint] | ✅ | ✅ | ✅ | ✅ |
| [`pre-commit`][pre-commit] | - | ✅ | ✅ | ✅ |
| [`prettier-lint`][prettier-lint] | ✅ | ✅ | ✅ | ✅ |
| [`python-lint-fix`][python-lint-fix] | ✅ | ✅ | ✅ | ✅ |
| [`release-monthly`][release-monthly] | - | - | ✅ | ✅ |
| [`security-scan`][security-scan] | ✅ | - | ✅ | ✅ |
| [`stale`][stale] | - | - | ✅ | ✅ |
| [`sync-labels`][sync-labels] | - | - | ✅ | ✅ |
| [`terraform-lint-fix`][terraform-lint-fix] | - | - | ✅ | ✅ |
| [`validate-inputs`][validate-inputs] | - | - | ✅ | ✅ |
| :--------------------------------------------------- | :-----: | :------------: | :--------: | :-----: |
| [`action-versioning`][action-versioning] | - | - | ✅ | ✅ |
| [`ansible-lint-fix`][ansible-lint-fix] | ✅ | - | ✅ | ✅ |
| [`biome-lint`][biome-lint] | ✅ | ✅ | ✅ | ✅ |
| [`codeql-analysis`][codeql-analysis] | - | ✅ | ✅ | ✅ |
| [`compress-images`][compress-images] | - | - | ✅ | ✅ |
| [`csharp-build`][csharp-build] | ✅ | ✅ | ✅ | ✅ |
| [`csharp-lint-check`][csharp-lint-check] | ✅ | ✅ | ✅ | ✅ |
| [`csharp-publish`][csharp-publish] | ✅ | ✅ | ✅ | ✅ |
| [`docker-build`][docker-build] | ✅ | ✅ | ✅ | ✅ |
| [`docker-publish`][docker-publish] | - | - | ✅ | ✅ |
| [`eslint-lint`][eslint-lint] | ✅ | ✅ | ✅ | ✅ |
| [`go-build`][go-build] | ✅ | ✅ | ✅ | ✅ |
| [`go-lint`][go-lint] | ✅ | - | ✅ | ✅ |
| [`language-version-detect`][language-version-detect] | - | ✅ | ✅ | ✅ |
| [`npm-publish`][npm-publish] | ✅ | ✅ | ✅ | ✅ |
| [`php-tests`][php-tests] | ✅ | ✅ | ✅ | ✅ |
| [`pr-lint`][pr-lint] | ✅ | ✅ | ✅ | ✅ |
| [`pre-commit`][pre-commit] | - | ✅ | ✅ | ✅ |
| [`prettier-lint`][prettier-lint] | ✅ | ✅ | ✅ | ✅ |
| [`python-lint-fix`][python-lint-fix] | ✅ | ✅ | ✅ | ✅ |
| [`release-monthly`][release-monthly] | - | - | ✅ | ✅ |
| [`security-scan`][security-scan] | ✅ | - | ✅ | ✅ |
| [`stale`][stale] | - | - | ✅ | ✅ |
| [`sync-labels`][sync-labels] | - | - | ✅ | ✅ |
| [`terraform-lint-fix`][terraform-lint-fix] | - | - | ✅ | ✅ |
| [`validate-inputs`][validate-inputs] | - | - | ✅ | ✅ |
### Language Support
| Language | Actions |
|:---------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| :------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| .NET | [`csharp-build`][csharp-build], [`csharp-lint-check`][csharp-lint-check], [`csharp-publish`][csharp-publish], [`language-version-detect`][language-version-detect] |
| Ansible | [`ansible-lint-fix`][ansible-lint-fix] |
| C# | [`codeql-analysis`][codeql-analysis], [`csharp-build`][csharp-build], [`csharp-lint-check`][csharp-lint-check], [`csharp-publish`][csharp-publish] |

View File

@@ -183,9 +183,6 @@ validate_input_python "docker-build" "tag" "v1.0.0" # success
validate_input_python "pre-commit" "config-file" "config.yml" # success
validate_input_python "pre-commit" "config-file" "../etc/pass" # failure
# Injection detection
validate_input_python "common-retry" "command" "echo test" # success
validate_input_python "common-retry" "command" "rm -rf /; " # failure
```
### Helper Functions from spec_helper.sh
@@ -482,11 +479,6 @@ End
✅ **Always include**:
```bash
It "rejects command injection"
When call validate_input_python "common-retry" "command" "rm -rf /; "
The status should be failure
End
It "rejects path traversal"
When call validate_input_python "pre-commit" "config-file" "../etc/passwd"
The status should be failure

View File

@@ -264,7 +264,7 @@ def get_input_property(action_file: str, input_name: str, property_check: str) -
if property_check == "description":
description = input_data.get("description", "")
return description if description else "no-description"
return description or "no-description"
if property_check == "all_optional":
# Check if all inputs are optional (none are required)

View File

@@ -337,7 +337,7 @@ class ValidationCore:
"""
if not value: # Empty values are generally allowed, except for specific cases
# Some inputs should not be empty even if they're optional
if action_name == "php-composer" and input_name in ["composer-version"]:
if action_name == "php-composer" and input_name == "composer-version":
return False, f"Empty {input_name} is not allowed"
return None, ""
@@ -552,7 +552,7 @@ class ActionFileParser:
def _get_description_property(input_data: dict) -> str:
"""Get the description property."""
description = input_data.get("description", "")
return description if description else "no-description"
return description or "no-description"
@staticmethod
def _get_all_optional_property(inputs: dict) -> str:

View File

@@ -92,9 +92,6 @@ setup_default_inputs() {
"go-build" | "go-lint")
[[ "$input_name" != "go-version" ]] && export INPUT_GO_VERSION="1.21"
;;
"common-retry")
[[ "$input_name" != "command" ]] && export INPUT_COMMAND="echo test"
;;
"dotnet-version-detect")
[[ "$input_name" != "default-version" ]] && export INPUT_DEFAULT_VERSION="8.0"
;;
@@ -154,9 +151,6 @@ cleanup_default_inputs() {
"go-build" | "go-lint")
[[ "$input_name" != "go-version" ]] && unset INPUT_GO_VERSION
;;
"common-retry")
[[ "$input_name" != "command" ]] && unset INPUT_COMMAND
;;
"dotnet-version-detect")
[[ "$input_name" != "default-version" ]] && unset INPUT_DEFAULT_VERSION
;;
@@ -239,12 +233,6 @@ shellspec_mock_action_run() {
"common-file-check")
echo "found=true" >>"$GITHUB_OUTPUT"
;;
"common-retry")
echo "success=true" >>"$GITHUB_OUTPUT"
echo "attempts=1" >>"$GITHUB_OUTPUT"
echo "exit-code=0" >>"$GITHUB_OUTPUT"
echo "duration=5" >>"$GITHUB_OUTPUT"
;;
"compress-images")
echo "images_compressed=true" >>"$GITHUB_OUTPUT"
printf "compression_report=## Compression Results\n- 3 images compressed\n- 25%% size reduction\n" >>"$GITHUB_OUTPUT"

View File

@@ -23,19 +23,43 @@ for tool in find grep sed printf sort cut tr wc; do
fi
done
# --- Validation pass: detect non-SHA-pinned references ---
violations_file=$(safe_mktemp)
trap 'rm -f "$violations_file"' EXIT
find . -maxdepth 2 -name "action.yml" -path "*/action.yml" \
! -path "./_*" ! -path "./.github/*" \
-exec grep -nE '^\s+uses:\s+ivuorinen/actions/' {} /dev/null \; \
>"$violations_file"
violations_found=false
while IFS= read -r match; do
if ! printf '%s\n' "$match" | grep -qE '@[0-9a-f]{40}'; then
if [ "$violations_found" = false ]; then
msg_error "Non-SHA-pinned action references found:"
violations_found=true
fi
printf ' %s\n' "$match" >&2
fi
done <"$violations_file"
if [ "$violations_found" = true ]; then
rm -f "$violations_file"
exit 1
fi
rm -f "$violations_file"
printf '%b' "${BLUE}Current SHA-pinned action references:${NC}\n"
printf '\n'
# Create temp files for processing
temp_file=$(safe_mktemp)
trap 'rm -f "$temp_file"' EXIT
temp_input=$(safe_mktemp)
trap 'rm -f "$temp_file" "$temp_input"' EXIT
# Find all action references and collect SHA|action pairs
# Use input redirection to avoid subshell issues with pipeline
find . -maxdepth 2 -name "action.yml" -path "*/action.yml" ! -path "./_*" ! -path "./.github/*" -exec grep -h "uses: ivuorinen/actions/" {} \; > "$temp_input"
find . -maxdepth 2 -name "action.yml" -path "*/action.yml" ! -path "./_*" ! -path "./.github/*" -exec grep -h "uses: ivuorinen/actions/" {} \; >"$temp_input"
while IFS= read -r line; do
# Extract action name and SHA using sed
@@ -43,9 +67,9 @@ while IFS= read -r line; do
sha=$(echo "$line" | sed -n 's|.*@\([a-f0-9]\{40\}\).*|\1|p')
if [ -n "$action" ] && [ -n "$sha" ]; then
printf '%s\n' "$sha|$action" >> "$temp_file"
printf '%s\n' "$sha|$action" >>"$temp_file"
fi
done < "$temp_input"
done <"$temp_input"
# Check if we found any references
if [ ! -s "$temp_file" ]; then
@@ -54,7 +78,7 @@ if [ ! -s "$temp_file" ]; then
fi
# Sort by SHA and group
sort "$temp_file" | uniq > "${temp_file}.sorted"
sort "$temp_file" | uniq >"${temp_file}.sorted"
mv "${temp_file}.sorted" "$temp_file"
# Count unique SHAs
@@ -95,7 +119,7 @@ while IFS='|' read -r sha action; do
# Add to current SHA group
actions_list="$actions_list, $action"
fi
done < "$temp_file"
done <"$temp_file"
# Print last SHA group
if [ -n "$current_sha" ]; then

View File

@@ -10,7 +10,7 @@ ARG ACT_VERSION=0.2.71
ARG SHELLSPEC_VERSION=0.28.1
# Stage 1: Build kcov separately to keep final image slim
FROM ubuntu:24.04 AS kcov-builder
FROM ubuntu:24.04@sha256:d1e2e92c075e5ca139d51a140fff46f84315c0fdce203eab2807c7e495eff4f9 AS kcov-builder
ARG KCOV_VERSION
@@ -43,7 +43,7 @@ RUN cmake .. \
&& make install DESTDIR=/kcov-install
# Stage 2: Base system setup
FROM ubuntu:24.04 AS base
FROM ubuntu:24.04@sha256:d1e2e92c075e5ca139d51a140fff46f84315c0fdce203eab2807c7e495eff4f9 AS base
LABEL maintainer="ivuorinen"
LABEL description="GitHub Actions testing framework with pre-installed tools"

View File

@@ -83,7 +83,7 @@ runs:
- name: Install ansible-lint
id: install-ansible-lint
if: steps.check-files.outputs.files_found == 'true'
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with:
timeout_minutes: 5
max_attempts: ${{ inputs.max-retries }}
@@ -130,6 +130,6 @@ runs:
- name: Upload SARIF Report
if: steps.check-files.outputs.files_found == 'true'
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: ansible-lint.sarif

View File

@@ -181,7 +181,7 @@ runs:
echo "Detected package manager: $package_manager"
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '24'
@@ -212,7 +212,7 @@ runs:
- name: Setup Bun
if: steps.detect-pm.outputs.package-manager == 'bun'
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
uses: oven-sh/setup-bun@ecf28ddc73e819eb6fa29df6b34ef8921c743461 # v2.1.3
with:
bun-version: latest
@@ -331,7 +331,7 @@ runs:
- name: Upload SARIF Report
if: inputs.mode == 'check' && always()
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: biome-report.sarif

View File

@@ -186,7 +186,7 @@ runs:
echo "Using build mode: $build_mode"
- name: Initialize CodeQL
uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/init@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
languages: ${{ inputs.language }}
queries: ${{ inputs.queries }}
@@ -199,12 +199,12 @@ runs:
threads: ${{ inputs.threads }}
- name: Autobuild
uses: github/codeql-action/autobuild@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/autobuild@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
if: ${{ steps.set-build-mode.outputs.build-mode == 'autobuild' }}
- name: Perform CodeQL Analysis
id: analysis
uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/analyze@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
category: ${{ steps.set-category.outputs.category }}
upload: ${{ inputs.upload-results }}

View File

@@ -148,14 +148,14 @@ runs:
echo "Final detected .NET version: $detected_version" >&2
- name: Setup .NET SDK
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
with:
dotnet-version: ${{ steps.detect-dotnet-version.outputs.detected-version }}
cache: true
cache-dependency-path: '**/packages.lock.json'
- name: Restore Dependencies
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with:
timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }}
@@ -203,7 +203,7 @@ runs:
- name: Upload Test Results
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: csharp-test-results
path: |

View File

@@ -164,7 +164,7 @@ runs:
echo "Final detected .NET version: $detected_version" >&2
- name: Setup .NET SDK
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
with:
dotnet-version: ${{ steps.detect-dotnet-version.outputs.detected-version }}
cache: true
@@ -206,6 +206,6 @@ runs:
fi
- name: Upload SARIF Report
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: dotnet-format.sarif

View File

@@ -162,14 +162,14 @@ runs:
echo "Final detected .NET version: $detected_version" >&2
- name: Setup .NET SDK
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7 # v5.2.0
with:
dotnet-version: ${{ inputs.dotnet-version || steps.detect-dotnet-version.outputs.detected-version }}
cache: true
cache-dependency-path: '**/packages.lock.json'
- name: Restore Dependencies
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with:
timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }}

View File

@@ -169,13 +169,13 @@ runs:
fi
- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
with:
platforms: ${{ inputs.architectures }}
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ inputs.buildx-version }}
platforms: ${{ inputs.architectures }}
@@ -321,7 +321,7 @@ runs:
- name: Login to GitHub Container Registry
if: ${{ inputs.push == 'true' }}
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -536,7 +536,7 @@ runs:
- name: Scan Image for Vulnerabilities
id: scan
if: inputs.scan-image == 'true' && inputs.dry-run != 'true'
uses: aquasecurity/trivy-action@e368e328979b113139d6f9068e03accaed98a518 # 0.34.1
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # 0.35.0
with:
scan-type: 'image'
image-ref: ${{ steps.image-name.outputs.name }}:${{ inputs.tag }}

View File

@@ -202,7 +202,7 @@ runs:
printf '%s\n' "Input validation completed successfully"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Determine Image Names and Tags
id: meta
@@ -265,14 +265,14 @@ runs:
- name: Login to Docker Hub
if: inputs.registry == 'dockerhub' || inputs.registry == 'both'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
username: ${{ inputs.dockerhub-username }}
password: ${{ inputs.dockerhub-token }}
- name: Login to GitHub Container Registry
if: inputs.registry == 'github' || inputs.registry == 'both'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -280,7 +280,7 @@ runs:
- name: Build and Push Docker Image
id: build
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: ${{ inputs.context }}
file: ${{ inputs.dockerfile }}

View File

@@ -288,7 +288,7 @@ runs:
echo "Detected package manager: $package_manager"
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '24'
@@ -319,7 +319,7 @@ runs:
- name: Setup Bun
if: steps.detect-pm.outputs.package-manager == 'bun'
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
uses: oven-sh/setup-bun@ecf28ddc73e819eb6fa29df6b34ef8921c743461 # v2.1.3
with:
bun-version: latest
@@ -457,7 +457,7 @@ runs:
- name: Upload SARIF Report
if: inputs.mode == 'check' && inputs.report-format == 'sarif' && always()
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: ${{ inputs.working-directory }}/eslint-results.sarif

View File

@@ -159,13 +159,13 @@ runs:
echo "Final detected Go version: $detected_version" >&2
- name: Setup Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: ${{ steps.detect-go-version.outputs.detected-version }}
cache: true
- name: Download Dependencies
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with:
timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }}
@@ -253,7 +253,7 @@ runs:
- name: Upload Build Artifacts
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: go-build-artifacts
path: |

View File

@@ -205,7 +205,7 @@ runs:
validate_linter_list "$DISABLE_LINTERS" "disable-linters"
- name: Setup Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: ${{ inputs.go-version }}
cache: true
@@ -414,7 +414,7 @@ runs:
- name: Upload Lint Results
if: always() && inputs.report-format == 'sarif'
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: ${{ inputs.working-directory }}/reports/golangci-lint.sarif
category: golangci-lint

View File

@@ -121,7 +121,7 @@ runs:
echo "Detected package manager: $package_manager"
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '24'
@@ -152,7 +152,7 @@ runs:
- name: Setup Bun
if: steps.detect-pm.outputs.package-manager == 'bun'
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
uses: oven-sh/setup-bun@ecf28ddc73e819eb6fa29df6b34ef8921c743461 # v2.1.3
with:
bun-version: latest

108
package-lock.json generated
View File

@@ -13,7 +13,7 @@
"js-yaml": "^4.1.0",
"markdown-table": "^3.0.3",
"markdown-table-formatter": "^1.6.0",
"markdownlint-cli2": "^0.20.0",
"markdownlint-cli2": "^0.21.0",
"prettier": "^3.3.3",
"yaml-lint": "^1.7.0"
},
@@ -185,9 +185,9 @@
}
},
"node_modules/brace-expansion": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz",
"integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==",
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -422,16 +422,6 @@
"node": ">=8"
}
},
"node_modules/dir-glob/node_modules/path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -533,9 +523,9 @@
"license": "MIT"
},
"node_modules/fs-extra": {
"version": "11.3.3",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz",
"integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==",
"version": "11.3.4",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz",
"integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -609,18 +599,18 @@
}
},
"node_modules/globby": {
"version": "15.0.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-15.0.0.tgz",
"integrity": "sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw==",
"version": "16.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-16.1.0.tgz",
"integrity": "sha512-+A4Hq7m7Ze592k9gZRy4gJ27DrXRNnC1vPjxTt1qQxEY8RxagBkBxivkCwg7FxSTG0iLLEMaUx13oOr0R2/qcQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@sindresorhus/merge-streams": "^4.0.0",
"fast-glob": "^3.3.3",
"ignore": "^7.0.5",
"path-type": "^6.0.0",
"is-path-inside": "^4.0.0",
"slash": "^5.1.0",
"unicorn-magic": "^0.3.0"
"unicorn-magic": "^0.4.0"
},
"engines": {
"node": ">=20"
@@ -776,6 +766,19 @@
"node": ">=0.12.0"
}
},
"node_modules/is-path-inside": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz",
"integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
@@ -810,9 +813,9 @@
}
},
"node_modules/katex": {
"version": "0.16.32",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.32.tgz",
"integrity": "sha512-ac0FzkRJlpw4WyH3Zu/OgU9LmPKqjHr6O2BxfSrBt8uJ1BhvH2YK3oJ4ut/K+O+6qQt2MGpdbn0MrffVEnnUDQ==",
"version": "0.16.35",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.35.tgz",
"integrity": "sha512-S0+riEvy1CK4VKse1ivMff8gmabe/prY7sKB3njjhyoLLsNFDQYtKNgXrbWUggGDCJBz7Fctl5i8fLCESHXzSg==",
"dev": true,
"funding": [
"https://opencollective.com/katex",
@@ -871,9 +874,9 @@
}
},
"node_modules/markdown-it": {
"version": "14.1.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"version": "14.1.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
"integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -958,16 +961,16 @@
}
},
"node_modules/markdownlint-cli2": {
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.20.0.tgz",
"integrity": "sha512-esPk+8Qvx/f0bzI7YelUeZp+jCtFOk3KjZ7s9iBQZ6HlymSXoTtWGiIRZP05/9Oy2ehIoIjenVwndxGtxOIJYQ==",
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/markdownlint-cli2/-/markdownlint-cli2-0.21.0.tgz",
"integrity": "sha512-DzzmbqfMW3EzHsunP66x556oZDzjcdjjlL2bHG4PubwnL58ZPAfz07px4GqteZkoCGnBYi779Y2mg7+vgNCwbw==",
"dev": true,
"license": "MIT",
"dependencies": {
"globby": "15.0.0",
"globby": "16.1.0",
"js-yaml": "4.1.1",
"jsonc-parser": "3.3.1",
"markdown-it": "14.1.0",
"markdown-it": "14.1.1",
"markdownlint": "0.40.0",
"markdownlint-cli2-formatter-default": "0.0.6",
"micromatch": "4.0.8"
@@ -1563,9 +1566,9 @@
}
},
"node_modules/minimatch": {
"version": "10.2.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz",
"integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==",
"version": "10.2.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
"dev": true,
"license": "BlueOak-1.0.0",
"dependencies": {
@@ -1756,16 +1759,13 @@
}
},
"node_modules/path-type": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz",
"integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
"node": ">=8"
}
},
"node_modules/picomatch": {
@@ -1912,9 +1912,9 @@
}
},
"node_modules/replace-in-file/node_modules/minimatch": {
"version": "5.1.7",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.7.tgz",
"integrity": "sha512-FjiwU9HaHW6YB3H4a1sFudnv93lvydNjz2lmyUXR6IwKhGI+bgL3SOZrBGn6kvvX2pJvhEkGSGjyTHN47O4rqA==",
"version": "5.1.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -2034,13 +2034,13 @@
}
},
"node_modules/strip-ansi": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
"integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
"integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.0.1"
"ansi-regex": "^6.2.2"
},
"engines": {
"node": ">=12"
@@ -2096,13 +2096,13 @@
"license": "MIT"
},
"node_modules/unicorn-magic": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
"integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz",
"integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
"node": ">=20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"

View File

@@ -24,7 +24,7 @@
"js-yaml": "^4.1.0",
"markdown-table": "^3.0.3",
"markdown-table-formatter": "^1.6.0",
"markdownlint-cli2": "^0.20.0",
"markdownlint-cli2": "^0.21.0",
"prettier": "^3.3.3",
"yaml-lint": "^1.7.0"
},

View File

@@ -376,7 +376,7 @@ runs:
composer clear-cache
- name: Install Composer Dependencies
uses: step-security/retry@e1d59ce1f574b32f0915e3a8df055cfe9f99be5d # v3.0.4
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with:
timeout_minutes: 10
max_attempts: ${{ inputs.max-retries }}

View File

@@ -118,7 +118,7 @@ runs:
- name: Setup Node.js
if: steps.detect-node.outputs.found == 'true'
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '24'
@@ -156,7 +156,7 @@ runs:
- name: Setup Bun
if: steps.detect-node.outputs.found == 'true' && steps.detect-pm.outputs.package-manager == 'bun'
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
uses: oven-sh/setup-bun@ecf28ddc73e819eb6fa29df6b34ef8921c743461 # v2.1.3
with:
bun-version: latest
@@ -621,18 +621,45 @@ runs:
- name: Setup Go
if: steps.detect-go.outputs.found == 'true'
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: ${{ steps.go-version.outputs.detected-version }}
cache: true
# ╭──────────────────────────────────────────────────────────╮
# │ Dependency Review │
# ╰──────────────────────────────────────────────────────────╯
- name: Check Repository Visibility
id: repo-visibility
if: github.event_name == 'pull_request'
shell: sh
run: |
set -eu
is_private=$(jq -r '.repository.private' "$GITHUB_EVENT_PATH")
if [ "$is_private" = "false" ]; then
printf '%s\n' "is-public=true" >> "$GITHUB_OUTPUT"
fi
- name: Dependency Review
id: dependency-review
continue-on-error: true
if: >-
steps.repo-visibility.outputs.is-public == 'true'
&& github.event_name == 'pull_request'
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
with:
comment-summary-in-pr: always
fail-on-severity: critical
# ╭──────────────────────────────────────────────────────────╮
# │ MegaLinter │
# ╰──────────────────────────────────────────────────────────╯
- name: MegaLinter
# You can override MegaLinter flavor used to have faster performances
# More info at https://megalinter.io/latest/flavors/
uses: oxsecurity/megalinter/flavors/cupcake@42bb470545e359597e7f12156947c436e4e3fb9a # v9.3.0
uses: oxsecurity/megalinter/flavors/cupcake@8fbdead70d1409964ab3d5afa885e18ee85388bb # v9.4.0
id: ml
# All available variables are described in documentation
@@ -677,10 +704,17 @@ runs:
# Upload MegaLinter artifacts
- name: Archive production artifacts
if: success() || failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: MegaLinter reports
include-hidden-files: 'true'
path: |
megalinter-reports
mega-linter.log
- name: Fail if dependency review found critical issues
if: steps.dependency-review.outcome == 'failure'
shell: sh
run: |
printf '%s\n' "Dependency review found critical issues" >&2
exit 1

View File

@@ -274,7 +274,7 @@ runs:
echo "Detected package manager: $package_manager"
- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '24'
@@ -305,7 +305,7 @@ runs:
- name: Setup Bun
if: steps.detect-pm.outputs.package-manager == 'bun'
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3 # v2.1.2
uses: oven-sh/setup-bun@ecf28ddc73e819eb6fa29df6b34ef8921c743461 # v2.1.3
with:
bun-version: latest

View File

@@ -370,7 +370,7 @@ runs:
- name: Upload SARIF Report
if: steps.check-files.outputs.result == 'found'
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: ${{ inputs.working-directory }}/reports/flake8.sarif
category: 'python-lint'

View File

@@ -99,7 +99,7 @@ runs:
- name: Run actionlint
if: steps.check-configs.outputs.run_actionlint == 'true'
uses: raven-actions/actionlint@e01d1ea33dd6a5ed517d95b4c0c357560ac6f518 # v2.1.1
uses: raven-actions/actionlint@205b530c5d9fa8f44ae9ed59f341a0db994aa6f8 # v2.1.2
with:
cache: true
fail-on-error: true
@@ -161,21 +161,21 @@ runs:
- name: Upload Trivy results
if: steps.verify-sarif.outputs.has_trivy == 'true'
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: 'trivy-results.sarif'
category: 'trivy'
- name: Upload Gitleaks results
if: steps.verify-sarif.outputs.has_gitleaks == 'true'
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: 'gitleaks-report.sarif'
category: 'gitleaks'
- name: Archive security reports
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: security-reports-${{ github.run_id }}
path: |

View File

@@ -128,7 +128,7 @@ runs:
- name: Setup Terraform
if: steps.check-files.outputs.found == 'true'
uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # v4.0.0
with:
terraform_version: ${{ inputs.terraform-version }}
terraform_wrapper: false
@@ -256,7 +256,7 @@ runs:
- name: Upload SARIF Report
if: steps.check-files.outputs.found == 'true' && inputs.format == 'sarif'
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
with:
sarif_file: ${{ env.VALIDATED_WORKING_DIR }}/reports/tflint.sarif
category: terraform-lint

38
uv.lock generated
View File

@@ -299,27 +299,27 @@ wheels = [
[[package]]
name = "ruff"
version = "0.15.2"
version = "0.15.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" }
sdist = { url = "https://files.pythonhosted.org/packages/77/9b/840e0039e65fcf12758adf684d2289024d6140cde9268cc59887dc55189c/ruff-0.15.5.tar.gz", hash = "sha256:7c3601d3b6d76dce18c5c824fc8d06f4eef33d6df0c21ec7799510cde0f159a2", size = 4574214, upload-time = "2026-03-05T20:06:34.946Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" },
{ url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" },
{ url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" },
{ url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" },
{ url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" },
{ url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" },
{ url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" },
{ url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" },
{ url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" },
{ url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" },
{ url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" },
{ url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" },
{ url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" },
{ url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" },
{ url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" },
{ url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" },
{ url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" },
{ url = "https://files.pythonhosted.org/packages/47/20/5369c3ce21588c708bcbe517a8fbe1a8dfdb5dfd5137e14790b1da71612c/ruff-0.15.5-py3-none-linux_armv6l.whl", hash = "sha256:4ae44c42281f42e3b06b988e442d344a5b9b72450ff3c892e30d11b29a96a57c", size = 10478185, upload-time = "2026-03-05T20:06:29.093Z" },
{ url = "https://files.pythonhosted.org/packages/44/ed/e81dd668547da281e5dce710cf0bc60193f8d3d43833e8241d006720e42b/ruff-0.15.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6edd3792d408ebcf61adabc01822da687579a1a023f297618ac27a5b51ef0080", size = 10859201, upload-time = "2026-03-05T20:06:32.632Z" },
{ url = "https://files.pythonhosted.org/packages/c4/8f/533075f00aaf19b07c5cd6aa6e5d89424b06b3b3f4583bfa9c640a079059/ruff-0.15.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:89f463f7c8205a9f8dea9d658d59eff49db05f88f89cc3047fb1a02d9f344010", size = 10184752, upload-time = "2026-03-05T20:06:40.312Z" },
{ url = "https://files.pythonhosted.org/packages/66/0e/ba49e2c3fa0395b3152bad634c7432f7edfc509c133b8f4529053ff024fb/ruff-0.15.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba786a8295c6574c1116704cf0b9e6563de3432ac888d8f83685654fe528fd65", size = 10534857, upload-time = "2026-03-05T20:06:19.581Z" },
{ url = "https://files.pythonhosted.org/packages/59/71/39234440f27a226475a0659561adb0d784b4d247dfe7f43ffc12dd02e288/ruff-0.15.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd4b801e57955fe9f02b31d20375ab3a5c4415f2e5105b79fb94cf2642c91440", size = 10309120, upload-time = "2026-03-05T20:06:00.435Z" },
{ url = "https://files.pythonhosted.org/packages/f5/87/4140aa86a93df032156982b726f4952aaec4a883bb98cb6ef73c347da253/ruff-0.15.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391f7c73388f3d8c11b794dbbc2959a5b5afe66642c142a6effa90b45f6f5204", size = 11047428, upload-time = "2026-03-05T20:05:51.867Z" },
{ url = "https://files.pythonhosted.org/packages/5a/f7/4953e7e3287676f78fbe85e3a0ca414c5ca81237b7575bdadc00229ac240/ruff-0.15.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc18f30302e379fe1e998548b0f5e9f4dff907f52f73ad6da419ea9c19d66c8", size = 11914251, upload-time = "2026-03-05T20:06:22.887Z" },
{ url = "https://files.pythonhosted.org/packages/77/46/0f7c865c10cf896ccf5a939c3e84e1cfaeed608ff5249584799a74d33835/ruff-0.15.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc6e7f90087e2d27f98dc34ed1b3ab7c8f0d273cc5431415454e22c0bd2a681", size = 11333801, upload-time = "2026-03-05T20:05:57.168Z" },
{ url = "https://files.pythonhosted.org/packages/d3/01/a10fe54b653061585e655f5286c2662ebddb68831ed3eaebfb0eb08c0a16/ruff-0.15.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cb7169f53c1ddb06e71a9aebd7e98fc0fea936b39afb36d8e86d36ecc2636a", size = 11206821, upload-time = "2026-03-05T20:06:03.441Z" },
{ url = "https://files.pythonhosted.org/packages/7a/0d/2132ceaf20c5e8699aa83da2706ecb5c5dcdf78b453f77edca7fb70f8a93/ruff-0.15.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9b037924500a31ee17389b5c8c4d88874cc6ea8e42f12e9c61a3d754ff72f1ca", size = 11133326, upload-time = "2026-03-05T20:06:25.655Z" },
{ url = "https://files.pythonhosted.org/packages/72/cb/2e5259a7eb2a0f87c08c0fe5bf5825a1e4b90883a52685524596bfc93072/ruff-0.15.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65bb414e5b4eadd95a8c1e4804f6772bbe8995889f203a01f77ddf2d790929dd", size = 10510820, upload-time = "2026-03-05T20:06:37.79Z" },
{ url = "https://files.pythonhosted.org/packages/ff/20/b67ce78f9e6c59ffbdb5b4503d0090e749b5f2d31b599b554698a80d861c/ruff-0.15.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d20aa469ae3b57033519c559e9bc9cd9e782842e39be05b50e852c7c981fa01d", size = 10302395, upload-time = "2026-03-05T20:05:54.504Z" },
{ url = "https://files.pythonhosted.org/packages/5f/e5/719f1acccd31b720d477751558ed74e9c88134adcc377e5e886af89d3072/ruff-0.15.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:15388dd28c9161cdb8eda68993533acc870aa4e646a0a277aa166de9ad5a8752", size = 10754069, upload-time = "2026-03-05T20:06:06.422Z" },
{ url = "https://files.pythonhosted.org/packages/c3/9c/d1db14469e32d98f3ca27079dbd30b7b44dbb5317d06ab36718dee3baf03/ruff-0.15.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b30da330cbd03bed0c21420b6b953158f60c74c54c5f4c1dabbdf3a57bf355d2", size = 11304315, upload-time = "2026-03-05T20:06:10.867Z" },
{ url = "https://files.pythonhosted.org/packages/28/3a/950367aee7c69027f4f422059227b290ed780366b6aecee5de5039d50fa8/ruff-0.15.5-py3-none-win32.whl", hash = "sha256:732e5ee1f98ba5b3679029989a06ca39a950cced52143a0ea82a2102cb592b74", size = 10551676, upload-time = "2026-03-05T20:06:13.705Z" },
{ url = "https://files.pythonhosted.org/packages/b8/00/bf077a505b4e649bdd3c47ff8ec967735ce2544c8e4a43aba42ee9bf935d/ruff-0.15.5-py3-none-win_amd64.whl", hash = "sha256:821d41c5fa9e19117616c35eaa3f4b75046ec76c65e7ae20a333e9a8696bc7fe", size = 11678972, upload-time = "2026-03-05T20:06:45.379Z" },
{ url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" },
]
[[package]]

View File

@@ -332,7 +332,7 @@ class CustomValidator(BaseValidator):
## Quality Metrics
- **Test Coverage**: 100% (769 tests)
- **Test Coverage**: 100%
- **Validators**: 9 specialized + unlimited custom
- **Performance**: < 10ms typical validation time
- **Zero Dependencies**: Uses only Python stdlib + PyYAML

View File

@@ -310,10 +310,6 @@ class ValidationRuleGenerator:
"common-file-check": {
"file-pattern": "file_path",
},
"common-retry": {
"backoff-strategy": "backoff_strategy",
"shell": "shell_type",
},
"docker-publish": {
"registry": "registry_enum",
"cache-mode": "cache_mode",

View File

@@ -1,74 +0,0 @@
"""Tests for common-retry custom validator.
Generated by generate-tests.py - Do not edit manually.
"""
# pylint: disable=invalid-name # Test file name matches action name
import sys
from pathlib import Path
# Add action directory to path to import custom validator
action_path = Path(__file__).parent.parent.parent / "common-retry"
sys.path.insert(0, str(action_path))
# pylint: disable=wrong-import-position
from CustomValidator import CustomValidator
class TestCustomCommonRetryValidator:
"""Test cases for common-retry custom validator."""
def setup_method(self):
"""Set up test fixtures."""
self.validator = CustomValidator("common-retry")
def teardown_method(self):
"""Clean up after tests."""
self.validator.clear_errors()
def test_validate_inputs_valid(self):
"""Test validation with valid inputs."""
# TODO: Add specific valid inputs for common-retry
inputs = {}
result = self.validator.validate_inputs(inputs)
# Adjust assertion based on required inputs
assert isinstance(result, bool)
def test_validate_inputs_invalid(self):
"""Test validation with invalid inputs."""
# TODO: Add specific invalid inputs for common-retry
inputs = {"invalid_key": "invalid_value"}
result = self.validator.validate_inputs(inputs)
# Custom validators may have specific validation rules
assert isinstance(result, bool)
def test_required_inputs(self):
"""Test required inputs detection."""
required = self.validator.get_required_inputs()
assert isinstance(required, list)
# TODO: Assert specific required inputs for common-retry
def test_validation_rules(self):
"""Test validation rules."""
rules = self.validator.get_validation_rules()
assert isinstance(rules, dict)
# TODO: Assert specific validation rules for common-retry
def test_github_expressions(self):
"""Test GitHub expression handling."""
inputs = {
"test_input": "${{ github.token }}",
}
result = self.validator.validate_inputs(inputs)
assert isinstance(result, bool)
# GitHub expressions should generally be accepted
def test_error_propagation(self):
"""Test error propagation from sub-validators."""
# Custom validators often use sub-validators
# Test that errors are properly propagated
inputs = {"test": "value"}
self.validator.validate_inputs(inputs)
# Check error handling
if self.validator.has_errors():
assert len(self.validator.errors) > 0

View File

@@ -631,27 +631,27 @@ wheels = [
[[package]]
name = "ruff"
version = "0.15.2"
version = "0.15.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/06/04/eab13a954e763b0606f460443fcbf6bb5a0faf06890ea3754ff16523dce5/ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342", size = 4558148, upload-time = "2026-02-19T22:32:20.271Z" }
sdist = { url = "https://files.pythonhosted.org/packages/77/9b/840e0039e65fcf12758adf684d2289024d6140cde9268cc59887dc55189c/ruff-0.15.5.tar.gz", hash = "sha256:7c3601d3b6d76dce18c5c824fc8d06f4eef33d6df0c21ec7799510cde0f159a2", size = 4574214, upload-time = "2026-03-05T20:06:34.946Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2f/70/3a4dc6d09b13cb3e695f28307e5d889b2e1a66b7af9c5e257e796695b0e6/ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d", size = 10430565, upload-time = "2026-02-19T22:32:41.824Z" },
{ url = "https://files.pythonhosted.org/packages/71/0b/bb8457b56185ece1305c666dc895832946d24055be90692381c31d57466d/ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e", size = 10820354, upload-time = "2026-02-19T22:32:07.366Z" },
{ url = "https://files.pythonhosted.org/packages/2d/c1/e0532d7f9c9e0b14c46f61b14afd563298b8b83f337b6789ddd987e46121/ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87", size = 10170767, upload-time = "2026-02-19T22:32:13.188Z" },
{ url = "https://files.pythonhosted.org/packages/47/e8/da1aa341d3af017a21c7a62fb5ec31d4e7ad0a93ab80e3a508316efbcb23/ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9", size = 10529591, upload-time = "2026-02-19T22:32:02.547Z" },
{ url = "https://files.pythonhosted.org/packages/93/74/184fbf38e9f3510231fbc5e437e808f0b48c42d1df9434b208821efcd8d6/ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80", size = 10260771, upload-time = "2026-02-19T22:32:36.938Z" },
{ url = "https://files.pythonhosted.org/packages/05/ac/605c20b8e059a0bc4b42360414baa4892ff278cec1c91fff4be0dceedefd/ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f", size = 11045791, upload-time = "2026-02-19T22:32:31.642Z" },
{ url = "https://files.pythonhosted.org/packages/fd/52/db6e419908f45a894924d410ac77d64bdd98ff86901d833364251bd08e22/ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77", size = 11879271, upload-time = "2026-02-19T22:32:29.305Z" },
{ url = "https://files.pythonhosted.org/packages/3e/d8/7992b18f2008bdc9231d0f10b16df7dda964dbf639e2b8b4c1b4e91b83af/ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea", size = 11303707, upload-time = "2026-02-19T22:32:22.492Z" },
{ url = "https://files.pythonhosted.org/packages/d7/02/849b46184bcfdd4b64cde61752cc9a146c54759ed036edd11857e9b8443b/ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a", size = 11149151, upload-time = "2026-02-19T22:32:44.234Z" },
{ url = "https://files.pythonhosted.org/packages/70/04/f5284e388bab60d1d3b99614a5a9aeb03e0f333847e2429bebd2aaa1feec/ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956", size = 11091132, upload-time = "2026-02-19T22:32:24.691Z" },
{ url = "https://files.pythonhosted.org/packages/fa/ae/88d844a21110e14d92cf73d57363fab59b727ebeabe78009b9ccb23500af/ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4", size = 10504717, upload-time = "2026-02-19T22:32:26.75Z" },
{ url = "https://files.pythonhosted.org/packages/64/27/867076a6ada7f2b9c8292884ab44d08fd2ba71bd2b5364d4136f3cd537e1/ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de", size = 10263122, upload-time = "2026-02-19T22:32:10.036Z" },
{ url = "https://files.pythonhosted.org/packages/e7/ef/faf9321d550f8ebf0c6373696e70d1758e20ccdc3951ad7af00c0956be7c/ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c", size = 10735295, upload-time = "2026-02-19T22:32:39.227Z" },
{ url = "https://files.pythonhosted.org/packages/2f/55/e8089fec62e050ba84d71b70e7834b97709ca9b7aba10c1a0b196e493f97/ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8", size = 11241641, upload-time = "2026-02-19T22:32:34.617Z" },
{ url = "https://files.pythonhosted.org/packages/23/01/1c30526460f4d23222d0fabd5888868262fd0e2b71a00570ca26483cd993/ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f", size = 10507885, upload-time = "2026-02-19T22:32:15.635Z" },
{ url = "https://files.pythonhosted.org/packages/5c/10/3d18e3bbdf8fc50bbb4ac3cc45970aa5a9753c5cb51bf9ed9a3cd8b79fa3/ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5", size = 11623725, upload-time = "2026-02-19T22:32:04.947Z" },
{ url = "https://files.pythonhosted.org/packages/6d/78/097c0798b1dab9f8affe73da9642bb4500e098cb27fd8dc9724816ac747b/ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e", size = 10941649, upload-time = "2026-02-19T22:32:18.108Z" },
{ url = "https://files.pythonhosted.org/packages/47/20/5369c3ce21588c708bcbe517a8fbe1a8dfdb5dfd5137e14790b1da71612c/ruff-0.15.5-py3-none-linux_armv6l.whl", hash = "sha256:4ae44c42281f42e3b06b988e442d344a5b9b72450ff3c892e30d11b29a96a57c", size = 10478185, upload-time = "2026-03-05T20:06:29.093Z" },
{ url = "https://files.pythonhosted.org/packages/44/ed/e81dd668547da281e5dce710cf0bc60193f8d3d43833e8241d006720e42b/ruff-0.15.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6edd3792d408ebcf61adabc01822da687579a1a023f297618ac27a5b51ef0080", size = 10859201, upload-time = "2026-03-05T20:06:32.632Z" },
{ url = "https://files.pythonhosted.org/packages/c4/8f/533075f00aaf19b07c5cd6aa6e5d89424b06b3b3f4583bfa9c640a079059/ruff-0.15.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:89f463f7c8205a9f8dea9d658d59eff49db05f88f89cc3047fb1a02d9f344010", size = 10184752, upload-time = "2026-03-05T20:06:40.312Z" },
{ url = "https://files.pythonhosted.org/packages/66/0e/ba49e2c3fa0395b3152bad634c7432f7edfc509c133b8f4529053ff024fb/ruff-0.15.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba786a8295c6574c1116704cf0b9e6563de3432ac888d8f83685654fe528fd65", size = 10534857, upload-time = "2026-03-05T20:06:19.581Z" },
{ url = "https://files.pythonhosted.org/packages/59/71/39234440f27a226475a0659561adb0d784b4d247dfe7f43ffc12dd02e288/ruff-0.15.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd4b801e57955fe9f02b31d20375ab3a5c4415f2e5105b79fb94cf2642c91440", size = 10309120, upload-time = "2026-03-05T20:06:00.435Z" },
{ url = "https://files.pythonhosted.org/packages/f5/87/4140aa86a93df032156982b726f4952aaec4a883bb98cb6ef73c347da253/ruff-0.15.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391f7c73388f3d8c11b794dbbc2959a5b5afe66642c142a6effa90b45f6f5204", size = 11047428, upload-time = "2026-03-05T20:05:51.867Z" },
{ url = "https://files.pythonhosted.org/packages/5a/f7/4953e7e3287676f78fbe85e3a0ca414c5ca81237b7575bdadc00229ac240/ruff-0.15.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc18f30302e379fe1e998548b0f5e9f4dff907f52f73ad6da419ea9c19d66c8", size = 11914251, upload-time = "2026-03-05T20:06:22.887Z" },
{ url = "https://files.pythonhosted.org/packages/77/46/0f7c865c10cf896ccf5a939c3e84e1cfaeed608ff5249584799a74d33835/ruff-0.15.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc6e7f90087e2d27f98dc34ed1b3ab7c8f0d273cc5431415454e22c0bd2a681", size = 11333801, upload-time = "2026-03-05T20:05:57.168Z" },
{ url = "https://files.pythonhosted.org/packages/d3/01/a10fe54b653061585e655f5286c2662ebddb68831ed3eaebfb0eb08c0a16/ruff-0.15.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cb7169f53c1ddb06e71a9aebd7e98fc0fea936b39afb36d8e86d36ecc2636a", size = 11206821, upload-time = "2026-03-05T20:06:03.441Z" },
{ url = "https://files.pythonhosted.org/packages/7a/0d/2132ceaf20c5e8699aa83da2706ecb5c5dcdf78b453f77edca7fb70f8a93/ruff-0.15.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9b037924500a31ee17389b5c8c4d88874cc6ea8e42f12e9c61a3d754ff72f1ca", size = 11133326, upload-time = "2026-03-05T20:06:25.655Z" },
{ url = "https://files.pythonhosted.org/packages/72/cb/2e5259a7eb2a0f87c08c0fe5bf5825a1e4b90883a52685524596bfc93072/ruff-0.15.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65bb414e5b4eadd95a8c1e4804f6772bbe8995889f203a01f77ddf2d790929dd", size = 10510820, upload-time = "2026-03-05T20:06:37.79Z" },
{ url = "https://files.pythonhosted.org/packages/ff/20/b67ce78f9e6c59ffbdb5b4503d0090e749b5f2d31b599b554698a80d861c/ruff-0.15.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d20aa469ae3b57033519c559e9bc9cd9e782842e39be05b50e852c7c981fa01d", size = 10302395, upload-time = "2026-03-05T20:05:54.504Z" },
{ url = "https://files.pythonhosted.org/packages/5f/e5/719f1acccd31b720d477751558ed74e9c88134adcc377e5e886af89d3072/ruff-0.15.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:15388dd28c9161cdb8eda68993533acc870aa4e646a0a277aa166de9ad5a8752", size = 10754069, upload-time = "2026-03-05T20:06:06.422Z" },
{ url = "https://files.pythonhosted.org/packages/c3/9c/d1db14469e32d98f3ca27079dbd30b7b44dbb5317d06ab36718dee3baf03/ruff-0.15.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b30da330cbd03bed0c21420b6b953158f60c74c54c5f4c1dabbdf3a57bf355d2", size = 11304315, upload-time = "2026-03-05T20:06:10.867Z" },
{ url = "https://files.pythonhosted.org/packages/28/3a/950367aee7c69027f4f422059227b290ed780366b6aecee5de5039d50fa8/ruff-0.15.5-py3-none-win32.whl", hash = "sha256:732e5ee1f98ba5b3679029989a06ca39a950cced52143a0ea82a2102cb592b74", size = 10551676, upload-time = "2026-03-05T20:06:13.705Z" },
{ url = "https://files.pythonhosted.org/packages/b8/00/bf077a505b4e649bdd3c47ff8ec967735ce2544c8e4a43aba42ee9bf935d/ruff-0.15.5-py3-none-win_amd64.whl", hash = "sha256:821d41c5fa9e19117616c35eaa3f4b75046ec76c65e7ae20a333e9a8696bc7fe", size = 11678972, upload-time = "2026-03-05T20:06:45.379Z" },
{ url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" },
]
[[package]]