hol-guard 2.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. hol_guard-2.0.3/.clusterfuzzlite/Dockerfile +9 -0
  2. hol_guard-2.0.3/.clusterfuzzlite/build.sh +8 -0
  3. hol_guard-2.0.3/.clusterfuzzlite/project.yaml +3 -0
  4. hol_guard-2.0.3/.clusterfuzzlite/requirements-atheris.txt +1 -0
  5. hol_guard-2.0.3/.dockerignore +10 -0
  6. hol_guard-2.0.3/.github/CODEOWNERS +1 -0
  7. hol_guard-2.0.3/.github/dependabot.yml +12 -0
  8. hol_guard-2.0.3/.github/workflows/ci.yml +45 -0
  9. hol_guard-2.0.3/.github/workflows/codeql.yml +41 -0
  10. hol_guard-2.0.3/.github/workflows/e2e-test.yml +112 -0
  11. hol_guard-2.0.3/.github/workflows/fuzz.yml +53 -0
  12. hol_guard-2.0.3/.github/workflows/publish-action-repo.yml +206 -0
  13. hol_guard-2.0.3/.github/workflows/publish.yml +308 -0
  14. hol_guard-2.0.3/.github/workflows/scorecard.yml +27 -0
  15. hol_guard-2.0.3/.gitignore +42 -0
  16. hol_guard-2.0.3/.pre-commit-hooks.yaml +10 -0
  17. hol_guard-2.0.3/CONTRIBUTING.md +38 -0
  18. hol_guard-2.0.3/Dockerfile +51 -0
  19. hol_guard-2.0.3/LICENSE +120 -0
  20. hol_guard-2.0.3/PKG-INFO +661 -0
  21. hol_guard-2.0.3/README.md +626 -0
  22. hol_guard-2.0.3/SECURITY.md +34 -0
  23. hol_guard-2.0.3/action/README.legacy.md +25 -0
  24. hol_guard-2.0.3/action/README.md +280 -0
  25. hol_guard-2.0.3/action/action.yml +299 -0
  26. hol_guard-2.0.3/action/cisco-version.txt +1 -0
  27. hol_guard-2.0.3/action/pypi-attestations-version.txt +1 -0
  28. hol_guard-2.0.3/action/scanner-version.txt +1 -0
  29. hol_guard-2.0.3/docker-requirements.txt +12 -0
  30. hol_guard-2.0.3/docs/guard/architecture.md +33 -0
  31. hol_guard-2.0.3/docs/guard/get-started.md +82 -0
  32. hol_guard-2.0.3/docs/guard/harness-support.md +22 -0
  33. hol_guard-2.0.3/docs/guard/local-vs-cloud.md +22 -0
  34. hol_guard-2.0.3/docs/guard/repo-boundaries.md +21 -0
  35. hol_guard-2.0.3/docs/guard/testing-matrix.md +32 -0
  36. hol_guard-2.0.3/docs/trust/mcp-trust-draft.md +41 -0
  37. hol_guard-2.0.3/docs/trust/plugin-trust-draft.md +56 -0
  38. hol_guard-2.0.3/docs/trust/skill-trust-local.md +60 -0
  39. hol_guard-2.0.3/fuzzers/manifest_fuzzer.py +19 -0
  40. hol_guard-2.0.3/pyproject.toml +85 -0
  41. hol_guard-2.0.3/schemas/plugin-quality.v1.json +140 -0
  42. hol_guard-2.0.3/schemas/scan-result.v1.json +393 -0
  43. hol_guard-2.0.3/schemas/verify-result.v1.json +81 -0
  44. hol_guard-2.0.3/src/codex_plugin_scanner/__init__.py +29 -0
  45. hol_guard-2.0.3/src/codex_plugin_scanner/action_runner.py +481 -0
  46. hol_guard-2.0.3/src/codex_plugin_scanner/checks/__init__.py +0 -0
  47. hol_guard-2.0.3/src/codex_plugin_scanner/checks/best_practices.py +238 -0
  48. hol_guard-2.0.3/src/codex_plugin_scanner/checks/claude.py +285 -0
  49. hol_guard-2.0.3/src/codex_plugin_scanner/checks/code_quality.py +115 -0
  50. hol_guard-2.0.3/src/codex_plugin_scanner/checks/ecosystem_common.py +34 -0
  51. hol_guard-2.0.3/src/codex_plugin_scanner/checks/gemini.py +196 -0
  52. hol_guard-2.0.3/src/codex_plugin_scanner/checks/manifest.py +501 -0
  53. hol_guard-2.0.3/src/codex_plugin_scanner/checks/manifest_support.py +61 -0
  54. hol_guard-2.0.3/src/codex_plugin_scanner/checks/marketplace.py +334 -0
  55. hol_guard-2.0.3/src/codex_plugin_scanner/checks/opencode.py +223 -0
  56. hol_guard-2.0.3/src/codex_plugin_scanner/checks/operational_security.py +346 -0
  57. hol_guard-2.0.3/src/codex_plugin_scanner/checks/security.py +447 -0
  58. hol_guard-2.0.3/src/codex_plugin_scanner/checks/skill_security.py +241 -0
  59. hol_guard-2.0.3/src/codex_plugin_scanner/cli.py +509 -0
  60. hol_guard-2.0.3/src/codex_plugin_scanner/config.py +83 -0
  61. hol_guard-2.0.3/src/codex_plugin_scanner/ecosystems/__init__.py +15 -0
  62. hol_guard-2.0.3/src/codex_plugin_scanner/ecosystems/base.py +20 -0
  63. hol_guard-2.0.3/src/codex_plugin_scanner/ecosystems/claude.py +112 -0
  64. hol_guard-2.0.3/src/codex_plugin_scanner/ecosystems/codex.py +94 -0
  65. hol_guard-2.0.3/src/codex_plugin_scanner/ecosystems/detect.py +46 -0
  66. hol_guard-2.0.3/src/codex_plugin_scanner/ecosystems/gemini.py +80 -0
  67. hol_guard-2.0.3/src/codex_plugin_scanner/ecosystems/opencode.py +184 -0
  68. hol_guard-2.0.3/src/codex_plugin_scanner/ecosystems/registry.py +41 -0
  69. hol_guard-2.0.3/src/codex_plugin_scanner/ecosystems/types.py +45 -0
  70. hol_guard-2.0.3/src/codex_plugin_scanner/guard/__init__.py +5 -0
  71. hol_guard-2.0.3/src/codex_plugin_scanner/guard/adapters/__init__.py +36 -0
  72. hol_guard-2.0.3/src/codex_plugin_scanner/guard/adapters/base.py +142 -0
  73. hol_guard-2.0.3/src/codex_plugin_scanner/guard/adapters/claude_code.py +199 -0
  74. hol_guard-2.0.3/src/codex_plugin_scanner/guard/adapters/codex.py +82 -0
  75. hol_guard-2.0.3/src/codex_plugin_scanner/guard/adapters/cursor.py +94 -0
  76. hol_guard-2.0.3/src/codex_plugin_scanner/guard/adapters/gemini.py +103 -0
  77. hol_guard-2.0.3/src/codex_plugin_scanner/guard/adapters/opencode.py +78 -0
  78. hol_guard-2.0.3/src/codex_plugin_scanner/guard/cli/__init__.py +5 -0
  79. hol_guard-2.0.3/src/codex_plugin_scanner/guard/cli/commands.py +438 -0
  80. hol_guard-2.0.3/src/codex_plugin_scanner/guard/cli/product.py +190 -0
  81. hol_guard-2.0.3/src/codex_plugin_scanner/guard/cli/prompt.py +342 -0
  82. hol_guard-2.0.3/src/codex_plugin_scanner/guard/cli/render.py +502 -0
  83. hol_guard-2.0.3/src/codex_plugin_scanner/guard/config.py +76 -0
  84. hol_guard-2.0.3/src/codex_plugin_scanner/guard/consumer/__init__.py +5 -0
  85. hol_guard-2.0.3/src/codex_plugin_scanner/guard/consumer/service.py +257 -0
  86. hol_guard-2.0.3/src/codex_plugin_scanner/guard/daemon/__init__.py +5 -0
  87. hol_guard-2.0.3/src/codex_plugin_scanner/guard/daemon/server.py +67 -0
  88. hol_guard-2.0.3/src/codex_plugin_scanner/guard/models.py +121 -0
  89. hol_guard-2.0.3/src/codex_plugin_scanner/guard/policy/__init__.py +5 -0
  90. hol_guard-2.0.3/src/codex_plugin_scanner/guard/policy/engine.py +31 -0
  91. hol_guard-2.0.3/src/codex_plugin_scanner/guard/proxy/__init__.py +6 -0
  92. hol_guard-2.0.3/src/codex_plugin_scanner/guard/proxy/remote.py +50 -0
  93. hol_guard-2.0.3/src/codex_plugin_scanner/guard/proxy/stdio.py +125 -0
  94. hol_guard-2.0.3/src/codex_plugin_scanner/guard/receipts/__init__.py +5 -0
  95. hol_guard-2.0.3/src/codex_plugin_scanner/guard/receipts/manager.py +36 -0
  96. hol_guard-2.0.3/src/codex_plugin_scanner/guard/runtime/__init__.py +5 -0
  97. hol_guard-2.0.3/src/codex_plugin_scanner/guard/runtime/runner.py +84 -0
  98. hol_guard-2.0.3/src/codex_plugin_scanner/guard/schemas/__init__.py +5 -0
  99. hol_guard-2.0.3/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +71 -0
  100. hol_guard-2.0.3/src/codex_plugin_scanner/guard/shims.py +95 -0
  101. hol_guard-2.0.3/src/codex_plugin_scanner/guard/store.py +420 -0
  102. hol_guard-2.0.3/src/codex_plugin_scanner/integrations/__init__.py +5 -0
  103. hol_guard-2.0.3/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +200 -0
  104. hol_guard-2.0.3/src/codex_plugin_scanner/lint_fixes.py +105 -0
  105. hol_guard-2.0.3/src/codex_plugin_scanner/marketplace_support.py +100 -0
  106. hol_guard-2.0.3/src/codex_plugin_scanner/models.py +177 -0
  107. hol_guard-2.0.3/src/codex_plugin_scanner/path_support.py +46 -0
  108. hol_guard-2.0.3/src/codex_plugin_scanner/policy.py +140 -0
  109. hol_guard-2.0.3/src/codex_plugin_scanner/quality_artifact.py +91 -0
  110. hol_guard-2.0.3/src/codex_plugin_scanner/repo_detect.py +137 -0
  111. hol_guard-2.0.3/src/codex_plugin_scanner/reporting.py +376 -0
  112. hol_guard-2.0.3/src/codex_plugin_scanner/rules/__init__.py +6 -0
  113. hol_guard-2.0.3/src/codex_plugin_scanner/rules/registry.py +101 -0
  114. hol_guard-2.0.3/src/codex_plugin_scanner/rules/specs.py +26 -0
  115. hol_guard-2.0.3/src/codex_plugin_scanner/scanner.py +557 -0
  116. hol_guard-2.0.3/src/codex_plugin_scanner/submission.py +284 -0
  117. hol_guard-2.0.3/src/codex_plugin_scanner/suppressions.py +87 -0
  118. hol_guard-2.0.3/src/codex_plugin_scanner/trust_domain_scoring.py +22 -0
  119. hol_guard-2.0.3/src/codex_plugin_scanner/trust_helpers.py +207 -0
  120. hol_guard-2.0.3/src/codex_plugin_scanner/trust_mcp_scoring.py +116 -0
  121. hol_guard-2.0.3/src/codex_plugin_scanner/trust_models.py +85 -0
  122. hol_guard-2.0.3/src/codex_plugin_scanner/trust_plugin_scoring.py +180 -0
  123. hol_guard-2.0.3/src/codex_plugin_scanner/trust_scoring.py +52 -0
  124. hol_guard-2.0.3/src/codex_plugin_scanner/trust_skill_scoring.py +296 -0
  125. hol_guard-2.0.3/src/codex_plugin_scanner/trust_specs.py +286 -0
  126. hol_guard-2.0.3/src/codex_plugin_scanner/verification.py +964 -0
  127. hol_guard-2.0.3/src/codex_plugin_scanner/version.py +3 -0
  128. hol_guard-2.0.3/tests/__init__.py +0 -0
  129. hol_guard-2.0.3/tests/fixtures/__init__.py +0 -0
  130. hol_guard-2.0.3/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +1 -0
  131. hol_guard-2.0.3/tests/fixtures/bad-plugin/.mcp.json +1 -0
  132. hol_guard-2.0.3/tests/fixtures/bad-plugin/secrets.js +3 -0
  133. hol_guard-2.0.3/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +6 -0
  134. hol_guard-2.0.3/tests/fixtures/claude-plugin-good/LICENSE +5 -0
  135. hol_guard-2.0.3/tests/fixtures/claude-plugin-good/README.md +3 -0
  136. hol_guard-2.0.3/tests/fixtures/claude-plugin-good/SECURITY.md +3 -0
  137. hol_guard-2.0.3/tests/fixtures/claude-plugin-good/hooks/hooks.json +5 -0
  138. hol_guard-2.0.3/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +8 -0
  139. hol_guard-2.0.3/tests/fixtures/code-quality-bad/evil.js +4 -0
  140. hol_guard-2.0.3/tests/fixtures/code-quality-bad/inject.js +2 -0
  141. hol_guard-2.0.3/tests/fixtures/gemini-extension-good/GEMINI.md +3 -0
  142. hol_guard-2.0.3/tests/fixtures/gemini-extension-good/LICENSE +5 -0
  143. hol_guard-2.0.3/tests/fixtures/gemini-extension-good/README.md +3 -0
  144. hol_guard-2.0.3/tests/fixtures/gemini-extension-good/SECURITY.md +3 -0
  145. hol_guard-2.0.3/tests/fixtures/gemini-extension-good/commands/hello.toml +5 -0
  146. hol_guard-2.0.3/tests/fixtures/gemini-extension-good/gemini-extension.json +17 -0
  147. hol_guard-2.0.3/tests/fixtures/good-plugin/.codex-plugin/plugin.json +33 -0
  148. hol_guard-2.0.3/tests/fixtures/good-plugin/.codexignore +3 -0
  149. hol_guard-2.0.3/tests/fixtures/good-plugin/LICENSE +17 -0
  150. hol_guard-2.0.3/tests/fixtures/good-plugin/README.md +3 -0
  151. hol_guard-2.0.3/tests/fixtures/good-plugin/SECURITY.md +3 -0
  152. hol_guard-2.0.3/tests/fixtures/good-plugin/assets/icon.svg +4 -0
  153. hol_guard-2.0.3/tests/fixtures/good-plugin/assets/logo.svg +4 -0
  154. hol_guard-2.0.3/tests/fixtures/good-plugin/assets/screenshot.svg +6 -0
  155. hol_guard-2.0.3/tests/fixtures/good-plugin/skills/example/SKILL.md +15 -0
  156. hol_guard-2.0.3/tests/fixtures/malformed-json/.codex-plugin/plugin.json +1 -0
  157. hol_guard-2.0.3/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +1 -0
  158. hol_guard-2.0.3/tests/fixtures/missing-fields/.codex-plugin/plugin.json +1 -0
  159. hol_guard-2.0.3/tests/fixtures/mit-license/LICENSE +7 -0
  160. hol_guard-2.0.3/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +5 -0
  161. hol_guard-2.0.3/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +1 -0
  162. hol_guard-2.0.3/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +1 -0
  163. hol_guard-2.0.3/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +1 -0
  164. hol_guard-2.0.3/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +1 -0
  165. hol_guard-2.0.3/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +5 -0
  166. hol_guard-2.0.3/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +43 -0
  167. hol_guard-2.0.3/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +18 -0
  168. hol_guard-2.0.3/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +1 -0
  169. hol_guard-2.0.3/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +3 -0
  170. hol_guard-2.0.3/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +1 -0
  171. hol_guard-2.0.3/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +1 -0
  172. hol_guard-2.0.3/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +6 -0
  173. hol_guard-2.0.3/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +6 -0
  174. hol_guard-2.0.3/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +6 -0
  175. hol_guard-2.0.3/tests/fixtures/no-version/.codex-plugin/plugin.json +1 -0
  176. hol_guard-2.0.3/tests/fixtures/opencode-good/.opencode/commands/hello.md +6 -0
  177. hol_guard-2.0.3/tests/fixtures/opencode-good/.opencode/plugins/example.ts +5 -0
  178. hol_guard-2.0.3/tests/fixtures/opencode-good/LICENSE +5 -0
  179. hol_guard-2.0.3/tests/fixtures/opencode-good/README.md +3 -0
  180. hol_guard-2.0.3/tests/fixtures/opencode-good/SECURITY.md +3 -0
  181. hol_guard-2.0.3/tests/fixtures/opencode-good/opencode.jsonc +14 -0
  182. hol_guard-2.0.3/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +1 -0
  183. hol_guard-2.0.3/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +1 -0
  184. hol_guard-2.0.3/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +1 -0
  185. hol_guard-2.0.3/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +1 -0
  186. hol_guard-2.0.3/tests/fixtures/with-marketplace/marketplace-broken.json +8 -0
  187. hol_guard-2.0.3/tests/fixtures/with-marketplace/marketplace.json +20 -0
  188. hol_guard-2.0.3/tests/test-trust-scoring.py +173 -0
  189. hol_guard-2.0.3/tests/test-trust-specs.py +45 -0
  190. hol_guard-2.0.3/tests/test_action_bundle.py +291 -0
  191. hol_guard-2.0.3/tests/test_action_runner.py +262 -0
  192. hol_guard-2.0.3/tests/test_best_practices.py +109 -0
  193. hol_guard-2.0.3/tests/test_cli.py +380 -0
  194. hol_guard-2.0.3/tests/test_code_quality.py +79 -0
  195. hol_guard-2.0.3/tests/test_config.py +93 -0
  196. hol_guard-2.0.3/tests/test_coverage_remaining.py +146 -0
  197. hol_guard-2.0.3/tests/test_ecosystems.py +188 -0
  198. hol_guard-2.0.3/tests/test_edge_cases.py +153 -0
  199. hol_guard-2.0.3/tests/test_final_coverage.py +52 -0
  200. hol_guard-2.0.3/tests/test_guard_cli.py +1046 -0
  201. hol_guard-2.0.3/tests/test_guard_launch_env.py +78 -0
  202. hol_guard-2.0.3/tests/test_guard_product_flow.py +322 -0
  203. hol_guard-2.0.3/tests/test_guard_runtime.py +627 -0
  204. hol_guard-2.0.3/tests/test_integration.py +110 -0
  205. hol_guard-2.0.3/tests/test_lint_fixes.py +70 -0
  206. hol_guard-2.0.3/tests/test_live_cisco_smoke.py +32 -0
  207. hol_guard-2.0.3/tests/test_manifest.py +235 -0
  208. hol_guard-2.0.3/tests/test_marketplace.py +184 -0
  209. hol_guard-2.0.3/tests/test_operational_security.py +137 -0
  210. hol_guard-2.0.3/tests/test_policy.py +27 -0
  211. hol_guard-2.0.3/tests/test_quality_artifact.py +23 -0
  212. hol_guard-2.0.3/tests/test_rule_registry.py +17 -0
  213. hol_guard-2.0.3/tests/test_scanner.py +127 -0
  214. hol_guard-2.0.3/tests/test_schema_contracts.py +58 -0
  215. hol_guard-2.0.3/tests/test_security.py +193 -0
  216. hol_guard-2.0.3/tests/test_security_ops.py +50 -0
  217. hol_guard-2.0.3/tests/test_skill_security.py +171 -0
  218. hol_guard-2.0.3/tests/test_submission.py +221 -0
  219. hol_guard-2.0.3/tests/test_trust_scoring.py +229 -0
  220. hol_guard-2.0.3/tests/test_trust_specs.py +45 -0
  221. hol_guard-2.0.3/tests/test_verification.py +226 -0
  222. hol_guard-2.0.3/tests/test_versioning.py +14 -0
  223. hol_guard-2.0.3/uv.lock +3581 -0
@@ -0,0 +1,9 @@
1
+ FROM gcr.io/oss-fuzz-base/base-builder-python@sha256:721650302bfda2f3832df73bb24aeacfa41c32e692f3d6e4dd06074e79c64ed7
2
+
3
+ COPY ./.clusterfuzzlite/requirements-atheris.txt $SRC/requirements-atheris.txt
4
+ RUN python3 -m pip install --require-hashes --no-cache-dir --no-binary=:all: --no-deps \
5
+ -r $SRC/requirements-atheris.txt
6
+
7
+ COPY . $SRC/codex-plugin-scanner
8
+ WORKDIR $SRC/codex-plugin-scanner
9
+ COPY ./.clusterfuzzlite/build.sh $SRC/build.sh
@@ -0,0 +1,8 @@
1
+ #!/bin/bash -eu
2
+
3
+ cd "$SRC/codex-plugin-scanner"
4
+ export PYTHONPATH="$PWD/src${PYTHONPATH:+:$PYTHONPATH}"
5
+
6
+ for fuzzer in fuzzers/*_fuzzer.py; do
7
+ compile_python_fuzzer "$fuzzer"
8
+ done
@@ -0,0 +1,3 @@
1
+ homepage: "https://github.com/hashgraph-online/codex-plugin-scanner"
2
+ language: python
3
+ main_repo: "https://github.com/hashgraph-online/codex-plugin-scanner"
@@ -0,0 +1 @@
1
+ atheris==3.0.0 --hash=sha256:1f0929c7bc3040f3fe4102e557718734190cf2d7718bbb8e3ce6d3eb56ef5bb3
@@ -0,0 +1,10 @@
1
+ .git
2
+ .github
3
+ .pytest_cache
4
+ .ruff_cache
5
+ .venv
6
+ __pycache__
7
+ dist
8
+ tests
9
+ action
10
+ *.pyc
@@ -0,0 +1 @@
1
+ * @hashgraph-online/core
@@ -0,0 +1,12 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ open-pull-requests-limit: 10
8
+ - package-ecosystem: "pip"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
12
+ open-pull-requests-limit: 10
@@ -0,0 +1,45 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+ branches: [main]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ ci:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
17
+ steps:
18
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
19
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e
23
+ with:
24
+ enable-cache: true
25
+ - run: uv sync --frozen --extra dev --python ${{ matrix.python-version }}
26
+ - run: uv run --no-sync python -m ruff check src/
27
+ - run: uv run --no-sync python -m ruff format --check src/
28
+ - run: uv run --no-sync pytest --tb=short
29
+
30
+ cross-platform:
31
+ runs-on: ${{ matrix.os }}
32
+ strategy:
33
+ matrix:
34
+ os: [macos-latest, windows-latest]
35
+ python-version: ["3.12"]
36
+ steps:
37
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
38
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
39
+ with:
40
+ python-version: ${{ matrix.python-version }}
41
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e
42
+ with:
43
+ enable-cache: true
44
+ - run: uv sync --frozen --extra dev --python ${{ matrix.python-version }}
45
+ - run: uv run --no-sync pytest tests/test_cli.py tests/test_verification.py tests/test_action_runner.py --tb=short
@@ -0,0 +1,41 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ schedule:
9
+ - cron: "0 4 * * 1"
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ analyze:
16
+ name: Analyze (${{ matrix.language }})
17
+ if: ${{ vars.CODEQL_ADVANCED_ENABLED == 'true' }}
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ language: [actions, python]
23
+ permissions:
24
+ actions: read
25
+ contents: read
26
+ security-events: write
27
+ steps:
28
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
29
+ - name: Provide legacy workspace alias for CodeQL default setup state
30
+ run: |
31
+ LEGACY_ROOT="/home/runner/work/codex-plugin-scanner"
32
+ mkdir -p "$LEGACY_ROOT"
33
+ ln -sfn "$GITHUB_WORKSPACE" "$LEGACY_ROOT/codex-plugin-scanner"
34
+ - uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d
35
+ with:
36
+ languages: ${{ matrix.language }}
37
+ build-mode: none
38
+ source-root: .
39
+ - uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d
40
+ with:
41
+ category: /language:${{ matrix.language }}
@@ -0,0 +1,112 @@
1
+ name: E2E Tests
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [feat/*]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ scanner-text:
15
+ name: Scanner (text format)
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
19
+ - uses: ./action
20
+ id: scan
21
+ with:
22
+ install_source: local
23
+ plugin_dir: tests/fixtures/good-plugin
24
+ min_score: 80
25
+
26
+ scanner-json:
27
+ name: Scanner (JSON format)
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
31
+ - uses: ./action
32
+ id: scan
33
+ with:
34
+ install_source: local
35
+ plugin_dir: tests/fixtures/good-plugin
36
+ format: json
37
+ output: report.json
38
+ - name: Validate JSON
39
+ run: |
40
+ python3 -c "
41
+ import json
42
+ d = json.load(open('report.json'))
43
+ assert 'score' in d
44
+ assert 'grade' in d
45
+ assert d['score'] >= 80, f'Expected score >= 80, got {d[\"score\"]}'
46
+ print(f'JSON output valid: score={d[\"score\"]}, grade={d[\"grade\"]}')
47
+ "
48
+
49
+ scanner-sarif:
50
+ name: Scanner (SARIF format)
51
+ runs-on: ubuntu-latest
52
+ steps:
53
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
54
+ - uses: ./action
55
+ id: scan
56
+ with:
57
+ install_source: local
58
+ plugin_dir: tests/fixtures/good-plugin
59
+ format: sarif
60
+ output: report.sarif
61
+ - name: Validate SARIF
62
+ run: |
63
+ python3 -c "
64
+ import json
65
+ d = json.load(open('report.sarif'))
66
+ assert d['version'] == '2.1.0'
67
+ assert d['\$schema'].startswith('https://')
68
+ print('SARIF output valid')
69
+ "
70
+ # Skip SARIF upload - CodeQL upload-sarif requires code scanning to be enabled on the repo
71
+
72
+ scanner-fail:
73
+ name: Scanner (fail on low score)
74
+ runs-on: ubuntu-latest
75
+ steps:
76
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
77
+ - uses: ./action
78
+ id: scan
79
+ continue-on-error: true
80
+ with:
81
+ install_source: local
82
+ plugin_dir: tests/fixtures/bad-plugin
83
+ min_score: 99
84
+ - name: Verify failure
85
+ if: always() && steps.scan.outcome == 'failure'
86
+ run: echo "Correctly failed for low score"
87
+ - name: Should have failed
88
+ if: always() && steps.scan.outcome != 'failure'
89
+ run: |
90
+ echo "Expected failure but scanner passed"
91
+ exit 1
92
+
93
+ scanner-markdown:
94
+ name: Scanner (Markdown format)
95
+ runs-on: ubuntu-latest
96
+ steps:
97
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
98
+ - uses: ./action
99
+ id: scan
100
+ with:
101
+ install_source: local
102
+ plugin_dir: tests/fixtures/good-plugin
103
+ format: markdown
104
+ output: report.md
105
+ - name: Validate Markdown
106
+ run: |
107
+ python3 -c "
108
+ content = open('report.md').read()
109
+ assert '/100' in content
110
+ assert 'Excellent' in content or 'Good' in content or 'Fair' in content
111
+ print('Markdown output valid')
112
+ "
@@ -0,0 +1,53 @@
1
+ name: Fuzzing
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+ schedule:
9
+ - cron: "0 6 * * 1"
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ code-change:
16
+ if: github.event_name == 'pull_request'
17
+ runs-on: ubuntu-latest
18
+ permissions:
19
+ contents: read
20
+ security-events: write
21
+ steps:
22
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
23
+ - uses: google/clusterfuzzlite/actions/build_fuzzers@52ecc61cb587ee99c26825a112a21abf19c7448c
24
+ with:
25
+ language: python
26
+ sanitizer: address
27
+ - uses: google/clusterfuzzlite/actions/run_fuzzers@52ecc61cb587ee99c26825a112a21abf19c7448c
28
+ with:
29
+ github-token: ${{ secrets.GITHUB_TOKEN }}
30
+ mode: code-change
31
+ sanitizer: address
32
+ fuzz-seconds: 600
33
+ output-sarif: true
34
+
35
+ batch:
36
+ if: github.event_name != 'pull_request'
37
+ runs-on: ubuntu-latest
38
+ permissions:
39
+ contents: read
40
+ security-events: write
41
+ steps:
42
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
43
+ - uses: google/clusterfuzzlite/actions/build_fuzzers@52ecc61cb587ee99c26825a112a21abf19c7448c
44
+ with:
45
+ language: python
46
+ sanitizer: address
47
+ - uses: google/clusterfuzzlite/actions/run_fuzzers@52ecc61cb587ee99c26825a112a21abf19c7448c
48
+ with:
49
+ github-token: ${{ secrets.GITHUB_TOKEN }}
50
+ mode: batch
51
+ sanitizer: address
52
+ fuzz-seconds: 1800
53
+ output-sarif: true
@@ -0,0 +1,206 @@
1
+ name: Publish GitHub Action Repository
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ai-plugin-scanner-action-repo-${{ github.ref }}
14
+ cancel-in-progress: false
15
+
16
+ jobs:
17
+ publish-action-repo:
18
+ name: Sync action repo + publish release notes
19
+ runs-on: ubuntu-latest
20
+ permissions:
21
+ contents: read
22
+ env:
23
+ ACTION_CANONICAL_REPOSITORY: ${{ vars.ACTION_CANONICAL_REPOSITORY != '' && vars.ACTION_CANONICAL_REPOSITORY || 'hashgraph-online/ai-plugin-scanner-action' }}
24
+ ACTION_COMPAT_REPOSITORY: ${{ vars.ACTION_COMPAT_REPOSITORY != '' && vars.ACTION_COMPAT_REPOSITORY || 'hashgraph-online/hol-codex-plugin-scanner-action' }}
25
+ SOURCE_REF: ${{ github.sha }}
26
+ SOURCE_REPOSITORY: ${{ github.repository }}
27
+ SOURCE_SERVER_URL: ${{ github.server_url }}
28
+ steps:
29
+ - name: Validate publication credentials
30
+ env:
31
+ ACTION_REPO_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
32
+ run: |
33
+ if [ -z "$ACTION_REPO_TOKEN" ]; then
34
+ echo "ACTION_REPO_TOKEN must be configured to publish the Marketplace action repository." >&2
35
+ exit 1
36
+ fi
37
+
38
+ - name: Checkout source repository
39
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
40
+ with:
41
+ fetch-depth: 0
42
+
43
+ - name: Compute next action release tag
44
+ id: version
45
+ env:
46
+ GH_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
47
+ run: |
48
+ latest_release_tag() {
49
+ target_repo="$1"
50
+ if ! gh repo view "$target_repo" >/dev/null 2>&1; then
51
+ return
52
+ fi
53
+ gh release list --repo "$target_repo" --limit 1 --json tagName --jq '.[0].tagName // ""'
54
+ }
55
+
56
+ latest_remote_tag() {
57
+ target_repo="$1"
58
+ if ! gh repo view "$target_repo" >/dev/null 2>&1; then
59
+ return
60
+ fi
61
+ git ls-remote --tags --refs "https://x-access-token:${GH_TOKEN}@github.com/${target_repo}.git" "refs/tags/v*" \
62
+ | awk -F'/' '{print $3}' \
63
+ | sort -V \
64
+ | tail -n1
65
+ }
66
+
67
+ LAST_TAG=""
68
+ for candidate in \
69
+ "$(latest_release_tag "$ACTION_CANONICAL_REPOSITORY")" \
70
+ "$(latest_release_tag "$ACTION_COMPAT_REPOSITORY")" \
71
+ "$(latest_remote_tag "$ACTION_CANONICAL_REPOSITORY")" \
72
+ "$(latest_remote_tag "$ACTION_COMPAT_REPOSITORY")"; do
73
+ if [ -z "$candidate" ]; then
74
+ continue
75
+ fi
76
+ if [ -z "$LAST_TAG" ] || [ "$(printf '%s\n%s\n' "$LAST_TAG" "$candidate" | sort -V | tail -n1)" = "$candidate" ]; then
77
+ LAST_TAG="$candidate"
78
+ fi
79
+ done
80
+
81
+ if [ -z "$LAST_TAG" ]; then
82
+ TAG="v1.0.0"
83
+ else
84
+ IFS=. read -r MAJOR MINOR PATCH <<< "${LAST_TAG#v}"
85
+ if [ -z "$MAJOR" ] || [ -z "$MINOR" ] || [ -z "$PATCH" ]; then
86
+ echo "Unsupported release tag format: $LAST_TAG" >&2
87
+ exit 1
88
+ fi
89
+ TAG="v${MAJOR}.${MINOR}.$((PATCH + 1))"
90
+ fi
91
+
92
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
93
+
94
+ - name: Compute scanner package version
95
+ id: scanner_version
96
+ env:
97
+ GITHUB_REF: ${{ github.ref }}
98
+ GITHUB_EVENT_NAME: ${{ github.event_name }}
99
+ run: |
100
+ BASE_VERSION=$(python3 -c "import tomllib; p=tomllib.load(open('pyproject.toml','rb')); print(p['project']['version'])")
101
+ VERSION="$BASE_VERSION"
102
+ if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
103
+ VERSION="${GITHUB_REF#refs/tags/v}"
104
+ elif [[ "$GITHUB_EVENT_NAME" == "push" && "$GITHUB_REF" == "refs/heads/main" ]]; then
105
+ LAST_TAG=$(git tag --list 'v*' --sort=-version:refname | head -n1)
106
+ if [[ -n "$LAST_TAG" ]]; then
107
+ IFS=. read -r MAJOR MINOR PATCH <<< "${LAST_TAG#v}"
108
+ if [[ -z "$MAJOR" || -z "$MINOR" || -z "$PATCH" ]]; then
109
+ echo "Unsupported release tag format: $LAST_TAG" >&2
110
+ exit 1
111
+ fi
112
+ VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
113
+ fi
114
+ fi
115
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
116
+
117
+ - name: Sync canonical and compatibility action repositories
118
+ env:
119
+ ACTION_REPO_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
120
+ GH_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
121
+ TAG: ${{ steps.version.outputs.tag }}
122
+ SCANNER_VERSION: ${{ steps.scanner_version.outputs.version }}
123
+ run: |
124
+ any_repo_changed="false"
125
+
126
+ publish_action_release() {
127
+ target_repo="$1"
128
+ repo_dir="$2"
129
+
130
+ git -C "$repo_dir" tag -fa v1 -m "Update floating major tag to ${TAG}"
131
+ if git -C "$repo_dir" ls-remote --tags origin "refs/tags/${TAG}" | grep -q .; then
132
+ echo "Refusing to publish action bundle with colliding existing tag ${TAG} in ${target_repo}." >&2
133
+ exit 1
134
+ fi
135
+ git -C "$repo_dir" tag "${TAG}"
136
+ git -C "$repo_dir" push origin "refs/tags/${TAG}"
137
+ git -C "$repo_dir" push origin refs/tags/v1 --force
138
+
139
+ if ! gh release view "${TAG}" --repo "$target_repo" >/dev/null 2>&1; then
140
+ gh release create "${TAG}" \
141
+ --repo "$target_repo" \
142
+ --title "${TAG}" \
143
+ --generate-notes \
144
+ --notes "Published automatically from ${SOURCE_SERVER_URL}/${SOURCE_REPOSITORY}/tree/${SOURCE_REF}"
145
+ fi
146
+ }
147
+
148
+ sync_action_repo() {
149
+ target_repo="$1"
150
+ readme_source="$2"
151
+ repo_description="$3"
152
+ repo_dir="$GITHUB_WORKSPACE/action-repos/${target_repo##*/}"
153
+ repo_changed="false"
154
+
155
+ if gh repo view "$target_repo" >/dev/null 2>&1; then
156
+ gh repo edit "$target_repo" --description "$repo_description"
157
+ gh repo clone "$target_repo" "$repo_dir" -- --depth 1
158
+ else
159
+ gh repo create "$target_repo" --public --description "$repo_description" --clone
160
+ mv "${target_repo##*/}" "$repo_dir"
161
+ fi
162
+
163
+ git -C "$repo_dir" remote set-url origin "https://x-access-token:${ACTION_REPO_TOKEN}@github.com/${target_repo}.git"
164
+
165
+ cp "${GITHUB_WORKSPACE}/action/action.yml" "${repo_dir}/action.yml"
166
+ cp "$readme_source" "${repo_dir}/README.md"
167
+ printf '%s\n' "$SCANNER_VERSION" > "${repo_dir}/scanner-version.txt"
168
+ cp "${GITHUB_WORKSPACE}/action/cisco-version.txt" "${repo_dir}/cisco-version.txt"
169
+ cp "${GITHUB_WORKSPACE}/action/pypi-attestations-version.txt" "${repo_dir}/pypi-attestations-version.txt"
170
+ cp "${GITHUB_WORKSPACE}/LICENSE" "${repo_dir}/LICENSE"
171
+ cp "${GITHUB_WORKSPACE}/SECURITY.md" "${repo_dir}/SECURITY.md"
172
+ cp "${GITHUB_WORKSPACE}/CONTRIBUTING.md" "${repo_dir}/CONTRIBUTING.md"
173
+
174
+ if [ -n "$(git -C "$repo_dir" status --short -- action.yml README.md scanner-version.txt cisco-version.txt pypi-attestations-version.txt LICENSE SECURITY.md CONTRIBUTING.md)" ]; then
175
+ repo_changed="true"
176
+ git -C "$repo_dir" config user.name "github-actions[bot]"
177
+ git -C "$repo_dir" config user.email "41898282+github-actions[bot]@users.noreply.github.com"
178
+ git -C "$repo_dir" add action.yml README.md scanner-version.txt cisco-version.txt pypi-attestations-version.txt LICENSE SECURITY.md CONTRIBUTING.md
179
+ git -C "$repo_dir" commit -m "chore: publish action bundle ${TAG}"
180
+ git -C "$repo_dir" push origin HEAD:main
181
+ any_repo_changed="true"
182
+ fi
183
+
184
+ printf '%s\t%s\n' "$target_repo" "$repo_dir" >> "$GITHUB_WORKSPACE/action-repos/publish-targets.tsv"
185
+ }
186
+
187
+ mkdir -p "$GITHUB_WORKSPACE/action-repos"
188
+ : > "$GITHUB_WORKSPACE/action-repos/publish-targets.tsv"
189
+
190
+ sync_action_repo \
191
+ "$ACTION_CANONICAL_REPOSITORY" \
192
+ "${GITHUB_WORKSPACE}/action/README.md" \
193
+ "HOL AI Plugin Scanner GitHub Action"
194
+
195
+ sync_action_repo \
196
+ "$ACTION_COMPAT_REPOSITORY" \
197
+ "${GITHUB_WORKSPACE}/action/README.legacy.md" \
198
+ "Compatibility alias for HOL AI Plugin Scanner GitHub Action"
199
+
200
+ if [ "$any_repo_changed" != "true" ]; then
201
+ exit 0
202
+ fi
203
+
204
+ while IFS=$'\t' read -r target_repo repo_dir; do
205
+ publish_action_release "$target_repo" "$repo_dir"
206
+ done < "$GITHUB_WORKSPACE/action-repos/publish-targets.tsv"