Skip to content

Commit 2f1b24d

Browse files
committed
feat: update guard flow (#62)
* feat: migrate action identity to ai plugin scanner Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: move action output defaults into runner Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: shorten canonical action slug Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: gate action tag publication on bundle changes Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: derive action tags from both published repos Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: avoid action release tag collisions Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: ignore peeled action tag refs Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: preserve action outputs on failure paths Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: keep action release tags aligned across repos Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * feat: improve guard cli diagnostics Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: align guard files with ci formatting Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: use active interpreter for claude hooks Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: preserve empty hook override state Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: tighten guard cli behavior Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: validate scoped guard policies Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: tighten guard artifact tracking Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: harden guard policy state Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: scope guard adapter artifact ids Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: preserve blocked guard baselines Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: harden guard runtime fallbacks Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: harden guard command validation Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> * fix: harden guard cli fallbacks Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com> --------- Signed-off-by: Michael Kantor <6068672+kantorcodes@users.noreply.github.com>
1 parent ac9761a commit 2f1b24d

47 files changed

Lines changed: 4891 additions & 185 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/publish-action-repo.yml

Lines changed: 116 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ permissions:
1010
contents: read
1111

1212
concurrency:
13-
group: codex-plugin-scanner-action-repo-${{ github.ref }}
13+
group: ai-plugin-scanner-action-repo-${{ github.ref }}
1414
cancel-in-progress: false
1515

1616
jobs:
@@ -20,7 +20,8 @@ jobs:
2020
permissions:
2121
contents: read
2222
env:
23-
ACTION_REPOSITORY: ${{ vars.ACTION_REPOSITORY != '' && vars.ACTION_REPOSITORY || 'hashgraph-online/hol-codex-plugin-scanner-action' }}
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' }}
2425
SOURCE_REF: ${{ github.sha }}
2526
SOURCE_REPOSITORY: ${{ github.repository }}
2627
SOURCE_SERVER_URL: ${{ github.server_url }}
@@ -44,7 +45,38 @@ jobs:
4445
env:
4546
GH_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
4647
run: |
47-
LAST_TAG=$(gh release list --repo "$ACTION_REPOSITORY" --limit 1 --json tagName --jq '.[0].tagName // ""')
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
4880
4981
if [ -z "$LAST_TAG" ]; then
5082
TAG="v1.0.0"
@@ -82,88 +114,93 @@ jobs:
82114
fi
83115
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
84116
85-
- name: Clone action repository
86-
env:
87-
GH_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
88-
run: gh repo clone "$ACTION_REPOSITORY" action-repo -- --depth 1
89-
90-
- name: Configure authenticated action repository remote
91-
working-directory: action-repo
117+
- name: Sync canonical and compatibility action repositories
92118
env:
93119
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 }}
94123
run: |
95-
git remote set-url origin "https://x-access-token:${ACTION_REPO_TOKEN}@github.com/$ACTION_REPOSITORY.git"
124+
any_repo_changed="false"
96125
97-
- name: Sync root-ready action bundle
98-
working-directory: action-repo
99-
run: |
100-
cp "${GITHUB_WORKSPACE}/action/action.yml" action.yml
101-
cp "${GITHUB_WORKSPACE}/action/README.md" README.md
102-
printf '%s\n' "${{ steps.scanner_version.outputs.version }}" > scanner-version.txt
103-
cp "${GITHUB_WORKSPACE}/action/cisco-version.txt" cisco-version.txt
104-
cp "${GITHUB_WORKSPACE}/action/pypi-attestations-version.txt" pypi-attestations-version.txt
105-
cp "${GITHUB_WORKSPACE}/LICENSE" LICENSE
106-
cp "${GITHUB_WORKSPACE}/SECURITY.md" SECURITY.md
107-
cp "${GITHUB_WORKSPACE}/CONTRIBUTING.md" CONTRIBUTING.md
108-
109-
- name: Detect sync changes
110-
id: diff
111-
working-directory: action-repo
112-
run: |
113-
if [ -n "$(git status --short -- action.yml README.md scanner-version.txt cisco-version.txt pypi-attestations-version.txt LICENSE SECURITY.md CONTRIBUTING.md)" ]; then
114-
echo "changed=true" >> "$GITHUB_OUTPUT"
115-
else
116-
echo "changed=false" >> "$GITHUB_OUTPUT"
117-
fi
126+
publish_action_release() {
127+
target_repo="$1"
128+
repo_dir="$2"
118129
119-
- name: Commit synced bundle
120-
if: steps.diff.outputs.changed == 'true'
121-
working-directory: action-repo
122-
run: |
123-
git config user.name "github-actions[bot]"
124-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
125-
git add action.yml README.md scanner-version.txt cisco-version.txt pypi-attestations-version.txt LICENSE SECURITY.md CONTRIBUTING.md
126-
git commit -m "chore: publish action bundle ${{ steps.version.outputs.tag }}"
127-
128-
- name: Push action repository branch and tags
129-
if: steps.diff.outputs.changed == 'true'
130-
working-directory: action-repo
131-
run: |
132-
TAG="${{ steps.version.outputs.tag }}"
133-
git push origin HEAD:main
134-
git tag "$TAG"
135-
git push origin "refs/tags/${TAG}"
136-
git tag -fa v1 -m "Update floating major tag to ${TAG}"
137-
git push origin refs/tags/v1 --force
138-
139-
- name: Check action release state
140-
id: release_state
141-
working-directory: action-repo
142-
env:
143-
GH_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
144-
run: |
145-
TAG="${{ steps.version.outputs.tag }}"
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
146162
147-
if gh release view "${TAG}" --repo "$ACTION_REPOSITORY" >/dev/null 2>&1; then
148-
echo "release_exists=true" >> "$GITHUB_OUTPUT"
149-
else
150-
echo "release_exists=false" >> "$GITHUB_OUTPUT"
151-
fi
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
152183
153-
if git ls-remote --tags origin "refs/tags/${TAG}" | grep -q .; then
154-
echo "tag_exists=true" >> "$GITHUB_OUTPUT"
155-
else
156-
echo "tag_exists=false" >> "$GITHUB_OUTPUT"
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
157202
fi
158203
159-
- name: Create action repository release
160-
if: steps.release_state.outputs.release_exists == 'false' && (steps.diff.outputs.changed == 'true' || steps.release_state.outputs.tag_exists == 'true')
161-
env:
162-
GH_TOKEN: ${{ secrets.ACTION_REPO_TOKEN }}
163-
run: |
164-
TAG="${{ steps.version.outputs.tag }}"
165-
gh release create "${TAG}" \
166-
--repo "$ACTION_REPOSITORY" \
167-
--title "$TAG" \
168-
--generate-notes \
169-
--notes "Published automatically from ${SOURCE_SERVER_URL}/${SOURCE_REPOSITORY}/tree/${SOURCE_REF}"
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"

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ jobs:
193193
run: |
194194
VERSION="${{ needs.build.outputs.version }}"
195195
BUNDLE_ROOT="dist/github-action-bundle"
196-
BUNDLE_PATH="dist/hol-codex-plugin-scanner-action-v${VERSION}.zip"
196+
BUNDLE_PATH="dist/ai-plugin-scanner-action-v${VERSION}.zip"
197197
198198
mkdir -p "${BUNDLE_ROOT}"
199199
cp action/action.yml "${BUNDLE_ROOT}/action.yml"

README.md

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ pipx run plugin-scanner verify .
2525

2626
```yaml
2727
# GitHub Actions PR gate
28-
- name: Codex plugin quality gate
29-
uses: hashgraph-online/hol-codex-plugin-scanner-action@v1
28+
- name: AI plugin quality gate
29+
uses: hashgraph-online/ai-plugin-scanner-action@v1
3030
with:
3131
plugin_dir: "."
3232
fail_on_severity: high
@@ -213,7 +213,7 @@ For repo-scoped marketplaces, `scan`, `lint`, `verify`, and `doctor` can target
213213
## Config + Baseline Example
214214

215215
```toml
216-
# .codex-plugin-scanner.toml
216+
# .plugin-scanner.toml
217217
[scanner]
218218
profile = "public-marketplace"
219219
baseline_file = "baseline.txt"
@@ -303,7 +303,7 @@ jobs:
303303
runs-on: ubuntu-latest
304304
steps:
305305
- uses: actions/checkout@v6
306-
- uses: hashgraph-online/hol-codex-plugin-scanner-action@v1
306+
- uses: hashgraph-online/ai-plugin-scanner-action@v1
307307
with:
308308
plugin_dir: "."
309309
mode: scan
@@ -322,9 +322,9 @@ Local pre-commit style hook:
322322
repos:
323323
- repo: local
324324
hooks:
325-
- id: codex-plugin-scanner
326-
name: Codex Plugin Scanner
327-
entry: codex-plugin-scanner
325+
- id: plugin-scanner
326+
name: Plugin Scanner
327+
entry: plugin-scanner
328328
language: system
329329
types: [directory]
330330
pass_filenames: false
@@ -351,25 +351,27 @@ The source repository can publish the GitHub Action automatically into a dedicat
351351
Configure:
352352

353353
- repository secret `ACTION_REPO_TOKEN`
354-
It should be a token that can create or update repositories and releases in the target repository.
355-
- optional repository variable `ACTION_REPOSITORY`
354+
It should be a token that can create or update repositories and releases in the canonical and compatibility action repositories.
355+
- optional repository variable `ACTION_CANONICAL_REPOSITORY`
356+
Defaults to `hashgraph-online/ai-plugin-scanner-action`.
357+
- optional repository variable `ACTION_COMPAT_REPOSITORY`
356358
Defaults to `hashgraph-online/hol-codex-plugin-scanner-action`.
357359

358-
When a tagged release is published, [publish-action-repo.yml](./.github/workflows/publish-action-repo.yml) will:
360+
When changes land on `main`, [publish-action-repo.yml](./.github/workflows/publish-action-repo.yml) will:
359361

360-
- create the dedicated action repository if it does not already exist
361-
- sync the root-ready `action.yml`, `README.md`, `LICENSE`, and `SECURITY.md`
362+
- create the canonical Marketplace repository if it does not already exist
363+
- sync the root-ready `action.yml`, repo-specific `README.md`, `LICENSE`, and `SECURITY.md` into both the canonical repo and the legacy compatibility repo
362364
- push the immutable release tag such as `v2.0.0`
363365
- move the floating `v1` tag
364-
- create or update the corresponding release in the action repository
366+
- create or update the corresponding release in each action repository
365367

366368
GitHub Marketplace still requires the one-time listing publication step in the dedicated action repository UI, but after that this repository can keep the action repository current automatically.
367369

368370
### Plugin Author Submission Flow
369371

370372
The action can also handle submission intake. A plugin repository can wire the scanner into CI so a passing scan opens or reuses a submission issue in [awesome-codex-plugins](https://github.com/hashgraph-online/awesome-codex-plugins).
371373

372-
It also emits Codex-friendly machine outputs:
374+
It also emits automation-friendly machine outputs:
373375

374376
- `score`, `grade`, `grade_label`, `max_severity`, and `findings_total` as GitHub Action outputs
375377
- a concise markdown summary in the job summary by default
@@ -397,7 +399,7 @@ jobs:
397399
398400
- name: Scan and submit if eligible
399401
id: scan
400-
uses: hashgraph-online/hol-codex-plugin-scanner-action@v1
402+
uses: hashgraph-online/ai-plugin-scanner-action@v1
401403
with:
402404
plugin_dir: "."
403405
min_score: 80
@@ -413,9 +415,9 @@ jobs:
413415

414416
`submission_token` is required when `submission_enabled: true`. This flow is idempotent. If the plugin repository was already submitted, the action reuses the existing open issue instead of opening duplicates by matching an exact hidden plugin URL marker in the existing issue body.
415417

416-
### Registry Payload For Codex Ecosystem Automation
418+
### Registry Payload For Plugin Ecosystem Automation
417419

418-
If you want to feed the same scan into a registry, badge pipeline, or another Codex automation step, request a registry payload file directly from the action:
420+
If you want to feed the same scan into a registry, badge pipeline, or another plugin ecosystem automation step, request a registry payload file directly from the action:
419421

420422
```yaml
421423
permissions:
@@ -429,12 +431,12 @@ jobs:
429431
430432
- name: Scan plugin
431433
id: scan
432-
uses: hashgraph-online/hol-codex-plugin-scanner-action@v1
434+
uses: hashgraph-online/ai-plugin-scanner-action@v1
433435
with:
434436
plugin_dir: "."
435437
format: sarif
436-
output: codex-plugin-scanner.sarif
437-
registry_payload_output: codex-plugin-registry-payload.json
438+
output: ai-plugin-scanner.sarif
439+
registry_payload_output: ai-plugin-registry-payload.json
438440
439441
- name: Show trust signals
440442
run: |
@@ -445,7 +447,7 @@ jobs:
445447
- name: Upload registry payload
446448
uses: actions/upload-artifact@v6
447449
with:
448-
name: codex-plugin-registry-payload
450+
name: ai-plugin-registry-payload
449451
path: ${{ steps.scan.outputs.registry_payload_path }}
450452
```
451453

action/README.legacy.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# HOL AI Plugin Scanner GitHub Action
2+
3+
[![Latest Release](https://img.shields.io/github/v/release/hashgraph-online/hol-codex-plugin-scanner-action?display_name=tag)](https://github.com/hashgraph-online/hol-codex-plugin-scanner-action/releases/latest)
4+
[![Compatibility Alias](https://img.shields.io/badge/legacy-slug-supported-6b7280)](https://github.com/hashgraph-online/hol-codex-plugin-scanner-action)
5+
[![Canonical Repository](https://img.shields.io/badge/canonical-ai--plugin--scanner--action-0A84FF)](https://github.com/hashgraph-online/ai-plugin-scanner-action)
6+
[![Source of Truth](https://img.shields.io/badge/source-ai--plugin--scanner-111827)](https://github.com/hashgraph-online/ai-plugin-scanner/tree/main/action)
7+
8+
This repository remains supported as a compatibility alias for existing workflows that use:
9+
10+
```yaml
11+
uses: hashgraph-online/hol-codex-plugin-scanner-action@v1
12+
```
13+
14+
New integrations should move to the canonical action slug:
15+
16+
```yaml
17+
uses: hashgraph-online/ai-plugin-scanner-action@v1
18+
```
19+
20+
The action behavior, release train, and source of truth are shared with the canonical repository:
21+
22+
- Canonical action repo: [hashgraph-online/ai-plugin-scanner-action](https://github.com/hashgraph-online/ai-plugin-scanner-action)
23+
- Source repo: [hashgraph-online/ai-plugin-scanner](https://github.com/hashgraph-online/ai-plugin-scanner)
24+
25+
The compatibility alias continues to receive the same reviewed root bundle, release tags, and floating `v1` major tag so existing consumers do not break during the identity migration.

0 commit comments

Comments
 (0)