Skip to content

Add PR validation workflow and docs#1

Open
FortiShield wants to merge 5 commits into
CtxOS:mainfrom
FortiShield:main
Open

Add PR validation workflow and docs#1
FortiShield wants to merge 5 commits into
CtxOS:mainfrom
FortiShield:main

Conversation

@FortiShield
Copy link
Copy Markdown

@FortiShield FortiShield commented Mar 31, 2026

Summary by CodeRabbit

  • New Features

    • Automated plugin validation for pull requests that checks plugin structure and metadata compliance.
    • Pull request validation failures are automatically reported as GitHub comments.
  • Documentation

    • Added plugin tag taxonomy guide with recommended tagging conventions.
  • Chores

    • Added example plugin template.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 31, 2026

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e9fa233d-1616-4523-9b3d-78edfc6191fc

📥 Commits

Reviewing files that changed from the base of the PR and between 4611d67 and 4b7147b.

📒 Files selected for processing (5)
  • .github/workflows/validate-plugin-pr.yml
  • TAGS.md
  • plugins/_example1/plugin.yaml
  • scripts/comment_validation_failure.js
  • scripts/validate_pr.py
 ______________________________________________________________
< Good things come to those who commit early and review often. >
 --------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
🧪 Generate unit tests (beta)

❌ Error creating Unit Test PR.

  • Create PR with unit tests
  • Commit unit tests in branch main

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

Migrating from UI to YAML configuration.

Use the @coderabbitai configuration command in a PR comment to get a dump of all your UI settings in YAML format. You can then edit this YAML file and upload it to the root of your repository to configure CodeRabbit programmatically.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 31, 2026

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 31, 2026

❌ Failed to create PR with unit tests: AGENT_CHAT: Failed to open pull request

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 31, 2026

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
scripts/validate_pr.py (3)

126-133: Redundant cast after truthiness check.

After verifying base_sha and head_sha are truthy (non-empty strings from os.environ.get), the cast(str, ...) calls are unnecessary since the values are already strings.

♻️ Simplified code
 def main() -> int:
     base_sha = os.environ.get("BASE_SHA")
     head_sha = os.environ.get("HEAD_SHA")
     if not base_sha or not head_sha:
         _fail("BASE_SHA and HEAD_SHA environment variables are required")
 
-    base_sha = cast(str, base_sha)
-    head_sha = cast(str, head_sha)
-
     changes = _get_changed_files(base_sha, head_sha)

The type checker should narrow the type after the if not base_sha or not head_sha guard. If your type checker doesn't handle this, you can use assert base_sha and head_sha instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/validate_pr.py` around lines 126 - 133, The code redundantly calls
cast(str, ...) for base_sha and head_sha after the truthiness guard in main;
remove the unnecessary cast calls and let the variables remain as the str values
returned by os.environ.get, or replace the guard with an assert (e.g., assert
base_sha and head_sha) if your type checker needs narrowing; update the
references to base_sha and head_sha in main accordingly and ensure the existing
_fail branch remains unchanged.

176-195: Consider handling symlinks explicitly.

plugin_root.iterdir() will include symlinks, and child.is_dir() follows symlinks. A malicious submission could include a symlink pointing outside the plugin directory. Consider checking child.is_symlink() and rejecting symlinks.

🛡️ Proposed fix to reject symlinks
     thumbnails: list[Path] = []
     for child in plugin_root.iterdir():
+        if child.is_symlink():
+            _fail(
+                f"Symbolic links are not allowed in plugin folders: {child.relative_to(REPO_ROOT)}"
+            )
         if child.is_dir():
             _fail(
                 f"No subdirectories are allowed inside a plugin folder: {child.relative_to(REPO_ROOT)}"
             )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/validate_pr.py` around lines 176 - 195, The current loop over
plugin_root.iterdir() does not handle symlinks; update the loop that builds
thumbnails: list[Path] = [] and iterates over plugin_root.iterdir() to
explicitly reject any symlinks by checking child.is_symlink() before other
checks and call _fail with a clear message if true; maintain existing behavior
for child.is_dir(), file suffix checks using ALLOWED_IMAGE_EXTS and thumbnail
name validation against THUMBNAIL_BASENAME, ensuring symlink rejection happens
first so no symlink can point outside the plugin folder.

216-221: Use exception chaining for clearer tracebacks.

When re-raising as SystemExit within an except block, use from e or from None to clarify the exception chain.

♻️ Proposed fix
 if __name__ == "__main__":
     try:
         raise SystemExit(main())
     except ValidationError as e:
         print(f"Validation failed: {e}")
-        raise SystemExit(1)
+        raise SystemExit(1) from None
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/validate_pr.py` around lines 216 - 221, In the __main__ block, change
the re-raise inside the except handler to use explicit exception chaining so the
traceback is clear: replace "raise SystemExit(1)" in the except ValidationError
as e block with "raise SystemExit(1) from e" (keep the initial "raise
SystemExit(main())" as-is) so the chain references the original ValidationError.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/validate-plugin-pr.yml:
- Around line 43-47: The workflow uses the non-existent input script-file on
actions/github-script@v7; replace that usage by reading the external script and
passing its contents to the script input. Concretely, remove the script-file:
scripts/comment_validation_failure.js entry and instead load the file content
(e.g., with a prior step that reads scripts/comment_validation_failure.js into
an output) then set script: to that content for the actions/github-script@v7
step (or alternatively inline the JS into the script: block); refer to the
inputs named script and script-file and the action tag actions/github-script@v7
when making the change.

---

Nitpick comments:
In `@scripts/validate_pr.py`:
- Around line 126-133: The code redundantly calls cast(str, ...) for base_sha
and head_sha after the truthiness guard in main; remove the unnecessary cast
calls and let the variables remain as the str values returned by os.environ.get,
or replace the guard with an assert (e.g., assert base_sha and head_sha) if your
type checker needs narrowing; update the references to base_sha and head_sha in
main accordingly and ensure the existing _fail branch remains unchanged.
- Around line 176-195: The current loop over plugin_root.iterdir() does not
handle symlinks; update the loop that builds thumbnails: list[Path] = [] and
iterates over plugin_root.iterdir() to explicitly reject any symlinks by
checking child.is_symlink() before other checks and call _fail with a clear
message if true; maintain existing behavior for child.is_dir(), file suffix
checks using ALLOWED_IMAGE_EXTS and thumbnail name validation against
THUMBNAIL_BASENAME, ensuring symlink rejection happens first so no symlink can
point outside the plugin folder.
- Around line 216-221: In the __main__ block, change the re-raise inside the
except handler to use explicit exception chaining so the traceback is clear:
replace "raise SystemExit(1)" in the except ValidationError as e block with
"raise SystemExit(1) from e" (keep the initial "raise SystemExit(main())" as-is)
so the chain references the original ValidationError.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: e9fa233d-1616-4523-9b3d-78edfc6191fc

📥 Commits

Reviewing files that changed from the base of the PR and between 4611d67 and 4b7147b.

📒 Files selected for processing (5)
  • .github/workflows/validate-plugin-pr.yml
  • TAGS.md
  • plugins/_example1/plugin.yaml
  • scripts/comment_validation_failure.js
  • scripts/validate_pr.py

Comment on lines +43 to +47
- name: Comment on PR (validation failure)
if: ${{ steps.validate.outputs.exit_code != '0' }}
uses: actions/github-script@v7
with:
script-file: scripts/comment_validation_failure.js
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

What inputs does actions/github-script@v7 GitHub Action accept?

💡 Result:

The actions/github-script@v7 GitHub Action accepts the following inputs: - script: The body of an asynchronous JavaScript function to execute (required). - github-token: GitHub token for authentication (optional; defaults to GITHUB_TOKEN). - result-encoding: Encoding for the result output (string, json; default string). - retries: Number of retries for the script (default 0). - debug: Enable debug logging (boolean). - user-agent: Custom user agent prefix. - previews: API preview headers (now GraphQL only in v7). These are used in examples throughout the documentation, such as: with: script: | ... result-encoding: string retries: 3 Note that custom inputs like 'foo' are not valid and will cause warnings; use env vars for additional data passed to the script via process.env to avoid injection risks.

Citations:


🏁 Script executed:

# Check if the script file exists
find . -name "comment_validation_failure.js" -type f

# Check for any other uses of script-file in GitHub workflows
rg "script-file" --type yaml

Repository: CtxOS/ctx-plugins

Length of output: 100


🏁 Script executed:

head -50 ./scripts/comment_validation_failure.js

Repository: CtxOS/ctx-plugins

Length of output: 1002


Invalid input script-file for actions/github-script@v7.

The script-file input does not exist in actions/github-script@v7. The action only accepts a script input. This will cause the workflow step to fail.

To execute an external script file, read its content and pass it to the script input:

🔧 Proposed fix
     - name: Comment on PR (validation failure)
       if: ${{ steps.validate.outputs.exit_code != '0' }}
       uses: actions/github-script@v7
       with:
-        script-file: scripts/comment_validation_failure.js
+        script: |
+          const fs = require('fs');
+          const scriptContent = fs.readFileSync('./scripts/comment_validation_failure.js', 'utf8');
+          eval(scriptContent);

Or alternatively, move the script logic inline or use a module export approach if preferred.

🧰 Tools
🪛 actionlint (1.7.11)

[error] 45-45: missing input "script" which is required by action "actions/github-script@v7". all required inputs are "script"

(action)


[error] 47-47: input "script-file" is not defined in action "actions/github-script@v7". available inputs are "base-url", "debug", "github-token", "previews", "result-encoding", "retries", "retry-exempt-status-codes", "script", "user-agent"

(action)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/validate-plugin-pr.yml around lines 43 - 47, The workflow
uses the non-existent input script-file on actions/github-script@v7; replace
that usage by reading the external script and passing its contents to the script
input. Concretely, remove the script-file: scripts/comment_validation_failure.js
entry and instead load the file content (e.g., with a prior step that reads
scripts/comment_validation_failure.js into an output) then set script: to that
content for the actions/github-script@v7 step (or alternatively inline the JS
into the script: block); refer to the inputs named script and script-file and
the action tag actions/github-script@v7 when making the change.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 31, 2026

❌ Failed to create PR with unit tests: AGENT_CHAT: Failed to open pull request

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 31, 2026

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants