maintenance/maint release utils#652
Conversation
- `dependabot-auto-merge` no longer needs `WORKFLOW_PAT` - `guardrail-audit-alert` to report to Slack on safeguard bypass by admins (e.g. push to `main`, merge without approval).
📝 WalkthroughWalkthroughAdds four Bash release automation scripts ( ChangesCI/CD Workflow Changes
Release Automation Scripts
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
31 fixed, 0 new since branch point (0f6474d) ✅ 31 CodeQL alerts resolved since the previous PR commit
✅ 31 CodeQL alerts resolved since the branch point
Review the full CodeQL report for details. |
There was a problem hiding this comment.
Actionable comments posted: 10
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/dependabot-auto-merge.yaml:
- Around line 15-19: The comment on the `repository-projects: write` permission
line is technically inaccurate. The comment claims this permission is required
to modify repository settings via API, but `repository-projects` actually
governs GitHub Projects (kanban boards) functionality, not repository
administration. The PATCH endpoint for auto_merge requires write permissions
which come from GITHUB_TOKEN's elevated privileges in workflows. Replace the
misleading comment with one that either accurately explains why
`repository-projects: write` is necessary for the dependabot auto-merge workflow
(documenting any non-obvious reasons), or clarify that GITHUB_TOKEN provides the
necessary access despite the unexpected permission scope name.
In @.github/workflows/guardrail-audit-alert.yaml:
- Around line 20-32: Add a guard check to validate that the SLACK_URL secret is
configured before attempting to use it in the curl command. Within the existing
if block that checks if the committer is not 'GitHub', add an additional
condition to verify that SLACK_URL is not empty. If SLACK_URL is missing or
empty, either exit with an error message to surface the configuration issue or
add a separate guard that returns early, preventing the curl command from
executing with an empty webhook URL and ensuring configuration problems are
caught immediately rather than failing silently.
- Around line 25-29: The jq command constructing the PAYLOAD variable on line 29
exceeds yamllint's 120-character limit at 127 characters. Fix this by either
adding a yamllint disable comment at the end of line 29 with `# yamllint
disable-line rule:line-length`, or alternatively, restructure the PAYLOAD
assignment to break the jq filter string across multiple lines for better
readability while staying within the character limit.
In `@scripts/release/01-detect-tier1.sh`:
- Around line 34-35: The comment for the git log command on line 33 states the
code checks for changes to "action.yaml or source files" but the pathspec in the
CHANGES variable assignment on line 34-35 only includes `-- action.yaml`. Either
update the comment to accurately reflect that only action.yaml changes are being
detected (if this is intentional), or expand the git log pathspec to include the
source files referenced in the comment by adding additional paths after
action.yaml in the `--` argument.
In `@scripts/release/02-execute-release.sh`:
- Line 62: The sed -i command in the release script is not portable between
macOS and Linux because BSD sed (macOS) requires an empty backup extension
argument while GNU sed (Linux) does not. Replace the sed -i invocation with
either sed -i '' to provide an empty backup extension that works on both
systems, or alternatively use perl -i -pe instead which provides consistent
behavior across both macOS and Linux platforms.
- Line 54: The jq query in the REPO_FULL_NAME assignment contains a typo in the
field name. Change `.nameWithOwnership` to `.nameWithOwner` in the gh repo view
command to correctly retrieve the repository name from the GitHub API. The typo
causes the query to return null, which will be incorrectly substituted into the
README.
- Around line 20-27: Replace the sed subprocess with bash parameter expansion to
strip the 'v' prefix from LATEST_TAG by using ${LATEST_TAG#v} instead of piping
through sed. Additionally, add validation to ensure LATEST_TAG follows the
expected vN pattern before performing arithmetic operations on VERSION_NUM,
since tags like v1.2.0 will cause the NEXT_NUM arithmetic expansion to fail
silently or produce unexpected results. Consider extracting only the major
version number or validating the tag format explicitly before the arithmetic
operation on line 23.
In `@scripts/release/trigger-dependabot.sh`:
- Around line 38-41: The local trigger branch stored in $TRIGGER_BRANCH is
created with git checkout but never deleted after the script completes. After
the script syncs back to the default branch (following the PR operations), add
an explicit git command to delete the local trigger branch by name to prevent
accumulation of stale local branches like
automation/trigger-dependabot-1718649600 on repeated script runs.
- Around line 67-73: The PR number extraction using grep -oE '[0-9]+$' on the
PR_URL output lacks validation and could silently produce an empty string or
incorrect value if the gh pr create command output format changes. Add a
defensive check immediately after the PR_NUMBER assignment that validates the
extracted value is not empty and contains only digits, and exit with a clear
error message if the validation fails. This prevents downstream commands like gh
pr close from failing with cryptic errors due to an invalid or empty PR number.
In `@scripts/release/view-dependabot-logs.sh`:
- Around line 23-37: The xdg-open command on line 26 suppresses stderr output
which masks failures when the browser fails to open (e.g., no $DISPLAY in
headless environments or no default browser configured). The script then prints
the success message regardless of whether the command actually succeeded. Remove
the `2>/dev/null` redirection from the xdg-open call to allow errors to surface,
and check the exit status of both xdg-open and open commands. Only print the
success message (the "⚡ Success: Browser session initialized." echo) after
confirming that one of the browser-opening commands actually succeeded by
checking their exit codes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 7a1c5b74-5f32-4518-8552-e9414ad94ceb
📒 Files selected for processing (6)
.github/workflows/dependabot-auto-merge.yaml.github/workflows/guardrail-audit-alert.yamlscripts/release/01-detect-tier1.shscripts/release/02-execute-release.shscripts/release/trigger-dependabot.shscripts/release/view-dependabot-logs.sh
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Framework-R-D/action-workflow-setup(auto-detected)Framework-R-D/action-complete-pr-comment(auto-detected)Framework-R-D/action-handle-fix-commit(auto-detected)
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze actions with CodeQL
🧰 Additional context used
🪛 GitHub Check: yaml-check
.github/workflows/guardrail-audit-alert.yaml
[warning] 29-29:
29:121 [line-length] line too long (127 > 120 characters)
[warning] 2-2:
2:1 [truthy] truthy value should be one of [false, true]
🪛 Shellcheck (0.11.0)
scripts/release/01-detect-tier1.sh
[style] 39-39: See if you can use ${variable//search/replace} instead.
(SC2001)
scripts/release/02-execute-release.sh
[style] 22-22: See if you can use ${variable//search/replace} instead.
(SC2001)
🪛 zizmor (1.25.2)
.github/workflows/dependabot-auto-merge.yaml
[error] 16-16: overly broad permissions (excessive-permissions): actions: write is overly broad at the workflow level
(excessive-permissions)
[error] 17-17: overly broad permissions (excessive-permissions): contents: write is overly broad at the workflow level
(excessive-permissions)
[error] 18-18: overly broad permissions (excessive-permissions): pull-requests: write is overly broad at the workflow level
(excessive-permissions)
[warning] 19-19: overly broad permissions (excessive-permissions): repository-projects: write is overly broad at the workflow level
(excessive-permissions)
[warning] 16-16: permissions without explanatory comments (undocumented-permissions): needs an explanatory comment
(undocumented-permissions)
.github/workflows/guardrail-audit-alert.yaml
[warning] 1-33: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block
(excessive-permissions)
[info] 7-7: workflow or action definition without a name (anonymous-definition): this job
(anonymous-definition)
[warning] 2-4: insufficient job-level concurrency limits (concurrency-limits): workflow is missing concurrency setting
(concurrency-limits)
🔀 Multi-repo context Framework-R-D/action-workflow-setup, Framework-R-D/action-complete-pr-comment, Framework-R-D/action-handle-fix-commit
Perfect! I now have comprehensive cross-repository context. Let me document my findings:
Linked repositories findings
Framework-R-D/action-workflow-setup
Dependabot Auto-Merge Workflow Consistency:
.github/workflows/dependabot-auto-merge.yaml:19— Identicalrepository-projects: writepermission added [::Framework-R-D/action-workflow-setup::].github/workflows/dependabot-auto-merge.yaml:61,68— BothGH_TOKENsteps usesecrets.GITHUB_TOKEN(replacedWORKFLOW_PAT) [::Framework-R-D/action-workflow-setup::]
Guardrail Alert Workflow Implementation:
.github/workflows/guardrail-audit-alert.yaml:1-32— Identical workflow deployed; triggers on main branch pushes withpermissions: {}and filters out dependabot [::Framework-R-D/action-workflow-setup::]- Requires
SLACK_WEBHOOK_URLsecret to be configured in the repository [::Framework-R-D/action-workflow-setup::]
Dependency Chain:
action.yaml:68,79,128— This action depends on three Framework-R-D sub-actions (action-prepare-check-outputs, action-prepare-fix-outputs, action-run-change-detection), each SHA-pinned [::Framework-R-D/action-workflow-setup::]RELEASES.md:163-172— Release procedure documents dependent action updates required after any new version [::Framework-R-D/action-workflow-setup::]
Framework-R-D/action-complete-pr-comment
Identical Workflow Changes:
.github/workflows/dependabot-auto-merge.yaml:19,61,68— Matches action-workflow-setup changes exactly [::Framework-R-D/action-complete-pr-comment::].github/workflows/guardrail-audit-alert.yaml:1-32— Identical guardrail workflow [::Framework-R-D/action-complete-pr-comment::]
Permission Requirements:
- Uses
actions/github-script@v9.0.0which requiresissues: writepermission per action.yaml description [::Framework-R-D/action-complete-pr-comment::]
Framework-R-D/action-handle-fix-commit
Identical Workflow Changes:
.github/workflows/dependabot-auto-merge.yaml:19,61,68— Matches the other repositories [::Framework-R-D/action-handle-fix-commit::].github/workflows/guardrail-audit-alert.yaml:1-32— Identical guardrail workflow [::Framework-R-D/action-handle-fix-commit::]
Critical Token Configuration:
action.yaml:30-31— Requires explicittokeninput parameter (a PAT) for commit operations; this is distinct from the workflowGITHUB_TOKEN[::Framework-R-D/action-handle-fix-commit::].github/workflows/dependabot-auto-merge.yamlworkflow change does NOT affect this action's token input requirement [::Framework-R-D/action-handle-fix-commit::]
Cross-Repository Consistency Check
Uniform Changes Across All Three Action Repositories:
All three consumer actions have been updated with identical changes:
repository-projects: writepermission added to enable auto-merge API callsGITHUB_TOKENreplacesWORKFLOW_PATin the dependabot merge automation- New guardrail-audit-alert workflow deployed to all three with Slack integration requirement
No Breaking Changes Detected:
- The PR changes are consistent and uniform across repositories
- The switch from
WORKFLOW_PATtoGITHUB_TOKENis a maintenance improvement with sufficient permissions (repository-projects: writeenables theallow_auto_merge=truePATCH call needed at line 91) - The guardrail workflow adds new functionality without affecting existing workflows
- Release scripts reference the correct action structure and dependency patterns
🔇 Additional comments (14)
.github/workflows/dependabot-auto-merge.yaml (2)
63-68: LGTM!
70-121: LGTM!.github/workflows/guardrail-audit-alert.yaml (1)
1-10: LGTM!scripts/release/trigger-dependabot.sh (4)
1-11: LGTM!
18-36: Solid fallback chain for remote resolution.The three-level fallback (current branch tracking → main's tracking → first listed remote) handles most fork/upstream scenarios nicely. The
|| trueguards preventset -efrom killing the script on missing configs, which is the right call here.
43-60: LGTM!
62-66: LGTM!Also applies to: 74-85
scripts/release/view-dependabot-logs.sh (2)
1-11: LGTM!
13-21: LGTM!scripts/release/01-detect-tier1.sh (2)
1-27: LGTM!
37-44: LGTM!scripts/release/02-execute-release.sh (3)
1-18: LGTM!
29-43: LGTM!
64-69: LGTM!
| permissions: | ||
| actions: write | ||
| contents: write | ||
| pull-requests: write | ||
| repository-projects: write # Required if the token needs to modify repository settings via API |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if there are any existing workflows or docs that clarify the permission requirements
rg -n -C3 'allow_auto_merge|repository-projects' --type yamlRepository: Framework-R-D/phlex
Length of output: 45
🏁 Script executed:
#!/bin/bash
# Check if the workflow file exists and read its actual content
if [ -f ".github/workflows/dependabot-auto-merge.yaml" ]; then
echo "=== File exists, reading content ==="
cat -n ".github/workflows/dependabot-auto-merge.yaml"
else
echo "=== File not found, listing .github/workflows ==="
ls -la .github/workflows/ 2>/dev/null || echo "No .github/workflows directory"
fiRepository: Framework-R-D/phlex
Length of output: 6769
🌐 Web query:
GitHub API PATCH repos allow_auto_merge permission required
💡 Result:
To update the allow_auto_merge setting for a repository using the GitHub REST API PATCH /repos/{owner}/{repo} endpoint, the authenticated user must have repository write permissions [1][2][3]. Specifically, the following requirements apply: 1. Permission Level: You must have admin or maintainer access to the repository to successfully perform this update [3]. 2. Authentication: If you are using a fine-grained personal access token or a GitHub App, ensure the token has the necessary repository-level permissions. For fine-grained tokens, the write access to the repository is generally required to modify repository settings [1][2]. 3. API Usage: The PATCH request must include the allow_auto_merge parameter in the body, set to true or false [4][3]. Example request: curl -X PATCH -H "Accept: application/vnd.github+json" -H "Authorization: Bearer " https://api.github.com/repos/OWNER/REPO -d '{"allow_auto_merge":true}' [5][3] Note: This setting enables the ability to use auto-merge within the repository [6]. If you are trying to enable auto-merge on an individual pull request rather than enabling the feature for the entire repository, you must use the GraphQL API mutation enablePullRequestAutoMerge instead [5].
Citations:
- 1: https://docs.github.com/en/rest/authentication/permissions-required-for-fine-grained-personal-access-tokens?apiVersion=2022-11-28
- 2: https://docs.github.com/en/rest/authentication/permissions-required-for-github-apps
- 3: https://www.withone.ai/knowledge/github/conn_mod_def%3A%3AGJ3aOe9-Gvc%3A%3AE993VLqyR_mi3915bjgDGw/md
- 4: https://www.simworkflow.com/integration-operation/github-repos-owner-repo-patch-f36
- 5: https://stackoverflow.com/questions/69916356/how-do-i-enable-auto-merge-on-a-github-pull-request-via-the-rest-api
- 6: https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-auto-merge-for-pull-requests-in-your-repository
🌐 Web query:
GitHub permission scope repository-projects what permissions does it grant
💡 Result:
The repository-projects permission scope grants access to interact with GitHub Projects associated with a repository [1]. Specifically, it provides read and write access to repository-level projects [1]. In contexts such as GitHub Codespaces configuration, this permission allows authorized entities to perform operations like viewing, creating, or editing projects linked to that specific repository [1]. While the exact level of access (read vs. write) depends on the specific implementation or configuration, it is generally treated as a distinct permission required to manage project boards and their items within the repository's scope [1]. It is important to note that this scope is distinct from broader project management scopes (such as the general project scope used for organization-wide or user-owned projects) [2][3]. Because repository projects are often treated as distinct resources, repository-projects ensures that automation or applications can manage these specific boards without requiring broader, higher-privilege access to all organization-level or personal projects [2][1].
Citations:
- 1: https://github.com/github/docs/blob/main/content/codespaces/managing-your-codespaces/managing-repository-access-for-your-codespaces.md
- 2: https://github.github.com/gh-aw/reference/auth-projects/
- 3: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps
Fix the misleading comment about the permission requirement on line 19.
The comment states repository-projects: write is "Required if the token needs to modify repository settings via API," but repository-projects permission specifically governs GitHub Projects (kanban boards), not repository administration. According to GitHub's API documentation, the PATCH endpoint for allow_auto_merge requires admin/maintainer access or repository write permissions—not the Projects scope.
This permission likely works in practice because secrets.GITHUB_TOKEN in workflows has elevated permissions, but the comment's explanation is technically inaccurate and will confuse future maintainers. Either correct the comment to explain that GITHUB_TOKEN grants the necessary access despite the unusual permission name, or explicitly document why repository-projects: write is present if there's a non-obvious reason.
🧰 Tools
🪛 zizmor (1.25.2)
[error] 16-16: overly broad permissions (excessive-permissions): actions: write is overly broad at the workflow level
(excessive-permissions)
[error] 17-17: overly broad permissions (excessive-permissions): contents: write is overly broad at the workflow level
(excessive-permissions)
[error] 18-18: overly broad permissions (excessive-permissions): pull-requests: write is overly broad at the workflow level
(excessive-permissions)
[warning] 19-19: overly broad permissions (excessive-permissions): repository-projects: write is overly broad at the workflow level
(excessive-permissions)
[warning] 16-16: permissions without explanatory comments (undocumented-permissions): needs an explanatory comment
(undocumented-permissions)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/dependabot-auto-merge.yaml around lines 15 - 19, The
comment on the `repository-projects: write` permission line is technically
inaccurate. The comment claims this permission is required to modify repository
settings via API, but `repository-projects` actually governs GitHub Projects
(kanban boards) functionality, not repository administration. The PATCH endpoint
for auto_merge requires write permissions which come from GITHUB_TOKEN's
elevated privileges in workflows. Replace the misleading comment with one that
either accurately explains why `repository-projects: write` is necessary for the
dependabot auto-merge workflow (documenting any non-obvious reasons), or clarify
that GITHUB_TOKEN provides the necessary access despite the unexpected
permission scope name.
| run: | | ||
| # If the committer isn't 'GitHub', an admin pushed directly via local CLI. | ||
| if [ "$COMMITTER" != "GitHub" ]; then | ||
|
|
||
| # Use jq to format a completely safe, escaped JSON object for Slack | ||
| PAYLOAD=$(jq -n \ | ||
| --arg msg "$COMMIT_MSG" \ | ||
| --arg repo "$REPO_NAME" \ | ||
| --arg actor "$ACTOR" \ | ||
| '{"text": "⚠️ *Direct Push to Main Detected!*\n*Repo:* `\($repo)`\n*Actor:* `@\($actor)`\n*Commit:* `\($msg)`"}') | ||
|
|
||
| curl -X POST -H 'Content-type: application/json' --data "$PAYLOAD" "$SLACK_URL" | ||
| fi |
There was a problem hiding this comment.
Consider adding a guard for missing SLACK_WEBHOOK_URL.
If the secret isn't configured in a new repo, this will fail silently (or curl will try to POST to an empty string). Adding a quick check would surface configuration issues faster:
run: |
+ if [ -z "$SLACK_URL" ]; then
+ echo "::warning::SLACK_WEBHOOK_URL secret is not configured - skipping alert"
+ exit 0
+ fi
# If the committer isn't 'GitHub', an admin pushed directly via local CLI.Also, kudos on using jq for the payload construction—that's the right call to avoid injection issues from funky commit messages.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| run: | | |
| # If the committer isn't 'GitHub', an admin pushed directly via local CLI. | |
| if [ "$COMMITTER" != "GitHub" ]; then | |
| # Use jq to format a completely safe, escaped JSON object for Slack | |
| PAYLOAD=$(jq -n \ | |
| --arg msg "$COMMIT_MSG" \ | |
| --arg repo "$REPO_NAME" \ | |
| --arg actor "$ACTOR" \ | |
| '{"text": "⚠️ *Direct Push to Main Detected!*\n*Repo:* `\($repo)`\n*Actor:* `@\($actor)`\n*Commit:* `\($msg)`"}') | |
| curl -X POST -H 'Content-type: application/json' --data "$PAYLOAD" "$SLACK_URL" | |
| fi | |
| run: | | |
| if [ -z "$SLACK_URL" ]; then | |
| echo "::warning::SLACK_WEBHOOK_URL secret is not configured - skipping alert" | |
| exit 0 | |
| fi | |
| # If the committer isn't 'GitHub', an admin pushed directly via local CLI. | |
| if [ "$COMMITTER" != "GitHub" ]; then | |
| # Use jq to format a completely safe, escaped JSON object for Slack | |
| PAYLOAD=$(jq -n \ | |
| --arg msg "$COMMIT_MSG" \ | |
| --arg repo "$REPO_NAME" \ | |
| --arg actor "$ACTOR" \ | |
| '{"text": "⚠️ *Direct Push to Main Detected!*\n*Repo:* `\($repo)`\n*Actor:* `@\($actor)`\n*Commit:* `\($msg)`"}') | |
| curl -X POST -H 'Content-type: application/json' --data "$PAYLOAD" "$SLACK_URL" | |
| fi |
🧰 Tools
🪛 GitHub Check: yaml-check
[warning] 29-29:
29:121 [line-length] line too long (127 > 120 characters)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/guardrail-audit-alert.yaml around lines 20 - 32, Add a
guard check to validate that the SLACK_URL secret is configured before
attempting to use it in the curl command. Within the existing if block that
checks if the committer is not 'GitHub', add an additional condition to verify
that SLACK_URL is not empty. If SLACK_URL is missing or empty, either exit with
an error message to surface the configuration issue or add a separate guard that
returns early, preventing the curl command from executing with an empty webhook
URL and ensuring configuration problems are caught immediately rather than
failing silently.
| PAYLOAD=$(jq -n \ | ||
| --arg msg "$COMMIT_MSG" \ | ||
| --arg repo "$REPO_NAME" \ | ||
| --arg actor "$ACTOR" \ | ||
| '{"text": "⚠️ *Direct Push to Main Detected!*\n*Repo:* `\($repo)`\n*Actor:* `@\($actor)`\n*Commit:* `\($msg)`"}') |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Line 29 exceeds yamllint's 120-char limit (127 chars).
Split the jq heredoc for readability:
- PAYLOAD=$(jq -n \
- --arg msg "$COMMIT_MSG" \
- --arg repo "$REPO_NAME" \
- --arg actor "$ACTOR" \
- '{"text": "⚠️ *Direct Push to Main Detected!*\n*Repo:* `\($repo)`\n*Actor:* `@\($actor)`\n*Commit:* `\($msg)`"}')
+ PAYLOAD=$(jq -n \
+ --arg msg "$COMMIT_MSG" \
+ --arg repo "$REPO_NAME" \
+ --arg actor "$ACTOR" \
+ '{"text": "⚠️ *Direct Push to Main Detected!*\n*Repo:* `\($repo)`\n*Actor:* `@\($actor)`\n*Commit:* `\($msg | .[0:100])`"}')Actually, the cleaner fix is just to break the string literal—but since jq filter strings don't easily split, you could also just disable the lint for this line with a # yamllint disable-line rule:line-length comment if you prefer keeping it as-is.
🧰 Tools
🪛 GitHub Check: yaml-check
[warning] 29-29:
29:121 [line-length] line too long (127 > 120 characters)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/guardrail-audit-alert.yaml around lines 25 - 29, The jq
command constructing the PAYLOAD variable on line 29 exceeds yamllint's
120-character limit at 127 characters. Fix this by either adding a yamllint
disable comment at the end of line 29 with `# yamllint disable-line
rule:line-length`, or alternatively, restructure the PAYLOAD assignment to break
the jq filter string across multiple lines for better readability while staying
within the character limit.
Source: Linters/SAST tools
| # 3. Check for any commits touching action.yaml or source files since the latest tag | ||
| CHANGES=$(git log "${LATEST_TAG}..HEAD" --oneline -- action.yaml 2>/dev/null || echo "") |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Comment claims more than the code delivers.
The comment says "action.yaml or source files" but the git log only checks -- action.yaml. If that's intentional (since action.yaml is the public contract), update the comment. If you meant to catch other files (scripts, etc.), expand the pathspec.
- # 3. Check for any commits touching action.yaml or source files since the latest tag
- CHANGES=$(git log "${LATEST_TAG}..HEAD" --oneline -- action.yaml 2>/dev/null || echo "")
+ # 3. Check for any commits touching action.yaml since the latest tag
+ CHANGES=$(git log "${LATEST_TAG}..HEAD" --oneline -- action.yaml 2>/dev/null || echo "")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # 3. Check for any commits touching action.yaml or source files since the latest tag | |
| CHANGES=$(git log "${LATEST_TAG}..HEAD" --oneline -- action.yaml 2>/dev/null || echo "") | |
| # 3. Check for any commits touching action.yaml since the latest tag | |
| CHANGES=$(git log "${LATEST_TAG}..HEAD" --oneline -- action.yaml 2>/dev/null || echo "") |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/release/01-detect-tier1.sh` around lines 34 - 35, The comment for the
git log command on line 33 states the code checks for changes to "action.yaml or
source files" but the pathspec in the CHANGES variable assignment on line 34-35
only includes `-- action.yaml`. Either update the comment to accurately reflect
that only action.yaml changes are being detected (if this is intentional), or
expand the git log pathspec to include the source files referenced in the
comment by adding additional paths after action.yaml in the `--` argument.
| # Step 1: Calculate NEXT_VERSION increment rule | ||
| LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0") | ||
| VERSION_NUM=$(echo "$LATEST_TAG" | sed 's/v//') | ||
| NEXT_NUM=$((VERSION_NUM + 1)) | ||
| NEXT_VERSION="v${NEXT_NUM}" | ||
| TODAY=$(date +%Y-%m-%d) | ||
|
|
||
| echo "-> Current: $LATEST_TAG --> Targets Next: $NEXT_VERSION" |
There was a problem hiding this comment.
Use parameter expansion and guard against non-numeric tags.
The sed can be swapped for native bash expansion—one less subprocess. Also, if LATEST_TAG ever diverges from the vN pattern (e.g., v1.2.0), the arithmetic silently explodes.
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0")
-VERSION_NUM=$(echo "$LATEST_TAG" | sed 's/v//')
+VERSION_NUM="${LATEST_TAG#v}"
+if ! [[ "$VERSION_NUM" =~ ^[0-9]+$ ]]; then
+ echo "❌ ERROR: Latest tag '$LATEST_TAG' is not in expected 'vN' format."
+ exit 1
+fi
NEXT_NUM=$((VERSION_NUM + 1))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Step 1: Calculate NEXT_VERSION increment rule | |
| LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0") | |
| VERSION_NUM=$(echo "$LATEST_TAG" | sed 's/v//') | |
| NEXT_NUM=$((VERSION_NUM + 1)) | |
| NEXT_VERSION="v${NEXT_NUM}" | |
| TODAY=$(date +%Y-%m-%d) | |
| echo "-> Current: $LATEST_TAG --> Targets Next: $NEXT_VERSION" | |
| # Step 1: Calculate NEXT_VERSION increment rule | |
| LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0") | |
| VERSION_NUM="${LATEST_TAG#v}" | |
| if ! [[ "$VERSION_NUM" =~ ^[0-9]+$ ]]; then | |
| echo "❌ ERROR: Latest tag '$LATEST_TAG' is not in expected 'vN' format." | |
| exit 1 | |
| fi | |
| NEXT_NUM=$((VERSION_NUM + 1)) | |
| NEXT_VERSION="v${NEXT_NUM}" | |
| TODAY=$(date +%Y-%m-%d) | |
| echo "-> Current: $LATEST_TAG --> Targets Next: $NEXT_VERSION" |
🧰 Tools
🪛 Shellcheck (0.11.0)
[style] 22-22: See if you can use ${variable//search/replace} instead.
(SC2001)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/release/02-execute-release.sh` around lines 20 - 27, Replace the sed
subprocess with bash parameter expansion to strip the 'v' prefix from LATEST_TAG
by using ${LATEST_TAG#v} instead of piping through sed. Additionally, add
validation to ensure LATEST_TAG follows the expected vN pattern before
performing arithmetic operations on VERSION_NUM, since tags like v1.2.0 will
cause the NEXT_NUM arithmetic expansion to fail silently or produce unexpected
results. Consider extracting only the major version number or validating the tag
format explicitly before the arithmetic operation on line 23.
Source: Linters/SAST tools
| NEW_SHA=$(gh api "repos/{owner}/{repo}/git/tags/${NEW_SHA}" --jq .object.sha) | ||
| fi | ||
|
|
||
| REPO_FULL_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwnership') |
There was a problem hiding this comment.
Typo: .nameWithOwnership → .nameWithOwner
This jq query will return null because the GitHub API field is nameWithOwner (no trailing "ship"). The script will then substitute a literal null@<sha> into your README, which is... not ideal. 💀
-REPO_FULL_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwnership')
+REPO_FULL_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwner')📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| REPO_FULL_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwnership') | |
| REPO_FULL_NAME=$(gh repo view --json nameWithOwner --jq '.nameWithOwner') |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/release/02-execute-release.sh` at line 54, The jq query in the
REPO_FULL_NAME assignment contains a typo in the field name. Change
`.nameWithOwnership` to `.nameWithOwner` in the gh repo view command to
correctly retrieve the repository name from the GitHub API. The typo causes the
query to return null, which will be incorrectly substituted into the README.
| OLD_PATTERN="${REPO_FULL_NAME}@[0-9a-f]\{40\} # v[0-9]*" | ||
| NEW_STRING="${REPO_FULL_NAME}@${NEW_SHA} # ${NEXT_VERSION}" | ||
|
|
||
| sed -i "s|${OLD_PATTERN}|${NEW_STRING}|" README.md |
There was a problem hiding this comment.
sed -i isn't portable to macOS.
BSD sed (macOS default) requires a backup extension argument even if empty: sed -i ''. GNU sed (Linux) accepts bare -i. If anyone runs this from their Mac, it'll error out cryptically.
Portable workaround:
-sed -i "s|${OLD_PATTERN}|${NEW_STRING}|" README.md
+sed -i.bak "s|${OLD_PATTERN}|${NEW_STRING}|" README.md && rm -f README.md.bakOr if you're feeling fancy, use perl which is consistent across platforms:
perl -i -pe "s|${OLD_PATTERN}|${NEW_STRING}|" README.md🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/release/02-execute-release.sh` at line 62, The sed -i command in the
release script is not portable between macOS and Linux because BSD sed (macOS)
requires an empty backup extension argument while GNU sed (Linux) does not.
Replace the sed -i invocation with either sed -i '' to provide an empty backup
extension that works on both systems, or alternatively use perl -i -pe instead
which provides consistent behavior across both macOS and Linux platforms.
| # 3. Check out a temporary branch specifically for the trigger | ||
| echo "--> Creating local trigger branch..." | ||
| TRIGGER_BRANCH="automation/trigger-dependabot-$(date +%s)" | ||
| git checkout -b "$TRIGGER_BRANCH" -q |
There was a problem hiding this comment.
Local trigger branch is never cleaned up.
gh pr close --delete-branch only removes the remote branch. After the script completes, the local $TRIGGER_BRANCH remains orphaned in the user's repo. Repeated runs will accumulate stale local branches like automation/trigger-dependabot-1718649600.
Add explicit local branch cleanup after syncing to the default branch:
🧹 Proposed fix to delete the local trigger branch
# 9. Sync your default branch cleanly to ensure local tracking matches remote tip
echo "--> Synchronizing local default branch workspace..."
git checkout "$DEFAULT_BRANCH" -q
git pull --ff-only "$REMOTE_NAME" "$DEFAULT_BRANCH" -q
+git branch -D "$TRIGGER_BRANCH" -q 2>/dev/null || true
echo "⚡ SUCCESS: Dependabot has initialized an immediate version check cycle cleanly!"Also applies to: 78-78, 82-83
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/release/trigger-dependabot.sh` around lines 38 - 41, The local
trigger branch stored in $TRIGGER_BRANCH is created with git checkout but never
deleted after the script completes. After the script syncs back to the default
branch (following the PR operations), add an explicit git command to delete the
local trigger branch by name to prevent accumulation of stale local branches
like automation/trigger-dependabot-1718649600 on repeated script runs.
| PR_URL=$(gh pr create \ | ||
| --title "chore: dynamic version check sweep" \ | ||
| --body "Automated system trigger. Safe to delete." \ | ||
| --head "$TRIGGER_BRANCH") | ||
|
|
||
| PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$') | ||
| echo " PR Opened: #$PR_NUMBER" |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
PR number extraction could fail silently with an unhelpful error.
If gh pr create ever changes its output format or returns an error message instead of a URL, grep -oE '[0-9]+$' will produce an empty string (or wrong number), and gh pr close "" will fail cryptically. Consider validating the extracted value:
🛡️ Proposed defensive check
PR_URL=$(gh pr create \
--title "chore: dynamic version check sweep" \
--body "Automated system trigger. Safe to delete." \
--head "$TRIGGER_BRANCH")
PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$')
+if [ -z "$PR_NUMBER" ]; then
+ echo "❌ Error: Failed to extract PR number from: $PR_URL"
+ exit 1
+fi
echo " PR Opened: #$PR_NUMBER"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| PR_URL=$(gh pr create \ | |
| --title "chore: dynamic version check sweep" \ | |
| --body "Automated system trigger. Safe to delete." \ | |
| --head "$TRIGGER_BRANCH") | |
| PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$') | |
| echo " PR Opened: #$PR_NUMBER" | |
| PR_URL=$(gh pr create \ | |
| --title "chore: dynamic version check sweep" \ | |
| --body "Automated system trigger. Safe to delete." \ | |
| --head "$TRIGGER_BRANCH") | |
| PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$') | |
| if [ -z "$PR_NUMBER" ]; then | |
| echo "❌ Error: Failed to extract PR number from: $PR_URL" | |
| exit 1 | |
| fi | |
| echo " PR Opened: #$PR_NUMBER" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/release/trigger-dependabot.sh` around lines 67 - 73, The PR number
extraction using grep -oE '[0-9]+$' on the PR_URL output lacks validation and
could silently produce an empty string or incorrect value if the gh pr create
command output format changes. Add a defensive check immediately after the
PR_NUMBER assignment that validates the extracted value is not empty and
contains only digits, and exit with a clear error message if the validation
fails. This prevents downstream commands like gh pr close from failing with
cryptic errors due to an invalid or empty PR number.
| # 3. Detect operating system environment and trigger the native window engine | ||
| if command -v xdg-open >/dev/null 2>&1; then | ||
| # Linux environment handler | ||
| xdg-open "$TARGET_LOG_PAGE" 2>/dev/null | ||
| elif command -v open >/dev/null 2>&1; then | ||
| # macOS environment handler | ||
| open "$TARGET_LOG_PAGE" | ||
| else | ||
| echo "❌ Error: Could not detect a desktop environment opener utility (xdg-open or open)." | ||
| echo " Please open this link manually instead:" | ||
| echo " $TARGET_LOG_PAGE" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "⚡ Success: Browser session initialized." |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | 💤 Low value
Suppressing stderr on xdg-open may mask failures.
Line 26 redirects stderr to /dev/null, but if xdg-open fails (e.g., no $DISPLAY set in a headless session, or no default browser configured), the script still prints "⚡ Success" even though the browser didn't actually open. The existing scripts/coverage.sh (line 680) does the same thing, so this is at least consistent with the codebase—but it's a pattern that can mislead users.
Consider checking the exit code or removing the stderr suppression so failures are visible:
🔧 Optional: let xdg-open errors surface
if command -v xdg-open >/dev/null 2>&1; then
# Linux environment handler
- xdg-open "$TARGET_LOG_PAGE" 2>/dev/null
+ xdg-open "$TARGET_LOG_PAGE"
elif command -v open >/dev/null 2>&1; thenAlternatively, if you want to keep stderr quiet but still detect failures:
- xdg-open "$TARGET_LOG_PAGE" 2>/dev/null
+ if ! xdg-open "$TARGET_LOG_PAGE" 2>/dev/null; then
+ echo "⚠️ Warning: xdg-open returned an error. Browser may not have launched."
+ fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # 3. Detect operating system environment and trigger the native window engine | |
| if command -v xdg-open >/dev/null 2>&1; then | |
| # Linux environment handler | |
| xdg-open "$TARGET_LOG_PAGE" 2>/dev/null | |
| elif command -v open >/dev/null 2>&1; then | |
| # macOS environment handler | |
| open "$TARGET_LOG_PAGE" | |
| else | |
| echo "❌ Error: Could not detect a desktop environment opener utility (xdg-open or open)." | |
| echo " Please open this link manually instead:" | |
| echo " $TARGET_LOG_PAGE" | |
| exit 1 | |
| fi | |
| echo "⚡ Success: Browser session initialized." | |
| # 3. Detect operating system environment and trigger the native window engine | |
| if command -v xdg-open >/dev/null 2>&1; then | |
| # Linux environment handler | |
| xdg-open "$TARGET_LOG_PAGE" | |
| elif command -v open >/dev/null 2>&1; then | |
| # macOS environment handler | |
| open "$TARGET_LOG_PAGE" | |
| else | |
| echo "❌ Error: Could not detect a desktop environment opener utility (xdg-open or open)." | |
| echo " Please open this link manually instead:" | |
| echo " $TARGET_LOG_PAGE" | |
| exit 1 | |
| fi | |
| echo "⚡ Success: Browser session initialized." |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/release/view-dependabot-logs.sh` around lines 23 - 37, The xdg-open
command on line 26 suppresses stderr output which masks failures when the
browser fails to open (e.g., no $DISPLAY in headless environments or no default
browser configured). The script then prints the success message regardless of
whether the command actually succeeded. Remove the `2>/dev/null` redirection
from the xdg-open call to allow errors to surface, and check the exit status of
both xdg-open and open commands. Only print the success message (the "⚡ Success:
Browser session initialized." echo) after confirming that one of the
browser-opening commands actually succeeded by checking their exit codes.
knoepfel
left a comment
There was a problem hiding this comment.
@greenc-FNAL, I suspect the additions to scripts/release can go away?
CI/Workflows
dependabot-auto-merge.yaml: Updated to use
secrets.GITHUB_TOKENinstead ofsecrets.WORKFLOW_PATfor theGH_TOKENenvironment variable, eliminating the need for a separate workflow PAT. Also addedrepository-projects: writepermission.guardrail-audit-alert.yaml (new): Monitors pushes to
mainbranch and sends Slack notifications when non-Dependabot commits are pushed directly (bypassing guardrails). UsesSLACK_WEBHOOK_URLsecret,jqfor safe JSON payload construction, andcurlto POST alerts.Release Utilities
01-detect-tier1.sh (new): Classifies repositories in
actions/*directories as Tier 1 by examining internal dependencies and detecting unreleased changes. Checks forFramework-R-D/references inaction.yamland inspectsgit logfor changes since the latest tag.02-execute-release.sh (new): Automates the complete release workflow including:
CHANGELOG.mdhas an entry for the new versiongh release create --generate-notesgh apiREADME.mdwith new pinned SHA and versionmaintrigger-dependabot.sh (new): Forces Dependabot re-scan by injecting a UTC timestamp comment into
.github/dependabot.yml, creating a temporary automation branch, opening and closing a short-lived PR to trigger the scan, then cleaning up.view-dependabot-logs.sh (new): Convenience utility that opens the Dependabot Management UI deep link (
/network/updates) usinggh repo viewto fetch the repo URL, withxdg-open(Linux) oropen(macOS) fallbacks.